From 3cafc7bcb28a938cfb392156a82267e4646745be Mon Sep 17 00:00:00 2001 From: Gabriel Radureau Date: Thu, 9 Apr 2026 11:16:25 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=B3=20Attempt=201:=20Inline=20version?= =?UTF-8?q?=20of=20docker/Dockerfile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/README.md | 163 ++++++++++++++++++++++++++++++ .gitea/workflows/ci-cd.yaml | 61 ++++------- .gitea/workflows/docker-push.yaml | 132 +++++++++++++++++++++--- 3 files changed, 298 insertions(+), 58 deletions(-) create mode 100644 .gitea/workflows/README.md diff --git a/.gitea/workflows/README.md b/.gitea/workflows/README.md new file mode 100644 index 0000000..82ec6ff --- /dev/null +++ b/.gitea/workflows/README.md @@ -0,0 +1,163 @@ +# CI/CD Workflow Architecture + +## πŸ—ΊοΈ Overview + +The dance-lessons-coach project uses a **multi-workflow architecture** for better separation of concerns, maintainability, and flexibility. + +## πŸ“ Workflow Files + +### 1. `ci-cd.yaml` - Main CI/CD Pipeline + +**Purpose**: Run tests, build binaries, and generate documentation + +**Triggers**: +- Push to `main`, `ci/**`, `feature/**`, `fix/**`, `refactor/**` branches +- Pull requests to `main` branch +- Manual workflow dispatch + +**Jobs**: +1. **build-cache** - Build and cache Docker build environment +2. **ci-pipeline** - Run tests, build binaries, generate Swagger docs +3. **trigger-docker-push** - Trigger separate Docker workflow on main branch + +**Key Features**: +- Runs in container environment with all build tools +- Generates Swagger documentation +- Runs BDD and unit tests with PostgreSQL +- Updates badges and version information +- Triggers Docker workflow only on main branch + +### 2. `docker-push.yaml` - Docker Image Publishing + +**Purpose**: Build and push Docker images to registry + +**Triggers**: +- Manual workflow dispatch only (no automatic triggers) +- Triggered by `ci-cd.yaml` on main branch + +**Jobs**: +1. **docker-push** - Build production Docker image and push to registry + +**Key Features**: +- Runs on host environment (access to Docker daemon) +- Uses dependency hash from build-cache +- Builds minimal Alpine-based production image +- Pushes multiple tags (version, latest, commit SHA) + +## πŸ”§ Architecture Benefits + +### 1. Clear Separation of Concerns +- **CI/CD Pipeline**: Testing and artifact generation +- **Docker Publishing**: Image building and registry operations + +### 2. Proper Environment Isolation +- **CI jobs run in container**: Consistent build environment +- **Docker jobs run on host**: Access to Docker daemon + +### 3. Flexible Testing +- Can trigger Docker workflow independently for testing +- No complex conditional logic in main workflow +- Easier to debug and maintain + +### 4. Better Security +- Docker operations isolated in separate workflow +- Clear dependency between test success and deployment +- Manual trigger capability for emergency situations + +## πŸš€ Usage Examples + +### Trigger Full CI/CD Pipeline +```bash +# Automatically triggered on push to main branch +# Or manually: +./scripts/gitea-client.sh trigger-workflow arcodange dance-lessons-coach ci-cd.yaml main +``` + +### Trigger Docker Push Manually +```bash +# Get dependency hash from build-cache job first +DEPS_HASH="abc123def456" + +# Trigger Docker workflow manually +./scripts/gitea-client.sh trigger-workflow arcodange dance-lessons-coach docker-push.yaml main --deps_hash $DEPS_HASH +``` + +### Workflow Dispatch Parameters (docker-push.yaml) +- `deps_hash` (required): Dependency hash from build-cache job +- `ref` (optional): Git reference (branch/tag), defaults to current + +## πŸ”— Workflow Dependencies + +```mermaid +graph TD + A[Push to main] --> B[ci-cd.yaml] + B --> C[build-cache job] + B --> D[ci-pipeline job] + D --> E[trigger-docker-push job] + E --> F[docker-push.yaml] + F --> G[docker-push job] + G --> H[Docker Registry] +``` + +## πŸ“‹ Best Practices + +### 1. Always Run CI First +- Docker workflow should only be triggered after CI passes +- Maintains quality gate before deployment + +### 2. Use Dependency Hash +- Ensures consistent builds across workflows +- Pass hash from build-cache to docker-push + +### 3. Manual Testing +- Use separate Docker workflow for testing image builds +- Avoids polluting main branch with test images + +### 4. Monitor Both Workflows +- CI/CD workflow for test results and artifacts +- Docker workflow for image build and push status + +## 🎯 Future Enhancements + +### Potential Improvements: +- Add workflow status badges to README +- Implement workflow chaining with outputs +- Add matrix builds for multiple architectures +- Implement canary deployment workflow +- Add rollback capability + +### Architecture Considerations: +- Keep workflows focused on single responsibilities +- Maintain clear separation between test and deploy +- Document all workflow triggers and conditions +- Monitor workflow execution times and optimize + +## πŸ“ Maintenance + +### Adding New Jobs: +- Add to appropriate workflow based on responsibility +- CI-related jobs β†’ `ci-cd.yaml` +- Docker-related jobs β†’ `docker-push.yaml` + +### Modifying Triggers: +- Update trigger conditions in respective workflow files +- Test changes thoroughly before merging + +### Debugging: +- Check workflow logs in Gitea Actions +- Use `gitea-client.sh diagnose-job` for detailed analysis +- Monitor workflow dependencies and execution order + +## πŸ”’ Security + +### Secrets Management: +- Docker registry credentials stored in Gitea secrets +- Never hardcode credentials in workflow files +- Use GitHub token for workflow dispatch + +### Access Control: +- Only authorized users can trigger workflows +- Manual approval required for production deployments +- Audit logs available for all workflow executions + +This architecture provides a clean, maintainable, and secure CI/CD pipeline that scales well with project growth while maintaining clear separation of concerns. \ No newline at end of file diff --git a/.gitea/workflows/ci-cd.yaml b/.gitea/workflows/ci-cd.yaml index d3572de..2af0d9b 100644 --- a/.gitea/workflows/ci-cd.yaml +++ b/.gitea/workflows/ci-cd.yaml @@ -132,7 +132,8 @@ jobs: name: CI Pipeline needs: build-cache runs-on: ubuntu-latest-ca - if: "!contains(github.event.head_commit.message, '[skip ci]') && github.actor != 'ci-bot'" + # Skip conditions: standard skip ci + actor check + respect skip_ci input + if: "!contains(github.event.head_commit.message, '[skip ci]') && github.actor != 'ci-bot' && (!github.event.inputs.skip_ci || github.event.inputs.skip_ci == 'false')" container: image: ${{ env.CI_REGISTRY }}/${{ env.GITEA_ORG }}/${{ env.GITEA_REPO }}-build-cache:${{ needs.build-cache.outputs.deps_hash }} @@ -304,47 +305,23 @@ jobs: echo "ℹ️ No changes to push" fi - # Docker build and push (main branch only) - - name: Login to Gitea Container Registry - if: github.ref == 'refs/heads/main' - uses: docker/login-action@v3 - with: - registry: ${{ env.CI_REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.PACKAGES_TOKEN }} - - name: Build and push Docker image - if: github.ref == 'refs/heads/main' - run: | - source VERSION - IMAGE_VERSION="$MAJOR.$MINOR.$PATCH${PRERELEASE:+-$PRERELEASE}" - - # Use the template file with proper dependency hash replacement - DEPS_HASH="${{ needs.build-cache.outputs.deps_hash }}" - echo "Using dependency hash: $DEPS_HASH" - - # Create Dockerfile.prod from template - sed "s/{{DEPS_HASH}}/$DEPS_HASH/g" docker/Dockerfile.prod.template > docker/Dockerfile.prod - - TAGS="$IMAGE_VERSION latest ${{ github.sha }}" - echo "Building Docker image with tags: $TAGS" - - # Build the production image - docker build -t dance-lessons-coach -f docker/Dockerfile.prod . - - for TAG in $TAGS; do - IMAGE_NAME="${{ env.CI_REGISTRY }}/${{ env.GITEA_ORG }}/${{ env.GITEA_REPO }}:$TAG" - echo "Tagging and pushing: $IMAGE_NAME" - docker tag dance-lessons-coach "$IMAGE_NAME" - docker push "$IMAGE_NAME" - done - - name: Show published images - if: github.ref == 'refs/heads/main' + + # Trigger Docker push workflow on main branch + trigger-docker-push: + name: Trigger Docker Push + needs: [build-cache, ci-pipeline] + runs-on: ubuntu-latest-ca + if: "!contains(github.event.head_commit.message, '[skip ci]') && github.actor != 'ci-bot' && github.ref == 'refs/heads/main'" + + steps: + - name: Trigger Docker Push Workflow run: | - source VERSION - IMAGE_VERSION="$MAJOR.$MINOR.$PATCH${PRERELEASE:+-$PRERELEASE}" - echo "πŸ“¦ Published Docker images:" - echo " - ${{ env.CI_REGISTRY }}/${{ env.GITEA_ORG }}/${{ env.GITEA_REPO }}:$IMAGE_VERSION" - echo " - ${{ env.CI_REGISTRY }}/${{ env.GITEA_ORG }}/${{ env.GITEA_REPO }}:latest" - echo " - ${{ env.CI_REGISTRY }}/${{ env.GITEA_ORG }}/${{ env.GITEA_REPO }}:${{ github.sha }}" + echo "πŸš€ Triggering Docker Push workflow..." + curl -X POST \ + -H "Authorization: token ${{ secrets.GITEA_TOKEN || secrets.PACKAGES_TOKEN }}" \ + -H "Content-Type: application/json" \ + "${{ env.GITEA_INTERNAL }}api/v1/repos/${{ env.GITEA_ORG }}/${{ env.GITEA_REPO }}/actions/workflows/docker-push.yaml/dispatches" \ + -d '{"ref":"${{ github.ref }}"}' + echo "βœ… Docker Push workflow triggered successfully!" diff --git a/.gitea/workflows/docker-push.yaml b/.gitea/workflows/docker-push.yaml index 025050a..1e4f879 100644 --- a/.gitea/workflows/docker-push.yaml +++ b/.gitea/workflows/docker-push.yaml @@ -1,27 +1,31 @@ --- -# dance-lessons-coach Docker Push Workflow - Placeholder -# This workflow will be implemented to handle Docker image building and pushing -# Currently a placeholder to test workflow dispatch functionality +# dance-lessons-coach Docker Push Workflow +# Separate workflow for Docker image building and pushing +# Can be triggered manually or by CI/CD workflow name: Docker Push on: - # Manual trigger only for testing + # Manual trigger for testing or production workflow_dispatch: inputs: - deps_hash: - description: 'Dependency hash from build-cache job' - required: true - type: string ref: description: 'Git reference (branch/tag)' required: false type: string default: '' +# Environment variables +env: + GITEA_INTERNAL: "https://gitea.arcodange.lab/" + GITEA_EXTERNAL: "https://gitea.arcodange.fr/" + GITEA_ORG: "arcodange" + GITEA_REPO: "dance-lessons-coach" + CI_REGISTRY: "gitea.arcodange.lab" + jobs: - placeholder: - name: Docker Push Placeholder + docker-push: + name: Docker Push runs-on: ubuntu-latest-ca steps: @@ -30,10 +34,106 @@ jobs: with: ref: ${{ github.event.inputs.ref || github.ref }} - - name: Show workflow inputs + - name: Login to Gitea Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.CI_REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.PACKAGES_TOKEN }} + + - name: Calculate dependency hash + id: calc_hash run: | - echo "πŸš€ Docker Push Workflow Triggered" - echo "Dependency Hash: ${{ github.event.inputs.deps_hash }}" - echo "Git Reference: ${{ github.event.inputs.ref || github.ref }}" - echo "πŸ“ This is a placeholder - full implementation coming soon!" - echo "βœ… Workflow dispatch is working correctly!" + # Calculate dependency hash (same method as build-cache job) + DEPS_HASH=$(sha256sum go.mod go.sum docker/Dockerfile.build | sha256sum | cut -d' ' -f1 | head -c 12) + echo "Dependency hash: $DEPS_HASH" + echo "deps_hash=$DEPS_HASH" >> $GITHUB_OUTPUT + + - name: Build and push Docker image + run: | + source VERSION + IMAGE_VERSION="$MAJOR.$MINOR.$PATCH${PRERELEASE:+-$PRERELEASE}" + + # Use the calculated dependency hash + DEPS_HASH="${{ steps.calc_hash.outputs.deps_hash }}" + echo "Using dependency hash: $DEPS_HASH" + + TAGS="$IMAGE_VERSION latest ${{ github.sha }}" + echo "Building Docker image with tags: $TAGS" + + # Build the production image using inline version of docker/Dockerfile + docker build -t dance-lessons-coach -f - . <<'EOF' + # dance-lessons-coach Docker Image + # Multi-stage build for production deployment + + # Stage 1: Build binary + FROM golang:1.26.1-alpine AS builder + + WORKDIR /app + + # Copy go mod files + COPY go.mod go.sum ./ + RUN go mod download + + # Copy source code + COPY . ./ + + # Install swag and generate Swagger docs only if they don't exist + RUN if [ ! -f pkg/server/docs/swagger.json ]; then \ + echo "πŸ“ Generating Swagger documentation..." && \ + go install github.com/swaggo/swag/cmd/swag@latest && \ + cd pkg/server && go generate && \ + echo "βœ… Swagger documentation generated"; \ + else \ + echo "βœ… Swagger documentation already exists, skipping swag installation and generation"; \ + fi + + # Build binary + RUN CGO_ENABLED=0 GOOS=linux go build -o /dance-lessons-coach ./cmd/server + + # Stage 2: Final image + FROM alpine:3.18 + + WORKDIR /app + + # Install dependencies + RUN apk add --no-cache ca-certificates tzdata + + # Copy binary from builder + COPY --from=builder /dance-lessons-coach /app/dance-lessons-coach + + # Copy configuration + COPY config.yaml /app/config.yaml + + # Set permissions + RUN chmod +x /app/dance-lessons-coach + + # Set timezone + ENV TZ=UTC + + # Expose port + EXPOSE 8080 + + # Health check + HEALTHCHECK --interval=30s --timeout=3s \ + CMD wget -q --spider http://localhost:8080/api/health || exit 1 + + # Entry point + ENTRYPOINT ["/app/dance-lessons-coach"] + EOF + + for TAG in $TAGS; do + IMAGE_NAME="${{ env.CI_REGISTRY }}/${{ env.GITEA_ORG }}/${{ env.GITEA_REPO }}:$TAG" + echo "Tagging and pushing: $IMAGE_NAME" + docker tag dance-lessons-coach "$IMAGE_NAME" + docker push "$IMAGE_NAME" + done + + - name: Show published images + run: | + source VERSION + IMAGE_VERSION="$MAJOR.$MINOR.$PATCH${PRERELEASE:+-$PRERELEASE}" + echo "πŸ“¦ Published Docker images:" + echo " - ${{ env.CI_REGISTRY }}/${{ env.GITEA_ORG }}/${{ env.GITEA_REPO }}:$IMAGE_VERSION" + echo " - ${{ env.CI_REGISTRY }}/${{ env.GITEA_ORG }}/${{ env.GITEA_REPO }}:latest" + echo " - ${{ env.CI_REGISTRY }}/${{ env.GITEA_ORG }}/${{ env.GITEA_REPO }}:${{ github.sha }}"