diff --git a/cmd/scm/cmd_compile.go b/cmd/scm/cmd_compile.go index c8ece8c..155bfac 100644 --- a/cmd/scm/cmd_compile.go +++ b/cmd/scm/cmd_compile.go @@ -16,6 +16,7 @@ import ( func addCompileCommand(parent *cli.Command) { var ( + version string dir string signKey string builtBy string @@ -27,11 +28,12 @@ func addCompileCommand(parent *cli.Command) { Short: "Compile manifest.yaml into core.json", Long: "Read .core/manifest.yaml, attach build metadata (commit, tag), and write core.json to the project root or a custom output path.", RunE: func(cmd *cli.Command, args []string) error { - return runCompile(dir, signKey, builtBy, output) + return runCompile(dir, version, signKey, builtBy, output) }, } cmd.Flags().StringVarP(&dir, "dir", "d", ".", "Project root directory") + cmd.Flags().StringVar(&version, "version", "", "Override the manifest version") cmd.Flags().StringVar(&signKey, "sign-key", "", "Hex-encoded ed25519 private key for signing") cmd.Flags().StringVar(&builtBy, "built-by", "core scm compile", "Builder identity") cmd.Flags().StringVarP(&output, "output", "o", "core.json", "Output path for the compiled manifest") @@ -39,7 +41,7 @@ func addCompileCommand(parent *cli.Command) { parent.AddCommand(cmd) } -func runCompile(dir, signKeyHex, builtBy, output string) error { +func runCompile(dir, version, signKeyHex, builtBy, output string) error { medium, err := io.NewSandboxed(dir) if err != nil { return cli.WrapVerb(err, "open", dir) @@ -51,6 +53,7 @@ func runCompile(dir, signKeyHex, builtBy, output string) error { } opts := manifest.CompileOptions{ + Version: version, Commit: gitCommit(dir), Tag: gitTag(dir), BuiltBy: builtBy, @@ -83,7 +86,7 @@ func runCompile(dir, signKeyHex, builtBy, output string) error { cli.Blank() cli.Print(" %s %s\n", successStyle.Render("compiled"), valueStyle.Render(m.Code)) - cli.Print(" %s %s\n", dimStyle.Render("version:"), valueStyle.Render(m.Version)) + cli.Print(" %s %s\n", dimStyle.Render("version:"), valueStyle.Render(cm.Version)) if opts.Commit != "" { cli.Print(" %s %s\n", dimStyle.Render("commit:"), valueStyle.Render(opts.Commit)) } diff --git a/cmd/scm/cmd_compile_test.go b/cmd/scm/cmd_compile_test.go index 4a14bb4..613753a 100644 --- a/cmd/scm/cmd_compile_test.go +++ b/cmd/scm/cmd_compile_test.go @@ -10,6 +10,7 @@ import ( "dappco.re/go/core/io" "dappco.re/go/core/scm/manifest" + "forge.lthn.ai/core/cli/pkg/cli" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -24,7 +25,7 @@ name: Compile Default version: 1.0.0 `), 0644)) - err := runCompile(dir, "", "core scm compile", "core.json") + err := runCompile(dir, "", "", "core scm compile", "core.json") require.NoError(t, err) raw, err := io.Local.Read(filepath.Join(dir, "core.json")) @@ -47,7 +48,7 @@ version: 2.0.0 `), 0644)) output := filepath.Join("dist", "core.json") - err := runCompile(dir, "", "custom builder", output) + err := runCompile(dir, "", "", "custom builder", output) require.NoError(t, err) raw, err := io.Local.Read(filepath.Join(dir, output)) @@ -69,7 +70,53 @@ name: Compile Invalid Key version: 1.0.0 `), 0644)) - err := runCompile(dir, hex.EncodeToString([]byte("short")), "core scm compile", "core.json") + err := runCompile(dir, "", hex.EncodeToString([]byte("short")), "core scm compile", "core.json") require.Error(t, err) assert.Contains(t, err.Error(), "invalid private key length") } + +func TestRunCompile_Good_VersionOverride_Good(t *testing.T) { + dir := t.TempDir() + coreDir := filepath.Join(dir, ".core") + require.NoError(t, os.MkdirAll(coreDir, 0755)) + require.NoError(t, os.WriteFile(filepath.Join(coreDir, "manifest.yaml"), []byte(` +code: compile-version +name: Compile Version +version: 1.0.0 +`), 0644)) + + err := runCompile(dir, "3.2.1", "", "core scm compile", "core.json") + require.NoError(t, err) + + raw, err := io.Local.Read(filepath.Join(dir, "core.json")) + require.NoError(t, err) + + cm, err := manifest.ParseCompiled([]byte(raw)) + require.NoError(t, err) + assert.Equal(t, "3.2.1", cm.Version) +} + +func TestAddScmCommands_Good_CompileVersionFlagRegistered_Good(t *testing.T) { + root := &cli.Command{Use: "root"} + + AddScmCommands(root) + + var scmCmd *cli.Command + for _, cmd := range root.Commands() { + if cmd.Name() == "scm" { + scmCmd = cmd + break + } + } + require.NotNil(t, scmCmd) + + var compileCmd *cli.Command + for _, cmd := range scmCmd.Commands() { + if cmd.Name() == "compile" { + compileCmd = cmd + break + } + } + require.NotNil(t, compileCmd) + assert.NotNil(t, compileCmd.Flags().Lookup("version")) +} diff --git a/manifest/compile.go b/manifest/compile.go index 4d571ba..78aa242 100644 --- a/manifest/compile.go +++ b/manifest/compile.go @@ -27,6 +27,7 @@ type CompiledManifest struct { // CompileOptions controls how Compile populates the build metadata. type CompileOptions struct { + Version string // Optional override for the manifest version Commit string // Git commit hash Tag string // Git tag (e.g. v1.0.0) BuiltBy string // Builder identity (e.g. "core build") @@ -47,6 +48,10 @@ func Compile(m *Manifest, opts CompileOptions) (*CompiledManifest, error) { return nil, coreerr.E("manifest.Compile", "missing version", nil) } + if opts.Version != "" { + m.Version = opts.Version + } + // Sign if a key is supplied. if opts.SignKey != nil { if err := Sign(m, opts.SignKey); err != nil { diff --git a/manifest/compile_test.go b/manifest/compile_test.go index c537f26..25c068c 100644 --- a/manifest/compile_test.go +++ b/manifest/compile_test.go @@ -22,6 +22,7 @@ func TestCompile_Good(t *testing.T) { } cm, err := Compile(m, CompileOptions{ + Version: "2.0.0", Commit: "abc1234", Tag: "v1.2.3", BuiltBy: "core build", @@ -30,7 +31,7 @@ func TestCompile_Good(t *testing.T) { assert.Equal(t, "my-widget", cm.Code) assert.Equal(t, "My Widget", cm.Name) - assert.Equal(t, "1.2.3", cm.Version) + assert.Equal(t, "2.0.0", cm.Version) assert.Equal(t, "abc1234", cm.Commit) assert.Equal(t, "v1.2.3", cm.Tag) assert.Equal(t, "core build", cm.BuiltBy) @@ -181,3 +182,18 @@ func TestCompile_Good_MinimalOptions_Good(t *testing.T) { assert.Empty(t, cm.BuiltBy) assert.NotEmpty(t, cm.BuiltAt) } + +func TestCompile_Good_WithVersionOverride_Good(t *testing.T) { + m := &Manifest{ + Code: "override", + Name: "Override", + Version: "0.0.1", + } + + cm, err := Compile(m, CompileOptions{ + Version: "9.9.9", + }) + require.NoError(t, err) + assert.Equal(t, "9.9.9", cm.Version) + assert.Equal(t, "9.9.9", m.Version) +}