Files
dance-lessons-coach/.vibe/skills/gitea-client/scripts/gitea-client.sh
Gabriel Radureau c17fb4f9b4
Some checks failed
CI/CD Pipeline / Build Docker Cache (push) Successful in 10s
CI/CD Pipeline / CI Pipeline (push) Failing after 4m14s
CI/CD Pipeline / Trigger Docker Push (push) Has been skipped
🐛 fix: emit all config-loading logs in correct JSON format from the start (#16)
## Summary

Closes #15

When `logging.json: true` (or `DLC_LOGGING_JSON=true`), the logger was unconditionally initialised to console/text format at the top of `LoadConfig()`, so early log lines — most visibly **"Config file loaded"** — were always written as human-readable text regardless of configuration.

## Root cause

Classic chicken-and-egg: the format flag lives inside the config that is being loaded. The format-switch block only ran *after* `v.Unmarshal()`, too late for the config-file log.

## Changes

### `pkg/config/config.go`
- Add `peekJSONLogging()`: resolves the JSON flag **before** any log is emitted by (1) checking `DLC_LOGGING_JSON` directly via `os.Getenv`, then (2) doing a minimal throwaway Viper pre-read of the config file for the `logging.json` key. This mirrors Viper's own priority order without parsing the full config twice.
- Apply the resolved format immediately and emit **"Logging configured"** as the very first log line.
- Remove the now-redundant format-switch block that ran after `Unmarshal()`.

### `scripts/start-server.sh`, `test-graceful-shutdown.sh`, `test-opentelemetry.sh`
- Replace hardcoded `PROJECT_DIR` path with a dynamic `SCRIPTS_DIR=$(dirname $(realpath ${BASH_SOURCE[0]}))` derivation so scripts work from any worktree or clone location.

## Test plan
- [x] `go test ./pkg/...` — all pass
- [x] `scripts/test-graceful-shutdown.sh` — all JSON valid, all startup logs present
- [x] Manual smoke test: first line is `{"level":"info",...,"message":"Logging configured"}`, every line is valid JSON

Reviewed-on: #16
Co-authored-by: Gabriel Radureau <arcodange@gmail.com>
Co-committed-by: Gabriel Radureau <arcodange@gmail.com>
2026-04-12 23:28:35 +02:00

578 lines
17 KiB
Bash
Executable File

#!/bin/bash
# Gitea Client - Main script for interacting with Gitea API
# Usage: gitea-client.sh <command> [args...]
set -e
# Configuration
GITEA_API_BASE="https://gitea.arcodange.lab/api/v1"
# Get authentication token
get_auth_token() {
if [[ -n "${GITEA_API_TOKEN_FILE:-}" ]]; then
if [[ -f "$GITEA_API_TOKEN_FILE" ]]; then
cat "$GITEA_API_TOKEN_FILE"
return
else
echo "Error: Token file $GITEA_API_TOKEN_FILE not found" >&2
exit 1
fi
fi
if [[ -n "${GITEA_API_TOKEN:-}" ]]; then
echo "$GITEA_API_TOKEN"
return
fi
echo "Error: No Gitea API token provided" >&2
echo "Set either GITEA_API_TOKEN or GITEA_API_TOKEN_FILE environment variable" >&2
exit 1
}
# Make API request
api_request() {
local method="$1"
local endpoint="$2"
local data="${3:-}"
local token=$(get_auth_token)
local url="${GITEA_API_BASE}${endpoint}"
local headers=(
"Authorization: token ${token}"
"Accept: application/json"
"Content-Type: application/json"
)
if [[ "$method" == "GET" ]]; then
curl -s -X GET "$url" -H "${headers[0]}" -H "${headers[1]}"
else
curl -s -X "$method" "$url" -H "${headers[0]}" -H "${headers[1]}" -H "${headers[2]}" -d "$data"
fi
}
# List workflows
cmd_list_workflows() {
local owner="$1"
local repo="$2"
if [[ -z "$owner" || -z "$repo" ]]; then
echo "Usage: $0 list-workflows <owner> <repo>" >&2
exit 1
fi
local endpoint="/repos/${owner}/${repo}/actions/workflows"
api_request "GET" "$endpoint"
}
# List jobs
cmd_list_jobs() {
local owner="$1"
local repo="$2"
local workflow_id="$3"
local limit="${4:-10}"
if [[ -z "$owner" || -z "$repo" || -z "$workflow_id" ]]; then
echo "Usage: $0 list-jobs <owner> <repo> <workflow_id> [limit]" >&2
exit 1
fi
local endpoint="/repos/${owner}/${repo}/actions/workflows/${workflow_id}/runs?limit=${limit}"
api_request "GET" "$endpoint"
}
# Get job status
cmd_job_status() {
local owner="$1"
local repo="$2"
local job_id="$3"
if [[ -z "$owner" || -z "$repo" || -z "$job_id" ]]; then
echo "Usage: $0 job-status <owner> <repo> <job_id>" >&2
exit 1
fi
local endpoint="/repos/${owner}/${repo}/actions/runs/${job_id}"
api_request "GET" "$endpoint"
}
# Get job logs
cmd_job_logs() {
local owner="$1"
local repo="$2"
local job_id="$3"
local output_file="${4:-}"
if [[ -z "$owner" || -z "$repo" || -z "$job_id" ]]; then
echo "Usage: $0 job-logs <owner> <repo> <job_id> [output_file]" >&2
exit 1
fi
local endpoint="/repos/${owner}/${repo}/actions/jobs/${job_id}/logs"
local logs=$(api_request "GET" "$endpoint")
if [[ -n "$output_file" ]]; then
echo "$logs" > "$output_file"
echo "Logs saved to: $output_file"
else
echo "$logs"
fi
}
# Get action job logs
cmd_action_logs() {
local owner="$1"
local repo="$2"
local action_job_id="$3"
local output_file="${4:-}"
if [[ -z "$owner" || -z "$repo" || -z "$action_job_id" ]]; then
echo "Usage: $0 action-logs <owner> <repo> <action_job_id> [output_file]" >&2
exit 1
fi
local endpoint="/repos/${owner}/${repo}/actions/jobs/${action_job_id}/logs"
local logs=$(api_request "GET" "$endpoint")
if [[ -n "$output_file" ]]; then
echo "$logs" > "$output_file"
echo "Logs saved to: $output_file"
else
echo "$logs"
fi
}
# List workflow jobs
cmd_list_workflow_jobs() {
local owner="$1"
local repo="$2"
local workflow_run_id="$3"
if [[ -z "$owner" || -z "$repo" || -z "$workflow_run_id" ]]; then
echo "Usage: $0 list-workflow-jobs <owner> <repo> <workflow_run_id>" >&2
exit 1
fi
local endpoint="/repos/${owner}/${repo}/actions/runs/${workflow_run_id}/jobs"
api_request "GET" "$endpoint"
}
# Wait for job completion
cmd_wait_job() {
local owner="$1"
local repo="$2"
local job_id="$3"
local timeout="${4:-300}"
if [[ -z "$owner" || -z "$repo" || -z "$job_id" ]]; then
echo "Usage: $0 wait-job <owner> <repo> <job_id> [timeout]" >&2
exit 1
fi
local start_time=$(date +%s)
local end_time=$((start_time + timeout))
echo "Waiting for job ${job_id} to complete (timeout: ${timeout}s)..."
while [[ $(date +%s) -lt $end_time ]]; do
local status=$(cmd_job_status "$owner" "$repo" "$job_id" | jq -r '.status')
case "$status" in
"completed")
echo "Job completed successfully"
return 0
;;
"failed")
echo "Job failed"
return 1
;;
"cancelled")
echo "Job was cancelled"
return 2
;;
*)
echo "Current status: ${status}"
sleep 5
;;
esac
done
echo "Timeout reached"
return 3
}
# Comment on PR
# Create a pull request
cmd_create_pr() {
local owner="$1"
local repo="$2"
local title="$3"
local body="$4"
local head="$5"
local base="${6:-main}"
if [[ -z "$owner" || -z "$repo" || -z "$title" || -z "$head" ]]; then
echo "Usage: $0 create-pr <owner> <repo> <title> <body> <head_branch> [base_branch]" >&2
exit 1
fi
local endpoint="/repos/${owner}/${repo}/pulls"
local data
data=$(jq -n \
--arg title "$title" \
--arg body "$body" \
--arg head "$head" \
--arg base "$base" \
'{title: $title, body: $body, head: $head, base: $base}')
api_request "POST" "$endpoint" "$data"
}
cmd_comment_pr() {
local owner="$1"
local repo="$2"
local pr_number="$3"
local comment="$4"
if [[ -z "$owner" || -z "$repo" || -z "$pr_number" || -z "$comment" ]]; then
echo "Usage: $0 comment-pr <owner> <repo> <pr_number> <comment>" >&2
exit 1
fi
local endpoint="/repos/${owner}/${repo}/issues/${pr_number}/comments"
local data
data=$(jq -n --arg body "$comment" '{body: $body}')
api_request "POST" "$endpoint" "$data"
}
# Get PR status
cmd_pr_status() {
local owner="$1"
local repo="$2"
local pr_number="$3"
if [[ -z "$owner" || -z "$repo" || -z "$pr_number" ]]; then
echo "Usage: $0 pr-status <owner> <repo> <pr_number>" >&2
exit 1
fi
local endpoint="/repos/${owner}/${repo}/pulls/${pr_number}"
api_request "GET" "$endpoint"
}
# Main command routing
main() {
local command="${1:-}"
shift || true
case "$command" in
list-workflows) cmd_list_workflows "$@" ;;
list-jobs) cmd_list_jobs "$@" ;;
job-status) cmd_job_status "$@" ;;
job-logs) cmd_job_logs "$@" ;;
action-logs) cmd_action_logs "$@" ;;
list-workflow-jobs) cmd_list_workflow_jobs "$@" ;;
wait-job) cmd_wait_job "$@" ;;
monitor-workflow) cmd_monitor_workflow "$@" ;;
diagnose-job) cmd_diagnose_job "$@" ;;
recent-workflows) cmd_recent_workflows "$@" ;;
create-pr) cmd_create_pr "$@" ;;
comment-pr) cmd_comment_pr "$@" ;;
pr-status) cmd_pr_status "$@" ;;
list-issues) cmd_list_issues "$@" ;;
create-issue) cmd_create_issue "$@" ;;
show-issue) cmd_show_issue "$@" ;;
comment-issue) cmd_comment_issue "$@" ;;
list-wiki) cmd_list_wiki "$@" ;;
create-wiki) cmd_create_wiki "$@" ;;
get-wiki) cmd_get_wiki "$@" ;;
trigger-workflow) cmd_trigger_workflow "$@" ;;
*)
echo "Usage: $0 <command> [args...]" >&2
echo "" >&2
echo "Commands:" >&2
echo " list-workflows <owner> <repo>" >&2
echo " list-jobs <owner> <repo> <workflow_id> [limit]" >&2
echo " job-status <owner> <repo> <job_id>" >&2
echo " job-logs <owner> <repo> <job_id> [output_file]" >&2
echo " action-logs <owner> <repo> <action_job_id> [output_file]" >&2
echo " list-workflow-jobs <owner> <repo> <workflow_run_id>" >&2
echo " wait-job <owner> <repo> <job_id> [timeout]" >&2
echo " monitor-workflow <owner> <repo> <workflow_run_id> [interval_seconds]" >&2
echo " diagnose-job <owner> <repo> <job_id>" >&2
echo " recent-workflows <owner> <repo> [limit] [status_filter]" >&2
echo " create-pr <owner> <repo> <title> <body> <head_branch> [base_branch]" >&2
echo " comment-pr <owner> <repo> <pr_number> <comment>" >&2
echo " pr-status <owner> <repo> <pr_number>" >&2
echo " list-issues <owner> <repo> [state]" >&2
echo " create-issue <owner> <repo> <title> <description>" >&2
echo " show-issue <owner> <repo> <issue_number>" >&2
echo " comment-issue <owner> <repo> <issue_number> <comment>" >&2
echo " list-wiki <owner> <repo>" >&2
echo " create-wiki <owner> <repo> <title> <content> [message]" >&2
echo " get-wiki <owner> <repo> <page_name>" >&2
echo " trigger-workflow <owner> <repo> <workflow_file> <branch>" >&2
exit 1
;;
esac
}
# List issues
cmd_list_issues() {
local owner="$1"
local repo="$2"
local state="${3:-open}"
if [[ -z "$owner" || -z "$repo" ]]; then
echo "Usage: $0 list-issues <owner> <repo> [state]" >&2
exit 1
fi
local endpoint="/repos/$owner/$repo/issues?state=$state"
api_request "GET" "$endpoint"
}
# Create a new issue
cmd_create_issue() {
local owner="$1"
local repo="$2"
local title="$3"
local description="$4"
if [[ -z "$owner" || -z "$repo" || -z "$title" || -z "$description" ]]; then
echo "Usage: $0 create-issue <owner> <repo> <title> <description>" >&2
exit 1
fi
local endpoint="/repos/$owner/$repo/issues"
local data=$(jq -n --arg title "$title" --arg body "$description" '{
title: $title,
body: $body
}')
api_request "POST" "$endpoint" "$data"
}
# Show issue details
cmd_show_issue() {
local owner="$1"
local repo="$2"
local issue_number="$3"
if [[ -z "$owner" || -z "$repo" || -z "$issue_number" ]]; then
echo "Usage: $0 show-issue <owner> <repo> <issue_number>" >&2
exit 1
fi
local endpoint="/repos/$owner/$repo/issues/$issue_number"
api_request "GET" "$endpoint"
}
# Comment on an issue
cmd_comment_issue() {
local owner="$1"
local repo="$2"
local issue_number="$3"
local comment="$4"
if [[ -z "$owner" || -z "$repo" || -z "$issue_number" || -z "$comment" ]]; then
echo "Usage: $0 comment-issue <owner> <repo> <issue_number> <comment>" >&2
exit 1
fi
local endpoint="/repos/$owner/$repo/issues/$issue_number/comments"
local data=$(jq -n --arg body "$comment" '{
body: $body
}')
api_request "POST" "$endpoint" "$data"
}
# List wiki pages
cmd_list_wiki() {
local owner="$1"
local repo="$2"
if [[ -z "$owner" || -z "$repo" ]]; then
echo "Usage: $0 list-wiki <owner> <repo>" >&2
exit 1
fi
local endpoint="/repos/$owner/$repo/wiki/pages"
api_request "GET" "$endpoint"
}
# Create wiki page
cmd_create_wiki() {
local owner="$1"
local repo="$2"
local title="$3"
local content="$4"
local message="${5:-Initial creation}"
if [[ -z "$owner" || -z "$repo" || -z "$title" || -z "$content" ]]; then
echo "Usage: $0 create-wiki <owner> <repo> <title> <content> [message]" >&2
exit 1
fi
local content_b64=$(echo "$content" | base64)
local endpoint="/repos/$owner/$repo/wiki/new"
local data=$(jq -n --arg title "$title" --arg content "$content_b64" --arg msg "$message" '{
title: $title,
content_base64: $content,
message: $msg
}')
api_request "POST" "$endpoint" "$data"
}
# Get wiki page
cmd_get_wiki() {
local owner="$1"
local repo="$2"
local page_name="$3"
if [[ -z "$owner" || -z "$repo" || -z "$page_name" ]]; then
echo "Usage: $0 get-wiki <owner> <repo> <page_name>" >&2
exit 1
fi
local endpoint="/repos/$owner/$repo/wiki/page/$page_name"
local response=$(api_request "GET" "$endpoint")
# Extract and decode the content_base64 field
local content_b64=$(echo "$response" | jq -r '.content_base64')
if [[ "$content_b64" != "null" && -n "$content_b64" ]]; then
echo "$content_b64" | base64 --decode
else
echo "$response"
fi
}
# Trigger workflow
cmd_trigger_workflow() {
local owner="$1"
local repo="$2"
local workflow_file="$3"
local branch="$4"
if [[ -z "$owner" || -z "$repo" || -z "$workflow_file" || -z "$branch" ]]; then
echo "Usage: $0 trigger-workflow <owner> <repo> <workflow_file> <branch>" >&2
exit 1
fi
local endpoint="/repos/${owner}/${repo}/actions/workflows/${workflow_file}/dispatches"
local data="{\"ref\": \"${branch}\"}"
echo "Triggering workflow: ${workflow_file} on branch: ${branch}"
api_request "POST" "$endpoint" "$data"
echo "Workflow triggered successfully!"
}
# Monitor workflow run until completion
cmd_monitor_workflow() {
local owner="$1"
local repo="$2"
local workflow_run_id="$3"
local interval="${4:-30}"
if [[ -z "$owner" || -z "$repo" || -z "$workflow_run_id" ]]; then
echo "Usage: $0 monitor-workflow <owner> <repo> <workflow_run_id> [interval_seconds]" >&2
exit 1
fi
echo "Monitoring workflow run $workflow_run_id (interval: ${interval}s)..."
echo "Press Ctrl+C to stop monitoring"
while true; do
local endpoint="/repos/${owner}/${repo}/actions/runs/${workflow_run_id}"
local status=$(api_request "GET" "$endpoint" | jq -r '.status')
local conclusion=$(api_request "GET" "$endpoint" | jq -r '.conclusion')
local updated_at=$(api_request "GET" "$endpoint" | jq -r '.updated_at')
echo "[$(date +'%Y-%m-%d %H:%M:%S')] Status: $status, Conclusion: ${conclusion:-not completed}, Updated: $updated_at"
# List jobs in this workflow
local jobs_endpoint="/repos/${owner}/${repo}/actions/runs/${workflow_run_id}/jobs"
local jobs=$(api_request "GET" "$jobs_endpoint")
echo "Jobs:"
echo "$jobs" | jq -r '.jobs[] | " \(.id): \(.name) - \(.status) \(if .conclusion then "(\(.conclusion))" else "" end)"'
# Check if workflow is completed
if [[ "$status" != "queued" && "$status" != "in_progress" && "$status" != "waiting" ]]; then
echo "Workflow run $workflow_run_id has completed with status: $status and conclusion: ${conclusion:-none}"
break
fi
sleep "$interval"
done
}
# Diagnose failed job
cmd_diagnose_job() {
local owner="$1"
local repo="$2"
local job_id="$3"
if [[ -z "$owner" || -z "$repo" || -z "$job_id" ]]; then
echo "Usage: $0 diagnose-job <owner> <repo> <job_id>" >&2
exit 1
fi
echo "Diagnosing job $job_id..."
# Get job details
local job_endpoint="/repos/${owner}/${repo}/actions/jobs/${job_id}"
local job_details=$(api_request "GET" "$job_endpoint")
echo "Job Details:"
echo "$job_details" | jq '. | {id, name, status, conclusion, started_at, completed_at, runner_name}'
# Get job logs
local logs_endpoint="/repos/${owner}/${repo}/actions/jobs/${job_id}/logs"
echo -e "\nLast 50 lines of logs:"
api_request "GET" "$logs_endpoint" | tail -50
# Look for errors
echo -e "\nError analysis:"
api_request "GET" "$logs_endpoint" | grep -i "error\|fail\|panic\|exception" | tail -10
# Get workflow run details
local run_id=$(echo "$job_details" | jq -r '.run_id')
local run_endpoint="/repos/${owner}/${repo}/actions/runs/${run_id}"
local run_details=$(api_request "GET" "$run_endpoint")
echo -e "\nWorkflow Run Details:"
echo "$run_details" | jq '. | {id, display_title, status, conclusion, head_branch, head_sha}'
}
# Get recent workflow runs summary
cmd_recent_workflows() {
local owner="$1"
local repo="$2"
local limit="${3:-10}"
local status_filter="${4:-}"
if [[ -z "$owner" || -z "$repo" ]]; then
echo "Usage: $0 recent-workflows <owner> <repo> [limit] [status_filter]" >&2
echo "Status filter options: all, completed, in_progress, queued, waiting" >&2
exit 1
fi
local endpoint="/repos/${owner}/${repo}/actions/runs?limit=${limit}"
if [[ -n "$status_filter" ]]; then
endpoint="$endpoint&status=$status_filter"
fi
local workflows=$(api_request "GET" "$endpoint")
echo "Recent Workflow Runs (showing $limit most recent):"
echo "$workflows" | jq -r '.workflow_runs[] | "\(.id): \(.display_title) - \(.status) \(if .conclusion then "(\(.conclusion))" else "" end) - \(.updated_at)"'
# Show summary statistics
echo -e "\nSummary:"
echo "$workflows" | jq -r '.workflow_runs | group_by(.conclusion) | .[] | " \(.[0].conclusion // "in_progress"): \(length)"'
}
main "$@"