name: Docker Publish on: push: branches: - main workflow_dispatch: permissions: contents: read packages: write 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: ${{ fromJson(needs.detect-changes.outputs.matrix) }} steps: - name: Checkout repository uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Log in to GitHub Container Registry uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Extract Docker metadata id: meta uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ github.repository_owner }}/nexus-terminal-${{ matrix.service }} tags: | type=raw,value=latest type=sha,format=short,prefix=sha- - name: Build and push ${{ matrix.service }} uses: docker/build-push-action@v6 with: context: . file: ${{ matrix.dockerfile }} platforms: linux/amd64 push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max,scope=${{ matrix.service }}