Skip to content

Commit 6dbc3c0

Browse files
authored
feat(internal/librarian): add a skeleton for release init (#1761)
Fixes #1655 Updates #1008
1 parent 6444b5f commit 6dbc3c0

File tree

18 files changed

+372
-88
lines changed

18 files changed

+372
-88
lines changed

internal/config/global_config.go renamed to internal/config/librarian_config.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ const (
2424
PermissionReadWrite = "read-write"
2525
)
2626

27-
// GlobalConfig defines the contract for the config.yaml file.
28-
type GlobalConfig struct {
27+
// LibrarianConfig defines the contract for the config.yaml file.
28+
type LibrarianConfig struct {
2929
GlobalFilesAllowlist []*GlobalFile `yaml:"global_files_allowlist"`
3030
}
3131

@@ -41,8 +41,8 @@ var validPermissions = map[string]bool{
4141
PermissionReadWrite: true,
4242
}
4343

44-
// Validate checks that the GlobalConfig is valid.
45-
func (g *GlobalConfig) Validate() error {
44+
// Validate checks that the LibrarianConfig is valid.
45+
func (g *LibrarianConfig) Validate() error {
4646
for i, globalFile := range g.GlobalFilesAllowlist {
4747
path, permissions := globalFile.Path, globalFile.Permissions
4848
if !isValidDirPath(path) {

internal/config/global_config_test.go renamed to internal/config/librarian_config_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ import (
2222
func TestGlobalConfig_Validate(t *testing.T) {
2323
for _, test := range []struct {
2424
name string
25-
config *GlobalConfig
25+
config *LibrarianConfig
2626
wantErr bool
2727
wantErrMsg string
2828
}{
2929
{
3030
name: "valid config",
31-
config: &GlobalConfig{
31+
config: &LibrarianConfig{
3232
GlobalFilesAllowlist: []*GlobalFile{
3333
{
3434
Path: "a/path",
@@ -47,7 +47,7 @@ func TestGlobalConfig_Validate(t *testing.T) {
4747
},
4848
{
4949
name: "invalid path in config",
50-
config: &GlobalConfig{
50+
config: &LibrarianConfig{
5151
GlobalFilesAllowlist: []*GlobalFile{
5252
{
5353
Path: "a/path",
@@ -64,7 +64,7 @@ func TestGlobalConfig_Validate(t *testing.T) {
6464
},
6565
{
6666
name: "invalid permission in config",
67-
config: &GlobalConfig{
67+
config: &LibrarianConfig{
6868
GlobalFilesAllowlist: []*GlobalFile{
6969
{
7070
Path: "a/path",

internal/config/state.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ type LibraryState struct {
112112
// permitted to reference the values configured in the library. If not specified
113113
// the assumed format is {id}-{version}. e.g., {id}/v{version}.
114114
TagFormat string `yaml:"tag_format,omitempty" json:"tag_format,omitempty"`
115+
// Whether including this library in a release.
116+
// This field is ignored when writing to state.yaml.
117+
ReleaseTriggered bool `yaml:"-" json:"release_triggered,omitempty"`
115118
// An error message from the docker response.
116119
// This field is ignored when writing to state.yaml.
117120
ErrorMessage string `yaml:"-" json:"error,omitempty"`

internal/docker/docker.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -116,15 +116,15 @@ type GenerateRequest struct {
116116
RepoDir string
117117
}
118118

119-
// ReleaseRequest contains all the information required for a language
120-
// container to run the release command.
121-
type ReleaseRequest struct {
119+
// ReleaseInitRequest contains all the information required for a language
120+
// container to run the init command.
121+
type ReleaseInitRequest struct {
122122
// Cfg is a pointer to the [config.Config] struct, holding general configuration
123123
// values parsed from flags or environment variables.
124124
Cfg *config.Config
125-
// GlobalConfig is a pointer to the [config.GlobalConfig] struct, holding
125+
// LibrarianConfig is a pointer to the [config.LibrarianConfig] struct, holding
126126
// global files configuration in a language repository.
127-
GlobalConfig *config.GlobalConfig
127+
LibrarianConfig *config.LibrarianConfig
128128
// State is a pointer to the [config.LibrarianState] struct, representing
129129
// the overall state of the generation and release pipeline.
130130
State *config.LibrarianState
@@ -252,7 +252,7 @@ func (c *Docker) Configure(ctx context.Context, request *ConfigureRequest) (stri
252252
}
253253

254254
// ReleaseInit initiates a release for a given language repository.
255-
func (c *Docker) ReleaseInit(ctx context.Context, request *ReleaseRequest) error {
255+
func (c *Docker) ReleaseInit(ctx context.Context, request *ReleaseInitRequest) error {
256256
requestFilePath := filepath.Join(request.Cfg.Repo, config.LibrarianDir, config.ReleaseInitRequest)
257257
if err := writeLibrarianState(request.State, requestFilePath); err != nil {
258258
return err
@@ -348,15 +348,15 @@ func (c *Docker) runCommand(cmdName string, args ...string) error {
348348
}
349349

350350
// setupPartialRepo copies the following files from the [config.Config.Repo] to
351-
// partialRepoDir in the given ReleaseRequest:
351+
// partialRepoDir in the given ReleaseInitRequest:
352352
//
353353
// 1. all directories that make up all libraries, or one library, if the library
354354
// ID is specified.
355355
//
356356
// 2. the .librarian directory.
357357
//
358358
// 3. global files declared in config.yaml.
359-
func setupPartialRepo(request *ReleaseRequest) error {
359+
func setupPartialRepo(request *ReleaseInitRequest) error {
360360
if request.partialRepoDir == "" {
361361
request.partialRepoDir = filepath.Join(request.Cfg.WorkRoot, "release-init")
362362
}
@@ -391,8 +391,8 @@ func setupPartialRepo(request *ReleaseRequest) error {
391391
return fmt.Errorf("failed to copy librarian dir to %s: %w", dst, err)
392392
}
393393

394-
// Copy global files declared in global config.
395-
for _, globalFile := range request.GlobalConfig.GlobalFilesAllowlist {
394+
// Copy global files declared in librarian config.
395+
for _, globalFile := range request.LibrarianConfig.GlobalFilesAllowlist {
396396
dstPath := filepath.Join(dst, globalFile.Path)
397397
srcPath := filepath.Join(src, globalFile.Path)
398398
if err := copyFile(dstPath, srcPath); err != nil {

internal/docker/docker_test.go

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -383,14 +383,14 @@ func TestDockerRun(t *testing.T) {
383383
t.Fatal(err)
384384
}
385385

386-
releaseInitRequest := &ReleaseRequest{
386+
releaseInitRequest := &ReleaseInitRequest{
387387
Cfg: &config.Config{
388388
Repo: repoDir,
389389
},
390-
State: state,
391-
Output: testOutput,
392-
GlobalConfig: &config.GlobalConfig{},
393-
partialRepoDir: partialRepoDir,
390+
State: state,
391+
Output: testOutput,
392+
LibrarianConfig: &config.LibrarianConfig{},
393+
partialRepoDir: partialRepoDir,
394394
}
395395

396396
defer os.RemoveAll(partialRepoDir)
@@ -420,14 +420,14 @@ func TestDockerRun(t *testing.T) {
420420
t.Fatal(err)
421421
}
422422

423-
releaseInitRequest := &ReleaseRequest{
423+
releaseInitRequest := &ReleaseInitRequest{
424424
Cfg: &config.Config{
425425
Repo: repoDir,
426426
},
427-
State: state,
428-
partialRepoDir: partialRepoDir,
429-
Output: testOutput,
430-
GlobalConfig: &config.GlobalConfig{},
427+
State: state,
428+
partialRepoDir: partialRepoDir,
429+
Output: testOutput,
430+
LibrarianConfig: &config.LibrarianConfig{},
431431
}
432432
defer os.RemoveAll(partialRepoDir)
433433

@@ -442,7 +442,7 @@ func TestDockerRun(t *testing.T) {
442442
Image: mockImage,
443443
},
444444
runCommand: func(ctx context.Context, d *Docker) error {
445-
releaseInitRequest := &ReleaseRequest{
445+
releaseInitRequest := &ReleaseInitRequest{
446446
Cfg: &config.Config{
447447
Repo: os.TempDir(),
448448
},
@@ -466,15 +466,15 @@ func TestDockerRun(t *testing.T) {
466466
if err := os.MkdirAll(filepath.Join(repoDir, config.LibrarianDir), 0755); err != nil {
467467
t.Fatal(err)
468468
}
469-
releaseInitRequest := &ReleaseRequest{
469+
releaseInitRequest := &ReleaseInitRequest{
470470
Cfg: &config.Config{
471471
Repo: repoDir,
472472
},
473-
State: state,
474-
partialRepoDir: partialRepoDir,
475-
Output: testOutput,
476-
LibraryID: testLibraryID,
477-
GlobalConfig: &config.GlobalConfig{},
473+
State: state,
474+
partialRepoDir: partialRepoDir,
475+
Output: testOutput,
476+
LibraryID: testLibraryID,
477+
LibrarianConfig: &config.LibrarianConfig{},
478478
}
479479
defer os.RemoveAll(partialRepoDir)
480480

@@ -504,16 +504,16 @@ func TestDockerRun(t *testing.T) {
504504
t.Fatal(err)
505505
}
506506

507-
releaseInitRequest := &ReleaseRequest{
507+
releaseInitRequest := &ReleaseInitRequest{
508508
Cfg: &config.Config{
509509
Repo: os.TempDir(),
510510
},
511-
State: state,
512-
partialRepoDir: partialRepoDir,
513-
Output: testOutput,
514-
LibraryID: testLibraryID,
515-
LibraryVersion: "1.2.3",
516-
GlobalConfig: &config.GlobalConfig{},
511+
State: state,
512+
partialRepoDir: partialRepoDir,
513+
Output: testOutput,
514+
LibraryID: testLibraryID,
515+
LibraryVersion: "1.2.3",
516+
LibrarianConfig: &config.LibrarianConfig{},
517517
}
518518
defer os.RemoveAll(partialRepoDir)
519519

@@ -568,15 +568,15 @@ func TestPartialCopyRepo(t *testing.T) {
568568
t.Parallel()
569569
for _, test := range []struct {
570570
name string
571-
request *ReleaseRequest
571+
request *ReleaseInitRequest
572572
includedFiles []string
573573
excludedFiles []string
574574
wantErr bool
575575
wantErrMsg string
576576
}{
577577
{
578578
name: "copy all libraries and required files to partial repo",
579-
request: &ReleaseRequest{
579+
request: &ReleaseInitRequest{
580580
Cfg: &config.Config{
581581
Repo: filepath.Join(os.TempDir(), "repo"),
582582
},
@@ -599,7 +599,7 @@ func TestPartialCopyRepo(t *testing.T) {
599599
},
600600
},
601601
partialRepoDir: filepath.Join(os.TempDir(), "partial-repo"),
602-
GlobalConfig: &config.GlobalConfig{
602+
LibrarianConfig: &config.LibrarianConfig{
603603
GlobalFilesAllowlist: []*config.GlobalFile{
604604
{
605605
Path: "read/one.txt",
@@ -630,7 +630,7 @@ func TestPartialCopyRepo(t *testing.T) {
630630
},
631631
{
632632
name: "copy one library and required files to partial repo",
633-
request: &ReleaseRequest{
633+
request: &ReleaseInitRequest{
634634
Cfg: &config.Config{
635635
Repo: filepath.Join(os.TempDir(), "repo"),
636636
},
@@ -654,7 +654,7 @@ func TestPartialCopyRepo(t *testing.T) {
654654
},
655655
},
656656
partialRepoDir: filepath.Join(os.TempDir(), "partial-repo"),
657-
GlobalConfig: &config.GlobalConfig{
657+
LibrarianConfig: &config.LibrarianConfig{
658658
GlobalFilesAllowlist: []*config.GlobalFile{
659659
{
660660
Path: "read/one.txt",
@@ -686,7 +686,7 @@ func TestPartialCopyRepo(t *testing.T) {
686686
},
687687
{
688688
name: "copy one library with empty initial directory",
689-
request: &ReleaseRequest{
689+
request: &ReleaseInitRequest{
690690
Cfg: &config.Config{
691691
Repo: filepath.Join(os.TempDir(), "repo"),
692692
WorkRoot: filepath.Join(os.TempDir(), time.Now().String()),
@@ -710,7 +710,7 @@ func TestPartialCopyRepo(t *testing.T) {
710710
},
711711
},
712712
},
713-
GlobalConfig: &config.GlobalConfig{
713+
LibrarianConfig: &config.LibrarianConfig{
714714
GlobalFilesAllowlist: []*config.GlobalFile{},
715715
},
716716
},
@@ -726,7 +726,7 @@ func TestPartialCopyRepo(t *testing.T) {
726726
},
727727
{
728728
name: "invalid partial repo dir",
729-
request: &ReleaseRequest{
729+
request: &ReleaseInitRequest{
730730
Cfg: &config.Config{
731731
Repo: os.TempDir(),
732732
},
@@ -737,7 +737,7 @@ func TestPartialCopyRepo(t *testing.T) {
737737
},
738738
{
739739
name: "invalid source repo dir",
740-
request: &ReleaseRequest{
740+
request: &ReleaseInitRequest{
741741
Cfg: &config.Config{
742742
Repo: "/non-existent-path",
743743
},
@@ -1167,7 +1167,7 @@ func TestDocker_runCommand(t *testing.T) {
11671167
}
11681168
}
11691169

1170-
func prepareRepo(t *testing.T, request *ReleaseRequest) error {
1170+
func prepareRepo(t *testing.T, request *ReleaseInitRequest) error {
11711171
t.Helper()
11721172
emptyFilename := "empty.txt"
11731173
repo := request.Cfg.Repo
@@ -1192,7 +1192,7 @@ func prepareRepo(t *testing.T, request *ReleaseRequest) error {
11921192
return err
11931193
}
11941194
// Create global files.
1195-
for _, globalFile := range request.GlobalConfig.GlobalFilesAllowlist {
1195+
for _, globalFile := range request.LibrarianConfig.GlobalFilesAllowlist {
11961196
filename := filepath.Join(repo, globalFile.Path)
11971197
if err := os.MkdirAll(filepath.Dir(filename), 0755); err != nil {
11981198
return err

internal/librarian/command.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ type commandRunner struct {
3636
repo gitrepo.Repository
3737
sourceRepo gitrepo.Repository
3838
state *config.LibrarianState
39+
librarianConfig *config.LibrarianConfig
3940
ghClient GitHubClient
4041
containerClient ContainerClient
4142
workRoot string
@@ -64,6 +65,12 @@ func newCommandRunner(cfg *config.Config) (*commandRunner, error) {
6465
if err != nil {
6566
return nil, err
6667
}
68+
69+
librarianConfig, err := loadLibrarianConfig(languageRepo)
70+
if err != nil {
71+
return nil, err
72+
}
73+
6774
image := deriveImage(cfg.Image, state)
6875

6976
var gitRepo *github.Repository
@@ -93,6 +100,7 @@ func newCommandRunner(cfg *config.Config) (*commandRunner, error) {
93100
repo: languageRepo,
94101
sourceRepo: sourceRepo,
95102
state: state,
103+
librarianConfig: librarianConfig,
96104
image: image,
97105
ghClient: ghClient,
98106
containerClient: container,

internal/librarian/flags.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,18 @@ func addFlagLibrary(fs *flag.FlagSet, cfg *config.Config) {
4545
fs.StringVar(&cfg.Library, "library", "", "The ID of a single library to update")
4646
}
4747

48+
func addFlagLibraryVersion(fs *flag.FlagSet, cfg *config.Config) {
49+
fs.StringVar(&cfg.LibraryVersion, "library-version", "", "the library version to release. Requires the --library flag to be specified.")
50+
}
51+
52+
func addFlagPR(fs *flag.FlagSet, cfg *config.Config) {
53+
fs.StringVar(&cfg.PullRequest, "pr", "", "a pull request to operate on. It should be in the format of a uri https://github.com/{owner}/{repo}/pull/{number}. If not specified, will search for all merged pull requests with the label `release:pending` in the last 30 days.")
54+
}
55+
56+
func addFlagPush(fs *flag.FlagSet, cfg *config.Config) {
57+
fs.BoolVar(&cfg.Push, "push", false, "whether to push the generated code")
58+
}
59+
4860
func addFlagRepo(fs *flag.FlagSet, cfg *config.Config) {
4961
fs.StringVar(&cfg.Repo, "repo", "",
5062
`Code repository where the generated code will reside.
@@ -58,11 +70,3 @@ func addFlagRepo(fs *flag.FlagSet, cfg *config.Config) {
5870
func addFlagWorkRoot(fs *flag.FlagSet, cfg *config.Config) {
5971
fs.StringVar(&cfg.WorkRoot, "output", "", "Working directory root. When this is not specified, a working directory will be created in /tmp.")
6072
}
61-
62-
func addFlagPR(fs *flag.FlagSet, cfg *config.Config) {
63-
fs.StringVar(&cfg.PullRequest, "pr", "", "a pull request to operate on. It should be in the format of a uri https://github.com/{owner}/{repo}/pull/{number}. If not specified, will search for all merged pull requests with the label `release:pending` in the last 30 days.")
64-
}
65-
66-
func addFlagPush(fs *flag.FlagSet, cfg *config.Config) {
67-
fs.BoolVar(&cfg.Push, "push", false, "whether to push the generated code")
68-
}

0 commit comments

Comments
 (0)