| name | n8n-nodes-hookdeck-release |
| description | Guides maintainers through releases of @hookdeck/n8n-nodes-hookdeck (stable from main, beta from main or a feature branch) and user-centric GitHub release notes. Validates the proposed version against SemVer as an n8n community node reads it, where a renamed node type or credential breaks saved workflows. Use when cutting a release, publishing a tag, drafting release notes, choosing MAJOR.MINOR.PATCH, npm publish, provenance, pre-releases, n8n verification, or `gh release create`. |
@hookdeck/n8n-nodes-hookdeck — release workflow
Canonical documentation
Follow CONTRIBUTING.md § Releasing for the human steps. This
skill adds how automation works, what counts as breaking for an n8n node,
and a research loop for drafting notes.
Agents: publish with the GitHub CLI — see Publish with gh below.
Agent checklist (end-to-end)
Follow in order. Items marked gate are blocking unless the maintainer
explicitly overrides.
What triggers a release
.github/workflows/publish.yml runs on
release: published — not on a tag push, and not on a branch push. Creating the
release in the GitHub UI or with gh release create creates the tag and starts
the workflow together.
The workflow checks out the release tag, fails if the tag does not match
version in package.json, then re-runs lint, scan, build, the load check and
the unit tests, then npm publish --provenance. A pre-release publishes
under the beta dist-tag so npm install @hookdeck/n8n-nodes-hookdeck keeps
resolving to the last stable version.
package.json is the version and the tag agrees with it. The bump lands on
main in the release PR, before the release exists — never as a follow-up
commit after publishing, which leaves a window where main and npm disagree.
That window is exactly what n8n flagged in the 0.2.0 review, when main still
read 0.1.0.
If the guard fails, the release is already created and the tag already exists.
Bump package.json on main, then delete both and recreate the release:
gh release delete v0.3.0 --repo hookdeck/n8n-nodes-hookdeck --cleanup-tag --yes
Editing the failed release does not re-run the workflow — it fires on
release: published.
Auth: provenance is not trusted publishing
Two things, easily conflated:
- Provenance — the signed attestation tying the package to this repo,
workflow and commit. Needs
id-token: write. This is what n8n requires.
- Trusted publishing — publishing with a short-lived OIDC token instead of a
long-lived npm token. Not required by n8n, and how this package publishes.
The workflow contains no token handling. npm >= 11.5.1 finds the trusted
publisher itself and exchanges the Actions OIDC token during publish, so there
is nothing to inject.
Never add an NPM_TOKEN secret. It is not a fallback: any credential in
.npmrc takes precedence over OIDC, so a stale or empty secret becomes the
publishing identity, or fails the publish.
The trusted publisher is already configured (owner hookdeck, repo
n8n-nodes-hookdeck, workflow publish.yml, environment blank). Leave the
environment blank — publish.yml declares no environment:, and npm matches
the OIDC claim exactly.
Publishing by hand is blocked: prepublishOnly runs n8n-node prerelease,
which exits unless RELEASE_MODE is set. Do not set it to work around a failing
release — a hand publish carries no provenance, which is what n8n requires.
What breaks an n8n node
SemVer here is about the contract with a saved workflow, not just the API
surface. n8n stores the node type, the credential name and every parameter name
inside the user's workflow JSON. Renaming any of them does not fail a build — it
silently detaches existing workflows.
Change since PREV_TAG | Bump | Examples |
|---|
| Breaking — an existing published workflow stops working or loses configuration | MAJOR | Renaming a node type (hookdeckEventGateway), renaming the credential type (hookdeckEventGatewayApi), renaming or removing a parameter, removing a resource or operation, changing the shape of the trigger's output item, changing a default in a way that alters delivery behaviour |
| New capability, backward compatible | MINOR | New resource or operation, new option, new source types, additive fields on the output item, a new delivery route that existing workflows are not moved onto |
| Fixes, docs, internals | PATCH | Bug fixes, wording, icons, tests, CI, dependency bumps, generated source-type refreshes |
Before 1.0.0, a MINOR bump is the strongest signal available for a breaking
change, so say so loudly in the notes rather than relying on the number.
Ask, do not guess. If it is unclear whether a change detaches an existing
workflow, ask the maintainer before tagging. The cost of over-bumping is a
version number; the cost of under-bumping is someone's production workflow.
The node-identity check, concretely
git diff PREV_TAG..HEAD -- nodes credentials \
| grep -E '^[-+]\s+(name:|displayName:)' | sort | uniq -c | sort -rn | head -20
Any - name: '...' paired with a + name: '...' in a node description, a
credential class or a property is a candidate break. Read it, do not skim it.
Stable release
-
Land everything, including the release PR that bumps package.json and
promotes the CHANGELOG, through PRs.
-
Confirm main is green:
SHA=$(git rev-parse origin/main)
gh api graphql -f query='
query($owner:String!,$repo:String!,$sha:GitObjectID!){
repository(owner:$owner,name:$repo){
object(oid:$sha){ ... on Commit { statusCheckRollup { state } } }
}
}' -F owner=hookdeck -F repo=n8n-nodes-hookdeck -F sha="$SHA" \
--jq '.data.repository.object.statusCheckRollup.state'
Do not release on FAILURE, or on PENDING for required checks. The states
are uppercase.
Use the rollup, not gh api .../commits/${SHA}/status. That endpoint reads
legacy commit statuses, which GitHub Actions does not write, so it returns
pending however green CI is.
-
Create the release targeting main (see Publish with gh).
Pre-release (beta)
Tag as v0.3.0-beta.1, with package.json set to the same 0.3.0-beta.1 on
the branch being released. The base version still has to satisfy the table
above relative to the last stable release — a beta containing a breaking change
is v1.0.0-beta.1, not v0.9.0-beta.1.
- From
main: --target main --prerelease. Still requires green CI.
- From a feature branch:
--target <branch> --prerelease. Requires green CI
on that branch, and the notes should say what to test.
Install with npm install @hookdeck/n8n-nodes-hookdeck@beta.
Publish with gh
Create the release, not a bare tag: the release carries the notes and is what
the workflow listens for.
-
Write the notes to a temp file, with cleanup registered up front:
NOTES_FILE="$(mktemp "${TMPDIR:-/tmp}/n8n-nodes-hookdeck-notes.XXXXXX.md")"
trap 'rm -f "$NOTES_FILE"' EXIT
-
Write the final markdown body to "$NOTES_FILE".
-
Create the release:
gh release create "v0.2.0" \
--repo hookdeck/n8n-nodes-hookdeck \
--target main \
--title "v0.2.0" \
--notes-file "$NOTES_FILE"
Add --prerelease for a beta, and --target <branch> for a branch beta.
-
Confirm the workflow ran and the package landed:
gh run list --repo hookdeck/n8n-nodes-hookdeck --workflow Publish --limit 1
npm view @hookdeck/n8n-nodes-hookdeck dist-tags
Never put a secret in the notes. The release body is public.
Drafting release notes
Start from
references/release-notes-template.md.
Write for someone running a workflow, not someone reading the diff. "Events are
no longer lost when the CLI restarts" beats "changed teardown from delete to
disable".
Include only headings with real content. Do not write "Breaking changes:
none".
Always end with:
**Full Changelog**: https://github.com/hookdeck/n8n-nodes-hookdeck/compare/<PREV_TAG>...<NEW_TAG>
Say what a user must do. If a release changes delivery behaviour, needs a
workflow republished to take effect, or requires the Hookdeck CLI to be
restarted, that belongs at the top, not in a bullet halfway down.
Contributors: only call out a new contributor shipping their first work,
or an exceptionally large contribution. No generic thanks block.
Research loop
- Tags:
git describe --tags --abbrev=0 on the target branch, or ask.
- Commits:
git log PREV_TAG..HEAD --oneline, then read the full messages.
This repo writes long commit messages that explain why — use them; they are
usually closer to release-note prose than the diff is.
- Group by user impact, merging related commits.
- SemVer check against the table above, plus the node-identity check.
- PRs:
gh pr list --state merged --search "merged:>=<date>" for links.
- Sanity: if a commit is unclear, read the README section it changed —
user-facing behaviour is documented there.
- gate — CI on the branch being released.
Safety
- Do not release with a failing
npm run scan. It is the same rule set n8n runs
for verification, and a failure there is a rejected submission.
- Do not under-bump. A renamed node type in a PATCH release detaches workflows
silently.
- Do not publish from a laptop. n8n requires provenance from GitHub Actions, and
a local
npm publish produces none.
- Do not tag a version that
package.json on the target branch does not carry.
The workflow stops it, and the fix costs a deleted release and tag.
- Respect branch protection; no surprise tags.
Related files