Files
at1-workstation-scripts/gitea_push.sh
2026-04-17 01:44:15 +02:00

299 lines
8.3 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/zsh
# Script Version: 1.6
# Description: Pushes the current folder (e.g. /etc) or a single file to a nested Gitea repo using provided nesting arguments. Auto-creates the remote repo via Gitea API if missing.
# Set variables
# ========
# Try to extract GITEA_API_TOKEN from ~/.gitea_token if not set
if [ -z "$GITEA_API_TOKEN" ] && [ -f "$HOME/.gitea_token" ]; then
GITEA_API_TOKEN=$(<"$HOME/.gitea_token")
export GITEA_API_TOKEN
fi
GITEA_USER=$(awk '{for(i=1;i<=NF;i++) if($i=="login") print $(i+1)}' ~/.netrc | head -n1)
if [ -z "$GITEA_USER" ]; then
echo "[ERROR] No login found in ~/.netrc"
exit 1
fi
GITEA_URL="https://$(awk '{for(i=1;i<=NF;i++) if($i=="machine") print $(i+1)}' ~/.netrc | head -n1)"
if [ -z "$GITEA_URL" ]; then
echo "[ERROR] No URL found in ~/.netrc"
exit 1
fi
GITEA_API_URL="$GITEA_URL/api/v1"
PRIVATE=false
DEBUG=false
COMMIT_MESSAGE="Update $(date +"%F_%T")"
SINGLE_FILE=""
TARGET_REPO=""
# Logging function
# ========
log() {
local level="$1"; shift
if [[ "$level" == "DEBUG" && "$DEBUG" != true ]]; then return; fi
local color_reset="$(tput sgr0)"
local color=""
case "$level" in
INFO) color="$(tput setaf 2)" ;; # green
WARNING) color="$(tput setaf 3)" ;; # yellow
ERROR) color="$(tput setaf 1)" ;; # red
DEBUG) color="$(tput setaf 4)" ;; # blue
esac
echo "${color}[$level] $*${color_reset}"
}
# Functions
# ========
create_repo() {
log INFO "Repository does not exist. Creating via API: $REMOTE_PATH"
log DEBUG "POST $GITEA_API_URL/user/repos with name=$REMOTE_PATH and private=$PRIVATE"
RESPONSE=$(curl -s -X POST \
-H "Authorization: token $GITEA_API_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"name\": \"$FOLDER_NAME\", \"private\": $PRIVATE}" \
"$GITEA_API_URL/user/repos")
if echo "$RESPONSE" | grep -q '"clone_url"'; then
log INFO "Remote repository created successfully."
HTTP_STATUS=200
else
log ERROR "Failed to create remote repository: $RESPONSE"
exit 1
fi
}
prepare_commit() {
if [ -n "$SINGLE_FILE" ]; then
git add "$SINGLE_FILE"
else
git add .
fi
if git diff --quiet HEAD && ! git rev-parse --verify HEAD >/dev/null 2>&1; then
log INFO "Creating initial commit"
git commit -m "$COMMIT_MESSAGE"
elif ! git diff --quiet HEAD; then
log INFO "Committing changes"
git commit -m "$COMMIT_MESSAGE"
else
log INFO "Nothing to commit"
fi
}
setup_remote() {
if git remote | grep -q '^origin$'; then
log INFO "Updating remote origin URL"
git remote set-url origin "$GIT_REMOTE"
else
log INFO "Adding remote origin"
git remote add origin "$GIT_REMOTE"
fi
}
push_changes() {
log INFO "Pushing to $GIT_REMOTE"
git push -u origin main
}
# Show help if no arguments are given
# ========
if [ $# -eq 0 ]; then
echo "GITEA_API_TOKEN=<your token>"
echo "Usage: $0 [--private] [--debug] [--message \"your commit message\"] [--file <path>] [--repo <repo_name>] <host_group>"
echo "Example: $0 server"
echo " $0 --private workstation"
echo " $0 --debug server"
echo " $0 --message \"minor update\" server"
echo " $0 --file /path/to/script.sh server"
echo " $0 --file /path/to/script.sh --repo at1-workstation-scripts server"
echo
echo "Note: Without --file, you must cd into the target folder before running this script."
echo "For example:"
echo " cd /etc && $0 server"
echo
echo "With --file, you can push a single file from any location:"
echo " $0 --file /home/user/scripts/myscript.sh server"
echo
echo "With --repo, you can specify an existing repository name instead of auto-generating:"
echo " $0 --file /path/to/script.sh --repo at1-workstation-scripts server"
echo
echo "Authentication:"
echo " Git operations (clone, push, pull) use ~/.netrc with your Git password:"
echo " machine \$(echo \"$GITEA_URL\" | sed 's|https\?://||') login $GITEA_USER password \"<your Git password>\""
echo " chmod 600 ~/.netrc"
echo
echo " API operations (e.g. creating repos) use a Personal Access Token stored in ~/.gitea_token"
echo " echo \"<your_token>\" > ~/.gitea_token && chmod 600 ~/.gitea_token"
exit 0
fi
# Parse arguments
# ========
POSITIONAL_ARGS=()
while [[ $# -gt 0 ]]; do
case "$1" in
--private)
PRIVATE=true
shift
;;
--debug)
DEBUG=true
shift
;;
--message)
COMMIT_MESSAGE="$2"
shift 2
;;
--file)
SINGLE_FILE="$2"
shift 2
;;
--repo)
TARGET_REPO="$2"
shift 2
;;
*)
POSITIONAL_ARGS+=("$1")
shift
;;
esac
done
set -- "${POSITIONAL_ARGS[@]}"
if [[ $# -ne 1 ]]; then
echo "Usage: $0 [--private] [--debug] [--message \"your commit message\"] [--file <path>] [--repo <repo_name>] <host_group>"
exit 1
fi
HOST_GROUP=$(echo "$1" | tr '[:upper:]' '[:lower:]' | tr -cd 'a-z0-9-')
HOST_NAME=$(hostname -s | tr '[:upper:]' '[:lower:]' | tr -cd 'a-z0-9-')
if [ -n "$TARGET_REPO" ]; then
# Use specified repository name
FOLDER_NAME="$TARGET_REPO"
if [ -n "$SINGLE_FILE" ]; then
# Validate file exists
if [ ! -f "$SINGLE_FILE" ]; then
log ERROR "File not found: $SINGLE_FILE"
exit 1
fi
FILE_DIR=$(dirname "$SINGLE_FILE")
REPO_PATH="$FILE_DIR"
log INFO "Using existing repo: $TARGET_REPO"
log INFO "Single file mode: $SINGLE_FILE"
else
REPO_PATH="$PWD"
log INFO "Using existing repo: $TARGET_REPO"
fi
REMOTE_PATH="$FOLDER_NAME"
GIT_REMOTE="$GITEA_URL/$GITEA_USER/$FOLDER_NAME.git"
elif [ -n "$SINGLE_FILE" ]; then
# Validate file exists
if [ ! -f "$SINGLE_FILE" ]; then
log ERROR "File not found: $SINGLE_FILE"
exit 1
fi
# Get directory and filename
FILE_DIR=$(dirname "$SINGLE_FILE")
FILE_NAME=$(basename "$SINGLE_FILE")
# Sanitize filename for repo name
FILE_NAME_SANITIZED=$(echo "$FILE_NAME" | tr '[:upper:]' '[:lower:]' | tr -cd 'a-z0-9-')
FOLDER_NAME="${HOST_NAME}-${HOST_GROUP}-${FILE_NAME_SANITIZED}"
REPO_PATH="$FILE_DIR"
REMOTE_PATH="$FOLDER_NAME"
GIT_REMOTE="$GITEA_URL/$GITEA_USER/$FOLDER_NAME.git"
log INFO "Single file mode: $SINGLE_FILE"
else
FOLDER_NAME="${HOST_NAME}-${HOST_GROUP}-$(basename "$PWD")"
REPO_PATH="$PWD"
REMOTE_PATH="$FOLDER_NAME"
GIT_REMOTE="$GITEA_URL/$GITEA_USER/$FOLDER_NAME.git"
fi
# Git authentication hint
log DEBUG "Ensure ~/.netrc has: machine <host> login $GITEA_USER password <your Git password>"
# Check or create remote repo
check_or_create_repo() {
if [ -n "$TARGET_REPO" ]; then
# Assume repo exists when --repo is specified
log INFO "Skipping repo creation (using --repo)"
HTTP_STATUS=200
return
fi
if [ -z "$GITEA_API_TOKEN" ]; then
log WARNING "GITEA_API_TOKEN is not set. Skipping API repo creation."
return
fi
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: token $GITEA_API_TOKEN" \
"$GITEA_API_URL/repos/$GITEA_USER/$FOLDER_NAME")
if [ "$HTTP_STATUS" -ne 200 ]; then
create_repo
else
log INFO "Remote repository already exists."
fi
}
check_or_create_repo
# Main Process
# ========
# Safety check against pushing from / or $HOME
if [[ "$REPO_PATH" == "$HOME" || "$REPO_PATH" == "/" ]]; then
log ERROR "Refusing to run inside \$REPO_PATH=$REPO_PATH"
exit 1
fi
log INFO "Pushing $REPO_PATH to $GIT_REMOTE"
cd "$REPO_PATH" || { log ERROR "Directory $REPO_PATH not found"; exit 1; }
# Initialize git if needed
# Branch is fixed to 'main' for simplicity and consistency
if [ ! -d .git ]; then
if [ -n "$TARGET_REPO" ]; then
# Clone existing repository when --repo is specified
log INFO "Cloning existing repository from $GIT_REMOTE"
TEMP_DIR=".gitea_push_clone_$$"
git clone "$GIT_REMOTE" "$TEMP_DIR"
# Move .git from temp dir to current dir
mv "$TEMP_DIR/.git" .git
rm -rf "$TEMP_DIR"
git config init.defaultBranch main
log INFO "Repository cloned successfully"
else
log INFO "Initializing Git repo"
git init
git config init.defaultBranch main
git checkout -b main
fi
else
log DEBUG ".git directory already present"
fi
# Ensure at least one commit exists
prepare_commit
# Set or update remote
if [ "$HTTP_STATUS" -eq 200 ]; then
setup_remote
else
log WARNING "Skipping remote setup repository does not exist."
fi
# Push to remote
if [ "$HTTP_STATUS" -eq 200 ]; then
push_changes
else
log WARNING "Skipping push repository does not exist."
fi