github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/scripts/grab-mergecommits/main.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "os" 6 "os/exec" 7 "strings" 8 "time" 9 10 "github.com/ActiveState/cli/internal/errs" 11 "github.com/ActiveState/cli/internal/osutils" 12 "github.com/ActiveState/cli/internal/sliceutils" 13 wh "github.com/ActiveState/cli/scripts/internal/workflow-helpers" 14 "github.com/thoas/go-funk" 15 ) 16 17 // cutoff tells the script not to look at PRs before this date. 18 // You want to set this to the date when development on the given version started 19 var cutoff, _ = time.Parse("2006-Jan-02", "2022-Apr-25") 20 21 func main() { 22 if err := run(); err != nil { 23 fmt.Printf("Failed: %s", errs.JoinMessage(err)) 24 os.Exit(1) 25 } 26 fmt.Println("Done") 27 } 28 29 func run() error { 30 if len(os.Args) < 2 { 31 return errs.New("Invalid arguments, please provide the version tag as the first argument") 32 } 33 targetVersion := os.Args[1] 34 35 ghClient := wh.InitGHClient() 36 jiraClient, err := wh.InitJiraClient() 37 if err != nil { 38 return errs.Wrap(err, "failed to initialize Jira client") 39 } 40 41 // Grab target stories from jira 42 issues, _, err := jiraClient.Issue.Search(fmt.Sprintf(`project = "DX" AND fixVersion=%s ORDER BY created DESC`, targetVersion), nil) 43 if err != nil { 44 return errs.Wrap(err, "Could not find issues") 45 } 46 47 // Create map of issue ID's by iterating over issues and extracting the ID property 48 var jiraIssueIDs = make(map[string]struct{}) 49 for _, issue := range issues { 50 jiraIssueIDs[strings.ToUpper(issue.Key)] = struct{}{} 51 } 52 53 fmt.Printf("Found %d issues: %v\n", len(issues), funk.Keys(jiraIssueIDs)) 54 55 // Grab github PRs to compare against jira stories, cause Jira's API does not tell us what the linker PR is 56 prs, err := wh.FetchPRs(ghClient, cutoff, nil) 57 if err != nil { 58 return errs.Wrap(err, "Could not find PRs") 59 } 60 61 fmt.Printf("Found %d PRs\n", len(prs)) 62 63 missingIDs := []string{} 64 resultCommits := []string{} 65 for _, pr := range prs { 66 if pr.MergeCommitSHA == nil || *pr.MergeCommitSHA == "" || pr.Base.GetRef() != "master" { 67 continue 68 } 69 70 commit := pr.GetMergeCommitSHA()[0:7] 71 72 jiraIssueID, err := wh.ExtractJiraIssueID(pr) 73 if err != nil { 74 missingIDs = append(missingIDs, fmt.Sprintf("%s (branch: %s, commit: %s): %s", *pr.Title, pr.Head.GetRef(), commit, pr.Links.GetHTML().GetHRef())) 75 continue 76 } 77 78 _, ok := jiraIssueIDs[jiraIssueID] 79 if !ok { 80 continue 81 } 82 83 fmt.Printf("Adding %s (branch: %s, commit: %s) as it matches Jira issue %s\n", *pr.Title, pr.Head.GetRef(), commit, jiraIssueID) 84 resultCommits = append(resultCommits, commit) 85 } 86 87 fmt.Printf("\nMissing Jira ID:\n%s\n\nCommits to merge: %s\n", strings.Join(missingIDs, "\n"), strings.Join(orderCommits(resultCommits), " ")) 88 89 return nil 90 } 91 92 // Order the commits by calling out to `git merge-base --is-ancestor commit1 commit2` 93 func orderCommits(hashes []string) []string { 94 ordered := []string{} 95 for _, hash := range hashes { 96 handled := false 97 for oidx, ohash := range ordered { 98 code, _, err := osutils.Execute("git", []string{"merge-base", "--is-ancestor", hash, ohash}, nil) 99 if err != nil && !errs.Matches(err, &exec.ExitError{}) { 100 panic(err) 101 } 102 if code == 0 { 103 ordered = sliceutils.InsertStringAt(ordered, oidx, hash) 104 handled = true 105 break 106 } 107 } 108 if !handled { 109 ordered = append(ordered, hash) 110 } 111 } 112 return ordered 113 }