#!/bin/zsh # Script Version: 1.6 # Description: Pushes the current folder (e.g. /etc) 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")" # 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 6)" ;; # cyan (was green) WARNING) color="$(tput setaf 3)" ;; # yellow ERROR) color="$(tput setaf 1)" ;; # red DEBUG) color="$(tput bold; tput setaf 4)" ;; # bold blue # 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() { git add . git diff --quiet HEAD HAS_CHANGES=$? if [ $HAS_CHANGES -eq 1 ] && ! git rev-parse --verify HEAD >/dev/null 2>&1; then log INFO "Creating initial commit" git commit -m "$COMMIT_MESSAGE" elif [ $HAS_CHANGES -eq 1 ]; 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=" echo "Usage: $0 [--private] [--debug] [--message \"your commit message\"] " echo "Example: $0 server" echo " $0 --private workstation" echo " $0 --debug server" echo " $0 --message \"minor update\" server" echo echo "Note: You must cd into the target folder before running this script." echo "For example:" echo " cd /etc && $0 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 \"\"" echo " chmod 600 ~/.netrc" echo echo " API operations (e.g. creating repos) use a Personal Access Token stored in ~/.gitea_token" echo " echo \"\" > ~/.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 ;; *) POSITIONAL_ARGS+=("$1") shift ;; esac done set -- "${POSITIONAL_ARGS[@]}" if [[ $# -ne 1 ]]; then echo "Usage: $0 [--private] [--debug] [--message \"your commit message\"] " 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-') FOLDER_NAME="${HOST_NAME}-${HOST_GROUP}-$(basename "$PWD")" REPO_PATH="$PWD" REMOTE_PATH="$FOLDER_NAME" GIT_REMOTE="$GITEA_URL/$GITEA_USER/$FOLDER_NAME.git" # Git authentication hint log DEBUG "Ensure ~/.netrc has: machine login $GITEA_USER password " # Check or create remote repo check_or_create_repo() { 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 # ======== # Ensure Git user identity is configured log DEBUG "Checking Git user configuration..." if ! git config user.name >/dev/null 2>&1; then git config --global user.name "$(whoami)" log DEBUG "Set Git user.name to $(whoami)" else log DEBUG "Git user.name already set to $(git config --show-origin user.name)" fi if ! git config user.email >/dev/null 2>&1; then git config --global user.email "$(whoami)@$(hostname -f)" log DEBUG "Set Git user.email to $(whoami)@$(hostname -f)" else log DEBUG "Git user.email already set to $(git config --show-origin user.email)" fi # Safety check against pushing from / or $HOME if [[ "$PWD" == "$HOME" || "$PWD" == "/" ]]; then log ERROR "Refusing to run inside \$PWD=$PWD" 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 log INFO "Initializing Git repo" git init git config init.defaultBranch main git checkout -b main else CURRENT_BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null) if [ "$CURRENT_BRANCH" != "main" ]; then log WARNING "Current branch is '$CURRENT_BRANCH', renaming to 'main'" git branch -m main fi log DEBUG ".git directory already present" 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