Zum Inhalt

Semantic Release and Conventional Commits

Einordnung ins Overtime-Projekt

Damit Overtime-Images in der GitOps-Historie eindeutig und nachvollziehbar versioniert sind, statt nur über SHA-Tags identifiziert zu werden, wird Semantic Release auf Basis von Conventional Commits eingesetzt.


1. Kontext & Problemstellung (Deutsch)

Für ein verlässliches Deployment und einfache Rollbacks im fiktiven B2B-Kollaborations-Projekt Overtime benötigen Container-Images stabile und aussagekräftige Versions-Tags. Ein reiner Git-SHA-Tag (wie a3f9c12) bietet zwar technische Rückverfolgbarkeit, liefert den Betreibern und Auditoren jedoch keinerlei fachlichen Kontext über den Umfang der Änderung (Breaking Change, Feature, Bugfix).

Die manuelle Pflege von Changelogs und das händische Hochzählen von Versionsnummern (Versioning) sind fehleranfällig und werden unter Zeitdruck oft vernachlässigt. Um den strengen Anforderungen an Nachvollziehbarkeit und automatisierte Deployments gerecht zu werden, müssen Versionsnummern deterministisch aus der Code-Historie abgeleitet und Release Notes vollständig automatisch generiert werden.


2. Architecture Decision Record (English)

ADR-014: Semantic Release and Conventional Commits

Status

Accepted

Context and Problem Statement

Container images need stable, meaningful version tags for deployment and rollback. A SHA-only tag (a3f9c12) is traceable but carries no information about the scope of the change (breaking, feature, fix). Manually maintaining a changelog and bumping version numbers is error-prone and often skipped under time pressure. Release notes for auditors and operators must accurately reflect what changed between deployments without manual intervention.

Decision Drivers

  • Deterministic Versioning: Version bumping rules must be deterministic and derived directly from commit messages, entirely removing human judgement.
  • Automated Audit Trail: Changelogs and release notes must be generated automatically.
  • Unambiguous GitOps State: Image tags in the GitOps repository must be unique, ordered, and semantically meaningful to make rollbacks unambiguous.
  • Strict Release Gating: Version tags must only be created on the main branch after successful Merge Request reviews, never directly from feature branches. Only versioned builds should make it into production.

Considered Options

  • Manual Versioning — A human edits pyproject.toml and manually creates a git tag. This is frequently forgotten, inconsistent, and lacks an automated changelog.
  • Date-based Tags (2025-06-18) — Unique and ordered, but carry no semantic meaning regarding the impact of the release. They also do not solve the changelog problem.
  • Semantic Release — Automatically reads commit messages, derives the next semantic version (SemVer), creates the tag, and generates the changelog. Fully automated.

Decision Outcome

Chosen: Semantic Release driven by Conventional Commits.

Commit messages across all Overtime repositories must follow the Conventional Commits format to drive the automated release process.

Conventional Commits Specification

Commit messages follow this strict format:

<type>(<optional scope>): <description>

[optional body]

[optional footer: BREAKING CHANGE: ...]
Commit Type SemVer Bump Example
fix: Patch (0.0.x) fix: handle missing phone field in pii scrubber
feat: Minor (0.x.0) feat: add correlation ID to outbound HTTP calls
feat!:, fix!: or BREAKING CHANGE: in footer Major (x.0.0) feat!: overhaul API responses or any commit with a BREAKING CHANGE: footer
chore:, docs:, refactor:, test:, ci: None No release is created, avoiding release noise

Consequences & Trade-offs

Positive Consequences
  • Automated Traceability: Every image in the GitOps repository either has a SHA tag (short-lived, branch build) or a SemVer tag (release-ready, accompanied by an SBOM, security scan, and release notes).
  • Structured Changelogs: Release notes are automatically structured by commit type and published as GitLab Releases — no manual changelog maintenance is required.
  • Clean Rollbacks: A rollback in the overtime-gitops repository is a simple git revert to a specific SemVer tag, and the GitLab release notes describe exactly what was included in that version.
  • Reduced Noise: Commits labeled as chore: or ci: do not trigger releases, preventing version inflation from dependency updates or pipeline tweaks.
Negative Consequences / Trade-offs
  • Strict Enforcement Required: Conventional Commits must be strictly enforced by team convention or pre-commit hooks (e.g., commitlint). Semantic Release produces garbage output if commit messages are freeform.
  • Token Management: The @semantic-release/gitlab plugin requires a GL_TOKEN (a Personal Access Token) on the GitLab Free tier. If the token owner leaves the organization, the token must be manually rotated.
  • Pipeline Overhead: The Semantic Release job runs on every merge to the main branch, even if there are no releasable commits (e.g., only docs: changes). It exits cleanly but still incurs the minor overhead of initializing a Node.js environment.

3. Pipeline Implementation & Code Snippet (English)

The tagging process and release generation are tightly integrated into the CI/CD pipeline. Semantic Release evaluates the commits on the main branch and creates a standard v{major}.{minor}.{patch} tag (e.g., v1.3.0).

This newly created tag automatically triggers a subsequent Tag Pipeline, which executes the following crucial steps:

  1. Builds and pushes the final release image explicitly tagged with the Semantic Version.
  2. Generates the SBOM and runs Trivy vulnerability and license scans specifically for this release image.
  3. Exposes manual deployment gating buttons for both the Test and Production environments.
.semantic-release:
  stage: release
  image: node:24.17.0@sha256:032e78d7e54e352129831743737e3a83171d9cc5b5896f411649c597ce0b11ea
  before_script:
    - npm install --no-save semantic-release @semantic-release/commit-analyzer @semantic-release/release-notes-generator @semantic-release/gitlab
  script:
    - npx semantic-release
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

Configuration (.releaserc.json)

The following configuration file is placed in the repository root to define the branch rules and load the necessary plugins for GitLab integration:

{
  "branches": ["main"],
  "tagFormat": "v${version}",
  "plugins": [
    "@semantic-release/commit-analyzer",
    "@semantic-release/release-notes-generator",
    "@semantic-release/gitlab"
  ]
}

Note on CI Variables: To authenticate with the GitLab API and create the release and tag, a GL_TOKEN (GitLab Access Token with the api scope) must be stored as a masked and protected CI/CD variable within the GitLab project settings. Group/project access tokens are natively supported but require a paid GitLab Premium tier.


4. Compliance Einordnung (Deutsch)

Das detaillierte Mapping auf BSI IT-Grundschutz, CRA und CIS Benchmarks wird später ergänzt.