Skip to content

Commit 1f288c8

Browse files
authored
build: specify full repo in repositories.yaml (#1818)
Towards #1778 Accompanies cl/799250047
1 parent 7ef0103 commit 1f288c8

File tree

8 files changed

+201
-12
lines changed

8 files changed

+201
-12
lines changed

infra/prod/generate.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ steps:
2121
args:
2222
- 'clone'
2323
- '--depth=1'
24-
- https://github.com/$_ORGANIZATION/$_REPOSITORY
24+
- $_FULL_REPOSITORY
2525
- name: gcr.io/cloud-builders/git
2626
id: configure-language-repo-name
2727
waitFor: ['clone-language-repo']

infra/prod/publish-release.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ steps:
2525
- '--depth=1'
2626
- '--single-branch'
2727
- '--branch=$_BRANCH'
28-
- https://github.com/googleapis/$_REPOSITORY
28+
- $_FULL_REPOSITORY
2929
- name: 'us-central1-docker.pkg.dev/cloud-sdk-librarian-prod/images-dev/librarian'
3030
id: publish-release
3131
waitFor: ['clone-language-repo']

infra/prod/stage-release.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ steps:
2323
args:
2424
- 'clone'
2525
- '--depth=1'
26-
- https://github.com/googleapis/$_REPOSITORY
26+
- $_FULL_REPOSITORY
2727
- name: gcr.io/cloud-builders/git
2828
id: clone-googleapis
2929
waitFor: ['-']

internal/automation/prod/repositories.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
repositories:
22
- name: "google-cloud-python"
3+
full-name: https://github.com/googleapis/google-cloud-python
34
github-token-secret-name: "google-cloud-python-github-token"
45
supported-commands:
56
- generate

internal/automation/repositories.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ var availableCommands = map[string]bool{
3535
// RepositoryConfig represents a single registered librarian GitHub repository.
3636
type RepositoryConfig struct {
3737
Name string `yaml:"name"`
38+
FullName string `yaml:"full-name"`
3839
SecretName string `yaml:"github-token-secret-name"`
3940
SupportedCommands []string `yaml:"supported-commands"`
4041
}
@@ -44,10 +45,21 @@ type RepositoriesConfig struct {
4445
Repositories []*RepositoryConfig `yaml:"repositories"`
4546
}
4647

48+
// GitURL returns the full git url to clone.
49+
func (c *RepositoryConfig) GitURL() (string, error) {
50+
if c.FullName == "" {
51+
if c.Name == "" {
52+
return "", fmt.Errorf("name or full name is required")
53+
}
54+
return fmt.Sprintf("https://github.com/googleapis/%s", c.Name), nil
55+
}
56+
return c.FullName, nil
57+
}
58+
4759
// Validate checks the the RepositoryConfig is valid.
4860
func (c *RepositoryConfig) Validate() error {
49-
if c.Name == "" {
50-
return fmt.Errorf("name is required")
61+
if c.FullName == "" && c.Name == "" {
62+
return fmt.Errorf("name or full name is required")
5163
}
5264
if c.SecretName == "" {
5365
return fmt.Errorf("secret name is required")

internal/automation/repositories_test.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,19 @@ func TestRepositoriesConfig_Validate(t *testing.T) {
3939
},
4040
wantErr: false,
4141
},
42+
{
43+
name: "valid full name",
44+
config: &RepositoriesConfig{
45+
Repositories: []*RepositoryConfig{
46+
{
47+
FullName: "https://github.com/googleapis/google-cloud-foo",
48+
SecretName: "google-cloud-foo-github-token",
49+
SupportedCommands: []string{"generate", "stage-release", "publish-release"},
50+
},
51+
},
52+
},
53+
wantErr: false,
54+
},
4255
{
4356
name: "missing name",
4457
config: &RepositoriesConfig{
@@ -136,6 +149,27 @@ func TestParseRepositoriesConfig(t *testing.T) {
136149
},
137150
},
138151
},
152+
{
153+
name: "valid state with full name",
154+
content: `repositories:
155+
- name: google-cloud-python
156+
full-name: https://github.com/some-org/google-cloud-python
157+
github-token-secret-name: google-cloud-python-github-token
158+
supported-commands:
159+
- generate
160+
- stage-release
161+
`,
162+
want: &RepositoriesConfig{
163+
Repositories: []*RepositoryConfig{
164+
{
165+
Name: "google-cloud-python",
166+
FullName: "https://github.com/some-org/google-cloud-python",
167+
SecretName: "google-cloud-python-github-token",
168+
SupportedCommands: []string{"generate", "stage-release"},
169+
},
170+
},
171+
},
172+
},
139173
{
140174
name: "invalid yaml",
141175
content: `repositories:
@@ -225,3 +259,55 @@ func TestRepositoriesForCommand(t *testing.T) {
225259
})
226260
}
227261
}
262+
263+
func TestRepositoryGitUrl(t *testing.T) {
264+
for _, test := range []struct {
265+
name string
266+
repository *RepositoryConfig
267+
want string
268+
wantError bool
269+
}{
270+
{
271+
name: "sets default organization",
272+
repository: &RepositoryConfig{
273+
Name: "google-cloud-python",
274+
},
275+
want: "https://github.com/googleapis/google-cloud-python",
276+
},
277+
{
278+
name: "reads full name",
279+
repository: &RepositoryConfig{
280+
FullName: "https://github.com/some-org/google-cloud-python",
281+
},
282+
want: "https://github.com/some-org/google-cloud-python",
283+
},
284+
{
285+
name: "prefers full name",
286+
repository: &RepositoryConfig{
287+
Name: "google-cloud-python",
288+
FullName: "https://github.com/some-org/google-cloud-python",
289+
},
290+
want: "https://github.com/some-org/google-cloud-python",
291+
},
292+
{
293+
name: "missing name",
294+
repository: &RepositoryConfig{
295+
Name: "google-cloud-python",
296+
FullName: "https://github.com/some-org/google-cloud-python",
297+
},
298+
want: "https://github.com/some-org/google-cloud-python",
299+
wantError: true,
300+
},
301+
} {
302+
t.Run(test.name, func(t *testing.T) {
303+
got, err := test.repository.GitURL()
304+
if err != nil && test.wantError {
305+
t.Errorf("expected to return error")
306+
return
307+
}
308+
if diff := cmp.Diff(test.want, got); diff != "" {
309+
t.Errorf("parseRepositoriesConfig() mismatch (-want +got): %s", diff)
310+
}
311+
})
312+
}
313+
}

internal/automation/trigger.go

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,15 @@ func RunCommand(ctx context.Context, command string, projectId string, push bool
7979
}
8080

8181
func runCommandWithClient(ctx context.Context, client CloudBuildClient, ghClient GitHubClient, command string, projectId string, push bool, build bool) error {
82+
config, err := loadRepositoriesConfig()
83+
if err != nil {
84+
slog.Error("error loading repositories config", slog.Any("err", err))
85+
return err
86+
}
87+
return runCommandWithConfig(ctx, client, ghClient, command, projectId, push, build, config)
88+
}
89+
90+
func runCommandWithConfig(ctx context.Context, client CloudBuildClient, ghClient GitHubClient, command string, projectId string, push bool, build bool, config *RepositoriesConfig) error {
8291
// validate command is allowed
8392
triggerName := triggerNameByCommandName[command]
8493
if triggerName == "" {
@@ -87,18 +96,19 @@ func runCommandWithClient(ctx context.Context, client CloudBuildClient, ghClient
8796

8897
errs := make([]error, 0)
8998

90-
config, err := loadRepositoriesConfig()
91-
if err != nil {
92-
slog.Error("error loading repositories config", slog.Any("err", err))
93-
return err
94-
}
95-
9699
repositories := config.RepositoriesForCommand(command)
97100
for _, repository := range repositories {
98-
slog.Debug("running command", slog.String("command", command), slog.String("repository", repository.Name))
101+
slog.Debug("running command", "command", command, "repository", repository.Name)
102+
103+
gitUrl, err := repository.GitURL()
104+
if err != nil {
105+
slog.Error("repository has no configured git url", slog.Any("repository", repository))
106+
return err
107+
}
99108

100109
substitutions := map[string]string{
101110
"_REPOSITORY": repository.Name,
111+
"_FULL_REPOSITORY": gitUrl,
102112
"_GITHUB_TOKEN_SECRET_NAME": repository.SecretName,
103113
"_PUSH": fmt.Sprintf("%v", push),
104114
}

internal/automation/trigger_test.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,3 +176,83 @@ func TestRunCommandWithClient(t *testing.T) {
176176
})
177177
}
178178
}
179+
180+
func TestRunCommandWithConfig(t *testing.T) {
181+
var buildTriggers = []*cloudbuildpb.BuildTrigger{
182+
{
183+
Name: "generate",
184+
Id: "generate-trigger-id",
185+
},
186+
{
187+
Name: "prepare-release",
188+
Id: "prepare-release-trigger-id",
189+
},
190+
}
191+
for _, test := range []struct {
192+
name string
193+
command string
194+
config *RepositoriesConfig
195+
want string
196+
runError error
197+
wantErr bool
198+
ghPRs []*github.PullRequest
199+
ghError error
200+
}{
201+
{
202+
name: "runs generate trigger with name",
203+
command: "generate",
204+
config: &RepositoriesConfig{
205+
Repositories: []*RepositoryConfig{
206+
{
207+
Name: "google-cloud-python",
208+
SupportedCommands: []string{"generate"},
209+
},
210+
},
211+
},
212+
wantErr: false,
213+
},
214+
{
215+
name: "runs generate trigger with full name",
216+
command: "generate",
217+
config: &RepositoriesConfig{
218+
Repositories: []*RepositoryConfig{
219+
{
220+
Name: "https://github.com/googleapis/google-cloud-python",
221+
SupportedCommands: []string{"generate"},
222+
},
223+
},
224+
},
225+
wantErr: false,
226+
},
227+
{
228+
name: "runs generate trigger without name",
229+
command: "generate",
230+
config: &RepositoriesConfig{
231+
Repositories: []*RepositoryConfig{
232+
{
233+
SupportedCommands: []string{"generate"},
234+
},
235+
},
236+
},
237+
wantErr: true,
238+
},
239+
} {
240+
t.Run(test.name, func(t *testing.T) {
241+
ctx := context.Background()
242+
client := &mockCloudBuildClient{
243+
runError: test.runError,
244+
buildTriggers: buildTriggers,
245+
}
246+
ghClient := &mockGitHubClient{
247+
prs: test.ghPRs,
248+
err: test.ghError,
249+
}
250+
err := runCommandWithConfig(ctx, client, ghClient, test.command, "some-project", true, true, test.config)
251+
if test.wantErr && err == nil {
252+
t.Errorf("expected error, but did not return one")
253+
} else if !test.wantErr && err != nil {
254+
t.Errorf("did not expect error, but received one: %s", err)
255+
}
256+
})
257+
}
258+
}

0 commit comments

Comments
 (0)