Releasing¶
Overview¶
The HAProxy Template Ingress Controller uses a dual-release model where the controller and Helm chart have independent version numbers. This allows chart-only releases (e.g., documentation fixes) without requiring a new controller version.
Both use Semantic Versioning with support for pre-release suffixes.
Version Numbering¶
Format: MAJOR.MINOR.PATCH[-PRERELEASE]
| Type | Example | Description |
|---|---|---|
| Stable release | 0.1.0, 1.0.0 |
Production-ready version |
| Alpha | 0.1.0-alpha.1 |
Early testing, APIs may change |
| Beta | 0.1.0-beta.1 |
Feature complete, needs testing |
| Release candidate | 0.1.0-rc.1 |
Final testing before release |
CHANGELOG Conventions¶
A single CHANGELOG.md tracks changes for both controller and chart. Use prefixes to indicate scope:
| Prefix | When to Use |
|---|---|
[Controller] |
Changes to controller code only |
[Chart] |
Changes to Helm chart only (values, templates) |
| (no prefix) | Changes affecting both controller and chart |
Example:
## [0.1.0] - 2025-01-15
### Added
- [Chart] Default SSL certificate support via Helm values
- [Controller] Leader election for high availability
- New CRD field for custom annotations <!-- affects both -->
### Changed
- [Chart] Default replica count changed from 1 to 2
Prerequisites¶
Before releasing:
- Clean working directory - All changes committed
- CHANGELOG.md updated - Release notes documented
- All tests passing - CI pipeline green on main branch
- Documentation updated - Any new features documented
Controller Release Process¶
The main branch is protected, so releases are made via merge requests. CI automatically creates tags when the VERSION file changes on main.
Step 1: Update CHANGELOG.md¶
Prepare the changelog for release:
# Change from:
## [Unreleased]
### Added
- New feature X
# To:
## [0.1.0-alpha.1] - 2025-01-15
### Added
- New feature X
## [Unreleased]
Step 2: Run the Release Script¶
The script will:
- Validate version format (SemVer)
- Check CHANGELOG.md has the version entry
- Update the
VERSIONfile - Update
Chart.yamlappVersion and image annotation - Create a release commit
Step 3: Create and Merge Release MR¶
# Create release branch
git checkout -b release/controller-v<version>
# Push branch
git push -u origin release/controller-v<version>
# Create merge request
glab mr create --title "release: haptic-controller v<version>" \
--description "Release haptic-controller v<version>" \
--target-branch main
Review and merge the MR through GitLab.
Automatic Tag Creation¶
After the MR is merged, CI automatically:
- Detects the VERSION file change on main
- Creates and pushes the
v<version>tag - Triggers the release pipeline (binaries, images, GitLab release)
No manual tagging is required.
Manual Tagging (Fallback)
If automatic tagging fails, you can create the tag manually:
What CI Does Automatically¶
When a v* tag is pushed, CI will:
- Build binaries for linux/amd64, linux/arm64, linux/arm/v7
- Create GitLab release with:
- Signed binaries
- SHA256 checksums
- Release notes from CHANGELOG.md
- Pre-release flag (for alpha/beta/rc versions)
- Build Docker images for HAProxy 3.0, 3.1, 3.2
- Sign all artifacts with Cosign (keyless OIDC)
- Generate SBOM (Software Bill of Materials) for each image
- Attach SBOM attestation to images via Cosign
- Trigger documentation build with version tag
Chart Release Process¶
When to Release Chart Separately
Only release the chart separately when:
- Chart-only changes (values, templates, docs)
- Breaking Helm value changes
- Chart bug fixes independent of controller
Controller releases automatically update the chart's appVersion.
Step 1: Update CHANGELOG.md¶
Add a ## [<version>] section with chart changes prefixed by [Chart]:
Step 2: Run the Release Script¶
The script will:
- Validate version format (SemVer)
- Check CHANGELOG.md has the version entry
- Update
Chart.yamlversion - Create a release commit
Step 3: Create and Merge Release MR¶
git checkout -b release/haptic-chart-v<version>
git push -u origin release/haptic-chart-v<version>
glab mr create --title "release: chart v<version>" \
--description "Release chart v<version>" \
--target-branch main
Review and merge the MR through GitLab.
Automatic Tag Creation¶
After the MR is merged, CI automatically:
- Detects the Chart.yaml version change on main
- Creates and pushes the
haptic-chart-v<version>tag - Triggers the release pipeline (OCI registry, GitLab release)
No manual tagging is required.
Manual Tagging (Fallback)
If automatic tagging fails, you can create the tag manually:
What CI Does Automatically¶
When a haptic-chart-v* tag is pushed, CI will:
- Package Helm chart as OCI artifact
- Push to GitLab registry at
registry.gitlab.com/haproxy-haptic/haptic/charts - Sign with Cosign (keyless)
- Create GitLab release with release notes from CHANGELOG.md
- Trigger documentation build with version tag
Documentation Versioning¶
Each release creates a versioned documentation snapshot:
| Release Type | Docs Behavior |
|---|---|
Stable (0.1.0) |
Creates version, gets latest alias |
Pre-release (0.1.0-alpha.1) |
Creates version, no latest alias |
| Final after pre-release | Removes matching pre-release versions |
Example lifecycle:
0.1.0-alpha.1released -> Docs at/v0.1.0-alpha.1/0.1.0-alpha.2released -> Docs at/v0.1.0-alpha.2/0.1.0released -> Docs at/v0.1.0/withlatestalias, alpha versions removed
Pre-release vs Final Release¶
Pre-releases¶
Pre-releases (alpha, beta, rc) have these differences:
- Docker images built but don't get
latesttag - Documentation created but not marked as
latest - GitLab release marked as pre-release
- Not recommended for production use
Final Releases¶
Final releases (no suffix):
- Docker images get
latesttags - Documentation gets
latestalias - Pre-release documentation versions are removed
- Recommended for production use
Troubleshooting¶
Release Script Fails¶
| Error | Solution |
|---|---|
| "Working directory is not clean" | Commit or stash changes |
| "CHANGELOG.md has no entry" | Add ## [version] section |
| "Invalid version format" | Use X.Y.Z or X.Y.Z-suffix.N |
CI Pipeline Fails¶
- Check GitLab CI logs for specific error
- Verify tests pass locally with
make test - Check Docker builds work locally
Docker Image Missing¶
If images don't appear after release:
- Check
release-controller-imagesjob completed - Verify registry authentication succeeded
- Check for build errors in job logs
Supply Chain Security¶
All release artifacts are signed and include security metadata:
Artifact Signing¶
All artifacts are signed with Cosign using keyless OIDC:
- Binaries: Checksums file signed with detached signature
- Docker images: Each image tag signed
- Helm chart: OCI artifact signed
Verify image signature:
cosign verify \
--certificate-identity-regexp='https://gitlab.com/haproxy-haptic/.*' \
--certificate-oidc-issuer='https://gitlab.com' \
registry.gitlab.com/haproxy-haptic/haptic:v0.1.0
SBOM (Software Bill of Materials)¶
Each Docker image includes an SBOM attestation in SPDX format:
View SBOM:
cosign verify-attestation \
--type spdxjson \
--certificate-identity-regexp='https://gitlab.com/haproxy-haptic/.*' \
--certificate-oidc-issuer='https://gitlab.com' \
registry.gitlab.com/haproxy-haptic/haptic:v0.1.0 \
| jq -r '.payload' | base64 -d | jq '.predicate'
The SBOM lists all packages, libraries, and dependencies in the container image.
Version Files Reference¶
| File | Content | Updated By |
|---|---|---|
VERSION |
Controller version | Release script |
Chart.yaml:version |
Chart version | Chart release script |
Chart.yaml:appVersion |
Controller version | Controller release script |
Chart.yaml annotation |
Image version | Controller release script |