diff --git a/README.md b/README.md index 2ec98ae..5c82e2c 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ Examples: score-compose generate score.yaml --override-file=./overrides.score.yaml --override-property=metadata.key=value Flags: - --build stringArray An optional build context to use for the given container --build=container=./dir or --build=container={'"context":"./dir"} + --build stringArray An optional build context to use for the given container --build=container=./dir or --build=container={"context":"./dir"} --env-file string Location to store a skeleton .env file for compose - this will override existing content -h, --help help for generate --image string An optional container image to use for any container with image == '.' diff --git a/internal/command/generate.go b/internal/command/generate.go index bd4d955..eec505b 100644 --- a/internal/command/generate.go +++ b/internal/command/generate.go @@ -16,13 +16,13 @@ package command import ( "context" - "encoding/json" "fmt" "log/slog" "os" "slices" "strings" + composeloader "github.com/compose-spec/compose-go/v2/loader" "github.com/compose-spec/compose-go/v2/types" "github.com/imdario/mergo" "github.com/score-spec/score-go/framework" @@ -158,10 +158,12 @@ arguments. return fmt.Errorf("invalid --%s '%s': unknown container '%s'", generateCmdBuildFlag, buildFlag, parts[0]) } if strings.HasPrefix(parts[1], "{") { + var intermediate interface{} + if err := yaml.Unmarshal([]byte(parts[1]), &intermediate); err != nil { + return fmt.Errorf("invalid --%s '%s': %w", generateCmdBuildFlag, buildFlag, err) + } var out types.BuildConfig - dec := json.NewDecoder(strings.NewReader(parts[1])) - dec.DisallowUnknownFields() - if err := dec.Decode(&out); err != nil { + if err := composeloader.Transform(intermediate, &out); err != nil { return fmt.Errorf("invalid --%s '%s': %w", generateCmdBuildFlag, buildFlag, err) } containerBuildContexts[parts[0]] = out @@ -327,7 +329,7 @@ func init() { generateCommand.Flags().String(generateCmdOverridesFileFlag, "", "An optional file of Score overrides to merge in") generateCommand.Flags().StringArray(generateCmdOverridePropertyFlag, []string{}, "An optional set of path=key overrides to set or remove") generateCommand.Flags().String(generateCmdImageFlag, "", "An optional container image to use for any container with image == '.'") - generateCommand.Flags().StringArray(generateCmdBuildFlag, []string{}, "An optional build context to use for the given container --build=container=./dir or --build=container={'\"context\":\"./dir\"}") + generateCommand.Flags().StringArray(generateCmdBuildFlag, []string{}, "An optional build context to use for the given container --build=container=./dir or --build=container={\"context\":\"./dir\"}") generateCommand.Flags().String(generateCmdEnvFileFlag, "", "Location to store a skeleton .env file for compose - this will override existing content") rootCmd.AddCommand(generateCommand) } diff --git a/internal/command/generate_test.go b/internal/command/generate_test.go index 1b3e8d2..4bdb7b3 100644 --- a/internal/command/generate_test.go +++ b/internal/command/generate_test.go @@ -53,7 +53,7 @@ Examples: score-compose generate score.yaml --override-file=./overrides.score.yaml --override-property=metadata.key=value Flags: - --build stringArray An optional build context to use for the given container --build=container=./dir or --build=container={'"context":"./dir"} + --build stringArray An optional build context to use for the given container --build=container=./dir or --build=container={"context":"./dir"} --env-file string Location to store a skeleton .env file for compose - this will override existing content -h, --help help for generate --image string An optional container image to use for any container with image == '.' @@ -270,6 +270,44 @@ services: assert.Equal(t, expectedOutput, string(raw)) }) + t.Run("generate with json build context and array args", func(t *testing.T) { + stdout, _, err = executeAndResetCommand(context.Background(), rootCmd, []string{ + "generate", "-o", "compose-output.yaml", "--build", `example={"context":"./dir","args":["DEBUG"]}`, "--", "score.yaml", + }) + assert.NoError(t, err) + assert.Equal(t, "", stdout) + raw, err := os.ReadFile(filepath.Join(td, "compose-output.yaml")) + assert.NoError(t, err) + expectedOutput := `name: "001" +services: + example-example: + build: + context: ./dir + args: + DEBUG: null + hostname: example +` + assert.Equal(t, expectedOutput, string(raw)) + }) + + t.Run("generate with yaml build context", func(t *testing.T) { + stdout, _, err = executeAndResetCommand(context.Background(), rootCmd, []string{ + "generate", "-o", "compose-output.yaml", "--build", `example={context: "./dir"}`, "--", "score.yaml", + }) + assert.NoError(t, err) + assert.Equal(t, "", stdout) + raw, err := os.ReadFile(filepath.Join(td, "compose-output.yaml")) + assert.NoError(t, err) + expectedOutput := `name: "001" +services: + example-example: + build: + context: ./dir + hostname: example +` + assert.Equal(t, expectedOutput, string(raw)) + }) + } func TestInitAndGenerate_with_files(t *testing.T) {