Skip to content

Commit a00e91b

Browse files
authored
fix: save old version in release (#1953)
Run command: ``` go run ./cmd/librarian release init -repo=. -push ``` Release pull request created in #1955 The release note is not well formatted, will address in #1964. Fixes #1932
1 parent 50acf6e commit a00e91b

File tree

7 files changed

+131
-148
lines changed

7 files changed

+131
-148
lines changed

internal/config/state.go

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import (
1919
"path/filepath"
2020
"regexp"
2121
"strings"
22+
23+
"github.com/googleapis/librarian/internal/conventionalcommits"
2224
)
2325

2426
const (
@@ -106,11 +108,13 @@ type LibraryState struct {
106108
LastGeneratedCommit string `yaml:"last_generated_commit" json:"last_generated_commit"`
107109
// The changes from the language repository since the library was last released.
108110
// This field is ignored when writing to state.yaml.
109-
Changes []*Change `yaml:"-" json:"changes,omitempty"`
111+
Changes []*conventionalcommits.ConventionalCommit `yaml:"-" json:"changes,omitempty"`
110112
// A list of APIs that are part of this library.
111113
APIs []*API `yaml:"apis" json:"apis"`
112114
// A list of directories in the language repository where Librarian contributes code.
113115
SourceRoots []string `yaml:"source_roots" json:"source_roots"`
116+
// The previous release version, this field is only for bookkeeping.
117+
PreviousVersion string `yaml:"-" json:"-"`
114118
// A list of regular expressions for files and directories to preserve during the copy and remove process.
115119
PreserveRegex []string `yaml:"preserve_regex" json:"preserve_regex"`
116120
// A list of regular expressions for files and directories to remove before copying generated code.
@@ -223,20 +227,6 @@ func (a *API) Validate() error {
223227
return nil
224228
}
225229

226-
// Change represents the changelog of a library.
227-
type Change struct {
228-
// The type of the change, should be one of the conventional type.
229-
Type string `yaml:"type" json:"type"`
230-
// The summary of the change.
231-
Subject string `yaml:"subject" json:"subject"`
232-
// The body of the change.
233-
Body string `yaml:"body" json:"body"`
234-
// The Changelist number in piper associated with this change.
235-
ClNum string `yaml:"piper_cl_number" json:"piper_cl_number"`
236-
// The commit hash in the source repository associated with this change.
237-
CommitHash string `yaml:"source_commit_hash" json:"source_commit_hash"`
238-
}
239-
240230
// invalidPathChars contains characters that are invalid in path components,
241231
// plus path separators and the null byte.
242232
const invalidPathChars = "<>:\"|?*/\\\x00"

internal/librarian/command.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ type commitInfo struct {
5858
ghClient GitHubClient
5959
idToCommits map[string]string
6060
failedLibraries []string
61+
pullRequestLabels []string
6162
commitMessage string
6263
prType string
63-
pullRequestLabels []string
6464
}
6565

6666
type commandRunner struct {
@@ -400,11 +400,11 @@ func commitAndPush(ctx context.Context, info *commitInfo) error {
400400
// Passing in `nil` for labels will no-op and an empty list for labels will clear all labels on the PR.
401401
// TODO: Consolidate the params to a potential PullRequestInfo struct.
402402
func addLabelsToPullRequest(ctx context.Context, ghClient GitHubClient, pullRequestLabels []string, prMetadata *github.PullRequestMetadata) error {
403-
// Do not update if there are aren't labels provided
403+
// Do not update if there aren't labels provided
404404
if pullRequestLabels == nil {
405405
return nil
406406
}
407-
// Github API treats Issues and Pull Request the same
407+
// GitHub API treats Issues and Pull Request the same
408408
// https://docs.github.com/en/rest/issues/labels#add-labels-to-an-issue
409409
if err := ghClient.AddLabelsToIssue(ctx, prMetadata.Repo, prMetadata.Number, pullRequestLabels); err != nil {
410410
return fmt.Errorf("failed to add labels to pull request: %w", err)

internal/librarian/commit_version_analyzer_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,6 @@ func TestGetConventionalCommitsSinceLastRelease(t *testing.T) {
177177
Footers: make(map[string]string),
178178
},
179179
},
180-
wantErr: false,
181180
},
182181
{
183182
name: "GetCommitsForPathsSinceTag error",

internal/librarian/release_init.go

Lines changed: 19 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,13 @@ import (
2121
"os"
2222
"path/filepath"
2323

24-
"github.com/googleapis/librarian/internal/conventionalcommits"
25-
2624
"github.com/googleapis/librarian/internal/docker"
2725

2826
"github.com/googleapis/librarian/internal/cli"
2927
"github.com/googleapis/librarian/internal/config"
3028
"github.com/googleapis/librarian/internal/gitrepo"
3129
)
3230

33-
const (
34-
KeyClNum = "PiperOrigin-RevId"
35-
)
36-
3731
// cmdInit is the command for the `release init` subcommand.
3832
var cmdInit = &cli.Command{
3933
Short: "init initiates a release by creating a release pull request.",
@@ -84,14 +78,14 @@ func newInitRunner(cfg *config.Config) (*initRunner, error) {
8478
}
8579
return &initRunner{
8680
cfg: runner.cfg,
87-
workRoot: runner.workRoot,
8881
repo: runner.repo,
89-
partialRepo: filepath.Join(runner.workRoot, "release-init"),
9082
state: runner.state,
9183
librarianConfig: runner.librarianConfig,
92-
image: runner.image,
9384
ghClient: runner.ghClient,
9485
containerClient: runner.containerClient,
86+
workRoot: runner.workRoot,
87+
partialRepo: filepath.Join(runner.workRoot, "release-init"),
88+
image: runner.image,
9589
}, nil
9690
}
9791

@@ -113,7 +107,7 @@ func (r *initRunner) run(ctx context.Context) error {
113107
commitMessage: "chore: create a release",
114108
prType: release,
115109
// Newly created PRs from the `release init` command should have a
116-
// `release:pending` Github tab to be tracked for release.
110+
// `release:pending` GitHub tab to be tracked for release.
117111
pullRequestLabels: []string{"release:pending"},
118112
}
119113
if err := commitAndPush(ctx, commitInfo); err != nil {
@@ -128,15 +122,16 @@ func (r *initRunner) runInitCommand(ctx context.Context, outputDir string) error
128122
if err := os.MkdirAll(dst, 0755); err != nil {
129123
return fmt.Errorf("failed to make directory: %w", err)
130124
}
131-
src := r.repo.GetDir()
132125

126+
src := r.repo.GetDir()
133127
for _, library := range r.state.Libraries {
134128
if r.cfg.Library != "" {
135129
if r.cfg.Library != library.ID {
136130
continue
137131
}
132+
138133
// Only update one library with the given library ID.
139-
if err := updateLibrary(r.repo, library, r.cfg.LibraryVersion); err != nil {
134+
if err := r.updateLibrary(library); err != nil {
140135
return err
141136
}
142137
if err := copyLibrary(dst, src, library); err != nil {
@@ -147,7 +142,7 @@ func (r *initRunner) runInitCommand(ctx context.Context, outputDir string) error
147142
}
148143

149144
// Update all libraries.
150-
if err := updateLibrary(r.repo, library, r.cfg.LibraryVersion); err != nil {
145+
if err := r.updateLibrary(library); err != nil {
151146
return err
152147
}
153148
if err := copyLibrary(dst, src, library); err != nil {
@@ -201,24 +196,28 @@ func (r *initRunner) runInitCommand(ctx context.Context, outputDir string) error
201196

202197
// updateLibrary updates the given library in the following way:
203198
//
204-
// 1. Get the library's commit history in the given git repository.
199+
// 1. Update the library's previous version.
205200
//
206-
// 2. Override the library version if libraryVersion is not empty.
201+
// 2. Get the library's commit history in the given git repository.
207202
//
208-
// 3. Set the library's release trigger to true.
209-
func updateLibrary(repo gitrepo.Repository, library *config.LibraryState, libraryVersion string) error {
210-
commits, err := GetConventionalCommitsSinceLastRelease(repo, library)
203+
// 3. Override the library version if libraryVersion is not empty.
204+
//
205+
// 4. Set the library's release trigger to true.
206+
func (r *initRunner) updateLibrary(library *config.LibraryState) error {
207+
// Update the previous version, we need this value when creating release note.
208+
library.PreviousVersion = library.Version
209+
commits, err := GetConventionalCommitsSinceLastRelease(r.repo, library)
211210
if err != nil {
212211
return fmt.Errorf("failed to fetch conventional commits for library, %s: %w", library.ID, err)
213212
}
214213

215-
library.Changes = coerceLibraryChanges(commits)
214+
library.Changes = commits
216215
if len(library.Changes) == 0 {
217216
slog.Info("Skip releasing library since no eligible change is found", "library", library.ID)
218217
return nil
219218
}
220219

221-
nextVersion, err := NextVersion(commits, library.Version, libraryVersion)
220+
nextVersion, err := NextVersion(commits, library.Version, r.cfg.LibraryVersion)
222221
if err != nil {
223222
return err
224223
}
@@ -229,38 +228,6 @@ func updateLibrary(repo gitrepo.Repository, library *config.LibraryState, librar
229228
return nil
230229
}
231230

232-
func coerceLibraryChanges(commits []*conventionalcommits.ConventionalCommit) []*config.Change {
233-
changes := make([]*config.Change, 0)
234-
for _, commit := range commits {
235-
clNum := ""
236-
if cl, ok := commit.Footers[KeyClNum]; ok {
237-
clNum = cl
238-
}
239-
240-
changeType := getChangeType(commit)
241-
changes = append(changes, &config.Change{
242-
Type: changeType,
243-
Subject: commit.Description,
244-
Body: commit.Body,
245-
ClNum: clNum,
246-
CommitHash: commit.SHA,
247-
})
248-
}
249-
250-
return changes
251-
}
252-
253-
// getChangeType gets the type of the commit, adding an escalation mark (!) if
254-
// it is a breaking change.
255-
func getChangeType(commit *conventionalcommits.ConventionalCommit) string {
256-
changeType := commit.Type
257-
if commit.IsBreaking {
258-
changeType = changeType + "!"
259-
}
260-
261-
return changeType
262-
}
263-
264231
// copyGlobalAllowlist copies files in the global file allowlist excluding
265232
//
266233
// read-only files and copies global files from src.

internal/librarian/release_init_test.go

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import (
2222
"strings"
2323
"testing"
2424

25+
"github.com/googleapis/librarian/internal/conventionalcommits"
26+
2527
"github.com/go-git/go-git/v5"
2628

2729
"github.com/googleapis/librarian/internal/gitrepo"
@@ -467,22 +469,26 @@ func TestUpdateLibrary(t *testing.T) {
467469
},
468470
},
469471
want: &config.LibraryState{
470-
ID: "one-id",
471-
Version: "2.0.0",
472+
ID: "one-id",
473+
Version: "2.0.0",
474+
PreviousVersion: "1.2.3",
472475
SourceRoots: []string{
473476
"one/path",
474477
"two/path",
475478
},
476-
Changes: []*config.Change{
479+
Changes: []*conventionalcommits.ConventionalCommit{
477480
{
478-
Type: "fix",
479-
Subject: "change a typo",
481+
Type: "fix",
482+
Description: "change a typo",
483+
LibraryID: "one-id",
484+
Footers: map[string]string{},
480485
},
481486
{
482-
Type: "feat",
483-
Subject: "add a config file",
484-
Body: "This is the body.",
485-
ClNum: "12345",
487+
Type: "feat",
488+
Description: "add a config file",
489+
Body: "This is the body.",
490+
LibraryID: "one-id",
491+
Footers: map[string]string{"PiperOrigin-RevId": "12345"},
486492
},
487493
},
488494
ReleaseTriggered: true,
@@ -516,21 +522,30 @@ func TestUpdateLibrary(t *testing.T) {
516522
},
517523
},
518524
want: &config.LibraryState{
519-
ID: "one-id",
520-
Version: "2.0.0",
525+
ID: "one-id",
526+
Version: "2.0.0",
527+
PreviousVersion: "1.2.3",
521528
SourceRoots: []string{
522529
"one/path",
523530
"two/path",
524531
},
525-
Changes: []*config.Change{
532+
Changes: []*conventionalcommits.ConventionalCommit{
526533
{
527-
Type: "feat!",
528-
Subject: "add another config file",
529-
Body: "This is the body",
534+
Type: "feat",
535+
Description: "add another config file",
536+
Body: "This is the body",
537+
LibraryID: "one-id",
538+
Footers: map[string]string{
539+
"BREAKING CHANGE": "this is a breaking change",
540+
},
541+
IsBreaking: true,
530542
},
531543
{
532-
Type: "feat!",
533-
Subject: "change a typo",
544+
Type: "feat",
545+
Description: "change a typo",
546+
LibraryID: "one-id",
547+
Footers: map[string]string{},
548+
IsBreaking: true,
534549
},
535550
},
536551
ReleaseTriggered: true,
@@ -554,12 +569,19 @@ func TestUpdateLibrary(t *testing.T) {
554569
},
555570
} {
556571
t.Run(test.name, func(t *testing.T) {
572+
r := &initRunner{
573+
cfg: &config.Config{
574+
LibraryVersion: test.libraryVersion,
575+
},
576+
repo: test.repo,
577+
}
557578
var err error
558579
if test.repo != nil {
559-
err = updateLibrary(test.repo, test.library, test.libraryVersion)
580+
err = r.updateLibrary(test.library)
560581
} else {
561582
repo := setupRepoForGetCommits(t, test.pathAndMessages, test.tags)
562-
err = updateLibrary(repo, test.library, test.libraryVersion)
583+
r.repo = repo
584+
err = r.updateLibrary(test.library)
563585
}
564586

565587
if test.wantErr {
@@ -577,7 +599,7 @@ func TestUpdateLibrary(t *testing.T) {
577599
if err != nil {
578600
t.Errorf("failed to run getChangesOf(): %q", err.Error())
579601
}
580-
if diff := cmp.Diff(test.want, test.library, cmpopts.IgnoreFields(config.Change{}, "CommitHash")); diff != "" {
602+
if diff := cmp.Diff(test.want, test.library, cmpopts.IgnoreFields(conventionalcommits.ConventionalCommit{}, "SHA", "When")); diff != "" {
581603
t.Errorf("state mismatch (-want +got):\n%s", diff)
582604
}
583605
})

internal/librarian/release_notes.go

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -274,19 +274,14 @@ func formatLibraryReleaseNotes(repo gitrepo.Repository, library *config.LibraryS
274274
if err != nil {
275275
return nil, fmt.Errorf("failed to fetch github repo from remote: %w", err)
276276
}
277-
previousTag := formatTag(library, "")
278-
commits, err := GetConventionalCommitsSinceLastRelease(repo, library)
279-
if err != nil {
280-
return nil, fmt.Errorf("failed to get conventional commits for library %s: %w", library.ID, err)
281-
}
282-
newVersion, err := NextVersion(commits, library.Version, "")
283-
if err != nil {
284-
return nil, fmt.Errorf("failed to get next version for library %s: %w", library.ID, err)
285-
}
277+
278+
// The version should already be updated to the next version.
279+
newVersion := library.Version
286280
newTag := formatTag(library, newVersion)
281+
previousTag := formatTag(library, library.PreviousVersion)
287282

288283
commitsByType := make(map[string][]*conventionalcommits.ConventionalCommit)
289-
for _, commit := range commits {
284+
for _, commit := range library.Changes {
290285
commitsByType[commit.Type] = append(commitsByType[commit.Type], commit)
291286
}
292287

0 commit comments

Comments
 (0)