#!/bin/bash # backfill_releases.sh - Backfill Gitea releases for existing v0.1 tags # # For each tag passed (or all v0.1.1..v0.1.6 and v0.2.0), this script: # 1. Builds the orca binary from the current milestone branch head # (v0.1 retrospective: phase tags marked ship points but the entry # point fix is consolidated into a single post-fix build; see # .ciagent/RELEASE_POLICY.md for the standing rule) # 2. Injects the historical version via -ldflags # 3. Packages a tarball # 4. Creates a Gitea release with the tarball as an asset # # Idempotent: skips tags that already have a release. # # Usage: scripts/backfill_releases.sh [tag1 tag2 ...] set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" cd "$REPO_ROOT" # Source .env for GITEA_TOKEN for env_file in "$REPO_ROOT/.env" "$PWD/.env" "./.env"; do if [ -f "$env_file" ]; then set -a # shellcheck disable=SC1090 . "$env_file" set +a break fi done err() { echo "backfill: error: $*" >&2; exit 1; } info() { echo "backfill: $*"; } : "${GITEA_TOKEN:?GITEA_TOKEN is required}" command -v tea >/dev/null 2>&1 || err "tea CLI not on PATH" command -v go >/dev/null 2>&1 || err "go not on PATH" command -v tar >/dev/null 2>&1 || err "tar not on PATH" REPO="coreci/orca" # Default: backfill v0.1.1..v0.1.6 and v0.2.0 if [ $# -eq 0 ]; then TAGS=(v0.1.1 v0.1.2 v0.1.3 v0.1.4 v0.1.5 v0.1.6 v0.2.0) else TAGS=("$@") fi # Existing releases to skip EXISTING="$(tea releases list --repo "$REPO" --output simple 2>/dev/null | awk '{print $1}' || true)" OS="$(uname -s | tr '[:upper:]' '[:lower:]')" ARCH="$(uname -m)" case "$ARCH" in x86_64) ARCH=amd64 ;; aarch64) ARCH=arm64 ;; armv7l) ARCH=armv7 ;; esac # Use the cached Go 1.25.0 toolchain explicitly TOOLGO="/root/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.25.0.linux-amd64/bin/go" if [ ! -x "$TOOLGO" ]; then TOOLGO="$(command -v go)" fi phase_name() { case "$1" in v0.1.1) echo "Phase 1: CLI skeleton" ;; v0.1.2) echo "Phase 2: Node management" ;; v0.1.3) echo "Phase 3: Task execution" ;; v0.1.4) echo "Phase 4: State persistence" ;; v0.1.5) echo "Phase 5: Health checks" ;; v0.1.6) echo "Phase 6: CoreCI release flow" ;; v0.2.0) echo "Milestone v0.1: Foundation complete" ;; *) echo "Orca $1" ;; esac } for TAG in "${TAGS[@]}"; do if echo "$EXISTING" | grep -qx "$TAG"; then info "skip $TAG (release exists)" continue fi info "=== $TAG ===" # The v0.1.1..v0.1.6 phase tags point to merge commits; the canonical # source of truth for v0.1 code is the current milestone branch HEAD # (which includes the main.go entry-point fix). BUILD_COMMIT="$(git rev-parse --short HEAD)" FULL_COMMIT="$(git rev-parse HEAD)" info "build from HEAD: $BUILD_COMMIT (per RELEASE_POLICY.md v0.1 retrospective)" BUILD_TIME="$(date -u +%Y-%m-%dT%H:%M:%SZ)" LDFLAGS="-s -w -X git.cloudinit.dev/coreci/orca/internal/cli.version=$TAG -X git.cloudinit.dev/coreci/orca/internal/cli.gitCommit=$BUILD_COMMIT -X git.cloudinit.dev/coreci/orca/internal/cli.buildTime=$BUILD_TIME" mkdir -p bin GOTOOLCHAIN=local "$TOOLGO" build -trimpath -ldflags="$LDFLAGS" -o bin/orca ./cmd/orca TARBALL="orca-${TAG}-${OS}-${ARCH}.tar.gz" tar -czf "$TARBALL" -C bin orca info "tarball: $TARBALL ($(du -h "$TARBALL" | cut -f1))" # Generate release notes PREV_TAG="$(git describe --tags --abbrev=0 "$TAG^" 2>/dev/null || true)" NOTES_FILE="$(mktemp)" PHASE_NAME="$(phase_name "$TAG")" { echo "# Release $TAG — ${PHASE_NAME}" echo "" echo "_Built: $BUILD_TIME from $BUILD_COMMIT (${FULL_COMMIT:0:12})_" echo "" echo "## Notes" echo "" echo "This release artifact is built from the v0.1 milestone branch HEAD" echo "(post entry-point fix). For v0.2+ and future milestones, every phase" echo "tag will be released with the binary as-of that exact commit; see" echo "\`.ciagent/RELEASE_POLICY.md\` for the standing rule." echo "" if [ -n "$PREV_TAG" ] && [ "$TAG" != "v0.2.0" ]; then echo "## Changes since $PREV_TAG" echo "" git log --pretty=format:'- %s' "${PREV_TAG}..${TAG}" 2>/dev/null | head -50 echo "" fi if [ "$TAG" = "v0.2.0" ]; then echo "## Milestone v0.1: Foundation — All Phases" echo "" echo "All 6 phases of the v0.1 Foundation milestone are complete:" echo "" echo "- **Phase 1** (v0.1.1): CLI skeleton with Cobra, subcommand stubs, pre-push hook" echo "- **Phase 2** (v0.1.2): Node management with SQLite-backed registry" echo "- **Phase 3** (v0.1.3): Task execution engine with HCL specs, jobs, tasks, WaitDelay" echo "- **Phase 4** (v0.1.4): Local state persistence — audit log + migration runner" echo "- **Phase 5** (v0.1.5): Health-check daemon with /healthz, /readyz, /v1/* handlers" echo "- **Phase 6** (v0.1.6): CoreCI release flow with .coreci.yml and tea integration" echo "" echo "## Requirements Covered (21/24)" echo "" echo "REQ-001 Go 1.25+ toolchain, REQ-002 CLI-first single binary, REQ-003 Offline-first," echo "REQ-004 Single-node task execution, REQ-005 modernc/sqlite CGO-free, REQ-006 slog" echo "audit logging, REQ-007 CoreCI release flow, REQ-008 Structured JSON logging," echo "REQ-009 HCL/YAML job spec parsing, REQ-010 --json output flag, REQ-012 Config" echo "locations (~/.orca/, ORCA_DB), REQ-013 Pre-push hook, REQ-015 MIT LICENSE," echo "REQ-016 README quickstart, REQ-017 context.Context propagation, REQ-018 %w error" echo "wrapping, REQ-019 Cobra CLI, REQ-020 hashicorp/hcl parser, REQ-021 os/exec" echo "WaitDelay, REQ-024 Makefile standard targets." echo "" echo "Deferred to v0.2: REQ-011/023 (mTLS), REQ-014 (gosec+govulncheck), REQ-022" echo "(iter.Seq streaming)." echo "" echo "## Changes since v0.1.6" echo "" git log --pretty=format:'- %s' "v0.1.6..${TAG}" 2>/dev/null | head -50 echo "" fi } > "$NOTES_FILE" info "creating gitea release..." tea releases create "$TAG" \ --repo "$REPO" \ --title "Orca $TAG — ${PHASE_NAME}" \ --note-file "$NOTES_FILE" \ --asset "$TARBALL" info "✓ $TAG published" rm -f "$TARBALL" done info "all done"