Skip to content

Commit 1d68698

Browse files
authored
feat: Stage release with forceRun flag. Check cloudBuild trigger with triggersRun variable (#2150)
Stage release job with forceRun flag. By default Stage release job will only be run on odd weeks, and forceRun flag is False. If forceRun is True, Stage release job can be run on even weeks. Check cloudBuild trigger with triggersRun variable #2060
1 parent 8062cf7 commit 1d68698

File tree

6 files changed

+240
-63
lines changed

6 files changed

+240
-63
lines changed

infra/prod/stage-release-worker.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ steps:
2424
- '--project=$PROJECT_ID'
2525
- '--command=stage-release'
2626
- '--push=$_PUSH'
27+
- '--force-run=$_FORCE_RUN'
2728
tags: ['stage-release-dispatcher']
2829
availableSecrets:
2930
options:

internal/automation/cli.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ import (
2020
"log/slog"
2121
)
2222

23+
// runCommandFn is a function type that matches RunCommand, for mocking in tests.
24+
var runCommandFn = RunCommand
25+
2326
// Run parses the command line arguments and triggers the specified command.
2427
func Run(args []string) error {
2528
ctx := context.Background()
@@ -29,7 +32,7 @@ func Run(args []string) error {
2932
return err
3033
}
3134

32-
err = RunCommand(ctx, options.Command, options.ProjectId, options.Push, options.Build)
35+
err = runCommandFn(ctx, options.Command, options.ProjectId, options.Push, options.Build, options.ForceRun)
3336
if err != nil {
3437
slog.Error("Error running command", slog.Any("err", err))
3538
return err
@@ -42,6 +45,7 @@ type runOptions struct {
4245
ProjectId string
4346
Push bool
4447
Build bool
48+
ForceRun bool
4549
}
4650

4751
func parseFlags(args []string) (*runOptions, error) {
@@ -50,6 +54,7 @@ func parseFlags(args []string) (*runOptions, error) {
5054
command := flagSet.String("command", "generate", "The librarian command to run")
5155
push := flagSet.Bool("push", true, "The _PUSH flag (true/false) to Librarian CLI's -push option")
5256
build := flagSet.Bool("build", true, "The _BUILD flag (true/false) to Librarian CLI's -build option")
57+
forceRun := flagSet.Bool("force-run", false, "The _FORCE_RUN flag (true/false) to Librarian CLI's -force-run option")
5358
err := flagSet.Parse(args)
5459
if err != nil {
5560
return nil, err
@@ -59,5 +64,6 @@ func parseFlags(args []string) (*runOptions, error) {
5964
Command: *command,
6065
Push: *push,
6166
Build: *build,
67+
ForceRun: *forceRun,
6268
}, nil
6369
}

internal/automation/cli_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,50 @@
1515
package automation
1616

1717
import (
18+
"context"
19+
"errors"
1820
"testing"
1921

2022
"github.com/google/go-cmp/cmp"
2123
)
2224

25+
func TestRun(t *testing.T) {
26+
27+
tests := []struct {
28+
name string
29+
args []string
30+
runCommandErr error
31+
wantErr bool
32+
}{
33+
{
34+
name: "success",
35+
args: []string{"--command=generate"},
36+
wantErr: false,
37+
},
38+
{
39+
name: "error parsing flags",
40+
args: []string{"--unknown-flag"},
41+
wantErr: true,
42+
},
43+
{
44+
name: "error from RunCommand",
45+
args: []string{"--command=generate"},
46+
runCommandErr: errors.New("run command failed"),
47+
wantErr: true,
48+
},
49+
}
50+
for _, tt := range tests {
51+
t.Run(tt.name, func(t *testing.T) {
52+
runCommandFn = func(ctx context.Context, command string, projectId string, push bool, build bool, forceRun bool) error {
53+
return tt.runCommandErr
54+
}
55+
if err := Run(tt.args); (err != nil) != tt.wantErr {
56+
t.Errorf("Run() error = %v, wantErr %v", err, tt.wantErr)
57+
}
58+
})
59+
}
60+
}
61+
2362
func TestParseArgs(t *testing.T) {
2463
for _, test := range []struct {
2564
name string
@@ -36,6 +75,7 @@ func TestParseArgs(t *testing.T) {
3675
ProjectId: "cloud-sdk-librarian-prod",
3776
Push: true,
3877
Build: true,
78+
ForceRun: false,
3979
},
4080
},
4181
{
@@ -47,6 +87,7 @@ func TestParseArgs(t *testing.T) {
4787
ProjectId: "some-project-id",
4888
Push: true,
4989
Build: true,
90+
ForceRun: false,
5091
},
5192
},
5293
{
@@ -58,6 +99,7 @@ func TestParseArgs(t *testing.T) {
5899
ProjectId: "cloud-sdk-librarian-prod",
59100
Push: true,
60101
Build: true,
102+
ForceRun: false,
61103
},
62104
},
63105
{
@@ -69,6 +111,7 @@ func TestParseArgs(t *testing.T) {
69111
ProjectId: "cloud-sdk-librarian-prod",
70112
Push: false,
71113
Build: true,
114+
ForceRun: false,
72115
},
73116
},
74117
{
@@ -80,6 +123,19 @@ func TestParseArgs(t *testing.T) {
80123
ProjectId: "cloud-sdk-librarian-prod",
81124
Push: true,
82125
Build: false,
126+
ForceRun: false,
127+
},
128+
},
129+
{
130+
name: "sets forceRun",
131+
args: []string{"--force-run=true"},
132+
wantErr: false,
133+
want: &runOptions{
134+
Command: "generate",
135+
ProjectId: "cloud-sdk-librarian-prod",
136+
Push: true,
137+
Build: true,
138+
ForceRun: true,
83139
},
84140
},
85141
} {

internal/automation/cloudbuild_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,20 @@ import (
2929
type mockCloudBuildClient struct {
3030
runError error
3131
buildTriggers []*cloudbuildpb.BuildTrigger
32+
triggersRun []string
3233
}
3334

3435
func (c *mockCloudBuildClient) RunBuildTrigger(ctx context.Context, req *cloudbuildpb.RunBuildTriggerRequest, opts ...gax.CallOption) error {
3536
slog.Info("running fake RunBuildTrigger")
3637
if c.runError != nil {
3738
return c.runError
3839
}
40+
for _, t := range c.triggersRun {
41+
if t == req.TriggerId {
42+
return nil
43+
}
44+
}
45+
c.triggersRun = append(c.triggersRun, req.TriggerId)
3946
return nil
4047
}
4148

internal/automation/trigger.go

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"log/slog"
2323
"os"
2424
"strings"
25+
"time"
2526

2627
cloudbuild "cloud.google.com/go/cloudbuild/apiv1/v2"
2728
"cloud.google.com/go/cloudbuild/apiv1/v2/cloudbuildpb"
@@ -63,7 +64,7 @@ func (c *wrappedCloudBuildClient) ListBuildTriggers(ctx context.Context, req *cl
6364
}
6465

6566
// RunCommand triggers a command for each registered repository that supports it.
66-
func RunCommand(ctx context.Context, command string, projectId string, push bool, build bool) error {
67+
func RunCommand(ctx context.Context, command string, projectId string, push bool, build bool, forceRun bool) error {
6768
c, err := cloudbuild.NewClient(ctx)
6869
if err != nil {
6970
return fmt.Errorf("error creating cloudbuild client: %w", err)
@@ -76,25 +77,32 @@ func RunCommand(ctx context.Context, command string, projectId string, push bool
7677
if err != nil {
7778
return fmt.Errorf("error creating github client: %w", err)
7879
}
79-
return runCommandWithClient(ctx, wrappedClient, ghClient, command, projectId, push, build)
80+
return runCommandWithClient(ctx, wrappedClient, ghClient, command, projectId, push, build, forceRun, time.Now())
8081
}
8182

82-
func runCommandWithClient(ctx context.Context, client CloudBuildClient, ghClient GitHubClient, command string, projectId string, push bool, build bool) error {
83+
func runCommandWithClient(ctx context.Context, client CloudBuildClient, ghClient GitHubClient, command string, projectId string, push bool, build bool, forceRun bool, dateTime time.Time) error {
8384
config, err := loadRepositoriesConfig()
8485
if err != nil {
8586
slog.Error("error loading repositories config", slog.Any("err", err))
8687
return err
8788
}
88-
return runCommandWithConfig(ctx, client, ghClient, command, projectId, push, build, config)
89+
return runCommandWithConfig(ctx, client, ghClient, command, projectId, push, build, forceRun, config, dateTime)
8990
}
9091

91-
func runCommandWithConfig(ctx context.Context, client CloudBuildClient, ghClient GitHubClient, command string, projectId string, push bool, build bool, config *RepositoriesConfig) error {
92+
func runCommandWithConfig(ctx context.Context, client CloudBuildClient, ghClient GitHubClient, command string, projectId string, push bool, build bool, forceRun bool, config *RepositoriesConfig, dateTime time.Time) error {
9293
// validate command is allowed
9394
triggerName := triggerNameByCommandName[command]
9495
if triggerName == "" {
95-
return fmt.Errorf("unsuppoted command: %s", command)
96+
return fmt.Errorf("unsupported command: %s", command)
9697
}
9798

99+
if triggerName == "stage-release" {
100+
_, week := dateTime.ISOWeek()
101+
if week%2 == 0 && !forceRun {
102+
slog.Info("Skipping stage-release on an even week.")
103+
return nil
104+
}
105+
}
98106
errs := make([]error, 0)
99107

100108
repositories := config.RepositoriesForCommand(command)

0 commit comments

Comments
 (0)