#!/usr/bin/env bash # semantic-release-bumptest.sh — prove semantic-release computes the version bumps # Olsitec expects (documentation/999_testing.md "semantic-release testing"). # # Uses the SAME releaserc + `--dry-run --no-ci --tag-format '${version}'` technique # as the canonical GitLab template (olsitec/gitlab ci_templates/release-automation/ # semantic-release.yaml): conventionalcommits preset + the custom releaseRules # (feat→minor, fix/chore→patch, breaking→major, BREAKING CHANGE/BREAKING CHANGES # footers→major). Self-contained — builds a throwaway repo + bare origin, walks the # conventional-commit sequence, and asserts: # init → 1.0.0 · feat → 1.1.0 · fix/chore → 1.1.1 · feat! → 2.0.0 · BREAKING → 3.0.0 # Exits non-zero on the first mismatch. Runs in the foundation-ci image (which bakes # semantic-release + the conventionalcommits preset). set -euo pipefail WORK=$(mktemp -d) trap 'rm -rf "$WORK"' EXIT REPO="$WORK/repo" BARE="$WORK/origin.git" BRANCH=master git init -q --bare "$BARE" git init -q -b "$BRANCH" "$REPO" cd "$REPO" git config user.email ci@olsitec.de git config user.name "CI Bumptest" git remote add origin "$BARE" # The releaserc Olsitec uses (trimmed to the version-COMPUTE plugins: the host # publish plugins are irrelevant to a dry-run bump check and would need a token). cat > .releaserc.yaml <<'EOF' branches: - name: master tagFormat: "${version}" plugins: - - "@semantic-release/commit-analyzer" - preset: conventionalcommits releaseRules: - breaking: true release: major - type: breaking release: major - type: feature release: minor - type: feat release: minor - type: fix release: patch - type: build release: patch - type: chore release: patch - type: ci release: patch - type: docs release: patch - type: perf release: patch - type: refactor release: patch - type: style release: patch - type: test release: patch parserOpts: noteKeywords: - BREAKING CHANGE - BREAKING CHANGES - "@semantic-release/release-notes-generator" EOF git add -A git commit -q -m "chore: scaffold releaserc" # Echo the version semantic-release would publish next (dry-run), or "" if none. compute() { out=$(semantic-release --dry-run --no-ci --tag-format '${version}' --branches "$BRANCH" 2>&1 || true) # semantic-release logs e.g. "The next release version is 1.1.0" printf '%s\n' "$out" \ | grep -oiE 'next release version is [0-9]+\.[0-9]+\.[0-9]+' \ | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | tail -1 } FAILED=0 # step [body] step() { exp="$1"; subj="$2"; body="${3:-}" if [ -n "$body" ]; then git commit -q --allow-empty -m "$subj" -m "$body" else git commit -q --allow-empty -m "$subj" fi git push -q origin "$BRANCH" got=$(compute) if [ "$got" = "$exp" ]; then echo " OK '$subj' → $got" git tag "$got" # simulate the published release (bare tag) git push -q origin "$got" else echo " FAIL '$subj' → expected $exp, got '${got:-}'" FAILED=1 fi } echo "semantic-release bump sequence (999_testing):" step 1.0.0 "feat: initial release" step 1.1.0 "feat: add a feature" step 1.1.1 "fix: correct a bug" step 2.0.0 "feat!: breaking redesign" step 3.0.0 "feat: another change" "BREAKING CHANGE: drops the old API" if [ "$FAILED" -ne 0 ]; then echo "semantic-release bumptest: FAILED" exit 1 fi echo "semantic-release bumptest: PASS (1.0.0 → 1.1.0 → 1.1.1 → 2.0.0 → 3.0.0)"