gitfield-codeberg
1 #!/bin/bash 2 set -euo pipefail 3 IFS=$'\n\t' 4 5 # Configuration 6 GIT_REMOTE_NAME="codeberg" 7 CODEBERG_DOMAIN="codeberg.org" 8 CODEBERG_SSH="git@$CODEBERG_DOMAIN" 9 CODEBERG_SSH_PORT="22" 10 CODEBERG_API="https://$CODEBERG_DOMAIN/api/v1" 11 USERNAME="mrhavens" 12 REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null) || { echo "[ERROR] Not inside a git repository. Please run this script from within a git repository." >&2; exit 1; } 13 REPO_NAME=$(basename "$REPO_ROOT") || { echo "[ERROR] Failed to get repository name" >&2; exit 1; } 14 MARKDOWN_FILE="$REPO_ROOT/.gitfield/codeberg.sigil.md" 15 DEFAULT_NAME="Mark Randall Havens" 16 DEFAULT_EMAIL="mark.r.havens@gmail.com" 17 TOKEN_FILE="$HOME/.codeberg_token" 18 SCRIPT_VERSION="1.0" 19 20 # Logging functions 21 info() { echo -e "\e[1;34m[INFO]\e[0m $*"; } 22 warn() { echo -e "\e[1;33m[WARN]\e[0m $*"; } 23 error() { echo -e "\e[1;31m[ERROR]\e[0m $*" >&2; exit 1; } 24 25 # Check for required tools 26 info "Checking for required tools..." 27 for cmd in git curl jq ssh lsb_release; do 28 command -v "$cmd" >/dev/null || { 29 sudo apt update -qq || warn "Failed to update package lists, continuing..." 30 sudo apt install -y git curl jq openssh-client lsb-release || error "Failed to install $cmd" 31 } 32 done 33 34 # Handle Codeberg token 35 RESET_TOKEN=false 36 if [[ "${1:-}" == "--reset-token" ]]; then 37 RESET_TOKEN=true 38 rm -f "$TOKEN_FILE" 2>/dev/null || warn "Failed to remove token file" 39 info "Token reset requested." 40 fi 41 42 if [[ -f "$TOKEN_FILE" && "$RESET_TOKEN" == false ]]; then 43 TOKEN=$(cat "$TOKEN_FILE" 2>/dev/null) || error "Failed to read token from $TOKEN_FILE" 44 info "Using cached token from $TOKEN_FILE" 45 else 46 echo "š Paste your Codeberg Personal Access Token (scopes: write:repository, write:ssh_key)" 47 echo "ā Generate at: $CODEBERG_DOMAIN/settings/tokens" 48 read -rsp "Token: " TOKEN 49 echo 50 [[ -z "$TOKEN" ]] && error "Token cannot be empty" 51 echo "$TOKEN" > "$TOKEN_FILE" || error "Failed to write token to $TOKEN_FILE" 52 chmod 600 "$TOKEN_FILE" || error "Failed to set permissions on $TOKEN_FILE" 53 info "Token saved at $TOKEN_FILE" 54 fi 55 56 # Set git user info 57 git config --global user.name "$DEFAULT_NAME" || warn "Failed to set git user name" 58 git config --global user.email "$DEFAULT_EMAIL" || warn "Failed to set git user email" 59 info "Git identity set to: $DEFAULT_NAME <$DEFAULT_EMAIL>" 60 61 # Ensure at least one commit exists 62 if ! git rev-parse HEAD &>/dev/null; then 63 error "No commits found in the repository. Please add and commit files before running this script." 64 fi 65 66 # SSH setup with default port (22 for Codeberg) 67 if [[ ! -f "$HOME/.ssh/id_ed25519" ]]; then 68 info "Generating SSH key..." 69 ssh-keygen -t ed25519 -C "$DEFAULT_EMAIL" -f "$HOME/.ssh/id_ed25519" -N "" || error "Failed to generate SSH key" 70 fi 71 72 eval "$(ssh-agent -s)" >/dev/null 2>&1 || error "Failed to start ssh-agent" 73 ssh-add "$HOME/.ssh/id_ed25519" >/dev/null 2>&1 || warn "SSH key already added or could not be added" 74 75 # Configure SSH for Codeberg 76 SSH_CONFIG_FILE="$HOME/.ssh/config" 77 if ! grep -q "Host $CODEBERG_DOMAIN" "$SSH_CONFIG_FILE" 2>/dev/null; then 78 mkdir -p "$HOME/.ssh" && chmod 700 "$HOME/.ssh" 79 cat >> "$SSH_CONFIG_FILE" <<EOF 80 Host $CODEBERG_DOMAIN 81 HostName $CODEBERG_DOMAIN 82 User git 83 Port $CODEBERG_SSH_PORT 84 IdentityFile $HOME/.ssh/id_ed25519 85 StrictHostKeyChecking no 86 UserKnownHostsFile /dev/null 87 EOF 88 chmod 600 "$SSH_CONFIG_FILE" || warn "Failed to set permissions on SSH config file" 89 info "Added SSH config for $CODEBERG_DOMAIN with port $CODEBERG_SSH_PORT" 90 fi 91 92 # SSH key upload to Codeberg 93 set +e 94 info "Testing SSH connection..." 95 SSH_TEST_OUTPUT=$(ssh -T -p "$CODEBERG_SSH_PORT" "$CODEBERG_SSH" 2>&1) 96 if ! echo "$SSH_TEST_OUTPUT" | grep -q "successfully authenticated"; then 97 warn "SSH test failed, attempting to upload SSH key. Output: $SSH_TEST_OUTPUT" 98 PUBKEY=$(cat "$HOME/.ssh/id_ed25519.pub" 2>/dev/null) || error "Failed to read SSH public key" 99 TITLE="AutoKey-$(hostname)-$(date +%s 2>/dev/null || echo 'unknown')" 100 CURL_OUTPUT=$(curl -s --fail -X POST "$CODEBERG_API/user/keys" \ 101 -H "Authorization: token $TOKEN" \ 102 -H "Content-Type: application/json" \ 103 -d "{\"title\": \"$TITLE\", \"key\": \"$PUBKEY\", \"read_only\": false}" 2>&1) 104 if [[ $? -ne 0 ]]; then 105 warn "SSH key upload failed: $CURL_OUTPUT" 106 else 107 info "SSH key uploaded successfully." 108 sleep 2 109 SSH_TEST_OUTPUT=$(ssh -T -p "$CODEBERG_SSH_PORT" "$CODEBERG_SSH" 2>&1) 110 if ! echo "$SSH_TEST_OUTPUT" | grep -q "successfully authenticated"; then 111 warn "SSH test still failing after key upload. Output: $SSH_TEST_OUTPUT" 112 else 113 info "SSH test passed after key upload." 114 fi 115 fi 116 else 117 info "SSH test passed: $SSH_TEST_OUTPUT" 118 fi 119 set -e 120 121 # Check and create Codeberg repository 122 info "Checking if repository exists..." 123 EXISTS=$(curl -s -H "Authorization: token $TOKEN" "$CODEBERG_API/repos/$USERNAME/$REPO_NAME" | jq -r .name 2>/dev/null || echo "") 124 if [[ "$EXISTS" != "$REPO_NAME" ]]; then 125 info "Creating repository $REPO_NAME on Codeberg..." 126 CURL_OUTPUT=$(curl -s --fail -X POST "$CODEBERG_API/user/repos" \ 127 -H "Authorization: token $TOKEN" \ 128 -H "Content-Type: application/json" \ 129 -d "{\"name\": \"$REPO_NAME\", \"description\": \"Created via gitfield-codeberg\", \"private\": false}" 2>&1) || { 130 warn "Failed to create repository: $CURL_OUTPUT" 131 error "Repository creation failed. Check token permissions or network." 132 } 133 info "Repository created successfully." 134 fi 135 136 # Set up git remote 137 REMOTE_URL="$CODEBERG_SSH:$USERNAME/$REPO_NAME.git" 138 if ! git remote get-url "$GIT_REMOTE_NAME" &>/dev/null; then 139 info "Adding remote $GIT_REMOTE_NAME..." 140 git remote add "$GIT_REMOTE_NAME" "$REMOTE_URL" || error "Failed to add remote $GIT_REMOTE_NAME" 141 else 142 info "Updating remote $GIT_REMOTE_NAME..." 143 git remote set-url "$GIT_REMOTE_NAME" "$REMOTE_URL" || error "Failed to set remote URL for $GIT_REMOTE_NAME" 144 fi 145 146 # Generate metadata file 147 mkdir -p "$(dirname "$MARKDOWN_FILE")" || error "Failed to create directory for $MARKDOWN_FILE" 148 149 TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S') || error "Failed to get timestamp" 150 DEFAULT_BRANCH=$(git symbolic-ref --short HEAD) || error "Failed to get default branch" 151 REPO_PATH="$REPO_ROOT" 152 LATEST_SHA=$(git rev-parse HEAD) || error "Failed to get latest commit SHA" 153 LAST_COMMIT_MSG=$(git log -1 --pretty=format:"%s" 2>/dev/null || echo "Unknown") 154 LAST_COMMIT_DATE=$(git log -1 --pretty=format:"%ad" 2>/dev/null || echo "Unknown") 155 LAST_COMMIT_AUTHOR=$(git log -1 --pretty=format:"%an <%ae>" 2>/dev/null || echo "Unknown") 156 TOTAL_COMMITS=$(git rev-list --count HEAD 2>/dev/null || echo "Unknown") 157 TRACKED_FILES=$(git ls-files 2>/dev/null | wc -l 2>/dev/null || echo "Unknown") 158 UNCOMMITTED=$(if ! git diff --quiet 2>/dev/null || ! git diff --cached --quiet 2>/dev/null; then echo "Yes"; else echo "No"; fi) 159 LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "None") 160 HOSTNAME=$(hostname 2>/dev/null || echo "Unknown") 161 CURRENT_USER=$(whoami 2>/dev/null || echo "Unknown") 162 TIMEZONE=$(date +%Z 2>/dev/null || echo "Unknown") 163 OS_NAME=$(uname -s 2>/dev/null || echo "Unknown") 164 KERNEL_VERSION=$(uname -r 2>/dev/null || echo "Unknown") 165 ARCHITECTURE=$(uname -m 2>/dev/null || echo "Unknown") 166 OS_PRETTY_NAME=$(grep PRETTY_NAME /etc/os-release 2>/dev/null | cut -d= -f2 | tr -d '"' || echo "Unknown") 167 DOCKER_CHECK=$(grep -qE '/docker|/lxc' /proc/1/cgroup 2>/dev/null && echo "Yes" || echo "No") 168 WSL_CHECK=$(grep -qi microsoft /proc/version 2>/dev/null && echo "Yes" || echo "No") 169 VM_CHECK=$(systemd-detect-virt 2>/dev/null || echo "Unknown") 170 UPTIME=$(uptime -p 2>/dev/null || echo "Unknown") 171 MAC_ADDR=$(ip link 2>/dev/null | awk '/ether/ {print $2}' | head -n 1 2>/dev/null || echo "Unknown") 172 LOCAL_IP=$(hostname -I 2>/dev/null | awk '{print $1}' 2>/dev/null || echo "Unknown") 173 CPU_MODEL=$(grep -m1 'model name' /proc/cpuinfo 2>/dev/null | cut -d: -f2 | sed 's/^ //' 2>/dev/null || echo "Unknown") 174 RAM_GB=$(awk '/MemTotal/ {printf "%.2f", $2/1024/1024}' /proc/meminfo 2>/dev/null || echo "Unknown") 175 WEB_LINK="https://$CODEBERG_DOMAIN/$USERNAME/$REPO_NAME" 176 177 cat > "$MARKDOWN_FILE" <<EOF 178 # š Codeberg Repository Link 179 180 - **Repo Name**: \`$REPO_NAME\` 181 - **Codeberg User**: \`$USERNAME\` 182 - **Remote URL**: [$WEB_LINK]($WEB_LINK) 183 - **Local Repo Path**: \`$REPO_PATH\` 184 - **Remote Label**: \`$GIT_REMOTE_NAME\` 185 - **Default Branch**: \`$DEFAULT_BRANCH\` 186 - **Repo Created**: \`$TIMESTAMP\` 187 188 --- 189 190 ## š¦ Commit Info 191 192 - **This Commit Timestamp**: \`$TIMESTAMP\` 193 - **Last Commit SHA**: \`$LATEST_SHA\` 194 - **Last Commit Message**: \`$LAST_COMMIT_MSG\` 195 - **Last Commit Author**: \`$LAST_COMMIT_AUTHOR\` 196 - **Last Commit Date**: \`$LAST_COMMIT_DATE\` 197 - **This Commit URL**: [$WEB_LINK/commit/$LATEST_SHA]($WEB_LINK/commit/$LATEST_SHA) 198 199 --- 200 201 ## š Repo Status 202 203 - **Total Commits**: \`$TOTAL_COMMITS\` 204 - **Tracked Files**: \`$TRACKED_FILES\` 205 - **Uncommitted Changes**: \`$UNCOMMITTED\` 206 - **Latest Tag**: \`$LATEST_TAG\` 207 208 --- 209 210 ## š§ Environment 211 212 - **Host Machine**: \`$HOSTNAME\` 213 - **Current User**: \`$CURRENT_USER\` 214 - **Time Zone**: \`$TIMEZONE\` 215 - **Script Version**: \`$SCRIPT_VERSION\` 216 217 --- 218 219 ## 𧬠Hardware & OS Fingerprint 220 221 - **OS Name**: \`$OS_NAME\` 222 - **OS Version**: \`$OS_PRETTY_NAME\` 223 - **Kernel Version**: \`$KERNEL_VERSION\` 224 - **Architecture**: \`$ARCHITECTURE\` 225 - **Running in Docker**: \`$DOCKER_CHECK\` 226 - **Running in WSL**: \`$WSL_CHECK\` 227 - **Virtual Machine**: \`$VM_CHECK\` 228 - **System Uptime**: \`$UPTIME\` 229 - **MAC Address**: \`$MAC_ADDR\` 230 - **Local IP**: \`$LOCAL_IP\` 231 - **CPU Model**: \`$CPU_MODEL\` 232 - **Total RAM (GB)**: \`$RAM_GB\` 233 234 --- 235 236 _Auto-generated by \`gitfield-codeberg\` push script._ 237 EOF 238 [[ $? -eq 0 ]] || error "Failed to write metadata to $MARKDOWN_FILE" 239 240 # Commit and push 241 set +e 242 info "Committing markdown file..." 243 git add "$MARKDOWN_FILE" || warn "Failed to add markdown file" 244 git commit -m "Codeberg metadata link commit at $TIMESTAMP ā $WEB_LINK/commit/$LATEST_SHA" || warn "No changes to commit" 245 246 info "Pushing to Codeberg..." 247 if ! git config --get branch."$DEFAULT_BRANCH".remote &>/dev/null; then 248 git push -u "$GIT_REMOTE_NAME" "$DEFAULT_BRANCH" || { 249 warn "Push to Codeberg failed. Check SSH setup or network." 250 warn "Run 'ssh -T -p $CODEBERG_SSH_PORT git@$CODEBERG_DOMAIN' to debug." 251 } 252 else 253 git push "$GIT_REMOTE_NAME" "$DEFAULT_BRANCH" || { 254 warn "Push to Codeberg failed. Check SSH setup or network." 255 warn "Run 'ssh -T -p $CODEBERG_SSH_PORT git@$CODEBERG_DOMAIN' to debug." 256 } 257 fi 258 set -e 259 260 info "ā Codeberg push complete." 261 echo -e "\nš View in browser: $WEB_LINK\n"