#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" cd "${PROJECT_DIR}" usage() { cat <<'USAGE' Usage: scripts/release.sh [options] Bundles the current lockfile into a portal archive and publishes the release to Gitea. Options: --lock PATH Lock file to use (default: release/toolbox.lock.json) --tag TAG Release tag to create/push (default: v) --owner OWNER Gitea owner/org (default: lotobo) --repo REPO Gitea repository (default: toolbox-portal) --api-base URL Gitea API base URL (default: https://git.add-ideas.de/api/v1) --remote REMOTE Git remote used to push the tag (default: origin) --build-dir DIR Build directory (default: build) --output-subdir DIR Assembled output directory under build-dir (default: toolbox) --skip-tests Skip npm test --skip-assemble Skip npm run assemble --skip-build Skip npm run build --skip-tag Skip tagging/push of the release tag --skip-git-push Skip pushing git branch and tag --skip-publish Skip Gitea release publish/upload --force Force overwrite of build outputs --dry-run Print commands without running remote publishing operations --help Show this help Environment: GITEA_TOKEN Personal token for Gitea API calls GITEA_API_BASE Optional override for API base URL Examples: scripts/release.sh scripts/release.sh --tag v0.20.4 --skip-tests USAGE } LOCK_FILE="release/toolbox.lock.json" OWNER="lotobo" REPO="toolbox-portal" API_BASE="${GITEA_API_BASE:-https://git.add-ideas.de/api/v1}" REMOTE="origin" BUILD_DIR="build" OUTPUT_SUBDIR="toolbox" SKIP_TESTS=0 SKIP_ASSEMBLE=0 SKIP_BUILD=0 SKIP_TAG=0 SKIP_GIT_PUSH=0 SKIP_PUBLISH=0 FORCE=0 DRY_RUN=0 while [ "$#" -gt 0 ]; do case "$1" in --lock) LOCK_FILE="$2" shift 2 ;; --tag) TAG_OVERRIDE="$2" shift 2 ;; --owner) OWNER="$2" shift 2 ;; --repo) REPO="$2" shift 2 ;; --api-base) API_BASE="$2" shift 2 ;; --remote) REMOTE="$2" shift 2 ;; --build-dir) BUILD_DIR="$2" shift 2 ;; --output-subdir) OUTPUT_SUBDIR="$2" shift 2 ;; --skip-tests) SKIP_TESTS=1 shift ;; --skip-assemble) SKIP_ASSEMBLE=1 shift ;; --skip-build) SKIP_BUILD=1 shift ;; --skip-tag) SKIP_TAG=1 shift ;; --skip-git-push) SKIP_GIT_PUSH=1 shift ;; --skip-publish) SKIP_PUBLISH=1 shift ;; --force) FORCE=1 shift ;; --dry-run) DRY_RUN=1 shift ;; --help|-h) usage exit 0 ;; *) echo "Unknown argument: $1" >&2 usage exit 1 ;; esac done run() { if [ "$DRY_RUN" -eq 1 ]; then echo "DRY-RUN: $*" return 0 fi "$@" } RELEASE_VERSION="$(node -e "const fs=require('fs');const path=process.argv[1];const lock=JSON.parse(fs.readFileSync(path,'utf8'));if(!lock?.releaseVersion){process.exit(1);}console.log(lock.releaseVersion);" "$LOCK_FILE")" if [ -z "$RELEASE_VERSION" ]; then echo "releaseVersion could not be read from ${LOCK_FILE}" >&2 exit 1 fi if [ -n "${TAG_OVERRIDE:-}" ]; then RELEASE_TAG="$TAG_OVERRIDE" else RELEASE_TAG="v${RELEASE_VERSION}" fi ZIP_FILE="${BUILD_DIR}/add-ideas-toolbox-${RELEASE_VERSION}.zip" CHECKSUM_FILE="${ZIP_FILE}.sha256" TARGET_DIR="${BUILD_DIR}/${OUTPUT_SUBDIR}" if [ "$SKIP_TESTS" -eq 0 ]; then run npm test fi if [ "$SKIP_BUILD" -eq 0 ]; then run npm run build fi if [ "$SKIP_ASSEMBLE" -eq 0 ]; then ASSEMBLE_ARGS=( npm run assemble -- --lock "$LOCK_FILE" --portal-dist dist --output "$TARGET_DIR" --archive "$ZIP_FILE" ) if [ "$FORCE" -eq 1 ]; then ASSEMBLE_ARGS+=(--force) fi run "${ASSEMBLE_ARGS[@]}" fi if [ ! -s "$ZIP_FILE" ]; then echo "Release archive missing: $ZIP_FILE" >&2 exit 1 fi if [ ! -s "$CHECKSUM_FILE" ]; then if [ "$DRY_RUN" -eq 1 ]; then echo "DRY-RUN: would create ${CHECKSUM_FILE}" else sha256sum "$ZIP_FILE" > "$CHECKSUM_FILE" fi fi if [ "$SKIP_TAG" -eq 0 ]; then if git rev-parse -q --verify "refs/tags/${RELEASE_TAG}" >/dev/null; then CURRENT_COMMIT="$(git rev-parse "${RELEASE_TAG}^{commit}")" HEAD_COMMIT="$(git rev-parse HEAD)" if [ "$CURRENT_COMMIT" != "$HEAD_COMMIT" ]; then echo "Tag ${RELEASE_TAG} already exists at ${CURRENT_COMMIT}, but HEAD is ${HEAD_COMMIT}." >&2 exit 1 fi echo "Tag exists at HEAD: ${RELEASE_TAG}" else echo "Creating tag ${RELEASE_TAG}" run git tag -a "$RELEASE_TAG" -m "toolbox ${RELEASE_TAG}" fi if [ "$SKIP_GIT_PUSH" -eq 0 ]; then run git push "$REMOTE" HEAD run git push "$REMOTE" "$RELEASE_TAG" fi fi if [ "$SKIP_PUBLISH" -eq 0 ]; then TOKEN="${GITEA_TOKEN:-}" if [ -z "$TOKEN" ]; then if [ -f "${HOME}/.config/gitea/gitea.env" ]; then # shellcheck disable=SC1091 . "${HOME}/.config/gitea/gitea.env" TOKEN="${GITEA_TOKEN:-}" fi fi if [ -z "$TOKEN" ]; then echo "GITEA_TOKEN is required for publishing (or use --skip-publish)." >&2 exit 1 fi run node scripts/publish-release.mjs \ --api-base "$API_BASE" \ --owner "$OWNER" \ --repo "$REPO" \ --tag "$RELEASE_TAG" \ --target "$(git rev-parse HEAD)" \ --name "Toolbox ${RELEASE_TAG}" \ --archive "$ZIP_FILE" \ --checksum "$CHECKSUM_FILE" \ --lock-file "$LOCK_FILE" \ --token "$TOKEN" if [ "$DRY_RUN" -eq 1 ]; then echo "Dry run complete. No assets were uploaded." else echo "Published ${RELEASE_TAG} to Gitea." fi fi echo "Release wrapper finished for ${RELEASE_TAG}"