eadd28fac0
P01 — release/install pipeline fix (REQ-097, REQ-098; gate C-21).
release.sh (REQ-097):
- Cross-build linux-amd64 regardless of host arch (GOOS=linux GOARCH=amd64
go build, CGO_ENABLED=0). D-193: the host-arch build produced the wrong
tarball when cut from arm64 — root cause of the v0.8.x asset-less
releases.
- Hardcode tarball name to orca-${VERSION}-linux-amd64.tar.gz (not
host-arch-dependent).
- Post-create asset verification (C-21): after tea releases create, query
the Gitea API and assert the tarball appears in attachments. Retry once
via tea release edit if missing. Fail loudly if still missing. This
catches the tea CLI bug where create exits 0 without attaching the asset.
install.sh (REQ-098):
- Asset fallback walk: if the resolved release (latest or --version) lacks
the matching tarball, query /releases?limit=50, extract all
browser_download_urls from the list response (assets are inline), find
the newest release with a matching orca-*-linux-amd64.tar.gz asset, print
a WARNING, and use that release. Fixes the v0.4.5 install incident where
v0.8.15 had no asset and install.sh errored out with no fallback.
- --check dry-run mode (D-194): prints version + asset URL + install path
+ current version without writing anything.
Tests (scripts/tests/):
- install_test.bash: 5 tests (--help, --check happy path, --check fallback
walk, unknown arg rejection, --system root check).
- release_test.bash: 5 tests (script exists, syntax valid, cross-build
command present, amd64 tarball name hardcoded, asset verification present).
All 30 bats tests pass. make lint clean (no new warnings).
---ci---
project: orca
phase: 1
milestone: v0.10
status: execute
---/ci---
210 lines
7.7 KiB
Bash
Executable File
210 lines
7.7 KiB
Bash
Executable File
#!/bin/bash
|
|
# install.sh — 1-liner installer for orca
|
|
#
|
|
# Usage:
|
|
# curl -fsSL https://git.cloudinit.dev/coreci/orca/raw/branch/main/scripts/install.sh | bash
|
|
# curl -fsSL https://git.cloudinit.dev/coreci/orca/raw/branch/main/scripts/install.sh | bash -s -- --system
|
|
# curl -fsSL https://git.cloudinit.dev/coreci/orca/raw/branch/main/scripts/install.sh | bash -s -- --version v0.4.2
|
|
#
|
|
# Options:
|
|
# --system Install at system level (/usr/local/bin/orca, namespace /root/.orca). Requires root.
|
|
# --version <tag> Pin a specific version (e.g. v0.4.2). Default: latest release.
|
|
# --check Dry-run: print the version + asset URL + install path without writing.
|
|
# --help, -h Show this help.
|
|
#
|
|
# Behavior:
|
|
# - Downloads the release tarball from the public Gitea release URL.
|
|
# - Extracts the orca binary to the install path.
|
|
# - If the resolved release (latest or pinned) has no matching binary
|
|
# asset, walks backward through recent releases to find one that does,
|
|
# and prints a warning. (REQ-098 — the v0.8.x releases shipped with
|
|
# zero binary assets, causing install to resolve to v0.4.5.)
|
|
# - If an existing orca binary is found, reads its version and prints
|
|
# "updated from X to Y" (in-place update; preserves config/db/certs).
|
|
# - Idempotent: re-running with the same version reinstalls the binary.
|
|
# - Never touches the namespace dir (~/.orca or /root/.orca) — that's user state.
|
|
|
|
set -euo pipefail
|
|
|
|
GITEA_URL="${GITEA_URL:-https://git.cloudinit.dev}"
|
|
GITEA_OWNER="${GITEA_OWNER:-coreci}"
|
|
GITEA_REPO="${GITEA_REPO:-orca}"
|
|
|
|
SYSTEM=false
|
|
VERSION=""
|
|
CHECK=false
|
|
INSTALL_BIN=""
|
|
NAMESPACE_DIR=""
|
|
|
|
err() { echo "install: error: $*" >&2; exit 1; }
|
|
info() { echo "install: $*"; }
|
|
|
|
usage() {
|
|
sed -n '2,/^$/p' "$0" | sed 's/^# \?//' >&2
|
|
exit 0
|
|
}
|
|
|
|
# --- parse args ------------------------------------------------------------
|
|
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--system) SYSTEM=true; shift ;;
|
|
--version) VERSION="${2:-}"; shift 2 ;;
|
|
--version=*) VERSION="${1#*=}"; shift ;;
|
|
--check) CHECK=true; shift ;;
|
|
--help|-h) usage ;;
|
|
*) err "unknown argument: $1 (try --help)" ;;
|
|
esac
|
|
done
|
|
|
|
# --- determine install paths ----------------------------------------------
|
|
|
|
if [ "$SYSTEM" = "true" ]; then
|
|
if [ "$(id -u)" -ne 0 ]; then
|
|
err "--system requires root (uid 0). Re-run with sudo or drop --system for user-level install."
|
|
fi
|
|
INSTALL_BIN="/usr/local/bin/orca"
|
|
NAMESPACE_DIR="/root/.orca"
|
|
else
|
|
INSTALL_BIN="${HOME}/.local/bin/orca"
|
|
NAMESPACE_DIR="${HOME}/.orca"
|
|
fi
|
|
|
|
INSTALL_DIR="$(dirname "$INSTALL_BIN")"
|
|
|
|
# --- determine version ----------------------------------------------------
|
|
|
|
if [ -z "$VERSION" ]; then
|
|
info "querying latest release from ${GITEA_URL}..."
|
|
VERSION="$(curl -fsSL "${GITEA_URL}/api/v1/repos/${GITEA_OWNER}/${GITEA_REPO}/releases/latest" \
|
|
| sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' \
|
|
| head -1)"
|
|
if [ -z "$VERSION" ]; then
|
|
err "could not determine latest release version from Gitea API"
|
|
fi
|
|
fi
|
|
info "version: ${VERSION}"
|
|
|
|
# --- detect arch ----------------------------------------------------------
|
|
|
|
ARCH="$(uname -m)"
|
|
case "$ARCH" in
|
|
x86_64) ARCH=amd64 ;;
|
|
aarch64|arm64) ARCH=arm64 ;;
|
|
armv7l) ARCH=armv7 ;;
|
|
*) err "unsupported architecture: ${ARCH} (supported: amd64, arm64, armv7)" ;;
|
|
esac
|
|
|
|
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
|
TARBALL="orca-${VERSION}-${OS}-${ARCH}.tar.gz"
|
|
|
|
# --- find asset download URL (with fallback walk — REQ-098) --------------
|
|
#
|
|
# The v0.8.x releases shipped with zero binary assets attached, causing
|
|
# install to error out on the latest release. If the resolved release
|
|
# (latest or --version) lacks the matching tarball, walk backward through
|
|
# recent releases to find one that carries it, and print a warning.
|
|
|
|
find_asset_url() {
|
|
# $1 = tag. Prints the browser_download_url for the matching tarball, or empty.
|
|
# The `|| true` prevents set -e + pipefail from exiting the script when
|
|
# grep finds no match (exit 1) — an empty result is a valid outcome.
|
|
local tag="$1"
|
|
curl -fsSL "${GITEA_URL}/api/v1/repos/${GITEA_OWNER}/${GITEA_REPO}/releases/tags/${tag}" \
|
|
| sed -n 's/.*"browser_download_url"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' \
|
|
| grep "/${TARBALL}\$" \
|
|
| head -1 || true
|
|
}
|
|
|
|
info "locating asset ${TARBALL} in release ${VERSION}..."
|
|
ASSET_URL="$(find_asset_url "$VERSION")"
|
|
|
|
if [ -z "$ASSET_URL" ]; then
|
|
info "WARNING: release ${VERSION} has no ${TARBALL} asset. Walking back through recent releases..."
|
|
# The /releases list endpoint returns assets inline (browser_download_url
|
|
# appears within each release's assets array). Extract all download URLs
|
|
# from the list response and find the first (newest) one matching our
|
|
# OS+arch tarball pattern (any version). This avoids per-release API calls.
|
|
ASSET_URL="$(curl -fsSL "${GITEA_URL}/api/v1/repos/${GITEA_OWNER}/${GITEA_REPO}/releases?limit=50" \
|
|
| grep -oE '"browser_download_url"[[:space:]]*:[[:space:]]*"[^"]*"' \
|
|
| sed -n 's/.*"browser_download_url"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' \
|
|
| grep -E "/orca-[^/]*-${OS}-${ARCH}\.tar\.gz$" \
|
|
| head -1 || true)"
|
|
if [ -n "$ASSET_URL" ]; then
|
|
# Extract the version from the URL (e.g. .../download/v0.4.5/orca-...)
|
|
FALLBACK_VERSION="$(echo "$ASSET_URL" | sed -n 's|.*/download/\([^/]*\)/.*|\1|p')"
|
|
info "WARNING: latest release ${VERSION} has no binary asset; falling back to ${FALLBACK_VERSION} which has orca-${FALLBACK_VERSION}-${OS}-${ARCH}.tar.gz."
|
|
VERSION="$FALLBACK_VERSION"
|
|
else
|
|
err "could not find any release with a ${OS}-${ARCH} tarball in the last 50 releases. Check that a release exists with a linux-${ARCH} binary."
|
|
fi
|
|
fi
|
|
info "asset: ${ASSET_URL}"
|
|
|
|
# --- in-place update detection -------------------------------------------
|
|
|
|
OLD_VERSION=""
|
|
if [ -x "$INSTALL_BIN" ]; then
|
|
OLD_VERSION="$("$INSTALL_BIN" version --json 2>/dev/null | sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1 || echo "")"
|
|
fi
|
|
|
|
# --- --check dry-run (D-194) ---------------------------------------------
|
|
# Print what would be installed without writing anything.
|
|
|
|
if [ "$CHECK" = "true" ]; then
|
|
info "dry-run (--check): no files will be written"
|
|
info " would install: orca ${VERSION}"
|
|
info " asset: ${ASSET_URL}"
|
|
info " binary path: ${INSTALL_BIN}"
|
|
info " namespace root: ${NAMESPACE_DIR}"
|
|
if [ -n "$OLD_VERSION" ]; then
|
|
info " current: ${OLD_VERSION} (would update to ${VERSION})"
|
|
else
|
|
info " current: (not installed)"
|
|
fi
|
|
exit 0
|
|
fi
|
|
|
|
# --- download + extract ---------------------------------------------------
|
|
|
|
TMPDIR="$(mktemp -d)"
|
|
trap 'rm -rf "$TMPDIR"' EXIT
|
|
|
|
info "downloading..."
|
|
curl -fsSL -o "${TMPDIR}/${TARBALL}" "$ASSET_URL"
|
|
|
|
info "extracting..."
|
|
tar -xzf "${TMPDIR}/${TARBALL}" -C "$TMPDIR"
|
|
|
|
if [ ! -f "${TMPDIR}/orca" ]; then
|
|
err "tarball did not contain an 'orca' binary"
|
|
fi
|
|
|
|
# --- install --------------------------------------------------------------
|
|
|
|
mkdir -p "$INSTALL_DIR"
|
|
install -m 0755 "${TMPDIR}/orca" "$INSTALL_BIN"
|
|
|
|
# --- report ---------------------------------------------------------------
|
|
|
|
if [ -n "$OLD_VERSION" ]; then
|
|
if [ "$OLD_VERSION" = "$VERSION" ]; then
|
|
info "✓ reinstalled orca ${VERSION} at ${INSTALL_BIN}"
|
|
else
|
|
info "✓ updated orca from ${OLD_VERSION} to ${VERSION} at ${INSTALL_BIN}"
|
|
fi
|
|
else
|
|
info "✓ installed orca ${VERSION} to ${INSTALL_BIN}"
|
|
fi
|
|
|
|
if [ "$SYSTEM" = "true" ]; then
|
|
info " namespace root: ${NAMESPACE_DIR} (use 'orca --system init' to initialize)"
|
|
else
|
|
info " namespace root: ${NAMESPACE_DIR} (use 'orca init' to initialize)"
|
|
if ! echo "$PATH" | grep -q "$INSTALL_DIR"; then
|
|
info " NOTE: $INSTALL_DIR is not on your PATH. Add it:"
|
|
info " export PATH=\"\$PATH:$INSTALL_DIR\""
|
|
fi
|
|
fi
|
|
|
|
info " verify: ${INSTALL_BIN} version" |