foundation/ci/semantic-release-bumptest.sh
Andreas Niemann f9aecf1b18
All checks were successful
CI / preflight (push) Successful in 7s
CI / typecheck (push) Successful in 17s
ecosystem-selftest / semantic-release-bumptest (push) Successful in 12s
pulumi-preview / preview (push) Successful in 20s
ecosystem-selftest / eslint-gate (push) Successful in 5s
ecosystem-selftest / yamllint-gate (push) Successful in 4s
feat(ci): reusable ecosystem workflows + selftest (999_testing)
The ecosystem-CI architecture: reusable Forgejo workflows (on: workflow_call)
that downstream repos reference as
`uses: olsitec/foundation/.forgejo/workflows/<x>.yml@master`.

- reusable-node-build.yml: install + build for npm/bun/none — covers the npm
  package (olsicrypto), bun package (document-engine), and no-artifact versioned
  (olsitrack/api) shapes.
- reusable-docker-build.yml: docker build via the host socket (R5: trusted repos
  only until the runner is fenced) — the seaspots-homepage / token-service shape.
- reusable-lint.yml: eslint + yamllint gate (either error → job non-zero).
- reusable-semantic-release.yml: conventionalcommits-preset version probe (dry-run),
  faithful to the GitLab template; outputs the computed next version. Real Forgejo
  publishing deferred (no @semantic-release/forgejo analogue yet).

- ecosystem-selftest.yml + ci/semantic-release-bumptest.sh: self-contained proof
  on the runner of the 999_testing acceptance criteria that need no external repo —
  the semantic-release bump sequence (1.0.0→1.1.0→1.1.1→2.0.0→3.0.0) and the
  eslint/yamllint non-zero-exit gates. Validated in a foundation-ci container.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 01:03:56 +02:00

115 lines
3.7 KiB
Bash
Executable file

#!/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 <expected> <commit-subject> [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:-<none>}'"
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)"