Publish container image on release; Coolify catalog submission kit - #145
Publish container image on release; Coolify catalog submission kit#145tracking202 wants to merge 3 commits into
Conversation
Groundwork for listing Prosper202 in Coolify's one-click service
catalog (coolify.io/services), which is generated from the
coollabsio/coolify repository:
- release.yml gains a docker-image job: on every vX.Y.Z tag it
publishes the Dockerfile's default app stage to
ghcr.io/tracking202/prosper202:{version,latest} for linux/amd64 and
linux/arm64, using the built-in GITHUB_TOKEN (no external registry
account). workflow_dispatch runs build without pushing. One manual
step remains after the first tagged release: flip the GHCR package
to public in its settings so anonymous docker pull works.
- build/coolify-service-template/ holds the ready-to-submit kit: the
catalog template (image-based mirror of docker-compose.coolify.yaml
with the required metadata header — one-click services pull a
published image, never build from git), a brand-colored placeholder
logo SVG, and a README with the submission checklist. Blocking
caveat documented there: Coolify's contribution guide requires the
service repo to have at least 1,000 GitHub stars (currently 22), so
the submission waits on either star growth or a maintainer
exception; the image publishing is valuable independently.
Template validated with docker compose config (5 services, 4 named
volumes); workflow and SVG parse clean. The multi-arch image build
itself runs first in CI (workflow_dispatch) — not buildable in this
sandbox because composer's downloads are blocked by egress policy.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SJt817AkfBdUYoXnvaN8vh
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 940ae004b1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| docker-image: | ||
| runs-on: ubuntu-latest |
There was a problem hiding this comment.
Gate image publication on release validation
The docker-image job has no dependency on release, so both jobs run independently. When a v* tag fails the version check or the release artifact build, this job can still push that commit under both its version tag and latest, making an invalid release available to the Coolify template even though no corresponding GitHub Release was published; make image publication depend on successful release validation.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Confirmed — without the dependency, a tag failing the tag-vs-version.php check could still ship an image and move latest with no corresponding Release. Fixed in c3a4c32: docker-image now needs: release.
Generated by Claude Code
| type=semver,pattern={{version}} | ||
| type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }} |
There was a problem hiding this comment.
Keep prerelease images from replacing latest
The repository accepts versions with suffixes such as 2.0.0-beta, but this raw tag rule enables latest for every v* tag. Publishing such a prerelease therefore replaces the production image consumed by the new Coolify template's :latest references; only emit latest for stable semantic versions.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Confirmed — version.php explicitly permits suffixed prereleases, and the catalog template pulls :latest. Fixed in c3a4c32: the latest tag is now additionally gated on !contains(github.ref_name, '-'), so v2.0.0-beta publishes only its version tag.
Generated by Claude Code
| environment: | ||
| - SERVICE_FQDN_PROSPER202_80 |
There was a problem hiding this comment.
Declare the generated service URL for the worker
Only SERVICE_FQDN_PROSPER202_80 is declared on the routed service, while the worker later consumes SERVICE_URL_PROSPER202 as P202_PUBLIC_ORIGIN. Coolify generates the FQDN and URL variants independently when declared—the existing docker-compose.coolify.yaml deliberately declares both—so webhook exports from this catalog deployment can fall back to a configured tracking domain or localhost instead of producing links for the assigned Coolify URL; declare SERVICE_URL_PROSPER202 alongside the FQDN.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Confirmed — this was a lesson already applied to docker-compose.coolify.yaml that didn't get carried into the template. Fixed in c3a4c32: SERVICE_URL_PROSPER202 is now declared on the routed service alongside the FQDN, and the worker consumes it as ${SERVICE_URL_PROSPER202:-}. Also applied the companion hardening from the same commit: ${SERVICE_PASSWORD_MYSQL:?} fails fast at all three sites (verified: docker compose config passes with the password set and errors loudly without it).
Generated by Claude Code
There was a problem hiding this comment.
Pull request overview
Prepares Prosper202 for image-based deployments and eventual inclusion in Coolify’s one-click service catalog by publishing a GHCR container image on releases and adding a ready-to-submit Coolify service template kit under build/.
Changes:
- Add a
docker-imagejob to the release workflow to build/push a multi-arch image to GHCR onv*tags (and build-only onworkflow_dispatch). - Add
build/coolify-service-template/containing a Coolify service template YAML, submission checklist README, and placeholder SVG logo. - Document the new Coolify submission kit directory in
build/README.md.
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
.github/workflows/release.yml |
Adds GHCR image publishing (multi-arch) on version tags and build-only on manual runs. |
build/README.md |
Documents the new Coolify submission kit directory and sync expectations. |
build/coolify-service-template/README.md |
Provides submission checklist and prerequisites for Coolify’s catalog PR. |
build/coolify-service-template/prosper202.yaml |
Defines the image-based Coolify one-click service template stack. |
build/coolify-service-template/svgs/prosper202.svg |
Adds a placeholder SVG logo for the template. |
Suppressed comments (3)
build/coolify-service-template/prosper202.yaml:54
- The MySQL service root password should fail fast if SERVICE_PASSWORD_MYSQL is missing; otherwise compose will pass an empty password and MySQL initialization/auth will not match the app config.
- MYSQL_ROOT_PASSWORD=${SERVICE_PASSWORD_MYSQL}
build/coolify-service-template/prosper202.yaml:100
- Same as the main service: guard SERVICE_PASSWORD_MYSQL so the worker container can’t start with an empty MYSQL_ROOT_PASSWORD substitution.
- MYSQL_ROOT_PASSWORD=${SERVICE_PASSWORD_MYSQL}
build/coolify-service-template/prosper202.yaml:107
- Using ${SERVICE_URL_PROSPER202} without a default causes docker compose to substitute an empty string (and emit warnings) when the variable isn’t set; match docker-compose.coolify.yaml’s pattern so local validation and non-Coolify runs are clean.
- P202_PUBLIC_ORIGIN=${SERVICE_URL_PROSPER202}
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Five verified findings from the bot reviews on #145: - docker-image now needs: release, so a tag that fails the tag-vs-version.php check or the artifact build can no longer publish an image (or move `latest`) with no corresponding GitHub Release. - `latest` is only emitted for stable versions: version.php permits suffixed prereleases (v2.0.0-beta), which must not replace the production image the catalog template pulls by `:latest`. - The catalog template now declares SERVICE_URL_PROSPER202 on the routed service (Coolify generates FQDN and URL variants independently), matching what docker-compose.coolify.yaml already does — without it the worker's P202_PUBLIC_ORIGIN would always be empty on catalog deployments. - ${SERVICE_PASSWORD_MYSQL:?} fails fast at all three sites instead of silently substituting an empty password, and the worker's ${SERVICE_URL_PROSPER202:-} matches the main stack's pattern so plain-compose validation stays clean. Verified: workflow YAML parses; the template passes docker compose config with the password set and errors loudly without it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SJt817AkfBdUYoXnvaN8vh
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c3a4c32b9d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| with: | ||
| images: ghcr.io/${{ github.repository }} | ||
| tags: | | ||
| type=semver,pattern={{version}} |
There was a problem hiding this comment.
Reject non-SemVer versions before generating image tags
When version.php contains a value accepted by its current regex but rejected by strict SemVer—such as 01.2.3 or 1.2.3-01—the tag check and GitHub Release publication succeed, but this type=semver rule cannot generate the versioned image tag. For a malformed stable version the raw rule can still publish only latest; for a malformed prerelease the push has no tag and fails. Validate strict SemVer before publishing the Release or generate the immutable tag from the already-validated version string.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Confirmed — version.php's regex admits values strict SemVer rejects (leading zeros, 1.2.3-01), and type=semver would silently drop the versioned tag for those. Fixed in cbdc9d8 by taking the second suggested route: the versioned image tag is now derived directly from the git tag (${GITHUB_REF_NAME#v}), which the release job this job depends on has already validated against version.php — so the versioned tag is always produced with no re-parse. Non-tag workflow_dispatch builds get a type=sha name so the unpushed build never has an empty tag list.
Generated by Claude Code
Verified review finding on #145: version.php's format regex permits values strict SemVer rejects (leading zeros such as 01.2.3, or a 1.2.3-01 prerelease identifier). metadata-action's type=semver rule silently generates no versioned tag for those, so a release could publish only `latest` (stable) or fail the push with an empty tag list (prerelease). The versioned tag now comes straight from the git tag with the v prefix stripped — the release job this job depends on has already validated the tag against version.php, so no re-parse is needed and the versioned tag is always produced. Non-tag workflow_dispatch runs get a type=sha name so the (unpushed) build never has an empty tag list. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SJt817AkfBdUYoXnvaN8vh
Prep work for listing Prosper202 in Coolify's one-click service catalog (https://coolify.io/services), which is generated from the
coollabsio/coolifyrepository. Everything here is valuable on its own before any catalog submission happens.What's included
Container image publishing (
.github/workflows/release.yml)docker-imagejob: everyvX.Y.Ztag publishes the Dockerfile's defaultappstage toghcr.io/tracking202/prosper202:{version,latest}forlinux/amd64+linux/arm64, using the built-inGITHUB_TOKEN— no external registry account.workflow_dispatchruns build without pushing, so the image build is verifiable outside the release flow.docker pullworks (packages are created private).Catalog submission kit (
build/coolify-service-template/)prosper202.yaml— the ready-to-submit service template with Coolify's required metadata header (documentation/slogan/category/tags/logo/port). It mirrorsdocker-compose.coolify.yamlbut pulls the published image instead of building from git, since one-click services never clone the repository. Validated withdocker compose config(5 services, 4 named volumes).svgs/prosper202.svg— brand-colored placeholder logo (swap for official vector art before submitting, if available).README.md— the submission checklist (forkcoollabsio/coolify, where each file goes, how to test via "Docker Compose Empty", the post-merge docs page), plus the blocking caveat: Coolify's contribution guide requires the service repo to have ≥1,000 GitHub stars (currently 22), so the actual submission waits on star growth or a maintainer exception.build/README.mddocuments the new directory and the sync expectation withdocker-compose.coolify.yaml.Verification
Workflow YAML, template YAML, and SVG all parse clean; the template validates under
docker compose config. The multi-arch image build itself will run first in CI (workflow_dispatchon the release workflow) — it can't be built in this sandbox because composer's downloads are blocked by the session's egress policy.🤖 Generated with Claude Code
https://claude.ai/code/session_01SJt817AkfBdUYoXnvaN8vh
Generated by Claude Code