Skip to content

Commit 5e0dc1c

Browse files
committed
docs: [#448] add release process specification
1 parent ca63c6c commit 5e0dc1c

1 file changed

Lines changed: 293 additions & 0 deletions

File tree

Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
# Define a Standard Release Process (Branch, Tag, Docker Image, Crate)
2+
3+
**Issue**: #448
4+
**Parent Epic**: N/A (standalone release process task)
5+
**Related**:
6+
7+
- `docs/contributing/roadmap-issues.md`
8+
- `docs/contributing/commit-process.md`
9+
- `docs/roadmap.md`
10+
11+
## Overview
12+
13+
Define and document a repeatable release process for this repository so releases are
14+
predictable, auditable, and less error-prone.
15+
16+
This repository already has a container workflow in `.github/workflows/container.yaml`
17+
that publishes Docker images for `main` and `develop`. The new release process should
18+
extend that model to support release branches, while keeping the overall process much
19+
simpler than the Torrust Tracker release process.
20+
21+
The initial release process should include these mandatory steps in order:
22+
23+
1. Update the version in the relevant `Cargo.toml` files
24+
2. Commit the release version
25+
3. Push the release commit to `main`
26+
4. Create the release tag and push it
27+
5. Create the release branch and push it
28+
6. Create the GitHub release from the tag
29+
7. Let GitHub Actions publish release artifacts:
30+
- Docker image for the release branch
31+
- Crate for the release branch
32+
33+
## Goals
34+
35+
- [ ] Define a single documented release workflow with explicit step order
36+
- [ ] Make branch and tag conventions consistent across releases
37+
- [ ] Ensure Docker image publication is triggered from release branches
38+
- [ ] Ensure crate publication is triggered from release branches
39+
- [ ] Define validation and rollback guidance for failed release steps
40+
- [ ] Keep the first version of the process intentionally simpler than the tracker repository
41+
- [ ] Avoid duplicate Docker release tags for the same version
42+
43+
## 🏗️ Architecture Requirements
44+
45+
**DDD Layer**: Infrastructure (CI/CD and release automation), Documentation
46+
**Module Path**: `docs/`, `.github/workflows/`, and release-related scripts if needed
47+
**Pattern**: Release workflow and operational guide
48+
49+
### Module Structure Requirements
50+
51+
- [ ] Keep process documentation in `docs/`
52+
- [ ] Keep automation in `.github/workflows/` and/or `scripts/`
53+
- [ ] Keep branch and tag naming rules explicit and testable
54+
- [ ] Keep artifact version alignment across Git tag, Docker image tag, and crate version
55+
56+
### Architectural Constraints
57+
58+
- [ ] Release order must be deterministic and documented
59+
- [ ] Tag format must be clearly defined as `vX.Y.Z`
60+
- [ ] Release branch format must be clearly defined and compatible with workflow triggers
61+
- [ ] Docker publish step must support reproducible release tagging without overloading `main` publish behavior
62+
- [ ] Docker release tags must not include the Git tag `v` prefix
63+
- [ ] Crate publish step must define pre-checks and ownership requirements
64+
- [ ] Docker Hub credentials must separate secrets from non-sensitive variables
65+
- [ ] Workflow triggers and branch protections must align with allowed branches (`develop`, `main`, `releases/**/*`)
66+
67+
### Anti-Patterns to Avoid
68+
69+
- ❌ Manual ad-hoc release steps without a checklist
70+
- ❌ Tagging and artifact versions drifting from each other
71+
- ❌ Publishing the same Docker release twice with both `vX.Y.Z` and `X.Y.Z` tags
72+
- ❌ Publishing artifacts without verification or rollback notes
73+
- ❌ Coupling release steps to undocumented local machine state
74+
75+
## Specifications
76+
77+
### 1. Release Branch Strategy
78+
79+
Define how release branches are created, named, and finalized.
80+
81+
- Naming convention: `releases/vX.Y.Z`
82+
- Source branch: create the release branch from the same commit that was pushed to `main`
83+
- The release branch is a publication trigger, not a long-lived development branch
84+
- The release branch name must be parseable by GitHub Actions so release version metadata can be extracted
85+
86+
### 2. Version Update and Release Commit
87+
88+
Define which manifests are updated before the release commit.
89+
90+
- Root `Cargo.toml` version must be updated from the current development version to the release version
91+
- Publishable package versions must also be updated in their own manifests
92+
- The likely first publishable crate is `packages/sdk/Cargo.toml` (`torrust-tracker-deployer-sdk`)
93+
- The release commit should be explicit and traceable, for example: `release: version vX.Y.Z`
94+
- Verify release metadata quality for publishable crates (`description`, `license`, `repository`, `readme`) before publishing
95+
96+
### 3. Tagging Strategy
97+
98+
Define release tag rules and when tags are created.
99+
100+
- Tag format: `vX.Y.Z`
101+
- Annotated and signed tag requirements
102+
- Tag is created from the release commit already pushed to `main`
103+
- Tag, release branch, Docker tags, and crate versions must all refer to the same semantic version
104+
- Git tags keep the `v` prefix, but Docker release tags must use bare semver (`X.Y.Z`)
105+
106+
### 4. Docker Image Publication
107+
108+
Extend `.github/workflows/container.yaml` so release branches also publish Docker images.
109+
110+
- Keep existing behavior for `main` and `develop`
111+
- Add support for `releases/**/*` branch pushes
112+
- Follow the tracker repository pattern for deriving release image tags from the release branch version
113+
- Release branch publication should push versioned tags, not `latest`
114+
- Release branch publication must publish only canonical semver Docker tags such as `1.2.3`
115+
- Do not publish duplicate release image tags with both `v1.2.3` and `1.2.3`
116+
- Verify the image can be pulled and inspected after publication
117+
118+
Environment configuration for Docker publish:
119+
120+
- Use GitHub Environment: `dockerhub-torrust`
121+
- Keep `DOCKER_HUB_ACCESS_TOKEN` as a secret
122+
- Keep `DOCKER_HUB_USERNAME` as a normal environment variable (already set to `torrust` in deployer)
123+
- Do not store `DOCKER_HUB_USERNAME` or `DOCKER_HUB_REPOSITORY_NAME` as secrets
124+
- Repository name can be hardcoded for this repo (`tracker-deployer`) or stored as a non-secret variable
125+
126+
### 5. Library Crate Publication
127+
128+
Add a dedicated workflow for publishing crates from release branches.
129+
130+
- Preferred initial target crate: `torrust-tracker-deployer-sdk`
131+
- Trigger on push to `releases/**/*`
132+
- Run tests and release pre-checks before publication
133+
- Verify packaged contents before publishing (`cargo package --list`) to avoid shipping unintended files
134+
- `cargo publish --dry-run` before real publish
135+
- Post-publish verification (crate visible in registry and installable)
136+
- Verify docs.rs build status for the published version
137+
- Avoid mixing Docker-specific logic into the crate publication workflow
138+
139+
Environment configuration for crate publish:
140+
141+
- Use a dedicated GitHub Environment for crate publication (for example `deployment`)
142+
- Store cargo registry token as a secret only in that environment
143+
- Keep non-sensitive crate metadata as normal variables when needed
144+
145+
### 6. GitHub Release Creation
146+
147+
Define how the GitHub release is created from the pushed tag.
148+
149+
- Keep this step simple for now: create the GitHub release manually from the tag
150+
- Attach release notes manually or with a minimal template
151+
- Do not block Docker or crate publication on a more complex release-notes automation flow
152+
153+
Release finalization gate order:
154+
155+
- Confirm the release commit is pushed to `main`
156+
- Confirm tag `vX.Y.Z` is pushed
157+
- Confirm branch `releases/vX.Y.Z` is pushed
158+
- Confirm Docker release workflow passed
159+
- Confirm crate release workflow passed
160+
- Create/publish GitHub release as final step
161+
162+
### 7. Workflow Separation Strategy
163+
164+
Prefer independent workflows instead of one workflow that publishes all release artifacts.
165+
166+
- Keep Docker publication in `container.yaml` because it already owns Docker build/test/publish logic
167+
- Add a separate release-oriented workflow for crate publication; `deployment.yaml` is probably too vague in this repository
168+
- Prefer a name that reveals the artifact, for example `publish-crate.yaml` or `release-crate.yaml`
169+
- Keep GitHub release creation outside the artifact publication workflows for the first iteration
170+
171+
Reasoning:
172+
173+
- Docker and crate publishing have different credentials, failure modes, and verification steps
174+
- Separate workflows reduce accidental coupling and make reruns more targeted
175+
- The simpler process is easier to debug than one orchestrator workflow with multiple artifact paths
176+
177+
### 8. Failure Handling and Recovery
178+
179+
Define how to proceed when a step fails.
180+
181+
- If Docker publication fails, the release branch can be re-pushed or the workflow can be re-run without changing the tag
182+
- If crate publication fails after tag and branch creation, document whether a version must be abandoned or publication can be retried safely
183+
- Branch/tag rollback guidance
184+
- Docker publish retry policy
185+
- Crate publish partial-failure guidance
186+
- Operator-facing troubleshooting notes
187+
188+
Partial-failure action matrix:
189+
190+
- Docker failed, crate not started: fix Docker workflow and re-run publication on the same release branch
191+
- Docker passed, crate failed before upload: fix issue and re-run crate workflow on the same release branch
192+
- Crate published, later step failed: do not republish same crate version; proceed with follow-up patch release if needed
193+
194+
Idempotency and re-run rules:
195+
196+
- Docker release publication must be safely re-runnable for the same release branch/version
197+
- Crate workflow must detect already-published versions and fail with clear guidance instead of ambiguous errors
198+
- Tag and branch creation steps must check for existing refs and stop with actionable output if refs already exist
199+
200+
Crate rollback/yank policy:
201+
202+
- Never delete published versions (not possible on crates.io); use `cargo yank` only when necessary
203+
- Prefer yanking only for severe release defects (broken build, critical security issue, unusable package)
204+
- After yanking, cut a patch release with a higher version and document remediation in release notes
205+
206+
### 9. Pre-Flight Checks
207+
208+
Define mandatory checks before starting any release actions.
209+
210+
- Verify required GitHub environments exist (`dockerhub-torrust` and crate publish environment)
211+
- Verify required secrets and variables exist in those environments
212+
- Verify the releaser has permission to access protected environments and push required refs
213+
- Verify local workspace is clean and on the expected source branch before version bump/tagging
214+
215+
### 10. Repository Settings Alignment
216+
217+
Define repository settings expectations that release automation depends on.
218+
219+
- Allowed branches for release-related workflows: `develop`, `main`, `releases/**/*`
220+
- Release workflows must be trigger-scoped to those branches; avoid broad wildcard triggers
221+
- Current tracker policy (`10` branches and `0` tags allowed) should be documented as reference, and deployer should adopt equivalent branch scoping for release workflows where applicable
222+
223+
## Implementation Plan
224+
225+
### Phase 1: Define the Manual Release Sequence (estimated time: 2-3 hours)
226+
227+
- [ ] Task 1.1: Document the simplified release steps from version bump through GitHub release creation
228+
- [ ] Task 1.2: Define version, tag, and release branch naming conventions
229+
- [ ] Task 1.3: Specify which `Cargo.toml` files must be updated for each release
230+
- [ ] Task 1.4: Add a pre-flight checklist for environments, permissions, and clean git state
231+
232+
### Phase 2: Docker Release Branch Publishing (estimated time: 1-2 hours)
233+
234+
- [ ] Task 2.1: Extend `container.yaml` to trigger on `releases/**/*`
235+
- [ ] Task 2.2: Add release branch context detection and release image tags
236+
- [ ] Task 2.3: Define image verification, credential, and rerun requirements
237+
- [ ] Task 2.4: Ensure Docker Hub username/repository are configured as non-secret variables (token remains secret)
238+
239+
### Phase 3: Crate Publishing Workflow (estimated time: 1-2 hours)
240+
241+
- [ ] Task 3.1: Create a dedicated workflow for publishing the SDK crate from `releases/**/*`
242+
- [ ] Task 3.2: Define package inspection, dry-run, publish, and post-publish verification steps
243+
- [ ] Task 3.3: Define dedicated environment and document cargo registry credentials and failure recovery rules
244+
- [ ] Task 3.4: Add docs.rs post-publish verification guidance
245+
246+
### Phase 4: Validation and Operational Guidance (estimated time: 2-4 hours)
247+
248+
- [ ] Task 4.1: Validate the end-to-end release flow against a test version
249+
- [ ] Task 4.2: Document how maintainers verify Docker image, crate publication, and GitHub release creation
250+
- [ ] Task 4.3: Add troubleshooting notes for partial publication failures
251+
- [ ] Task 4.4: Add explicit idempotency/re-run guidance and crate yank policy
252+
253+
## Acceptance Criteria
254+
255+
> **Note for Contributors**: These criteria define what the PR reviewer will check. Use this as your pre-review checklist before submitting the PR to minimize back-and-forth iterations.
256+
257+
**Quality Checks**:
258+
259+
- [ ] Pre-commit checks pass: `./scripts/pre-commit.sh`
260+
261+
**Task-Specific Criteria**:
262+
263+
- [ ] The documented release process follows this order: version update, release commit, push to `main`, tag push, release branch push, GitHub release creation, workflow-driven artifact publication
264+
- [ ] The spec defines explicit finalization gates (main push, tag push, release branch push, Docker pass, crate pass, GitHub release)
265+
- [ ] Branch naming and tag naming conventions are documented as `releases/vX.Y.Z` and `vX.Y.Z`
266+
- [ ] `container.yaml` is specified to publish Docker images for release branches in addition to existing `main` and `develop` behavior
267+
- [ ] The spec explicitly requires Docker release tags to use `X.Y.Z` and forbids `vX.Y.Z` image tags
268+
- [ ] A separate crate publication workflow is specified for the SDK crate on `releases/**/*`
269+
- [ ] The spec explicitly records the decision to keep Docker and crate publication in independent workflows
270+
- [ ] Docker Hub configuration policy is explicit: token is secret, username/repository are variables
271+
- [ ] Release workflow branch scope is explicit and aligned with `develop`, `main`, and `releases/**/*`
272+
- [ ] Docker publish procedure includes verification and failure handling
273+
- [ ] Crate publish procedure includes dry-run and post-publish verification
274+
- [ ] Crate publish procedure includes package content inspection before publish
275+
- [ ] Crate publish procedure includes docs.rs build verification after publish
276+
- [ ] Pre-flight checks are documented for environments, secrets/variables, permissions, and git state
277+
- [ ] Partial-failure and re-run rules are documented for Docker and crate workflows
278+
- [ ] Crate rollback policy includes explicit yank criteria and patch-release follow-up
279+
- [ ] Version consistency rules are documented across Git tags, Docker tags, and crate versions
280+
281+
## Related Documentation
282+
283+
- `docs/contributing/roadmap-issues.md`
284+
- `docs/contributing/commit-process.md`
285+
- `docs/roadmap.md`
286+
- https://raw.githubusercontent.com/torrust/torrust-linting/refs/heads/main/skills/publish-rust-crate/SKILL.md
287+
288+
## Notes
289+
290+
- Keep the first iteration focused on one release path that can be executed by maintainers without additional assumptions.
291+
- Start with the SDK crate only unless additional crates are explicitly marked for publication.
292+
- Do not import the tracker repository's full staging and develop branch merge-back process into this repository yet.
293+
- Guard against the tracker bug described in `torrust/torrust-tracker#1029`: Docker release tags should not be published with the `v` prefix.

0 commit comments

Comments
 (0)