refactor(build): centralise workflow output alias resolution
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
83b5f12ce1
commit
dbe7c69378
5 changed files with 89 additions and 67 deletions
|
|
@ -4,7 +4,6 @@ package buildcmd
|
|||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"dappco.re/go/core/build/internal/ax"
|
||||
"dappco.re/go/core/build/pkg/build"
|
||||
|
|
@ -63,7 +62,7 @@ func AddWorkflowCommand(buildCmd *cli.Command) {
|
|||
// 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(
|
||||
resolvedOutputPathInput, err := build.ResolveReleaseWorkflowOutputPath(
|
||||
workflowOutputPathInput,
|
||||
workflowOutputPathSnakeInput,
|
||||
workflowOutputLegacyInput,
|
||||
|
|
@ -80,37 +79,6 @@ func runReleaseWorkflow(_ context.Context, workflowPathInput, workflowOutputPath
|
|||
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.
|
||||
//
|
||||
// runReleaseWorkflowInDir("/tmp/project", "", "") // /tmp/project/.github/workflows/release.yml
|
||||
|
|
|
|||
|
|
@ -14,32 +14,32 @@ import (
|
|||
|
||||
func TestBuildCmd_resolveReleaseWorkflowOutputPathInput_Good(t *testing.T) {
|
||||
t.Run("accepts the preferred output path", func(t *testing.T) {
|
||||
path, err := resolveReleaseWorkflowOutputPathInput("ci/release.yml", "", "")
|
||||
path, err := build.ResolveReleaseWorkflowOutputPath("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", "")
|
||||
path, err := build.ResolveReleaseWorkflowOutputPath("", "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")
|
||||
path, err := build.ResolveReleaseWorkflowOutputPath("", "", "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")
|
||||
path, err := build.ResolveReleaseWorkflowOutputPath("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", "")
|
||||
_, err := build.ResolveReleaseWorkflowOutputPath("ci/release.yml", "ops/release.yml", "")
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "output aliases specify different locations")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import (
|
|||
stdio "io"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"dappco.re/go/core/api"
|
||||
"dappco.re/go/core/api/pkg/provider"
|
||||
|
|
@ -21,7 +20,6 @@ import (
|
|||
"dappco.re/go/core/build/pkg/release"
|
||||
"dappco.re/go/core/build/pkg/sdk"
|
||||
"dappco.re/go/core/io"
|
||||
coreerr "dappco.re/go/core/log"
|
||||
"dappco.re/go/core/ws"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
|
@ -556,33 +554,7 @@ type ReleaseWorkflowRequest struct {
|
|||
// resolvedOutputPath resolves the workflow output aliases with the same
|
||||
// conflict rules as the CLI.
|
||||
func (r ReleaseWorkflowRequest) resolvedOutputPath() (string, error) {
|
||||
return resolveOutputPathInput(r.OutputPath, r.OutputPathSnake, r.LegacyOutputPath)
|
||||
}
|
||||
|
||||
// resolveOutputPathInput chooses the workflow output path alias with
|
||||
// deterministic precedence.
|
||||
func resolveOutputPathInput(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("api.resolveOutputPathInput", "output aliases specify different locations", nil)
|
||||
}
|
||||
}
|
||||
|
||||
return resolved, nil
|
||||
return build.ResolveReleaseWorkflowOutputPath(r.OutputPath, r.OutputPathSnake, r.LegacyOutputPath)
|
||||
}
|
||||
|
||||
func (p *BuildProvider) generateReleaseWorkflow(c *gin.Context) {
|
||||
|
|
|
|||
|
|
@ -130,6 +130,22 @@ func ResolveReleaseWorkflowInputPathWithMedium(filesystem io_interface.Medium, p
|
|||
)
|
||||
}
|
||||
|
||||
// ResolveReleaseWorkflowOutputPath resolves the workflow output aliases used by
|
||||
// the CLI, API, and UI layers.
|
||||
//
|
||||
// build.ResolveReleaseWorkflowOutputPath("ci/release.yml", "", "") // "ci/release.yml"
|
||||
// build.ResolveReleaseWorkflowOutputPath("", "ci/release.yml", "") // "ci/release.yml"
|
||||
// build.ResolveReleaseWorkflowOutputPath("", "", "ci/release.yml") // "ci/release.yml"
|
||||
// build.ResolveReleaseWorkflowOutputPath("ci/release.yml", "ops.yml", "") // error
|
||||
func ResolveReleaseWorkflowOutputPath(outputPathInput, outputPathSnakeInput, outputLegacyInput string) (string, error) {
|
||||
return resolveReleaseWorkflowPathPair(
|
||||
outputPathInput,
|
||||
outputPathSnakeInput,
|
||||
outputLegacyInput,
|
||||
"build.ResolveReleaseWorkflowOutputPath",
|
||||
)
|
||||
}
|
||||
|
||||
// resolveReleaseWorkflowInputPathPair resolves the workflow path from the path
|
||||
// and output aliases, rejecting conflicting values and preferring explicit
|
||||
// inputs over the default.
|
||||
|
|
@ -157,6 +173,33 @@ func resolveReleaseWorkflowInputPathPair(pathInput, outputPathInput string, reso
|
|||
return resolve(""), nil
|
||||
}
|
||||
|
||||
// resolveReleaseWorkflowPathPair resolves any trio of workflow path aliases by
|
||||
// trimming whitespace, rejecting conflicts, and returning the first non-empty
|
||||
// value when aliases agree.
|
||||
func resolveReleaseWorkflowPathPair(primaryInput, secondaryInput, tertiaryInput, errorName string) (string, error) {
|
||||
values := []string{
|
||||
cleanWorkflowInput(primaryInput),
|
||||
cleanWorkflowInput(secondaryInput),
|
||||
cleanWorkflowInput(tertiaryInput),
|
||||
}
|
||||
|
||||
var resolved string
|
||||
for _, value := range values {
|
||||
if value == "" {
|
||||
continue
|
||||
}
|
||||
if resolved == "" {
|
||||
resolved = value
|
||||
continue
|
||||
}
|
||||
if resolved != value {
|
||||
return "", coreerr.E(errorName, "output aliases specify different locations", nil)
|
||||
}
|
||||
}
|
||||
|
||||
return resolved, nil
|
||||
}
|
||||
|
||||
// resolveReleaseWorkflowInputPath resolves one workflow input into a file path.
|
||||
//
|
||||
// resolveReleaseWorkflowInputPath("/tmp/project", "ci", io.Local) // /tmp/project/ci/release.yml
|
||||
|
|
|
|||
|
|
@ -319,3 +319,42 @@ func TestWorkflow_ResolveReleaseWorkflowInputPathWithMedium_Good(t *testing.T) {
|
|||
assert.Equal(t, "/tmp/project/ci/release.yml", path)
|
||||
})
|
||||
}
|
||||
|
||||
func TestWorkflow_ResolveReleaseWorkflowOutputPath_Good(t *testing.T) {
|
||||
t.Run("accepts the preferred output path", func(t *testing.T) {
|
||||
path, err := ResolveReleaseWorkflowOutputPath("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 := ResolveReleaseWorkflowOutputPath("", "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 := ResolveReleaseWorkflowOutputPath("", "", "ci/release.yml")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "ci/release.yml", path)
|
||||
})
|
||||
|
||||
t.Run("trims surrounding whitespace from aliases", func(t *testing.T) {
|
||||
path, err := ResolveReleaseWorkflowOutputPath(" ci/release.yml ", " ", " ")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "ci/release.yml", path)
|
||||
})
|
||||
|
||||
t.Run("accepts matching aliases", func(t *testing.T) {
|
||||
path, err := ResolveReleaseWorkflowOutputPath("ci/release.yml", "ci/release.yml", "ci/release.yml")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "ci/release.yml", path)
|
||||
})
|
||||
}
|
||||
|
||||
func TestWorkflow_ResolveReleaseWorkflowOutputPath_Bad(t *testing.T) {
|
||||
path, err := ResolveReleaseWorkflowOutputPath("ci/release.yml", "ops/release.yml", "")
|
||||
assert.Error(t, err)
|
||||
assert.Empty(t, path)
|
||||
assert.Contains(t, err.Error(), "output aliases specify different locations")
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue