feat(workflow): scope docker publishes to changed services

Add a preflight change-detection job to the Docker publish workflow and
derive the build matrix from shared-root and service-specific path
filters. Preserve full publishes on manual dispatch while skipping
unaffected service image builds on routine pushes.
This commit is contained in:
yinjianm
2026-04-19 01:59:35 +08:00
parent 5118e75efe
commit 00d7c6c2f3
8 changed files with 277 additions and 19 deletions
+80 -8
View File
@@ -14,18 +14,90 @@ env:
REGISTRY: ghcr.io
jobs:
detect-changes:
runs-on: ubuntu-latest
outputs:
shared: ${{ steps.manual.outputs.shared || steps.filter.outputs.shared }}
frontend: ${{ steps.manual.outputs.frontend || steps.filter.outputs.frontend }}
backend: ${{ steps.manual.outputs.backend || steps.filter.outputs.backend }}
remote_gateway: ${{ steps.manual.outputs.remote_gateway || steps.filter.outputs.remote_gateway }}
matrix: ${{ steps.matrix.outputs.matrix }}
has_changes: ${{ steps.matrix.outputs.has_changes }}
steps:
- name: Checkout repository
if: github.event_name != 'workflow_dispatch'
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Mark all services changed for manual dispatch
if: github.event_name == 'workflow_dispatch'
id: manual
run: |
echo "shared=true" >> "$GITHUB_OUTPUT"
echo "frontend=true" >> "$GITHUB_OUTPUT"
echo "backend=true" >> "$GITHUB_OUTPUT"
echo "remote_gateway=true" >> "$GITHUB_OUTPUT"
- name: Detect changed paths
if: github.event_name != 'workflow_dispatch'
id: filter
uses: dorny/paths-filter@v3
with:
filters: |
shared:
- '.github/workflows/docker-publish.yml'
- 'package.json'
- 'package-lock.json'
- 'docker-compose.yml'
- 'patches/**'
frontend:
- 'packages/frontend/**'
backend:
- 'packages/backend/**'
remote_gateway:
- 'packages/remote-gateway/**'
- name: Build service matrix
id: matrix
env:
SHARED: ${{ steps.manual.outputs.shared || steps.filter.outputs.shared }}
FRONTEND: ${{ steps.manual.outputs.frontend || steps.filter.outputs.frontend }}
BACKEND: ${{ steps.manual.outputs.backend || steps.filter.outputs.backend }}
REMOTE_GATEWAY: ${{ steps.manual.outputs.remote_gateway || steps.filter.outputs.remote_gateway }}
run: |
python <<'PY'
import json
import os
from pathlib import Path
shared = os.environ.get("SHARED") == "true"
services = [
("frontend", "packages/frontend/Dockerfile", os.environ.get("FRONTEND") == "true"),
("backend", "packages/backend/Dockerfile", os.environ.get("BACKEND") == "true"),
("remote-gateway", "packages/remote-gateway/Dockerfile", os.environ.get("REMOTE_GATEWAY") == "true"),
]
include = [
{"service": service, "dockerfile": dockerfile}
for service, dockerfile, changed in services
if shared or changed
]
output_path = Path(os.environ["GITHUB_OUTPUT"])
with output_path.open("a", encoding="utf-8") as output:
output.write(f"matrix={json.dumps({'include': include})}\n")
output.write(f"has_changes={'true' if include else 'false'}\n")
PY
publish:
needs: detect-changes
if: needs.detect-changes.outputs.has_changes == 'true'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- service: frontend
dockerfile: packages/frontend/Dockerfile
- service: backend
dockerfile: packages/backend/Dockerfile
- service: remote-gateway
dockerfile: packages/remote-gateway/Dockerfile
matrix: ${{ fromJson(needs.detect-changes.outputs.matrix) }}
steps:
- name: Checkout repository