#!/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"; } print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; } print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; } print_error() { echo -e "${RED}[ERROR]${NC} $1"; } # Global variables COMMIT_MESSAGE="" RELEASE_MODE=false # Parse command line arguments while [[ $# -gt 0 ]]; do case $1 in -r|--release) RELEASE_MODE=true shift ;; -h|--help) show_usage exit 0 ;; *) # First non-flag argument is the commit message if [[ -z "$COMMIT_MESSAGE" ]]; then COMMIT_MESSAGE="$1" fi shift ;; esac done show_usage() { echo "C-Relay Build and Push Script" echo "" echo "Usage:" echo " $0 \"commit message\" - Default: compile, increment patch, commit & push" echo " $0 -r \"commit message\" - Release: compile x86+arm64, increment minor, create release" echo "" echo "Examples:" echo " $0 \"Fixed event validation bug\"" echo " $0 --release \"Major release with new features\"" echo "" echo "Default Mode (patch increment):" echo " - Compile C-Relay" echo " - Increment patch version (v1.2.3 → v1.2.4)" echo " - Git add, commit with message, and push" echo "" echo "Release Mode (-r flag):" echo " - Compile C-Relay for x86_64 and arm64" echo " - Increment minor version, zero patch (v1.2.3 → v1.3.0)" echo " - Git add, commit, push, and create Gitea release" echo "" echo "Requirements for Release Mode:" echo " - For ARM64 builds: make install-arm64-deps (optional - will build x86_64 only if missing)" echo " - Gitea token in ~/.gitea_token for release uploads" } # Validate inputs if [[ -z "$COMMIT_MESSAGE" ]]; then print_error "Commit message is required" echo "" show_usage exit 1 fi # Check if we're in a git repository check_git_repo() { if ! git rev-parse --git-dir > /dev/null 2>&1; then print_error "Not in a git repository" exit 1 fi } # Function to get current version and increment appropriately increment_version() { local increment_type="$1" # "patch" or "minor" print_status "Getting current version..." # Get the highest version tag (not chronologically latest) 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 # Extract version components (remove 'v' prefix) VERSION=${LATEST_TAG#v} # Parse major.minor.patch using regex 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" print_error "Expected format: v0.1.0" exit 1 fi # Increment version based on type if [[ "$increment_type" == "minor" ]]; then # Minor release: increment minor, zero patch NEW_MINOR=$((MINOR + 1)) NEW_PATCH=0 NEW_VERSION="v${MAJOR}.${NEW_MINOR}.${NEW_PATCH}" print_status "Release mode: incrementing minor version" else # Default: increment patch NEW_PATCH=$((PATCH + 1)) NEW_VERSION="v${MAJOR}.${MINOR}.${NEW_PATCH}" print_status "Default mode: incrementing patch version" fi print_status "Current version: $LATEST_TAG" print_status "New version: $NEW_VERSION" # Export for use in other functions export NEW_VERSION } # Function to compile the C-Relay project compile_project() { print_status "Compiling C-Relay..." # Clean previous build if make clean > /dev/null 2>&1; then print_success "Cleaned previous build" else print_warning "Clean failed or no Makefile found" fi # Force regenerate version.h to pick up new tags if make force-version > /dev/null 2>&1; then print_success "Regenerated version.h" else print_warning "Failed to regenerate version.h" fi # Compile the project if make > /dev/null 2>&1; then print_success "C-Relay compiled successfully" else print_error "Compilation failed" exit 1 fi } # Function to build release binaries build_release_binaries() { print_status "Building release binaries..." # Build x86_64 version print_status "Building x86_64 version..." make clean > /dev/null 2>&1 if make x86 > /dev/null 2>&1; then if [[ -f "build/c_relay_x86" ]]; then cp build/c_relay_x86 c-relay-x86_64 print_success "x86_64 binary created: c-relay-x86_64" else print_error "x86_64 binary not found after compilation" exit 1 fi else print_error "x86_64 build failed" exit 1 fi # Try to build ARM64 version print_status "Attempting ARM64 build..." make clean > /dev/null 2>&1 if make arm64 > /dev/null 2>&1; then if [[ -f "build/c_relay_arm64" ]]; then cp build/c_relay_arm64 c-relay-arm64 print_success "ARM64 binary created: c-relay-arm64" else print_warning "ARM64 binary not found after compilation" fi else print_warning "ARM64 build failed - ARM64 cross-compilation not properly set up" print_status "Only x86_64 binary will be included in release" fi # Restore normal build make clean > /dev/null 2>&1 make > /dev/null 2>&1 } # Function to commit and push changes git_commit_and_push() { print_status "Preparing git commit..." # Stage all changes if git add . > /dev/null 2>&1; then print_success "Staged all changes" else print_error "Failed to stage changes" exit 1 fi # Check if there are changes to commit if git diff --staged --quiet; then print_warning "No changes to commit" else # Commit changes if git commit -m "$NEW_VERSION - $COMMIT_MESSAGE" > /dev/null 2>&1; then print_success "Committed changes" else print_error "Failed to commit changes" exit 1 fi fi # Create new git tag if git tag "$NEW_VERSION" > /dev/null 2>&1; then print_success "Created tag: $NEW_VERSION" else print_warning "Tag $NEW_VERSION already exists" fi # Push changes and tags print_status "Pushing to remote repository..." if git push > /dev/null 2>&1; then print_success "Pushed changes" else print_error "Failed to push changes" exit 1 fi # Push only the new tag to avoid conflicts with existing tags if git push origin "$NEW_VERSION" > /dev/null 2>&1; then print_success "Pushed tag: $NEW_VERSION" else print_warning "Tag push failed, trying force push..." if git push --force origin "$NEW_VERSION" > /dev/null 2>&1; then print_success "Force-pushed updated tag: $NEW_VERSION" else print_error "Failed to push tag: $NEW_VERSION" exit 1 fi fi } # Function to commit and push changes without creating a tag (tag already created) git_commit_and_push_no_tag() { print_status "Preparing git commit..." # Stage all changes if git add . > /dev/null 2>&1; then print_success "Staged all changes" else print_error "Failed to stage changes" exit 1 fi # Check if there are changes to commit if git diff --staged --quiet; then print_warning "No changes to commit" else # Commit changes if git commit -m "$NEW_VERSION - $COMMIT_MESSAGE" > /dev/null 2>&1; then print_success "Committed changes" else print_error "Failed to commit changes" exit 1 fi fi # Push changes and tags print_status "Pushing to remote repository..." if git push > /dev/null 2>&1; then print_success "Pushed changes" else print_error "Failed to push changes" exit 1 fi # Push only the new tag to avoid conflicts with existing tags if git push origin "$NEW_VERSION" > /dev/null 2>&1; then print_success "Pushed tag: $NEW_VERSION" else print_warning "Tag push failed, trying force push..." if git push --force origin "$NEW_VERSION" > /dev/null 2>&1; then print_success "Force-pushed updated tag: $NEW_VERSION" else print_error "Failed to push tag: $NEW_VERSION" exit 1 fi fi } # Function to create Gitea release create_gitea_release() { print_status "Creating Gitea release..." # Check for Gitea token if [[ ! -f "$HOME/.gitea_token" ]]; then print_warning "No ~/.gitea_token found. Skipping release creation." print_warning "Create ~/.gitea_token with your Gitea access token to enable releases." return 0 fi local token=$(cat "$HOME/.gitea_token" | tr -d '\n\r') local api_url="https://git.laantungir.net/api/v1/repos/laantungir/c-relay" # Create release print_status "Creating release $NEW_VERSION..." local 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 print_success "Created release $NEW_VERSION" upload_release_binaries "$api_url" "$token" elif echo "$response" | grep -q "already exists"; then print_warning "Release $NEW_VERSION already exists" upload_release_binaries "$api_url" "$token" else print_error "Failed to create release $NEW_VERSION" print_error "Response: $response" # Try to check if the release exists anyway print_status "Checking if release exists..." local check_response=$(curl -s -H "Authorization: token $token" "$api_url/releases/tags/$NEW_VERSION") if echo "$check_response" | grep -q '"id"'; then print_warning "Release exists but creation response was unexpected" upload_release_binaries "$api_url" "$token" else print_error "Release does not exist and creation failed" return 1 fi fi } # Function to upload release binaries upload_release_binaries() { local api_url="$1" local token="$2" # Get release ID with more robust parsing print_status "Getting release ID for $NEW_VERSION..." local response=$(curl -s -H "Authorization: token $token" "$api_url/releases/tags/$NEW_VERSION") local release_id=$(echo "$response" | grep -o '"id":[0-9]*' | head -n1 | cut -d: -f2) if [[ -z "$release_id" ]]; then print_error "Could not get release ID for $NEW_VERSION" print_error "API Response: $response" # Try to list all releases to debug print_status "Available releases:" curl -s -H "Authorization: token $token" "$api_url/releases" | grep -o '"tag_name":"[^"]*"' | head -5 return 1 fi print_success "Found release ID: $release_id" # Upload x86_64 binary if [[ -f "c-relay-x86_64" ]]; then print_status "Uploading x86_64 binary..." if curl -s -X POST "$api_url/releases/$release_id/assets" \ -H "Authorization: token $token" \ -F "attachment=@c-relay-x86_64;filename=c-relay-${NEW_VERSION}-linux-x86_64" > /dev/null; then print_success "Uploaded x86_64 binary" else print_warning "Failed to upload x86_64 binary" fi fi # Upload ARM64 binary if [[ -f "c-relay-arm64" ]]; then print_status "Uploading ARM64 binary..." if curl -s -X POST "$api_url/releases/$release_id/assets" \ -H "Authorization: token $token" \ -F "attachment=@c-relay-arm64;filename=c-relay-${NEW_VERSION}-linux-arm64" > /dev/null; then print_success "Uploaded ARM64 binary" else print_warning "Failed to upload ARM64 binary" fi fi } # Function to clean up release binaries cleanup_release_binaries() { if [[ -f "c-relay-x86_64" ]]; then rm -f c-relay-x86_64 print_status "Cleaned up x86_64 binary" fi if [[ -f "c-relay-arm64" ]]; then rm -f c-relay-arm64 print_status "Cleaned up ARM64 binary" fi } # Main execution main() { print_status "C-Relay Build and Push Script" # Check prerequisites check_git_repo if [[ "$RELEASE_MODE" == true ]]; then print_status "=== RELEASE MODE ===" # Increment minor version for releases increment_version "minor" # Create new git tag BEFORE compilation so version.h picks it up if git tag "$NEW_VERSION" > /dev/null 2>&1; then print_success "Created tag: $NEW_VERSION" else print_warning "Tag $NEW_VERSION already exists, removing and recreating..." git tag -d "$NEW_VERSION" > /dev/null 2>&1 git tag "$NEW_VERSION" > /dev/null 2>&1 fi # Compile project first (will now pick up the new tag) compile_project # Build release binaries build_release_binaries # Commit and push (but skip tag creation since we already did it) git_commit_and_push_no_tag # Create Gitea release with binaries create_gitea_release # Cleanup cleanup_release_binaries print_success "Release $NEW_VERSION completed successfully!" print_status "Binaries uploaded to Gitea release" else print_status "=== DEFAULT MODE ===" # Increment patch version for regular commits increment_version "patch" # Create new git tag BEFORE compilation so version.h picks it up if git tag "$NEW_VERSION" > /dev/null 2>&1; then print_success "Created tag: $NEW_VERSION" else print_warning "Tag $NEW_VERSION already exists, removing and recreating..." git tag -d "$NEW_VERSION" > /dev/null 2>&1 git tag "$NEW_VERSION" > /dev/null 2>&1 fi # Compile project (will now pick up the new tag) compile_project # Commit and push (but skip tag creation since we already did it) git_commit_and_push_no_tag print_success "Build and push completed successfully!" print_status "Version $NEW_VERSION pushed to repository" fi } # Execute main function main