Skip to content

Commit cd4a94a

Browse files
authored
Merge pull request #580 from stevekuznetsov/skuznets/better-sort
scripts/bumper: improve sort order
2 parents e98b8f0 + 0158c8c commit cd4a94a

File tree

1 file changed

+50
-10
lines changed

1 file changed

+50
-10
lines changed

scripts/bumper/main.go

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
"os/signal"
1313
"path/filepath"
1414
"regexp"
15-
"sort"
15+
"strconv"
1616
"strings"
1717
"text/tabwriter"
1818
"time"
@@ -57,6 +57,7 @@ type options struct {
5757
logLevel string
5858
centralRef string
5959
fetchMode string
60+
history int
6061

6162
dryRun bool
6263
githubLogin string
@@ -80,6 +81,7 @@ func (o *options) Bind(fs *flag.FlagSet) {
8081
fs.StringVar(&o.logLevel, "log-level", logrus.InfoLevel.String(), "Logging level.")
8182
fs.StringVar(&o.centralRef, "central-ref", "origin/master", "Git ref for the central branch that will be updated, used as the base for determining what commits need to be cherry-picked.")
8283
fs.StringVar(&o.fetchMode, "fetch-mode", string(ssh), "Method to use for fetching from git remotes.")
84+
fs.IntVar(&o.history, "history", 1, "How many commits back to start searching for missing vendor commits.")
8385

8486
fs.BoolVar(&o.dryRun, "dry-run", true, "Whether to actually create the pull request with github client")
8587
fs.StringVar(&o.githubLogin, "github-login", githubLogin, "The GitHub username to use.")
@@ -165,7 +167,7 @@ func main() {
165167
logrus.WithError(err).Fatal("could not unmarshal input commits")
166168
}
167169
} else {
168-
commits, err = detectNewCommits(ctx, logger.WithField("phase", "detect"), opts.stagingDir, opts.centralRef, fetchMode(opts.fetchMode))
170+
commits, err = detectNewCommits(ctx, logger.WithField("phase", "detect"), opts.stagingDir, opts.centralRef, fetchMode(opts.fetchMode), opts.history)
169171
if err != nil {
170172
logger.WithError(err).Fatal("failed to detect commits")
171173
}
@@ -266,7 +268,7 @@ type commit struct {
266268
var repoRegex = regexp.MustCompile(`Upstream-repository: ([^ ]+)\n`)
267269
var commitRegex = regexp.MustCompile(`Upstream-commit: ([a-f0-9]+)\n`)
268270

269-
func detectNewCommits(ctx context.Context, logger *logrus.Entry, stagingDir, centralRef string, mode fetchMode) ([]commit, error) {
271+
func detectNewCommits(ctx context.Context, logger *logrus.Entry, stagingDir, centralRef string, mode fetchMode, history int) ([]commit, error) {
270272
lastCommits := map[string]string{}
271273
if err := fs.WalkDir(os.DirFS(stagingDir), ".", func(path string, d fs.DirEntry, err error) error {
272274
if err != nil {
@@ -284,11 +286,12 @@ func detectNewCommits(ctx context.Context, logger *logrus.Entry, stagingDir, cen
284286
output, err := runCommand(logger, exec.CommandContext(ctx,
285287
"git", "log",
286288
centralRef,
287-
"-n", "1",
289+
"-n", strconv.Itoa(history),
288290
"--grep", "Upstream-repository: "+path,
289291
"--grep", "Upstream-commit",
290292
"--all-match",
291293
"--pretty=%B",
294+
"--reverse",
292295
"--",
293296
filepath.Join(stagingDir, path),
294297
))
@@ -315,7 +318,7 @@ func detectNewCommits(ctx context.Context, logger *logrus.Entry, stagingDir, cen
315318
return nil, fmt.Errorf("failed to walk %s: %w", stagingDir, err)
316319
}
317320

318-
var commits []commit
321+
commits := map[string][]commit{}
319322
for repo, lastCommit := range lastCommits {
320323
var remote string
321324
switch mode {
@@ -335,6 +338,7 @@ func detectNewCommits(ctx context.Context, logger *logrus.Entry, stagingDir, cen
335338
output, err := runCommand(logger, exec.CommandContext(ctx,
336339
"git", "log",
337340
"--pretty=%H",
341+
"--no-merges",
338342
lastCommit+"...FETCH_HEAD",
339343
))
340344
if err != nil {
@@ -365,7 +369,10 @@ func detectNewCommits(ctx context.Context, logger *logrus.Entry, stagingDir, cen
365369
if err != nil {
366370
return nil, fmt.Errorf("invalid time %s: %w", parts[1], err)
367371
}
368-
commits = append(commits, commit{
372+
if _, ok := commits[repo]; !ok {
373+
commits[repo] = []commit{}
374+
}
375+
commits[repo] = append(commits[repo], commit{
369376
Hash: parts[0],
370377
Date: committedTime,
371378
Author: parts[2],
@@ -375,10 +382,43 @@ func detectNewCommits(ctx context.Context, logger *logrus.Entry, stagingDir, cen
375382
}
376383
}
377384
}
378-
sort.Slice(commits, func(i, j int) bool {
379-
return commits[i].Date.Before(commits[j].Date)
380-
})
381-
return commits, nil
385+
// we would like to intertwine the commits from each upstream repository by date, while
386+
// keeping the order of commits from any one repository in the order they were committed in
387+
var orderedCommits []commit
388+
indices := map[string]int{}
389+
for repo := range commits {
390+
indices[repo] = 0
391+
}
392+
for {
393+
// find which repo's commit stack we should pop off to get the next earliest commit
394+
nextTime := time.Now()
395+
var nextRepo string
396+
for repo, index := range indices {
397+
if commits[repo][index].Date.Before(nextTime) {
398+
nextTime = commits[repo][index].Date
399+
nextRepo = repo
400+
}
401+
}
402+
403+
// pop the commit, add it to our list and do housekeeping for our index records
404+
orderedCommits = append(orderedCommits, commits[nextRepo][indices[nextRepo]])
405+
if indices[nextRepo] == len(commits[nextRepo])-1 {
406+
delete(indices, nextRepo)
407+
} else {
408+
indices[nextRepo] += 1
409+
}
410+
411+
if len(indices) == 0 {
412+
break
413+
}
414+
}
415+
416+
// our ordered list is descending, but we need to cherry-pick from the oldest first
417+
var reversedCommits []commit
418+
for i := range orderedCommits {
419+
reversedCommits = append(reversedCommits, orderedCommits[len(orderedCommits)-i-1])
420+
}
421+
return reversedCommits, nil
382422
}
383423

384424
func isCommitMissing(ctx context.Context, logger *logrus.Entry, stagingDir string, c commit) (bool, error) {

0 commit comments

Comments
 (0)