3.7 KiB
3.7 KiB
Production GitHub Actions redesign
Goal
Rework .github/workflows into a production baseline that balances reliability, security, speed, and clear failures while keeping automatic deploys from main.
Current problems
- Deploy runner checks out submodules recursively even though deploy work happens on the VPS. Fresh submodule SHAs can fail with
not our refbefore deploy starts. - Repository dispatch can update a parent submodule pointer before the submodule SHA is fetchable by GitHub Actions.
- Build and deploy permissions are broader than needed at workflow level.
- Failure logs do not clearly separate build, manifest update, submodule readiness, and deployment phases.
Chosen approach
Use a split pipeline:
docker-build-push.ymlremains the build and manifest update pipeline.deploy-docker.ymlremains deploy-only.- Repository dispatch waits for the requested submodule SHA to be fetchable before building and updating the parent pointer.
- Deploy checkout no longer uses recursive submodules; the VPS updates submodules after resetting to
origin/main.
Build workflow design
Triggers:
pushtomainfor app/package/docker/workflow changes.repository_dispatchwithserviceandshapayload.workflow_dispatchfor manual full builds.
Jobs:
changes: detects the service matrix and validates dispatch payloads.build: builds and pushes only selected service images using Docker Buildx registry cache.update-manifest: updates compose image tags and, for dispatch events, updates the matching submodule pointer.
Repository dispatch handling:
- For dispatch events, wait until
git ls-remoteor equivalent fetch confirms the payload SHA exists in the service submodule remote. - Retry for a bounded timeout and fail with an explicit message if the SHA never becomes visible.
- Only after readiness is confirmed, checkout the SHA in the submodule and commit the parent pointer update.
Deploy workflow design
Triggers:
workflow_runfrom successfulBuild and Push Docker Imagesonmain.pushtomainforinfra/compose/**and deploy workflow changes.workflow_dispatch.
Behavior:
- Keep automatic deploy from
main. - Keep a single deploy concurrency group.
- Use non-recursive checkout on the runner.
- On the VPS, fetch/reset
origin/main, update submodules, compute changed compose stacks, pull images, and run Docker Compose.
Permissions and action trust
Defaults:
permissions:
contents: read
Job-specific permissions:
- Build job:
contents: read,packages: write. - Manifest update job:
contents: write. - Deploy job:
contents: read.
Action pinning:
- GitHub-owned and Docker official actions may use major versions such as
actions/checkout@v4anddocker/build-push-action@v6. - Any future third-party action should be pinned to a full commit SHA.
Reliability details
- Keep
set -euo pipefailin shell steps. - Add bounded retry around submodule SHA readiness.
- Add clear logs for selected services, image tags, compose files changed, and dispatch payload values.
- Avoid recursive submodule checkout in deploy to eliminate fresh-SHA checkout race.
- Manifest commits continue using
[skip ci]to prevent build loops.
Speed details
- Keep selective matrix builds.
- Keep Docker Buildx registry cache.
- Keep deploy checkout shallow and submodule-free.
- Avoid rebuilding from compose-only manifest commits.
Validation
Before marking implementation complete:
- Validate workflow YAML syntax.
- Run
gh workflow listor equivalent sanity checks. - Verify build workflow still detects React updates.
- Verify deploy workflow no longer fails during runner checkout for fresh submodule SHAs.