From e808d9a15e0c8bc40549430e16717c3720850ab6 Mon Sep 17 00:00:00 2001 From: Max N Date: Sat, 15 Aug 2026 18:40:44 -0400 Subject: [PATCH] improve ci for separate package release, optimize CI execution paths --- .github/scripts/version-packages.js | 55 +++++++++++++++++++ .github/workflows/coverage.yml | 10 ++-- .../workflows/enforce-solidity-comments.yml | 4 ++ .github/workflows/gas-report.yml | 9 +-- .github/workflows/release.yml | 50 +++++++++++++++-- .github/workflows/slither.yml | 14 ++--- .github/workflows/test.yml | 22 +++++--- RELEASING.md | 19 +++++-- package.json | 2 +- 9 files changed, 150 insertions(+), 35 deletions(-) create mode 100644 .github/scripts/version-packages.js diff --git a/.github/scripts/version-packages.js b/.github/scripts/version-packages.js new file mode 100644 index 00000000..3d99ed9d --- /dev/null +++ b/.github/scripts/version-packages.js @@ -0,0 +1,55 @@ +#!/usr/bin/env node + +/** + * Wrapper around `changeset version` that supports --ignore for selective + * package releases. Also syncs the root CHANGELOG.md with src/CHANGELOG.md + * before and after versioning (the dual-CHANGELOG pattern). + * + * Usage: + * node .github/scripts/version-packages.js + * node .github/scripts/version-packages.js --ignore @perfect-abstractions/compose-cli + * node .github/scripts/version-packages.js --ignore @perfect-abstractions/compose + */ + +const { execSync } = require('child_process'); +const fs = require('fs'); +const path = require('path'); + +const ROOT = process.cwd(); +const ROOT_CL = path.join(ROOT, 'CHANGELOG.md'); +const SRC_CL = path.join(ROOT, 'src', 'CHANGELOG.md'); + +function copyFile(src, dest) { + if (fs.existsSync(src)) { + fs.copyFileSync(src, dest); + } +} + +function execOrDie(cmd) { + console.log(`> ${cmd}`); + execSync(cmd, { stdio: 'inherit', cwd: ROOT }); +} + +// --- Parse --ignore flag --- +const ignoreIdx = process.argv.indexOf('--ignore'); +const ignorePkg = ignoreIdx !== -1 ? process.argv[ignoreIdx + 1] : null; + +if (ignorePkg) { + console.log(`Selective release: ignoring ${ignorePkg}`); +} + +// --- Pre-sync: copy root CHANGELOG into src/ so changeset version reads the latest --- +copyFile(ROOT_CL, SRC_CL); + +// --- Run changeset version --- +const versionCmd = ignorePkg + ? `npx changeset version --ignore ${ignorePkg}` + : 'npx changeset version'; + +execOrDie(versionCmd); + +// --- Post-sync: copy updated src/ CHANGELOG back to root, then back to src/ --- +// This mirrors the original shell one-liner behavior: +// cp src/CHANGELOG.md CHANGELOG.md; cp CHANGELOG.md src/CHANGELOG.md +copyFile(SRC_CL, ROOT_CL); +copyFile(ROOT_CL, SRC_CL); diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 30fab45c..f06ef1ba 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -2,10 +2,12 @@ name: Coverage on: pull_request: - paths-ignore: - - '**.md' - - 'website/**' - - 'cli/**' + paths: + - 'src/**' + - 'test/**' + - 'script/**' + - 'foundry.toml' + - '.github/workflows/coverage.yml' workflow_dispatch: env: diff --git a/.github/workflows/enforce-solidity-comments.yml b/.github/workflows/enforce-solidity-comments.yml index f7a375bb..af431032 100644 --- a/.github/workflows/enforce-solidity-comments.yml +++ b/.github/workflows/enforce-solidity-comments.yml @@ -3,8 +3,12 @@ on: push: branches: - '**' + paths: + - '**.sol' pull_request: types: [opened, synchronize, reopened, edited] + paths: + - '**.sol' permissions: contents: read diff --git a/.github/workflows/gas-report.yml b/.github/workflows/gas-report.yml index 7c88b20b..3262de4d 100644 --- a/.github/workflows/gas-report.yml +++ b/.github/workflows/gas-report.yml @@ -2,10 +2,11 @@ name: Gas Report on: pull_request: - paths-ignore: - - '**.md' - - 'website/**' - - 'cli/**' + paths: + - 'src/**' + - 'test/**' + - 'foundry.toml' + - '.github/workflows/gas-report.yml' workflow_dispatch: env: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 56c2a5c8..3436c29f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,12 +2,47 @@ name: Release on: workflow_dispatch: + inputs: + release_target: + description: 'Packages to release' + required: true + default: 'all' + type: choice + options: + - all + - compose + - compose-cli permissions: contents: read jobs: + prepare: + runs-on: ubuntu-latest + outputs: + ignore_flag: ${{ steps.map.outputs.ignore_flag }} + version_branch: ${{ steps.map.outputs.version_branch }} + steps: + - name: Map release target to flags + id: map + run: | + case "${{ inputs.release_target }}" in + all) + echo "ignore_flag=" >> "$GITHUB_OUTPUT" + echo "version_branch=changeset-release/main" >> "$GITHUB_OUTPUT" + ;; + compose) + echo "ignore_flag=--ignore @perfect-abstractions/compose-cli" >> "$GITHUB_OUTPUT" + echo "version_branch=changeset-release/main-compose" >> "$GITHUB_OUTPUT" + ;; + compose-cli) + echo "ignore_flag=--ignore @perfect-abstractions/compose" >> "$GITHUB_OUTPUT" + echo "version_branch=changeset-release/main-cli" >> "$GITHUB_OUTPUT" + ;; + esac + quality-gates: + needs: prepare runs-on: ubuntu-latest permissions: contents: read @@ -20,6 +55,7 @@ jobs: submodules: recursive - name: Install Foundry + if: inputs.release_target == 'all' || inputs.release_target == 'compose' uses: foundry-rs/foundry-toolchain@v1 - name: Setup Node.js @@ -32,12 +68,17 @@ jobs: - name: Install dependencies run: npm ci - - name: Run all packages quality checks - run: npm run check + - name: Library quality gates + if: inputs.release_target == 'all' || inputs.release_target == 'compose' + run: npm run compose@check && npm run compose@pack:check + + - name: CLI quality gates + if: inputs.release_target == 'all' || inputs.release_target == 'compose-cli' + run: npm run cli@build && npm run cli@check && npm run cli@pack:check version-packages: + needs: [prepare, quality-gates] runs-on: ubuntu-latest - needs: quality-gates permissions: contents: write pull-requests: write @@ -63,8 +104,9 @@ jobs: - name: Create or update version PR uses: changesets/action@v1 with: - version: npm run version-packages + version: npm run version-packages -- ${{ needs.prepare.outputs.ignore_flag }} commit: "chore(release): apply changesets and bump versions" title: "chore(release): bump npm versions & changelogs" + branch: ${{ needs.prepare.outputs.version_branch }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/slither.yml b/.github/workflows/slither.yml index d35e7680..024ad87a 100644 --- a/.github/workflows/slither.yml +++ b/.github/workflows/slither.yml @@ -4,15 +4,13 @@ name: Slither on: push: branches: [main] - paths-ignore: - - '**.md' - - 'website/**' - - 'cli/**' + paths: + - 'src/**' + - '.github/workflows/slither.yml' pull_request: - paths-ignore: - - '**.md' - - 'website/**' - - 'cli/**' + paths: + - 'src/**' + - '.github/workflows/slither.yml' workflow_dispatch: env: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 33b9e29c..5eecc3f3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,15 +3,21 @@ name: Test on: push: branches: [main] - paths-ignore: - - '**.md' - - 'website/**' - - 'cli/**' + paths: + - 'src/**' + - 'test/**' + - 'script/**' + - 'foundry.toml' + - 'remappings.txt' + - '.github/workflows/test.yml' pull_request: - paths-ignore: - - '**.md' - - 'website/**' - - 'cli/**' + paths: + - 'src/**' + - 'test/**' + - 'script/**' + - 'foundry.toml' + - 'remappings.txt' + - '.github/workflows/test.yml' workflow_dispatch: env: diff --git a/RELEASING.md b/RELEASING.md index 79ce0c74..92d15507 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -16,9 +16,13 @@ Releases use [Changesets](https://github.com/changesets/changesets) and GitHub A - **Branch:** `main` only for production releases. - **Versioning:** independent per package. -- **Batching:** Multiple PRs can add `.changeset/*.md` files; one **version bump PR** (same PR updated) applies all pending bumps together. -- **Open/update the version PR:** Run the **Release** workflow manually (**Actions → Release → Run workflow**). It checks out `main`, runs checks, then [changesets/action](https://github.com/changesets/action) creates or updates the PR (branch is usually `changeset-release/main`). -- **Publish:** Runs automatically when that **version bump PR is merged** into `main` (workflow **Publish**). You can also run **Publish** manually (`workflow_dispatch`) to retry or publish without merging from that branch (e.g. hotfix). +- **Selective releases:** The **Release** workflow has a dropdown to choose which packages to release: **all**, **compose** only, or **compose-cli** only. Selecting a single package uses `changeset version --ignore` to skip the other, so its changesets stay pending for a future release. +- **Batching:** Multiple PRs can add `.changeset/*.md` files; one **version bump PR** (same PR updated) applies all pending bumps for the selected package(s). +- **Open/update the version PR:** Run the **Release** workflow manually (**Actions → Release → Run workflow**). It checks out `main`, runs only the quality gates for the selected package(s), then [changesets/action](https://github.com/changesets/action) creates or updates a version PR on a target-specific branch: + - **All:** `changeset-release/main` + - **Compose:** `changeset-release/main-compose` + - **Compose-cli:** `changeset-release/main-cli` +- **Publish:** Runs automatically when any **version bump PR is merged** into `main` (workflow **Publish**). You can also run **Publish** manually (`workflow_dispatch`) to retry or publish without merging from that branch (e.g. hotfix). - **Publish approval:** Jobs that publish to npm use GitHub Environment **`npm-publish`** (required reviewers). Approval is requested when those jobs run, including after an automatic trigger. - **Authentication:** Publishes use **npm Trusted Publishing (OIDC)** - **Provenance:** For public repos, npm generates provenance automatically when publishing via trusted publishing. @@ -33,11 +37,14 @@ There is **no** failing CI check for missing changesets; maintainers batch or ad ## Maintainer release flow -1. When you want a version bump PR, run **Release** manually on `main`. -2. Review and merge the **chore(release): bump npm versions & changelogs** PR (from `changeset-release/main` or the same prefix — automatic **Publish** only runs for merges from branches named `changeset-release/*`). +1. Go to **Actions → Release → Run workflow**. Select the target: + - **all** — releases both packages together + - **compose** — releases only the library (CLI changesets stay pending) + - **compose-cli** — releases only the CLI (library changesets stay pending) +2. Review and merge the **chore(release): bump npm versions & changelogs** PR. Each release target creates a PR on a different branch (`changeset-release/main`, `changeset-release/main-compose`, or `changeset-release/main-cli` — automatic **Publish** only runs for merges from branches named `changeset-release/*`). 3. **Publish** starts automatically on that merge. Approve the **`npm-publish`** environment when GitHub prompts you. 4. The **plan** job fails if any real `.changeset/*.md` files remain (finish merging the version PR so only `.changeset/README.md` is left). -5. The **plan** job compares each package’s `package.json` version to npm (see [`.github/publish-packages.json`](.github/publish-packages.json)). If every configured package already matches npm, the publish job is skipped (nothing new to ship). +5. The **plan** job compares each package's `package.json` version to npm (see [`.github/publish-packages.json`](.github/publish-packages.json)). If every configured package already matches npm, the publish job is skipped (nothing new to ship). 6. A single **publish** workflow job runs a **matrix**: one row per package that is ahead of npm. Rows run in parallel when several packages need a release. Each row publishes to npm, then creates a short git tag and GitHub Release: - Library tag: `compose@` (e.g. `compose@0.2.0`) - CLI tag: `compose-cli@` (e.g. `compose-cli@0.2.0`) diff --git a/package.json b/package.json index b461f21a..5b7da3e3 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "cli@check": "npm --workspace cli run check", "cli@pack:check": "npm --workspace cli run pack:check", "check": "npm run compose@check && npm run compose@pack:check && npm run cli@build && npm run cli@check && npm run cli@pack:check", - "version-packages": "sh -c 'cp CHANGELOG.md src/CHANGELOG.md 2>/dev/null || true; changeset version; cp src/CHANGELOG.md CHANGELOG.md; cp CHANGELOG.md src/CHANGELOG.md'", + "version-packages": "node .github/scripts/version-packages.js", "release": "changeset publish" }, "homepage": "https://compose.diamonds",