dccdb746ea
Dockerfile.traefik: extends traefik:v3.3.0 with baked default
static config (entrypoints 127.0.0.1:8080/8443/8081, file provider
watching /etc/traefik/dynamic, json log). Host-side traefik.yml
mounted :ro at runtime to override baked default (preserves
traefik-on-public-ip opt-out, REQ-100, C-58).
No certificatesResolvers — traefik v3.3 only supports acme/tailscale
(research finding). tls: {} in dynamic config for v0.14; real mTLS
deferred to v0.15 (grill G-003, confidence 0.55 < 0.60).
release.sh: second docker block builds+pushes orca-traefik image.
.coreci.yml: container-publish-traefik step mirrors container-publish.
Verified: docker build -f Dockerfile.traefik . succeeds; image starts
traefik v3.3.0 with --configFile=/etc/traefik/traefik.yml.
---ci---
project: orca
phase: 1
milestone: v0.14
status: execute
---/ci---
247 lines
8.9 KiB
Bash
Executable File
247 lines
8.9 KiB
Bash
Executable File
#!/bin/bash
|
|
# release.sh - Build a release artifact and create a Gitea release via `tea`
|
|
#
|
|
# Usage:
|
|
# scripts/release.sh [VERSION]
|
|
#
|
|
# If VERSION is not given, it is read from the latest git tag (e.g. v0.1.5).
|
|
# Falls back to "dev" if no tag is found.
|
|
#
|
|
# Steps:
|
|
# 1. Validate toolchain (git, go, tar, tea)
|
|
# 2. Determine version
|
|
# 3. Build orca binary with version injection via -ldflags
|
|
# 4. Package as tarball: orca-${VERSION}-${OS}-${ARCH}.tar.gz
|
|
# 5. Generate release notes from `---ci---` blocks since last tag
|
|
# 6. Invoke `tea releases create` to publish to Gitea
|
|
#
|
|
# Requires:
|
|
# - GITEA_TOKEN environment variable
|
|
# - `tea` CLI on PATH (https://gitea.com/gitea/tea)
|
|
#
|
|
# Idempotent: tea releases create will fail if the release already exists;
|
|
# the script surfaces that error rather than silently swallowing it.
|
|
|
|
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 if present
|
|
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
|
|
|
|
# --- gitea repo resolution ------------------------------------------------
|
|
# REPO is the tea-CLI repo slug (owner/repo). tea resolves login from its
|
|
# config (~/.config/tea/config.yml) and the repo slug from --repo.
|
|
REPO="${GITEA_OWNER:-coreci}/${GITEA_REPO:-orca}"
|
|
|
|
# --- helpers --------------------------------------------------------------
|
|
|
|
err() { echo "release: error: $*" >&2; exit 1; }
|
|
info() { echo "release: $*"; }
|
|
|
|
require_tool() {
|
|
command -v "$1" >/dev/null 2>&1 || err "required tool not found: $1"
|
|
}
|
|
|
|
# --- preflight ------------------------------------------------------------
|
|
|
|
require_tool git
|
|
require_tool go
|
|
require_tool tar
|
|
|
|
if [ -z "${GITEA_TOKEN:-}" ]; then
|
|
err "GITEA_TOKEN is not set. Export it or put it in .env"
|
|
fi
|
|
|
|
if ! command -v tea >/dev/null 2>&1; then
|
|
err "tea CLI not found on PATH. Install from https://gitea.com/gitea/tea"
|
|
fi
|
|
|
|
# --- version detection ----------------------------------------------------
|
|
|
|
VERSION="${1:-}"
|
|
if [ -z "$VERSION" ]; then
|
|
VERSION="$(git describe --tags --abbrev=0 2>/dev/null || echo dev)"
|
|
fi
|
|
# Strip leading 'v' for the tarball name (we keep it in the release tag itself)
|
|
VERSION_NUMBER="${VERSION#v}"
|
|
|
|
info "version: $VERSION"
|
|
info "building..."
|
|
|
|
# --- build with version injection ----------------------------------------
|
|
# Cross-build linux-amd64 regardless of host arch (D-193). The install.sh
|
|
# user base is amd64; the .coreci.yml release step hardcodes the amd64
|
|
# tarball name. Building for the host arch produced the wrong tarball when
|
|
# the release was cut from an arm64 dev machine — the root cause of the
|
|
# v0.4.5 install incident (REQ-097).
|
|
|
|
GIT_COMMIT="$(git rev-parse --short HEAD)"
|
|
BUILD_TIME="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
LDFLAGS="-s -w -X git.cloudinit.dev/coreci/orca/internal/cli.version=$VERSION -X git.cloudinit.dev/coreci/orca/internal/cli.gitCommit=$GIT_COMMIT -X git.cloudinit.dev/coreci/orca/internal/cli.buildTime=$BUILD_TIME"
|
|
|
|
mkdir -p bin
|
|
info "building orca-${VERSION}-linux-amd64 (cross-compile, CGO_ENABLED=0)..."
|
|
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -ldflags="$LDFLAGS" -o bin/orca ./cmd/orca
|
|
info "built: bin/orca (linux-amd64)"
|
|
|
|
# --- tarball --------------------------------------------------------------
|
|
# Always produce the linux-amd64 tarball name that install.sh looks for.
|
|
# (D-193: arm64 is a separate enhancement; this milestone ships amd64 only.)
|
|
|
|
TARBALL="orca-${VERSION}-linux-amd64.tar.gz"
|
|
tar -czf "$TARBALL" -C bin orca
|
|
sha256sum "$TARBALL" > SHA256SUMS
|
|
info "checksum: SHA256SUMS"
|
|
cat SHA256SUMS
|
|
info "packaged: $TARBALL ($(du -h "$TARBALL" | cut -f1))"
|
|
|
|
# --- release notes from ---ci--- blocks ----------------------------------
|
|
|
|
NOTES_FILE="$(mktemp)"
|
|
trap 'rm -f "$NOTES_FILE"' EXIT
|
|
|
|
{
|
|
echo "# Release $VERSION"
|
|
echo ""
|
|
echo "_Built: $BUILD_TIME from $GIT_COMMIT"
|
|
echo ""
|
|
|
|
PREV_TAG="$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")"
|
|
if [ -n "$PREV_TAG" ]; then
|
|
RANGE="$PREV_TAG..HEAD"
|
|
else
|
|
RANGE="HEAD"
|
|
fi
|
|
|
|
echo "## Changes since $PREV_TAG"
|
|
echo ""
|
|
# Extract messages of ---ci--- tagged commits in the range
|
|
git log --pretty=format:'- %s' "$RANGE" 2>/dev/null | head -100 || true
|
|
echo ""
|
|
} > "$NOTES_FILE"
|
|
|
|
info "release notes: $NOTES_FILE"
|
|
cat "$NOTES_FILE"
|
|
|
|
# --- publish to gitea -----------------------------------------------------
|
|
|
|
info "creating gitea release..."
|
|
tea releases create "$VERSION" \
|
|
--repo "$REPO" \
|
|
--title "Orca $VERSION" \
|
|
--note-file "$NOTES_FILE" \
|
|
--asset "$TARBALL"
|
|
|
|
# --- post-create asset verification (REQ-097, gate C-21) ------------------
|
|
# tea releases create has been observed to exit 0 without attaching the
|
|
# asset in some versions. Verify the asset actually appears in the release
|
|
# via the Gitea API; retry once if missing; fail loudly if still missing.
|
|
# This is the root-cause fix for the v0.8.x releases that shipped with zero
|
|
# binary assets.
|
|
|
|
verify_asset() {
|
|
local tag="$1" want="$2"
|
|
curl -fsSL "${GITEA_URL:-https://git.cloudinit.dev}/api/v1/repos/${GITEA_OWNER:-coreci}/${GITEA_REPO:-orca}/releases/tags/${tag}" \
|
|
| sed -n 's/.*"name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' \
|
|
| grep -qx "$want"
|
|
}
|
|
|
|
info "verifying asset ${TARBALL} attached to release ${VERSION}..."
|
|
if verify_asset "$VERSION" "$TARBALL"; then
|
|
info "✓ asset verified: ${TARBALL}"
|
|
else
|
|
info "asset missing after tea releases create; retrying upload..."
|
|
# Retry: re-add the asset via tea releases edit
|
|
tea release edit "$VERSION" --repo "$REPO" --asset "$TARBALL" 2>/dev/null \
|
|
|| tea releases edit "$VERSION" --repo "$REPO" --asset "$TARBALL" 2>/dev/null \
|
|
|| true
|
|
sleep 2
|
|
if verify_asset "$VERSION" "$TARBALL"; then
|
|
info "✓ asset verified on retry: ${TARBALL}"
|
|
else
|
|
err "asset ${TARBALL} NOT attached to release ${VERSION} after retry — the release exists but has no binary. Run 'tea releases edit ${VERSION} --repo $REPO --asset $TARBALL' manually. (REQ-097, C-21)"
|
|
fi
|
|
fi
|
|
|
|
info "✓ release $VERSION published with binary asset"
|
|
|
|
# --- publish container image to gitea registry (REQ-046) ------------------
|
|
# Skipped gracefully if docker is not on PATH (e.g. local dev without docker).
|
|
# The .coreci.yml release pipeline has a dedicated container-publish step
|
|
# that runs in a docker:24-cli image with docker-in-docker.
|
|
|
|
CONTAINER_REGISTRY="${CONTAINER_REGISTRY:-git.cloudinit.dev}"
|
|
CONTAINER_OWNER="${CONTAINER_OWNER:-coreci}"
|
|
CONTAINER_IMAGE="${CONTAINER_IMAGE:-orca}"
|
|
IMAGE="${CONTAINER_REGISTRY}/${CONTAINER_OWNER}/${CONTAINER_IMAGE}"
|
|
|
|
if ! command -v docker >/dev/null 2>&1; then
|
|
info "docker not found on PATH — skipping container image publish (CI handles it)."
|
|
else
|
|
info "building container image ${IMAGE}:${VERSION}..."
|
|
docker build \
|
|
--build-arg VERSION="$VERSION" \
|
|
--build-arg GIT_COMMIT="$GIT_COMMIT" \
|
|
--build-arg BUILD_TIME="$BUILD_TIME" \
|
|
-t "${IMAGE}:${VERSION}" \
|
|
-t "${IMAGE}:latest" \
|
|
"$REPO_ROOT"
|
|
|
|
if [ -z "${GITEA_TOKEN:-}" ]; then
|
|
info "GITEA_TOKEN not set — skipping docker push (image built locally only)."
|
|
else
|
|
info "logging in to ${CONTAINER_REGISTRY}..."
|
|
echo "$GITEA_TOKEN" | docker login "$CONTAINER_REGISTRY" -u cloudinit-bot --password-stdin
|
|
info "pushing ${IMAGE}:${VERSION}..."
|
|
docker push "${IMAGE}:${VERSION}"
|
|
info "pushing ${IMAGE}:latest..."
|
|
docker push "${IMAGE}:latest"
|
|
docker logout "$CONTAINER_REGISTRY"
|
|
info "✓ container image ${IMAGE}:${VERSION} published"
|
|
fi
|
|
fi
|
|
|
|
# --- publish orca-traefik container image (REQ-171, R-024) ----------------
|
|
# Custom traefik image with baked default static config. The host-side
|
|
# traefik.yml is mounted :ro at runtime to override the baked default.
|
|
# Skipped gracefully if docker is not on PATH (CI handles it via
|
|
# .coreci.yml container-publish-traefik step).
|
|
|
|
TRAEFIK_IMAGE="${CONTAINER_REGISTRY}/${CONTAINER_OWNER}/orca-traefik"
|
|
|
|
if ! command -v docker >/dev/null 2>&1; then
|
|
info "docker not found on PATH — skipping orca-traefik image publish (CI handles it)."
|
|
else
|
|
info "building orca-traefik image ${TRAEFIK_IMAGE}:${VERSION}..."
|
|
docker build \
|
|
-f Dockerfile.traefik \
|
|
-t "${TRAEFIK_IMAGE}:${VERSION}" \
|
|
-t "${TRAEFIK_IMAGE}:latest" \
|
|
"$REPO_ROOT"
|
|
|
|
if [ -z "${GITEA_TOKEN:-}" ]; then
|
|
info "GITEA_TOKEN not set — skipping orca-traefik push (image built locally only)."
|
|
else
|
|
if ! docker login "$CONTAINER_REGISTRY" -u cloudinit-bot --password-stdin <<<"$GITEA_TOKEN" 2>/dev/null; then
|
|
echo "$GITEA_TOKEN" | docker login "$CONTAINER_REGISTRY" -u cloudinit-bot --password-stdin
|
|
fi
|
|
info "pushing ${TRAEFIK_IMAGE}:${VERSION}..."
|
|
docker push "${TRAEFIK_IMAGE}:${VERSION}"
|
|
info "pushing ${TRAEFIK_IMAGE}:latest..."
|
|
docker push "${TRAEFIK_IMAGE}:latest"
|
|
docker logout "$CONTAINER_REGISTRY"
|
|
info "✓ orca-traefik image ${TRAEFIK_IMAGE}:${VERSION} published"
|
|
fi
|
|
fi
|