diff --git a/internal/adapter/templates/templates/skeleton/.woodpecker.yml.tmpl b/internal/adapter/templates/templates/skeleton/.woodpecker.yml.tmpl index fbb54dc..7f8a7cc 100644 --- a/internal/adapter/templates/templates/skeleton/.woodpecker.yml.tmpl +++ b/internal/adapter/templates/templates/skeleton/.woodpecker.yml.tmpl @@ -37,11 +37,206 @@ steps: # COMPONENT_STEPS_BELOW # Do not remove the marker above - component steps are inserted here + # Sync point after all component builds complete + # This step has NO depends_on, so it waits for ALL previous steps + # (including any component steps inserted above) to complete + build-complete: + image: alpine:3.19 + commands: + - echo "All component builds complete" + when: + branch: main + event: push + + # Export OpenAPI specs from built services + # Runs after build-complete to ensure all services are ready + export-openapi: + depends_on: [build-complete] + image: golang:1.23 + commands: + - | + echo "==> Exporting OpenAPI specs from services" + for svc_dir in services/*/; do + [ -d "$svc_dir" ] || continue + svc=$(basename "$svc_dir") + [ "$svc" = ".gitkeep" ] && continue + + if [ -f "$svc_dir/cmd/server/main.go" ]; then + echo " Exporting spec for $svc" + (cd "$svc_dir" && go run ./cmd/server --export-openapi > openapi.json) || { + echo " WARNING: Failed to export spec for $svc" + continue + } + echo " Generated $svc_dir/openapi.json" + fi + done + when: + branch: main + event: push + + # Generate API documentation from OpenAPI specs + generate-docs: + image: node:20-slim + depends_on: [export-openapi] + commands: + - npm install -g widdershins + - | + echo "==> Generating Slate markdown from OpenAPI specs" + mkdir -p docs/source/includes + found_specs=0 + for spec in services/*/openapi.json; do + if [ -f "$spec" ]; then + svc=$(dirname "$spec" | xargs basename) + echo " Converting $svc" + widdershins \ + --language_tabs 'shell:curl' 'go:Go' \ + --summary \ + --omitHeader \ + --resolve \ + --shallowSchemas \ + "$spec" \ + -o "docs/source/includes/_${svc}.md" + found_specs=$((found_specs + 1)) + fi + done + echo "==> Converted $found_specs service specs" + when: + branch: main + event: push + + # Build Slate static documentation (skipped if no docs infrastructure) + build-docs: + image: ruby:3.2-slim + depends_on: [generate-docs] + commands: + - | + if [ ! -d "docs" ] || [ ! -f "docs/Gemfile" ]; then + echo "==> No docs/ directory or Gemfile found, skipping Slate build" + exit 0 + fi + - apt-get update && apt-get install -y build-essential nodejs + - cd docs && bundle install --jobs 4 + - cd docs && bundle exec middleman build --clean + - echo "==> Docs built to docs/build/" + when: + branch: main + event: push + + # Build and push docs-nginx image (skipped if no docs build output) + build-docs-image: + image: gcr.io/kaniko-project/executor:latest + depends_on: [build-docs] + commands: + - | + if [ ! -d "docs/build" ]; then + echo "==> No docs/build/ directory, skipping image build" + exit 0 + fi + - /kaniko/executor --dockerfile=docs/Dockerfile.nginx --context=docs --destination=registry.threesix.ai/{{PROJECT_NAME}}-docs:latest --destination=registry.threesix.ai/{{PROJECT_NAME}}-docs:${CI_COMMIT_SHA:0:8} + when: + branch: main + event: push + + # Deploy docs to docs.{{DOMAIN}} (skipped if no docs image was built) + deploy-docs: + image: bitnami/kubectl:latest + depends_on: [build-docs-image] + commands: + - | + # Check if docs image exists by trying to describe the deployment + # If this is the first build, the deployment won't exist yet + if [ ! -d "docs/build" ]; then + echo "==> No docs build output, skipping deployment" + exit 0 + fi + - | + cat <