@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.
- Release shape: stable from
main, beta frommain, or beta from a feature branch. Confirm with the maintainer. -
PREV_TAG/NEW_TAG: agreed. For a beta series the baseline is usually the last stable tag, not the last beta. - Change set:
git log PREV_TAG..HEADread in full, grouped by user impact (see Research loop). - gate — SemVer: the proposed tag matches the minimum bump the delta requires (see What breaks an n8n node). Stop and realign if under-bumped.
- gate — node identity unchanged: no node
name, credentialnameor parameternamechanged since the last stable release without a MAJOR bump and a migration note. These are recorded in saved workflows. - gate — verification scan:
npm run scanpasses. A release that fails it would fail n8n's review. - gate — CI green: the commit being released has green checks. For a
stable release that means the tip of
main. - gate — release PR merged:
versioninpackage.jsonset to the new version and## [Unreleased]in the CHANGELOG promoted to that version with a date, in one normal PR before the release. The publish workflow refuses a tag that disagrees withpackage.json, and n8n's verification review comparesmainagainst npm. - Notes drafted: see Drafting release notes and references/release-notes-template.md. Include the Full Changelog compare link.
- gate — approval: the maintainer has signed off on the version, the notes and the target branch. Never push a surprise tag.
- Publish: notes to a temp file →
gh release create→ remove the temp file.--prereleasefor betas. - Post-publish: the Publish workflow succeeded, and the version is on npm under the expected dist-tag.
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.jsonand promotes the CHANGELOG, through PRs.Confirm
mainis 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 onPENDINGfor 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 returnspendinghowever green CI is.Create the release targeting
main(see Publish withgh).
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"' EXITWrite 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
--prereleasefor 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=0on 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 publishproduces none. - Do not tag a version that
package.jsonon 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
| Topic | Location |
|---|---|
| Human steps | CONTRIBUTING.md § Releasing |
| Publish workflow | .github/workflows/publish.yml |
| CI | .github/workflows/ci.yml |
| Live API tests | .github/workflows/integration.yml |
| Change history | CHANGELOG.md |
| Notes template | references/release-notes-template.md |