Merge pull request #279 from christianlouis/copilot/consolidate-workflow-files

Consolidate workflows into 3-stage CI pipeline with proper dependencies
This commit is contained in:
Christian Krakau-Louis
2026-02-13 15:08:38 +01:00
committed by GitHub
7 changed files with 211 additions and 315 deletions
+211
View File
@@ -0,0 +1,211 @@
name: CI Pipeline
on:
push:
branches:
- main
- develop
tags:
- 'v*'
- '[0-9]+.*'
pull_request:
branches:
- main
permissions:
contents: read
packages: write
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
IMAGE_NAME: christianlouis/docuelevate
jobs:
# ══════════════════════════════════════════════════════════════════════════
# Stage 1: Quality Checks (run in parallel)
# ══════════════════════════════════════════════════════════════════════════
test:
name: Tests
runs-on: ubuntu-latest
services:
redis:
image: redis:7
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
rabbitmq:
image: rabbitmq:3-management
ports:
- 5672:5672
- 15672:15672
options: >-
--health-cmd "rabbitmq-diagnostics -q ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
- name: Run Tests
run: pytest tests/ -v --cov=app --cov-report=xml --cov-report=term --junitxml=junit.xml -o junit_family=legacy -m "not e2e"
- name: Upload coverage reports to Codecov
if: ${{ !cancelled() }}
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./coverage.xml
fail_ci_if_error: false
- name: Upload test results to Codecov
if: ${{ !cancelled() }}
uses: codecov/test-results-action@v1
with:
token: ${{ secrets.CODECOV_TOKEN }}
- name: Upload test artifacts
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v4
with:
name: test-results
path: |
junit.xml
coverage.xml
lint:
name: Ruff Lint & Format
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install Ruff
run: pip install ruff
- name: Run Ruff Check
run: ruff check app/ tests/
- name: Run Ruff Format
run: ruff format --check app/ tests/
mypy:
name: Mypy
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
- name: Run Mypy
run: mypy app/
# ══════════════════════════════════════════════════════════════════════════
# Stage 2: Build & Push Docker Image (only after all Stage 1 jobs pass)
# ══════════════════════════════════════════════════════════════════════════
build:
name: Build & Push Docker Image
runs-on: ubuntu-latest
needs: [test, lint, mypy]
if: github.event_name == 'push'
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Generate Build Metadata
run: |
chmod +x scripts/generate_build_metadata.sh
./scripts/generate_build_metadata.sh
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata for tags
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.IMAGE_NAME }}
ghcr.io/${{ github.repository_owner }}/docuelevate
tags: |
type=ref,event=branch
type=sha,prefix={{branch}}-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and Push Docker Image
uses: docker/build-push-action@v6
with:
context: .
file: Dockerfile
platforms: linux/amd64
push: true
sbom: true
provenance: mode=max
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
# ══════════════════════════════════════════════════════════════════════════
# Stage 3: Deploy (only after build succeeds, only on main branch)
# ══════════════════════════════════════════════════════════════════════════
deploy:
name: Deploy to Production
runs-on: ubuntu-latest
needs: [build]
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
steps:
- name: Call Deployment Webhook
run: |
curl -X POST https://docker2.kuechenserver.org/api/stacks/webhooks/960c7d8e-97ec-4175-a8dc-73f037b02349
-48
View File
@@ -1,14 +1,3 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL Advanced"
on:
@@ -22,20 +11,10 @@ on:
jobs:
analyze:
name: Analyze (${{ matrix.language }})
# Runner size impacts CodeQL analysis time. To learn more, please see:
# - https://gh.io/recommended-hardware-resources-for-running-codeql
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners (GitHub.com only)
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
permissions:
# required for all workflows
security-events: write
# required to fetch internal or private CodeQL packs
packages: read
# only required for workflows in private repositories
actions: read
contents: read
@@ -49,43 +28,16 @@ jobs:
build-mode: none
- language: python
build-mode: none
# CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift'
# Use `c-cpp` to analyze code written in C, C++ or both
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Add any setup steps before running the `github/codeql-action/init` action.
# This includes steps like installing compilers or runtimes (`actions/setup-node`
# or others). This is typically only required for manual builds.
# - name: Setup runtime (example)
# uses: actions/setup-example@v1
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# If the analyze step fails for one of the languages you are analyzing with
# "We were unable to automatically build your code", modify the matrix above
# to set the build mode to "manual" for that language. Then modify this step
# to build your code.
# ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- name: Run manual build steps
if: matrix.build-mode == 'manual'
shell: bash
-18
View File
@@ -1,18 +0,0 @@
name: Deploy to Production
on:
workflow_run:
workflows: ["Build and Push Docker Image"]
types:
- completed
permissions:
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Call Deployment Webhook
run: |
curl -X POST https://docker2.kuechenserver.org/api/stacks/webhooks/960c7d8e-97ec-4175-a8dc-73f037b02349
-80
View File
@@ -1,80 +0,0 @@
name: Build and Push Docker Image
permissions:
contents: read
packages: write
on:
push:
branches:
- main
- develop
tags:
- 'v*'
- '[0-9]+.*'
pull_request:
branches:
- main
env:
IMAGE_NAME: christianlouis/docuelevate
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Generate Build Metadata
run: |
chmod +x scripts/generate_build_metadata.sh
./scripts/generate_build_metadata.sh
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract Git Tag (if applicable)
if: startsWith(github.ref, 'refs/tags/')
run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
- name: Extract metadata for tags
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.IMAGE_NAME }}
ghcr.io/${{ github.repository_owner }}/docuelevate
- name: Build and Push Docker Image with Provenance and SBOM
uses: docker/build-push-action@v6
with:
context: .
file: Dockerfile
platforms: linux/amd64
push: true
sbom: true
provenance: mode=max
tags: |
${{ env.IMAGE_NAME }}:latest
${{ env.IMAGE_NAME }}:${{ github.sha }}
ghcr.io/${{ github.repository_owner }}/docuelevate:latest
ghcr.io/${{ github.repository_owner }}/docuelevate:${{ github.sha }}
${{ startsWith(github.ref, 'refs/tags/') && format('{0}:{1}', env.IMAGE_NAME, env.VERSION) || '' }}
${{ startsWith(github.ref, 'refs/tags/') && format('ghcr.io/{0}/docuelevate:{1}', github.repository_owner, env.VERSION) || '' }}
cache-from: type=gha
cache-to: type=gha,mode=max
-41
View File
@@ -1,41 +0,0 @@
name: ci
on:
push:
branches:
- "main"
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Generate Build Metadata
run: |
chmod +x scripts/generate_build_metadata.sh
./scripts/generate_build_metadata.sh
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ vars.DOCKER_USER }}
password: ${{ secrets.DOCKER_PAT }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
driver: cloud
endpoint: "christianlouis/cklbuilder"
install: true
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
tags: "${{ vars.DOCKER_USER }}/docuelevate:latest"
outputs: ${{ github.event_name == 'pull_request' && 'type=cacheonly' || 'type=registry' }}
provenance: mode=max
sbom: true
-11
View File
@@ -60,14 +60,3 @@ jobs:
git commit -m "chore(release): update build metadata files [skip ci]"
git push
fi
- name: Trigger Docker Build on Tag
if: startsWith(github.ref, 'refs/tags/')
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const ref = context.ref;
const tag = ref.replace('refs/tags/', '');
console.log(`New tag created: ${tag}`);
console.log('Docker build will be triggered automatically by the docker-build workflow');
-117
View File
@@ -1,117 +0,0 @@
name: Run Tests & Linting
on: [push, pull_request]
permissions:
contents: read
jobs:
# ── Tests ──────────────────────────────────────────────────────────────
test:
name: Tests
runs-on: ubuntu-latest
services:
redis:
image: redis:7
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
rabbitmq:
image: rabbitmq:3-management
ports:
- 5672:5672
- 15672:15672
options: >-
--health-cmd "rabbitmq-diagnostics -q ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
- name: Run Tests
# Exclude E2E tests (-m "not e2e") as they require Docker-in-Docker (testcontainers)
# which isn't well-supported in GitHub Actions without additional DinD configuration.
# E2E tests can be run locally with: pytest -m e2e
run: pytest tests/ -v --cov=app --cov-report=xml --cov-report=term --junitxml=junit.xml -o junit_family=legacy -m "not e2e"
- name: Upload coverage reports to Codecov
if: ${{ !cancelled() }}
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./coverage.xml
fail_ci_if_error: false
- name: Upload test results to Codecov
if: ${{ !cancelled() }}
uses: codecov/test-results-action@v1
with:
token: ${{ secrets.CODECOV_TOKEN }}
- name: Upload test artifacts
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v4
with:
name: test-results
path: |
junit.xml
coverage.xml
# ── Lint (Ruff) ───────────────────────────────────────────────────────
lint:
name: Ruff Lint & Format
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install Ruff
run: pip install ruff
- name: Run Ruff Check
run: ruff check app/ tests/
- name: Run Ruff Format
run: ruff format --check app/ tests/
# ── Mypy ───────────────────────────────────────────────────────────────
mypy:
name: Mypy
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
- name: Run Mypy
run: mypy app/