mirror of
https://github.com/storytold/craft-common-actions.git
synced 2026-11-15 15:02:24 +00:00
feat(docker-build): support Docker Hub registry alongside DOCR and GHCR (#179)
This commit is contained in:
1 parent
3b3ea7ed62
commit
a5eda472ea
3 files changed
+70
-5
No files matched your search
@@ -20,7 +20,7 @@ on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
images:
|
||||
description: "Image repositories to push, one per line (registry.digitalocean.com/... and/or ghcr.io/...)"
|
||||
description: "Image repositories to push, one per line (registry.digitalocean.com/..., ghcr.io/... and/or docker.io/...)"
|
||||
type: string
|
||||
required: true
|
||||
platforms:
|
||||
@@ -91,10 +91,10 @@ on:
|
||||
description: "DigitalOcean token or DOCR robot with write access; used when an image lives in registry.digitalocean.com"
|
||||
required: false
|
||||
DOCKERHUB_USERNAME:
|
||||
description: "Docker Hub user for dhi.io base images; only read with dhi-login"
|
||||
description: "Docker Hub user for dhi.io base images and docker.io pushes; only read when configured"
|
||||
required: false
|
||||
DOCKERHUB_TOKEN:
|
||||
description: "Docker Hub token for dhi.io base images; only read with dhi-login"
|
||||
description: "Docker Hub token for dhi.io base images and docker.io pushes; only read when configured"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -161,6 +161,13 @@ jobs:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
if: ${{ contains(inputs.images, 'docker.io/') }}
|
||||
uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # v4.7.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Set up Buildx
|
||||
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
|
||||
|
||||
@@ -186,7 +193,7 @@ jobs:
|
||||
image="${image//[[:space:]]/}"
|
||||
[ -n "$image" ] || continue
|
||||
case "$image" in
|
||||
registry.digitalocean.com/* | ghcr.io/*) ;;
|
||||
registry.digitalocean.com/* | ghcr.io/* | docker.io/*) ;;
|
||||
*)
|
||||
echo "error: unsupported image repository: $image" >&2
|
||||
exit 1
|
||||
@@ -273,6 +280,13 @@ jobs:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
if: ${{ contains(inputs.images, 'docker.io/') }}
|
||||
uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # v4.7.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Set up Buildx
|
||||
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
|
||||
|
||||
|
||||
@@ -690,7 +690,8 @@ jobs:
|
||||
Builds one image per entry in `platforms`, pushes every platform by digest to each repository in
|
||||
`images`, then joins those digests into a single multi-arch manifest per repository. It logs in only
|
||||
where an image needs it: `registry.digitalocean.com` when a DOCR image is listed, `ghcr.io` through
|
||||
the workflow token, and `dhi.io` when `dhi-login: true` and the Docker Hub secrets are provided.
|
||||
the workflow token, `docker.io` when Docker Hub images are listed (using `DOCKERHUB_USERNAME` and
|
||||
`DOCKERHUB_TOKEN`), and `dhi.io` when `dhi-login: true` and the Docker Hub secrets are provided.
|
||||
|
||||
Both craft web images publish this way. `font-preview-service` fetches its font sources into the
|
||||
build context first, so it passes a `pre-build-command`; `artcraft-services` builds one platform on a
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
"""Verify the shared docker-build workflow handles Docker Hub alongside DOCR and GHCR."""
|
||||
|
||||
from pathlib import Path
|
||||
import unittest
|
||||
import yaml
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
WORKFLOW_PATH = ROOT / ".github/workflows/docker-build.yml"
|
||||
WORKFLOW = yaml.load(WORKFLOW_PATH.read_text(), Loader=yaml.BaseLoader)
|
||||
|
||||
|
||||
class DockerBuildWorkflowTests(unittest.TestCase):
|
||||
def test_workflow_interface(self):
|
||||
call = WORKFLOW["on"]["workflow_call"]
|
||||
self.assertIn("images", call["inputs"])
|
||||
self.assertIn("DOCKERHUB_USERNAME", call["secrets"])
|
||||
self.assertIn("DOCKERHUB_TOKEN", call["secrets"])
|
||||
|
||||
def test_dockerhub_login_in_build_job(self):
|
||||
steps = WORKFLOW["jobs"]["build"]["steps"]
|
||||
dh_step = next(
|
||||
(s for s in steps if s.get("name") == "Log in to Docker Hub"),
|
||||
None,
|
||||
)
|
||||
self.assertIsNotNone(dh_step, "Build job missing 'Log in to Docker Hub' step")
|
||||
self.assertIn("docker.io/", dh_step["if"])
|
||||
self.assertEqual(dh_step["with"]["username"], "${{ secrets.DOCKERHUB_USERNAME }}")
|
||||
self.assertEqual(dh_step["with"]["password"], "${{ secrets.DOCKERHUB_TOKEN }}")
|
||||
|
||||
def test_dockerhub_login_in_merge_job(self):
|
||||
steps = WORKFLOW["jobs"]["merge"]["steps"]
|
||||
dh_step = next(
|
||||
(s for s in steps if s.get("name") == "Log in to Docker Hub"),
|
||||
None,
|
||||
)
|
||||
self.assertIsNotNone(dh_step, "Merge job missing 'Log in to Docker Hub' step")
|
||||
self.assertIn("docker.io/", dh_step["if"])
|
||||
self.assertEqual(dh_step["with"]["username"], "${{ secrets.DOCKERHUB_USERNAME }}")
|
||||
self.assertEqual(dh_step["with"]["password"], "${{ secrets.DOCKERHUB_TOKEN }}")
|
||||
|
||||
def test_build_step_accepts_docker_io_repository(self):
|
||||
steps = WORKFLOW["jobs"]["build"]["steps"]
|
||||
build_step = next(s for s in steps if s.get("name") == "Build and push by digest")
|
||||
script = build_step["run"]
|
||||
self.assertIn("docker.io/*", script)
|
||||
self.assertIn("registry.digitalocean.com/* | ghcr.io/* | docker.io/*", script)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user