Files
orca/scripts/ci-run.sh
T
Jon Chery 8ca5ffd0fc
Release / ci (push) Failing after 8m5s
Release / container-orca (push) Has been skipped
Release / container-traefik (push) Has been skipped
fix(P1): clean disk before release + fallback to existing binary
The release job fails in 5 seconds — likely due to disk full (CoreCI's
SQLite logging fills the disk during go test -race). Fix:
1. Clean up coverage.out and Go build cache before the release job
2. If go build fails (disk full), fall back to the existing bin/orca
   from the build job (which succeeded)
3. Add more error handling for tar/sha256sum

---ci---
project: orca
phase: 1
milestone: v0.16
status: execute
---/ci---
2026-08-12 22:18:45 +00:00

194 lines
8.4 KiB
Bash
Executable File

#!/bin/sh
# ci-run.sh — CoreCI pipeline runner for orca.
# Called by .coreci.yml jobs via: sh scripts/ci-run.sh <job-name>
#
# CoreCI's ValidateShellCommand forbids shell metacharacters (&|;`><$())
# in the invoke: string. This script wraps the complex logic so the
# invoke: field is just "sh scripts/ci-run.sh <job-name>".
#
# Environment variables (provided by CoreCI's CI context + PassThroughEnv):
# CI_COMMIT_BRANCH — tag name on tag pushes (from GITHUB_REF_NAME)
# CI_COMMIT_SHA — commit SHA
# GITEA_TOKEN — Gitea API token (from Gitea Actions secret PAT_TOKEN)
#
# NOTE: uses #!/bin/sh — do NOT use bash-only features (pipefail, [[ ]], etc.)
# The Gitea Actions runner uses dash as /bin/sh.
set -u
JOB="${1:-}"
if [ -z "$JOB" ]; then
echo "usage: sh scripts/ci-run.sh <job-name>" >&2
exit 1
fi
# CoreCI's shell-isolated executor (buildIsolatedEnv) does NOT forward
# Go toolchain env vars (GOROOT, GOPATH, GOCACHE, GOMODCACHE are in the
# systemVars deny-list). Re-derive them from the `go` binary on PATH so
# Go commands work in the shell-isolated executor.
echo "ci-run: PATH=$PATH" >&2
echo "ci-run: which go=$(command -v go 2>/dev/null || echo 'not found')" >&2
if command -v go >/dev/null 2>&1; then
export GOROOT="${GOROOT:-$(go env GOROOT 2>/dev/null || echo "")}"
export GOPATH="${GOPATH:-$(go env GOPATH 2>/dev/null || echo "$HOME/go")}"
export GOCACHE="${GOCACHE:-$(go env GOCACHE 2>/dev/null || echo "$HOME/.cache/go-build")}"
export GOMODCACHE="${GOMODCACHE:-$(go env GOMODCACHE 2>/dev/null || echo "$HOME/go/pkg/mod")}"
echo "ci-run: GOROOT=$GOROOT GOPATH=$GOPATH GOCACHE=$GOCACHE GOMODCACHE=$GOMODCACHE" >&2
fi
info() { echo "ci-run: $*"; }
err() { echo "ci-run: error: $*" >&2; exit 1; }
case "$JOB" in
# ── validate ──────────────────────────────────────────────────────
go-vet)
go version
gofmt -l .
go vet ./...
;;
verify-reqs)
make verify-reqs
;;
gosec)
go install github.com/securego/gosec/v2/cmd/gosec@v2.18.2
gosec -fmt text -quiet ./...
;;
govulncheck)
go install golang.org/x/vuln/cmd/govulncheck@v1.1.3
govulncheck -mode binary ./...
;;
gitleaks)
curl -fsSL https://github.com/gitleaks/gitleaks/releases/latest/download/gitleaks-linux-amd64.tar.gz -o /tmp/gitleaks.tar.gz
tar -xzf /tmp/gitleaks.tar.gz -C /tmp gitleaks
mv /tmp/gitleaks /usr/local/bin/gitleaks 2>/dev/null || cp /tmp/gitleaks ./gitleaks
chmod +x ./gitleaks 2>/dev/null || true
if [ -x ./gitleaks ]; then
./gitleaks detect --source . --config .gitleaks.toml --baseline-path .gitleaks-baseline.json --no-banner
else
gitleaks detect --source . --config .gitleaks.toml --baseline-path .gitleaks-baseline.json --no-banner
fi
;;
# ── build ──────────────────────────────────────────────────────────
build)
info "building orca binary..."
VERSION="${CI_COMMIT_BRANCH:-dev}"
GIT_COMMIT="${CI_COMMIT_SHA:-unknown}"
BUILD_TIME="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
info "VERSION=$VERSION GIT_COMMIT=$GIT_COMMIT BUILD_TIME=$BUILD_TIME"
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 "running: go build -trimpath -ldflags=... -o bin/orca ./cmd/orca"
go build -trimpath -ldflags="${LDFLAGS}" -o bin/orca ./cmd/orca 2>&1 || err "go build failed with exit $?"
file bin/orca 2>/dev/null || echo "file command not available"
./bin/orca version 2>&1 || echo "orca version failed"
;;
# ── test (REQ-031: -race) ─────────────────────────────────────────
test)
go test -race -coverprofile=coverage.out ./...
go tool cover -func=coverage.out | tail -1
;;
# ── release ────────────────────────────────────────────────────────
release)
VERSION="${CI_COMMIT_BRANCH:-dev}"
TARBALL="orca-${VERSION}-linux-amd64.tar.gz"
if [ -z "${GITEA_TOKEN:-${CI_GITEA_TOKEN:-}}" ]; then
err "GITEA_TOKEN is not set"
fi
GITEA_TOKEN="${GITEA_TOKEN:-${CI_GITEA_TOKEN:-}}"
info "release ${VERSION} — GITEA_TOKEN length: ${#GITEA_TOKEN}"
# Clean up disk space — CoreCI's SQLite logging can fill the disk.
# Remove coverage.out and Go build cache to free space.
rm -f coverage.out 2>/dev/null || true
go clean -cache 2>/dev/null || true
# Rebuild the binary (the build job's binary may not persist if the
# executor uses separate workdirs, or the disk was full).
info "building release binary..."
GIT_COMMIT="${CI_COMMIT_SHA:-unknown}"
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
go build -trimpath -ldflags="${LDFLAGS}" -o bin/orca ./cmd/orca 2>&1
BUILD_EXIT=$?
if [ ${BUILD_EXIT} -ne 0 ]; then
info "go build failed (exit ${BUILD_EXIT}) — trying with existing bin/orca from build job"
if [ -x bin/orca ]; then
info "found existing bin/orca from build job"
else
err "go build failed and no existing binary found"
fi
fi
tar -czf "${TARBALL}" -C bin orca 2>&1 || err "tar failed"
sha256sum "${TARBALL}" > SHA256SUMS 2>&1 || err "sha256sum failed"
info "built ${TARBALL}"
# Create or update the Gitea release directly via the API.
# The CIAgent ship workflow may have already created the release
# (title+body, no binary). Check if it exists first.
info "checking for existing release ${VERSION}..."
RELEASE_ID=$(curl -fsSL \
"https://git.cloudinit.dev/api/v1/repos/coreci/orca/releases/tags/${VERSION}" \
-H "Authorization: token ${GITEA_TOKEN}" \
| python3 -c "import json,sys; r=json.load(sys.stdin); print(r.get('id',''))" 2>/dev/null || echo "")
if [ -z "${RELEASE_ID}" ]; then
info "creating new release ${VERSION}..."
RELEASE_ID=$(curl -fsSL -X POST \
"https://git.cloudinit.dev/api/v1/repos/coreci/orca/releases" \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
-d "{\"tag_name\":\"${VERSION}\",\"name\":\"Orca ${VERSION}\",\"body\":\"Release ${VERSION} built by CoreCI\"}" \
| python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || echo "")
if [ -z "${RELEASE_ID}" ]; then
err "failed to create release ${VERSION}"
fi
info "created release ID ${RELEASE_ID}"
else
info "release ${VERSION} already exists (ID ${RELEASE_ID}) — attaching assets"
fi
# Attach tarball and SHA256SUMS to the release.
info "attaching ${TARBALL} to release ${RELEASE_ID}..."
curl -fsSL -X POST \
"https://git.cloudinit.dev/api/v1/repos/coreci/orca/releases/${RELEASE_ID}/assets?name=${TARBALL}" \
-H "Authorization: token ${GITEA_TOKEN}" \
-F "attachment=@${TARBALL}" 2>&1 || err "failed to attach ${TARBALL}"
info "attaching SHA256SUMS to release ${RELEASE_ID}..."
curl -fsSL -X POST \
"https://git.cloudinit.dev/api/v1/repos/coreci/orca/releases/${RELEASE_ID}/assets?name=SHA256SUMS" \
-H "Authorization: token ${GITEA_TOKEN}" \
-F "attachment=@SHA256SUMS" 2>&1 || err "failed to attach SHA256SUMS"
# Verify assets are actually attached (REQ-097, gate C-21).
ASSET_COUNT=$(curl -fsSL \
"https://git.cloudinit.dev/api/v1/repos/coreci/orca/releases/tags/${VERSION}" \
-H "Authorization: token ${GITEA_TOKEN}" \
| python3 -c "import json,sys; print(len(json.load(sys.stdin).get('attachments',[])))" 2>/dev/null || echo "0")
info "release ${VERSION} has ${ASSET_COUNT} assets"
if [ "${ASSET_COUNT}" -lt 2 ]; then
err "assets not attached after upload (REQ-097, C-21) — got ${ASSET_COUNT}"
fi
info "release ${VERSION} published with ${ASSET_COUNT} binary assets"
;;
*)
err "unknown job: ${JOB}"
;;
esac