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  }