GITEA_API_TOKEN is for the local platform Gitea (docs comments, user provisioning, SSO). New GITEA_REGISTRY_API_TOKEN is for the remote registry at gitea.bnkops.com (release uploads via build-release.sh). Previously both contexts shared one variable, causing auth failures when the token for one instance was used against the other. Bunker Admin
240 lines
8.1 KiB
Bash
Executable File
240 lines
8.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# =============================================================================
|
|
# Changemaker Lite V2 — Build Release Tarball
|
|
#
|
|
# Creates a lightweight release tarball (~1-2 MB) containing only runtime files
|
|
# needed to deploy with pre-built Docker images. No source code included.
|
|
#
|
|
# Usage:
|
|
# ./scripts/build-release.sh [OPTIONS]
|
|
#
|
|
# Options:
|
|
# --tag TAG Version tag (default: git describe or commit SHA)
|
|
# --output DIR Output directory (default: ./releases/)
|
|
# --upload Upload to Gitea Releases API after building
|
|
# --dry-run Show what would be included without creating tarball
|
|
# --help Show this help
|
|
#
|
|
# Prerequisites:
|
|
# Run ./scripts/build-and-push.sh first to push Docker images to registry.
|
|
# =============================================================================
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
|
|
|
# --- Defaults ---
|
|
TAG=""
|
|
OUTPUT_DIR="${PROJECT_DIR}/releases"
|
|
UPLOAD=false
|
|
DRY_RUN=false
|
|
|
|
# --- Colors ---
|
|
if [[ -t 1 ]] && [[ -z "${NO_COLOR:-}" ]]; then
|
|
RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m'
|
|
BLUE='\033[0;34m' CYAN='\033[0;36m' BOLD='\033[1m' NC='\033[0m'
|
|
else
|
|
RED='' GREEN='' YELLOW='' BLUE='' CYAN='' BOLD='' NC=''
|
|
fi
|
|
|
|
info() { echo -e "${BLUE}[INFO]${NC} $*"; }
|
|
success() { echo -e "${GREEN}[OK]${NC} $*"; }
|
|
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
|
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
|
|
|
# --- Arg parser ---
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--tag) TAG="$2"; shift 2 ;;
|
|
--output) OUTPUT_DIR="$2"; shift 2 ;;
|
|
--upload) UPLOAD=true; shift ;;
|
|
--dry-run) DRY_RUN=true; shift ;;
|
|
--help|-h)
|
|
sed -n '2,20p' "$0" | grep '^#' | sed 's/^# \?//'
|
|
exit 0 ;;
|
|
*) error "Unknown option: $1"; exit 1 ;;
|
|
esac
|
|
done
|
|
|
|
# --- Determine version ---
|
|
cd "$PROJECT_DIR"
|
|
if [[ -z "$TAG" ]]; then
|
|
TAG="$(git describe --tags --always 2>/dev/null || git rev-parse --short HEAD)"
|
|
fi
|
|
COMMIT_SHA="$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")"
|
|
BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
|
|
echo -e "${BOLD}Changemaker Lite — Build Release${NC}"
|
|
echo " Tag: $TAG"
|
|
echo " Commit: $COMMIT_SHA"
|
|
echo " Date: $BUILD_DATE"
|
|
echo ""
|
|
|
|
# --- Create staging directory ---
|
|
STAGE_DIR="$(mktemp -d)/changemaker-lite"
|
|
mkdir -p "$STAGE_DIR"
|
|
|
|
# --- Write VERSION file ---
|
|
cat > "$STAGE_DIR/VERSION" << EOF
|
|
$TAG
|
|
$COMMIT_SHA
|
|
$BUILD_DATE
|
|
EOF
|
|
info "VERSION: $TAG ($COMMIT_SHA)"
|
|
|
|
# --- Copy production docker-compose ---
|
|
if [[ ! -f "$PROJECT_DIR/docker-compose.prod.yml" ]]; then
|
|
error "docker-compose.prod.yml not found. Generate it first."
|
|
exit 1
|
|
fi
|
|
cp "$PROJECT_DIR/docker-compose.prod.yml" "$STAGE_DIR/docker-compose.yml"
|
|
info "docker-compose.yml (production)"
|
|
|
|
# --- Copy config files ---
|
|
cp "$PROJECT_DIR/.env.example" "$STAGE_DIR/"
|
|
cp "$PROJECT_DIR/config.sh" "$STAGE_DIR/"
|
|
info "Config files (.env.example, config.sh)"
|
|
|
|
# --- Copy scripts ---
|
|
mkdir -p "$STAGE_DIR/scripts"
|
|
|
|
# Init scripts (from api/prisma/ to scripts/)
|
|
cp "$PROJECT_DIR/api/prisma/init-nocodb-db.sh" "$STAGE_DIR/scripts/"
|
|
cp "$PROJECT_DIR/api/prisma/init-gancio-db.sh" "$STAGE_DIR/scripts/"
|
|
|
|
# Runtime scripts
|
|
for script in nocodb-init.sh mkdocs-entrypoint.sh backup.sh \
|
|
upgrade.sh upgrade-check.sh upgrade-watcher.sh; do
|
|
if [[ -f "$PROJECT_DIR/scripts/$script" ]]; then
|
|
cp "$PROJECT_DIR/scripts/$script" "$STAGE_DIR/scripts/"
|
|
fi
|
|
done
|
|
|
|
# MkDocs build trigger
|
|
if [[ -f "$PROJECT_DIR/scripts/mkdocs-build-trigger.py" ]]; then
|
|
cp "$PROJECT_DIR/scripts/mkdocs-build-trigger.py" "$STAGE_DIR/scripts/"
|
|
fi
|
|
|
|
# Systemd units
|
|
if [[ -d "$PROJECT_DIR/scripts/systemd" ]]; then
|
|
cp -r "$PROJECT_DIR/scripts/systemd" "$STAGE_DIR/scripts/"
|
|
fi
|
|
|
|
# Install script (for reference)
|
|
cp "$PROJECT_DIR/scripts/install.sh" "$STAGE_DIR/scripts/"
|
|
|
|
chmod +x "$STAGE_DIR/scripts/"*.sh 2>/dev/null || true
|
|
info "Scripts ($(ls "$STAGE_DIR/scripts/" | wc -l) files)"
|
|
|
|
# --- Copy configs ---
|
|
if [[ -d "$PROJECT_DIR/configs" ]]; then
|
|
cp -r "$PROJECT_DIR/configs" "$STAGE_DIR/"
|
|
# Ensure code-server skeleton dirs exist
|
|
mkdir -p "$STAGE_DIR/configs/code-server/.config"
|
|
mkdir -p "$STAGE_DIR/configs/code-server/.local"
|
|
info "Configs (homepage, prometheus, grafana, alertmanager, pangolin)"
|
|
fi
|
|
|
|
# --- Copy nginx templates (for reference) ---
|
|
mkdir -p "$STAGE_DIR/nginx/conf.d"
|
|
cp "$PROJECT_DIR"/nginx/conf.d/*.template "$STAGE_DIR/nginx/conf.d/" 2>/dev/null || true
|
|
info "Nginx templates (for reference)"
|
|
|
|
# --- Copy MkDocs starter docs ---
|
|
if [[ -d "$PROJECT_DIR/mkdocs" ]]; then
|
|
mkdir -p "$STAGE_DIR/mkdocs"
|
|
cp "$PROJECT_DIR/mkdocs/mkdocs.yml" "$STAGE_DIR/mkdocs/" 2>/dev/null || true
|
|
cp -r "$PROJECT_DIR/mkdocs/docs" "$STAGE_DIR/mkdocs/" 2>/dev/null || mkdir -p "$STAGE_DIR/mkdocs/docs"
|
|
cp -r "$PROJECT_DIR/mkdocs/overrides" "$STAGE_DIR/mkdocs/" 2>/dev/null || mkdir -p "$STAGE_DIR/mkdocs/overrides"
|
|
mkdir -p "$STAGE_DIR/mkdocs/.cache"
|
|
mkdir -p "$STAGE_DIR/mkdocs/site"
|
|
info "MkDocs (starter documentation)"
|
|
fi
|
|
|
|
# --- Copy public-web ---
|
|
if [[ -d "$PROJECT_DIR/public-web" ]]; then
|
|
cp -r "$PROJECT_DIR/public-web" "$STAGE_DIR/"
|
|
else
|
|
mkdir -p "$STAGE_DIR/public-web"
|
|
fi
|
|
info "Public web assets"
|
|
|
|
# --- Create empty data directories ---
|
|
mkdir -p "$STAGE_DIR/assets/uploads"
|
|
mkdir -p "$STAGE_DIR/assets/icons"
|
|
mkdir -p "$STAGE_DIR/assets/images"
|
|
mkdir -p "$STAGE_DIR/data/upgrade"
|
|
mkdir -p "$STAGE_DIR/media/local/inbox"
|
|
mkdir -p "$STAGE_DIR/media/local/thumbnails"
|
|
mkdir -p "$STAGE_DIR/media/local/photos"
|
|
mkdir -p "$STAGE_DIR/media/public"
|
|
mkdir -p "$STAGE_DIR/local-files"
|
|
info "Data directories (empty)"
|
|
|
|
# --- Summary ---
|
|
echo ""
|
|
STAGE_SIZE=$(du -sh "$STAGE_DIR" | cut -f1)
|
|
FILE_COUNT=$(find "$STAGE_DIR" -type f | wc -l)
|
|
info "Staging: ${FILE_COUNT} files, ${STAGE_SIZE}"
|
|
|
|
if [[ "$DRY_RUN" == "true" ]]; then
|
|
echo ""
|
|
info "[DRY RUN] Would create: changemaker-lite-${TAG}.tar.gz"
|
|
find "$STAGE_DIR" -type f | sed "s|$STAGE_DIR/||" | sort
|
|
rm -rf "$(dirname "$STAGE_DIR")"
|
|
exit 0
|
|
fi
|
|
|
|
# --- Create tarball ---
|
|
mkdir -p "$OUTPUT_DIR"
|
|
TARBALL="${OUTPUT_DIR}/changemaker-lite-${TAG}.tar.gz"
|
|
|
|
tar czf "$TARBALL" -C "$(dirname "$STAGE_DIR")" "changemaker-lite"
|
|
rm -rf "$(dirname "$STAGE_DIR")"
|
|
|
|
TARBALL_SIZE=$(du -h "$TARBALL" | cut -f1)
|
|
success "Created: $TARBALL (${TARBALL_SIZE})"
|
|
|
|
# --- Upload to Gitea (optional) ---
|
|
if [[ "$UPLOAD" == "true" ]]; then
|
|
source "$PROJECT_DIR/.env" 2>/dev/null || true
|
|
# GITEA_REGISTRY_API_TOKEN is for the remote registry (gitea.bnkops.com)
|
|
# GITEA_API_TOKEN is for the local platform Gitea — do NOT use it here
|
|
GITEA_TOKEN="${GITEA_REGISTRY_API_TOKEN:-}"
|
|
# GITEA_URL is the internal Docker hostname — use GITEA_REGISTRY for external access
|
|
GITEA_REGISTRY_HOST="${GITEA_REGISTRY%%/*}" # strip /admin path → gitea.bnkops.com
|
|
GITEA_HOST="${GITEA_EXTERNAL_URL:-https://${GITEA_REGISTRY_HOST:-gitea.bnkops.com}}"
|
|
|
|
if [[ -z "$GITEA_TOKEN" ]]; then
|
|
warn "GITEA_REGISTRY_API_TOKEN not set — skipping upload"
|
|
warn "Set GITEA_REGISTRY_API_TOKEN in .env and re-run with --upload"
|
|
else
|
|
info "Creating Gitea release ${TAG}..."
|
|
RELEASE_RESPONSE=$(curl -sf -X POST \
|
|
"${GITEA_HOST}/api/v1/repos/admin/changemaker.lite/releases" \
|
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"tag_name\":\"${TAG}\",\"name\":\"Changemaker Lite ${TAG}\",\"body\":\"Release ${TAG} (${COMMIT_SHA})\"}" \
|
|
2>/dev/null || true)
|
|
|
|
RELEASE_ID=$(echo "$RELEASE_RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
|
|
|
|
if [[ -n "$RELEASE_ID" ]]; then
|
|
info "Uploading tarball to release ${RELEASE_ID}..."
|
|
curl -sf -X POST \
|
|
"${GITEA_HOST}/api/v1/repos/admin/changemaker.lite/releases/${RELEASE_ID}/assets" \
|
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
-F "attachment=@${TARBALL}" \
|
|
>/dev/null 2>&1
|
|
success "Uploaded to Gitea release ${TAG}"
|
|
else
|
|
warn "Failed to create release — upload manually at ${GITEA_HOST}/admin/changemaker.lite/releases"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
echo ""
|
|
success "Release ${TAG} ready."
|
|
echo " Tarball: $TARBALL"
|
|
echo " Install: tar xzf $(basename "$TARBALL") && cd changemaker-lite && bash config.sh"
|