18 KiB
name, description, triggers, role
| name | description | triggers | role | |||||
|---|---|---|---|---|---|---|---|---|
| release | Use ONLY when ready to cut a release. The Release Manager (Worker) inspects project state (git log, version files, build) to determine the semver bump, generate the changelog, tag, and produce a release artifact. Works on any project state 鈥?no pipeline artifacts required. |
|
Producer |
Core 涓珛鐗堬紙Increment 6a 鏀瑰啓锛屽師 deferHard verbatimDir锛夈€傛満鍒躲€佺粨鏋勪笌 frontmatter 淇濇寔锛涘疄渚嬫湳璇紙宸ュ叿鍚嶃€佽矾寰勩€佸伐鍗曞彿锛夋寜
core/adapters/TERMINOLOGY.md缁戝畾鍒板叿浣撳疄渚嬨€?
Release
Prepare and tag a release based on project facts 鈥?git history since the last
tag, current version, build status, and dependency health. No dependency on .artifacts/{slug}/
(deprecated 鈥?SDLC artifacts now live in the Gitea wiki at {slug}/...;
see _shared/gitea-read-patterns.md) or any pipeline skill outputs.
This SKILL does not deploy. Deployment is project-specific (K8s, Docker, npm publish, etc.) and varies too widely to template. The release artifact produced here is the input to project-specific deployment workflows.
Agent Role
The release is owned and executed by the Release Manager (Worker).
Context compaction: release is a pipeline stage boundary. The main session
compacts at this clean boundary ONLY when a capacity/projection trigger holds,
per core/rules/compact.md 搂"Stage-boundary compaction" (long multi-stage
runs 鈥?DAG Epic orchestration 鈥?keep the legacy every-boundary compaction;
short runs 鈥?bugfix / DAG task 鈥?and standalone runs default to NOT
compacting). The Release Manager itself is single-phase and
artifact-driven (version files, changelog, tag); a mid-run compaction loses
nothing 鈥?re-read the release checklist state and git log to resume.
Preconditions
Before starting the release:
- Working tree is clean (
git statushas no uncommitted changes). core/checklists/release.mdis accessible.
Phase 1 鈥?Pre-release Gate
Run each check against the live project. Stop and report failures.
- Clean workspace:
git statusmust show nothing to commit. - Branch: confirm the current branch. Default assumption: release from
mainormaster. If on another branch, note it. - Build: run the project's build command. Must pass.
- Typecheck + Lint: run the project's typecheck and lint. Must pass.
- Tests: run the project's test suite. Must pass.
- Dependency audit: run the project's vulnerability scanner
(e.g.
npm audit,bun audit,pip-audit,cargo audit).- No new HIGH or CRITICAL CVEs block the release.
- Pre-existing HIGH/CRITICAL CVEs do NOT block but MUST be filed as tech-debt before the release lands. File them in TWO TIERS (batching rule, [org-internal #3846] 鈥?a single release audit once fanned out to 14 TDs 鈫?14 PRs 鈫? 56-84 CI runs on a saturated runner pool): Tier A below is the general mechanical-change batching rule; Tier B and the escape hatch follow it.
Tier A 鈥?閫氱敤鏈烘鍙樻洿骞跺崟瑙勫垯 / Universal mechanical-change batching rule
Origin [org-internal #3846] (audit-batch pilot, generalized in place): the rule covers ANY single-source fan-out of mechanical changes, not just dependency audits. Two source types today: (a) dependency bump audits; (b) docs 鎵归噺淇 (batch docs revisions).
瑙勫垯姝f枃 / Rule text
- Core: mechanical changes of ONE class fanning out from a single source are filed as ONE batch issue + ONE batch PR 鈥?never N脳issue + N脳PR. The batch body keeps one row per item (per-CVE / per-doc mapping), so per-item traceability is unchanged; work the batch as a single PR.
- (a) Dependency bump audits (the [org-internal #3846] origin case): advisories whose
remediation is a plain version bump (lockfile-only diff, no semver-major
jump, no overrides/catalog surgery, no API or adapter fallout) are filed
together via
宸ュ崟 API锛堣 TERMINOLOGY锛塩reatewithtitle="[{origin}] audit-batch@{version}: mechanical bumps for {N} advisories (TD-{NNN})"and labels[tech_debt_label_id, severity_label_id, kind_bug_label_id](severity = highest in the batch). One row per advisory 鈥?CVE/GHSA ID, affected package + from鈫抰o version, severity (CVSS), advisory URL, recommended remediation, and a per-advisory Reactivation Trigger ("resolved whennpm audit/bun auditreports no HIGH/CRITICAL for this advisory") 鈥?so the release-notesTD-NNN 鈫?#NNNNmapping stays per-advisory. - (b) Docs 鎵归噺淇 (batch docs revisions): many small same-class docs
corrections discovered in one pass (e.g. a terminology sweep) file as ONE
issue via the same flow,
title="[{origin}] docs-batch: {class} revisions for {N} files", with one row per file (path, correction, reason); same ONE-batch-PR landing. - Landing: when members live on separate branches, compose the single
batch PR via the
land-batchskill (core/skills/land-batch/SKILL.md鈥?cross-branch batch composition, topology B). For dependency-bump batches passbatch-compose --convergent bun.lock(script.gitea/scripts/batch-compose.ts): the regenerable lockfile is exempt from path-overlap admission and lockfile-only conflicts are surgically resolved to the running head's version.
閫傜敤杈圭晫 / Applicability boundary
- 闈?mechanical锛堝惈鍒ゆ柇鎴愬垎鐨勫彉鏇达紝涓嶅苟鍗曪級 鈥?items requiring judgment (wording decisions, behavior/API changes, review-dependent edits) are never batched; file each as its own issue.
- *璺緞閲嶅彔锛坆atch 鎴愬憳瑙︾鐩稿悓鏂囦欢 鈫?涓嶅苟鍗曪紱鍞竴璞佸厤 =
鍙啀鐢熷叡浜枃浠?
bun.lock缁?batch-compose--convergent鏀舵暃锛? 鈥?the sole path-overlap exemption is the regenerable shared lockfile under--convergent; every other same-file collision stays un-batched. - *semver-major 璺冲彉 / overrides路catalog 鎵嬫湳 / adapter路peer 鑱斿姩锛堚啋 Tier B 鐙珛鍗曪紝缁存寔 per-package锛? 鈥?these stay per-package Tier B issues. Tier B and the escape hatch (below) survive this generalization unchanged.
闄嶇骇璺緞 / Degradation path
- **骞跺崟 PR CI 澶辫触 鈫?鎸夐攣鏂囦欢 hunk 鎷嗗寘鍥為€€锛坆isect锛?*: for dependency batches, bisect by splitting lockfile hunks per package back into per-package PRs 鈥?the original Tier A bisect semantics carried over verbatim (鍚岃涔夛紝娉涘寲鎺緸: every mechanical batch degrades the same way).
- Docs batches: split per file back into per-file PRs.
- land-batch composition fallback (exit codes per
.gitea/scripts/batch-compose.ts):3path-overlap 鈫?split the batch along the reported pairs (or land the overlapping member 1:1) and re-run per group;4merge conflict /5transport/git error 鈫?fall back to 1:1 PRs for the whole batch. - Preflight hedge ([org-internal #3846]): run
bun install --dry-runbefore opening a dependency-batch PR 鈥?the resolver accepting the composed version set is a cheap pre-CI rejection of impossible bump combinations.
Tier B and the escape hatch (unchanged by the generalization):
- Tier B 鈥?surgery, one issue per package: semver-major jumps,
adapter/peer fallout, or overrides/catalog surgery keep the
per-package issue:
title="[{origin}] {CVE-ID/GHSA-ID} in {package} (TD-{NNN})"with the same labels; body requirements match the Tier A rows. - Escape hatch: either tier may carve a single advisory into its own issue when same-day remediation is required (urgent HIGH/CRITICAL).
De-duplicate against open tech-debt issues (match by
CVE/GHSA ID) before creating. Record the TD-NNN 鈫?#NNNN mapping in the
release notes. See verify Phase 5.5 for the tech-debt promotion body
template and _shared/gitea-write-patterns.md Pattern 3.
## Pre-release Gate
| Check | Status |
| ----------------- | ----------------------------------------------------- |
| Clean workspace | 鉁?/ 鉂? |
| Branch | {branch name} |
| Build | 鉁?/ 鉂? |
| Typecheck + Lint | 鉁?/ 鉂? |
| Tests | 鉁?/ 鉂?(N passed, M failed) |
| Dependency audit | 鉁?/ 鈿狅笍 N known CVEs (pre-existing) / 鉂?N new CVEs |
If any gate fails except known CVEs, stop and report what failed.
Phase 2 鈥?Version Bump
Determine the new version by inspecting git history since the last tag.
-
Find last tag:
git describe --tags --abbrev=0(orgit tag --sort=-v:refname | head -1).- No previous tag? This is the first tracked release. Use the initial commit as
baseline:
git rev-list --max-parents=0 HEAD. After tagging this release, create a retroactive baseline tag (v{base-version}) on the initial commit so future cycles have a clean{tag}..{tag}range. Document the gap in the release report.
- No previous tag? This is the first tracked release. Use the initial commit as
baseline:
-
Read commits since last tag:
git log <last-tag>..HEAD --oneline. -
Read current version from the project's version file (
package.jsonversion,Cargo.toml,VERSION, etc.). -
Categorize commits by change type:
Conventional prefix Semver Examples BREAKING CHANGE:/!:MAJOR API removal, schema change feat:MINOR New feature, new endpoint fix:PATCH Bug fix only perf:PATCH Performance improvement refactor:PATCH Internal restructuring docs:/chore:(skip) Not user-visible If no conventional prefix found, infer from the subject line:
- "add", "implement", "introduce" 鈫?MINOR
- "fix", "resolve", "correct" 鈫?PATCH
- "remove", "drop", "rename" (public API) 鈫?MAJOR
-
Compute bump:
- If any MAJOR commit 鈫?bump MAJOR.
- Else if any MINOR commit 鈫?bump MINOR.
- Else 鈫?bump PATCH.
## Version Bump
**Last tag**: {tag}
**Current version**: {old version}
**New version**: {new version}
**Type**: MAJOR / MINOR / PATCH
**Commits since last tag**: {N}
**Reason**: {justification 鈥?e.g. "2 feat + 3 fix 鈫?MINOR"}
Phase 3 鈥?Changelog
Generate the changelog from git log <last-tag>..HEAD:
- List all commits. For each, extract:
- Type (from prefix or inferred).
- Scope (if present, e.g.
feat(auth):). - Description (the subject line, past tense, human-readable).
- Group by type:
- Added 鈥?
feat:commits. - Changed 鈥?modifications to existing behavior (non-breaking).
- Fixed 鈥?
fix:commits. - Breaking 鈥?
BREAKING CHANGE:or!:commits.
- Added 鈥?
- Deduplicate: squash multiple commits for the same change into one entry where it makes narrative sense.
- Read the existing root
CHANGELOG.md(if any) and prepend this release.
Write to root CHANGELOG.md (prepend section).
## [{version}] 鈥?{YYYY-MM-DD}
### Added
- {feature} ({commit hash short})
### Changed
- {change} ({hash})
### Fixed
- {bugfix} ({hash})
### Breaking
- {breaking change} ({hash}) 鈥?see migration notes above
Phase 4 鈥?Tag & Finalize
- Update version file 鈥?write the new version to the project's version manifest.
- Commit:
git addversion file + changelog file, commit with message:release: {version} - Tag:
git tag v{version}(adjust prefix per project convention 鈥? check existing tags withgit tag -l). - Verify tag:
git tag -l v{version}confirms the tag exists.
Do not push 鈥?the user must explicitly request pushing to remote.
## Release Artifact
- **Version**: {version}
- **Commit**: {commit hash}
- **Tag**: v{version}
- **Changelog**: CHANGELOG.md updated
### Files Changed
| File | Change |
| -------------- | ------------------------- |
| {version file} | {old} 鈫?{new} |
| CHANGELOG.md | Prepended {version} |
Phase 4b 鈥?Publish Release Artifacts (octopus project, manual)
Octopus-specific. Other projects: substitute your own artifact pipeline 鈥? the goal is identical (turn the tag into downloadable assets).
The CI publish pipeline (.gitea/workflows/publish.yml) was retired by
[org-internal #2003] (138/138 historical runs cancelled; the pipeline sat unused for 35+
days). Releasing octopus is now a manual local process. All former CI
steps live in repo scripts, runnable from a maintainer machine with the right
credentials in the environment.
Prerequisites
- Clean checkout of the release commit (tag pushed or about to be pushed).
- Credentials in env:
GITEA_TOKEN鈥?PAT withwrite:repository(release create/undraft, tag push) andwrite:package(container registry). TheCI_PATsecret value is the canonical token.NODE_AUTH_TOKEN鈥?only if publishing to npm.AUR_KEY鈥?only if pushing the AUR package.- Docker logged in to the Gitea container registry:
echo "$GITEA_TOKEN" | docker login <instance-registry-host> -u <user> --password-stdin.
Steps
-
Version + draft release (idempotent 鈥?skips if already published):
GITEA_TOKEN=<pat> GH_REPO=Octopus/octopus bun script/version.tsCreates (or refines) the draft Gitea release for
v{version}. -
Build the 12 platform binaries + archives (longest step):
OCTOPUS_VERSION={version} OCTOPUS_RELEASE={release-id} \ GH_REPO=Octopus/octopus GITEA_TOKEN=<pat> \ bun <harness-package>/script/build.tsbuild.tsattaches the 12 release assets to the draft release. -
Publish npm / docker / AUR + git sync:
OCTOPUS_VERSION={version} OCTOPUS_RELEASE={release-id} \ GITEA_TOKEN=<pat> GH_REPO=Octopus/octopus \ NODE_AUTH_TOKEN=<npm-token> \ bun script/publish.tsSet
OCTOPUS_GITEA_ONLY=trueto skip npm/docker/AUR/homebrew. -
Undraft the release (makes it public):
curl -fsS -X PATCH \ "<instance-base-url>/api/v1/repos/Octopus/octopus/releases/{release-id}" \ -H "Authorization: token $GITEA_TOKEN" \ -H "Content-Type: application/json" -d '{"draft": false}' -
Verify assets 鈥?the release must carry 12 assets:
curl -sS "<instance-base-url>/api/v1/repos/Octopus/octopus/releases/tags/v{version}" \ -H "Authorization: token $GITEA_TOKEN" | jq '.assets | length' -
Sync the public mirror repo (
Octopus/octopus-release):CI_PAT=<pat> VERSION={version} bash script/sync-public-install.sh CI_PAT=<pat> VERSION={version} bash script/sync-public-assets.sh CI_PAT=<pat> VERSION={version} bash script/verify-public-sync.sh
Notes
- Windows code-signing is not provisioned (no Windows runner / Azure Trusted Signing); the CLI ships unsigned, as before ([org-internal #252]).
- Rollback: if a step fails mid-release, the draft release + tag can be deleted and re-run; every script above is idempotent or safely re-runnable.
- If a future CI pipeline replaces this manual flow, update this section and reference [org-internal #2003] for the retirement rationale.
Phase 5 鈥?Rollback Plan
Document how to undo this release:
- Git rollback:
git tag -d v{version}(if not yet pushed).git revert {commit_hash}(if already merged).- If the release includes DB migrations, confirm the
downmigration exists.
- Data rollback (if applicable):
- For each migration, confirm the
downmigration exists and has been tested. - If the release changes data format without a reversible migration, mark
鈿狅笍 IRREVERSIBLE DATA CHANGE.
- For each migration, confirm the
## Rollback Plan
### Git Rollback
git tag -d v{version}
# or: git revert {hash}
### Data Rollback
- Migration `{name}`: down {exists / NOT FOUND}
- {additional risks}
### Rollback Triggers
| Condition | Threshold | Duration |
| ------------------ | ------------ | -------- |
| P99 latency spike | 2x baseline | 5 min |
| Error rate spike | 1% | 1 min |
| Critical bug | Data loss / security breach | immediate |
Phase 6 鈥?Post-release Smoke Test
- Run the project's build command on the tagged commit. Must pass.
- Run the test suite. Must pass.
- Return to the branch:
git checkout <original-branch>.
Phase 7 鈥?Report
## Release Report
**Version**: {old} 鈫?{new} (MAJOR / MINOR / PATCH)
**Tag**: v{version}
**Commits**: {N} since last tag ({feat} features, {fix} fixes)
**Typecheck**: 鉁?| Lint: 鉁?| Tests: 鉁?
### Changelog
{paste changelog section}
### Release Artifacts
- Commit: {hash} 鈥?`release: {version}`
- Tag: v{version}
- Changelog: CHANGELOG.md updated
---
**Deploy**: {manual step 鈥?"merge to main triggers CI", etc.}
**Rollback**: see Phase 5 above
**Next**: `core/skills/retrospective/SKILL.md` (optional 鈥?run on any project state)
References
core/checklists/release.md鈥?Release checklist- Semver spec: https://semver.org
- Conventional Commits: https://www.conventionalcommits.org