From 6b52526e44c03d8933b6dbe8677165758a9c11dd Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Sat, 20 Jun 2026 09:16:27 +0200 Subject: [PATCH] Auto-build docker when docker file changes. --- .gitea/workflows/ci.yaml | 75 ++++++++++++++++++++++++++++++++++++ .gitea/workflows/docker.yaml | 45 ++++++++++++++++++++++ .gitea/workflows/docs.yaml | 10 ++--- .gitea/workflows/test.yaml | 15 ++------ 4 files changed, 126 insertions(+), 19 deletions(-) create mode 100644 .gitea/workflows/ci.yaml create mode 100644 .gitea/workflows/docker.yaml diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml new file mode 100644 index 0000000..a45ba41 --- /dev/null +++ b/.gitea/workflows/ci.yaml @@ -0,0 +1,75 @@ +name: '๐Ÿšฆ CI' + +# Single orchestrator. This is the only workflow that triggers on push/PR. +# It decides which reusable sub-workflows to run and in what order: +# changes โ”€โ”ฌโ”€> docker (only if the Dockerfile/requirements changed) โ”€โ”ฌโ”€> test +# โ”‚ โ””โ”€> docs +# When the builder image is rebuilt it MUST finish (and push) before test/docs +# run, so they validate against the fresh image. +on: + push: + branches: + - master + - develop + pull_request: + branches: + - master + - develop + workflow_dispatch: + +jobs: + # Detect which parts of the repo changed in this push/PR. + changes: + runs-on: linux/amd64 + outputs: + dockerfile: ${{ steps.filter.outputs.dockerfile }} + code: ${{ steps.filter.outputs.code }} + docs: ${{ steps.filter.outputs.docs }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Detect changed paths + id: filter + uses: dorny/paths-filter@v3 + with: + filters: | + dockerfile: + - 'Dockerfile.builder' + - 'docs/requirements.txt' + docs: + - 'docs/**' + - 'mkdocs.yml' + - 'examples/**/*.cpp' + code: + - 'src/**' + - 'include/**' + - 'tests/**' + - 'examples/**' + - 'python/**' + - 'CMakeLists.txt' + - '**/*.cpp' + - '**/*.hpp' + - '**/*.h' + + # Rebuild the builder image first, but only when it actually changed. + # On pull requests we build to validate the Dockerfile but do not push. + docker: + needs: changes + if: ${{ needs.changes.outputs.dockerfile == 'true' }} + uses: ./.gitea/workflows/docker.yaml + with: + push: ${{ github.event_name != 'pull_request' }} + + # Runs after docker (if docker ran). A skipped docker job is fine; a failed + # one blocks this via !failure(). Re-run tests when code OR the image changed. + test: + needs: [changes, docker] + if: ${{ !failure() && !cancelled() && (needs.changes.outputs.code == 'true' || needs.changes.outputs.dockerfile == 'true') }} + uses: ./.gitea/workflows/test.yaml + + docs: + needs: [changes, docker] + if: ${{ !failure() && !cancelled() && github.ref == 'refs/heads/master' && (needs.changes.outputs.docs == 'true' || needs.changes.outputs.dockerfile == 'true') }} + uses: ./.gitea/workflows/docs.yaml + secrets: inherit diff --git a/.gitea/workflows/docker.yaml b/.gitea/workflows/docker.yaml new file mode 100644 index 0000000..824e4fb --- /dev/null +++ b/.gitea/workflows/docker.yaml @@ -0,0 +1,45 @@ +name: '๐Ÿณ Builder Image' + +# Reusable workflow: builds (and optionally pushes) the kpnpp-builder image. +# It is called by ci.yaml only when Dockerfile.builder or docs/requirements.txt +# change. It runs on the host runner (NOT inside the builder container) because +# it needs the Docker CLI/daemon. +on: + workflow_call: + inputs: + push: + description: 'Push the built image to the registry' + type: boolean + default: true + workflow_dispatch: + inputs: + push: + description: 'Push the built image to the registry' + type: boolean + default: true + +jobs: + build: + runs-on: linux/amd64 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # No docker login step: the host runner was authenticated to + # gitea.tourolle.paris with `docker login` during setup, so its cached + # credentials in ~/.docker/config.json cover the push below. + - name: Build builder image + # Context is the repo root because Dockerfile.builder COPYs + # docs/requirements.txt during the build. + run: | + docker build \ + -f Dockerfile.builder \ + -t gitea.tourolle.paris/dtourolle/kpnpp-builder:latest \ + -t gitea.tourolle.paris/dtourolle/kpnpp-builder:${{ github.sha }} \ + . + + - name: Push builder image + if: ${{ inputs.push }} + run: | + docker push gitea.tourolle.paris/dtourolle/kpnpp-builder:latest + docker push gitea.tourolle.paris/dtourolle/kpnpp-builder:${{ github.sha }} diff --git a/.gitea/workflows/docs.yaml b/.gitea/workflows/docs.yaml index 596d487..98cbdec 100644 --- a/.gitea/workflows/docs.yaml +++ b/.gitea/workflows/docs.yaml @@ -1,13 +1,9 @@ name: '๐Ÿ“š Docs' +# Triggering and path filtering are owned by ci.yaml (the orchestrator), which +# calls this as a reusable workflow. workflow_dispatch is kept for manual runs. on: - push: - branches: - - master - paths: - - 'docs/**' - - 'mkdocs.yml' - - 'examples/**/*.cpp' # snippet sources + workflow_call: workflow_dispatch: jobs: diff --git a/.gitea/workflows/test.yaml b/.gitea/workflows/test.yaml index 1deea37..799fac8 100644 --- a/.gitea/workflows/test.yaml +++ b/.gitea/workflows/test.yaml @@ -1,18 +1,9 @@ name: '๐Ÿงช Test' +# Triggering and path filtering are owned by ci.yaml (the orchestrator), which +# calls this as a reusable workflow. workflow_dispatch is kept for manual runs. on: - push: - branches: - - master - - develop - paths-ignore: - - '**/*.md' - pull_request: - branches: - - master - - develop - paths-ignore: - - '**/*.md' + workflow_call: workflow_dispatch: jobs: