Skip to content

Commit b06989f

Browse files
authored
fix(internal/librarian): make repo flag optional and derive from cwd when applicable (#1522)
Make repo flag optional, removing required flag validation. Add logic to derive from current working directory when there is librarian state file detected, otherwise, return error. Fixes: #1516
1 parent 3089ed5 commit b06989f

File tree

4 files changed

+82
-18
lines changed

4 files changed

+82
-18
lines changed

internal/librarian/command.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,22 @@ import (
3030
"github.com/googleapis/librarian/internal/gitrepo"
3131
)
3232

33+
func deriveRepoPath(repoFlag string) (string, error) {
34+
if repoFlag != "" {
35+
return repoFlag, nil
36+
}
37+
wd, err := os.Getwd()
38+
if err != nil {
39+
return "", fmt.Errorf("getting working directory: %w", err)
40+
}
41+
stateFile := filepath.Join(wd, config.LibrarianDir, pipelineStateFile)
42+
if _, err := os.Stat(stateFile); err != nil {
43+
return "", fmt.Errorf("repo flag not specified and no state file found in current working directory: %w", err)
44+
}
45+
slog.Info("repo not specified, using current working directory as repo root", "path", wd)
46+
return wd, nil
47+
}
48+
3349
func cloneOrOpenLanguageRepo(workRoot, repo, ci string) (*gitrepo.LocalRepository, error) {
3450
if repo == "" {
3551
return nil, errors.New("repo must be specified")

internal/librarian/command_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,61 @@ func TestCommandUsage(t *testing.T) {
5050
}
5151
}
5252

53+
func TestDeriveRepoPath(t *testing.T) {
54+
for _, test := range []struct {
55+
name string
56+
repoPath string
57+
setup func(t *testing.T, dir string)
58+
wantErr bool
59+
wantRepoPath string
60+
}{
61+
{
62+
name: "repo path provided",
63+
repoPath: "/some/path",
64+
wantRepoPath: "/some/path",
65+
},
66+
{
67+
name: "empty repo path, state file exists",
68+
setup: func(t *testing.T, dir string) {
69+
stateDir := filepath.Join(dir, config.LibrarianDir)
70+
if err := os.MkdirAll(stateDir, 0755); err != nil {
71+
t.Fatal(err)
72+
}
73+
stateFile := filepath.Join(stateDir, pipelineStateFile)
74+
if err := os.WriteFile(stateFile, []byte("test"), 0644); err != nil {
75+
t.Fatal(err)
76+
}
77+
},
78+
},
79+
{
80+
name: "empty repo path, no state file",
81+
wantErr: true,
82+
},
83+
} {
84+
t.Run(test.name, func(t *testing.T) {
85+
tmpDir := t.TempDir()
86+
if test.setup != nil {
87+
test.setup(t, tmpDir)
88+
}
89+
t.Chdir(tmpDir)
90+
91+
gotRepoPath, err := deriveRepoPath(test.repoPath)
92+
if (err != nil) != test.wantErr {
93+
t.Errorf("deriveRepoPath() error = %v, wantErr %v", err, test.wantErr)
94+
return
95+
}
96+
97+
wantPath := test.wantRepoPath
98+
if wantPath == "" && !test.wantErr {
99+
wantPath = tmpDir
100+
}
101+
102+
if diff := cmp.Diff(wantPath, gotRepoPath); diff != "" {
103+
t.Errorf("deriveRepoPath() mismatch (-want +got):\n%s", diff)
104+
}
105+
})
106+
}
107+
}
53108
func TestFindLibraryByID(t *testing.T) {
54109
lib1 := &config.LibraryState{ID: "lib1"}
55110
lib2 := &config.LibraryState{ID: "lib2"}

internal/librarian/flags.go

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -52,28 +52,18 @@ func addFlagPushConfig(fs *flag.FlagSet, cfg *config.Config) {
5252

5353
func addFlagRepo(fs *flag.FlagSet, cfg *config.Config) {
5454
fs.StringVar(&cfg.Repo, "repo", "",
55-
"Code repository where the generated code will reside. "+
56-
"Can be a remote in the format of a remote URL such as "+
57-
"https://github.com/{owner}/{repo} or a local file path like "+
58-
"/path/to/repo`. Both absolute and relative paths are supported.")
55+
`Code repository where the generated code will reside.
56+
Can be a remote in the format of a remote URL such as
57+
https://github.com/{owner}/{repo} or a local file path like
58+
/path/to/repo. Both absolute and relative paths are supported.
59+
If not specified, will try to detect if the current working
60+
directory is configured as a language repository.`)
5961
}
6062

6163
func addFlagWorkRoot(fs *flag.FlagSet, cfg *config.Config) {
6264
fs.StringVar(&cfg.WorkRoot, "output", "", "Working directory root. When this is not specified, a working directory will be created in /tmp.")
6365
}
6466

65-
// validateRequiredFlag validates that the flag with the given name has been provided.
66-
// TODO(https://github.com/googleapis/librarian/issues/488): add support for required string flags
67-
// We should rework how we add flags so that these can be validated before we even
68-
// start executing the command. (At least for simple cases where a flag is required;
69-
// note that this isn't always going to be the same for all commands for one flag.)
70-
func validateRequiredFlag(name, value string) error {
71-
if value == "" {
72-
return fmt.Errorf("required flag -%s not specified", name)
73-
}
74-
return nil
75-
}
76-
7767
// validatePushConfigAndGithubTokenCoexist validates that the github token should exist if pushConfig flag is set.
7868
func validatePushConfigAndGithubTokenCoexist(pushConfig, gitHubToken string) error {
7969
if pushConfig != "" && gitHubToken == "" {

internal/librarian/generate.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"encoding/json"
2121
"errors"
2222
"fmt"
23-
"gopkg.in/yaml.v3"
2423
"io/fs"
2524
"log/slog"
2625
"os"
@@ -30,6 +29,8 @@ import (
3029
"strings"
3130
"time"
3231

32+
"gopkg.in/yaml.v3"
33+
3334
"github.com/googleapis/librarian/internal/cli"
3435
"github.com/googleapis/librarian/internal/config"
3536
"github.com/googleapis/librarian/internal/docker"
@@ -102,9 +103,11 @@ type generateRunner struct {
102103
}
103104

104105
func newGenerateRunner(cfg *config.Config) (*generateRunner, error) {
105-
if err := validateRequiredFlag("repo", cfg.Repo); err != nil {
106+
repoPath, err := deriveRepoPath(cfg.Repo)
107+
if err != nil {
106108
return nil, err
107109
}
110+
cfg.Repo = repoPath
108111
if err := validatePushConfigAndGithubTokenCoexist(cfg.PushConfig, cfg.GitHubToken); err != nil {
109112
return nil, err
110113
}

0 commit comments

Comments
 (0)