263 lines
6.3 KiB
Bash
263 lines
6.3 KiB
Bash
#!/usr/bin/env bash
|
|
# Shared Git Utilities
|
|
# Sprint: CI/CD Enhancement - Script Consolidation
|
|
#
|
|
# Purpose: Common git operations for CI/CD scripts
|
|
# Usage: source "$(dirname "${BASH_SOURCE[0]}")/lib/git-utils.sh"
|
|
|
|
# Prevent multiple sourcing
|
|
if [[ -n "${__STELLAOPS_GIT_UTILS_LOADED:-}" ]]; then
|
|
return 0
|
|
fi
|
|
export __STELLAOPS_GIT_UTILS_LOADED=1
|
|
|
|
# Source dependencies
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
source "${SCRIPT_DIR}/logging.sh" 2>/dev/null || true
|
|
source "${SCRIPT_DIR}/exit-codes.sh" 2>/dev/null || true
|
|
|
|
# ============================================================================
|
|
# Repository Information
|
|
# ============================================================================
|
|
|
|
# Get repository root directory
|
|
git_root() {
|
|
git rev-parse --show-toplevel 2>/dev/null || echo "."
|
|
}
|
|
|
|
# Check if current directory is a git repository
|
|
is_git_repo() {
|
|
git rev-parse --git-dir >/dev/null 2>&1
|
|
}
|
|
|
|
# Get current commit SHA (full)
|
|
git_sha() {
|
|
git rev-parse HEAD 2>/dev/null
|
|
}
|
|
|
|
# Get current commit SHA (short)
|
|
git_sha_short() {
|
|
git rev-parse --short HEAD 2>/dev/null
|
|
}
|
|
|
|
# Get current branch name
|
|
git_branch() {
|
|
git rev-parse --abbrev-ref HEAD 2>/dev/null
|
|
}
|
|
|
|
# Get current tag (if HEAD is tagged)
|
|
git_tag() {
|
|
git describe --tags --exact-match HEAD 2>/dev/null || echo ""
|
|
}
|
|
|
|
# Get latest tag
|
|
git_latest_tag() {
|
|
git describe --tags --abbrev=0 2>/dev/null || echo ""
|
|
}
|
|
|
|
# Get remote URL
|
|
git_remote_url() {
|
|
local remote="${1:-origin}"
|
|
git remote get-url "$remote" 2>/dev/null
|
|
}
|
|
|
|
# Get repository name from remote URL
|
|
git_repo_name() {
|
|
local url
|
|
url=$(git_remote_url "${1:-origin}")
|
|
basename "$url" .git
|
|
}
|
|
|
|
# ============================================================================
|
|
# Commit Information
|
|
# ============================================================================
|
|
|
|
# Get commit message
|
|
git_commit_message() {
|
|
local sha="${1:-HEAD}"
|
|
git log -1 --format="%s" "$sha" 2>/dev/null
|
|
}
|
|
|
|
# Get commit author
|
|
git_commit_author() {
|
|
local sha="${1:-HEAD}"
|
|
git log -1 --format="%an" "$sha" 2>/dev/null
|
|
}
|
|
|
|
# Get commit author email
|
|
git_commit_author_email() {
|
|
local sha="${1:-HEAD}"
|
|
git log -1 --format="%ae" "$sha" 2>/dev/null
|
|
}
|
|
|
|
# Get commit timestamp (ISO 8601)
|
|
git_commit_timestamp() {
|
|
local sha="${1:-HEAD}"
|
|
git log -1 --format="%aI" "$sha" 2>/dev/null
|
|
}
|
|
|
|
# Get commit timestamp (Unix epoch)
|
|
git_commit_epoch() {
|
|
local sha="${1:-HEAD}"
|
|
git log -1 --format="%at" "$sha" 2>/dev/null
|
|
}
|
|
|
|
# ============================================================================
|
|
# Working Tree State
|
|
# ============================================================================
|
|
|
|
# Check if working tree is clean
|
|
git_is_clean() {
|
|
[[ -z "$(git status --porcelain 2>/dev/null)" ]]
|
|
}
|
|
|
|
# Check if working tree is dirty
|
|
git_is_dirty() {
|
|
! git_is_clean
|
|
}
|
|
|
|
# Get list of changed files
|
|
git_changed_files() {
|
|
git status --porcelain 2>/dev/null | awk '{print $2}'
|
|
}
|
|
|
|
# Get list of staged files
|
|
git_staged_files() {
|
|
git diff --cached --name-only 2>/dev/null
|
|
}
|
|
|
|
# Get list of untracked files
|
|
git_untracked_files() {
|
|
git ls-files --others --exclude-standard 2>/dev/null
|
|
}
|
|
|
|
# ============================================================================
|
|
# Diff and History
|
|
# ============================================================================
|
|
|
|
# Get files changed between two refs
|
|
git_diff_files() {
|
|
local from="${1:-HEAD~1}"
|
|
local to="${2:-HEAD}"
|
|
git diff --name-only "$from" "$to" 2>/dev/null
|
|
}
|
|
|
|
# Get files changed in last N commits
|
|
git_recent_files() {
|
|
local count="${1:-1}"
|
|
git diff --name-only "HEAD~${count}" HEAD 2>/dev/null
|
|
}
|
|
|
|
# Check if file was changed between two refs
|
|
git_file_changed() {
|
|
local file="$1"
|
|
local from="${2:-HEAD~1}"
|
|
local to="${3:-HEAD}"
|
|
git diff --name-only "$from" "$to" -- "$file" 2>/dev/null | grep -q "$file"
|
|
}
|
|
|
|
# Get commits between two refs
|
|
git_commits_between() {
|
|
local from="${1:-HEAD~10}"
|
|
local to="${2:-HEAD}"
|
|
git log --oneline "$from".."$to" 2>/dev/null
|
|
}
|
|
|
|
# ============================================================================
|
|
# Tag Operations
|
|
# ============================================================================
|
|
|
|
# Create a tag
|
|
git_create_tag() {
|
|
local tag="$1"
|
|
local message="${2:-}"
|
|
|
|
if [[ -n "$message" ]]; then
|
|
git tag -a "$tag" -m "$message"
|
|
else
|
|
git tag "$tag"
|
|
fi
|
|
}
|
|
|
|
# Delete a tag
|
|
git_delete_tag() {
|
|
local tag="$1"
|
|
git tag -d "$tag" 2>/dev/null
|
|
}
|
|
|
|
# Push tag to remote
|
|
git_push_tag() {
|
|
local tag="$1"
|
|
local remote="${2:-origin}"
|
|
git push "$remote" "$tag"
|
|
}
|
|
|
|
# List tags matching pattern
|
|
git_list_tags() {
|
|
local pattern="${1:-*}"
|
|
git tag -l "$pattern" 2>/dev/null
|
|
}
|
|
|
|
# ============================================================================
|
|
# Branch Operations
|
|
# ============================================================================
|
|
|
|
# Check if branch exists
|
|
git_branch_exists() {
|
|
local branch="$1"
|
|
git show-ref --verify --quiet "refs/heads/$branch" 2>/dev/null
|
|
}
|
|
|
|
# Check if remote branch exists
|
|
git_remote_branch_exists() {
|
|
local branch="$1"
|
|
local remote="${2:-origin}"
|
|
git show-ref --verify --quiet "refs/remotes/$remote/$branch" 2>/dev/null
|
|
}
|
|
|
|
# Get default branch
|
|
git_default_branch() {
|
|
local remote="${1:-origin}"
|
|
git remote show "$remote" 2>/dev/null | grep "HEAD branch" | awk '{print $NF}'
|
|
}
|
|
|
|
# ============================================================================
|
|
# CI/CD Helpers
|
|
# ============================================================================
|
|
|
|
# Get version string for CI builds
|
|
git_ci_version() {
|
|
local tag
|
|
tag=$(git_tag)
|
|
|
|
if [[ -n "$tag" ]]; then
|
|
echo "$tag"
|
|
else
|
|
local branch sha
|
|
branch=$(git_branch | tr '/' '-')
|
|
sha=$(git_sha_short)
|
|
echo "${branch}-${sha}"
|
|
fi
|
|
}
|
|
|
|
# Check if current commit is on default branch
|
|
git_is_default_branch() {
|
|
local current default
|
|
current=$(git_branch)
|
|
default=$(git_default_branch)
|
|
[[ "$current" == "$default" ]]
|
|
}
|
|
|
|
# Check if running in CI environment
|
|
git_is_ci() {
|
|
[[ -n "${CI:-}" ]] || [[ -n "${GITHUB_ACTIONS:-}" ]] || [[ -n "${GITLAB_CI:-}" ]]
|
|
}
|
|
|
|
# Ensure clean worktree or fail
|
|
git_require_clean() {
|
|
if git_is_dirty; then
|
|
log_error "Working tree is dirty. Commit or stash changes first."
|
|
return "${EXIT_DIRTY_WORKTREE:-71}"
|
|
fi
|
|
}
|