#!/bin/bash set -e # 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; } COMMIT_MESSAGE="" RELEASE_MODE=false VERSION_INCREMENT_TYPE="patch" VERSION_INCREMENT_EXPLICIT=false show_usage() { echo "nsigner 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 release with assets" echo " -h, --help Show this help message" } while [[ $# -gt 0 ]]; do case $1 in -r|--release) RELEASE_MODE=true shift ;; -p|--patch) VERSION_INCREMENT_TYPE="patch" VERSION_INCREMENT_EXPLICIT=true shift ;; -m|--minor) VERSION_INCREMENT_TYPE="minor" VERSION_INCREMENT_EXPLICIT=true shift ;; -M|--major) VERSION_INCREMENT_TYPE="major" VERSION_INCREMENT_EXPLICIT=true shift ;; -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 check_git_repo() { if ! git rev-parse --git-dir > /dev/null 2>&1; then print_error "Not in a git repository" exit 1 fi } update_version_in_header() { local new_version="$1" local major="$2" local minor="$3" local patch="$4" local version_file="" if [[ -f "src/main.h" ]]; then version_file="src/main.h" elif [[ -f "src/main.c" ]]; then version_file="src/main.c" else print_error "Neither src/main.h nor src/main.c found" exit 1 fi sed -i "s/#define NSIGNER_VERSION \".*\"/#define NSIGNER_VERSION \"$new_version\"/" "$version_file" sed -i "s/#define NSIGNER_VERSION_MAJOR [0-9]\+/#define NSIGNER_VERSION_MAJOR $major/" "$version_file" sed -i "s/#define NSIGNER_VERSION_MINOR [0-9]\+/#define NSIGNER_VERSION_MINOR $minor/" "$version_file" sed -i "s/#define NSIGNER_VERSION_PATCH [0-9]\+/#define NSIGNER_VERSION_PATCH $patch/" "$version_file" print_success "Updated $version_file to $new_version" } increment_version() { local increment_type="$1" LATEST_TAG=$(git tag -l 'v*.*.*' | sort -V | tail -n 1 || echo "") if [[ -z "$LATEST_TAG" ]]; then LATEST_TAG="v0.0.0" 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_in_header "$NEW_VERSION" "$new_major" "$new_minor" "$new_patch" export NEW_VERSION } git_commit_and_push_no_tag() { git add . if ! git diff --staged --quiet; then git commit -m "$NEW_VERSION - $COMMIT_MESSAGE" else print_warning "No changes to commit" fi git push git push origin "$NEW_VERSION" || git push --force origin "$NEW_VERSION" } verify_binary_version() { local bin_path="$1" local expected="$2" if [[ ! -x "$bin_path" ]]; then print_error "Binary not found or not executable: $bin_path" return 1 fi local got got="$($bin_path --version 2>/dev/null | awk '{print $2}')" if [[ "$got" != "$expected" ]]; then print_error "Binary version mismatch for $(basename "$bin_path"): expected $expected, got ${got:-}" return 1 fi return 0 } build_release_binary() { if [[ ! -f "build_static.sh" ]]; then print_error "build_static.sh not found" return 1 fi # Prevent stale artifacts from previous builds being uploaded. rm -f build/nsigner_static_x86_64 build/nsigner_static_arm64 ./build_static.sh > /dev/null 2>&1 || return 1 verify_binary_version "build/nsigner_static_x86_64" "$NEW_VERSION" || return 1 ./build_static.sh --arch arm64 > /dev/null 2>&1 || print_warning "ARM64 build failed (continuing)" if [[ -x "build/nsigner_static_arm64" ]]; then verify_binary_version "build/nsigner_static_arm64" "$NEW_VERSION" || return 1 fi return 0 } create_source_tarball() { local tarball_name="nsigner-${NEW_VERSION#v}.tar.gz" if tar -czf "$tarball_name" \ --exclude='build/*' \ --exclude='.git*' \ --exclude='*.log' \ --exclude='*.tar.gz' \ . > /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=$(cat "$HOME/.gitea_token" | tr -d '\n\r') local api_url="https://git.laantungir.net/api/v1/repos/laantungir/n_signer" local response response=$(curl -s -X POST "$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 return 1 fi } upload_release_assets() { local release_id="$1" local binary_path_x86="$2" local tarball_path="$3" local binary_path_arm64="$4" if [[ ! -f "$HOME/.gitea_token" ]]; then print_warning "No ~/.gitea_token found. Skipping asset uploads." return 0 fi local token token=$(cat "$HOME/.gitea_token" | tr -d '\n\r') local api_url="https://git.laantungir.net/api/v1/repos/laantungir/n_signer" local assets_url="$api_url/releases/$release_id/assets" if [[ -f "$binary_path_x86" ]]; then curl -s -X POST "$assets_url" \ -H "Authorization: token $token" \ -F "attachment=@$binary_path_x86;filename=$(basename "$binary_path_x86")" \ -F "name=$(basename "$binary_path_x86")" > /dev/null fi if [[ -f "$binary_path_arm64" ]]; then curl -s -X POST "$assets_url" \ -H "Authorization: token $token" \ -F "attachment=@$binary_path_arm64;filename=$(basename "$binary_path_arm64")" \ -F "name=$(basename "$binary_path_arm64")" > /dev/null 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 fi } main() { check_git_repo if [[ "$RELEASE_MODE" == true ]]; then increment_version "$VERSION_INCREMENT_TYPE" 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 fi if ! build_release_binary; then print_error "x86_64 release build failed; aborting release before push/upload" exit 1 fi git_commit_and_push_no_tag local binary_path_x86="build/nsigner_static_x86_64" local binary_path_arm64="build/nsigner_static_arm64" local tarball_path="" tarball_path=$(create_source_tarball || true) local release_id="" release_id=$(create_gitea_release || true) if [[ -n "$release_id" ]]; then upload_release_assets "$release_id" "$binary_path_x86" "$tarball_path" "$binary_path_arm64" fi print_success "Release flow completed" else increment_version "$VERSION_INCREMENT_TYPE" 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 fi git_commit_and_push_no_tag print_success "Increment and push completed" fi } main