🐛 fix: emit all config-loading logs in correct JSON format from the start #16
@@ -203,6 +203,31 @@ cmd_wait_job() {
|
||||
}
|
||||
|
||||
# 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"
|
||||
@@ -215,7 +240,8 @@ cmd_comment_pr() {
|
||||
fi
|
||||
|
||||
local endpoint="/repos/${owner}/${repo}/issues/${pr_number}/comments"
|
||||
local data="{\"body\": \"${comment}\"}"
|
||||
local data
|
||||
data=$(jq -n --arg body "$comment" '{body: $body}')
|
||||
api_request "POST" "$endpoint" "$data"
|
||||
}
|
||||
|
||||
@@ -250,6 +276,7 @@ main() {
|
||||
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 "$@" ;;
|
||||
@@ -274,6 +301,7 @@ main() {
|
||||
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
|
||||
|
||||
429
README.md
429
README.md
@@ -1,421 +1,98 @@
|
||||
# dance-lessons-coach
|
||||
|
||||
[](https://gitea.arcodange.fr/arcodange/dance-lessons-coach/actions/workflows/ci-cd.yaml/badge.svg)
|
||||
[](https://goreportcard.com/report/github.com/arcodange/dance-lessons-coach)
|
||||
[](https://gitea.arcodange.fr/arcodange/dance-lessons-coach/actions/workflows/ci-cd.yaml)
|
||||
[](https://gitea.arcodange.fr/arcodange/dance-lessons-coach/releases)
|
||||
[](LICENSE)
|
||||
[](https://gitea.arcodange.lab/arcodange/dance-lessons-coach)
|
||||
[](https://gitea.arcodange.lab/arcodange/dance-lessons-coach)
|
||||
|
||||
A Go project demonstrating idiomatic package structure, CLI implementation, and JSON API with Chi router.
|
||||
=======
|
||||
Go web service demonstrating idiomatic package structure, versioned JSON API, and production-ready features.
|
||||
|
||||
## Features
|
||||
|
||||
- Greet function with default behavior
|
||||
- Command-line interface
|
||||
- JSON API with versioned endpoints
|
||||
- Chi router integration
|
||||
- Zerolog for high-performance logging
|
||||
- Viper for configuration management
|
||||
- Graceful shutdown with context
|
||||
- Readiness endpoint for Kubernetes/service mesh integration
|
||||
- OpenTelemetry integration with Jaeger support
|
||||
- OpenAPI/Swagger documentation
|
||||
- Unit tests
|
||||
- Go 1.26.1 compatible
|
||||
- Versioned JSON API (`/api/v1`, `/api/v2`)
|
||||
- Chi router with graceful shutdown
|
||||
- Zerolog structured logging (console and JSON modes)
|
||||
- Viper configuration (file + env vars)
|
||||
- Readiness endpoint for Kubernetes / service mesh
|
||||
- OpenTelemetry / Jaeger distributed tracing
|
||||
- OpenAPI / Swagger UI (embedded in binary)
|
||||
- PostgreSQL user service with JWT auth
|
||||
- BDD + unit tests
|
||||
|
||||
## Installation
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone https://gitea.arcodange.lab/arcodange/dance-lessons-coach.git
|
||||
cd dance-lessons-coach
|
||||
|
||||
# Build all binaries
|
||||
./scripts/build.sh
|
||||
|
||||
# Use the new Cobra CLI
|
||||
./bin/dance-lessons-coach --help
|
||||
|
||||
# Or use the legacy greet CLI
|
||||
go run ./cmd/greet
|
||||
./scripts/build.sh # produces ./bin/server and ./bin/greet
|
||||
./scripts/start-server.sh start
|
||||
```
|
||||
|
||||
## CI/CD Pipeline
|
||||
|
||||
dance-lessons-coach features an optimized CI/CD pipeline using GitHub Actions with container/services architecture:
|
||||
|
||||
### Key Features
|
||||
- ✅ **Container-based execution**: All steps run in pre-built Docker cache images
|
||||
- ✅ **Service-based PostgreSQL**: Automatic database service provisioning
|
||||
- ✅ **Smart caching**: Dependency-aware cache invalidation
|
||||
- ✅ **Multi-platform**: Compatible with Gitea, GitHub, and GitLab
|
||||
- ✅ **Fast execution**: No Docker Compose overhead
|
||||
- ✅ **Reliable testing**: Full database connectivity with proper environment setup
|
||||
|
||||
### Architecture
|
||||
|
||||
The pipeline uses GitHub Actions' native `container` and `services` directives instead of Docker Compose:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
ci-pipeline:
|
||||
container:
|
||||
image: gitea.arcodange.lab/arcodange/dance-lessons-coach-build-cache:${{ needs.build-cache.outputs.deps_hash }}
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:15
|
||||
env:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: dance_lessons_coach_bdd_test
|
||||
```
|
||||
|
||||
### Benefits
|
||||
|
||||
1. **Performance**: Direct container execution without compose overhead
|
||||
2. **Reliability**: Service containers managed by GitHub Actions
|
||||
3. **Simplicity**: Cleaner workflow definition
|
||||
4. **Portability**: Works across CI platforms
|
||||
5. **Caching**: Intelligent dependency-based cache rebuilding
|
||||
|
||||
### Workflow Steps
|
||||
|
||||
1. **Build Cache**: Creates Docker image with Go tools and dependencies
|
||||
2. **CI Pipeline**: Runs tests, builds binaries, and generates documentation
|
||||
3. **Database Tests**: Connects to PostgreSQL service container
|
||||
4. **Coverage Reporting**: Updates coverage badges automatically
|
||||
5. **Artifact Publishing**: Builds and pushes Docker images (main branch only)
|
||||
|
||||
### Environment Configuration
|
||||
|
||||
The pipeline automatically sets up database environment variables:
|
||||
|
||||
```bash
|
||||
echo "DLC_DATABASE_HOST=postgres" >> $GITHUB_ENV
|
||||
echo "DLC_DATABASE_PORT=5432" >> $GITHUB_ENV
|
||||
echo "DLC_DATABASE_USER=postgres" >> $GITHUB_ENV
|
||||
echo "DLC_DATABASE_PASSWORD=postgres" >> $GITHUB_ENV
|
||||
echo "DLC_DATABASE_NAME=dance_lessons_coach_bdd_test" >> $GITHUB_ENV
|
||||
echo "DLC_DATABASE_SSL_MODE=disable" >> $GITHUB_ENV
|
||||
curl http://localhost:8080/api/health
|
||||
curl http://localhost:8080/api/v1/greet/Alice
|
||||
```
|
||||
|
||||
### Status
|
||||
Stop: `./scripts/start-server.sh stop`
|
||||
|
||||
[](https://gitea.arcodange.fr/arcodange/dance-lessons-coach)
|
||||
## Greet CLI
|
||||
|
||||
=======
|
||||
- ✅ **Linting**: Code quality checks with `go fmt` and `go vet`
|
||||
- ✅ **Version Management**: Automatic version detection
|
||||
- ✅ **Portable**: Uses standard GitHub Actions workflow format
|
||||
|
||||
### Workflow File
|
||||
```yaml
|
||||
# .github/workflows/main.yml
|
||||
jobs:
|
||||
build-test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.26.1'
|
||||
- run: go build ./...
|
||||
- run: go test ./... -cover
|
||||
|
||||
lint-format:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: go fmt ./...
|
||||
- run: go vet ./...
|
||||
```bash
|
||||
go run ./cmd/greet # Hello world!
|
||||
go run ./cmd/greet Alice # Hello Alice!
|
||||
```
|
||||
|
||||
### Setup Instructions
|
||||
1. **Gitea**: Enable GitHub Actions compatibility in repo settings
|
||||
2. **GitHub**: Push to mirror repository (workflow runs automatically)
|
||||
3. **GitLab**: Convert workflow to `.gitlab-ci.yml` or use compatibility mode
|
||||
|
||||
**See [ADR 0016](adr/0016-ci-cd-pipeline-design.md) for complete CI/CD design and [STATUS_BADGES.md](STATUS_BADGES.md) for badge setup.**
|
||||
|
||||
## Configuration
|
||||
|
||||
Basic configuration options:
|
||||
All options are available via `config.yaml` or `DLC_*` environment variables.
|
||||
|
||||
```bash
|
||||
# Start with default configuration
|
||||
./scripts/start-server.sh start
|
||||
| Env var | Default | Description |
|
||||
|---------|---------|-------------|
|
||||
| `DLC_SERVER_PORT` | `8080` | Listening port |
|
||||
| `DLC_SERVER_HOST` | `0.0.0.0` | Bind address |
|
||||
| `DLC_LOGGING_JSON` | `false` | JSON log format |
|
||||
| `DLC_LOGGING_OUTPUT` | stderr | Log file path |
|
||||
| `DLC_SHUTDOWN_TIMEOUT` | `30s` | Graceful shutdown window |
|
||||
| `DLC_API_V2_ENABLED` | `false` | Enable `/api/v2` routes |
|
||||
| `DLC_CONFIG_FILE` | `./config.yaml` | Override config path |
|
||||
|
||||
# Custom port
|
||||
export DLC_SERVER_PORT=9090
|
||||
./scripts/start-server.sh start
|
||||
See `config.example.yaml` for a full template.
|
||||
|
||||
# JSON logging
|
||||
export DLC_LOGGING_JSON=true
|
||||
./scripts/start-server.sh start
|
||||
```
|
||||
## API
|
||||
|
||||
**See [AGENTS.md](AGENTS.md#configuration-management) for comprehensive configuration guide including:**
|
||||
- File-based configuration
|
||||
- Environment variables
|
||||
- Configuration priority rules
|
||||
- OpenTelemetry setup
|
||||
- Advanced scenarios
|
||||
|
||||
## Usage
|
||||
|
||||
### New Cobra CLI (Recommended)
|
||||
|
||||
```bash
|
||||
# Show help
|
||||
./bin/dance-lessons-coach --help
|
||||
|
||||
# Show version
|
||||
./bin/dance-lessons-coach version
|
||||
|
||||
# Greet someone
|
||||
./bin/dance-lessons-coach greet John
|
||||
|
||||
# Start server
|
||||
./bin/dance-lessons-coach server
|
||||
```
|
||||
|
||||
### Legacy CLI (Deprecated)
|
||||
|
||||
```bash
|
||||
# Default greeting
|
||||
go run ./cmd/greet
|
||||
# Output: Hello world!
|
||||
|
||||
# Custom greeting
|
||||
go run ./cmd/greet John
|
||||
# Output: Hello John!
|
||||
```
|
||||
|
||||
### Web Server
|
||||
|
||||
**Using the server control script (recommended):**
|
||||
|
||||
```bash
|
||||
# Start the server
|
||||
./scripts/start-server.sh start
|
||||
|
||||
# Test API endpoints
|
||||
./scripts/start-server.sh test
|
||||
|
||||
# Access OpenAPI documentation
|
||||
# Swagger UI: http://localhost:8080/swagger/
|
||||
# OpenAPI spec: http://localhost:8080/swagger/doc.json
|
||||
|
||||
# Stop the server
|
||||
./scripts/start-server.sh stop
|
||||
```
|
||||
|
||||
**Manual server management:**
|
||||
|
||||
```bash
|
||||
# Start the server
|
||||
go run ./cmd/server
|
||||
|
||||
# Test API endpoints
|
||||
curl http://localhost:8080/api/health
|
||||
# Output: {"status":"healthy"}
|
||||
|
||||
curl http://localhost:8080/api/ready
|
||||
# Output: {"ready":true}
|
||||
|
||||
curl http://localhost:8080/api/v1/greet
|
||||
# Output: {"message":"Hello world!"}
|
||||
|
||||
curl http://localhost:8080/api/v1/greet/John
|
||||
# Output: {"message":"Hello John!"}
|
||||
```
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| GET | `/api/health` | Liveness check |
|
||||
| GET | `/api/ready` | Readiness check (503 during shutdown) |
|
||||
| GET | `/api/version` | Version info (`?format=plain\|full\|json`) |
|
||||
| GET | `/api/v1/greet/` | Default greeting |
|
||||
| GET | `/api/v1/greet/{name}` | Named greeting |
|
||||
| POST | `/api/v2/greet` | V2 greeting with validation |
|
||||
| GET | `/swagger/` | Swagger UI |
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
go test ./...
|
||||
|
||||
# Run specific package tests
|
||||
go test ./pkg/greet/
|
||||
go test ./... # unit + integration tests
|
||||
./scripts/test-graceful-shutdown.sh # lifecycle + JSON logging validation
|
||||
./scripts/test-opentelemetry.sh # tracing end-to-end
|
||||
```
|
||||
|
||||
## CI/CD
|
||||
## Gitea Client
|
||||
|
||||
dance-lessons-coach includes a comprehensive CI/CD pipeline with multiple testing options:
|
||||
AI agent helper script at `.vibe/skills/gitea-client/scripts/gitea-client.sh`.
|
||||
|
||||
### Local Testing (No Gitea Required)
|
||||
Auth setup:
|
||||
```bash
|
||||
# Validate workflow structure
|
||||
./scripts/cicd.sh validate
|
||||
|
||||
# Test workflow steps locally
|
||||
./scripts/cicd.sh test-simple
|
||||
echo "your_token" > ~/.gitea_token
|
||||
chmod 600 ~/.gitea_token
|
||||
export GITEA_API_TOKEN_FILE="$HOME/.gitea_token"
|
||||
```
|
||||
|
||||
### Gitea Integration
|
||||
```bash
|
||||
# Test local setup with Gitea configuration
|
||||
./scripts/cicd.sh test-local
|
||||
|
||||
# Check pipeline status on Gitea
|
||||
./scripts/cicd.sh check-status
|
||||
```
|
||||
|
||||
### Full CI/CD Testing
|
||||
```bash
|
||||
# Test with docker compose (requires Gitea runner)
|
||||
./scripts/cicd.sh test-docker
|
||||
```
|
||||
|
||||
**See [adr/0016-ci-cd-pipeline-design.md](adr/0016-ci-cd-pipeline-design.md) for complete CI/CD architecture.**
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
dance-lessons-coach/
|
||||
├── adr/ # Architecture Decision Records
|
||||
├── cmd/ # Entry points (greet CLI, server)
|
||||
├── pkg/ # Core packages (config, greet, server, telemetry)
|
||||
│ └── server/docs/ # Generated OpenAPI documentation (gitignored)
|
||||
├── config.yaml # Configuration file
|
||||
├── scripts/ # Management scripts
|
||||
└── go.mod # Go module definition
|
||||
```
|
||||
|
||||
**See [AGENTS.md](AGENTS.md#project-structure) for detailed structure and component explanations.**
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
### Generate OpenAPI Documentation
|
||||
|
||||
The project uses [swaggo/swag](https://github.com/swaggo/swag) to generate OpenAPI/Swagger documentation from code annotations:
|
||||
|
||||
```bash
|
||||
# Generate documentation
|
||||
go generate ./pkg/server/
|
||||
|
||||
# This creates:
|
||||
# - pkg/server/docs/docs.go (swagger template)
|
||||
# - pkg/server/docs/swagger.json (OpenAPI spec)
|
||||
# - pkg/server/docs/swagger.yaml (YAML version)
|
||||
```
|
||||
|
||||
**Note:** `pkg/server/docs/` is gitignored. Documentation is embedded in the binary at build time.
|
||||
|
||||
### Documentation Annotations
|
||||
|
||||
Add swagger annotations to handlers and models:
|
||||
|
||||
```go
|
||||
// @Summary Get personalized greeting
|
||||
// @Description Returns a greeting with the specified name
|
||||
// @Tags greet
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param name path string true "Name to greet"
|
||||
// @Success 200 {object} GreetResponse "Successful response"
|
||||
// @Failure 400 {object} ErrorResponse "Invalid name parameter"
|
||||
// @Router /v1/greet/{name} [get]
|
||||
func (h *apiV1GreetHandler) handleGreetPath(w http.ResponseWriter, r *http.Request) {
|
||||
// handler implementation
|
||||
}
|
||||
```
|
||||
Get a token at https://gitea.arcodange.lab → Profile → Settings → Applications.
|
||||
|
||||
## Architecture
|
||||
|
||||
This project uses Architecture Decision Records (ADRs) to document key technical choices. See [adr/](adr/) for complete documentation including decisions on Go 1.26.1, Chi router, Zerolog, OpenTelemetry, interface-based design, graceful shutdown, configuration management, testing strategies, and OpenAPI documentation.
|
||||
|
||||
**Adding new decisions?** See [adr/README.md](adr/README.md) for guidelines.
|
||||
|
||||
## Gitea Integration
|
||||
|
||||
dance-lessons-coach includes AI agent skills for Gitea integration to monitor CI/CD jobs and interact with pull requests.
|
||||
|
||||
### Gitea Client Skill Setup
|
||||
|
||||
The Gitea client skill enables AI agents to:
|
||||
- Monitor CI/CD job status
|
||||
- Fetch job logs for debugging
|
||||
- Comment on pull requests
|
||||
- Track PR status
|
||||
|
||||
**Setup Instructions:**
|
||||
|
||||
1. **Create a Personal Access Token:**
|
||||
- Log in to https://gitea.arcodange.lab
|
||||
- Go to Profile → Settings → Applications
|
||||
- Generate token with `read:repository`, `write:repository`, and `read:user` scopes
|
||||
|
||||
2. **Configure Authentication:**
|
||||
```bash
|
||||
# Option 1: Environment variable
|
||||
export GITEA_API_TOKEN="your_token"
|
||||
|
||||
# Option 2: Token file (recommended)
|
||||
echo "your_token" > ~/.gitea_token
|
||||
chmod 600 ~/.gitea_token
|
||||
export GITEA_API_TOKEN_FILE="$HOME/.gitea_token"
|
||||
```
|
||||
|
||||
3. **Add to shell configuration:**
|
||||
```bash
|
||||
echo 'export GITEA_API_TOKEN_FILE="$HOME/.gitea_token"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
**Usage Examples:**
|
||||
```bash
|
||||
# List recent jobs
|
||||
.vibe/skills/gitea-client/scripts/gitea-client.sh list-jobs owner repo workflow_id 5
|
||||
|
||||
# Wait for job completion
|
||||
.vibe/skills/gitea-client/scripts/gitea-client.sh wait-job owner repo job_id 300
|
||||
|
||||
# Comment on PR
|
||||
.vibe/skills/gitea-client/scripts/gitea-client.sh comment-pr owner repo 42 "Build completed!"
|
||||
```
|
||||
|
||||
**Documentation:** See [.vibe/skills/gitea-client/README.md](.vibe/skills/gitea-client/README.md) for complete setup and usage guide.
|
||||
|
||||
## 🤖 AI Agent Usage
|
||||
|
||||
### Quick Launch Commands
|
||||
|
||||
**Programmer Agent** (for code implementation, testing, CI/CD):
|
||||
```bash
|
||||
vibe start --agent dancelessonscoachprogrammer
|
||||
```
|
||||
|
||||
**Product Owner Agent** (for requirements, interviews, documentation):
|
||||
```bash
|
||||
vibe start --agent dancelessonscoach-product-owner
|
||||
```
|
||||
|
||||
### Full Documentation
|
||||
|
||||
For complete agent usage guide including:
|
||||
- Agent selection guidance
|
||||
- Common workflow examples
|
||||
- Configuration reference
|
||||
- Best practices
|
||||
- Troubleshooting tips
|
||||
|
||||
See: [AGENT_USAGE_GUIDE.md](documentation/AGENT_USAGE_GUIDE.md)
|
||||
|
||||
### Gitmoji Cheatsheet
|
||||
|
||||
Quick reference for commit messages:
|
||||
- **📝 `:memo:` docs** - Documentation
|
||||
- **✨ `:sparkles:` feat** - New feature
|
||||
- **🐛 `:bug:` fix** - Bug fix
|
||||
- **♻️ `:recycle:` refactor** - Code refactoring
|
||||
- **🔧 `:wrench:` chore** - Build/config changes
|
||||
|
||||
Full cheatsheet: [GITMOJI_CHEATSHEET.md](documentation/GITMOJI_CHEATSHEET.md)
|
||||
Key decisions are documented in [adr/](adr/). See [AGENTS.md](AGENTS.md) for the full development reference (commands, config, ADR index, commit conventions).
|
||||
|
||||
## License
|
||||
|
||||
|
||||
Reference in New Issue
Block a user