Skip to content

Commit 8a78d64

Browse files
authored
chore: add missing logic to release command (#3447)
Added missing logic in the release command: 1) Take into account skipPublish config 2) Take into account Release.FilesToIgnore config. As part of this change reused existing FilesChangedSince helper function to get all files changed since last git release at one time. 3) Updated migrate command to populate the ignored-files field in librarian.yaml 4) Added logic for rust releases to check if cargo version had already been bumped since last release tag For #3232 --------- Signed-off-by: ldetmer <1771267+ldetmer@users.noreply.github.com>
1 parent 32f4200 commit 8a78d64

8 files changed

Lines changed: 154 additions & 103 deletions

File tree

internal/git/git.go

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222
"fmt"
2323
"os/exec"
2424
"slices"
25-
"strconv"
2625
"strings"
2726

2827
"github.com/go-git/go-git/v5/plumbing/format/gitignore"
@@ -132,14 +131,3 @@ func MatchesBranchPoint(ctx context.Context, gitExe, remote, branch string) erro
132131
}
133132
return nil
134133
}
135-
136-
// ChangesInDirectorySinceTag checks if there have been any changes in directory since tag.
137-
func ChangesInDirectorySinceTag(ctx context.Context, gitExe, tag, dir string) (int, error) {
138-
delta := fmt.Sprintf("%s...HEAD", tag)
139-
cmd := exec.CommandContext(ctx, gitExe, "rev-list", "--count", delta, "--", dir)
140-
output, err := cmd.CombinedOutput()
141-
if err != nil {
142-
return 0, fmt.Errorf("running %s failed: %w\noutput: %s", cmd.String(), err, string(output))
143-
}
144-
return strconv.Atoi(strings.TrimSpace(string(output)))
145-
}

internal/git/git_test.go

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -296,39 +296,6 @@ func TestMatchesDirtyCloneError(t *testing.T) {
296296
}
297297
}
298298

299-
func TestChangesInDirectorySinceTag(t *testing.T) {
300-
for _, test := range []struct {
301-
name string
302-
dir string
303-
want int
304-
}{
305-
{
306-
name: "changes exist in directory",
307-
dir: "src/storage",
308-
want: 1,
309-
},
310-
{
311-
name: "changes do not exist in directory",
312-
dir: "src/gax-internal",
313-
want: 0,
314-
},
315-
} {
316-
t.Run(test.name, func(t *testing.T) {
317-
testhelper.RequireCommand(t, "git")
318-
tag := "v1.2.3"
319-
remoteDir := testhelper.SetupRepoWithChange(t, tag)
320-
testhelper.CloneRepository(t, remoteDir)
321-
got, err := ChangesInDirectorySinceTag(t.Context(), "git", tag, test.dir)
322-
if err != nil {
323-
t.Fatal(err)
324-
}
325-
if got != test.want {
326-
t.Errorf("ChangesInDirectorySinceTag() = %d, want %d", got, test.want)
327-
}
328-
})
329-
}
330-
}
331-
332299
func TestShowFile(t *testing.T) {
333300
testhelper.RequireCommand(t, "git")
334301
remoteDir := testhelper.SetupRepo(t)

internal/librarian/release.go

Lines changed: 42 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"context"
1919
"errors"
2020
"fmt"
21+
"strings"
2122

2223
"github.com/googleapis/librarian/internal/command"
2324
"github.com/googleapis/librarian/internal/config"
@@ -82,8 +83,16 @@ func runRelease(ctx context.Context, cmd *cli.Command) error {
8283
return err
8384
}
8485

86+
if cfg.Release == nil {
87+
return errReleaseConfigEmpty
88+
}
89+
lastTag, err := git.GetLastTag(ctx, gitExe, cfg.Release.Remote, cfg.Release.Branch)
90+
if err != nil {
91+
return err
92+
}
93+
8594
if all {
86-
err = releaseAll(ctx, cfg)
95+
err = releaseAll(ctx, cfg, lastTag, gitExe)
8796
} else {
8897
libConfg, err := libraryByName(cfg, libraryName)
8998
if err != nil {
@@ -93,7 +102,7 @@ func runRelease(ctx context.Context, cmd *cli.Command) error {
93102
if err != nil {
94103
return err
95104
}
96-
err = releaseLibrary(ctx, cfg, libConfg, srcPath)
105+
err = releaseLibrary(ctx, cfg, libConfg, srcPath, lastTag, gitExe)
97106
if err != nil {
98107
return err
99108
}
@@ -104,25 +113,41 @@ func runRelease(ctx context.Context, cmd *cli.Command) error {
104113
return yaml.Write(librarianConfigPath, cfg)
105114
}
106115

107-
func releaseAll(ctx context.Context, cfg *config.Config) error {
116+
func releaseAll(ctx context.Context, cfg *config.Config, lastTag, gitExe string) error {
117+
filesChanged, err := git.FilesChangedSince(ctx, lastTag, gitExe, cfg.Release.IgnoredChanges)
118+
if err != nil {
119+
return err
120+
}
108121
for _, library := range cfg.Libraries {
109122
srcPath, err := getSrcPathForLanguage(cfg, library)
110123
if err != nil {
111124
return err
112125
}
113-
release, err := shouldReleaseLibrary(ctx, cfg, srcPath)
114-
if err != nil {
115-
return err
116-
}
117-
if release {
118-
if err := releaseLibrary(ctx, cfg, library, srcPath); err != nil {
126+
if shouldRelease(library, filesChanged, srcPath) {
127+
if err := releaseLibrary(ctx, cfg, library, srcPath, lastTag, gitExe); err != nil {
119128
return err
120129
}
121130
}
122131
}
123132
return nil
124133
}
125134

135+
func shouldRelease(library *config.Library, filesChanged []string, srcPath string) bool {
136+
if library.SkipPublish {
137+
return false
138+
}
139+
pathWithTrailingSlash := srcPath
140+
if !strings.HasSuffix(pathWithTrailingSlash, "/") {
141+
pathWithTrailingSlash = pathWithTrailingSlash + "/"
142+
}
143+
for _, path := range filesChanged {
144+
if strings.Contains(path, pathWithTrailingSlash) {
145+
return true
146+
}
147+
}
148+
return false
149+
}
150+
126151
func getSrcPathForLanguage(cfg *config.Config, libConfig *config.Library) (string, error) {
127152
srcPath := ""
128153
switch cfg.Language {
@@ -137,11 +162,18 @@ func getSrcPathForLanguage(cfg *config.Config, libConfig *config.Library) (strin
137162
return srcPath, nil
138163
}
139164

140-
func releaseLibrary(ctx context.Context, cfg *config.Config, libConfig *config.Library, srcPath string) error {
165+
func releaseLibrary(ctx context.Context, cfg *config.Config, libConfig *config.Library, srcPath, lastTag, gitExe string) error {
141166
switch cfg.Language {
142167
case languageFake:
143168
return fakeReleaseLibrary(libConfig)
144169
case languageRust:
170+
release, err := rust.ManifestVersionNeedsBump(gitExe, lastTag, srcPath+"/Cargo.toml")
171+
if err != nil {
172+
return err
173+
}
174+
if !release {
175+
return nil
176+
}
145177
if err := rust.ReleaseLibrary(libConfig, srcPath); err != nil {
146178
return err
147179
}
@@ -166,22 +198,3 @@ func libraryByName(c *config.Config, name string) (*config.Library, error) {
166198
}
167199
return nil, errLibraryNotFound
168200
}
169-
170-
// shouldReleaseLibrary looks up last release tag and returns true if any commits have been made
171-
// in the provided path since then.
172-
func shouldReleaseLibrary(ctx context.Context, cfg *config.Config, path string) (bool, error) {
173-
if cfg.Release == nil {
174-
return false, errReleaseConfigEmpty
175-
}
176-
gitExe := command.GetExecutablePath(cfg.Release.Preinstalled, "git")
177-
lastTag, err := git.GetLastTag(ctx, gitExe, cfg.Release.Remote, cfg.Release.Branch)
178-
if err != nil {
179-
return false, err
180-
}
181-
numberOfChanges, err := git.ChangesInDirectorySinceTag(ctx, gitExe, lastTag, path)
182-
if err != nil {
183-
return false, err
184-
}
185-
186-
return numberOfChanges > 0, nil
187-
}

internal/librarian/release_test.go

Lines changed: 85 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,19 @@ func TestReleaseCommand(t *testing.T) {
9999
args: []string{"librarian", "release", "--all"},
100100
dirtyGitStatus: true,
101101
},
102+
{
103+
name: "release config empty",
104+
args: []string{"librarian", "release", "--all"},
105+
srcPaths: map[string]string{
106+
testlib: "src/storage",
107+
testlib2: "src/storage",
108+
},
109+
wantVersions: map[string]string{
110+
testlib: fakeReleaseVersion,
111+
testlib2: fakeReleaseVersion,
112+
},
113+
wantErr: errReleaseConfigEmpty,
114+
},
102115
} {
103116
t.Run(test.name, func(t *testing.T) {
104117
testhelper.RequireCommand(t, "git")
@@ -125,6 +138,9 @@ func TestReleaseCommand(t *testing.T) {
125138
},
126139
},
127140
}
141+
if test.wantErr == errReleaseConfigEmpty {
142+
cfg.Release = nil
143+
}
128144
if !test.skipYamlCreation {
129145
if err := yaml.Write(configPath, cfg); err != nil {
130146
t.Fatal(err)
@@ -229,6 +245,7 @@ func TestRelease(t *testing.T) {
229245
name string
230246
srcPath string
231247
version string
248+
lastTag string
232249
}{
233250
{
234251
name: "library released",
@@ -250,7 +267,7 @@ func TestRelease(t *testing.T) {
250267
for _, test := range tests {
251268
t.Run(test.name, func(t *testing.T) {
252269
libConfg := &config.Library{}
253-
err := releaseLibrary(t.Context(), cfg, libConfg, test.srcPath)
270+
err := releaseLibrary(t.Context(), cfg, libConfg, test.srcPath, test.lastTag, "git")
254271
if err != nil {
255272
t.Fatalf("releaseLibrary() error = %v", err)
256273
}
@@ -262,11 +279,72 @@ func TestRelease(t *testing.T) {
262279
}
263280
}
264281

265-
func TestMissingReleaseConfig(t *testing.T) {
266-
cfg := &config.Config{}
267-
_, err := shouldReleaseLibrary(t.Context(), cfg, "")
268-
if !errors.Is(err, errReleaseConfigEmpty) {
269-
t.Fatalf("Run() error = %v, wantErr %v", err, errReleaseConfigEmpty)
270-
}
282+
func TestReleaseAll(t *testing.T) {
271283

284+
for _, test := range []struct {
285+
name string
286+
libName string
287+
dir string
288+
skipPublish bool
289+
wantVersion string
290+
}{
291+
{
292+
name: "library has changes",
293+
libName: "google-cloud-storage",
294+
dir: "src/storage",
295+
wantVersion: "1.2.3",
296+
skipPublish: false,
297+
},
298+
{
299+
name: "library does not have any changes",
300+
libName: "gax-internal",
301+
dir: "src/gax-internal",
302+
wantVersion: "1.2.2",
303+
skipPublish: false,
304+
},
305+
{
306+
name: "library does not have any changes on shared directory prefix",
307+
libName: "gax-internal",
308+
dir: "src/stor",
309+
wantVersion: "1.2.2",
310+
skipPublish: false,
311+
},
312+
{
313+
name: "library has changes but skipPublish is true",
314+
libName: "google-cloud-storage",
315+
dir: "src/storage",
316+
wantVersion: "1.2.2",
317+
skipPublish: true,
318+
},
319+
} {
320+
t.Run(test.name, func(t *testing.T) {
321+
testhelper.RequireCommand(t, "git")
322+
tag := "v1.2.3"
323+
config := &config.Config{
324+
Language: languageFake,
325+
Libraries: []*config.Library{
326+
{
327+
Name: test.libName,
328+
Version: "1.2.2",
329+
Output: test.dir,
330+
SkipPublish: test.skipPublish,
331+
},
332+
},
333+
Release: &config.Release{
334+
Remote: "origin",
335+
Branch: "main",
336+
IgnoredChanges: []string{},
337+
},
338+
}
339+
remoteDir := testhelper.SetupRepoWithChange(t, tag)
340+
testhelper.CloneRepository(t, remoteDir)
341+
err := releaseAll(t.Context(), config, tag, "git")
342+
if err != nil {
343+
t.Fatal(err)
344+
}
345+
if config.Libraries[0].Version != test.wantVersion {
346+
t.Errorf("got version %s, want %s", config.Libraries[0].Version, test.wantVersion)
347+
}
348+
})
349+
}
272350
}

internal/librarian/rust/update_manifest.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ type Cargo struct {
3939

4040
// UpdateManifest bumps the version of a crate if it has changed since the last tag.
4141
func UpdateManifest(gitExe, lastTag, manifest string) ([]string, error) {
42-
needsBump, err := manifestVersionNeedsBump(gitExe, lastTag, manifest)
42+
needsBump, err := ManifestVersionNeedsBump(gitExe, lastTag, manifest)
4343
if err != nil {
4444
return nil, err
4545
}
@@ -99,7 +99,9 @@ func UpdateCargoVersion(path, newVersion string) error {
9999
return os.WriteFile(path, []byte(strings.Join(lines, "\n")), 0644)
100100
}
101101

102-
func manifestVersionNeedsBump(gitExe, lastTag, manifest string) (bool, error) {
102+
// ManifestVersionNeedsBump checks if the manifest version needs to be bumped.
103+
// It returns false if the version has already been updated since the last tag.
104+
func ManifestVersionNeedsBump(gitExe, lastTag, manifest string) (bool, error) {
103105
delta := fmt.Sprintf("%s..HEAD", lastTag)
104106
cmd := exec.Command(gitExe, "diff", delta, "--", manifest)
105107
cmd.Dir = "."

internal/librarian/rust/update_manifest_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ func TestManifestVersionNeedsBumpSuccess(t *testing.T) {
215215
t.Fatal(err)
216216
}
217217

218-
needsBump, err := manifestVersionNeedsBump("git", tag, name)
218+
needsBump, err := ManifestVersionNeedsBump("git", tag, name)
219219
if err != nil {
220220
t.Fatal(err)
221221
}
@@ -238,7 +238,7 @@ func TestManifestVersionNeedsBumpNewCrate(t *testing.T) {
238238
}
239239
name := path.Join("src", "new", "Cargo.toml")
240240

241-
needsBump, err := manifestVersionNeedsBump("git", tag, name)
241+
needsBump, err := ManifestVersionNeedsBump("git", tag, name)
242242
if err != nil {
243243
t.Fatal(err)
244244
}
@@ -252,7 +252,7 @@ func TestManifestVersionNeedsBumpNoChange(t *testing.T) {
252252
testhelper.RequireCommand(t, "git")
253253
testhelper.SetupForVersionBump(t, tag)
254254
name := path.Join("src", "storage", "Cargo.toml")
255-
needsBump, err := manifestVersionNeedsBump("git", tag, name)
255+
needsBump, err := ManifestVersionNeedsBump("git", tag, name)
256256
if err != nil {
257257
t.Fatal(err)
258258
}
@@ -266,7 +266,7 @@ func TestManifestVersionNeedsBumpBadDiff(t *testing.T) {
266266
testhelper.RequireCommand(t, "git")
267267
testhelper.SetupForVersionBump(t, tag)
268268
name := path.Join("src", "storage", "Cargo.toml")
269-
if updated, err := manifestVersionNeedsBump("git", "not-a-valid-tag", name); err == nil {
269+
if updated, err := ManifestVersionNeedsBump("git", "not-a-valid-tag", name); err == nil {
270270
t.Errorf("expected an error with an valid tag, got=%v", updated)
271271
}
272272
}

0 commit comments

Comments
 (0)