← back to Cli Printing Press
fix(pipeline): clean generated cli artifacts
421c81bdcbb83d7a2d35e7c1e1f6d206ae804416 · 2026-03-28 01:35:03 -0700 · Trevin Chow
Clean up disposable binaries and recursive generated copies around validation and verification without breaking iterative work.
Keep the runtime verify binary and build cache until explicit cleanup, and add coverage for the new artifact lifecycle.
Files touched
A internal/artifacts/cleanup.goA internal/artifacts/cleanup_test.goM internal/cli/verify.goA internal/cli/verify_test.goM internal/generator/generator_test.goM internal/generator/validate.goM internal/pipeline/dogfood.goM internal/pipeline/fullrun.goM internal/pipeline/runtime.goA internal/pipeline/runtime_test.goM internal/pipeline/verify.go
Diff
commit 421c81bdcbb83d7a2d35e7c1e1f6d206ae804416
Author: Trevin Chow <trevin@trevinchow.com>
Date: Sat Mar 28 01:35:03 2026 -0700
fix(pipeline): clean generated cli artifacts
Clean up disposable binaries and recursive generated copies around validation and verification without breaking iterative work.
Keep the runtime verify binary and build cache until explicit cleanup, and add coverage for the new artifact lifecycle.
---
internal/artifacts/cleanup.go | 99 ++++++++++++++++++++++++++++++++++++
internal/artifacts/cleanup_test.go | 52 +++++++++++++++++++
internal/cli/verify.go | 36 +++++++++++++
internal/cli/verify_test.go | 39 ++++++++++++++
internal/generator/generator_test.go | 1 +
internal/generator/validate.go | 16 ++++++
internal/pipeline/dogfood.go | 17 ++++---
internal/pipeline/fullrun.go | 1 +
internal/pipeline/runtime.go | 42 +++++++++------
internal/pipeline/runtime_test.go | 60 ++++++++++++++++++++++
internal/pipeline/verify.go | 10 ++++
11 files changed, 349 insertions(+), 24 deletions(-)
diff --git a/internal/artifacts/cleanup.go b/internal/artifacts/cleanup.go
new file mode 100644
index 00000000..62a8e937
--- /dev/null
+++ b/internal/artifacts/cleanup.go
@@ -0,0 +1,99 @@
+package artifacts
+
+import (
+ "errors"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+// CleanupOptions controls which generated artifacts to remove.
+type CleanupOptions struct {
+ RemoveCache bool
+ RemoveRuntimeBinary bool
+ RemoveValidationBinaries bool
+ RemoveDogfoodBinaries bool
+ RemoveRecursiveCopies bool
+ RemoveFinderMetadata bool
+}
+
+// CleanupGeneratedCLI removes reproducible artifacts from a generated CLI tree.
+func CleanupGeneratedCLI(dir string, opts CleanupOptions) error {
+ var errs []error
+
+ if opts.RemoveRuntimeBinary {
+ name := filepath.Base(filepath.Clean(dir))
+ if name != "." && name != string(filepath.Separator) {
+ errs = append(errs, removeFileIfExists(filepath.Join(dir, name)))
+ }
+ }
+
+ if opts.RemoveValidationBinaries || opts.RemoveDogfoodBinaries {
+ entries, err := os.ReadDir(dir)
+ if err != nil && !os.IsNotExist(err) {
+ errs = append(errs, err)
+ }
+ for _, entry := range entries {
+ if entry.IsDir() {
+ continue
+ }
+ name := entry.Name()
+ switch {
+ case opts.RemoveValidationBinaries && strings.HasSuffix(name, "-validation"):
+ errs = append(errs, removeFileIfExists(filepath.Join(dir, name)))
+ case opts.RemoveDogfoodBinaries && strings.HasSuffix(name, "-dogfood"):
+ errs = append(errs, removeFileIfExists(filepath.Join(dir, name)))
+ }
+ }
+ }
+
+ if opts.RemoveRecursiveCopies {
+ errs = append(errs, removeDirIfExists(filepath.Join(dir, "cmd", "library")))
+ }
+
+ if opts.RemoveFinderMetadata {
+ errs = append(errs, removeFinderMetadata(dir))
+ }
+
+ if opts.RemoveCache {
+ errs = append(errs, removeDirIfExists(filepath.Join(dir, ".cache")))
+ }
+
+ return errors.Join(errs...)
+}
+
+func removeFinderMetadata(root string) error {
+ var errs []error
+ walkErr := filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error {
+ if err != nil {
+ errs = append(errs, err)
+ return nil
+ }
+ if d.IsDir() || d.Name() != ".DS_Store" {
+ return nil
+ }
+ errs = append(errs, removeFileIfExists(path))
+ return nil
+ })
+ if walkErr != nil {
+ errs = append(errs, walkErr)
+ }
+ return errors.Join(errs...)
+}
+
+func removeFileIfExists(path string) error {
+ if err := os.Remove(path); err != nil && !os.IsNotExist(err) {
+ return err
+ }
+ return nil
+}
+
+func removeDirIfExists(path string) error {
+ if _, err := os.Stat(path); err != nil {
+ if os.IsNotExist(err) {
+ return nil
+ }
+ return err
+ }
+ return os.RemoveAll(path)
+}
diff --git a/internal/artifacts/cleanup_test.go b/internal/artifacts/cleanup_test.go
new file mode 100644
index 00000000..a2bceb41
--- /dev/null
+++ b/internal/artifacts/cleanup_test.go
@@ -0,0 +1,52 @@
+package artifacts
+
+import (
+ "os"
+ "path/filepath"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestCleanupGeneratedCLI(t *testing.T) {
+ dir := filepath.Join(t.TempDir(), "sample-cli")
+ require.NoError(t, os.MkdirAll(filepath.Join(dir, "cmd", "library", "sample-cli"), 0o755))
+ require.NoError(t, os.MkdirAll(filepath.Join(dir, ".cache", "go-build"), 0o755))
+ require.NoError(t, os.MkdirAll(filepath.Join(dir, "nested"), 0o755))
+
+ writeArtifactFile(t, filepath.Join(dir, "sample-cli"))
+ writeArtifactFile(t, filepath.Join(dir, "sample-cli-validation"))
+ writeArtifactFile(t, filepath.Join(dir, "sample-cli-dogfood"))
+ writeArtifactFile(t, filepath.Join(dir, ".DS_Store"))
+ writeArtifactFile(t, filepath.Join(dir, "nested", ".DS_Store"))
+ writeArtifactFile(t, filepath.Join(dir, ".cache", "go-build", "index"))
+ writeArtifactFile(t, filepath.Join(dir, "cmd", "library", "sample-cli", "main.go"))
+
+ err := CleanupGeneratedCLI(dir, CleanupOptions{
+ RemoveRuntimeBinary: true,
+ RemoveValidationBinaries: true,
+ RemoveDogfoodBinaries: true,
+ RemoveRecursiveCopies: true,
+ RemoveFinderMetadata: true,
+ })
+ require.NoError(t, err)
+
+ assert.NoFileExists(t, filepath.Join(dir, "sample-cli"))
+ assert.NoFileExists(t, filepath.Join(dir, "sample-cli-validation"))
+ assert.NoFileExists(t, filepath.Join(dir, "sample-cli-dogfood"))
+ assert.NoFileExists(t, filepath.Join(dir, ".DS_Store"))
+ assert.NoFileExists(t, filepath.Join(dir, "nested", ".DS_Store"))
+ assert.NoDirExists(t, filepath.Join(dir, "cmd", "library"))
+ assert.DirExists(t, filepath.Join(dir, ".cache"))
+
+ err = CleanupGeneratedCLI(dir, CleanupOptions{RemoveCache: true})
+ require.NoError(t, err)
+ assert.NoDirExists(t, filepath.Join(dir, ".cache"))
+}
+
+func writeArtifactFile(t *testing.T, path string) {
+ t.Helper()
+ require.NoError(t, os.MkdirAll(filepath.Dir(path), 0o755))
+ require.NoError(t, os.WriteFile(path, []byte("artifact"), 0o644))
+}
diff --git a/internal/cli/verify.go b/internal/cli/verify.go
index 165c7695..8f29f00d 100644
--- a/internal/cli/verify.go
+++ b/internal/cli/verify.go
@@ -4,7 +4,9 @@ import (
"encoding/json"
"fmt"
"os"
+ "path/filepath"
+ "github.com/mvanhorn/cli-printing-press/internal/artifacts"
"github.com/mvanhorn/cli-printing-press/internal/pipeline"
"github.com/spf13/cobra"
)
@@ -18,6 +20,7 @@ func newVerifyCmd() *cobra.Command {
var fix bool
var maxIterations int
var asJSON bool
+ var cleanup bool
cmd := &cobra.Command{
Use: "verify",
@@ -39,6 +42,9 @@ Use --fix to auto-patch common failures and re-test (max 3 iterations).`,
# Auto-fix failures and re-test
printing-press verify --dir ./github-cli --spec /tmp/spec.json --fix
+ # Remove transient build artifacts after the final verification pass
+ printing-press verify --dir ./github-cli --spec /tmp/spec.json --cleanup
+
# Set pass threshold and output JSON
printing-press verify --dir ./github-cli --spec /tmp/spec.json --threshold 70 --json`,
RunE: func(cmd *cobra.Command, args []string) error {
@@ -68,6 +74,10 @@ Use --fix to auto-patch common failures and re-test (max 3 iterations).`,
}
}
+ if err := cleanupVerifyArtifacts(dir, cleanup); err != nil {
+ return err
+ }
+
if asJSON {
output := map[string]any{"verify": report}
if fixReport != nil {
@@ -103,6 +113,7 @@ Use --fix to auto-patch common failures and re-test (max 3 iterations).`,
cmd.Flags().BoolVar(&fix, "fix", false, "Auto-fix common failures and re-test")
cmd.Flags().IntVar(&maxIterations, "max-iterations", 3, "Maximum fix loop iterations")
cmd.Flags().BoolVar(&asJSON, "json", false, "Output as JSON")
+ cmd.Flags().BoolVar(&cleanup, "cleanup", false, "Remove transient build artifacts after verification")
_ = cmd.MarkFlagRequired("dir")
return cmd
}
@@ -130,6 +141,31 @@ func printVerifyReport(report *pipeline.VerifyReport) {
fmt.Printf("Verdict: %s\n", report.Verdict)
}
+func cleanupVerifyArtifacts(dir string, cleanup bool) error {
+ if !cleanup {
+ return nil
+ }
+ if dir == "" {
+ return fmt.Errorf("cleaning generated artifacts: empty dir")
+ }
+ if !filepath.IsAbs(dir) {
+ if absDir, err := filepath.Abs(dir); err == nil {
+ dir = absDir
+ }
+ }
+ if err := artifacts.CleanupGeneratedCLI(dir, artifacts.CleanupOptions{
+ RemoveCache: true,
+ RemoveRuntimeBinary: true,
+ RemoveValidationBinaries: true,
+ RemoveDogfoodBinaries: true,
+ RemoveRecursiveCopies: true,
+ RemoveFinderMetadata: true,
+ }); err != nil {
+ return fmt.Errorf("cleaning generated artifacts: %w", err)
+ }
+ return nil
+}
+
func passFail(b bool) string {
if b {
return "PASS"
diff --git a/internal/cli/verify_test.go b/internal/cli/verify_test.go
new file mode 100644
index 00000000..ba477863
--- /dev/null
+++ b/internal/cli/verify_test.go
@@ -0,0 +1,39 @@
+package cli
+
+import (
+ "os"
+ "path/filepath"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestCleanupVerifyArtifacts(t *testing.T) {
+ dir := filepath.Join(t.TempDir(), "sample-cli")
+ require.NoError(t, os.MkdirAll(filepath.Join(dir, ".cache", "go-build"), 0o755))
+ require.NoError(t, os.MkdirAll(filepath.Join(dir, "cmd", "library", "sample-cli"), 0o755))
+ require.NoError(t, os.WriteFile(filepath.Join(dir, "sample-cli"), []byte("bin"), 0o755))
+ require.NoError(t, os.WriteFile(filepath.Join(dir, "sample-cli-validation"), []byte("bin"), 0o755))
+ require.NoError(t, os.WriteFile(filepath.Join(dir, "sample-cli-dogfood"), []byte("bin"), 0o755))
+ require.NoError(t, os.WriteFile(filepath.Join(dir, ".DS_Store"), []byte("finder"), 0o644))
+
+ require.NoError(t, cleanupVerifyArtifacts(dir, true))
+
+ assert.NoFileExists(t, filepath.Join(dir, "sample-cli"))
+ assert.NoFileExists(t, filepath.Join(dir, "sample-cli-validation"))
+ assert.NoFileExists(t, filepath.Join(dir, "sample-cli-dogfood"))
+ assert.NoFileExists(t, filepath.Join(dir, ".DS_Store"))
+ assert.NoDirExists(t, filepath.Join(dir, ".cache"))
+ assert.NoDirExists(t, filepath.Join(dir, "cmd", "library"))
+}
+
+func TestCleanupVerifyArtifacts_NoOpWhenDisabled(t *testing.T) {
+ dir := filepath.Join(t.TempDir(), "sample-cli")
+ require.NoError(t, os.MkdirAll(dir, 0o755))
+ require.NoError(t, os.WriteFile(filepath.Join(dir, "sample-cli"), []byte("bin"), 0o755))
+
+ require.NoError(t, cleanupVerifyArtifacts(dir, false))
+
+ assert.FileExists(t, filepath.Join(dir, "sample-cli"))
+}
diff --git a/internal/generator/generator_test.go b/internal/generator/generator_test.go
index 2b965183..9dfc3ebb 100644
--- a/internal/generator/generator_test.go
+++ b/internal/generator/generator_test.go
@@ -143,6 +143,7 @@ func TestGenerateWithNoAuth(t *testing.T) {
gen := New(apiSpec, outputDir)
require.NoError(t, gen.Generate())
require.NoError(t, gen.Validate())
+ assert.NoFileExists(t, filepath.Join(outputDir, "noauth-cli-validation"))
}
func TestGenerateWithOwnerField(t *testing.T) {
diff --git a/internal/generator/validate.go b/internal/generator/validate.go
index 2080e0d0..7a290241 100644
--- a/internal/generator/validate.go
+++ b/internal/generator/validate.go
@@ -9,6 +9,8 @@ import (
"path/filepath"
"strings"
"time"
+
+ "github.com/mvanhorn/cli-printing-press/internal/artifacts"
)
type validationGate struct {
@@ -18,6 +20,20 @@ type validationGate struct {
func (g *Generator) Validate() error {
binPath := filepath.Join(g.OutputDir, g.Spec.Name+"-cli-validation")
+ if err := artifacts.CleanupGeneratedCLI(g.OutputDir, artifacts.CleanupOptions{
+ RemoveValidationBinaries: true,
+ RemoveRecursiveCopies: true,
+ RemoveFinderMetadata: true,
+ }); err != nil {
+ return fmt.Errorf("pre-validating cleanup: %w", err)
+ }
+ defer func() {
+ _ = artifacts.CleanupGeneratedCLI(g.OutputDir, artifacts.CleanupOptions{
+ RemoveValidationBinaries: true,
+ RemoveRecursiveCopies: true,
+ RemoveFinderMetadata: true,
+ })
+ }()
gates := []validationGate{
{
diff --git a/internal/pipeline/dogfood.go b/internal/pipeline/dogfood.go
index 455efa3a..91b062e2 100644
--- a/internal/pipeline/dogfood.go
+++ b/internal/pipeline/dogfood.go
@@ -14,14 +14,14 @@ import (
)
type DogfoodReport struct {
- Dir string `json:"dir"`
- SpecPath string `json:"spec_path,omitempty"`
- Verdict string `json:"verdict"`
- PathCheck PathCheckResult `json:"path_check"`
- AuthCheck AuthCheckResult `json:"auth_check"`
- DeadFlags DeadCodeResult `json:"dead_flags"`
- DeadFuncs DeadCodeResult `json:"dead_functions"`
- PipelineCheck PipelineResult `json:"pipeline_check"`
+ Dir string `json:"dir"`
+ SpecPath string `json:"spec_path,omitempty"`
+ Verdict string `json:"verdict"`
+ PathCheck PathCheckResult `json:"path_check"`
+ AuthCheck AuthCheckResult `json:"auth_check"`
+ DeadFlags DeadCodeResult `json:"dead_flags"`
+ DeadFuncs DeadCodeResult `json:"dead_functions"`
+ PipelineCheck PipelineResult `json:"pipeline_check"`
ExampleCheck ExampleCheckResult `json:"example_check"`
Issues []string `json:"issues"`
}
@@ -466,6 +466,7 @@ func checkExamples(dir string) ExampleCheckResult {
result.Detail = fmt.Sprintf("could not build CLI binary: %v", err)
return result
}
+ defer os.Remove(binaryPath)
// Get global flags from root --help
globalOut, err := runDogfoodCmd(binaryPath, 15*time.Second, "--help")
diff --git a/internal/pipeline/fullrun.go b/internal/pipeline/fullrun.go
index 990282c3..00a3db28 100644
--- a/internal/pipeline/fullrun.go
+++ b/internal/pipeline/fullrun.go
@@ -146,6 +146,7 @@ func MakeBestCLI(apiName, level, specFlag, specURL, outputDir, pressBinary strin
result.DogfoodError = fmt.Sprintf("build failed: %v", buildErr)
result.Errors = append(result.Errors, fmt.Sprintf("dogfood build: %v", buildErr))
} else {
+ defer os.Remove(cliBinaryPath)
dogfood, dogErr := RunDogfood(outputDir, "")
if dogErr != nil {
result.DogfoodError = dogErr.Error()
diff --git a/internal/pipeline/runtime.go b/internal/pipeline/runtime.go
index 49691882..ee3be5ea 100644
--- a/internal/pipeline/runtime.go
+++ b/internal/pipeline/runtime.go
@@ -12,6 +12,8 @@ import (
"regexp"
"strings"
"time"
+
+ "github.com/mvanhorn/cli-printing-press/internal/artifacts"
)
// VerifyConfig configures a runtime verification run.
@@ -25,27 +27,27 @@ type VerifyConfig struct {
// VerifyReport is the output of a runtime verification run.
type VerifyReport struct {
- Mode string `json:"mode"` // "live" or "mock"
- Total int `json:"total"`
- Passed int `json:"passed"`
- Failed int `json:"failed"`
- Critical int `json:"critical"`
- PassRate float64 `json:"pass_rate"`
- DataPipeline bool `json:"data_pipeline"`
- Verdict string `json:"verdict"` // PASS, WARN, FAIL
+ Mode string `json:"mode"` // "live" or "mock"
+ Total int `json:"total"`
+ Passed int `json:"passed"`
+ Failed int `json:"failed"`
+ Critical int `json:"critical"`
+ PassRate float64 `json:"pass_rate"`
+ DataPipeline bool `json:"data_pipeline"`
+ Verdict string `json:"verdict"` // PASS, WARN, FAIL
Results []CommandResult `json:"results"`
- Binary string `json:"binary"`
+ Binary string `json:"binary"`
}
// CommandResult is the test result for a single command.
type CommandResult struct {
- Command string `json:"command"`
- Kind string `json:"kind"` // read, write, local, data-layer
- Help bool `json:"help"`
- DryRun bool `json:"dry_run"`
- Execute bool `json:"execute"`
- Score int `json:"score"` // 0-3
- Error string `json:"error,omitempty"`
+ Command string `json:"command"`
+ Kind string `json:"kind"` // read, write, local, data-layer
+ Help bool `json:"help"`
+ DryRun bool `json:"dry_run"`
+ Execute bool `json:"execute"`
+ Score int `json:"score"` // 0-3
+ Error string `json:"error,omitempty"`
}
// RunVerify executes the runtime verification pipeline.
@@ -53,6 +55,14 @@ func RunVerify(cfg VerifyConfig) (*VerifyReport, error) {
if cfg.Threshold == 0 {
cfg.Threshold = 80
}
+ if err := artifacts.CleanupGeneratedCLI(cfg.Dir, artifacts.CleanupOptions{
+ RemoveValidationBinaries: true,
+ RemoveDogfoodBinaries: true,
+ RemoveRecursiveCopies: true,
+ RemoveFinderMetadata: true,
+ }); err != nil {
+ return nil, fmt.Errorf("pre-verify cleanup: %w", err)
+ }
report := &VerifyReport{}
diff --git a/internal/pipeline/runtime_test.go b/internal/pipeline/runtime_test.go
new file mode 100644
index 00000000..69b13bc7
--- /dev/null
+++ b/internal/pipeline/runtime_test.go
@@ -0,0 +1,60 @@
+package pipeline
+
+import (
+ "os"
+ "path/filepath"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestRunVerify_CleansTransientArtifactsButKeepsCache(t *testing.T) {
+ dir := filepath.Join(t.TempDir(), "sample-cli")
+ require.NoError(t, os.MkdirAll(filepath.Join(dir, "cmd", "sample-cli"), 0o755))
+ require.NoError(t, os.MkdirAll(filepath.Join(dir, "internal", "cli"), 0o755))
+ require.NoError(t, os.MkdirAll(filepath.Join(dir, "cmd", "library", "sample-cli"), 0o755))
+ require.NoError(t, os.MkdirAll(filepath.Join(dir, ".cache", "go-build"), 0o755))
+
+ writeTestFile(t, filepath.Join(dir, "go.mod"), "module example.com/sample-cli\n\ngo 1.26.1\n")
+ writeTestFile(t, filepath.Join(dir, "cmd", "sample-cli", "main.go"), `package main
+func main() {}
+`)
+ writeTestFile(t, filepath.Join(dir, "internal", "cli", "root.go"), `package cli
+func initRoot() {
+ rootCmd.AddCommand(newUsersListCmd())
+}
+`)
+ writeTestFile(t, filepath.Join(dir, "cmd", "library", "sample-cli", "main.go"), "package recursive\n")
+ writeTestFile(t, filepath.Join(dir, ".DS_Store"), "finder")
+ writeTestFile(t, filepath.Join(dir, ".cache", "go-build", "index"), "cache")
+
+ report, err := RunVerify(VerifyConfig{Dir: dir})
+ require.NoError(t, err)
+ assert.Equal(t, "PASS", report.Verdict)
+ assert.FileExists(t, report.Binary)
+
+ assert.FileExists(t, filepath.Join(dir, "sample-cli"))
+ assert.NoDirExists(t, filepath.Join(dir, "cmd", "library"))
+ assert.NoFileExists(t, filepath.Join(dir, ".DS_Store"))
+ assert.DirExists(t, filepath.Join(dir, ".cache"))
+}
+
+func TestRunVerify_KeepsExistingBinaryWhenRebuildFails(t *testing.T) {
+ dir := filepath.Join(t.TempDir(), "sample-cli")
+ require.NoError(t, os.MkdirAll(filepath.Join(dir, "cmd", "sample-cli"), 0o755))
+
+ existingBinary := filepath.Join(dir, "sample-cli")
+ require.NoError(t, os.WriteFile(existingBinary, []byte("previous-build"), 0o755))
+ writeTestFile(t, filepath.Join(dir, "go.mod"), "module example.com/sample-cli\n\ngo 1.26.1\n")
+ writeTestFile(t, filepath.Join(dir, "cmd", "sample-cli", "main.go"), `package main
+func main() {
+ this will not compile
+}
+`)
+
+ report, err := RunVerify(VerifyConfig{Dir: dir})
+ require.Error(t, err)
+ assert.Nil(t, report)
+ assert.FileExists(t, existingBinary)
+}
diff --git a/internal/pipeline/verify.go b/internal/pipeline/verify.go
index 49a9a839..307f5b91 100644
--- a/internal/pipeline/verify.go
+++ b/internal/pipeline/verify.go
@@ -10,6 +10,8 @@ import (
"strings"
"time"
"unicode"
+
+ "github.com/mvanhorn/cli-printing-press/internal/artifacts"
)
type Verifier struct {
@@ -84,6 +86,14 @@ func (v *Verifier) CompileGate() error {
if v == nil {
return fmt.Errorf("nil verifier")
}
+ if err := artifacts.CleanupGeneratedCLI(v.Dir, artifacts.CleanupOptions{
+ RemoveValidationBinaries: true,
+ RemoveDogfoodBinaries: true,
+ RemoveRecursiveCopies: true,
+ RemoveFinderMetadata: true,
+ }); err != nil {
+ return fmt.Errorf("pre-compile cleanup: %w", err)
+ }
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
← 3a850fc5 fix(pipeline): match short path declarations
·
back to Cli Printing Press
·
docs: add compound engineering plugin to setup instructions 23925ce9 →