Skip to content

feat: switch to label-driven releases with workflow_dispatch escape hatch#160

Merged
kevwilliams merged 7 commits intomainfrom
feat/label-driven-release-workflow
Apr 2, 2026
Merged

feat: switch to label-driven releases with workflow_dispatch escape hatch#160
kevwilliams merged 7 commits intomainfrom
feat/label-driven-release-workflow

Conversation

@kevwilliams
Copy link
Copy Markdown
Contributor

Summary

  • Removes the release: published trigger (was the source of the circular tag problem)
  • Adds workflow_dispatch trigger with bump-type input (patch/minor/major) as an escape hatch for "I forgot to add the label"
  • Adds a detect-mode job that reads the merged PR's labels to decide dev vs release mode
  • Passes bump-type through to the reusable workflow so workflow_dispatch works without a PR to read labels from

How releases work now

Normal flow (merge with label):

  1. Add release, release:minor, or release:major label to the PR before merging
  2. Merge to main — CI detects the label, runs in release mode, bumps version, tags, publishes to npm, creates GitHub Release

Forgot the label (escape hatch):

  1. Go to Actions → "Publish UI to NPM" → Run workflow
  2. Choose bump type (patch/minor/major)
  3. Workflow runs in release mode manually

No label (default):

  • Publishes a dev build (x.y.z-dev.{sha}) to the @dev npm dist-tag only

Dependency

Requires datum-cloud/actions datum-cloud/actions#59 to be merged and tagged as v1.13.0 first — this workflow references that version.

Test plan

  • feat: extract version bumping into reusable bump-npm-version workflow actions#59 merged and tagged v1.13.0
  • Update the @v1.13.0 reference in this file once that tag exists
  • Merge a PR without a release label → confirm dev build published, no GH Release created
  • Merge a PR with release:minor label → confirm minor version bump + GH Release
  • Trigger workflow_dispatch with major → confirm major bump + GH Release

@kevwilliams kevwilliams requested a review from scotwells March 26, 2026 18:13
Comment on lines +9 to +13
bump-type:
description: "Version bump type"
type: choice
options: [patch, minor, major]
default: patch
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it's better to have the release version as an input and the workflow orchestrating this is the thing responsible for determining the version to create?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its effectively a shortcut for adding the release: label which gives less room for error and is only here for situations like when someone forgets to add the release:patch label to the PR before merging it and needs to run it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just meant that maybe the release version should be an input to this pipeline and not have the npm job be responsible for determining the release version. Ideally that's done by whatever is calling this repo since that version number needs to be consistent across many steps.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok good call ive rearchitected this a bit more along these lines, it still has a job that does it but the publish-npm-job now just does build and publish

new flow looks like this

push to main (with release label) or workflow_dispatch                                                                                                                                     
    │                                                                                                                                                                                        
    ├── detect-mode        → release-mode, bump-type                                                                                                                                         
    │                                                                                                                                                                                        
    ├── bump-version       → npm version patch/minor/major                                                                                                                                   
    │     owns:              git commit + tag + push to main                                                                                                                                 
    │     outputs:           new-version (e.g. v0.3.2)                                                                                                                                       
    │                                                                                                                                                                                        
    ├── publish            → checkout main (already has bumped package.json)                                                                                                                 
    │     reusable workflow: build + npm publish only, no git ops                                                                                                                            
    │                                                                                                                                                                                        
    └── create-release     → gh release create v0.3.2                                                                                                                                        
          depends on:        bump-version output (not publish)                                                                                                                     ```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wonder if we should have this be a manually triggered workflow? What if we want to merge in multiple features to a single release before pushing out.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure we can remove the label detection and just stick with workflow_dispatch as the release trigger

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok done now

  • Every push to main → dev build (@dev dist-tag)
  • workflow_dispatch → pick patch/minor/major → bump, tag, publish @latest, create GitHub Release

- Add bump-version job: owns npm version, git tag, and push to main
- The publish job receives the version already set in package.json
- The create-release job depends on bump-version output, not publish
- Remove bump-type pass-through to reusable workflow (no longer needed)
- The reusable workflow now only builds and publishes
Every push to main publishes a dev build. Stable releases are triggered
explicitly via workflow_dispatch, allowing multiple PRs to be batched
into a single release before shipping.
Comment on lines +30 to +78
# Runs only on manual dispatch. Bumps the version in package.json, commits,
# creates the git tag, and pushes to main. All downstream jobs read the
# version from this job's output — the npm publish workflow receives it
# already set in package.json.
bump-version:
name: Bump version
if: github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
new-version: ${{ steps.bump.outputs.new-version }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: main

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
package_json_file: ui/package.json

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 24
cache: pnpm
cache-dependency-path: ui/pnpm-lock.yaml

- name: Configure git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

- name: Bump version and push tag
id: bump
working-directory: ui
env:
BUMP_TYPE: ${{ inputs.bump-type }}
run: |
if [[ "$BUMP_TYPE" != "major" && "$BUMP_TYPE" != "minor" && "$BUMP_TYPE" != "patch" ]]; then
echo "::error::Invalid bump-type '$BUMP_TYPE'. Must be major, minor, or patch."
exit 1
fi
NEW_VERSION=$(npm version "$BUMP_TYPE" \
--message "chore: release @datum-cloud/activity-ui v%s [skip ci]")
echo "new-version=${NEW_VERSION}" >> "$GITHUB_OUTPUT"
git push origin main --follow-tags
Copy link
Copy Markdown
Contributor

@scotwells scotwells Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thoughts on moving this to the shared actions repo as a bump-npm-version job? Seems valuable to re-use across repos. Can we also have a separate step that takes the bump type and turns it into the version that's being released? Want to de-couple those concepts since the npm workflow shouldn't be responsible for determining what the next version should be.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — moved to datum-cloud/actions as a new bump-npm-version.yaml reusable workflow (added to PR #59 there). The workflow has two distinct steps: resolve-version computes the new version string from package.json + bump-type using inline Node.js (no git ops), then bump-version runs npm version + git push. The new-version output is set from the resolve step so callers get the version string independently of the git operations.

publish-ui-npm.yaml here is now just a 5-line uses: call that passes package-path, package-name, and bump-type — no more inline steps.

@kevwilliams kevwilliams requested a review from scotwells March 27, 2026 22:34
kevwilliams added a commit to datum-cloud/actions that referenced this pull request Apr 2, 2026
…#59)

## Summary

- Removes version bumping, git tagging, and PR label detection from
\`publish-npm-package\`'s \`publish-release\` job — it now only builds
and publishes whatever version is already in \`package.json\`
- Removes GitHub Release creation from \`publish-npm-package\` — callers
are responsible for this
- Adds a new \`bump-npm-version.yaml\` reusable workflow that owns the
full version bump lifecycle:
1. **resolve-version** — computes the new version string from
\`package.json\` + \`bump-type\` using inline Node.js (no git ops);
outputs \`new-version\` (e.g. \`v1.3.0\`)
  2. **bump** — runs \`npm version\`, creates the commit and tag
  3. **push** — \`git push origin main --follow-tags\`

## Motivation

The previous \`publish-release\` job did too much: it detected bump type
from PR labels, bumped the version, pushed the tag, built, and published
— all in one job. This made it hard to reuse across repos and coupled
version calculation to the publish step.

The new design separates concerns:
- **bump-npm-version** owns the git side (version resolution → commit →
tag → push)
- **publish-npm-package** owns the npm side (build → publish)

Callers compose them as sequential jobs, passing \`new-version\` between
them. The resolved version is available as an output before any git
operations run.

## Dependency

\`datum-cloud/activity\` PR #160 references \`v1.13.0\` of both
\`bump-npm-version.yaml\` and \`publish-npm-package.yaml\` — this PR
should be merged and tagged \`v1.13.0\` first.

## Test plan

- [ ] Merge this PR and cut tag \`v1.13.0\`
- [ ] Merge datum-cloud/activity#160 which references \`v1.13.0\`
- [ ] Trigger \`workflow_dispatch\` on activity with \`bump-type=minor\`
→ confirm minor bump commit, tag, npm publish, and GitHub Release all
created correctly
- [ ] Push to activity main without dispatch → confirm only dev build
published, no release created
@kevwilliams kevwilliams merged commit 9fb61b4 into main Apr 2, 2026
7 checks passed
@kevwilliams kevwilliams deleted the feat/label-driven-release-workflow branch April 2, 2026 15:57
kevwilliams added a commit to datum-cloud/actions that referenced this pull request Apr 2, 2026
## Summary

`bump-npm-version.yaml` never runs `pnpm install`, so `setup-node` with
`cache: pnpm` fails at teardown because the cache directory doesn't
exist:

```
Path Validation Error: Path(s) specified in the action for caching do(es) not exist, hence no cache is being saved.
```

This caused the `Post Setup Node.js` step to fail in
datum-cloud/activity#160.

## Changes

- Remove `pnpm/action-setup` step — not needed when there's no install
- Remove `cache: pnpm` and `cache-dependency-path` from `setup-node` —
same reason
- Remove `lockfile-path` input — only existed to support pnpm caching

The workflow only needs Node.js to read `package.json` (version
resolution) and run `npm version` (bump + tag).

## Test plan

- [ ] Merge and tag `v1.13.1`
- [ ] Re-run the failing workflow in datum-cloud/activity — `Post Setup
Node.js` should no longer fail
kevwilliams added a commit that referenced this pull request Apr 2, 2026
Fixes the `Post Setup Node.js` cache failure introduced in #160.

`bump-npm-version.yaml` never runs `pnpm install`, so `setup-node` with
`cache: pnpm` failed at teardown because the cache directory didn't
exist. datum-cloud/actions#60 removed the pnpm cache from that workflow
and was released as `v1.13.1`.

## Test plan
- [ ] Trigger `workflow_dispatch` on this branch → `Post Setup Node.js`
no longer fails
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants