feat(build): resolve workflow output aliases

This commit is contained in:
Virgil 2026-04-01 23:46:51 +00:00
parent ef72e09c1e
commit fdb684ccf0
2 changed files with 92 additions and 10 deletions

View file

@ -4,6 +4,7 @@ package buildcmd
import (
"context"
"strings"
"dappco.re/go/core/build/internal/ax"
"dappco.re/go/core/build/pkg/build"
@ -14,14 +15,22 @@ import (
)
var (
releaseWorkflowPathInput string
releaseWorkflowOutputPathInput string
releaseWorkflowPathInput string
releaseWorkflowOutputPathInput string
releaseWorkflowOutputPathSnakeInput string
releaseWorkflowOutputLegacyInput string
)
var releaseWorkflowCmd = &cli.Command{
Use: "workflow",
RunE: func(cmd *cli.Command, args []string) error {
return runReleaseWorkflow(cmd.Context(), releaseWorkflowPathInput, releaseWorkflowOutputPathInput)
return runReleaseWorkflow(
cmd.Context(),
releaseWorkflowPathInput,
releaseWorkflowOutputPathInput,
releaseWorkflowOutputPathSnakeInput,
releaseWorkflowOutputLegacyInput,
)
},
}
@ -33,8 +42,8 @@ func setWorkflowI18n() {
func initWorkflowFlags() {
releaseWorkflowCmd.Flags().StringVar(&releaseWorkflowPathInput, "path", "", i18n.T("cmd.build.workflow.flag.path"))
releaseWorkflowCmd.Flags().StringVar(&releaseWorkflowOutputPathInput, "output-path", "", i18n.T("cmd.build.workflow.flag.output_path"))
releaseWorkflowCmd.Flags().StringVar(&releaseWorkflowOutputPathInput, "output_path", "", i18n.T("cmd.build.workflow.flag.output_path"))
releaseWorkflowCmd.Flags().StringVar(&releaseWorkflowOutputPathInput, "output", "", i18n.T("cmd.build.workflow.flag.output"))
releaseWorkflowCmd.Flags().StringVar(&releaseWorkflowOutputPathSnakeInput, "output_path", "", i18n.T("cmd.build.workflow.flag.output_path"))
releaseWorkflowCmd.Flags().StringVar(&releaseWorkflowOutputLegacyInput, "output", "", i18n.T("cmd.build.workflow.flag.output"))
}
// buildCmd := &cli.Command{Use: "build"}
@ -48,17 +57,58 @@ func AddWorkflowCommand(buildCmd *cli.Command) {
// runReleaseWorkflow writes the embedded release workflow into the current project directory.
//
// buildcmd.AddWorkflowCommand(buildCmd)
// runReleaseWorkflow(ctx, "", "") // writes to .github/workflows/release.yml
// runReleaseWorkflow(ctx, "ci/release.yml", "") // writes to ./ci/release.yml under the project root
// runReleaseWorkflow(ctx, "", "ci/release.yml") // output-path, output_path, and output are aliases for the output path input
func runReleaseWorkflow(_ context.Context, workflowPathInput, workflowOutputPathInput string) error {
// runReleaseWorkflow(ctx, "", "", "", "") // writes to .github/workflows/release.yml
// runReleaseWorkflow(ctx, "ci/release.yml", "", "", "") // writes to ./ci/release.yml under the project root
// runReleaseWorkflow(ctx, "", "ci/release.yml", "", "") // uses the preferred explicit output path
// runReleaseWorkflow(ctx, "", "", "ci/release.yml", "") // uses the snake_case alias
// runReleaseWorkflow(ctx, "", "", "", "ci/release.yml") // uses the legacy output alias
func runReleaseWorkflow(_ context.Context, workflowPathInput, workflowOutputPathInput, workflowOutputPathSnakeInput, workflowOutputLegacyInput string) error {
resolvedOutputPathInput, err := resolveReleaseWorkflowOutputPathInput(
workflowOutputPathInput,
workflowOutputPathSnakeInput,
workflowOutputLegacyInput,
)
if err != nil {
return err
}
projectDir, err := ax.Getwd()
if err != nil {
return coreerr.E("build.runReleaseWorkflow", "failed to get working directory", err)
}
return runReleaseWorkflowInDir(projectDir, workflowPathInput, workflowOutputPathInput)
return runReleaseWorkflowInDir(projectDir, workflowPathInput, resolvedOutputPathInput)
}
// resolveReleaseWorkflowOutputPathInput chooses the workflow output path alias
// with deterministic precedence.
//
// resolveReleaseWorkflowOutputPathInput("ci/release.yml", "", "") // "ci/release.yml"
// resolveReleaseWorkflowOutputPathInput("", "ci/release.yml", "") // "ci/release.yml"
// resolveReleaseWorkflowOutputPathInput("", "", "ci/release.yml") // "ci/release.yml"
// resolveReleaseWorkflowOutputPathInput("ci/release.yml", "ops/release.yml", "") // error
func resolveReleaseWorkflowOutputPathInput(outputPathInput, outputPathSnakeInput, outputLegacyInput string) (string, error) {
values := []string{
strings.TrimSpace(outputPathInput),
strings.TrimSpace(outputPathSnakeInput),
strings.TrimSpace(outputLegacyInput),
}
var resolved string
for _, value := range values {
if value == "" {
continue
}
if resolved == "" {
resolved = value
continue
}
if resolved != value {
return "", coreerr.E("build.resolveReleaseWorkflowOutputPathInput", "output aliases specify different locations", nil)
}
}
return resolved, nil
}
// runReleaseWorkflowInDir writes the embedded release workflow into projectDir.

View file

@ -12,6 +12,38 @@ import (
"github.com/stretchr/testify/require"
)
func TestBuildCmd_resolveReleaseWorkflowOutputPathInput_Good(t *testing.T) {
t.Run("accepts the preferred output path", func(t *testing.T) {
path, err := resolveReleaseWorkflowOutputPathInput("ci/release.yml", "", "")
require.NoError(t, err)
assert.Equal(t, "ci/release.yml", path)
})
t.Run("accepts the snake_case output path alias", func(t *testing.T) {
path, err := resolveReleaseWorkflowOutputPathInput("", "ci/release.yml", "")
require.NoError(t, err)
assert.Equal(t, "ci/release.yml", path)
})
t.Run("accepts the legacy output alias", func(t *testing.T) {
path, err := resolveReleaseWorkflowOutputPathInput("", "", "ci/release.yml")
require.NoError(t, err)
assert.Equal(t, "ci/release.yml", path)
})
t.Run("accepts matching output aliases", func(t *testing.T) {
path, err := resolveReleaseWorkflowOutputPathInput("ci/release.yml", "ci/release.yml", "ci/release.yml")
require.NoError(t, err)
assert.Equal(t, "ci/release.yml", path)
})
}
func TestBuildCmd_resolveReleaseWorkflowOutputPathInput_Bad(t *testing.T) {
_, err := resolveReleaseWorkflowOutputPathInput("ci/release.yml", "ops/release.yml", "")
require.Error(t, err)
assert.Contains(t, err.Error(), "output aliases specify different locations")
}
func TestBuildCmd_RunReleaseWorkflow_Good(t *testing.T) {
projectDir := t.TempDir()