Map CLI profiles to selected modules
This commit is contained in:
@@ -16,7 +16,7 @@ import (
|
||||
"gitea.maximumdirect.net/eric/ReleaseKit/internal/process"
|
||||
)
|
||||
|
||||
const Usage = "usage: releasekit version\n releasekit check [--repo DIR] [--config FILE] VERSION\n releasekit publish [--repo DIR] [--config FILE] VERSION\n releasekit build [--repo DIR] [--config FILE] [--output DIR] VERSION\n releasekit deliver [--repo DIR] [--config FILE] [--assets DIR] VERSION\n releasekit ci-deliver [--repo DIR] [--config FILE] [--remote NAME] --commit OID VERSION"
|
||||
const Usage = "usage: releasekit version\n releasekit check [--repo DIR] [--config FILE] VERSION\n releasekit publish [--repo DIR] [--config FILE] [--expected-module DIR] VERSION\n releasekit build [--repo DIR] [--config FILE] [--output DIR] VERSION\n releasekit deliver [--repo DIR] [--config FILE] [--assets DIR] VERSION\n releasekit ci-deliver [--repo DIR] [--config FILE] [--remote NAME] --commit OID VERSION"
|
||||
|
||||
type Command string
|
||||
|
||||
@@ -31,14 +31,15 @@ const (
|
||||
|
||||
// Invocation contains parsed command settings owned by the CLI adapter.
|
||||
type Invocation struct {
|
||||
Command Command
|
||||
Repository string
|
||||
ConfigPath string
|
||||
OutputDir string
|
||||
AssetsDir string
|
||||
Remote string
|
||||
Commit string
|
||||
Version string
|
||||
Command Command
|
||||
Repository string
|
||||
ConfigPath string
|
||||
OutputDir string
|
||||
AssetsDir string
|
||||
Remote string
|
||||
Commit string
|
||||
Version string
|
||||
ExpectedModule string
|
||||
}
|
||||
|
||||
// Parse accepts only commands that have been implemented by the executable.
|
||||
@@ -67,6 +68,10 @@ func Parse(args []string) (Invocation, error) {
|
||||
flags.StringVar(&assetsDir, "assets", "", "verified build assets directory")
|
||||
}
|
||||
var remote *string
|
||||
expectedModule := ""
|
||||
if action == PublishAction {
|
||||
flags.StringVar(&expectedModule, "expected-module", "", "expected module directory from a launcher mapping")
|
||||
}
|
||||
expectedCommit := ""
|
||||
if action == CIDeliveryAction {
|
||||
remote = flags.String("remote", "origin", "Git remote")
|
||||
@@ -88,7 +93,7 @@ func Parse(args []string) (Invocation, error) {
|
||||
if remote != nil {
|
||||
parsedRemote = *remote
|
||||
}
|
||||
return Invocation{Command: action, Repository: *repository, ConfigPath: *configPath, OutputDir: outputDir, AssetsDir: assetsDir, Remote: parsedRemote, Commit: expectedCommit, Version: flags.Arg(0)}, nil
|
||||
return Invocation{Command: action, Repository: *repository, ConfigPath: *configPath, OutputDir: outputDir, AssetsDir: assetsDir, Remote: parsedRemote, Commit: expectedCommit, Version: flags.Arg(0), ExpectedModule: expectedModule}, nil
|
||||
default:
|
||||
return Invocation{}, fmt.Errorf("unknown command %q", args[0])
|
||||
}
|
||||
@@ -116,6 +121,7 @@ type CheckCommand struct {
|
||||
// validation selections, and check commands read from a releasekit.json profile.
|
||||
type Settings struct {
|
||||
Product string `json:"product"`
|
||||
ModuleDir string `json:"module_dir,omitempty"`
|
||||
Remote string `json:"remote,omitempty"`
|
||||
ExpectedPushURL string `json:"expected_push_url,omitempty"`
|
||||
Checks []CheckCommand `json:"checks,omitempty"`
|
||||
@@ -126,7 +132,10 @@ type Settings struct {
|
||||
|
||||
// ValidationSettings selects shared candidate checks in a release profile.
|
||||
type ValidationSettings struct {
|
||||
Go GoValidationSettings `json:"go,omitempty"`
|
||||
// SharedFiles selects committed files relative to the repository root.
|
||||
// Nil uses optional defaults; a non-nil empty slice selects no shared files.
|
||||
SharedFiles []string `json:"shared_files"`
|
||||
Go GoValidationSettings `json:"go,omitempty"`
|
||||
// GoFormat checks the formatting of committed regular Go source files.
|
||||
// Omitted or false disables the check.
|
||||
GoFormat bool `json:"go_format,omitempty"`
|
||||
@@ -269,9 +278,9 @@ func LoadSettings(repoDir, configPath string) (Settings, error) {
|
||||
return settings, nil
|
||||
}
|
||||
|
||||
// RunChecks runs configured argument vectors in repoDir. Each command receives
|
||||
// RunChecks runs configured argument vectors in dir. Each command receives
|
||||
// its own environment overlay and inherits the remaining process environment.
|
||||
func RunChecks(ctx context.Context, repoDir string, checks []CheckCommand, ownedEnv map[string]string, stdout, stderr io.Writer) error {
|
||||
func RunChecks(ctx context.Context, dir string, checks []CheckCommand, ownedEnv map[string]string, stdout, stderr io.Writer) error {
|
||||
for i, check := range checks {
|
||||
environment := make(map[string]string, len(check.Env)+len(ownedEnv))
|
||||
for key, value := range check.Env {
|
||||
@@ -282,7 +291,7 @@ func RunChecks(ctx context.Context, repoDir string, checks []CheckCommand, owned
|
||||
}
|
||||
if err := process.Run(ctx, process.Invocation{
|
||||
Args: check.Args,
|
||||
Dir: repoDir,
|
||||
Dir: dir,
|
||||
Env: environment,
|
||||
Stdout: stdout,
|
||||
Stderr: stderr,
|
||||
|
||||
@@ -33,6 +33,10 @@ func TestParse(t *testing.T) {
|
||||
if publish.Command != PublishAction || publish.Repository != "candidate" || publish.ConfigPath != "releasekit.json" || publish.Version != "v1.2.4" {
|
||||
t.Fatalf("Parse(publish) = %#v", publish)
|
||||
}
|
||||
publishMapped, err := Parse([]string{"publish", "--repo", "candidate", "--expected-module", "integrations/ckconfig", "v1.2.4"})
|
||||
if err != nil || publishMapped.ExpectedModule != "integrations/ckconfig" {
|
||||
t.Fatalf("Parse(publish --expected-module) = %#v, error = %v", publishMapped, err)
|
||||
}
|
||||
build, err := Parse([]string{"build", "--repo", "candidate", "--config", "releasekit.json", "--output", "output with spaces", "v1.2.5"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -166,6 +170,56 @@ func TestLoadSettingsReadsGoValidation(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadSettingsPreservesSharedFilesSelection(t *testing.T) {
|
||||
repoDir := t.TempDir()
|
||||
profileDir := filepath.Join(repoDir, "profiles")
|
||||
if err := os.MkdirAll(profileDir, 0o700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
profile string
|
||||
wantNil bool
|
||||
wantFile string
|
||||
}{
|
||||
{name: "omitted", profile: `{"product":"Example","module_dir":"integrations/ckconfig","validation":{}}`, wantNil: true},
|
||||
{name: "null", profile: `{"product":"Example","module_dir":"integrations/ckconfig","validation":{"shared_files":null}}`, wantNil: true},
|
||||
{name: "empty", profile: `{"product":"Example","module_dir":"integrations/ckconfig","validation":{"shared_files":[]}}`},
|
||||
{name: "selected", profile: `{"product":"Example","module_dir":"integrations/ckconfig","validation":{"shared_files":["../README.md"]}}`, wantFile: "../README.md"},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
path := filepath.Join(profileDir, "release.json")
|
||||
if err := os.WriteFile(path, []byte(test.profile), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
settings, err := LoadSettings(repoDir, filepath.Join("profiles", "release.json"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if settings.ModuleDir != "integrations/ckconfig" {
|
||||
t.Fatalf("module_dir = %q", settings.ModuleDir)
|
||||
}
|
||||
if settings.Validation == nil || (settings.Validation.SharedFiles == nil) != test.wantNil {
|
||||
t.Fatalf("shared_files = %#v, want nil=%t", settings.Validation, test.wantNil)
|
||||
}
|
||||
if test.wantFile != "" && (len(settings.Validation.SharedFiles) != 1 || settings.Validation.SharedFiles[0] != test.wantFile) {
|
||||
t.Fatalf("shared_files = %#v, want %q", settings.Validation.SharedFiles, test.wantFile)
|
||||
}
|
||||
encoded, err := json.Marshal(settings)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var roundTrip Settings
|
||||
if err := json.Unmarshal(encoded, &roundTrip); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if (roundTrip.Validation.SharedFiles == nil) != test.wantNil {
|
||||
t.Fatalf("serialized shared_files = %#v, want nil=%t; JSON=%s", roundTrip.Validation.SharedFiles, test.wantNil, encoded)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadSettingsPreservesMarkdownObjectSelection(t *testing.T) {
|
||||
repoDir := t.TempDir()
|
||||
profilePath := filepath.Join(repoDir, "releasekit.json")
|
||||
|
||||
Reference in New Issue
Block a user