Skip to content

Commit 977ac88

Browse files
committed
pkg/cli/admin/release/info: Mention elided first-parent, non-merge commits
Originally, the change-log generation focused on merge commits, which are common in many repositories. For example, in this 'oc' repository: $ git log --graph --oneline -10 * 559c67e (HEAD -> main, origin/main) Merge pull request openshift#2083 from wking/oc-adm-upgrade-recommend-certificate-authority |\ | * b98b2e1 pkg/cli/admin/inspectalerts: Pass through --certificate-authority, etc. * | e7900fe Merge pull request openshift#2082 from ardaguclu/code-rabbit-test |\ \ | |/ |/| | * ffe752e Remove mentioning about IRC channel from README * | f114b17 OTA-1581: Promote `oc adm upgrade status` to general availability (openshift#2063) * | 1c54ec0 Merge pull request openshift#2077 from hongkailiu/OTA-1601 |\ \ | * | 5f1dbb8 Move not-lines-related table.Write out of the loop | * | a352662 Truncate long reasons | * | 11f9f47 Reproduce the long reason issue | * | 970f883 status: improve line break handling for CO Message 4299014 (Add squash-merge support into oc adm release info, 2022-04-26, openshift#1116), and mentioned the insights operator: $ git clone --depth 10 --branch master https://github.com/openshift/insights-operator $ cd insights-operator $ git log --graph --oneline -5 * da45333 (HEAD -> master, origin/master, origin/HEAD) OCPBUGS-60611: virt launcher logs gatherer (openshift#1110) * 737b59b fix: incorrect anonymization of domains (openshift#1111) * b5185da feat: add permissions to gather clusterrole (openshift#1106) * 3099eb0 feat: Allow on-demand gathering during initial periodic run (openshift#1109) * 7f8b40d RFE-4152: Add missing readonlyRootFilesystem (openshift#1104) But some repositories also use a mixture of real merges and squash or rebase merges: $ git clone --depth 20 --branch main https://github.com/openshift/operator-framework-operator-controller $ cd operator-framework-operator-controller $ git log --graph --oneline -11 * 9319f22a (HEAD -> main, origin/main, origin/HEAD) UPSTREAM: <carry>: Ensure unique name for bad-catalog tests * 9b50498a UPSTREAM: <carry>: Adds ResourceVersion checks to the tls secret deletion test, mirroring the logic used in the certificate rotation test. This makes the test more robust by ensuring a new secret is created, not just that an existing one is still present. * 2ed1a5c8 UPSTREAM: <carry>: Migrate single/own namespace tests * 0c4f4303 UPSTREAM: <carry>: [OTE] add catalog tests from openshift/origin * 28299f38 UPSTREAM: <carry>: remove obsolete owners * 5aa7897f UPSTREAM: <carry>: [OTE] - Readme:Add info to help use payload-aggregate with new tests * 0bb19537 UPSTREAM: <carry>: Adds ResourceVersion checks to the tls secret deletion test, mirroring the logic used in the certificate rotation test. This makes the test more robust by ensuring a new secret is created, not just that an existing one is still present. * e9e3220f UPSTREAM: <carry>: [OTE] Add webhook to validate openshift-service-ca certificate rotation * a7d35272 Merge pull request openshift#453 from openshift-bot/synchronize-upstream |\ | * d93f9d16 UPSTREAM: <drop>: configure the commit-checker | * 9a69e8ed UPSTREAM: <drop>: remove upstream GitHub configuration Before this commit, the logic would find the merge commits, assume that all content came in via merge commits, and not mention the other changes: $ git log --first-parent --merges --oneline a7d3527 Merge pull request openshift#453 from openshift-bot/synchronize-upstream 4cae159 Merge pull request openshift#449 from openshift-bot/synchronize-upstream 82f63dc Merge pull request openshift#444 from openshift-bot/synchronize-upstream 6f91d84 Merge pull request openshift#435 from openshift-bot/synchronize-upstream With this commit, we'll continue to include a line for each of those merges. But we'll also include the count of any elided, non-merge, first-parent commits: $ git log --first-parent --no-merges --oneline | wc -l 16 Folks interested in what exactly was elided will have to click through to 'Full changelog' or otherwise go digging. But at least they'll get the count of elided commits to know that there is more information there to see behind that click.
1 parent 559c67e commit 977ac88

File tree

3 files changed

+57
-35
lines changed

3 files changed

+57
-35
lines changed

pkg/cli/admin/release/git.go

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -215,34 +215,35 @@ var (
215215
rePrefix = regexp.MustCompile(`^(\[[\w\.\-]+\]\s*)+`)
216216
)
217217

218-
func mergeLogForRepo(g gitInterface, repo string, from, to string) ([]MergeCommit, error) {
218+
func mergeLogForRepo(g gitInterface, repo string, from, to string) ([]MergeCommit, int, error) {
219219
if from == to {
220-
return nil, nil
220+
return nil, 0, nil
221221
}
222222

223223
args := []string{"log", "--merges", "--topo-order", "--first-parent", "-z", "--pretty=format:%H %P%x1E%ct%x1E%s%x1E%b", fmt.Sprintf("%s..%s", from, to)}
224224
out, err := g.exec(args...)
225225
if err != nil {
226226
// retry once if there's a chance we haven't fetched the latest commits
227227
if !strings.Contains(out, "Invalid revision range") {
228-
return nil, gitOutputToError(err, out)
228+
return nil, 0, gitOutputToError(err, out)
229229
}
230230
if _, err := g.exec("fetch", "--all"); err != nil {
231-
return nil, gitOutputToError(err, out)
231+
return nil, 0, gitOutputToError(err, out)
232232
}
233233
if _, err := g.exec("cat-file", "-e", from+"^{commit}"); err != nil {
234-
return nil, fmt.Errorf("from commit %s does not exist", from)
234+
return nil, 0, fmt.Errorf("from commit %s does not exist", from)
235235
}
236236
if _, err := g.exec("cat-file", "-e", to+"^{commit}"); err != nil {
237-
return nil, fmt.Errorf("to commit %s does not exist", to)
237+
return nil, 0, fmt.Errorf("to commit %s does not exist", to)
238238
}
239239
out, err = g.exec(args...)
240240
if err != nil {
241-
return nil, gitOutputToError(err, out)
241+
return nil, 0, gitOutputToError(err, out)
242242
}
243243
}
244244

245245
squash := false
246+
elidedCommits := 0
246247
if out == "" {
247248
// some repositories use squash merging(like insights-operator) and
248249
// out which is populated by --merges flag is empty. Thereby,
@@ -251,9 +252,21 @@ func mergeLogForRepo(g gitInterface, repo string, from, to string) ([]MergeCommi
251252
args = []string{"log", "--no-merges", "--topo-order", "-z", "--pretty=format:%H %P%x1E%ct%x1E%s%x1E%b", fmt.Sprintf("%s..%s", from, to)}
252253
out, err = g.exec(args...)
253254
if err != nil {
254-
return nil, gitOutputToError(err, out)
255+
return nil, 0, gitOutputToError(err, out)
255256
}
256257
squash = true
258+
} else {
259+
// some repositories use both real merges and squash or rebase merging.
260+
// Don't flood the output with single-commit noise, which might be poorly curated,
261+
// but do at least mention the fact that there are non-merge commits in the
262+
// first-parent line, so folks who are curious can click through to GitHub for
263+
// details.
264+
args := []string{"log", "--no-merges", "--first-parent", "-z", "--format=%H", fmt.Sprintf("%s..%s", from, to)}
265+
out, err := g.exec(args...)
266+
if err != nil {
267+
return nil, 0, gitOutputToError(err, out)
268+
}
269+
elidedCommits = strings.Count(out, "\x00")
257270
}
258271

259272
if klog.V(5).Enabled() {
@@ -262,16 +275,16 @@ func mergeLogForRepo(g gitInterface, repo string, from, to string) ([]MergeCommi
262275

263276
var commits []MergeCommit
264277
if len(out) == 0 {
265-
return nil, nil
278+
return nil, elidedCommits, nil
266279
}
267280
for _, entry := range strings.Split(out, "\x00") {
268281
records := strings.Split(entry, "\x1e")
269282
if len(records) != 4 {
270-
return nil, fmt.Errorf("unexpected git log output width %d columns", len(records))
283+
return nil, elidedCommits, fmt.Errorf("unexpected git log output width %d columns", len(records))
271284
}
272285
unixTS, err := strconv.ParseInt(records[1], 10, 64)
273286
if err != nil {
274-
return nil, fmt.Errorf("unexpected timestamp: %v", err)
287+
return nil, elidedCommits, fmt.Errorf("unexpected timestamp: %v", err)
275288
}
276289
commitValues := strings.Split(records[0], " ")
277290

@@ -304,7 +317,7 @@ func mergeLogForRepo(g gitInterface, repo string, from, to string) ([]MergeCommi
304317
}
305318
mergeCommit.PullRequest, err = strconv.Atoi(m[1])
306319
if err != nil {
307-
return nil, fmt.Errorf("could not extract PR number from %q: %v", mergeMsg, err)
320+
return nil, elidedCommits, fmt.Errorf("could not extract PR number from %q: %v", mergeMsg, err)
308321
}
309322
if len(msg) == 0 {
310323
msg = "Merge"
@@ -314,7 +327,7 @@ func mergeLogForRepo(g gitInterface, repo string, from, to string) ([]MergeCommi
314327
commits = append(commits, mergeCommit)
315328
}
316329

317-
return commits, nil
330+
return commits, elidedCommits, nil
318331
}
319332

320333
// ensureCloneForRepo ensures that the repo exists on disk, is cloned, and has remotes for

pkg/cli/admin/release/git_test.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,15 @@ func (g fakeGit) exec(commands ...string) (string, error) {
2222

2323
func Test_mergeLogForRepo(t *testing.T) {
2424
tests := []struct {
25-
name string
26-
input string
27-
repo string
28-
from string
29-
to string
30-
squash bool
31-
want []MergeCommit
32-
wantErr bool
25+
name string
26+
input string
27+
repo string
28+
from string
29+
to string
30+
squash bool
31+
want []MergeCommit
32+
wantElidedCommits int
33+
wantErr bool
3334
}{
3435
{
3536
input: "abc\x1e1\x1eMerge pull request #145 from\x1eBug 1743564: test",
@@ -291,14 +292,17 @@ func Test_mergeLogForRepo(t *testing.T) {
291292
for _, tt := range tests {
292293
t.Run(tt.name, func(t *testing.T) {
293294
g := fakeGit{input: tt.input, squash: tt.squash}
294-
got, err := mergeLogForRepo(g, tt.repo, "a", "b")
295+
got, elidedCommits, err := mergeLogForRepo(g, tt.repo, "a", "b")
295296
if (err != nil) != tt.wantErr {
296297
t.Errorf("mergeLogForRepo() error = %v, wantErr %v", err, tt.wantErr)
297298
return
298299
}
299300
if !reflect.DeepEqual(got, tt.want) {
300301
t.Errorf("mergeLogForRepo(): %s", diff.ObjectReflectDiff(tt.want, got))
301302
}
303+
if elidedCommits != tt.wantElidedCommits {
304+
t.Errorf("mergeLogForRepo(): %d elided commits report differs from expected %d", elidedCommits, tt.wantElidedCommits)
305+
}
302306
})
303307
}
304308
}

pkg/cli/admin/release/info.go

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1794,16 +1794,17 @@ func describeChangelog(out, errOut io.Writer, releaseInfo *ReleaseInfo, diff *Re
17941794
}
17951795
}
17961796
for _, change := range codeChanges {
1797-
u, commits, err := commitsForRepo(dir, change, out, errOut)
1797+
u, commits, elidedCommits, err := commitsForRepo(dir, change, out, errOut)
17981798
if err != nil {
17991799
fmt.Fprintf(errOut, "error: %v\n", err)
18001800
hasError = true
18011801
continue
18021802
}
1803-
if len(commits) > 0 {
1803+
if len(commits) > 0 || elidedCommits > 0 {
18041804
info := ChangeLogImageInfo{
1805-
Name: strings.Join(change.ImagesAffected, ", "),
1806-
Commits: []CommitInfo{},
1805+
Name: strings.Join(change.ImagesAffected, ", "),
1806+
Commits: []CommitInfo{},
1807+
ElidedCommits: elidedCommits,
18071808
}
18081809
if u.Host == "github.com" {
18091810
info.Path = fmt.Sprintf("https://github.com%s/tree/%s", u.Path, change.To)
@@ -1903,13 +1904,13 @@ func describeChangelog(out, errOut io.Writer, releaseInfo *ReleaseInfo, diff *Re
19031904
}
19041905

19051906
for _, change := range codeChanges {
1906-
u, commits, err := commitsForRepo(dir, change, out, errOut)
1907+
u, commits, elidedCommits, err := commitsForRepo(dir, change, out, errOut)
19071908
if err != nil {
19081909
fmt.Fprintf(errOut, "error: %v\n", err)
19091910
hasError = true
19101911
continue
19111912
}
1912-
if len(commits) > 0 {
1913+
if len(commits) > 0 || elidedCommits > 0 {
19131914
if u.Host == "github.com" {
19141915
fmt.Fprintf(out, "### [%s](https://github.com%s/tree/%s)\n\n", strings.Join(change.ImagesAffected, ", "), u.Path, change.To)
19151916
} else {
@@ -1930,6 +1931,9 @@ func describeChangelog(out, errOut io.Writer, releaseInfo *ReleaseInfo, diff *Re
19301931
}
19311932
fmt.Fprintf(out, "\n")
19321933
}
1934+
if elidedCommits > 0 {
1935+
fmt.Fprintf(out, "* And %d elided commits (e.g. from squash or rebase merges)\n", elidedCommits)
1936+
}
19331937
if u.Host == "github.com" {
19341938
fmt.Fprintf(out, "* [Full changelog](%s)\n\n", fmt.Sprintf("https://%s%s/compare/%s...%s", u.Host, u.Path, change.From, change.To))
19351939
} else {
@@ -1955,7 +1959,7 @@ func describeBugs(out, errOut io.Writer, diff *ReleaseDiff, dir string, format s
19551959

19561960
bugIDs := make(map[string]Ref)
19571961
for _, change := range codeChanges {
1958-
_, commits, err := commitsForRepo(dir, change, out, errOut)
1962+
_, commits, _, err := commitsForRepo(dir, change, out, errOut)
19591963
if err != nil {
19601964
fmt.Fprintf(errOut, "error: %v\n", err)
19611965
hasError = true
@@ -2479,20 +2483,20 @@ func (c CodeChange) ToShort() string {
24792483
return c.To
24802484
}
24812485

2482-
func commitsForRepo(dir string, change CodeChange, out, errOut io.Writer) (*url.URL, []MergeCommit, error) {
2486+
func commitsForRepo(dir string, change CodeChange, out, errOut io.Writer) (*url.URL, []MergeCommit, int, error) {
24832487
u, err := sourceLocationAsURL(change.Repo)
24842488
if err != nil {
2485-
return nil, nil, fmt.Errorf("The source repository cannot be parsed %s: %v", change.Repo, err)
2489+
return nil, nil, 0, fmt.Errorf("The source repository cannot be parsed %s: %v", change.Repo, err)
24862490
}
24872491
g, err := ensureCloneForRepo(dir, change.Repo, change.AlternateRepos, errOut, errOut)
24882492
if err != nil {
2489-
return nil, nil, err
2493+
return u, nil, 0, err
24902494
}
2491-
commits, err := mergeLogForRepo(g, change.Repo, change.From, change.To)
2495+
commits, elidedCommits, err := mergeLogForRepo(g, change.Repo, change.From, change.To)
24922496
if err != nil {
2493-
return nil, nil, fmt.Errorf("Could not load commits for %s: %v", change.Repo, err)
2497+
return u, commits, elidedCommits, fmt.Errorf("Could not load commits for %s: %v", change.Repo, err)
24942498
}
2495-
return u, commits, nil
2499+
return u, commits, elidedCommits, nil
24962500
}
24972501

24982502
func releaseDiffContentChanges(diff *ReleaseDiff) ([]CodeChange, []ImageChange, []string) {
@@ -2733,6 +2737,7 @@ type ChangeLogImageInfo struct {
27332737
Commit string `json:"commit,omitempty"`
27342738
ImageRef string `json:"imageRef,omitempty"`
27352739
Commits []CommitInfo `json:"commits,omitempty"`
2740+
ElidedCommits int `json:"elidedCommits,omitempty"`
27362741
FullChangeLog string `json:"fullChangeLog,omitempty"`
27372742
}
27382743

0 commit comments

Comments
 (0)