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
90 changes: 90 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
name: Publish

on:
pull_request_target:
types: [closed]

concurrency:
group: release-main
cancel-in-progress: false

jobs:
publish:
if: github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'main'
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write

steps:
- name: Determine release bump from labels
id: release_meta
uses: actions/github-script@v7
with:
script: |
const labels = (context.payload.pull_request.labels || []).map((label) => label.name);
const candidates = ["major", "minor", "patch"];
const matched = candidates.filter((candidate) => labels.includes(candidate));

if (matched.length === 0) {
core.notice("No release label found (major|minor|patch). Skipping publish.");
core.setOutput("should_release", "false");
return;
}

if (matched.length > 1) {
core.setFailed(`Multiple release labels found: ${matched.join(", ")}. Keep exactly one of major|minor|patch.`);
return;
}

core.info(`Selected release bump: ${matched[0]}`);
core.setOutput("should_release", "true");
core.setOutput("bump", matched[0]);

- uses: actions/checkout@v4
if: steps.release_meta.outputs.should_release == 'true'
with:
ref: main
fetch-depth: 0

- uses: actions/setup-node@v4
if: steps.release_meta.outputs.should_release == 'true'
with:
node-version: 20
cache: npm
registry-url: https://registry.npmjs.org

- run: npm ci
if: steps.release_meta.outputs.should_release == 'true'

- run: npm run check
if: steps.release_meta.outputs.should_release == 'true'
env:
ARENA_VCR_MODE: replay
ARENA_API_URL: https://staging-api.are.na

- name: Configure git author
if: steps.release_meta.outputs.should_release == 'true'
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"

- name: Bump version and create tag
id: version
if: steps.release_meta.outputs.should_release == 'true'
run: |
NEW_TAG="$(npm version "${{ steps.release_meta.outputs.bump }}" -m "release: %s")"
echo "tag=${NEW_TAG}" >> "$GITHUB_OUTPUT"

- name: Push release commit and tags
if: steps.release_meta.outputs.should_release == 'true'
run: git push origin HEAD:main --follow-tags

- run: npm publish --provenance --access public
if: steps.release_meta.outputs.should_release == 'true'

- name: Create GitHub Release
if: steps.release_meta.outputs.should_release == 'true'
env:
GH_TOKEN: ${{ github.token }}
run: gh release create "${{ steps.version.outputs.tag }}" --generate-notes
69 changes: 22 additions & 47 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,81 +2,56 @@

Use this checklist to cut a new npm release for `@aredotna/cli`.

Publishing is automated by GitHub Actions when a PR with a release label is merged to `main`.
Use exactly one label on the PR: `major`, `minor`, or `patch`.
The workflow bumps the version, publishes to npm with trusted publishing (OIDC), pushes the release commit and tag, and creates a GitHub Release.

## 1) Preflight

- [ ] Ensure you are on the intended release branch:
- [ ] Ensure release label is present on the PR:

```bash
git branch --show-current
gh pr view --json labels --jq '.labels[].name'
```

- [ ] Ensure working tree is clean:

```bash
git status --short
```
- [ ] Verify exactly one of `major|minor|patch` is set.

- [ ] Run full checks:
- [ ] (Optional) Run full checks locally before merge:

```bash
npm run check
```

## 2) Confirm npm auth

- [ ] Verify npm login:
## 2) Merge the PR to `main`

```bash
npm whoami
```

If this fails with `401 Unauthorized`, authenticate first:

```bash
npm login
```
- [ ] Merge the labeled PR.

## 3) Bump version

- [ ] Choose version type (`patch`, `minor`, `major`) and bump:

```bash
npm version patch
```

This updates `package.json`, creates a release commit, and creates a git tag.

## 4) Publish package

- [ ] Publish to npm:

```bash
npm publish
```
This triggers `.github/workflows/publish.yml`.

## 5) Push commit + tag
## 3) Confirm publish workflow success

- [ ] Push branch and tags:
- [ ] Wait for the "Publish" workflow on the pushed tag to complete successfully:

```bash
git push origin "$(git branch --show-current)" --follow-tags
gh run list --workflow publish.yml --limit 5
```

## 6) Verify release
## 4) Verify release

- [ ] Check published version:

```bash
npm view @aredotna/cli version
```

- [ ] Confirm tag exists remotely:
- [ ] Verify GitHub Release exists for the tag:

```bash
git ls-remote --tags origin | tail
VERSION="$(npm view @aredotna/cli version)"
gh release view "v${VERSION}"
```

## 7) Optional post-release smoke test
## 5) Optional post-release smoke test

- [ ] Install latest globally:

Expand All @@ -93,6 +68,6 @@ arena whoami --json

## Troubleshooting

- `npm whoami` fails with 401: run `npm login` and retry.
- `npm publish` says version exists: bump again (`npm version patch`) and republish.
- Push fails due to remote changes: rebase/merge branch, rerun checks, then push again.
- Publish job fails with OIDC/trusted publishing error: verify trusted publisher settings on npm exactly match `aredotna/cli` and workflow file `publish.yml`.
- Workflow skips publishing: merged PR did not contain one of `major`, `minor`, or `patch` labels.
- Workflow fails with multiple release labels: keep exactly one of `major|minor|patch` on the PR.
Loading