Conversation
Implements step.build_from_config (Phase 5.1 roadmap) — a pipeline step that assembles a self-contained Docker image from a workflow config YAML file, a server binary, and optional plugin binaries. - Creates a temp build context, copies config + server + plugin binaries - Generates a Dockerfile with correct ENTRYPOINT/CMD for workflow server - Executes docker build (and optional docker push) via exec.Command - exec.Command is injectable for deterministic unit testing - 17 tests cover factory validation, Dockerfile generation, error paths, push flag, plugin inclusion, and build context file layout - Registers step.build_from_config in plugins/cicd manifest and factory map Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR adds step.build_from_config to the cicd plugin, implementing Phase 5.1 of the roadmap. The step assembles self-contained Docker images from workflow configuration YAML files by bundling the server binary, config file, and optional plugin binaries into a single container image. The implementation uses dependency injection for exec.CommandContext to enable deterministic unit testing without requiring Docker to be present during tests.
Changes:
- Adds new
BuildFromConfigStepimplementation that validates inputs, creates a temporary build context, generates a Dockerfile, and executes docker build/push commands - Updates cicd plugin registration to include the new step type across descriptions, manifests, and factory maps
- Provides comprehensive test coverage with 17 test cases covering factory validation, Dockerfile generation, execution paths, and error scenarios
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| module/pipeline_step_build_from_config.go | Core implementation with factory, Execute method, Dockerfile generation, and docker command execution |
| module/pipeline_step_build_from_config_test.go | Comprehensive test suite with 17 tests covering factory validation, execution paths, and build context layout |
| plugins/cicd/plugin.go | Updated plugin registration, descriptions, and factory map to include step.build_from_config |
| plugins/cicd/plugin_test.go | Updated test expectations to reflect 13 total step factories (was 12) |
| } | ||
| } | ||
|
|
||
| func TestBuildFromConfigStep_GenerateDockerfile_NoPLugins(t *testing.T) { |
There was a problem hiding this comment.
Typo in function name: "NoPLugins" should be "NoPlugins" (lowercase 'l').
| func TestBuildFromConfigStep_GenerateDockerfile_NoPLugins(t *testing.T) { | |
| func TestBuildFromConfigStep_GenerateDockerfile_NoPlugins(t *testing.T) { |
| _, err = fmt.Fprintf(out, "") | ||
| if err != nil { | ||
| return err | ||
| } | ||
| _, err = out.Seek(0, 0) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| f, err := os.Open(path) //nolint:gosec | ||
| if err != nil { | ||
| return err | ||
| } | ||
| defer f.Close() | ||
| _, copyErr := io.Copy(out, f) |
There was a problem hiding this comment.
The copyDirRecursive helper function has unnecessary complexity. Lines 500-507 write an empty string and then seek back to position 0, which is redundant since the file was just created with O_TRUNC. Additionally, lines 508-513 open the same source file again (that was already opened at line 490) for copying. This can be simplified to directly use io.Copy from the already-opened 'in' file handle instead of reopening it as 'f'.
| _, err = fmt.Fprintf(out, "") | |
| if err != nil { | |
| return err | |
| } | |
| _, err = out.Seek(0, 0) | |
| if err != nil { | |
| return err | |
| } | |
| f, err := os.Open(path) //nolint:gosec | |
| if err != nil { | |
| return err | |
| } | |
| defer f.Close() | |
| _, copyErr := io.Copy(out, f) | |
| _, copyErr := io.Copy(out, in) |
Summary
step.build_from_configto thecicdplugin (Phase 5.1 roadmap item)exec.Commandis injected via a field on the step struct, enabling deterministic unit tests without running DockerWhat it does
config_fileandserver_binaryexist on diskconfig.yaml, server binary →server, and each plugin binary →plugins/<name>/<binary>Dockerfile:docker build -t <tag> <context_dir>docker push <tag>whenpush: trueimage_taganddockerfile_contentas step outputsExample config
Test plan
go test ./module/ -run TestBuildFromConfig— 17 tests, all passgo test ./plugins/cicd/...— 4 tests, all pass (count updated 12→13)go build ./...— full build succeeds with no new errors🤖 Generated with Claude Code