282 lines
8.8 KiB
Bash
Executable File
282 lines
8.8 KiB
Bash
Executable File
#!/bin/sh
|
|
# Gitea Initialization Script for Fellowship DevOps Escape Room
|
|
# Sets up Gitea with admin user, organization, and the LOTR SUT repository
|
|
# This script runs as a one-shot container after Gitea starts up
|
|
#
|
|
# Key: We use docker-compose exec instead of docker exec for reliable container access
|
|
|
|
set -e
|
|
|
|
GITEA_URL="${GITEA_URL:-http://gitea:3000}"
|
|
ADMIN_USER="${GITEA_ADMIN_USER:-fellowship}"
|
|
ADMIN_PASS="${GITEA_ADMIN_PASSWORD:-fellowship123}"
|
|
ADMIN_EMAIL="${GITEA_ADMIN_EMAIL:-gandalf@fellowship.local}"
|
|
ORG_NAME="${GITEA_ORG_NAME:-fellowship-org}"
|
|
REPO_NAME="${GITEA_REPO_NAME:-lotr-sut}"
|
|
REPO_DESC="The Fellowship's Quest List — LOTR-themed SUT for DevOps tutorials"
|
|
SUT_SOURCE_DIR="${SUT_SOURCE_DIR:-/sut-source}"
|
|
|
|
log() {
|
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [gitea-init] $*"
|
|
}
|
|
|
|
warn() {
|
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [gitea-init] ⚠️ WARNING: $*" >&2
|
|
}
|
|
|
|
error() {
|
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [gitea-init] ❌ ERROR: $*" >&2
|
|
return 1
|
|
}
|
|
|
|
log "=========================================="
|
|
log "Gitea Initialization — Fellowship DevOps"
|
|
log "=========================================="
|
|
log "Settings:"
|
|
log " Gitea Container: ${GITEA_CONTAINER}"
|
|
log " Admin User: ${ADMIN_USER}"
|
|
log " Organization: ${ORG_NAME}"
|
|
log " Repository: ${ORG_NAME}/${REPO_NAME}"
|
|
log "=========================================="
|
|
|
|
# Install required tools
|
|
setup_tools() {
|
|
log "Setting up tools..."
|
|
if ! command -v curl > /dev/null 2>&1; then
|
|
apk add --no-cache curl
|
|
fi
|
|
if ! command -v docker > /dev/null 2>&1; then
|
|
apk add --no-cache docker-cli
|
|
fi
|
|
log "✓ Tools ready"
|
|
}
|
|
|
|
# Wait for Gitea to be ready
|
|
wait_for_gitea() {
|
|
log "Waiting for Gitea API to be ready at ${GITEA_URL}..."
|
|
local max_attempts=60
|
|
local attempt=1
|
|
while [ $attempt -le $max_attempts ]; do
|
|
if curl -sf "${GITEA_URL}/api/v1/version" > /dev/null 2>&1; then
|
|
log "✓ Gitea API is ready"
|
|
return 0
|
|
fi
|
|
sleep 2
|
|
attempt=$((attempt + 1))
|
|
[ $((attempt % 10)) -eq 0 ] && log " Still waiting (${attempt}/${max_attempts})..."
|
|
done
|
|
error "Gitea did not become ready after $((max_attempts * 2)) seconds"
|
|
return 1
|
|
}
|
|
|
|
# Create the admin user using Gitea CLI via docker
|
|
create_admin() {
|
|
log "Creating admin user '${ADMIN_USER}'..."
|
|
|
|
# Check if user already exists via API
|
|
local existing_user
|
|
existing_user=$(curl -s -u "${ADMIN_USER}:${ADMIN_PASS}" "${GITEA_URL}/api/v1/user" 2>/dev/null || echo "")
|
|
|
|
if echo "$existing_user" | grep -q '"username"'; then
|
|
log "✓ Admin user '${ADMIN_USER}' already exists"
|
|
return 0
|
|
fi
|
|
|
|
# Find gitea container by name matching (handles project prefix like fellowship-gitea-1)
|
|
local gitea_container
|
|
gitea_container=$(docker ps --format '{{.Names}}' | grep -E 'gitea$|gitea-1$|gitea-[\w-]*$' | head -1)
|
|
|
|
if [ -z "$gitea_container" ]; then
|
|
error "Could not find gitea container"
|
|
return 1
|
|
fi
|
|
|
|
log " Found gitea container: $gitea_container"
|
|
|
|
# Use gitea CLI to create admin user via docker exec
|
|
# Must run as 'git' user (not root) - Gitea refuses to run as root
|
|
if docker exec -u git "$gitea_container" \
|
|
gitea admin user create \
|
|
--username "${ADMIN_USER}" \
|
|
--password "${ADMIN_PASS}" \
|
|
--email "${ADMIN_EMAIL}" \
|
|
--admin \
|
|
--must-change-password=false > /tmp/gitea_user_create.log 2>&1; then
|
|
log "✓ Admin user '${ADMIN_USER}' created successfully"
|
|
return 0
|
|
fi
|
|
|
|
# Check if user already exists (might exist from previous run)
|
|
if grep -q "already exists" /tmp/gitea_user_create.log 2>/dev/null; then
|
|
log "✓ Admin user '${ADMIN_USER}' already exists"
|
|
return 0
|
|
fi
|
|
|
|
# If both methods fail, show error and return failure
|
|
log "Creation output:"
|
|
cat /tmp/gitea_user_create.log || true
|
|
error "Failed to create admin user"
|
|
return 1
|
|
}
|
|
|
|
|
|
# Create organization via API (requires auth)
|
|
create_org() {
|
|
log "Creating organization '${ORG_NAME}'..."
|
|
|
|
local response
|
|
response=$(curl -s -X POST "${GITEA_URL}/api/v1/orgs" \
|
|
-u "${ADMIN_USER}:${ADMIN_PASS}" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{
|
|
\"username\": \"${ORG_NAME}\",
|
|
\"full_name\": \"The Fellowship of the Ring\",
|
|
\"description\": \"One org to rule them all\",
|
|
\"visibility\": \"public\"
|
|
}" 2>&1)
|
|
|
|
if echo "$response" | grep -q '"id"'; then
|
|
log "✓ Organization '${ORG_NAME}' created"
|
|
return 0
|
|
elif echo "$response" | grep -q "already exists\|account already exists"; then
|
|
log "✓ Organization '${ORG_NAME}' already exists"
|
|
return 0
|
|
else
|
|
# Log the actual API response for debugging
|
|
echo "$response" 1>&2
|
|
error "Failed to create organization"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Create repository via API (requires auth)
|
|
create_repo() {
|
|
log "Creating repository '${ORG_NAME}/${REPO_NAME}'..."
|
|
|
|
local status
|
|
status=$(curl -s -o /dev/null -w "%{http_code}" \
|
|
-u "${ADMIN_USER}:${ADMIN_PASS}" \
|
|
"${GITEA_URL}/api/v1/repos/${ORG_NAME}/${REPO_NAME}" 2>/dev/null)
|
|
|
|
if [ "$status" = "200" ]; then
|
|
log "✓ Repository '${ORG_NAME}/${REPO_NAME}' already exists"
|
|
return 0
|
|
fi
|
|
|
|
local response
|
|
response=$(curl -s -X POST "${GITEA_URL}/api/v1/orgs/${ORG_NAME}/repos" \
|
|
-u "${ADMIN_USER}:${ADMIN_PASS}" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{
|
|
\"name\": \"${REPO_NAME}\",
|
|
\"description\": \"${REPO_DESC}\",
|
|
\"private\": false,
|
|
\"auto_init\": false,
|
|
\"default_branch\": \"main\"
|
|
}" 2>&1)
|
|
|
|
if echo "$response" | grep -q '"id"'; then
|
|
log "✓ Repository '${ORG_NAME}/${REPO_NAME}' created"
|
|
return 0
|
|
elif echo "$response" | grep -q "already exists\|The repository already exists"; then
|
|
log "✓ Repository '${ORG_NAME}/${REPO_NAME}' already exists"
|
|
return 0
|
|
else
|
|
# Log the actual API response for debugging
|
|
echo "$response" 1>&2
|
|
error "Failed to create repository"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Push SUT source code to Gitea (optional, skipped if repo has commits)
|
|
push_sut_code() {
|
|
log "Checking if SUT code needs to be pushed..."
|
|
|
|
# Check if repo already has commits
|
|
local commits
|
|
commits=$(curl -s \
|
|
-u "${ADMIN_USER}:${ADMIN_PASS}" \
|
|
"${GITEA_URL}/api/v1/repos/${ORG_NAME}/${REPO_NAME}/commits?limit=1" \
|
|
2>/dev/null | grep -c '"sha"' || echo "0")
|
|
|
|
# Trim whitespace and handle invalid values
|
|
commits=$(echo "$commits" | xargs)
|
|
commits=${commits:-0} # Default to 0 if empty
|
|
|
|
# Check if commits is a valid number and greater than 0
|
|
if [ "$commits" -gt 0 ] 2>/dev/null; then
|
|
log "✓ Repository already has commits — skipping push"
|
|
return 0
|
|
fi
|
|
|
|
# Find the SUT source
|
|
if [ ! -d "${SUT_SOURCE_DIR}" ]; then
|
|
warn "SUT source directory not found at ${SUT_SOURCE_DIR}"
|
|
warn "Skipping code push — repository will be created but empty"
|
|
return 0
|
|
fi
|
|
|
|
log " Source directory: ${SUT_SOURCE_DIR}"
|
|
log " (Code push omitted for now — repository ready for manual commit)"
|
|
return 0
|
|
}
|
|
|
|
|
|
|
|
# Main initialization sequence
|
|
main() {
|
|
setup_tools || exit 1
|
|
|
|
if ! wait_for_gitea; then
|
|
error "Aborting — Gitea is not available"
|
|
exit 1
|
|
fi
|
|
|
|
# Create admin user first (required for subsequent operations)
|
|
if ! create_admin; then
|
|
error "Failed to create admin user"
|
|
exit 1
|
|
fi
|
|
|
|
# Wait for admin credentials to be valid before using API
|
|
log "Waiting for admin credentials to be recognized..."
|
|
local max_attempts=15
|
|
local attempt=1
|
|
while [ $attempt -le $max_attempts ]; do
|
|
if curl -sf -u "${ADMIN_USER}:${ADMIN_PASS}" \
|
|
"${GITEA_URL}/api/v1/user" > /dev/null 2>&1; then
|
|
log "✓ Admin user is now authenticated"
|
|
break
|
|
fi
|
|
sleep 1
|
|
attempt=$((attempt + 1))
|
|
[ $((attempt % 5)) -eq 0 ] && log " Still waiting (${attempt}/${max_attempts})..."
|
|
done
|
|
|
|
# Create organization
|
|
if ! create_org; then
|
|
warn "Failed to create organization (may already exist)"
|
|
fi
|
|
|
|
# Create repository
|
|
if ! create_repo; then
|
|
warn "Failed to create repository (may already exist)"
|
|
fi
|
|
|
|
# Push source code (optional)
|
|
push_sut_code || true
|
|
|
|
log "=========================================="
|
|
log "✅ Gitea initialization complete!"
|
|
log "=========================================="
|
|
log " URL: ${GITEA_URL}"
|
|
log " Admin: ${ADMIN_USER}"
|
|
log " Repository: ${GITEA_URL}/${ORG_NAME}/${REPO_NAME}"
|
|
log "=========================================="
|
|
}
|
|
|
|
# Run main initialization
|
|
main "$@"
|
|
|