Release script now supports: patch (default), minor, major, or explicit version. Auto-updates Cargo.toml and flake.nix before building. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
214 lines
6.5 KiB
Bash
Executable File
214 lines
6.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# Lux Release Script
|
|
# Builds a static binary, generates changelog, and creates a Gitea release.
|
|
#
|
|
# Usage:
|
|
# ./scripts/release.sh # auto-bump patch (0.2.0 → 0.2.1)
|
|
# ./scripts/release.sh patch # same as above
|
|
# ./scripts/release.sh minor # bump minor (0.2.0 → 0.3.0)
|
|
# ./scripts/release.sh major # bump major (0.2.0 → 1.0.0)
|
|
# ./scripts/release.sh v1.2.3 # explicit version
|
|
#
|
|
# Environment:
|
|
# GITEA_TOKEN - API token for git.qrty.ink (prompted if not set)
|
|
# GITEA_URL - Gitea instance URL (default: https://git.qrty.ink)
|
|
|
|
# cd to repo root (directory containing this script's parent)
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
cd "$SCRIPT_DIR/.."
|
|
|
|
GITEA_URL="${GITEA_URL:-https://git.qrty.ink}"
|
|
REPO_OWNER="blu"
|
|
REPO_NAME="lux"
|
|
API_BASE="$GITEA_URL/api/v1"
|
|
|
|
# Colors
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
CYAN='\033[0;36m'
|
|
BOLD='\033[1m'
|
|
NC='\033[0m'
|
|
|
|
info() { printf "${CYAN}::${NC} %s\n" "$1"; }
|
|
ok() { printf "${GREEN}ok${NC} %s\n" "$1"; }
|
|
warn() { printf "${YELLOW}!!${NC} %s\n" "$1"; }
|
|
err() { printf "${RED}error:${NC} %s\n" "$1" >&2; exit 1; }
|
|
|
|
# --- Determine version ---
|
|
CURRENT=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
|
|
BUMP="${1:-patch}"
|
|
|
|
bump_version() {
|
|
local ver="$1" part="$2"
|
|
IFS='.' read -r major minor patch <<< "$ver"
|
|
case "$part" in
|
|
major) echo "$((major + 1)).0.0" ;;
|
|
minor) echo "$major.$((minor + 1)).0" ;;
|
|
patch) echo "$major.$minor.$((patch + 1))" ;;
|
|
*) echo "$part" ;; # treat as explicit version
|
|
esac
|
|
}
|
|
|
|
case "$BUMP" in
|
|
major|minor|patch)
|
|
VERSION=$(bump_version "$CURRENT" "$BUMP")
|
|
info "Bumping $BUMP: $CURRENT → $VERSION"
|
|
;;
|
|
*)
|
|
# Explicit version — strip v prefix if present
|
|
VERSION="${BUMP#v}"
|
|
info "Explicit version: $VERSION"
|
|
;;
|
|
esac
|
|
|
|
TAG="v$VERSION"
|
|
|
|
# --- Check for clean working tree ---
|
|
if [ -n "$(git status --porcelain)" ]; then
|
|
warn "Working tree has uncommitted changes:"
|
|
git status --short
|
|
printf "\n"
|
|
read -rp "Continue anyway? [y/N] " confirm
|
|
[[ "$confirm" =~ ^[Yy]$ ]] || exit 1
|
|
fi
|
|
|
|
# --- Check if tag already exists ---
|
|
if git rev-parse "$TAG" >/dev/null 2>&1; then
|
|
err "Tag $TAG already exists. Choose a different version."
|
|
fi
|
|
|
|
# --- Update version in source files ---
|
|
if [ "$VERSION" != "$CURRENT" ]; then
|
|
info "Updating version in Cargo.toml and flake.nix..."
|
|
sed -i "0,/^version = \"$CURRENT\"/s//version = \"$VERSION\"/" Cargo.toml
|
|
sed -i "s/version = \"$CURRENT\";/version = \"$VERSION\";/g" flake.nix
|
|
sed -i "s/v$CURRENT/v$VERSION/g" flake.nix
|
|
git add Cargo.toml flake.nix
|
|
git commit --no-gpg-sign -m "chore: bump version to $VERSION"
|
|
ok "Version updated and committed"
|
|
fi
|
|
|
|
# --- Generate changelog ---
|
|
info "Generating changelog..."
|
|
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
|
|
if [ -n "$LAST_TAG" ]; then
|
|
RANGE="$LAST_TAG..HEAD"
|
|
info "Changes since $LAST_TAG:"
|
|
else
|
|
RANGE="HEAD"
|
|
info "First release — summarizing recent commits:"
|
|
fi
|
|
|
|
CHANGELOG=$(git log "$RANGE" --pretty=format:"- %s" --no-merges 2>/dev/null | head -50 || true)
|
|
if [ -z "$CHANGELOG" ]; then
|
|
CHANGELOG="- Initial release"
|
|
fi
|
|
|
|
# --- Build static binary ---
|
|
info "Building static binary (nix build .#static)..."
|
|
nix build .#static
|
|
BINARY="result/bin/lux"
|
|
if [ ! -f "$BINARY" ]; then
|
|
err "Static binary not found at $BINARY"
|
|
fi
|
|
|
|
BINARY_SIZE=$(ls -lh "$BINARY" | awk '{print $5}')
|
|
BINARY_TYPE=$(file "$BINARY" | sed 's/.*: //')
|
|
ok "Binary: $BINARY_SIZE, $BINARY_TYPE"
|
|
|
|
# --- Prepare release artifact ---
|
|
ARTIFACT="/tmp/lux-${TAG}-linux-x86_64"
|
|
cp "$BINARY" "$ARTIFACT"
|
|
chmod +x "$ARTIFACT"
|
|
|
|
# --- Show release summary ---
|
|
printf "\n"
|
|
printf "${BOLD}═══ Release Summary ═══${NC}\n"
|
|
printf "\n"
|
|
printf " ${BOLD}Tag:${NC} %s\n" "$TAG"
|
|
printf " ${BOLD}Binary:${NC} %s (%s)\n" "lux-${TAG}-linux-x86_64" "$BINARY_SIZE"
|
|
printf " ${BOLD}Commit:${NC} %s\n" "$(git rev-parse --short HEAD)"
|
|
printf "\n"
|
|
printf "${BOLD}Changelog:${NC}\n"
|
|
printf "%s\n" "$CHANGELOG"
|
|
printf "\n"
|
|
|
|
# --- Confirm ---
|
|
read -rp "Create release $TAG? [y/N] " confirm
|
|
[[ "$confirm" =~ ^[Yy]$ ]] || { info "Aborted."; exit 0; }
|
|
|
|
# --- Get Gitea token ---
|
|
if [ -z "${GITEA_TOKEN:-}" ]; then
|
|
printf "\n"
|
|
info "Gitea API token required (create at $GITEA_URL/user/settings/applications)"
|
|
read -rsp "Token: " GITEA_TOKEN
|
|
printf "\n"
|
|
fi
|
|
|
|
if [ -z "$GITEA_TOKEN" ]; then
|
|
err "No token provided"
|
|
fi
|
|
|
|
# --- Create and push tag ---
|
|
info "Creating tag $TAG..."
|
|
git tag -a "$TAG" -m "Release $TAG" --no-sign
|
|
ok "Tag created"
|
|
|
|
info "Pushing tag to origin..."
|
|
git push origin "$TAG"
|
|
ok "Tag pushed"
|
|
|
|
# --- Create Gitea release ---
|
|
info "Creating release on Gitea..."
|
|
|
|
RELEASE_BODY=$(printf "## Lux %s\n\n### Changes\n\n%s\n\n### Installation\n\n\`\`\`bash\ncurl -Lo lux %s/%s/%s/releases/download/%s/lux-linux-x86_64\nchmod +x lux\n./lux --version\n\`\`\`" \
|
|
"$TAG" "$CHANGELOG" "$GITEA_URL" "$REPO_OWNER" "$REPO_NAME" "$TAG")
|
|
|
|
RELEASE_JSON=$(jq -n \
|
|
--arg tag "$TAG" \
|
|
--arg name "Lux $TAG" \
|
|
--arg body "$RELEASE_BODY" \
|
|
'{tag_name: $tag, name: $name, body: $body, draft: false, prerelease: false}')
|
|
|
|
RELEASE_RESPONSE=$(curl -s -X POST \
|
|
"$API_BASE/repos/$REPO_OWNER/$REPO_NAME/releases" \
|
|
-H "Authorization: token $GITEA_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d "$RELEASE_JSON")
|
|
|
|
RELEASE_ID=$(echo "$RELEASE_RESPONSE" | jq -r '.id // empty')
|
|
if [ -z "$RELEASE_ID" ]; then
|
|
echo "$RELEASE_RESPONSE" | jq . 2>/dev/null || echo "$RELEASE_RESPONSE"
|
|
err "Failed to create release"
|
|
fi
|
|
ok "Release created (id: $RELEASE_ID)"
|
|
|
|
# --- Upload binary ---
|
|
info "Uploading binary..."
|
|
UPLOAD_RESPONSE=$(curl -s -X POST \
|
|
"$API_BASE/repos/$REPO_OWNER/$REPO_NAME/releases/$RELEASE_ID/assets?name=lux-linux-x86_64" \
|
|
-H "Authorization: token $GITEA_TOKEN" \
|
|
-H "Content-Type: application/octet-stream" \
|
|
--data-binary "@$ARTIFACT")
|
|
|
|
ASSET_NAME=$(echo "$UPLOAD_RESPONSE" | jq -r '.name // empty')
|
|
if [ -z "$ASSET_NAME" ]; then
|
|
echo "$UPLOAD_RESPONSE" | jq . 2>/dev/null || echo "$UPLOAD_RESPONSE"
|
|
err "Failed to upload binary"
|
|
fi
|
|
ok "Binary uploaded: $ASSET_NAME"
|
|
|
|
# --- Done ---
|
|
printf "\n"
|
|
printf "${GREEN}${BOLD}Release $TAG published!${NC}\n"
|
|
printf "\n"
|
|
printf " ${BOLD}URL:${NC} %s/%s/%s/releases/tag/%s\n" "$GITEA_URL" "$REPO_OWNER" "$REPO_NAME" "$TAG"
|
|
printf " ${BOLD}Download:${NC} %s/%s/%s/releases/download/%s/lux-linux-x86_64\n" "$GITEA_URL" "$REPO_OWNER" "$REPO_NAME" "$TAG"
|
|
printf "\n"
|
|
|
|
# Cleanup
|
|
rm -f "$ARTIFACT"
|