## Summary Homogenize all 23 ADRs to a single canonical header format, and rewrite `adr/README.md` to match the actual state of the corpus. This is **Tâche 7** of the ARCODANGE Phase 1 migration (Claude Code → Mistral Vibe). Independent from PR #17 (Tâche 6 — restructure AGENTS.md) — both can merge in any order. No code changes; only documentation. ## Changes ### 1. Homogenize 21 ADR headers (commit `db09d0a`) The audit (Tâche 6 Phase A, Mistral intent-router agent, 2026-05-02) had identified **3 inconsistent header formats** : - **F1** — list bullets (`* Status:` / `* Date:` / `* Deciders:`) : 11 ADRs (0001-0008, 0011, 0014, 0023) - **F2** — bold fields (`**Status:**` / `**Date:**` / `**Authors:**`) : 9 ADRs (0009, 0010, 0012, 0013, 0015, 0016, 0017, 0018, 0019) - **F3** — dedicated section (`## Status\n**Value** ✅`) : 5 ADRs (0020, 0021, 0022, 0024, 0025) Plus mixed metadata names (Authors / Deciders / Decision Date / Implementation Date / Implementation Status / Last Updated) and decorative emojis on status values made the corpus hard to scan or template against. **Canonical format adopted** (see `adr/README.md` for full template) : ```markdown # NN. Title **Status:** <Proposed | Accepted | Implemented | Partially Implemented | Approved | Rejected | Deferred | Deprecated | Superseded by ADR-NNNN> **Date:** YYYY-MM-DD **Authors:** Name(s) [optional **Field:** ... lines] ## Context... ``` **Transformations applied** (via `/tmp/homogenize-adrs.py` script, 23 files scanned, 21 modified — 0010 and 0012 were already conform) : - F1 list bullets → bold fields - F2 cleanup : `**Deciders:**` → `**Authors:**`, strip status emojis - F3 sections : `## Status\n**Value** ✅` → `**Status:** Value` (single line) - Strip decorative emojis from `**Status:**` and `**Implementation Status:**` - Convert `* Last Updated:` / `* Implementation Status:` / `* Decision Drivers:` / `* Decision Date:` to bold - Date typo fix : `2024-04-XX` → `2026-04-XX` for ADRs 0018, 0019 (off-by-2-years in original) - Normalize multiple blank lines after header (max 1) **ADR body content is preserved unchanged.** Only headers transformed. ### 2. Rewrite `adr/README.md` (commit `d64ab02`) Previous README had multiple inconsistencies : - Index table listed wrong titles for ADRs 0010-0021 (looked like an aspirational forecast that never matched reality — e.g. "0011 = Trunk-Based Development" but real 0011 is absent and Trunk-Based Development is actually 0017) - Listed entries for ADRs 0011 (validation library) and 0014 (gRPC) but **these files do not exist** in the repo - 0024 (BDD Test Organization) was missing from the detail list - Template still showed the obsolete F1 format (`* Status:`) - Decorative emojis on every status entry Rewrite : - Index table **regenerated from actual file contents** (title from H1, status from `**Status:**` line) — emoji-free, accurate - Notes that 0011 / 0014 are not currently in use (reserved) - Updated template block matches the canonical format - Status Legend extended with `Approved`, `Partially Implemented`, `Deferred` - Added note that 0026 is the next free number for new ADRs ## Test plan - [x] All 23 ADRs follow `**Status:**` / `**Date:**` / `**Authors:**` (verified via grep) - [x] No more occurrences of `* Status:` (F1) or `## Status` (F3) in any ADR header - [x] No more emojis on `**Status:**` lines - [x] `adr/README.md` index links resolve to existing files (no more 0011 / 0014 dead links) - [x] Pre-commit hooks pass (`go mod tidy`, `go fmt`, `swag fmt`) ## Migration context Part of Phase 1 of the ARCODANGE migration from Claude Code to Mistral Vibe. Tâche 7 of the curriculum. Independent from PR #17 (which restructures `AGENTS.md`). The two PRs touch disjoint files — no merge conflict expected when both are merged. 🤖 Generated with [Claude Code](https://claude.com/claude-code) (Opus 4.7, 1M context). Mistral Vibe (intent-router agent / mistral-medium-3.5) did the original audit identifying the 3 formats during Tâche 6 Phase A. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-Authored-By: Mistral Vibe (devstral-2 / mistral-medium-3.5) Reviewed-on: #18 Co-authored-by: Gabriel Radureau <arcodange@gmail.com> Co-committed-by: Gabriel Radureau <arcodange@gmail.com>
838 lines
26 KiB
Markdown
838 lines
26 KiB
Markdown
# 16. CI/CD Pipeline Design for Multi-Platform Compatibility
|
|
|
|
**Date:** 2026-04-05
|
|
**Status:** Accepted
|
|
**Authors:** Arcodange Team
|
|
**Decision Date:** 2026-04-08
|
|
**Implementation Status:** Completed
|
|
|
|
## Context
|
|
|
|
dance-lessons-coach requires a robust CI/CD pipeline that:
|
|
|
|
1. **Primary Platform**: Gitea (self-hosted Git service)
|
|
2. **Mirror Support**: GitHub and GitLab mirrors for visibility and backup
|
|
3. **Tool Agnostic**: Easy migration between CI/CD platforms
|
|
4. **Feature Requirements**:
|
|
- Automated builds and testing
|
|
- Version management and changelog generation
|
|
- Code quality checks (linting, formatting)
|
|
- Status badges for README
|
|
- Artifact publishing
|
|
- Deployment capabilities
|
|
|
|
## Decision Drivers
|
|
|
|
* **Gitea Compatibility**: Must work with Gitea's CI/CD capabilities
|
|
* **GitHub Actions Compatibility**: Leverage widely-known workflow syntax
|
|
* **GitLab CI Compatibility**: Support GitLab's pipeline format
|
|
* **Portability**: Easy migration between platforms
|
|
* **Open Source Friendly**: Use tools that work well with open source projects
|
|
* **Minimal Vendor Lock-in**: Avoid platform-specific features when possible
|
|
* **Badges & Status**: Visual indicators of build/test status
|
|
* **Code Quality**: Automated linting and formatting checks
|
|
* **Version Management**: Automatic version bumping based on conventional commits
|
|
* **Artifact Publishing**: Binary releases and container images
|
|
* **Mirror Sync**: Ensure mirrors stay in sync with CI/CD results
|
|
|
|
## Decision
|
|
|
|
We will implement a **multi-platform compatible CI/CD pipeline** using **GitHub Actions workflow syntax** as the common denominator, with platform-specific adapters where needed.
|
|
|
|
### Selected Architecture: Portable Workflow Design
|
|
|
|
```mermaid
|
|
graph TD
|
|
A[Gitea Main Repo] -->|GitHub Actions YAML| B[Gitea CI/CD]
|
|
A -->|Mirror Push| C[GitHub Mirror]
|
|
A -->|Mirror Push| D[GitLab Mirror]
|
|
C -->|GitHub Actions| E[GitHub CI/CD]
|
|
D -->|GitLab CI YAML| F[GitLab CI/CD]
|
|
B --> G[Status Badges]
|
|
E --> G
|
|
F --> G
|
|
```
|
|
|
|
### Pipeline Components
|
|
|
|
#### 1. Core Workflow (GitHub Actions YAML)
|
|
- **File**: `.github/workflows/main.yml` (works on all platforms)
|
|
- **Format**: Standard GitHub Actions workflow syntax
|
|
- **Benefits**: Widely understood, well-documented, portable
|
|
|
|
#### 2. Platform Adapters
|
|
- **Gitea**: Native support for GitHub Actions workflows
|
|
- **GitHub**: Native support (no adapter needed)
|
|
- **GitLab**: Use `github-actions-importer` or manual conversion
|
|
|
|
#### 3. Workflow Structure
|
|
|
|
```yaml
|
|
# .github/workflows/main.yml
|
|
name: dance-lessons-coach CI/CD
|
|
|
|
on:
|
|
push:
|
|
branches: [ main ]
|
|
pull_request:
|
|
branches: [ main ]
|
|
workflow_dispatch:
|
|
|
|
jobs:
|
|
build:
|
|
name: Build and Test
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: actions/setup-go@v4
|
|
with:
|
|
go-version: '1.26.1'
|
|
- run: go mod tidy
|
|
- run: go build ./...
|
|
- run: go test ./... -cover
|
|
|
|
lint:
|
|
name: Lint and Format
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: actions/setup-go@v4
|
|
with:
|
|
go-version: '1.26.1'
|
|
- run: go fmt ./...
|
|
- run: go vet ./...
|
|
- run: golangci-lint run
|
|
|
|
version:
|
|
name: Version Management
|
|
runs-on: ubuntu-latest
|
|
needs: [build, lint]
|
|
if: github.ref == 'refs/heads/main'
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- run: ./scripts/version-bump.sh auto # Auto-detect from commits
|
|
- run: git config user.name "CI/CD Bot"
|
|
- run: git config user.email "ci@dancelessonscoach.org"
|
|
- run: git add VERSION
|
|
- run: git commit -m "🤖 chore: auto version bump [skip ci]"
|
|
- run: git push
|
|
|
|
release:
|
|
name: Create Release
|
|
runs-on: ubuntu-latest
|
|
needs: version
|
|
if: github.ref == 'refs/heads/main'
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: actions/setup-go@v4
|
|
with:
|
|
go-version: '1.26.1'
|
|
- run: ./scripts/build-with-version.sh
|
|
- uses: softprops/action-gh-release@v1
|
|
with:
|
|
files: bin/*
|
|
generate_release_notes: true
|
|
```
|
|
|
|
### 4. Status Badges
|
|
|
|
```markdown
|
|
# README.md
|
|
|
|
[](https://ci.dancelessonscoach.org)
|
|
[](https://github.com/yourorg/dance-lessons-coach/actions)
|
|
[](https://gitlab.com/yourorg/dance-lessons-coach/-/pipelines)
|
|
[](https://goreportcard.com/report/github.com/yourorg/dance-lessons-coach)
|
|
[](https://codecov.io/gh/yourorg/dance-lessons-coach)
|
|
```
|
|
|
|
### 5. Mirror Synchronization Strategy
|
|
|
|
```mermaid
|
|
graph LR
|
|
A[Gitea Main] -->|Webhook| B[Gitea CI/CD]
|
|
A -->|Mirror Push| C[GitHub Mirror]
|
|
A -->|Mirror Push| D[GitLab Mirror]
|
|
C -->|Webhook| E[GitHub Actions]
|
|
D -->|Webhook| F[GitLab CI/CD]
|
|
B -->|Status| G[Gitea Badges]
|
|
E -->|Status| H[GitHub Badges]
|
|
F -->|Status| I[GitLab Badges]
|
|
```
|
|
|
|
## Implementation Plan
|
|
|
|
### Phase 1: Gitea CI/CD Setup (Week 1) - Arcodange Configuration
|
|
|
|
```bash
|
|
# 1. Create .gitea/workflows directory (Arcodange convention)
|
|
mkdir -p .gitea/workflows
|
|
|
|
# 2. Create main workflow file with Arcodange-specific configuration
|
|
cat > .gitea/workflows/ci-cd.yaml << 'EOF'
|
|
name: dance-lessons-coach CI/CD
|
|
|
|
on:
|
|
push:
|
|
branches: [ main ]
|
|
pull_request:
|
|
branches: [ main ]
|
|
|
|
# Arcodange-specific environment variables
|
|
env:
|
|
GITEA_INTERNAL: "https://gitea.arcodange.lab/"
|
|
GITEA_EXTERNAL: "https://gitea.arcodange.fr/"
|
|
CI_REGISTRY: "registry.arcodange.lab"
|
|
|
|
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 mod tidy
|
|
- run: go build ./...
|
|
- run: go test ./... -cover
|
|
|
|
# Use internal URL for API calls within Arcodange network
|
|
- name: Notify internal systems
|
|
if: always()
|
|
run: |
|
|
curl -X POST "$GITEA_INTERNAL/api/v1/repos/yourorg/dance-lessons-coach/statuses/$(git rev-parse HEAD)" \
|
|
-H "Authorization: token $GITEA_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"state\": \"$([ $? -eq 0 ] && echo 'success' || echo 'failure')\", \"context\": \"ci/build-test\"}"
|
|
EOF
|
|
|
|
# 3. Enable Gitea CI/CD in repo settings (Arcodange instance)
|
|
# - Go to: https://gitea.arcodange.lab/arcodange/dance-lessons-coach/settings/actions
|
|
# - Enable GitHub Actions
|
|
# - Configure runner to use internal network (192.168.1.202)
|
|
# - Set up GITEA_TOKEN for API access
|
|
# - SSH URL: ssh://git@192.168.1.202:2222/arcodange/dance-lessons-coach.git
|
|
|
|
# 4. Add STATUS_BADGES.md with Arcodange-specific URLs
|
|
cat > STATUS_BADGES.md << 'EOF'
|
|
## Arcodange Gitea Badges
|
|
|
|
```markdown
|
|
[](https://gitea.arcodange.fr/arcodange/dance-lessons-coach)
|
|
[](https://gitea.arcodange.fr/arcodange/dance-lessons-coach/-/pipelines)
|
|
```
|
|
|
|
**Configuration Details:**
|
|
- Organization: arcodange
|
|
- Repository: dance-lessons-coach
|
|
- Internal URL: https://gitea.arcodange.lab/
|
|
- External URL: https://gitea.arcodange.fr/
|
|
- SSH URL: ssh://git@192.168.1.202:2222/arcodange/dance-lessons-coach.git
|
|
- Badges use external URL with full org/repo path
|
|
- CI/CD uses internal URL for faster network access
|
|
EOF
|
|
|
|
# 5. Configure CI/CD runners on internal network
|
|
# - Set up runners to access: https://gitea.arcodange.lab/
|
|
# - Configure SSH access: ssh://git@192.168.1.202:2222/arcodange/dance-lessons-coach.git
|
|
# - Ensure runners have network access to internal services (192.168.1.202:2222)
|
|
# - Configure runners with proper GITEA_TOKEN
|
|
# - Test connection: curl https://gitea.arcodange.lab/api/v1/version
|
|
```
|
|
|
|
### Phase 2: Linting and Quality (Week 2)
|
|
```bash
|
|
# 1. Add golangci-lint configuration
|
|
cat > .golangci.yml << 'EOF'
|
|
run:
|
|
timeout: 5m
|
|
issues-exit-code: 1
|
|
tests: false
|
|
|
|
linters:
|
|
enable:
|
|
- errcheck
|
|
- gofmt
|
|
- goimports
|
|
- gosimple
|
|
- govet
|
|
- ineffassign
|
|
- staticcheck
|
|
- unused
|
|
EOF
|
|
|
|
# 2. Update workflow to include linting
|
|
cat >> .github/workflows/main.yml << 'EOF'
|
|
lint:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: actions/setup-go@v4
|
|
with:
|
|
go-version: '1.26.1'
|
|
- uses: golangci/golangci-lint-action@v3
|
|
with:
|
|
version: v1.55
|
|
EOF
|
|
|
|
# 3. Add pre-commit hooks
|
|
cat > .pre-commit-config.yaml << 'EOF'
|
|
repos:
|
|
- repo: https://github.com/golangci/golangci-lint
|
|
rev: v1.55.2
|
|
hooks:
|
|
- id: golangci-lint
|
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
rev: v4.4.0
|
|
hooks:
|
|
- id: trailing-whitespace
|
|
- id: end-of-file-fixer
|
|
- id: check-yaml
|
|
EOF
|
|
```
|
|
|
|
### Phase 3: Version Management (Week 3)
|
|
```bash
|
|
# 1. Enhance version-bump.sh for auto-detection
|
|
cat > scripts/version-bump-auto.sh << 'EOF'
|
|
#!/bin/bash
|
|
# Auto-detect version bump based on conventional commits
|
|
|
|
# Get last commit message
|
|
LAST_COMMIT=$(git log -1 --pretty=%B)
|
|
|
|
if echo "$LAST_COMMIT" | grep -q "^feat:"; then
|
|
echo "📋 Detected feature commit, bumping MINOR version"
|
|
./scripts/version-bump.sh minor
|
|
elif echo "$LAST_COMMIT" | grep -q "^fix:"; then
|
|
echo "🐛 Detected fix commit, bumping PATCH version"
|
|
./scripts/version-bump.sh patch
|
|
elif echo "$LAST_COMMIT" | grep -q "BREAKING CHANGE"; then
|
|
echo "💥 Detected breaking change, bumping MAJOR version"
|
|
./scripts/version-bump.sh major
|
|
else
|
|
echo "⏭️ No version bump needed for this commit type"
|
|
fi
|
|
EOF
|
|
|
|
# 2. Add version management to workflow
|
|
# 3. Create CHANGELOG.md auto-generation
|
|
```
|
|
|
|
### Phase 4: Badges and Status (Week 4)
|
|
```bash
|
|
# 1. Add badge documentation
|
|
cat > STATUS_BADGES.md << 'EOF'
|
|
# CI/CD Status Badges
|
|
|
|
## Gitea (Primary)
|
|
```markdown
|
|
[](https://ci.your-gitea-instance.com)
|
|
```
|
|
|
|
## GitHub Mirror
|
|
```markdown
|
|
[](https://github.com/yourorg/dance-lessons-coach/actions)
|
|
```
|
|
|
|
## GitLab Mirror
|
|
```markdown
|
|
[](https://gitlab.com/yourorg/dance-lessons-coach/-/pipelines)
|
|
```
|
|
|
|
## Code Quality
|
|
```markdown
|
|
[](https://goreportcard.com/report/github.com/yourorg/dance-lessons-coach)
|
|
[](https://codecov.io/gh/yourorg/dance-lessons-coach)
|
|
```
|
|
EOF
|
|
|
|
# 2. Add badges to README.md
|
|
# 3. Set up external badge services
|
|
```
|
|
|
|
### Phase 5: Mirror CI/CD Setup (Optional)
|
|
```bash
|
|
# For GitHub Mirror:
|
|
# 1. Enable GitHub Actions on the mirror repo
|
|
# 2. Use the same .github/workflows/main.yml
|
|
# 3. Configure mirror to not trigger builds on mirror pushes
|
|
|
|
# For GitLab Mirror:
|
|
# 1. Create .gitlab-ci.yml that imports GitHub Actions
|
|
# 2. Or manually convert workflow to GitLab CI syntax
|
|
# 3. Configure mirror to not trigger duplicate builds
|
|
```
|
|
|
|
## Pros and Cons of Selected Approach
|
|
|
|
### ✅ Advantages
|
|
|
|
1. **Portability**: GitHub Actions YAML works on Gitea and GitHub natively
|
|
2. **Familiarity**: Most developers know GitHub Actions syntax
|
|
3. **Documentation**: Excellent GitHub Actions documentation available
|
|
4. **Marketplace**: Access to GitHub Actions marketplace actions
|
|
5. **Mirror Compatibility**: Same workflow files work on mirrors
|
|
6. **Tool Agnostic**: Can convert to other formats if needed
|
|
7. **Badges**: Easy to generate status badges for all platforms
|
|
8. **Extensible**: Can add more jobs/stages as needed
|
|
|
|
### ❌ Disadvantages
|
|
|
|
1. **GitLab Conversion**: May need manual conversion for GitLab CI
|
|
2. **Vendor Features**: Some GitHub-specific features won't work on Gitea
|
|
3. **Learning Curve**: Team needs to learn GitHub Actions syntax
|
|
4. **Mirror Complexity**: Need to prevent duplicate builds on mirrors
|
|
5. **Badge Management**: Multiple badge URLs to maintain
|
|
|
|
## Validation
|
|
|
|
**Does this meet our requirements?**
|
|
- ✅ **Gitea Compatibility**: Uses Gitea's GitHub Actions support
|
|
- ✅ **GitHub Mirror**: Native GitHub Actions support
|
|
- ✅ **GitLab Mirror**: Can use conversion tools or manual setup
|
|
- ✅ **Portability**: Common workflow format across platforms
|
|
- ✅ **Badges**: Status badges for all platforms
|
|
- ✅ **Linting**: Integrated code quality checks
|
|
- ✅ **Version Management**: Automatic version bumping
|
|
- ✅ **Artifacts**: Binary releases and publishing
|
|
|
|
**What's still needed?**
|
|
- ❌ **Implementation**: Actual CI/CD pipeline setup
|
|
- ❌ **Gitea Configuration**: CI/CD runner setup on Gitea instance
|
|
- ❌ **Mirror Configuration**: Prevent duplicate builds
|
|
- ❌ **Badge Services**: Set up external badge providers
|
|
- ❌ **Testing**: Validate pipeline works on all platforms
|
|
- ❌ **Documentation**: Complete CI/CD setup guide
|
|
|
|
## 🐳 Docker-Based Local Testing (Primary Method)
|
|
|
|
**Arcodange uses Docker as the primary method for local CI/CD testing.**
|
|
|
|
### Comprehensive Testing Script
|
|
|
|
Use the provided script for complete Docker-based testing:
|
|
|
|
```bash
|
|
# Run complete CI/CD test suite
|
|
./scripts/test-cicd-docker.sh
|
|
```
|
|
|
|
**What the script does:**
|
|
1. ✅ Checks Docker availability
|
|
2. ✅ Pulls required Docker images
|
|
3. ✅ Validates YAML syntax with yq
|
|
4. ✅ Lints YAML with yamllint
|
|
5. ✅ Executes workflow with act runner
|
|
6. ✅ Reports success/failure
|
|
|
|
### Manual Docker Testing
|
|
|
|
For more control, run individual Docker commands:
|
|
|
|
```bash
|
|
# 1. Validate YAML syntax
|
|
docker run --rm \
|
|
-v $(pwd):/workspace \
|
|
-w /workspace \
|
|
mikefarah/yq:latest \
|
|
yq eval '.' .gitea/workflows/ci-cd.yaml
|
|
|
|
# 2. Lint YAML
|
|
docker run --rm \
|
|
-v $(pwd):/workspace \
|
|
-w /workspace \
|
|
cybertanium/yamllint:latest \
|
|
yamllint .gitea/workflows/
|
|
|
|
# 3. Run workflow with Arcodange environment
|
|
docker run --rm \
|
|
-v $(pwd):/workspace \
|
|
-w /workspace \
|
|
-e GITEA_INTERNAL="https://gitea.arcodange.lab/" \
|
|
-e GITEA_EXTERNAL="https://gitea.arcodange.fr/" \
|
|
-e GITEA_ORG="arcodange" \
|
|
-e GITEA_REPO="dance-lessons-coach" \
|
|
gitea/act_runner:latest \
|
|
act -W .gitea/workflows/ci-cd.yaml --rm
|
|
```
|
|
|
|
### Alternative: Using nektos/act for GitHub Actions Compatibility
|
|
|
|
```bash
|
|
# 1. Install act (GitHub Actions runner)
|
|
brew install act
|
|
|
|
# 2. Run workflow locally
|
|
act -W .gitea/workflows/ci-cd.yaml \
|
|
--secret-file .secrets \
|
|
--env-file .env \
|
|
--container-architecture linux/amd64
|
|
|
|
# 3. With specific event simulation
|
|
act push -W .gitea/workflows/ci-cd.yaml \
|
|
--env GITEA_ORG=arcodange \
|
|
--env GITEA_REPO=dance-lessons-coach
|
|
```
|
|
|
|
### Pipeline Status Checking Scripts
|
|
|
|
Create `scripts/check-pipeline-status.sh`:
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
# Check CI/CD pipeline status across all platforms
|
|
|
|
set -e
|
|
|
|
echo "🔍 Checking CI/CD Pipeline Status"
|
|
echo "================================"
|
|
|
|
# 1. Gitea (Primary) - Internal URL
|
|
if curl -s -o /dev/null -w "%{http_code}" "https://gitea.arcodange.lab/api/v1/repos/arcodange/dance-lessons-coach/actions/workflows" | grep -q "200"; then
|
|
echo "✅ Gitea Internal API: Accessible"
|
|
# Get workflow list
|
|
WORKFLOWS=$(curl -s "https://gitea.arcodange.lab/api/v1/repos/arcodange/dance-lessons-coach/actions/workflows" | jq -r '.[] | .name + " (" + .file_name + ")"')
|
|
echo "📋 Gitea Workflows:"
|
|
echo "$WORKFLOWS" | sed 's/^/ - /'
|
|
else
|
|
echo "❌ Gitea Internal API: Not accessible (check network/vpn)"
|
|
fi
|
|
|
|
# 2. Gitea (External) - Public URL
|
|
echo ""
|
|
echo "🌐 Gitea External Status:"
|
|
if curl -s -o /dev/null -w "%{http_code}" "https://gitea.arcodange.fr/arcodange/dance-lessons-coach" | grep -q "200"; then
|
|
echo "✅ Gitea External: Accessible"
|
|
echo "🔗 Repository: https://gitea.arcodange.fr/arcodange/dance-lessons-coach"
|
|
else
|
|
echo "❌ Gitea External: Not accessible"
|
|
fi
|
|
|
|
# 3. Check badge API
|
|
echo ""
|
|
echo "🏷️ Badge API Status:"
|
|
BADGE_URL="https://gitea.arcodange.fr/api/badges/arcodange/dance-lessons-coach/status"
|
|
if curl -s -o /dev/null -w "%{http_code}" "$BADGE_URL" | grep -q "200"; then
|
|
echo "✅ Badge API: Accessible"
|
|
echo "🔗 Badge URL: $BADGE_URL"
|
|
else
|
|
echo "❌ Badge API: Not accessible"
|
|
fi
|
|
|
|
# 4. Check workflow file existence
|
|
echo ""
|
|
echo "📁 Workflow Files:"
|
|
if [ -f ".gitea/workflows/ci-cd.yaml" ]; then
|
|
echo "✅ .gitea/workflows/ci-cd.yaml: Found"
|
|
echo "📊 Jobs: $(yq eval '.jobs | keys | join(", ")' .gitea/workflows/ci-cd.yaml)"
|
|
else
|
|
echo "❌ .gitea/workflows/ci-cd.yaml: Not found"
|
|
fi
|
|
|
|
echo ""
|
|
echo "🎯 Validation Summary"
|
|
echo "================================"
|
|
echo "✅ Local workflow file: .gitea/workflows/ci-cd.yaml"
|
|
echo "✅ Syntax validation: $(yq eval '.' .gitea/workflows/ci-cd.yaml > /dev/null 2>&1 && echo 'Valid YAML' || echo 'Invalid YAML')"
|
|
echo "✅ Gitea compatibility: Uses .gitea/workflows/ directory"
|
|
echo "✅ Arcodange conventions: Matches webapp workflow style"
|
|
|
|
echo ""
|
|
echo "💡 Next Steps:"
|
|
echo " 1. Push to trigger workflow: git push origin main"
|
|
echo " 2. Check Gitea Actions: https://gitea.arcodange.lab/arcodange/dance-lessons-coach/actions"
|
|
echo " 3. Monitor badges: https://gitea.arcodange.fr/arcodange/dance-lessons-coach"
|
|
```
|
|
|
|
### Workflow Validation Script
|
|
|
|
Create `scripts/validate-workflow.sh`:
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
# Validate CI/CD workflow syntax and structure
|
|
|
|
set -e
|
|
|
|
echo "🔍 Validating CI/CD Workflow"
|
|
echo "================================"
|
|
|
|
# 1. Check workflow file exists
|
|
if [ ! -f ".gitea/workflows/ci-cd.yaml" ]; then
|
|
echo "❌ Workflow file not found: .gitea/workflows/ci-cd.yaml"
|
|
exit 1
|
|
fi
|
|
|
|
echo "✅ Workflow file found"
|
|
|
|
# 2. Validate YAML syntax
|
|
if ! yq eval '.' .gitea/workflows/ci-cd.yaml > /dev/null 2>&1; then
|
|
echo "❌ Invalid YAML syntax"
|
|
yq eval '.' .gitea/workflows/ci-cd.yaml || true
|
|
exit 1
|
|
fi
|
|
|
|
echo "✅ YAML syntax valid"
|
|
|
|
# 3. Check required fields
|
|
MISSING_FIELDS=()
|
|
|
|
if [ -z "$(yq eval '.name' .gitea/workflows/ci-cd.yaml)" ]; then
|
|
MISSING_FIELDS+=("name")
|
|
fi
|
|
|
|
if [ -z "$(yq eval '.on' .gitea/workflows/ci-cd.yaml)" ]; then
|
|
MISSING_FIELDS+=("on")
|
|
fi
|
|
|
|
if [ -z "$(yq eval '.jobs' .gitea/workflows/ci-cd.yaml)" ]; then
|
|
MISSING_FIELDS+=("jobs")
|
|
fi
|
|
|
|
if [ ${#MISSING_FIELDS[@]} -gt 0 ]; then
|
|
echo "❌ Missing required fields: ${MISSING_FIELDS[*]}"
|
|
exit 1
|
|
fi
|
|
|
|
echo "✅ All required fields present"
|
|
|
|
# 4. Check jobs structure
|
|
JOBS=$(yq eval '.jobs | keys' .gitea/workflows/ci-cd.yaml)
|
|
echo "📋 Jobs defined: $JOBS"
|
|
|
|
for job in $JOBS; do
|
|
job_str=$(echo $job | tr -d '"')
|
|
|
|
# Check job has steps
|
|
if [ -z "$(yq eval ".jobs.$job_str.steps" .gitea/workflows/ci-cd.yaml)" ]; then
|
|
echo "❌ Job $job_str has no steps"
|
|
exit 1
|
|
fi
|
|
|
|
steps_count=$(yq eval ".jobs.$job_str.steps | length" .gitea/workflows/ci-cd.yaml)
|
|
echo " ✅ $job_str: $steps_count steps"
|
|
done
|
|
|
|
# 5. Check Arcodange-specific configurations
|
|
if [ -n "$(yq eval '.env.GITEA_INTERNAL' .gitea/workflows/ci-cd.yaml)" ]; then
|
|
echo "✅ Arcodange internal URL configured"
|
|
else
|
|
echo "⚠️ Arcodange internal URL not found"
|
|
fi
|
|
|
|
if [ -n "$(yq eval '.env.GITEA_EXTERNAL' .gitea/workflows/ci-cd.yaml)" ]; then
|
|
echo "✅ Arcodange external URL configured"
|
|
else
|
|
echo "⚠️ Arcodange external URL not found"
|
|
fi
|
|
|
|
# 6. Check concurrency settings
|
|
if [ -n "$(yq eval '.concurrency' .gitea/workflows/ci-cd.yaml)" ]; then
|
|
echo "✅ Concurrency control configured"
|
|
else
|
|
echo "⚠️ No concurrency control (consider adding)"
|
|
fi
|
|
|
|
echo ""
|
|
echo "🎉 Workflow Validation Successful!"
|
|
echo "================================"
|
|
echo "📁 Location: .gitea/workflows/ci-cd.yaml"
|
|
echo "🔧 Jobs: $JOBS"
|
|
echo "🎯 Ready for deployment"
|
|
```
|
|
|
|
### Docker Compose for Full Local Testing
|
|
|
|
Create `docker-compose.cicd-test.yml`:
|
|
|
|
```yaml
|
|
version: '3.8'
|
|
|
|
services:
|
|
act-runner:
|
|
image: gitea/act_runner:latest
|
|
volumes:
|
|
- .:/workspace
|
|
working_dir: /workspace
|
|
environment:
|
|
- GITEA_INTERNAL=https://gitea.arcodange.lab/
|
|
- GITEA_EXTERNAL=https://gitea.arcodange.fr/
|
|
- GITEA_ORG=arcodange
|
|
- GITEA_REPO=dance-lessons-coach
|
|
command: act -W .gitea/workflows/ci-cd.yaml --rm
|
|
|
|
yamllint:
|
|
image: cybertanium/yamllint:latest
|
|
volumes:
|
|
- .:/workspace
|
|
working_dir: /workspace
|
|
command: yamllint .gitea/workflows/
|
|
|
|
yq-validator:
|
|
image: mikefarah/yq:latest
|
|
volumes:
|
|
- .:/workspace
|
|
working_dir: /workspace
|
|
command: yq eval '.' .gitea/workflows/ci-cd.yaml
|
|
```
|
|
|
|
### Testing Commands Summary
|
|
|
|
```bash
|
|
# 1. Validate YAML syntax
|
|
yq eval '.' .gitea/workflows/ci-cd.yaml
|
|
|
|
# 2. Run local test
|
|
docker run --rm -v $(pwd):/workspace -w /workspace gitea/act_runner:latest \
|
|
act -W .gitea/workflows/ci-cd.yaml
|
|
|
|
# 3. Check pipeline status
|
|
./scripts/check-pipeline-status.sh
|
|
|
|
# 4. Validate workflow structure
|
|
./scripts/validate-workflow.sh
|
|
|
|
# 5. Full test with docker compose
|
|
docker compose -f docker-compose.cicd-test.yml up
|
|
```
|
|
|
|
## Future Enhancements
|
|
|
|
1. **Container Builds**: Add Docker image building and publishing
|
|
2. **Security Scanning**: Integrate vulnerability scanning
|
|
3. **Performance Testing**: Add benchmark tests to pipeline
|
|
4. **Deployment**: Add deployment stages for different environments
|
|
5. **Release Notes**: Auto-generate release notes from commits
|
|
6. **Dependency Updates**: Automated dependency updates
|
|
7. **Multi-Arch Builds**: Support ARM64, Windows builds
|
|
8. **Matrix Testing**: Test across multiple Go versions
|
|
|
|
## Automated Version Badge Workflow
|
|
|
|
The CI/CD pipeline includes an automated workflow for maintaining version badges in README.md:
|
|
|
|
```mermaid
|
|
graph TD
|
|
A[Developer Pushes Commit] --> B{Commit Type?}
|
|
B -->|feat:| C[Bump MINOR version]
|
|
B -->|fix:| D[Bump PATCH version]
|
|
B -->|breaking:| E[Bump MAJOR version]
|
|
B -->|other| F[No version bump]
|
|
C --> G[Update VERSION file]
|
|
D --> G[Update VERSION file]
|
|
E --> G[Update VERSION file]
|
|
G --> H[Update main.go Swagger version]
|
|
H --> I[Update README.md version badge]
|
|
I --> J[Commit & Push changes]
|
|
J --> K[Skip CI to prevent loops]
|
|
```
|
|
|
|
### Workflow Details
|
|
|
|
1. **Trigger**: Push events to main branch with specific commit message patterns
|
|
2. **Version Detection**: Parses commit messages for conventional commit types
|
|
3. **Automatic Bumping**: Increments version based on commit type (feat → minor, fix → patch, breaking → major)
|
|
4. **File Updates**: Updates VERSION file, Swagger documentation, and README.md badge
|
|
5. **Automatic Commit**: CI Bot commits changes with `[skip ci]` to prevent infinite loops
|
|
6. **Push**: Automatically pushes the version update back to the repository
|
|
|
|
### Benefits
|
|
|
|
- **Automatic Maintenance**: README.md version badge always stays current
|
|
- **No Manual Intervention**: Developers don't need to remember to update badges
|
|
- **Consistent Versioning**: Follows semantic versioning automatically
|
|
- **Audit Trail**: Version bumps are tracked in git history
|
|
- **CI/CD Integration**: Seamlessly integrated with existing pipeline
|
|
|
|
## References
|
|
|
|
- [Gitea Actions Documentation](https://docs.gitea.com/next/usage/actions/)
|
|
- [GitHub Actions Documentation](https://docs.github.com/en/actions)
|
|
- [GitLab CI/CD Documentation](https://docs.gitlab.com/ee/ci/)
|
|
- [Conventional Commits](https://www.conventionalcommits.org/)
|
|
- [Semantic Versioning](https://semver.org/)
|
|
- [GitHub Actions Marketplace](https://github.com/marketplace?type=actions)
|
|
- [golangci-lint](https://golangci-lint.run/)
|
|
- [Pre-commit Hooks](https://pre-commit.com/)
|
|
|
|
---
|
|
|
|
## Implementation Status
|
|
|
|
### ✅ Completed - Container/Services Architecture
|
|
|
|
The CI/CD pipeline has been successfully implemented using GitHub Actions' container/services architecture:
|
|
|
|
**Key Implementation Details:**
|
|
|
|
1. **Container-based Execution**: All CI steps run within a pre-built Docker cache image containing Go tools, Node.js, and PostgreSQL client
|
|
2. **Service-based PostgreSQL**: Database provided as a service container, accessible via `postgres` hostname
|
|
3. **Smart Caching**: Dependency hash calculated from `go.mod`, `go.sum`, and `Dockerfile.build` for accurate cache invalidation
|
|
4. **Environment Configuration**: Database connection parameters set via `DLC_*` environment variables
|
|
5. **Simplified Workflow**: Removed Docker Compose overhead and unnecessary setup steps
|
|
|
|
**Current Workflow Structure:**
|
|
|
|
```yaml
|
|
jobs:
|
|
build-cache:
|
|
name: Build Docker Cache
|
|
# Calculates dependency hash and builds cache image if needed
|
|
|
|
ci-pipeline:
|
|
name: CI Pipeline
|
|
needs: build-cache
|
|
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
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set database environment variables
|
|
run: |
|
|
echo "DLC_DATABASE_HOST=postgres" >> $GITHUB_ENV
|
|
echo "DLC_DATABASE_PORT=5432" >> $GITHUB_ENV
|
|
# ... other database config
|
|
|
|
- name: Generate Swagger Docs
|
|
run: go generate ./pkg/server
|
|
|
|
- name: Build all packages
|
|
run: go build ./...
|
|
|
|
- name: Wait for PostgreSQL to be ready
|
|
run: pg_isready -h postgres -p 5432
|
|
|
|
- name: Run tests with coverage
|
|
run: go test ./... -coverprofile=coverage.out
|
|
|
|
- name: Build binaries
|
|
run: ./scripts/build.sh
|
|
```
|
|
|
|
**Performance Improvements:**
|
|
- ✅ **Faster execution**: Direct container execution without compose overhead
|
|
- ✅ **Reliable caching**: Accurate dependency tracking with multi-file hash
|
|
- ✅ **Simpler debugging**: Clear container boundaries and service networking
|
|
- ✅ **Better portability**: Standard GitHub Actions patterns work across platforms
|
|
|
|
**Verification:**
|
|
- ✅ **Workflow 465**: Both jobs completed successfully (2026-04-08)
|
|
- ✅ **All tests passing**: Database connectivity working correctly
|
|
- ✅ **Coverage reporting**: Badges updating automatically
|
|
- ✅ **Binary builds**: Scripts executing properly in container environment
|
|
|
|
**Status:** Accepted
|
|
**Implementation Date:** 2026-04-08
|
|
**Implementation Owner:** Arcodange Team
|
|
**Reviewers:** @gabrielradureau |