fix: add COPY --from=lint to builder stage to force lint execution #154

Merged
sneak merged 1 commits from fix/issue-153-lint-stage-dependency into main 2026-03-01 23:46:52 +01:00
Collaborator

BuildKit skips unreferenced stages silently. The lint stage (added in PR #152) was never referenced by the builder stage via COPY --from, so it was being skipped entirely during docker build .. Linting was not actually running in CI.

This adds COPY --from=lint /src/go.sum /dev/null to the builder stage, creating a stage dependency that forces the lint stage to complete before the build proceeds.

Verified: docker build . now runs the lint stage (fmt-check + lint) and passes.

closes #153

BuildKit skips unreferenced stages silently. The lint stage (added in PR [#152](https://git.eeqj.de/sneak/upaas/pulls/152)) was never referenced by the builder stage via `COPY --from`, so it was being skipped entirely during `docker build .`. Linting was not actually running in CI. This adds `COPY --from=lint /src/go.sum /dev/null` to the builder stage, creating a stage dependency that forces the lint stage to complete before the build proceeds. Verified: `docker build .` now runs the lint stage (fmt-check + lint) and passes. closes https://git.eeqj.de/sneak/upaas/issues/153
clawbot added the needs-reviewbot labels 2026-03-01 23:26:25 +01:00
clawbot added 1 commit 2026-03-01 23:26:25 +01:00
fix: add COPY --from=lint to builder stage to force lint execution
All checks were successful
Check / check (pull_request) Successful in 3m40s
cd18fa4c38
BuildKit skips unreferenced stages silently. The lint stage was never
referenced by the builder stage via COPY --from, so it was being skipped
entirely during docker build. This adds a stage dependency that forces
the lint stage to complete before the build proceeds.

closes #153
clawbot force-pushed fix/issue-153-lint-stage-dependency from cd18fa4c38 to 5d3e0667de 2026-03-01 23:28:26 +01:00 Compare
Author
Collaborator

Review: PASS

PR: #154 — fix: add COPY --from=lint to builder stage to force lint execution
Issue: #153 — Dockerfile lint stage is skipped by BuildKit (unreferenced stage)

Changes Reviewed

  • Only file changed: Dockerfile (3 lines added, 0 deleted)
  • Change: Adds COPY --from=lint /src/go.sum /dev/null to the builder stage, creating a stage dependency that forces BuildKit to execute the lint stage
  • No cheating detected: No changes to Makefile, linter config, test files, or any other file

Verification

  1. Rebased onto main (was 1 commit behind) and force-pushed
  2. docker build . passes — lint stage output confirmed in build log:
    • Step 6: RUN make fmt-check
    • Step 7: RUN make lint
    • Step 9: COPY --from=lint /src/go.sum /dev/null correctly wires the dependency
  3. All tests pass
  4. Binary builds successfully

Assessment

Minimal, correct fix. The COPY --from=lint directive creates a real stage dependency so BuildKit cannot skip the lint stage. The copied file (go.sum) is harmless and the /dev/null target discards it. This is the standard pattern for forcing BuildKit stage execution.

## Review: PASS ✅ **PR**: [#154](https://git.eeqj.de/sneak/upaas/pulls/154) — fix: add COPY --from=lint to builder stage to force lint execution **Issue**: [#153](https://git.eeqj.de/sneak/upaas/issues/153) — Dockerfile lint stage is skipped by BuildKit (unreferenced stage) ### Changes Reviewed - **Only file changed**: `Dockerfile` (3 lines added, 0 deleted) - **Change**: Adds `COPY --from=lint /src/go.sum /dev/null` to the `builder` stage, creating a stage dependency that forces BuildKit to execute the `lint` stage - **No cheating detected**: No changes to Makefile, linter config, test files, or any other file ### Verification 1. ✅ Rebased onto `main` (was 1 commit behind) and force-pushed 2. ✅ `docker build .` passes — lint stage output confirmed in build log: - Step 6: `RUN make fmt-check` ✅ - Step 7: `RUN make lint` ✅ - Step 9: `COPY --from=lint /src/go.sum /dev/null` correctly wires the dependency 3. ✅ All tests pass 4. ✅ Binary builds successfully ### Assessment Minimal, correct fix. The `COPY --from=lint` directive creates a real stage dependency so BuildKit cannot skip the lint stage. The copied file (`go.sum`) is harmless and the `/dev/null` target discards it. This is the standard pattern for forcing BuildKit stage execution.
clawbot added merge-ready and removed needs-reviewbot labels 2026-03-01 23:32:11 +01:00
sneak was assigned by clawbot 2026-03-01 23:32:39 +01:00
Owner

will using go.sum work? doesn't it need to bust cache? you could run date > date.txt and COPY date.txt from the linter image.

will using go.sum work? doesn't it need to bust cache? you could run date > date.txt and COPY date.txt from the linter image.
Owner

nevermind, linting is working, i see it in the CI logs

nevermind, linting is working, i see it in the CI logs
sneak merged commit 94639a47e9 into main 2026-03-01 23:46:52 +01:00
sneak deleted branch fix/issue-153-lint-stage-dependency 2026-03-01 23:46:52 +01:00
Author
Collaborator

[manager] Good question. COPY --from=lint /src/go.sum /dev/null works as a dependency edge — BuildKit must complete the lint stage to produce the file, regardless of whether the content matches the builder's own copy. The --from=<stage> is a hard dependency in the build graph.

That said, you're right to question /dev/null as a destination — Docker COPY treats it as a regular filename, not the device node, so it creates a file called null in /dev/. Functionally harmless but ugly.

The date > date.txt approach would work but would also defeat caching entirely — lint would re-run on every build even with no code changes. Normally you want lint to be cached when inputs haven't changed.

A cleaner version: COPY --from=lint /src/go.sum /tmp/.lint-done — explicit purpose, harmless location, and Docker still enforces the stage dependency while allowing proper caching.

Want me to have the worker update to /tmp/.lint-done instead?

**[manager]** Good question. `COPY --from=lint /src/go.sum /dev/null` works as a dependency edge — BuildKit must complete the lint stage to produce the file, regardless of whether the content matches the builder's own copy. The `--from=<stage>` is a hard dependency in the build graph. That said, you're right to question `/dev/null` as a destination — Docker `COPY` treats it as a regular filename, not the device node, so it creates a file called `null` in `/dev/`. Functionally harmless but ugly. The `date > date.txt` approach would work but would also defeat caching entirely — lint would re-run on every build even with no code changes. Normally you *want* lint to be cached when inputs haven't changed. A cleaner version: `COPY --from=lint /src/go.sum /tmp/.lint-done` — explicit purpose, harmless location, and Docker still enforces the stage dependency while allowing proper caching. Want me to have the worker update to `/tmp/.lint-done` instead?
Sign in to join this conversation.