Skip to content

[#47] Add support for Dockerfiles + publishing#418

Merged
AlexSkrypnyk merged 2 commits intomainfrom
feature/47-docker-support
Feb 18, 2026
Merged

[#47] Add support for Dockerfiles + publishing#418
AlexSkrypnyk merged 2 commits intomainfrom
feature/47-docker-support

Conversation

@StevenWalker98
Copy link
Collaborator

@StevenWalker98 StevenWalker98 commented Feb 18, 2026

Closes #47

Changes

  • Added template Dockerfile (minimal alpine + bash + entrypoint) and entrypoint.sh
  • Added test-docker.yml workflow — builds image + hadolint lint
  • Added release-docker.yml workflow — multi-arch (linux/x86_64, linux/arm64) push to Docker Hub on tag
  • Added Use Docker prompt to init.sh (defaults to No)
  • When Docker is selected, prompts for Docker image name (defaults to namespace/project)
  • Added remove_docker() function + #;< DOCKER / #;> DOCKER token blocks
  • Added Docker section to CLAUDE.md
  • Added docker test case to InitTest.php with full snapshot fixture
  • Updated existing test fixtures via snapshot auto-update
  • All 14 init tests passing
  • Added Buildx to cspell dictionary

Docker Hub Secrets

The release workflow expects:

  • DOCKER_USER — Docker Hub username
  • DOCKER_PASS — Docker Hub access token

Based on the pattern from docker-wait-for-dependencies.

Overview

This PR closes issue #47 by adding optional Docker support and publishing workflows to the scaffold. It introduces a template Dockerfile and entrypoint, CI workflows to test and publish images, interactive init prompts to opt-in to Docker, cleanup hooks, documentation, and test fixtures.

Key Changes

Docker files

  • Dockerfile: Minimal Alpine-based image, installs bash, sets OCI labels, uses entrypoint.sh.
  • entrypoint.sh: Bash script with strict error handling (set -euo pipefail) that logs startup and forwards execution via exec "$@".

GitHub Actions workflows

  • .github/workflows/test-docker.yml: Lints Dockerfile with Hadolint (honors CI_LINT_IGNORE_FAILURE), sets up Buildx, builds (load=true) with cache, runs the image, and optionally opens a tmate terminal. Triggers: pushes to main, PRs to main/feature/**, and workflow_dispatch.
  • .github/workflows/release-docker.yml: Triggers on tag pushes; sets up QEMU and Buildx, logs into Docker Hub (DOCKER_USER/DOCKER_PASS), derives metadata with docker/metadata-action, and builds/pushes multi-arch images (linux/x86_64, linux/arm64) via docker/build-push-action.

Initialization and removal

  • init.sh: Adds interactive prompt Use Docker (default: No) and docker_image_name (default: namespace/project). When enabled, replaces placeholders; when disabled, calls remove_docker().
  • remove_docker(): Removes Docker artifacts (Dockerfile, entrypoint.sh, test/release workflows) and strips token-delimited Docker blocks (#;< DOCKER / #;> DOCKER).

Documentation

  • .scaffold/docs/content/docker/README.mdx: New comprehensive Docker documentation (Dockerfile, entrypoint, Hadolint, build/run examples, CI/CD workflows, required secrets).
  • CLAUDE.md: Docker section added (appears in multiple insertion points in this change set).
  • docs/cspell.json and .scaffold/docs/cspell.json: Added "Buildx" to cspell dictionaries.

Test fixtures and tests

  • Added docker fixture under .scaffold/tests/phpunit/fixtures/init/docker (Dockerfile, entrypoint.sh, workflows, .editorconfig, .gitattributes, .gitignore, CLAUDE.md, README.md).
  • InitTest.php: Added 'docker' data provider entry and new defaultAnswers keys use_docker and docker_image_name.
  • Snapshot fixtures auto-updated; all 14 init tests pass.

Minor updates

  • .github/workflows/scaffold-test.yml: Excludes entrypoint.sh from kcov exclude-pattern.
  • Fixture-level editorconfig/gitattributes/.gitignore adjustments included.

Secrets required for release workflow

  • DOCKER_USER — Docker Hub username
  • DOCKER_PASS — Docker Hub access token

Testing

  • New test-docker CI workflow for lint/build/run.
  • Release workflow patterned after drevops/docker-wait-for-dependencies/release.yml for multi-arch publishing.

Possibly related to: issue #47

@coderabbitai
Copy link

coderabbitai bot commented Feb 18, 2026

No actionable comments were generated in the recent review. 🎉


📝 Walkthrough

Walkthrough

Adds optional Docker scaffold: Dockerfile and entrypoint, init prompts and removal logic, test and release GitHub Actions workflows (multi‑arch build/push), fixture and test updates, documentation and cspell entries for "Buildx", and minor CI coverage exclude tweak.

Changes

Cohort / File(s) Summary
Repository workflows
/.github/workflows/release-docker.yml, /.github/workflows/test-docker.yml
Add "Release Docker" (on tag) and "Test Docker" (push/PR/dispatch) workflows. Release sets up QEMU/Buildx, extracts metadata, logs into Docker Hub, and builds/pushes multi‑arch images. Test lints the Dockerfile, sets up Buildx, builds/loads the image, runs it, and optionally opens a tmate session.
Fixture workflows
.scaffold/tests/phpunit/fixtures/init/docker/.github/workflows/*
Adds matching test/release workflow fixtures for scaffold tests (multi‑arch release and test pipelines).
Dockerfiles & entrypoints
Dockerfile, entrypoint.sh, .scaffold/.../docker/Dockerfile, .scaffold/.../docker/entrypoint.sh
Add Alpine-based Dockerfiles with OCI labels and bash entrypoint scripts using strict options and exec "$@" to run passed commands.
Scaffold init & templates
init.sh, .scaffold/tests/phpunit/fixtures/init/docker/*
Add interactive prompt use_docker and docker_image_name, replacement/removal logic (remove_docker()), and Docker artifact fixtures (Dockerfile, entrypoint, workflows, READMEs).
Documentation
CLAUDE.md, .scaffold/docs/content/docker/README.mdx, .scaffold/tests/phpunit/fixtures/init/docker/CLAUDE.md, .scaffold/tests/phpunit/fixtures/init/docker/README.md
Add Docker docs covering build/run, Hadolint linting, CI/CD workflow examples, and required Docker Hub secrets (note: some content duplicated across files).
Tests & spellcheck
docs/cspell.json, .scaffold/docs/cspell.json, .scaffold/tests/phpunit/fixtures/init/_baseline/docs/cspell.json, .scaffold/tests/phpunit/src/InitTest.php
Add "Buildx" to cspell dictionaries and extend InitTest data provider with a docker scenario and docker_image_name default.
Repository config (fixtures)
.scaffold/tests/phpunit/fixtures/init/docker/.gitattributes, .scaffold/tests/phpunit/fixtures/init/docker/.editorconfig, .scaffold/tests/phpunit/fixtures/init/docker/.gitignore
Adjust fixture editorconfig/gitattributes/gitignore entries to match Docker scaffold layout and packaging exclusions.
CI coverage tweak
/.github/workflows/scaffold-test.yml
Add entrypoint.sh to kcov exclude-patterns for coverage instrumentation.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Tag as "Git Tag (push)"
    participant GH as "GitHub Actions Runner"
    participant QEMU as "QEMU setup"
    participant Buildx as "Docker Buildx"
    participant Meta as "docker/metadata-action"
    participant Registry as "Docker Hub"

    Tag->>GH: Trigger "Release Docker" workflow
    GH->>GH: checkout repo
    GH->>QEMU: setup QEMU emulation
    GH->>Buildx: setup Buildx builder
    GH->>Meta: compute image tags & labels
    GH->>Buildx: build multi-arch images (linux/amd64, linux/arm64) with tags/labels
    Buildx->>Registry: push images
    Registry-->>GH: push status
    GH-->>Tag: workflow completed
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

  • Fixed more init processing. #300 — Overlaps init processing and fixture changes (init.sh, config files); likely related to Docker init/remove logic.
  • Moved Scaffold's own functional tests to PHP. #296 — Modifies scaffold CI workflow behavior and exclude patterns; related due to kcov exclude update for entrypoint.sh.
  • Linked issue #47 — Requests adding Dockerfile and publishing support; directly aligns with this PR’s objectives.

Poem

🐰
I hopped into code with a bashy grin,
Buildx whirs and multi‑arch begins,
"Image name?" I ask with a twitch of ear,
I push the tag and nibble logs near,
A tiny hop — container cheer!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title '[#47] Add support for Dockerfiles + publishing' clearly and specifically summarizes the main change—adding Docker support with publication workflows—matching the primary objectives.
Linked Issues check ✅ Passed All coding requirements from issue #47 are met: Dockerfile and entrypoint.sh templates added, test-docker.yml and release-docker.yml workflows implemented with multi-arch support, Docker opt-in prompt added to init.sh, remove_docker() function implemented, and Docker documentation provided.
Out of Scope Changes check ✅ Passed All changes are scoped to Docker support objectives: template files, workflows, initialization logic, test fixtures, documentation, and dictionary updates. No unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/47-docker-support

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

This comment has been minimized.

@codecov
Copy link

codecov bot commented Feb 18, 2026

Codecov Report

❌ Patch coverage is 0% with 16 lines in your changes missing coverage. Please review.
✅ Project coverage is 20.49%. Comparing base (38ab154) to head (470821b).
⚠️ Report is 2 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
init.sh 0.00% 13 Missing ⚠️
entrypoint.sh 0.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #418      +/-   ##
==========================================
- Coverage   21.42%   20.49%   -0.94%     
==========================================
  Files           5        6       +1     
  Lines         350      366      +16     
==========================================
  Hits           75       75              
- Misses        275      291      +16     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@StevenWalker98 StevenWalker98 force-pushed the feature/47-docker-support branch from 063eeab to bcd4fe6 Compare February 18, 2026 21:15
@github-actions

This comment has been minimized.

@StevenWalker98 StevenWalker98 force-pushed the feature/47-docker-support branch from bcd4fe6 to cde2fcc Compare February 18, 2026 21:16
@github-actions
Copy link

github-actions bot commented Feb 18, 2026

@github-actions

This comment has been minimized.

@github-actions github-actions bot temporarily deployed to pull request February 18, 2026 21:18 Inactive
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
.github/workflows/release-docker.yml (2)

44-44: Prefer linux/amd64 over linux/amd64's alias linux/x86_64 for platform consistency.

Docker buildx and the OCI spec use linux/amd64 as the canonical platform string. While linux/x86_64 is recognized, linux/amd64 is the standard form used in all Docker documentation and avoids potential edge-case rejection by some registries or manifest inspection tools.

♻️ Proposed fix
-          platforms: linux/x86_64,linux/arm64
+          platforms: linux/amd64,linux/arm64
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/release-docker.yml at line 44, Replace the non-canonical
platform alias in the GitHub Actions workflow by changing the platforms string
used in the release-docker job: update the value "platforms:
linux/x86_64,linux/arm64" to use the canonical "linux/amd64" form (i.e.,
"platforms: linux/amd64,linux/arm64") so buildx and registries see the standard
OCI platform name.

37-44: Consider adding a build cache to speed up release builds.

Unlike test-docker.yml, this workflow has no cache-from/cache-to configuration, so every tag push rebuilds from scratch. Adding GitHub Actions cache (consistent with the test workflow) would cut build times significantly.

♻️ Proposed fix
       - name: Build and push Docker image
         uses: docker/build-push-action@v6
         with:
           context: .
           push: true
           tags: ${{ steps.meta.outputs.tags }}
           labels: ${{ steps.meta.outputs.labels }}
           platforms: linux/amd64,linux/arm64
+          cache-from: type=gha
+          cache-to: type=gha,mode=max
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/release-docker.yml around lines 37 - 44, The Docker build
step ("Build and push Docker image" using docker/build-push-action@v6) has no
build cache configured so every release rebuilds from scratch; add BuildKit
cache settings by adding cache-from and cache-to entries under the step's with:
block (e.g., cache-from: type=gha,scope or key; cache-to: type=gha,mode=max or
inline) so the workflow reuses the GitHub Actions cache between runs; ensure you
reference the same cache key/descriptor (or include ${{ steps.meta.outputs.tags
}} or ${{ github.ref }} in the key) so successive builds can pull from and push
to the cache.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.scaffold/docs/content/docker/README.mdx:
- Line 72: Replace the non-canonical platform string "linux/x86_64" with the
OCI-canonical "linux/amd64" wherever it appears (e.g., in the multi-arch image
list text and the CI workflow platform list). Search for the exact token
"linux/x86_64" and update it to "linux/amd64" in both occurrences to ensure
consistency with the OCI/Go GOARCH convention and with the existing
"linux/arm64" entry.

In
@.scaffold/tests/phpunit/fixtures/init/docker/.github/workflows/test-docker.yml:
- Around line 53-56: The "Setup tmate session" step's if-condition uses
github.event.inputs.enable_terminal which is a string ("true"/"false") and
therefore always truthy; update the condition to use the inputs context so the
boolean is respected (e.g., replace github.event.inputs.enable_terminal with
inputs.enable_terminal in the if expression) and keep the existing cancelled()
check (so the final if remains something like: !cancelled() &&
inputs.enable_terminal) to ensure the tmate step only runs when the checkbox is
actually checked.

In `@init.sh`:
- Around line 593-597: The current global replace_string_content call is
overwriting the Dockerfile's org.opencontainers.image.source by substituting the
image name; update the flow so the GitHub source URL is set from a dedicated
placeholder (e.g., __GITHUB_SOURCE_URL__) rather than derived from
docker_image_name: add code in process_internal (or just before the Docker block
in main) to replace that placeholder with the full
"https://github.com/${namespace}/${project}" value, and keep the existing
replace_string_content "yournamespace/yourproject" "${docker_image_name}" only
for the image name; this ensures replace_string_content, replace_string_content,
process_internal, docker_image_name and remove_docker usages no longer collide
and the org.opencontainers.image.source label remains the correct GitHub URL.

---

Nitpick comments:
In @.github/workflows/release-docker.yml:
- Line 44: Replace the non-canonical platform alias in the GitHub Actions
workflow by changing the platforms string used in the release-docker job: update
the value "platforms: linux/x86_64,linux/arm64" to use the canonical
"linux/amd64" form (i.e., "platforms: linux/amd64,linux/arm64") so buildx and
registries see the standard OCI platform name.
- Around line 37-44: The Docker build step ("Build and push Docker image" using
docker/build-push-action@v6) has no build cache configured so every release
rebuilds from scratch; add BuildKit cache settings by adding cache-from and
cache-to entries under the step's with: block (e.g., cache-from: type=gha,scope
or key; cache-to: type=gha,mode=max or inline) so the workflow reuses the GitHub
Actions cache between runs; ensure you reference the same cache key/descriptor
(or include ${{ steps.meta.outputs.tags }} or ${{ github.ref }} in the key) so
successive builds can pull from and push to the cache.


1. Sets up QEMU and Docker Buildx for multi-architecture builds
2. Authenticates with Docker Hub
3. Builds and pushes multi-arch images (`linux/x86_64`, `linux/arm64`)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, check if the file exists and examine line 72
cat -n ".scaffold/docs/content/docker/README.mdx" | sed -n '68,76p'

Repository: AlexSkrypnyk/scaffold

Length of output: 425


🏁 Script executed:

# Run the verification script from the review comment
rg -n "linux/x86_64" --type yaml
rg -n "linux/x86_64" --glob "*.mdx" --glob "*.md"

Repository: AlexSkrypnyk/scaffold

Length of output: 47


🏁 Script executed:

# Also check what Docker documentation says about platform strings
# Let's search the codebase for any other platform strings being used
rg -n "linux/amd64|linux/arm64|linux/x86_64|linux/arm32" --type yaml --type json

Repository: AlexSkrypnyk/scaffold

Length of output: 47


🏁 Script executed:

# Find workflow files
fd -e yml -e yaml | grep -i workflow || fd -e yml -e yaml

Repository: AlexSkrypnyk/scaffold

Length of output: 86


🏁 Script executed:

# Check if release-docker.yml or similar workflow files exist
find . -name "*docker*.yml" -o -name "*release*.yml" 2>/dev/null | head -20

Repository: AlexSkrypnyk/scaffold

Length of output: 1383


🌐 Web query:

Docker OCI platform strings canonical linux/amd64 linux/x86_64

💡 Result:

In OCI/Docker, the canonical platform syntax is:

  • os/arch[/variant] (often called a “platform specifier”), e.g. linux/amd64 (pkg.go.dev)

For the arch portion, OCI specifies you should use Go’s GOARCH values (and os should use Go’s GOOS values). (oci-playground.github.io)

So for x86-64 Linux:

  • Canonical: linux/amd64
  • Not canonical (because x86_64 is not a Go GOARCH value): linux/x86_64 (oci-playground.github.io)

Some tooling may accept x86_64 as an alias and normalize it to amd64, but for OCI manifests/indexes and for best interoperability, use amd64 (optionally adding /variant only when applicable, e.g. linux/arm64/v8). (oci-playground.github.io)

Citations:


🏁 Script executed:

# Examine the release-docker.yml workflow to see what platform strings it uses
grep -n "linux/" "./.github/workflows/release-docker.yml"

Repository: AlexSkrypnyk/scaffold

Length of output: 113


Use canonical Docker platform string linux/amd64 instead of linux/x86_64

Per OCI specification, the canonical platform string for x86-64 is linux/amd64 (based on Go's GOARCH values), not linux/x86_64. While some tooling accepts linux/x86_64 as an alias, it is non-canonical and inconsistent with linux/arm64.

This non-canonical string appears in two places:

  • .scaffold/docs/content/docker/README.mdx line 72
  • ./.github/workflows/release-docker.yml line 44

Both should use the canonical linux/amd64 for consistency with OCI standards and Docker documentation.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.scaffold/docs/content/docker/README.mdx at line 72, Replace the
non-canonical platform string "linux/x86_64" with the OCI-canonical
"linux/amd64" wherever it appears (e.g., in the multi-arch image list text and
the CI workflow platform list). Search for the exact token "linux/x86_64" and
update it to "linux/amd64" in both occurrences to ensure consistency with the
OCI/Go GOARCH convention and with the existing "linux/arm64" entry.

@StevenWalker98 StevenWalker98 force-pushed the feature/47-docker-support branch from cde2fcc to 63a79be Compare February 18, 2026 21:49
@github-actions

This comment has been minimized.

@github-actions github-actions bot temporarily deployed to pull request February 18, 2026 21:51 Inactive
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
.scaffold/tests/phpunit/src/InitTest.php (1)

114-126: Consider adding a test case for a custom docker_image_name.

The current docker dataset only exercises TUI_DEFAULT (accept the pre-filled namespace/project value) for docker_image_name. There is no case that provides a literal string (e.g., 'myorg/custom-image'), so the text-input branch of that prompt and any substitution logic in init.sh are not independently validated. Given the snapshot-based approach, a second case would be a low-cost way to lock in that behaviour.

🔍 Suggested additional dataset
    yield 'docker custom image name' => [
        [
          'use_php' => self::$tuiNo,
          'use_php_command' => self::TUI_SKIP,
          'php_command_name' => self::TUI_SKIP,
          'use_php_command_build' => self::TUI_SKIP,
          'use_php_script' => self::TUI_SKIP,
          'use_nodejs' => self::$tuiNo,
          'use_shell' => self::$tuiNo,
          'use_docker' => self::$tuiYes,
+         'docker_image_name' => 'myorg/custom-image',
        ],
    ];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.scaffold/tests/phpunit/src/InitTest.php around lines 114 - 126, Add a test
dataset exercising a literal docker image name because the existing "docker"
case only uses TUI_DEFAULT; add a new yield entry (e.g., key "docker custom
image name") in the same dataset provider inside InitTest.php that mirrors the
existing docker case (keeping use_docker => self::$tuiYes and the same
TUI_SKIP/use flags) but sets 'docker_image_name' to a concrete string like
'myorg/custom-image' so the text-input branch and any substitution logic for
docker_image_name are exercised.
.github/workflows/release-docker.yml (1)

37-44: Consider adding build cache to the release workflow.

The test workflow configures cache-from: type=gha / cache-to: type=gha,mode=max, but the release workflow omits cache configuration entirely. For multi-arch builds this results in a cold-start on every release tag, lengthening release times. Adding the same GHA cache configuration would reuse layers warmed by CI runs.

♻️ Proposed addition
       - name: Build and push Docker image
         uses: docker/build-push-action@v6
         with:
           context: .
           push: true
           tags: ${{ steps.meta.outputs.tags }}
           labels: ${{ steps.meta.outputs.labels }}
           platforms: linux/x86_64,linux/arm64
+          cache-from: type=gha
+          cache-to: type=gha,mode=max
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/release-docker.yml around lines 37 - 44, The release
workflow's Docker step ("Build and push Docker image" using
docker/build-push-action@v6) lacks cache configuration causing cold multi-arch
builds; add the same GitHub Actions layer cache inputs used in CI: set
with.cache-from to include "type=gha" and with.cache-to to "type=gha,mode=max"
(and optionally with.cache-control or targets if used in CI) so the action can
reuse warmed layers across runs and speed up multi-arch builds.
init.sh (1)

534-535: Optional: show shell_command_name in the summary for consistency with docker_image_name.

This PR adds docker_image_name to the summary, but shell_command_name (set at line 504) is still silently omitted. A user who customises both would see the Docker image name but not the renamed shell script in the confirmation screen.

♻️ Suggested addition to the summary block
 echo "Use Shell                        : ${use_shell}"
+[ "${use_shell}" = "y" ] && echo "  Shell command name             : ${shell_command_name}"
 echo "Use Docker                       : ${use_docker}"
 [ "${use_docker}" = "y" ] && echo "  Docker image name              : ${docker_image_name}"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@init.sh` around lines 534 - 535, The summary omits the user-provided
shell_command_name while showing docker_image_name; add a matching summary line
for shell_command_name so users see both customizations. Locate the summary
block that prints use_docker and docker_image_name and add an echo for
shell_command_name (e.g., print "  Shell command name : ${shell_command_name}")
and conditionally display it only when shell_command_name is non-empty (or when
its relevant flag is set), similar to how docker_image_name is printed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In @.github/workflows/release-docker.yml:
- Line 44: Replace the non-canonical platform identifier in the GitHub Actions
docker build matrix: update the platforms entry that currently lists
"linux/x86_64,linux/arm64" to use "linux/amd64" instead of "linux/x86_64" (i.e.,
"platforms: linux/amd64,linux/arm64") so the platforms key uses the canonical
amd64 name.

In @.scaffold/docs/content/docker/README.mdx:
- Line 72: The platform string "linux/x86_64" in the Docker README is incorrect;
replace every occurrence of "linux/x86_64" with the OCI-canonical "linux/amd64"
(e.g., update the list item that currently reads "Builds and pushes multi-arch
images (`linux/x86_64`, `linux/arm64`)") so the documentation uses the correct
platform identifier.

In `@init.sh`:
- Around line 593-597: The replacement call replace_string_content
"yournamespace/yourproject" ${docker_image_name} in init.sh may still touch
non-Docker files; run a recursive search for the literal
"yournamespace/yourproject" (excluding .git, vendor, node_modules, etc.) and
confirm only Dockerfile/entrypoint/Docker workflow files contain it; if any
other files contain it, either (A) change those files to use a distinct
placeholder for the GitHub source URL used in Dockerfile, or (B) restrict
replace_string_content to only operate on Docker-related files (referencing the
init.sh call and the docker_image_name variable) so only intended files are
overwritten; update tests or add the verification script shown in the review to
prevent regressions.

---

Nitpick comments:
In @.github/workflows/release-docker.yml:
- Around line 37-44: The release workflow's Docker step ("Build and push Docker
image" using docker/build-push-action@v6) lacks cache configuration causing cold
multi-arch builds; add the same GitHub Actions layer cache inputs used in CI:
set with.cache-from to include "type=gha" and with.cache-to to
"type=gha,mode=max" (and optionally with.cache-control or targets if used in CI)
so the action can reuse warmed layers across runs and speed up multi-arch
builds.

In @.scaffold/tests/phpunit/src/InitTest.php:
- Around line 114-126: Add a test dataset exercising a literal docker image name
because the existing "docker" case only uses TUI_DEFAULT; add a new yield entry
(e.g., key "docker custom image name") in the same dataset provider inside
InitTest.php that mirrors the existing docker case (keeping use_docker =>
self::$tuiYes and the same TUI_SKIP/use flags) but sets 'docker_image_name' to a
concrete string like 'myorg/custom-image' so the text-input branch and any
substitution logic for docker_image_name are exercised.

In `@init.sh`:
- Around line 534-535: The summary omits the user-provided shell_command_name
while showing docker_image_name; add a matching summary line for
shell_command_name so users see both customizations. Locate the summary block
that prints use_docker and docker_image_name and add an echo for
shell_command_name (e.g., print "  Shell command name : ${shell_command_name}")
and conditionally display it only when shell_command_name is non-empty (or when
its relevant flag is set), similar to how docker_image_name is printed.

- Added template Dockerfile and entrypoint.sh
- Added test-docker.yml workflow (build + hadolint lint)
- Added release-docker.yml workflow (multi-arch push to Docker Hub)
- Added 'Use Docker' prompt to init.sh (defaults to No)
- Added Docker image name prompt (defaults to namespace/project)
- Added remove_docker() function for cleanup when Docker not selected
- Added DOCKER token blocks to CLAUDE.md
- Added 'docker' test case to InitTest.php
- Updated test fixtures via snapshot auto-update
- All 14 init tests passing
@StevenWalker98 StevenWalker98 force-pushed the feature/47-docker-support branch from 63a79be to e7dba77 Compare February 18, 2026 22:16
@github-actions

This comment has been minimized.

@github-actions github-actions bot temporarily deployed to pull request February 18, 2026 22:18 Inactive
- Updated exclude pattern to catch entrypoint.sh in root and subdirectories
- Addresses feedback from @AlexSkrypnyk in PR review
@github-actions
Copy link

Code Coverage Report:
  2026-02-18 22:24:07

 Summary:
  Classes: 100.00% (2/2)
  Methods: 100.00% (5/5)
  Lines:   100.00% (49/49)

YourNamespace\App\Command\JokeCommand
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% ( 26/ 26)
YourNamespace\App\Command\SayHelloCommand
  Methods: 100.00% ( 2/ 2)   Lines: 100.00% (  6/  6)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
.github/workflows/release-docker.yml (1)

3-6: Broad tag glob '*' triggers release on every tag — intentional?

tags: - '*' will fire the release workflow on any tag push (e.g. v1.0.0, beta, test-tag), immediately pushing to Docker Hub. Consider tightening the pattern (e.g. 'v[0-9]*') to avoid accidental publishes from non-version tags.

♻️ Optional tighter tag filter
 on:
   push:
     tags:
-      - '*'
+      - 'v[0-9]*'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/release-docker.yml around lines 3 - 6, The workflow
trigger currently uses a broad tag glob (on -> push -> tags: '*') which fires on
every tag; narrow the pattern to only semantic/version tags by replacing the
glob with a stricter pattern (for example 'v[0-9]*' or another regex matching
your release tag format) in the on.push.tags entry of the release-docker.yml
workflow so Docker publishes only for intended version tags.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.scaffold/tests/phpunit/fixtures/init/docker/Dockerfile:
- Around line 1-11: The Dockerfile currently leaves the container running as
root (no USER), so add steps to create a dedicated non-root user and switch to
it: create a group and user (e.g., addgroup/adduser or use adduser -D with
addgroup), chown the copied artifact (/usr/local/bin/entrypoint.sh) to that user
and set appropriate permissions, and then add a USER instruction before
ENTRYPOINT to switch to that non-root user; update the Dockerfile lines around
the COPY of entrypoint.sh and the ENTRYPOINT instruction accordingly so
ENTRYPOINT still points to /usr/local/bin/entrypoint.sh but runs as the new
non-root user.

In `@init.sh`:
- Around line 593-597: The current unconditional call to replace_string_content
"yournamespace/yourproject" "${docker_image_name}" corrupts non-Docker scaffold
files; update init.sh to (a) stop doing a global replace at that location and
instead only replace docker image references in Docker-specific files (e.g.,
Dockerfile, workflows) or call replace_string_content with an explicit file
list/grep-limited target, (b) introduce a separate placeholder (e.g.,
yourgithubnamespace/yourgithubproject) for GitHub source/repo references used in
Dockerfile labels and other scaffold files, and (c) ensure process_internal
still runs to restore scaffold-specific names; reference the existing symbols
use_docker, docker_image_name, replace_string_content, process_internal, and
remove_docker when making these changes.

---

Duplicate comments:
In
@.scaffold/tests/phpunit/fixtures/init/docker/.github/workflows/test-docker.yml:
- Around line 53-56: The "Setup tmate session" job step uses an if condition
that treats github.event.inputs.enable_terminal as always truthy; update the
condition on that step to perform an explicit comparison (e.g., compare to the
expected string/boolean value) or remove the redundant check if another guard
already ensures enable_terminal is meaningful; specifically, locate the step
named "Setup tmate session" and change the if expression that currently
references github.event.inputs.enable_terminal so it does an explicit equality
check (or drop the check) to avoid the always-truthy behavior.

---

Nitpick comments:
In @.github/workflows/release-docker.yml:
- Around line 3-6: The workflow trigger currently uses a broad tag glob (on ->
push -> tags: '*') which fires on every tag; narrow the pattern to only
semantic/version tags by replacing the glob with a stricter pattern (for example
'v[0-9]*' or another regex matching your release tag format) in the on.push.tags
entry of the release-docker.yml workflow so Docker publishes only for intended
version tags.

Comment on lines +1 to +11
# hadolint global ignore=DL3018
FROM alpine:3

LABEL org.opencontainers.image.authors="Luke Skywalker" \
org.opencontainers.image.source="https://github.com/yodashut/force-crystal"

RUN apk add --no-cache bash

COPY entrypoint.sh /usr/local/bin/entrypoint.sh

ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Container runs as root — add a non-root USER directive.

Trivy rule DS-0002: the Dockerfile has no USER instruction, so every container spawned from this image runs as root. As a scaffold template this sets the pattern for all downstream projects.

🛡️ Proposed fix — add a dedicated non-root user
 RUN apk add --no-cache bash
+
+RUN addgroup -S app && adduser -S app -G app
+USER app

 COPY entrypoint.sh /usr/local/bin/entrypoint.sh
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# hadolint global ignore=DL3018
FROM alpine:3
LABEL org.opencontainers.image.authors="Luke Skywalker" \
org.opencontainers.image.source="https://github.com/yodashut/force-crystal"
RUN apk add --no-cache bash
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
# hadolint global ignore=DL3018
FROM alpine:3
LABEL org.opencontainers.image.authors="Luke Skywalker" \
org.opencontainers.image.source="https://github.com/yodashut/force-crystal"
RUN apk add --no-cache bash
RUN addgroup -S app && adduser -S app -G app
USER app
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
🧰 Tools
🪛 Trivy (0.69.1)

[error] 1-1: Image user should not be 'root'

Specify at least 1 USER command in Dockerfile with non-root user as argument

Rule: DS-0002

Learn more

(IaC/Dockerfile)


[error] 1-1: Image user should not be 'root'

Specify at least 1 USER command in Dockerfile with non-root user as argument

Rule: DS-0002

Learn more

(IaC/Dockerfile)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.scaffold/tests/phpunit/fixtures/init/docker/Dockerfile around lines 1 - 11,
The Dockerfile currently leaves the container running as root (no USER), so add
steps to create a dedicated non-root user and switch to it: create a group and
user (e.g., addgroup/adduser or use adduser -D with addgroup), chown the copied
artifact (/usr/local/bin/entrypoint.sh) to that user and set appropriate
permissions, and then add a USER instruction before ENTRYPOINT to switch to that
non-root user; update the Dockerfile lines around the COPY of entrypoint.sh and
the ENTRYPOINT instruction accordingly so ENTRYPOINT still points to
/usr/local/bin/entrypoint.sh but runs as the new non-root user.

Comment on lines +593 to +597
if [ "${use_docker}" = "y" ]; then
replace_string_content "yournamespace/yourproject" "${docker_image_name}"
else
remove_docker
fi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# 1. Check what placeholder(s) the Dockerfile uses for image name vs GitHub source URL
echo "=== Dockerfile contents (image-name and source label lines) ==="
grep -n "yournamespace\|yourproject\|opencontainers\|image.source\|docker_image\|FROM" Dockerfile 2>/dev/null || echo "Dockerfile not found"

# 2. Check if non-Docker scaffold files reference "yournamespace/yourproject" directly
# (excluding Dockerfile, entrypoint.sh, and the two docker workflows)
echo ""
echo "=== Non-Docker files with 'yournamespace/yourproject' ==="
grep -rn "yournamespace/yourproject" \
  --exclude="Dockerfile" \
  --exclude="entrypoint.sh" \
  --exclude-dir=".git" \
  --exclude-dir="node_modules" \
  --exclude-dir="vendor" \
  . 2>/dev/null | grep -v "test-docker\|release-docker\|init.sh" || echo "(none)"

Repository: AlexSkrypnyk/scaffold

Length of output: 3264


Critical: Global replace of "yournamespace/yourproject" corrupts multiple non-Docker scaffold files.

The code at line 594 performs a global replace_string_content "yournamespace/yourproject" "${docker_image_name}" before process_internal runs. This has two confirmed impacts:

  1. Dockerfile source label is overwritten: The org.opencontainers.image.source label in the Dockerfile (line 5) contains the literal string "https://github.com/yournamespace/yourproject". This will be replaced with the Docker image name, corrupting the GitHub source URL metadata.

  2. Multiple scaffold files are corrupted: Non-Docker scaffold files contain "yournamespace/yourproject" directly and will have this replaced with docker_image_name:

    • composer.json (package name, homepage, source URLs)
    • README.dist.md (GitHub badges and links)
    • package.json (package name, repository, bugs URLs)
    • docs/docusaurus.config.js (GitHub URLs)
    • docs/package.json and docs/package-lock.json (package names)

    Since process_internal only recreates "yournamespace/yourproject" from pre-existing "AlexSkrypnyk/scaffold" occurrences, these direct uses are never corrected.

Fix: Use distinct placeholders—e.g., yourgithubnamespace/yourgithubproject for the Dockerfile source label and other GitHub references, and apply the docker_image_name replacement only to files where it belongs (Dockerfile image layers, workflows).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@init.sh` around lines 593 - 597, The current unconditional call to
replace_string_content "yournamespace/yourproject" "${docker_image_name}"
corrupts non-Docker scaffold files; update init.sh to (a) stop doing a global
replace at that location and instead only replace docker image references in
Docker-specific files (e.g., Dockerfile, workflows) or call
replace_string_content with an explicit file list/grep-limited target, (b)
introduce a separate placeholder (e.g., yourgithubnamespace/yourgithubproject)
for GitHub source/repo references used in Dockerfile labels and other scaffold
files, and (c) ensure process_internal still runs to restore scaffold-specific
names; reference the existing symbols use_docker, docker_image_name,
replace_string_content, process_internal, and remove_docker when making these
changes.

@github-actions github-actions bot temporarily deployed to pull request February 18, 2026 22:25 Inactive
@AlexSkrypnyk AlexSkrypnyk merged commit d7fffca into main Feb 18, 2026
24 checks passed
@AlexSkrypnyk AlexSkrypnyk deleted the feature/47-docker-support branch February 18, 2026 22:34
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.

Add support for Dockerfiles + publishing

2 participants