Files
voice_linux/increment_and_push.sh
T

244 lines
6.1 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
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" # patch | minor | major
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
VERSION_FILE="$ROOT_DIR/src/version.h"
show_usage() {
cat <<'EOF'
voice_linux increment and push script
USAGE:
./increment_and_push.sh [OPTIONS] "commit message"
OPTIONS:
-p, --patch Increment patch version (default)
-m, --minor Increment minor version
-M, --major Increment major version
-r, --release Build and create a source tarball after tagging
-h, --help Show this help
EXAMPLES:
./increment_and_push.sh "Fix VAD trigger logic"
./increment_and_push.sh -m "Add live debug indicators"
./increment_and_push.sh -M "Breaking config format update"
./increment_and_push.sh -r -m "Release minor update"
EOF
}
check_git_repo() {
if ! git -C "$ROOT_DIR" rev-parse --git-dir >/dev/null 2>&1; then
print_error "Not in a git repository: $ROOT_DIR"
exit 1
fi
}
require_clean_worktree() {
if ! git -C "$ROOT_DIR" diff --quiet || ! git -C "$ROOT_DIR" diff --cached --quiet; then
print_error "Working tree is not clean. Commit or stash changes before running this script."
exit 1
fi
}
latest_version_tag() {
git -C "$ROOT_DIR" tag -l 'v*.*.*' | sort -V | tail -n 1
}
read_header_version() {
if [[ ! -f "$VERSION_FILE" ]]; then
echo "v0.0.1"
return
fi
local v
v=$(grep -E '^#define[[:space:]]+VOICE_LINUX_VERSION[[:space:]]+"v[0-9]+\.[0-9]+\.[0-9]+"' "$VERSION_FILE" | sed -E 's/.*"(v[0-9]+\.[0-9]+\.[0-9]+)".*/\1/' || true)
if [[ -z "$v" ]]; then
echo "v0.0.1"
else
echo "$v"
fi
}
parse_semver() {
local v="$1"
if [[ "$v" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
echo "${BASH_REMATCH[1]} ${BASH_REMATCH[2]} ${BASH_REMATCH[3]}"
else
print_error "Invalid version: $v"
exit 1
fi
}
increment_version() {
local current="$1"
local kind="$2"
read -r major minor patch < <(parse_semver "$current")
case "$kind" in
major)
major=$((major + 1))
minor=0
patch=0
;;
minor)
minor=$((minor + 1))
patch=0
;;
patch)
patch=$((patch + 1))
;;
*)
print_error "Unknown increment type: $kind"
exit 1
;;
esac
echo "v${major}.${minor}.${patch}"
}
update_version_header() {
local new_version="$1"
read -r major minor patch < <(parse_semver "$new_version")
if [[ ! -f "$VERSION_FILE" ]]; then
print_error "Missing $VERSION_FILE"
exit 1
fi
sed -i -E "s|^#define[[:space:]]+VOICE_LINUX_VERSION[[:space:]]+\"v[0-9]+\.[0-9]+\.[0-9]+\"|#define VOICE_LINUX_VERSION \"${new_version}\"|" "$VERSION_FILE"
sed -i -E "s|^#define[[:space:]]+VOICE_LINUX_VERSION_MAJOR[[:space:]]+[0-9]+|#define VOICE_LINUX_VERSION_MAJOR ${major}|" "$VERSION_FILE"
sed -i -E "s|^#define[[:space:]]+VOICE_LINUX_VERSION_MINOR[[:space:]]+[0-9]+|#define VOICE_LINUX_VERSION_MINOR ${minor}|" "$VERSION_FILE"
sed -i -E "s|^#define[[:space:]]+VOICE_LINUX_VERSION_PATCH[[:space:]]+[0-9]+|#define VOICE_LINUX_VERSION_PATCH ${patch}|" "$VERSION_FILE"
print_success "Updated $VERSION_FILE to $new_version"
}
create_or_replace_tag() {
local tag="$1"
if git -C "$ROOT_DIR" rev-parse "$tag" >/dev/null 2>&1; then
print_warning "Tag $tag exists, replacing locally"
git -C "$ROOT_DIR" tag -d "$tag" >/dev/null
fi
git -C "$ROOT_DIR" tag "$tag"
print_success "Created tag: $tag"
}
git_commit_push_and_tag() {
local version="$1"
local message="$2"
git -C "$ROOT_DIR" add "$VERSION_FILE"
git -C "$ROOT_DIR" commit -m "$version - $message" >/dev/null
print_success "Committed: $version - $message"
create_or_replace_tag "$version"
git -C "$ROOT_DIR" push
print_success "Pushed branch"
if git -C "$ROOT_DIR" push origin "$version"; then
print_success "Pushed tag: $version"
else
print_warning "Tag push failed, trying force push"
git -C "$ROOT_DIR" push --force origin "$version"
print_success "Force-pushed tag: $version"
fi
}
build_and_package_release() {
local version="$1"
print_status "Running release build with bash ./build.sh"
(cd "$ROOT_DIR" && bash ./build.sh)
local tarball="voice_linux-${version#v}.tar.gz"
print_status "Creating source tarball: $tarball"
(cd "$ROOT_DIR" && tar -czf "$tarball" \
--exclude='.git' \
--exclude='.git/*' \
--exclude='vendor/whisper.cpp/build/*' \
--exclude='*.o' \
--exclude='voice_linux' \
--exclude='voice_linux_gui' \
--exclude='*.tar.gz' \
.)
print_success "Created tarball: $tarball"
}
while [[ $# -gt 0 ]]; do
case "$1" in
-p|--patch)
VERSION_INCREMENT_TYPE="patch"
shift
;;
-m|--minor)
VERSION_INCREMENT_TYPE="minor"
shift
;;
-M|--major)
VERSION_INCREMENT_TYPE="major"
shift
;;
-r|--release)
RELEASE_MODE=true
shift
;;
-h|--help)
show_usage
exit 0
;;
*)
if [[ -z "$COMMIT_MESSAGE" ]]; then
COMMIT_MESSAGE="$1"
else
COMMIT_MESSAGE="$COMMIT_MESSAGE $1"
fi
shift
;;
esac
done
if [[ -z "$COMMIT_MESSAGE" ]]; then
print_error "Commit message is required"
echo ""
show_usage
exit 1
fi
print_status "voice_linux increment and push"
check_git_repo
require_clean_worktree
LATEST_TAG="$(latest_version_tag || true)"
if [[ -z "$LATEST_TAG" ]]; then
LATEST_TAG="$(read_header_version)"
print_warning "No git version tags found, using header version: $LATEST_TAG"
fi
NEW_VERSION="$(increment_version "$LATEST_TAG" "$VERSION_INCREMENT_TYPE")"
print_status "Current: $LATEST_TAG"
print_status "Next: $NEW_VERSION"
update_version_header "$NEW_VERSION"
git_commit_push_and_tag "$NEW_VERSION" "$COMMIT_MESSAGE"
if [[ "$RELEASE_MODE" == true ]]; then
build_and_package_release "$NEW_VERSION"
fi
print_success "Done: $NEW_VERSION"