#!/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 [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 --- VERSION="${1:-}" if [ -z "$VERSION" ]; then VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') info "Version from Cargo.toml: v$VERSION" fi # Ensure v prefix [[ "$VERSION" == v* ]] || VERSION="v$VERSION" TAG="$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. Bump version in Cargo.toml or choose a different version." 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"