Files
c-relay/increment_and_push.sh
2025-10-18 15:04:45 -04:00

364 lines
11 KiB
Bash
Executable File

#!/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
show_usage() {
echo "C-Relay Increment and Push Script"
echo ""
echo "Usage:"
echo " $0 \"commit message\" - Default: increment patch, commit & push"
echo " $0 -r \"commit message\" - Release: 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 " - Increment patch version (v1.2.3 → v1.2.4)"
echo " - Git add, commit with message, and push"
echo ""
echo "Release Mode (-r flag):"
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 " - Gitea token in ~/.gitea_token for release uploads"
}
# 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
# 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"
# Update version in src/main.h
update_version_in_header "$NEW_VERSION" "$MAJOR" "${NEW_MINOR:-$MINOR}" "${NEW_PATCH:-$PATCH}"
# Export for use in other functions
export NEW_VERSION
}
# Function to update version macros in src/main.h
update_version_in_header() {
local new_version="$1"
local major="$2"
local minor="$3"
local patch="$4"
print_status "Updating version in src/main.h..."
# Check if src/main.h exists
if [[ ! -f "src/main.h" ]]; then
print_error "src/main.h not found"
exit 1
fi
# Update VERSION macro
sed -i "s/#define VERSION \".*\"/#define VERSION \"$new_version\"/" src/main.h
# Update VERSION_MAJOR macro
sed -i "s/#define VERSION_MAJOR [0-9]\+/#define VERSION_MAJOR $major/" src/main.h
# Update VERSION_MINOR macro
sed -i "s/#define VERSION_MINOR .*/#define VERSION_MINOR $minor/" src/main.h
# Update VERSION_PATCH macro
sed -i "s/#define VERSION_PATCH [0-9]\+/#define VERSION_PATCH $patch/" src/main.h
print_success "Updated version in src/main.h to $new_version"
}
# 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"
return 0
elif echo "$response" | grep -q "already exists"; then
print_warning "Release $NEW_VERSION already exists"
return 0
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"
return 0
else
print_error "Release does not exist and creation failed"
return 1
fi
fi
}
# Main execution
main() {
print_status "C-Relay Increment 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
# Commit and push (but skip tag creation since we already did it)
git_commit_and_push_no_tag
# Create Gitea release
if create_gitea_release; then
print_success "Release $NEW_VERSION completed successfully!"
else
print_error "Release creation failed"
fi
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
# Commit and push (but skip tag creation since we already did it)
git_commit_and_push_no_tag
print_success "Increment and push completed successfully!"
print_status "Version $NEW_VERSION pushed to repository"
fi
}
# Execute main function
main