-
Notifications
You must be signed in to change notification settings - Fork 88
ci: add release-prepare and release-publish workflows for npm releases #2206
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
base: refactor
Are you sure you want to change the base?
Changes from all commits
60e4030
aadd9a6
126ddf9
c967ad3
710a837
cef6488
a9ed7b2
59fa397
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| # Opens the release PR: bumps package.json, refreshes the vended @aws/agentcore-cdk pin, and pushes | ||
| # release/v<version>. Merging that PR is the release approval and triggers release-publish.yml. | ||
| name: release-prepare | ||
| on: | ||
| workflow_dispatch: | ||
| inputs: | ||
| bump: | ||
| description: Semver component to release. Ignored while an rc series is open, which continues or graduates instead. | ||
| required: true | ||
| type: choice | ||
| options: [major, minor, patch] | ||
| channel: | ||
| description: rc publishes under the rc dist-tag, stable under latest | ||
| required: true | ||
| type: choice | ||
| options: [rc, stable] | ||
|
|
||
| jobs: | ||
| prepare: | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| with: | ||
| fetch-tags: true | ||
| persist-credentials: false | ||
| - uses: oven-sh/setup-bun@v2 | ||
| - uses: actions/create-github-app-token@v3 | ||
| id: app-token | ||
| with: | ||
| app-id: ${{ vars.APP_ID }} | ||
| private-key: ${{ secrets.APP_PRIVATE_KEY }} | ||
|
|
||
| - name: Bump version | ||
| id: version | ||
| env: | ||
| BUMP: ${{ inputs.bump }} | ||
| CHANNEL: ${{ inputs.channel }} | ||
| run: | | ||
| set -euo pipefail | ||
| CURRENT=$(bun pm pkg get version | tr -d '"') | ||
| # 0.28.1 -> 1.0.0-rc.0 -> 1.0.0-rc.1 -> 1.0.0. Bun's own "major" would jump an rc to 2.0.0. | ||
| if [[ "$CURRENT" == *-rc.* ]]; then | ||
| INCREMENT=$([ "$CHANNEL" = rc ] && echo prerelease || echo "${CURRENT%%-*}") | ||
| else | ||
| INCREMENT=$([ "$CHANNEL" = rc ] && echo "pre$BUMP" || echo "$BUMP") | ||
| fi | ||
| TAG=$(bun pm version "$INCREMENT" --preid rc --no-git-tag-version) | ||
| if git rev-parse -q --verify "refs/tags/$TAG" >/dev/null; then | ||
| echo "::error::$TAG is already released" | ||
| exit 1 | ||
| fi | ||
| echo "version=${TAG#v}" >> "$GITHUB_OUTPUT" | ||
|
|
||
| - run: bun scripts/sync-vended-cdk.ts | ||
|
|
||
| - name: Open release PR | ||
| env: | ||
| GH_TOKEN: ${{ steps.app-token.outputs.token }} | ||
| VERSION: ${{ steps.version.outputs.version }} | ||
| run: | | ||
| set -euo pipefail | ||
| BRANCH="release/v$VERSION" | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "github-actions[bot]@users.noreply.github.com" | ||
| git commit -am "chore(release): v$VERSION" | ||
| git push --force "https://x-access-token:$GH_TOKEN@github.com/$GITHUB_REPOSITORY.git" "HEAD:refs/heads/$BRANCH" | ||
|
|
||
| if [ -z "$(gh pr list --base "$GITHUB_REF_NAME" --head "$BRANCH" --json number --jq '.[0].number')" ]; then | ||
| gh pr create --base "$GITHUB_REF_NAME" --head "$BRANCH" --title "chore(release): v$VERSION" \ | ||
| --body "Merging publishes \`@aws/agentcore@$VERSION\` to npm and creates the \`v$VERSION\` GitHub release with generated notes." | ||
| fi |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| # Publishes @aws/agentcore to npm and creates the GitHub release when a release PR from | ||
| # release-prepare.yml merges. The version is whatever the merged package.json says. | ||
| name: release-publish | ||
| on: | ||
| pull_request: | ||
| types: [closed] | ||
| # TODO: switch to main once the refactor lands there. | ||
| branches: [refactor] | ||
| workflow_dispatch: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why do we need workflow dispatch here? |
||
| inputs: | ||
| dry_run: | ||
| description: Build, pack and compile, but skip npm publish and the GitHub release | ||
| type: boolean | ||
| default: true | ||
|
|
||
| jobs: | ||
| check: | ||
| if: github.event_name == 'workflow_dispatch' || (github.event.pull_request.merged && startsWith(github.head_ref, 'release/v')) | ||
| uses: ./.github/workflows/check.yml | ||
| permissions: | ||
| contents: read | ||
| with: | ||
| ref: ${{ github.event.pull_request.merge_commit_sha || github.sha }} | ||
| build: | ||
| if: github.event_name == 'workflow_dispatch' || (github.event.pull_request.merged && startsWith(github.head_ref, 'release/v')) | ||
| uses: ./.github/workflows/build.yml | ||
| permissions: | ||
| contents: read | ||
| with: | ||
| ref: ${{ github.event.pull_request.merge_commit_sha || github.sha }} | ||
| unit-test: | ||
| if: github.event_name == 'workflow_dispatch' || (github.event.pull_request.merged && startsWith(github.head_ref, 'release/v')) | ||
| uses: ./.github/workflows/unit-test.yml | ||
| permissions: | ||
| contents: read | ||
| with: | ||
| ref: ${{ github.event.pull_request.merge_commit_sha || github.sha }} | ||
|
|
||
| publish: | ||
| needs: [check, build, unit-test] | ||
| # npm provenance is only issued from GitHub-hosted runners. | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write | ||
| id-token: write | ||
| env: | ||
| REF: ${{ github.event.pull_request.merge_commit_sha || github.sha }} | ||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| with: | ||
| ref: ${{ env.REF }} | ||
| fetch-tags: true | ||
| persist-credentials: false | ||
| - uses: oven-sh/setup-bun@v2 | ||
| - uses: actions/setup-node@v6 | ||
| with: | ||
| node-version: 20.x | ||
| registry-url: https://registry.npmjs.org | ||
| - run: bun install --frozen-lockfile | ||
|
|
||
| - name: Resolve release | ||
| id: release | ||
| run: | | ||
| set -euo pipefail | ||
| VERSION=$(bun pm pkg get version | tr -d '"') | ||
| # rc notes span from the previous rc, stable notes from the previous stable. Only this | ||
| # workflow's tags count, main's v1.0.0-preview.N tags live in the same repo. | ||
| DIST_TAG=latest | ||
| SEMVER_FLAGS=() | ||
| if [[ "$VERSION" == *-rc.* ]]; then | ||
| DIST_TAG=rc | ||
| SEMVER_FLAGS=(--include-prerelease) | ||
| fi | ||
| PREVIOUS=$(git tag -l 'v*' | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+(-rc\.[0-9]+)?$' \ | ||
| | xargs bunx semver "${SEMVER_FLAGS[@]}" --range "<$VERSION" | tail -1) | ||
| { | ||
| echo "version=$VERSION" | ||
| echo "dist_tag=$DIST_TAG" | ||
| echo "previous_tag=v$PREVIOUS" | ||
| } >> "$GITHUB_OUTPUT" | ||
|
|
||
| - run: bun run build | ||
| - id: pack | ||
| run: echo "tarball=$(bun pm pack --quiet --ignore-scripts)" >> "$GITHUB_OUTPUT" | ||
| - run: bun run compile | ||
|
|
||
| - if: ${{ !inputs.dry_run }} | ||
| env: | ||
| NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | ||
| VERSION: ${{ steps.release.outputs.version }} | ||
| DIST_TAG: ${{ steps.release.outputs.dist_tag }} | ||
| TARBALL: ${{ steps.pack.outputs.tarball }} | ||
| # A rerun after a failed release step must not republish, npm rejects an existing version. | ||
| run: | | ||
| if npm view "@aws/agentcore@$VERSION" version >/dev/null 2>&1; then | ||
| echo "@aws/agentcore@$VERSION is already on npm, skipping publish" | ||
| else | ||
| npm publish "$TARBALL" --provenance --access public --tag "$DIST_TAG" | ||
| fi | ||
|
|
||
| - if: ${{ !inputs.dry_run }} | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| VERSION: ${{ steps.release.outputs.version }} | ||
| PREVIOUS_TAG: ${{ steps.release.outputs.previous_tag }} | ||
| TARBALL: ${{ steps.pack.outputs.tarball }} | ||
| # A rerun after a failed asset upload re-uploads into the existing release instead of failing on the tag. | ||
| run: | | ||
| if gh release view "v$VERSION" >/dev/null 2>&1; then | ||
| gh release upload "v$VERSION" --clobber "$TARBALL" dist/bin/* | ||
| else | ||
| gh release create "v$VERSION" --target "$REF" --title "v$VERSION" \ | ||
| --generate-notes --notes-start-tag "$PREVIOUS_TAG" \ | ||
| ${{ steps.release.outputs.dist_tag == 'rc' && '--prerelease' || '--latest' }} \ | ||
| "$TARBALL" dist/bin/* | ||
| fi | ||
|
|
||
| - if: ${{ inputs.dry_run }} | ||
| uses: actions/upload-artifact@v7 | ||
| with: | ||
| name: release-${{ steps.release.outputs.version }} | ||
| path: | | ||
| ${{ steps.pack.outputs.tarball }} | ||
| dist/bin/* | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,10 @@ | ||
| { | ||
| "name": "agentcore", | ||
| "version": "1.0.0", | ||
| "name": "@aws/agentcore", | ||
| "version": "0.28.1", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. are we releasing under 1.0.0-rc or the previous version number?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we want to do 1.0.0-rc.1 |
||
| "repository": { | ||
| "type": "git", | ||
| "url": "https://github.com/aws/agentcore-cli.git" | ||
| }, | ||
| "module": "src/index.ts", | ||
| "type": "module", | ||
| "bin": { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| #!/usr/bin/env bun | ||
|
|
||
| /** | ||
| Pins the vended CDK template to the published @aws/agentcore-cdk at the given dist-tag (default latest). | ||
| Runs before bun install in release-prepare.yml, so it must not import anything from src/. | ||
| **/ | ||
|
|
||
| import { $ } from "bun"; | ||
| import { join, resolve } from "node:path"; | ||
|
|
||
| const CDK_PACKAGE = "@aws/agentcore-cdk"; | ||
| const TEMPLATE = Bun.file( | ||
| join(resolve(import.meta.dir, ".."), "src", "assets", "cdk", "package.json"), | ||
| ); | ||
|
|
||
| const tag = Bun.argv[2] ?? "latest"; | ||
| const target = (await $`bun pm view ${CDK_PACKAGE}@${tag} version`.text()).trim(); | ||
| const template = await TEMPLATE.json(); | ||
| const current = template.dependencies[CDK_PACKAGE]; | ||
|
|
||
| if (current === target) { | ||
| console.log(`${CDK_PACKAGE} already pinned to ${target}`); | ||
| } else { | ||
| template.dependencies[CDK_PACKAGE] = target; | ||
| await Bun.write(TEMPLATE, JSON.stringify(template, null, 2) + "\n"); | ||
| console.log(`${CDK_PACKAGE}: ${current} → ${target}`); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we take the opportunity to put all of these in one. That will be much more efficient and will save time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Harrison and TJ seemed to think that the release workflow
From the SDKs made a lot of sense. So I restructured it to be like those, it was originally one file.
Let's discuss
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think alex's comment is in reference to the check/build/unit-test workflows which are always run together, so I think the suggestion is to make it a single workflow containing check, build, and unit-test as jobs.
My understanding is that the runtime behavior would be the same, but we no longer need to manually wire in each job as a separate call. Instead, we call a single workflow that triggers all three, so it'd simplify some of the changes here.