Files
Archduino/docs/superpowers/specs/2026-04-14-release-pipeline-design.md
2026-04-14 20:54:37 +02:00

7.7 KiB

Release Pipeline Design (Plan 4c)

Date: 2026-04-14 Scope: Plan 4c of the Archduino Go rewrite — ship versioned releases and enable one-line install.

Goal

Let a user install Archduino with a single curl | bash, and let the maintainer ship versioned releases with a single make release, hosted entirely on the self-hosted Gitea instance at gitlab.hive-brain.de:2222.

Deliverables

  1. bootstrap.sh — thin curl-piped shim that installs prereqs, downloads the latest release, and execs archduino install.
  2. .goreleaser.yaml — cross-compile + archive + checksum + changelog + publish to Gitea Releases.
  3. Makefile with release and snapshot targets — driven by svu for SemVer bumps.
  4. .gitea/workflows/release.yml — tag-triggered workflow that runs goreleaser.

Components

1. bootstrap.sh (repo root)

Replaces the legacy install.sh (which is Bash-era and will be removed/archived).

Behavior:

  • set -euo pipefail throughout.
  • Detect Arch via /etc/arch-release; exit 1 with clear message otherwise.
  • sudo pacman -Sy --needed --noconfirm sudo git curl ca-certificates.
  • Detect arch: uname -m → x86_64 → amd64, aarch64 → arm64. Unknown arch → exit 1.
  • Query Gitea API for latest release: GET https://gitlab.hive-brain.de/api/v1/repos/MDietermann/Archduino/releases/latest Extract tag_name (e.g. v0.1.0) and use it to locate assets.
  • Download archduino_<version-without-v>_linux_<arch>.tar.gz and checksums.txt into a mktemp -d.
  • Verify SHA256 via sha256sum --check --ignore-missing checksums.txt; mismatch → exit 1.
  • Extract tarball.
  • Install with sudo:
    • Binary → /usr/local/bin/archduino (0755), overwriting.
    • completions/archduino.bash → /usr/share/bash-completion/completions/archduino.
    • completions/_archduino → /usr/share/zsh/site-functions/_archduino.
    • completions/archduino.fish → /usr/share/fish/vendor_completions.d/archduino.fish.
  • exec /usr/local/bin/archduino install "$@" so flags pass through (e.g. --halt-on-error).

Usage:

curl -fsSL https://gitlab.hive-brain.de/MDietermann/Archduino/raw/branch/master/bootstrap.sh | bash

2. .goreleaser.yaml (repo root)

  • project_name: archduino
  • before.hooks: regenerate shell completions via the cobra completion subcommand:
    • go run ./cmd/archduino completion bash > completions/archduino.bash
    • go run ./cmd/archduino completion zsh > completions/_archduino
    • go run ./cmd/archduino completion fish > completions/archduino.fish
    • Prerequisite: the completion subcommand must be registered on the root cobra command. If not already present, add it as part of the implementation.
  • builds:
    • One entry, main: ./cmd/archduino, binary: archduino.
    • env: [CGO_ENABLED=0].
    • goos: [linux], goarch: [amd64, arm64].
    • ldflags: -s -w -X gitlab.hive-brain.de/MDietermann/Archduino/internal/buildinfo.Version={{.Version}} -X ...Commit={{.Commit}} -X ...Date={{.Date}} (add a small internal/buildinfo package to hold these; surface via archduino version).
  • archives:
    • Format tar.gz.
    • Name template archduino_{{.Version}}_linux_{{.Arch}}.
    • Files: binary + completions/* + README.md + LICENSE (add if missing).
  • checksum: name_template: 'checksums.txt' (SHA256).
  • changelog:
    • use: git
    • Filters: exclude ^chore:, ^docs:, ^test:, ^ci:, ^style:, Merge pull request, Merge branch.
    • Groups: Features (^feat), Bug fixes (^fix|^perf), Others (everything else).
  • release:
    • gitea_urls.api: https://gitlab.hive-brain.de/api/v1
    • gitea_urls.download: https://gitlab.hive-brain.de

3. Makefile (repo root)

Targets:

  • snapshot — goreleaser release --snapshot --clean. No tagging, no publish. For local build-matrix validation.
  • release — SemVer bump flow:
    1. Assert working tree clean and current branch is master; abort otherwise.
    2. CURRENT=$$(svu current) and NEXT=$$(svu next). Display both plus the commit log since CURRENT.
    3. Prompt Tag $NEXT and push? [y/N]. Abort on anything but y.
    4. git tag $$NEXT && git push origin $$NEXT. The actual release is then produced by CI.
  • completions — regenerate completions into completions/ locally (useful for dev).
  • build — local go build ./cmd/archduino for quick smoke.

svu is a dev dependency; README gains a one-line note: go install github.com/caarlos0/svu@latest.

4. .gitea/workflows/release.yml

  • Trigger: on: push: tags: ['v*'].
  • runs-on: ubuntu-latest (Gitea Actions convention; matches runner labels).
  • Steps:
    1. actions/checkout@v4 with fetch-depth: 0 (goreleaser needs full history for changelog).
    2. actions/setup-go@v5 with the Go version pinned in go.mod.
    3. goreleaser/goreleaser-action@v6 with args: release --clean.
  • Env: GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }}. Token is created manually in Gitea UI (repo-scoped, write:package/write:repository as needed) and stored as a repo secret before first release.
  • Prerequisite (documented, not executed by the plan): a Gitea Actions runner must be registered on the instance. One-time setup outside the scope of this spec.

Data flow

dev: git commit -m "feat: ..."   (conventional commits)
dev: make release                → svu computes vX.Y.Z → git tag + push
Gitea Actions: tag push → goreleaser --clean → Gitea Release published
                                                 (tarballs + checksums.txt + changelog)
user: curl … | bash → bootstrap.sh → Gitea API (latest release) → tarball →
      sha256 verify → /usr/local/bin + completions → exec archduino install

Versioning

SemVer driven by Conventional Commits via svu:

  • feat: → minor
  • fix: / perf: → patch
  • feat!: or BREAKING CHANGE: footer → major
  • chore: / docs: / refactor: / test: / ci: / style: → no release

First release: v0.1.0 (seed tag so svu has a baseline; manual one-time git tag v0.1.0).

Error handling

  • bootstrap.sh: checksum mismatch, non-Arch host, arch detection failure, non-200 from API → exit 1 with a specific message; set -euo pipefail covers the rest.
  • goreleaser is transactional — the Gitea Release is created after artifacts upload successfully, so a mid-run failure leaves no partial release.
  • make release aborts before tagging if the tree is dirty or not on master.

Testing

  • make snapshot locally verifies the build matrix and archive contents without publishing.
  • bootstrap.sh tested against a snapshot tarball in a throwaway Arch container: docker run --rm -it archlinux bash → serve the tarball locally → run bootstrap with an overridden base URL (env var hook, e.g. ARCHDUINO_RELEASE_BASE) for test runs.
  • No Go test changes; this is all out-of-band release machinery.

Out of scope (deferred)

  • GPG-signed checksums (revisit if/when distribution widens).
  • Debian/Fedora/macOS builds (waiting on multi-distro support elsewhere in the roadmap).
  • Homebrew tap and AUR PKGBUILD (AUR is a natural follow-up but tracked separately).
  • Automated "release PR" bots (release-please / semantic-release) — svu + manual make release is the chosen trigger.

File touch list

New:

  • bootstrap.sh
  • .goreleaser.yaml
  • Makefile
  • .gitea/workflows/release.yml
  • internal/buildinfo/buildinfo.go (tiny — holds Version, Commit, Date vars)
  • completions/ (gitignored; generated)
  • LICENSE (if missing)

Modified:

  • cmd/archduino/main.go (register cobra completion subcommand if absent; wire a version subcommand that prints buildinfo).
  • README.md (install-via-bootstrap instructions, svu note).
  • .gitignore (add dist/, completions/).

Removed/archived:

  • install.sh (legacy Bash installer — superseded by bootstrap.sh + Go binary).