Skip to content

Build and publish the container image on push to main - #1

Merged
theNEXlevel merged 2 commits into
mainfrom
ci/publish-container
Aug 8, 2026
Merged

theNEXlevel merged 2 commits into
mainfrom
ci/publish-container

Conversation

@theNEXlevel

Copy link
Copy Markdown
Contributor

Summary

Same setup as C4G/va-stats#4 and C4G/template#8: move the production image build off the shared Coolify host into GitHub Actions.

  • .github/workflows/publish.yaml (new) — on push to main / workflow_dispatch: builds the image, pushes ghcr.io/c4g/va-partners:latest and :<sha>, then triggers a Coolify deploy of va-partners-test.
  • docker-compose.yaml — references the published image, no build: key. That absence is what stops Coolify from compiling on the server.
  • docker-compose.build.yaml (new) — restores the build: key for local builds.
  • .github/workflows/ci.yaml — PR runs overlay the build file, so they still verify an image built from the branch.
  • Dockerfile — drops the NEXT_PUBLIC_NEXTAUTH_URL build arg.
  • README.md — deployment section replacing the stale "Deploy on Vercel" text.

Simpler than the other two repos

  • No migration image to fold in. docker-entrypoint.sh already runs prisma migrate deploy at container start, so this repo was never building a second image.
  • The build arg was dead. NEXT_PUBLIC_NEXTAUTH_URL is referenced nowhere in the application source — only in Dockerfile, docker-compose.yaml and example.env. No source file reads any NEXT_PUBLIC_* at all. It was baked into the image and differs per environment, which would have tied one build to one origin, so dropping it makes the image environment-agnostic at zero runtime risk.
  • Coolify auto-deploy was already off on both va-partners and va-partners-test, so no server-side change was needed (unlike va-stats, where it had to be switched off on the test app).

Environments

Environment Coolify app Image tag
va-partners-test.c4g.dev va-partners-test (vz3iktyxmpi9i4bvmzsn2gs3) latest, deployed automatically on push to main
va-partners.c4g.dev va-partners (o3e54e7xtuk12ghoxy07p6ot) IMAGE_TAG pinned to a commit SHA, deployed manually

COOLIFY_APP_UUID repository variable set to the test app. The deploy step skips itself if it or COOLIFY_TOKEN is missing.

Verified locally with Docker

Built and booted the full stack (docker-compose.yaml + docker-compose.ci.yaml + docker-compose.build.yaml):

  • Entrypoint retry loop handled the DB not yet being up (P1001 → retried), then all 13 migrations applied to the bundled MySQL and the app started.
  • GET /api/health → {"status":"ok",...}, container reported healthy.
  • No va-partners*.c4g.dev origin baked anywhere in the server output, and the Prisma CLI is present at /usr/local/bin/prisma for the entrypoint.

Note for anyone testing locally

The repo-root .env is auto-loaded by Docker Compose for ${VAR} substitution, and its DATABASE_URL points at the remote staging database. A plain docker compose up locally therefore runs prisma migrate deploy against staging rather than the bundled MySQL. Pass --env-file /dev/null to force the bundled DB. CI is unaffected (no .env there). Documented in the README.

Follow-up required after the first run

The new GHCR package is created private. The Coolify host pulls anonymously (no ~/.docker/config.json on the server), so ghcr.io/c4g/va-partners must be set to public — matching the existing ghcr.io/c4g/* packages — or the first deploy will fail to pull.

🤖 Generated with Claude Code

Justin McLellan and others added 2 commits August 7, 2026 23:46
Coolify compiles the application on the shared host on every deploy, which ties
up CPU and disk for the other applications on the box. Move the build to GitHub
Actions: publish.yaml builds the image, pushes it to GHCR, and then calls the
Coolify deploy API for va-partners-test.

docker-compose.yaml now references the published image and has no `build:` key —
that absence is what keeps the build off the server. The build key moves to
docker-compose.build.yaml, which CI overlays so PR runs still verify an image
built from the branch rather than the published :latest.

The NEXT_PUBLIC_NEXTAUTH_URL build arg is dropped. It was baked into the image
and differs per environment, which would have tied one published build to one
origin; it is also read nowhere in the application source, so removing it has no
runtime effect. Migrations already run from docker-entrypoint.sh, so unlike the
template there is no second image to fold in.

Production is promoted by pinning IMAGE_TAG to a tested commit SHA rather than
tracking :latest, so it runs the exact image verified on va-partners-test.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
CI builds the PR head; with squash merges the commit that lands on main is
never exercised before its image is deployed. Run the production compose plus
the ci MySQL overlay against the just-pushed tag with no build overlay, so the
entrypoint's migrations run against the published image and the step proves it
pulls and runs without anything being built.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@theNEXlevel
theNEXlevel merged commit 0dae91c into main Aug 8, 2026
1 check passed
@theNEXlevel
theNEXlevel deleted the ci/publish-container branch August 8, 2026 05:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant