Skip to content

Commit bd087bc

Browse files
authored
fix: only release libraries if something has changed since last release (#3339)
Add logic to generic release command that if --all flag is specified only release libraries if a change has been made since the previous release. Fix #3327
1 parent 95d3aff commit bd087bc

File tree

5 files changed

+185
-54
lines changed

5 files changed

+185
-54
lines changed

internal/librarian/internal/rust/release.go

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
package rust
1717

1818
import (
19-
"errors"
2019
"os"
2120
"path/filepath"
2221
"strings"
@@ -36,14 +35,8 @@ type cargoManifest struct {
3635
Package *cargoPackage `toml:"package"`
3736
}
3837

39-
var errCouldNotDeriveSrcPath = errors.New("could not derive source path for library")
40-
4138
// ReleaseLibrary bumps version for Cargo.toml files and updates librarian config version.
42-
func ReleaseLibrary(cfg *config.Config, library *config.Library) error {
43-
srcPath := deriveSrcPath(library, cfg)
44-
if srcPath == "" {
45-
return errCouldNotDeriveSrcPath
46-
}
39+
func ReleaseLibrary(library *config.Library, srcPath string) error {
4740
cargoFile := filepath.Join(srcPath, "Cargo.toml")
4841
cargoContents, err := os.ReadFile(cargoFile)
4942
if err != nil {
@@ -70,7 +63,8 @@ func ReleaseLibrary(cfg *config.Config, library *config.Library) error {
7063
return nil
7164
}
7265

73-
func deriveSrcPath(libCfg *config.Library, cfg *config.Config) string {
66+
// DeriveSrcPath determines what src path library code lives in.
67+
func DeriveSrcPath(libCfg *config.Library, cfg *config.Config) string {
7468
if libCfg.Output != "" {
7569
return libCfg.Output
7670
}

internal/librarian/internal/rust/release_test.go

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ const (
4040

4141
func TestReleaseOne(t *testing.T) {
4242
cfg := setupRelease(t)
43-
err := ReleaseLibrary(cfg, cfg.Libraries[0])
43+
err := ReleaseLibrary(cfg.Libraries[0], storageDir)
4444
if err != nil {
4545
t.Fatal(err)
4646
}
@@ -161,24 +161,17 @@ func TestDeriveSrcPath(t *testing.T) {
161161
},
162162
} {
163163
t.Run(test.name, func(t *testing.T) {
164-
got := deriveSrcPath(test.config.Libraries[0], test.config)
164+
got := DeriveSrcPath(test.config.Libraries[0], test.config)
165165
if got != test.want {
166166
t.Errorf("got derived source path %s, wanted %s", got, test.want)
167167
}
168168
})
169169
}
170170
}
171171

172-
func TestInvalidDerivedSource(t *testing.T) {
173-
cfg := &config.Config{
174-
Libraries: []*config.Library{
175-
{
176-
Name: storageName,
177-
},
178-
},
179-
}
180-
err := ReleaseLibrary(cfg, cfg.Libraries[0])
181-
if err != errCouldNotDeriveSrcPath {
182-
t.Errorf("wanted error %v, got %v", errCouldNotDeriveSrcPath, err)
172+
func TestNoCargoFile(t *testing.T) {
173+
got := ReleaseLibrary(&config.Library{}, "")
174+
if got == nil {
175+
t.Errorf("Expected error reading cargo file but got %v", got)
183176
}
184177
}

internal/librarian/release.go

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,21 @@ import (
2020
"fmt"
2121

2222
"github.com/googleapis/librarian/internal/config"
23+
"github.com/googleapis/librarian/internal/librarian/githelpers"
2324
"github.com/googleapis/librarian/internal/librarian/internal/rust"
2425
"github.com/googleapis/librarian/internal/yaml"
2526
"github.com/urfave/cli/v3"
2627
)
2728

28-
var errLibraryNotFound = errors.New("library not found")
29+
var (
30+
errCouldNotDeriveSrcPath = errors.New("could not derive source path for library")
31+
errLibraryNotFound = errors.New("library not found")
32+
errReleaseConfigEmpty = errors.New("librarian Release.Config field empty")
33+
)
2934

3035
var (
31-
rustReleaseLibrary = rust.ReleaseLibrary
3236
librarianGenerateLibrary = generateLibrary
37+
rustReleaseLibrary = rust.ReleaseLibrary
3338
)
3439

3540
func releaseCommand() *cli.Command {
@@ -69,19 +74,27 @@ func runRelease(ctx context.Context, cmd *cli.Command) error {
6974
if all && libraryName != "" {
7075
return errBothLibraryAndAllFlag
7176
}
72-
7377
cfg, err := yaml.Read[config.Config](librarianConfigPath)
7478
if err != nil {
7579
return err
7680
}
81+
gitExe := cfg.Release.GetExecutablePath("git")
82+
if err := githelpers.AssertGitStatusClean(ctx, gitExe); err != nil {
83+
return err
84+
}
85+
7786
if all {
7887
err = releaseAll(ctx, cfg)
7988
} else {
8089
libConfg, err := libraryByName(cfg, libraryName)
8190
if err != nil {
8291
return err
8392
}
84-
err = releaseLibrary(ctx, cfg, libConfg)
93+
srcPath, err := getSrcPathForLanguage(cfg, libConfg)
94+
if err != nil {
95+
return err
96+
}
97+
err = releaseLibrary(ctx, cfg, libConfg, srcPath)
8598
if err != nil {
8699
return err
87100
}
@@ -94,19 +107,43 @@ func runRelease(ctx context.Context, cmd *cli.Command) error {
94107

95108
func releaseAll(ctx context.Context, cfg *config.Config) error {
96109
for _, library := range cfg.Libraries {
97-
if err := releaseLibrary(ctx, cfg, library); err != nil {
110+
srcPath, err := getSrcPathForLanguage(cfg, library)
111+
if err != nil {
98112
return err
99113
}
114+
release, err := shouldReleaseLibrary(ctx, cfg, srcPath)
115+
if err != nil {
116+
return err
117+
}
118+
if release {
119+
if err := releaseLibrary(ctx, cfg, library, srcPath); err != nil {
120+
return err
121+
}
122+
}
100123
}
101124
return nil
102125
}
103126

104-
func releaseLibrary(ctx context.Context, cfg *config.Config, libConfig *config.Library) error {
127+
func getSrcPathForLanguage(cfg *config.Config, libConfig *config.Library) (string, error) {
128+
srcPath := ""
129+
switch cfg.Language {
130+
case "testhelper":
131+
srcPath = testDeriveSrcPath(libConfig)
132+
case "rust":
133+
srcPath = rust.DeriveSrcPath(libConfig, cfg)
134+
}
135+
if srcPath == "" {
136+
return "", errCouldNotDeriveSrcPath
137+
}
138+
return srcPath, nil
139+
}
140+
141+
func releaseLibrary(ctx context.Context, cfg *config.Config, libConfig *config.Library, srcPath string) error {
105142
switch cfg.Language {
106143
case "testhelper":
107144
return testReleaseLibrary(libConfig)
108145
case "rust":
109-
if err := rustReleaseLibrary(cfg, libConfig); err != nil {
146+
if err := rustReleaseLibrary(libConfig, srcPath); err != nil {
110147
return err
111148
}
112149
if _, err := librarianGenerateLibrary(ctx, cfg, libConfig.Name); err != nil {
@@ -130,3 +167,22 @@ func libraryByName(c *config.Config, name string) (*config.Library, error) {
130167
}
131168
return nil, errLibraryNotFound
132169
}
170+
171+
// shouldReleaseLibrary looks up last release tag and returns true if any commits have been made
172+
// in the provided path since then.
173+
func shouldReleaseLibrary(ctx context.Context, cfg *config.Config, path string) (bool, error) {
174+
if cfg.Release == nil {
175+
return false, errReleaseConfigEmpty
176+
}
177+
gitExe := cfg.Release.GetExecutablePath("git")
178+
lastTag, err := githelpers.GetLastTag(ctx, gitExe, cfg.Release.Remote, cfg.Release.Branch)
179+
if err != nil {
180+
return false, err
181+
}
182+
numberOfChanges, err := githelpers.ChangesInDirectorySinceTag(ctx, gitExe, lastTag, path)
183+
if err != nil {
184+
return false, err
185+
}
186+
187+
return numberOfChanges > 0, nil
188+
}

0 commit comments

Comments
 (0)