404 lines
13 KiB
Bash
Executable File
404 lines
13 KiB
Bash
Executable File
#!/bin/bash
|
|
set -e
|
|
|
|
# increment_and_push.sh - Version increment and git automation script
|
|
#
|
|
# Usage:
|
|
# ./increment_and_push.sh "meaningful git comment"
|
|
# ./increment_and_push.sh -p "meaningful git comment" # patch bump (default)
|
|
# ./increment_and_push.sh -m "meaningful git comment" # minor bump
|
|
# ./increment_and_push.sh -M "meaningful git comment" # major bump
|
|
# ./increment_and_push.sh -r -p "meaningful git comment" # release: build, tag, push, gitea release + assets
|
|
# ./increment_and_push.sh --set-version vX.Y.Z "comment" # explicit version
|
|
#
|
|
# Mirrors the n_signer workflow: -p/-m/-M/-r flags, version read from git tags,
|
|
# updates both VERSION and src/version.h, and (in release mode) builds the
|
|
# binary, creates a Gitea release, and uploads the binary + source tarball.
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m'
|
|
|
|
print_status() { echo -e "${BLUE}[INFO]${NC} $1" >&2; }
|
|
print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" >&2; }
|
|
print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" >&2; }
|
|
print_error() { echo -e "${RED}[ERROR]${NC} $1" >&2; }
|
|
|
|
# --- Cleanup trap -------------------------------------------------------
|
|
# Any temp files registered here are removed on exit, including when the
|
|
# script is interrupted (Ctrl+C) or aborted by `set -e`. This prevents
|
|
# leftover sovereign_browser-*.tar.gz files from accumulating in the
|
|
# project root when a release run is interrupted.
|
|
CLEANUP_FILES=()
|
|
cleanup_on_exit() {
|
|
for f in "${CLEANUP_FILES[@]}"; do
|
|
[[ -n "$f" && -f "$f" ]] && rm -f "$f"
|
|
done
|
|
}
|
|
trap cleanup_on_exit EXIT INT TERM
|
|
register_cleanup() {
|
|
[[ -n "$1" ]] && CLEANUP_FILES+=("$1")
|
|
}
|
|
|
|
# --- Config -------------------------------------------------------------
|
|
|
|
# Gitea repo for release uploads (derived from the origin remote).
|
|
GITEA_API_URL="https://git.laantungir.net/api/v1/repos/laantungir/sovereign_browser"
|
|
BIN_NAME="sovereign_browser"
|
|
|
|
# --- Args ---------------------------------------------------------------
|
|
|
|
COMMIT_MESSAGE=""
|
|
RELEASE_MODE=false
|
|
VERSION_INCREMENT_TYPE="patch"
|
|
TARGET_VERSION=""
|
|
|
|
show_usage() {
|
|
echo "sovereign_browser Increment and Push Script"
|
|
echo ""
|
|
echo "USAGE:"
|
|
echo " $0 [OPTIONS] \"commit message\""
|
|
echo ""
|
|
echo "OPTIONS:"
|
|
echo " -p, --patch Increment patch version (default)"
|
|
echo " -m, --minor Increment minor version"
|
|
echo " -M, --major Increment major version"
|
|
echo " -r, --release Create a Gitea release with built binary + tarball"
|
|
echo " --set-version vX.Y.Z Set an explicit version instead of incrementing"
|
|
echo " -h, --help Show this help message"
|
|
echo ""
|
|
echo "EXAMPLES:"
|
|
echo " $0 \"Add hamburger menu\""
|
|
echo " $0 -m \"Security strip feature\""
|
|
echo " $0 -r -p \"Release: FIPS scheme handler\""
|
|
echo " $0 --set-version v0.1.0 \"First stable release\""
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
-r|--release)
|
|
RELEASE_MODE=true
|
|
shift
|
|
;;
|
|
-p|--patch)
|
|
VERSION_INCREMENT_TYPE="patch"
|
|
shift
|
|
;;
|
|
-m|--minor)
|
|
VERSION_INCREMENT_TYPE="minor"
|
|
shift
|
|
;;
|
|
-M|--major)
|
|
VERSION_INCREMENT_TYPE="major"
|
|
shift
|
|
;;
|
|
--set-version)
|
|
if [[ -z "$2" ]]; then
|
|
print_error "--set-version requires a version argument (vX.Y.Z)"
|
|
exit 1
|
|
fi
|
|
TARGET_VERSION="$2"
|
|
shift 2
|
|
;;
|
|
-h|--help)
|
|
show_usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
if [[ -z "$COMMIT_MESSAGE" ]]; then
|
|
COMMIT_MESSAGE="$1"
|
|
fi
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [[ -z "$COMMIT_MESSAGE" ]]; then
|
|
print_error "Commit message is required"
|
|
show_usage
|
|
exit 1
|
|
fi
|
|
|
|
# --- Checks -------------------------------------------------------------
|
|
|
|
# Check if we're in the correct directory
|
|
CURRENT_DIR=$(basename "$(pwd)")
|
|
if [ "$CURRENT_DIR" != "sovereign_browser" ]; then
|
|
print_error "Script must be run from the sovereign_browser directory"
|
|
echo ""
|
|
echo "Current directory: $CURRENT_DIR"
|
|
echo "Expected directory: sovereign_browser"
|
|
exit 1
|
|
fi
|
|
|
|
# Check if git repository exists
|
|
if ! git rev-parse --git-dir > /dev/null 2>&1; then
|
|
print_error "Not a git repository. Please initialize git first."
|
|
exit 1
|
|
fi
|
|
|
|
# Check that the version header exists (C-side source of truth)
|
|
if [ ! -f "src/version.h" ]; then
|
|
print_error "src/version.h not found"
|
|
exit 1
|
|
fi
|
|
|
|
# --- Version logic ------------------------------------------------------
|
|
|
|
update_version_files() {
|
|
local new_version="$1" # includes leading 'v'
|
|
local major="$2"
|
|
local minor="$3"
|
|
local patch="$4"
|
|
|
|
# VERSION file: plain X.Y.Z (no leading 'v'), matches nostr_core_lib
|
|
echo "$major.$minor.$patch" > VERSION
|
|
print_success "Updated VERSION file -> $major.$minor.$patch"
|
|
|
|
# src/version.h: C defines (SB_ prefix to avoid clashing with nostr_core_lib's VERSION)
|
|
sed -i "s/#define SB_VERSION .*/#define SB_VERSION \"v$major.$minor.$patch\"/" src/version.h
|
|
sed -i "s/#define SB_VERSION_MAJOR .*/#define SB_VERSION_MAJOR $major/" src/version.h
|
|
sed -i "s/#define SB_VERSION_MINOR .*/#define SB_VERSION_MINOR $minor/" src/version.h
|
|
sed -i "s/#define SB_VERSION_PATCH .*/#define SB_VERSION_PATCH $patch/" src/version.h
|
|
print_success "Updated src/version.h -> v$major.$minor.$patch"
|
|
}
|
|
|
|
increment_version() {
|
|
local increment_type="$1"
|
|
|
|
# Read the latest version from git tags (like n_signer), falling back to
|
|
# the VERSION file if no tags exist yet.
|
|
LATEST_TAG=$(git tag -l 'v*.*.*' | sort -V | tail -n 1 2>/dev/null || echo "")
|
|
if [[ -z "$LATEST_TAG" ]]; then
|
|
if [ -f "VERSION" ]; then
|
|
local file_ver
|
|
file_ver=$(tr -d '[:space:]' < VERSION)
|
|
file_ver="${file_ver#v}"
|
|
LATEST_TAG="v$file_ver"
|
|
else
|
|
LATEST_TAG="v0.0.0"
|
|
fi
|
|
print_warning "No version tags found, starting from $LATEST_TAG"
|
|
fi
|
|
|
|
VERSION=${LATEST_TAG#v}
|
|
if [[ $VERSION =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
|
|
MAJOR=${BASH_REMATCH[1]}
|
|
MINOR=${BASH_REMATCH[2]}
|
|
PATCH=${BASH_REMATCH[3]}
|
|
else
|
|
print_error "Invalid version format in tag: $LATEST_TAG"
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "$increment_type" == "major" ]]; then
|
|
NEW_VERSION="v$((MAJOR + 1)).0.0"
|
|
elif [[ "$increment_type" == "minor" ]]; then
|
|
NEW_VERSION="v${MAJOR}.$((MINOR + 1)).0"
|
|
else
|
|
NEW_VERSION="v${MAJOR}.${MINOR}.$((PATCH + 1))"
|
|
fi
|
|
|
|
local new_no_v=${NEW_VERSION#v}
|
|
local new_major=${new_no_v%%.*}
|
|
local rest=${new_no_v#*.}
|
|
local new_minor=${rest%%.*}
|
|
local new_patch=${rest##*.}
|
|
|
|
update_version_files "$NEW_VERSION" "$new_major" "$new_minor" "$new_patch"
|
|
export NEW_VERSION
|
|
}
|
|
|
|
set_explicit_version() {
|
|
if [[ ! "$TARGET_VERSION" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
|
|
print_error "Invalid target version format: $TARGET_VERSION (expected vX.Y.Z)"
|
|
exit 1
|
|
fi
|
|
NEW_VERSION="$TARGET_VERSION"
|
|
local new_no_v=${NEW_VERSION#v}
|
|
local new_major=${new_no_v%%.*}
|
|
local rest=${new_no_v#*.}
|
|
local new_minor=${rest%%.*}
|
|
local new_patch=${rest##*.}
|
|
|
|
update_version_files "$NEW_VERSION" "$new_major" "$new_minor" "$new_patch"
|
|
export NEW_VERSION
|
|
}
|
|
|
|
# --- Git operations -----------------------------------------------------
|
|
|
|
git_commit_and_push() {
|
|
git add .
|
|
|
|
if ! git diff --staged --quiet; then
|
|
git commit -m "$NEW_VERSION - $COMMIT_MESSAGE"
|
|
print_success "Changes committed"
|
|
else
|
|
print_warning "No changes to commit"
|
|
fi
|
|
|
|
# Create (or recreate) the tag.
|
|
if git tag "$NEW_VERSION" > /dev/null 2>&1; then
|
|
print_success "Created tag: $NEW_VERSION"
|
|
else
|
|
git tag -d "$NEW_VERSION" > /dev/null 2>&1 || true
|
|
git tag "$NEW_VERSION" > /dev/null 2>&1
|
|
print_warning "Replaced existing tag: $NEW_VERSION"
|
|
fi
|
|
|
|
CURRENT_BRANCH=$(git branch --show-current)
|
|
git push origin "$CURRENT_BRANCH" || print_warning "git push branch returned non-zero (continuing)"
|
|
git push origin "$NEW_VERSION" || git push --force origin "$NEW_VERSION" || print_warning "git push tag returned non-zero (continuing)"
|
|
}
|
|
|
|
# --- Release mode: build + Gitea release --------------------------------
|
|
|
|
build_release_binary() {
|
|
if [[ ! -f "build.sh" ]]; then
|
|
print_error "build.sh not found"
|
|
return 1
|
|
fi
|
|
|
|
# Prevent stale artifacts from previous builds.
|
|
rm -f "$BIN_NAME"
|
|
|
|
print_status "Building release binary..."
|
|
./build.sh > /dev/null 2>&1 || return 1
|
|
|
|
if [[ ! -x "$BIN_NAME" ]]; then
|
|
print_error "Binary not found or not executable after build: $BIN_NAME"
|
|
return 1
|
|
fi
|
|
|
|
print_success "Release binary built: $BIN_NAME"
|
|
return 0
|
|
}
|
|
|
|
create_source_tarball() {
|
|
local tarball_name="${BIN_NAME}-${NEW_VERSION#v}.tar.gz"
|
|
|
|
if tar -czf "$tarball_name" \
|
|
--exclude="$BIN_NAME" \
|
|
--exclude='.git*' \
|
|
--exclude='*.log' \
|
|
--exclude='*.tar.gz' \
|
|
--exclude='nostr_core_lib' \
|
|
--exclude='tests/local-site/assets/*.mp4' \
|
|
--exclude='tests/local-site/assets/*.m4a' \
|
|
--exclude='tests/local-site/assets/*.webm' \
|
|
--exclude='tests/local-site/assets/*.ogg' \
|
|
. > /dev/null 2>&1; then
|
|
echo "$tarball_name"
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
create_gitea_release() {
|
|
if [[ ! -f "$HOME/.gitea_token" ]]; then
|
|
print_warning "No ~/.gitea_token found. Skipping release creation."
|
|
return 0
|
|
fi
|
|
|
|
local token
|
|
token=$(tr -d '\n\r' < "$HOME/.gitea_token")
|
|
|
|
local response
|
|
response=$(curl -s -X POST "$GITEA_API_URL/releases" \
|
|
-H "Authorization: token $token" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"tag_name\": \"$NEW_VERSION\", \"name\": \"$NEW_VERSION\", \"body\": \"$COMMIT_MESSAGE\"}")
|
|
|
|
if echo "$response" | grep -q '"id"'; then
|
|
echo "$response" | grep -o '"id":[0-9]*' | head -1 | cut -d':' -f2
|
|
else
|
|
print_warning "Gitea release creation did not return an id. Response: $response"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
upload_release_assets() {
|
|
local release_id="$1"
|
|
local binary_path="$2"
|
|
local tarball_path="$3"
|
|
|
|
if [[ ! -f "$HOME/.gitea_token" ]]; then
|
|
print_warning "No ~/.gitea_token found. Skipping asset uploads."
|
|
return 0
|
|
fi
|
|
|
|
local token
|
|
token=$(tr -d '\n\r' < "$HOME/.gitea_token")
|
|
local assets_url="$GITEA_API_URL/releases/$release_id/assets"
|
|
|
|
if [[ -f "$binary_path" ]]; then
|
|
curl -s -X POST "$assets_url" \
|
|
-H "Authorization: token $token" \
|
|
-F "attachment=@$binary_path;filename=$(basename "$binary_path")" \
|
|
-F "name=$(basename "$binary_path")" > /dev/null
|
|
print_success "Uploaded binary: $(basename "$binary_path")"
|
|
fi
|
|
|
|
if [[ -f "$tarball_path" ]]; then
|
|
curl -s -X POST "$assets_url" \
|
|
-H "Authorization: token $token" \
|
|
-F "attachment=@$tarball_path;filename=$(basename "$tarball_path")" \
|
|
-F "name=$(basename "$tarball_path")" > /dev/null
|
|
print_success "Uploaded tarball: $(basename "$tarball_path")"
|
|
fi
|
|
}
|
|
|
|
# --- Main ---------------------------------------------------------------
|
|
|
|
print_status "Starting version increment and push process..."
|
|
|
|
if [[ -n "$TARGET_VERSION" ]]; then
|
|
set_explicit_version
|
|
else
|
|
increment_version "$VERSION_INCREMENT_TYPE"
|
|
fi
|
|
|
|
print_status "New version: $NEW_VERSION"
|
|
|
|
if [[ "$RELEASE_MODE" == true ]]; then
|
|
# Build before committing so a failed build aborts the release.
|
|
if ! build_release_binary; then
|
|
print_error "Release build failed; aborting before push/upload"
|
|
exit 1
|
|
fi
|
|
|
|
git_commit_and_push
|
|
|
|
local_tarball=""
|
|
local_tarball=$(create_source_tarball || true)
|
|
# Register the tarball for cleanup so it's removed on exit even if a
|
|
# later step fails or the script is interrupted. The trap also catches
|
|
# the case where create_gitea_release aborts via `set -e`.
|
|
register_cleanup "$local_tarball"
|
|
|
|
print_status "Creating Gitea release for $NEW_VERSION..."
|
|
release_id=""
|
|
release_id=$(create_gitea_release || true)
|
|
|
|
if [[ -n "$release_id" ]]; then
|
|
print_status "Uploading release assets (binary + tarball)..."
|
|
upload_release_assets "$release_id" "$BIN_NAME" "$local_tarball"
|
|
else
|
|
print_warning "Gitea release creation failed or returned no id. Binary not uploaded."
|
|
fi
|
|
|
|
# The tarball is removed by the cleanup_on_exit trap registered above,
|
|
# so no manual rm is needed here. The binary is gitignored already.
|
|
|
|
print_success "Release flow completed: $NEW_VERSION"
|
|
else
|
|
git_commit_and_push
|
|
print_success "Increment and push completed: $NEW_VERSION"
|
|
fi
|
|
|
|
echo ""
|
|
echo "🎉 Done! Version $NEW_VERSION is live."
|