Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions .github/scripts/version-packages.js
Original file line number Diff line number Diff line change
@@ -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);
10 changes: 6 additions & 4 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/enforce-solidity-comments.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ on:
push:
branches:
- '**'
paths:
- '**.sol'
pull_request:
types: [opened, synchronize, reopened, edited]
paths:
- '**.sol'

permissions:
contents: read
Expand Down
9 changes: 5 additions & 4 deletions .github/workflows/gas-report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
50 changes: 46 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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 }}
14 changes: 6 additions & 8 deletions .github/workflows/slither.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
22 changes: 14 additions & 8 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
19 changes: 13 additions & 6 deletions RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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@<version>` (e.g. `compose@0.2.0`)
- CLI tag: `compose-cli@<version>` (e.g. `compose-cli@0.2.0`)
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Loading