Skip to content

Commit 52250b9

Browse files
authored
feat(internal/librarian): add -f flag to skip binary version check (#3806)
At the moment, it isn't possible to test librarian using a different version than is in the librarian.yaml, because the tool always checks if the binary and librarian.yaml versions match. The -f flag is added which skips this check. Fixes #3800
1 parent c90de99 commit 52250b9

File tree

9 files changed

+117
-15
lines changed

9 files changed

+117
-15
lines changed

internal/librarian/add.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func addCommand() *cli.Command {
4646
if len(apis) == 0 {
4747
return errMissingAPI
4848
}
49-
cfg, err := loadConfig()
49+
cfg, err := loadConfig(ctx)
5050
if err != nil {
5151
return err
5252
}

internal/librarian/bump.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ Examples:
9292
if all && versionOverride != "" {
9393
return errBothVersionAndAllFlag
9494
}
95-
cfg, err := loadConfig()
95+
cfg, err := loadConfig(ctx)
9696
if err != nil {
9797
return err
9898
}

internal/librarian/generate.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ func generateCommand() *cli.Command {
6565
if all && libraryName != "" {
6666
return errBothLibraryAndAllFlag
6767
}
68-
cfg, err := loadConfig()
68+
cfg, err := loadConfig(ctx)
6969
if err != nil {
7070
return err
7171
}

internal/librarian/librarian.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import (
2828
// ErrLibraryNotFound is returned when the specified library is not found in config.
2929
var ErrLibraryNotFound = errors.New("library not found")
3030

31+
type skipVersionCheckKey struct{}
32+
3133
const (
3234
librarianConfigPath = "librarian.yaml"
3335
languageDart = "dart"
@@ -43,6 +45,11 @@ func Run(ctx context.Context, args ...string) error {
4345
Usage: "manage Google Cloud client libraries",
4446
UsageText: "librarian [command]",
4547
Flags: []cli.Flag{
48+
&cli.BoolFlag{
49+
Name: "force",
50+
Aliases: []string{"f"},
51+
Usage: "skip binary version check",
52+
},
4653
&cli.BoolFlag{
4754
Name: "verbose",
4855
Aliases: []string{"v"},
@@ -51,6 +58,7 @@ func Run(ctx context.Context, args ...string) error {
5158
},
5259
Before: func(ctx context.Context, cmd *cli.Command) (context.Context, error) {
5360
command.Verbose = cmd.Bool("verbose")
61+
ctx = context.WithValue(ctx, skipVersionCheckKey{}, cmd.Bool("force"))
5462
return ctx, nil
5563
},
5664
Commands: []*cli.Command{

internal/librarian/publish.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func publishCommand() *cli.Command {
5454
},
5555
},
5656
Action: func(ctx context.Context, cmd *cli.Command) error {
57-
cfg, err := loadConfig()
57+
cfg, err := loadConfig(ctx)
5858
if err != nil {
5959
return err
6060
}

internal/librarian/tidy.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func tidyCommand() *cli.Command {
3838
Usage: "format and validate librarian.yaml",
3939
UsageText: "librarian tidy [path]",
4040
Action: func(ctx context.Context, cmd *cli.Command) error {
41-
cfg, err := loadConfig()
41+
cfg, err := loadConfig(ctx)
4242
if err != nil {
4343
return err
4444
}

internal/librarian/update.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func updateCommand() *cli.Command {
7878
return fmt.Errorf("%w: %s", errUnknownSource, source)
7979
}
8080
}
81-
cfg, err := loadConfig()
81+
cfg, err := loadConfig(ctx)
8282
if err != nil {
8383
return err
8484
}

internal/librarian/version.go

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
package librarian
1616

1717
import (
18+
"context"
1819
_ "embed"
20+
"errors"
1921
"fmt"
2022
"runtime/debug"
2123
"strings"
@@ -25,6 +27,11 @@ import (
2527
"github.com/googleapis/librarian/internal/yaml"
2628
)
2729

30+
var (
31+
errNoConfigVersion = errors.New("librarian.yaml does not specify a version")
32+
errVersionMismatch = errors.New("version mismatch")
33+
)
34+
2835
//go:embed version.txt
2936
var versionString string
3037

@@ -67,31 +74,34 @@ func version(info *debug.BuildInfo) string {
6774
// loadConfig reads librarian.yaml and verifies that the librarian binary
6875
// version matches the version specified in the configuration file. It returns
6976
// the config and an error if the versions do not match. The check is skipped
70-
// if the binary version is "not available", which occurs during local
71-
// development without VCS info.
72-
func loadConfig() (*config.Config, error) {
77+
// if the -f flag is set or if the binary version is "not available", which
78+
// occurs during local development without VCS info.
79+
func loadConfig(ctx context.Context) (*config.Config, error) {
7380
cfg, err := yaml.Read[config.Config](librarianConfigPath)
7481
if err != nil {
7582
return nil, fmt.Errorf("%w: %w", errConfigNotFound, err)
7683
}
77-
if err := compareVersions(cfg.Version, Version()); err != nil {
78-
return nil, err
84+
if !skipVersionCheck(ctx) {
85+
if err := compareVersions(cfg.Version, Version()); err != nil {
86+
return nil, err
87+
}
7988
}
8089
return cfg, nil
8190
}
8291

8392
func compareVersions(configVersion, binaryVersion string) error {
8493
if configVersion == "" {
85-
return fmt.Errorf("librarian.yaml does not specify a version")
94+
return errNoConfigVersion
8695
}
8796
// Skip check for local builds, which have no version info.
8897
if binaryVersion == versionNotAvailable {
8998
return nil
9099
}
91100
if configVersion != binaryVersion {
92-
return fmt.Errorf(`binary version %s does not match librarian.yaml version %s
93-
go run github.com/googleapis/librarian/cmd/librarian@%s`,
94-
binaryVersion, configVersion, configVersion)
101+
return fmt.Errorf(`%w: binary version %s does not match librarian.yaml version %s
102+
go run github.com/googleapis/librarian/cmd/librarian@%s
103+
or use -f to skip this check`,
104+
errVersionMismatch, binaryVersion, configVersion, configVersion)
95105
}
96106
return nil
97107
}
@@ -134,3 +144,9 @@ func newPseudoVersion(info *debug.BuildInfo) string {
134144
}
135145
return buf.String()
136146
}
147+
148+
// skipVersionCheck returns true if the -f flag was set to skip version checking.
149+
func skipVersionCheck(ctx context.Context) bool {
150+
v, _ := ctx.Value(skipVersionCheckKey{}).(bool)
151+
return v
152+
}

internal/librarian/version_test.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
package librarian
1616

1717
import (
18+
"context"
19+
"errors"
1820
"fmt"
1921
"runtime/debug"
2022
"strings"
@@ -151,3 +153,79 @@ func TestNewPseudoVersion(t *testing.T) {
151153
})
152154
}
153155
}
156+
157+
func TestCompareVersions(t *testing.T) {
158+
for _, test := range []struct {
159+
name string
160+
configVersion string
161+
binaryVersion string
162+
wantErr error
163+
}{
164+
{
165+
name: "matching versions",
166+
configVersion: "v1.0.0",
167+
binaryVersion: "v1.0.0",
168+
},
169+
{
170+
name: "mismatched versions",
171+
configVersion: "v1.0.0",
172+
binaryVersion: "v2.0.0",
173+
wantErr: errVersionMismatch,
174+
},
175+
{
176+
name: "local build skips check",
177+
configVersion: "v1.0.0",
178+
binaryVersion: versionNotAvailable,
179+
},
180+
{
181+
name: "empty config version",
182+
configVersion: "",
183+
binaryVersion: "v1.0.0",
184+
wantErr: errNoConfigVersion,
185+
},
186+
} {
187+
t.Run(test.name, func(t *testing.T) {
188+
err := compareVersions(test.configVersion, test.binaryVersion)
189+
if !errors.Is(err, test.wantErr) {
190+
t.Errorf("got %v; want %v", err, test.wantErr)
191+
}
192+
})
193+
}
194+
}
195+
196+
func TestSkipVersionCheck(t *testing.T) {
197+
for _, test := range []struct {
198+
name string
199+
setKey bool
200+
value bool
201+
want bool
202+
}{
203+
{
204+
name: "key set to true",
205+
setKey: true,
206+
value: true,
207+
want: true,
208+
},
209+
{
210+
name: "key set to false",
211+
setKey: true,
212+
value: false,
213+
want: false,
214+
},
215+
{
216+
name: "key not set",
217+
setKey: false,
218+
want: false,
219+
},
220+
} {
221+
t.Run(test.name, func(t *testing.T) {
222+
ctx := t.Context()
223+
if test.setKey {
224+
ctx = context.WithValue(ctx, skipVersionCheckKey{}, test.value)
225+
}
226+
if got := skipVersionCheck(ctx); got != test.want {
227+
t.Errorf("got %v; want %v", got, test.want)
228+
}
229+
})
230+
}
231+
}

0 commit comments

Comments
 (0)