Repository navigation
ci: beta pr releases #1863
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
ci: beta pr releases #1863
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
549be16
ci: fix broken actions
jannik-stacks 386a105
Merge branch 'main' into ci/fix-actions
jannik-stacks c5efb92
Merge branch 'main' into ci/fix-actions
jannik-stacks 246d8ca
ci: switch to changesets
jannik-stacks 3ea8c3f
chore: update lock file
jannik-stacks 7477091
ci: update workflows
jannik-stacks 91583b6
ci: update release scripts
jannik-stacks a88f270
Merge remote-tracking branch 'origin/main' into ci/beta-pr-releases
jannik-stacks f023828
ci: re-add sticky header on PR canary
jannik-stacks 6bdf3fd
ci: simplify header
jannik-stacks e7ff7d1
ci: fix seed
jannik-stacks d1ca128
ci: change publish location
jannik-stacks 717697a
ci: rename flows
jannik-stacks 488a9d8
chore: fix repository link
jannik-stacks 56d470b
docs: fix shield
jannik-stacks 8ee9208
ci: update workflow dispatch
jannik-stacks 9b847d3
ci: simplify build
jannik-stacks File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| # Changesets | ||
|
|
||
| Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works | ||
| with multi-package repos, or single-package repos to help you version and publish your code. You can | ||
| find the full documentation for it [in our repository](https://github.com/changesets/changesets) | ||
|
|
||
| We have a quick list of common questions to get you started engaging with this project in | ||
| [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| { | ||
| "$schema": "https://unpkg.com/@changesets/config@2.3.1/schema.json", | ||
|
jannik-stacks marked this conversation as resolved.
Resolved
|
||
| "changelog": "@changesets/cli/changelog", | ||
| "commit": false, | ||
| "fixed": [["@stacks/*"]], | ||
| "linked": [], | ||
| "access": "public", | ||
| "baseBranch": "main", | ||
| "updateInternalDependencies": "patch", | ||
| "ignore": [] | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,18 +1,16 @@ | ||
| ## Adding dependencies | ||
|
|
||
| This repo uses Lerna [hoisting](https://github.com/lerna/lerna/blob/main/doc/hoist.md) for package dependencies. | ||
| This repo uses [npm workspaces](https://docs.npmjs.com/cli/v10/using-npm/workspaces) for package management. | ||
|
|
||
| In order to install a new dependency to a package, the [`lerna add`](https://github.com/lerna/lerna/tree/main/commands/add) command must be used, rather than `npm install <package>`. | ||
|
|
||
| For example, the following command installs `lodash` as a dependency to the `@stacks/storage` package: | ||
| To install a new dependency to a specific package, use the `-w` (workspace) flag: | ||
|
|
||
| ```shell | ||
| # Run within the root directory | ||
| npx lerna add lodash --scope @stacks/storage | ||
| npm install lodash -w @stacks/storage | ||
| ``` | ||
|
|
||
| Add `--dev` to install as a development dependency: | ||
| Add `--save-dev` to install as a development dependency: | ||
|
|
||
| ```shell | ||
| npx lerna add lodash --scope @stacks/storage --dev | ||
| npm install lodash -w @stacks/storage --save-dev | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| #!/usr/bin/env node | ||
| // Rewrite packages/*/package.json to a snapshot version like | ||
| // `<base>-<tag>.<counter>` (or `<base>-pr.<num>.<counter>`). Run between | ||
| // `changeset version` and `changeset publish --tag <tag>`. | ||
| // | ||
| // Usage: node .github/scripts/snapshot-version.mjs <beta|pr> [--pr <number>] | ||
|
jannik-stacks marked this conversation as resolved.
Resolved
|
||
|
|
||
| import { readFile, writeFile, readdir, appendFile } from 'node:fs/promises'; | ||
| import { execFileSync } from 'node:child_process'; | ||
|
|
||
| const [tag, , prNumber] = process.argv.slice(2); | ||
| if (!['beta', 'pr'].includes(tag) || (tag === 'pr' && !prNumber)) { | ||
| console.error('Usage: snapshot-version.mjs <beta|pr> [--pr <number>]'); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| const DEP_TYPES = ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies']; | ||
|
|
||
| const entries = await readdir('packages', { withFileTypes: true }); | ||
| const pkgs = (await Promise.all( | ||
| entries | ||
| .filter((e) => e.isDirectory()) | ||
| .map((e) => `packages/${e.name}/package.json`) | ||
| .map(async (file) => { | ||
| try { return { file, json: JSON.parse(await readFile(file, 'utf8')) }; } | ||
| catch { return null; } | ||
| }), | ||
| )).filter(Boolean); | ||
|
|
||
| const rep = pkgs.find(({ json }) => json.name && !json.private && /^\d+\.\d+\.\d+$/.test(json.version)); | ||
| if (!rep) { | ||
| console.error('No non-private workspace package with plain semver — did you run `changeset version` first?'); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| const prefix = tag === 'beta' ? `${rep.json.version}-beta.` : `${rep.json.version}-pr.${prNumber}.`; | ||
| const version = `${prefix}${nextCounter(rep.json.name, prefix)}`; | ||
| console.log(`Snapshot version: ${version} (base from ${rep.json.name})`); | ||
|
|
||
| const internals = new Set(pkgs.map(({ json }) => json.name).filter(Boolean)); | ||
| const named = pkgs.filter(({ json }) => json.name); | ||
|
|
||
| await Promise.all(named.map(({ file, json }) => | ||
| writeFile(file, JSON.stringify(rewrite(json, version, internals), null, 2) + '\n'), | ||
| )); | ||
| named.forEach(({ json }) => console.log(` ${json.name} → ${version}`)); | ||
|
|
||
| if (process.env.GITHUB_OUTPUT) await appendFile(process.env.GITHUB_OUTPUT, `version=${version}\n`); | ||
|
|
||
| function rewrite(json, version, internals) { | ||
| const rewriteDeps = (deps) => | ||
| Object.fromEntries(Object.entries(deps).map(([n, v]) => [n, internals.has(n) ? version : v])); | ||
| return DEP_TYPES.reduce( | ||
| (acc, dt) => (acc[dt] ? { ...acc, [dt]: rewriteDeps(acc[dt]) } : acc), | ||
| { ...json, version }, | ||
| ); | ||
| } | ||
|
|
||
| function nextCounter(name, prefix) { | ||
| let raw; | ||
| try { | ||
| raw = execFileSync('npm', ['view', name, 'versions', '--json'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] }); | ||
| } catch (e) { | ||
| if ((e.stderr || '').includes('E404')) return 0; | ||
| throw e; | ||
| } | ||
| const all = JSON.parse(raw); | ||
| const counters = (Array.isArray(all) ? all : [all]) | ||
| .filter((v) => v.startsWith(prefix)) | ||
| .map((v) => Number(v.slice(prefix.length))) | ||
| .filter(Number.isInteger); | ||
| return counters.length ? Math.max(...counters) + 1 : 0; | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,82 +1,177 @@ | ||
| name: publish | ||
|
|
||
| # All npm-publishing flows live in this single file. npm's trusted-publisher | ||
| # config for every `@stacks/*` package points at `publish.yml` — renaming this | ||
| # file requires updating that config on npmjs.com per package. | ||
| # | ||
| # release — push to main / workflow_dispatch. | ||
| # changesets/action opens/updates the "chore: version packages" | ||
| # PR. When that PR is merged, the same action publishes the | ||
| # bumped packages to npm under `latest`. `commitMode: github-api` | ||
| # gives commits a Verified badge without signing keys in CI. | ||
| # | ||
| # beta — push to main. | ||
| # Snapshot-publishes every push to `@beta`, with versions of the | ||
| # form `<next-release>-beta.<N>` (counter scoped to the base | ||
| # version, queried from npm). | ||
| # | ||
| # pr — pull_request. | ||
| # Same as `beta` but `@pr` dist-tag and versions of the form | ||
| # `<next-release>-pr.<PR#>.<N>`. Sticky-header'd into the PR | ||
| # description so reviewers can install the canary build. | ||
| # | ||
| # Forks never reach the publish step (`is-not-fork` gate from pre-run). | ||
|
|
||
| on: | ||
| push: | ||
| branches: | ||
| - main | ||
| tags-ignore: | ||
| - "**" | ||
| - '**' | ||
| paths-ignore: | ||
| - "**.md" | ||
| - '**.md' | ||
|
|
||
| workflow_dispatch: | ||
| inputs: | ||
| pr-number: | ||
| description: 'PR number to publish a canary build for (leave blank for a normal release dispatch)' | ||
|
jannik-stacks marked this conversation as resolved.
Resolved
|
||
| type: string | ||
| required: false | ||
| default: '' | ||
|
|
||
| permissions: | ||
| id-token: write # Required for OIDC | ||
| contents: read | ||
| contents: write | ||
| pull-requests: write | ||
| id-token: write # npm OIDC trusted publishing | ||
|
|
||
| concurrency: ${{ github.workflow }}-${{ github.ref }} | ||
|
|
||
| jobs: | ||
| pre-run: | ||
| uses: ./.github/workflows/pre-run.yml | ||
| secrets: inherit | ||
|
|
||
| publish: | ||
| release: | ||
| runs-on: ubuntu-latest | ||
| needs: pre-run | ||
| if: needs.pre-run.outputs.is-not-fork == 'true' && (github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.pr-number == '')) | ||
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
||
| - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | ||
| with: | ||
| node-version: 24 | ||
| cache: npm | ||
|
|
||
| - run: npm ci | ||
|
|
||
| - name: Create release PR or publish | ||
| uses: changesets/action@63a615b9cd06ba9a3e6d13796c7fbcb080a60a0b # v1.8.0 | ||
|
jannik-stacks marked this conversation as resolved.
Resolved
|
||
| with: | ||
| version: npm run version | ||
| publish: npm run release | ||
| title: 'chore: version packages' | ||
| commit: 'chore: version packages' | ||
| commitMode: github-api | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| beta: | ||
| runs-on: ubuntu-latest | ||
| needs: pre-run | ||
| if: "needs.pre-run.outputs.is-not-fork == 'true' && (github.event_name == 'workflow_dispatch' || contains(github.event.head_commit.message, 'chore: version packages'))" | ||
| if: needs.pre-run.outputs.is-not-fork == 'true' && github.event_name == 'push' | ||
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
||
| - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | ||
| with: | ||
| node-version: 24 | ||
| cache: npm | ||
|
|
||
| - run: npm ci | ||
| - run: npm run build | ||
|
|
||
| - run: git config --local user.email 'action@github.com' | ||
| - run: git config --local user.name 'GitHub Action' | ||
| - name: Seed dummy changeset if none present | ||
| run: | | ||
| if ! ls .changeset/*.md 2>/dev/null | grep -vqi readme; then | ||
| cat > .changeset/__snapshot.md <<'EOF' | ||
| --- | ||
| "@stacks/common": patch | ||
| --- | ||
|
|
||
| snapshot | ||
| EOF | ||
| fi | ||
|
|
||
| - name: Publish | ||
| - run: npx changeset version | ||
| - run: node .github/scripts/snapshot-version.mjs beta | ||
|
|
||
| - name: Build packages | ||
| run: | | ||
| npx lerna publish from-package --no-verify-access --yes | ||
| RELEASE=$(cat lerna.json | jq -r '.version') | ||
| git tag -a v$RELEASE -m v$RELEASE | ||
| git push origin v$RELEASE | ||
| npm run clean --workspaces --if-present | ||
| npm run build:cjs --workspaces --if-present | ||
| npm run build:esm --workspaces --if-present | ||
| npm run build:umd --workspaces --if-present | ||
|
|
||
| # NPM_CONFIG_IGNORE_SCRIPTS skips each package's prepublishOnly hook, | ||
| # avoiding duplicate test/build work during publish. | ||
| - run: npx changeset publish --tag beta --no-git-tag | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| NPM_CONFIG_IGNORE_SCRIPTS: 'true' | ||
|
|
||
| publish-beta: | ||
| pr: | ||
| runs-on: ubuntu-latest | ||
| needs: pre-run | ||
| if: "needs.pre-run.outputs.is-not-fork == 'true' && !contains(github.event.head_commit.message, 'chore: version packages')" | ||
| if: needs.pre-run.outputs.is-not-fork == 'true' && github.event_name == 'workflow_dispatch' && inputs.pr-number != '' | ||
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
||
| # pulls all tags (needed for lerna to correctly version) | ||
| - run: git fetch --depth=1 origin +refs/tags/*:refs/tags/* | ||
|
|
||
| - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | ||
| with: | ||
| node-version: 24 | ||
| cache: npm | ||
|
|
||
| - run: npm ci | ||
|
|
||
| - run: git config --local user.email 'action@github.com' | ||
| - run: git config --local user.name 'GitHub Action' | ||
| - name: Seed dummy changeset if none present | ||
| run: | | ||
| if ! ls .changeset/*.md 2>/dev/null | grep -vqi readme; then | ||
| cat > .changeset/__snapshot.md <<'EOF' | ||
| --- | ||
| "@stacks/common": patch | ||
| --- | ||
|
|
||
| snapshot | ||
| EOF | ||
| fi | ||
|
jannik-stacks marked this conversation as resolved.
Resolved
|
||
|
|
||
| - run: npx changeset version | ||
| - id: snapshot | ||
| run: node .github/scripts/snapshot-version.mjs pr --pr ${{ inputs.pr-number }} | ||
|
|
||
| - name: Version & Publish | ||
| - name: Build packages | ||
| run: | | ||
| LATEST=$(git describe --tags --abbrev=0) | ||
| npx lerna version $LATEST --force-publish --no-changelog --no-push --no-git-tag-version --yes | ||
| git commit -a -m 'DONT PUSH: fast-forward to latest npm release' --allow-empty --no-verify | ||
| npx lerna version --force-publish --no-changelog --conventional-commits --conventional-prerelease --preid beta --no-push --no-git-tag-version --yes | ||
| git commit -a -m 'DONT PUSH: version beta release' --allow-empty --no-verify | ||
| RELEASE=$(cat lerna.json | jq -r '.version') | ||
| npx lerna publish from-package --no-verify-access --pre-dist-tag beta --yes | ||
| git reset HEAD~2 --hard | ||
| git tag v$RELEASE | ||
| git push origin v$RELEASE | ||
| npm run clean --workspaces --if-present | ||
| npm run build:cjs --workspaces --if-present | ||
| npm run build:esm --workspaces --if-present | ||
| npm run build:umd --workspaces --if-present | ||
|
|
||
| - run: npx changeset publish --tag pr --no-git-tag | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| NPM_CONFIG_IGNORE_SCRIPTS: 'true' | ||
|
|
||
| - name: Update PR sticky header | ||
| uses: janniks/pull-request-fixed-header@57bc082ecbd040df344747d5b8644af5fad02c95 # v1.2.0 | ||
| with: | ||
| header: | | ||
| > This PR was published to npm with the version `${{ steps.snapshot.outputs.version }}` (dist-tag `pr`). | ||
| > e.g. `npm install @stacks/common@${{ steps.snapshot.outputs.version }} --save-exact` | ||
| pr-number: ${{ inputs.pr-number }} | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.