diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..661db58 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +/.github/** @Andarist @bluwy diff --git a/.github/actions/ci-setup/action.yml b/.github/actions/ci-setup/action.yml new file mode 100644 index 0000000..200c537 --- /dev/null +++ b/.github/actions/ci-setup/action.yml @@ -0,0 +1,29 @@ +name: Setup CI +description: Setup CI + +inputs: + node-version: + description: Node.js version + required: false + default: 24 + skip-cache: + description: "Whether to skip the cache" + required: false + default: "false" + +runs: + using: composite + steps: + - name: Set up pnpm + uses: pnpm/action-setup@91ab88e2619ed1f46221f0ba42d1492c02baf788 # v6.0.6 + + - name: Set up Node.js ${{ inputs.node-version }} + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: ${{ inputs.node-version }} + package-manager-cache: ${{ inputs.skip-cache != 'true' }} + cache: ${{ inputs.skip-cache != 'true' && 'pnpm' || '' }} + + - name: Install dependencies + shell: bash + run: pnpm install --frozen-lockfile diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..7495a7f --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "npm" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" + cooldown: + default-days: 7 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a852dcc..e649c80 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,37 +1,83 @@ -name: CI Checks +name: CI + on: pull_request: - push: + # merge queue is required so all commits on target branches trigger this workflow + # despite lack of the push event trigger here + merge_group: branches: - main permissions: - contents: write + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.sha }} + cancel-in-progress: true jobs: - ci-checks: + build: + name: Build + runs-on: ubuntu-latest + steps: + - name: Check out repo + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - uses: ./.github/actions/ci-setup + + - name: Build + run: pnpm build + + lint: + name: Lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Check out repo + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: - fetch-depth: 2 - - name: Use Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 + persist-credentials: false + + - uses: ./.github/actions/ci-setup + + - name: Lint + run: pnpm lint + + - name: Format + run: pnpm format:check + + test: + name: Test + runs-on: ubuntu-latest + timeout-minutes: 20 + permissions: + contents: write # integration tests create and push temporary branches + steps: + - name: Check out repo + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: - node-version: 24.x - - name: Extract pnpm version and install - run: | - VERSION=$(cat package.json | grep '"packageManager": "pnpm@' | sed 's/.*"pnpm@\([^"]*\)".*/\1/') - npm install -g pnpm@$VERSION - - uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2 + fetch-depth: 2 # integration tests read the two most recent local commits + persist-credentials: false + + - uses: ./.github/actions/ci-setup with: - path: ~/.pnpm-store - key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} - - run: pnpm install --frozen-lockfile - - run: pnpm build - - run: pnpm lint - - run: pnpm format:check - - run: pnpm test:integration + skip-cache: true # avoid cache poisoning from this only job with write access, just in case + + - name: Build + run: pnpm build + + - name: Integration tests + run: pnpm test:integration env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - HEAD_OID: ${{ github.base_ref }} + + ci-ok: + name: CI OK + runs-on: ubuntu-latest + if: always() + needs: [build, lint, test] + steps: + - name: Exit with error if some jobs are not successful + if: ${{ always() && (contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')) }} + run: exit 1 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 7cba105..450fb29 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,41 +1,66 @@ -name: Release & Publish +name: Publish on: push: branches: - main -permissions: - contents: write - pull-requests: write - id-token: write +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + queue: max + +permissions: {} jobs: - release-and-publish: + version: + name: Version runs-on: ubuntu-latest + timeout-minutes: 10 + outputs: + hasChangesets: ${{ steps.changesets.outputs.hasChangesets }} + permissions: + contents: write # to create version commits (changesets/action) + pull-requests: write # to create pull request (changesets/action) steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Check out repo + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - uses: ./.github/actions/ci-setup with: - token: ${{ secrets.GITHUB_TOKEN }} - - name: Use Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 + skip-cache: true # avoid cache poisoning attacks + + - name: Create or update release pull request + id: changesets + uses: changesets/action@63a615b9cd06ba9a3e6d13796c7fbcb080a60a0b # v1.8.0 + + publish: + name: Publish + if: needs.version.outputs.hasChangesets == 'false' + needs: version + runs-on: ubuntu-latest + environment: npm + timeout-minutes: 10 + permissions: + contents: write # to create release (changesets/action) + id-token: write # to use OpenID Connect token for trusted publishing (changesets/action) + steps: + - name: Check out repo + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: - node-version: 24.x - - name: Extract pnpm version and install - run: | - VERSION=$(cat package.json | grep '"packageManager": "pnpm@' | sed 's/.*"pnpm@\([^"]*\)".*/\1/') - npm install -g pnpm@$VERSION - - name: Cache pnpm modules - uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2 + persist-credentials: false + + - uses: ./.github/actions/ci-setup with: - path: ~/.pnpm-store - key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} - - run: pnpm install --frozen-lockfile - - run: pnpm build - - name: Run Changeset Workflow - uses: changesets/action@c48e67d110a68bc90ccf1098e9646092baacaa87 # v1.6.0 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + skip-cache: true # avoid cache poisoning attacks + + - name: Build + run: pnpm build + + - name: Publish to npm + uses: changesets/action@63a615b9cd06ba9a3e6d13796c7fbcb080a60a0b # v1.8.0 with: publish: pnpm changeset publish commitMode: github-api