github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/scripts/internal/workflow-controllers/pr.go (about)

     1  package wc
     2  
     3  import (
     4  	"fmt"
     5  	"net/url"
     6  	"os"
     7  	"strings"
     8  
     9  	"github.com/ActiveState/cli/internal/errs"
    10  	wh "github.com/ActiveState/cli/scripts/internal/workflow-helpers"
    11  	"github.com/andygrunwald/go-jira"
    12  	"github.com/blang/semver"
    13  	"github.com/google/go-github/v45/github"
    14  	"golang.org/x/net/context"
    15  )
    16  
    17  type Meta interface {
    18  	GetVersion() semver.Version
    19  	GetJiraVersion() string
    20  	GetVersionBranchName() string
    21  	GetVersionPRName() string
    22  }
    23  
    24  func DetectBaseRef(ghClient *github.Client, jiraClient *jira.Client, meta Meta) (string, error) {
    25  	if meta.GetVersion().EQ(wh.VersionMaster) {
    26  		return wh.MasterBranch, nil
    27  	}
    28  
    29  	// Check if master is safe to fork from
    30  	finish := PrintStart("Checking if master is safe to fork from for version %s", meta.GetVersion())
    31  	var ref *string
    32  	versionsGT, err := wh.BranchHasVersionsGT(ghClient, jiraClient, wh.MasterBranch, meta.GetVersion())
    33  	if err != nil {
    34  		return "", errs.Wrap(err, "failed to check if can fork master")
    35  	}
    36  
    37  	// Calculate SHA for master
    38  	if !versionsGT {
    39  		Print("Master is safe")
    40  		finish2 := PrintStart("Getting master HEAD SHA")
    41  		branch, _, err := ghClient.Repositories.GetBranch(context.Background(), "ActiveState", "cli", wh.MasterBranch, false)
    42  		if err != nil {
    43  			return "", errs.Wrap(err, "failed to get branch info")
    44  		}
    45  		ref = branch.GetCommit().SHA
    46  		Print("Master SHA: " + *ref)
    47  		finish2()
    48  	} else {
    49  		Print("Master is unsafe as it has versions greater than %s", meta.GetVersion())
    50  	}
    51  	finish()
    52  
    53  	// Master is unsafe, detect closest matching PR instead
    54  	if ref == nil {
    55  		finish = PrintStart("Finding nearest matching version PR to fork from")
    56  		prevVersionPR, err := wh.FetchVersionPR(ghClient, wh.AssertLT, meta.GetVersion())
    57  		if err != nil {
    58  			return "", errs.Wrap(err,
    59  				"Failed to find fork branch, please manually create the Version PR "+
    60  					"for '%s' by running the create-version-pr script.",
    61  				meta.GetVersion())
    62  		}
    63  
    64  		ref = prevVersionPR.Head.SHA
    65  		Print("Nearest matching PR: %s (%d), branch: %s, SHA: %s",
    66  			prevVersionPR.GetTitle(), prevVersionPR.GetNumber(), prevVersionPR.Head.GetRef(), *ref)
    67  		finish()
    68  	}
    69  
    70  	return *ref, nil
    71  }
    72  
    73  func CreateVersionPR(ghClient *github.Client, jiraClient *jira.Client, meta Meta) error {
    74  	finish := PrintStart("Detecting base ref to fork from")
    75  	prevVersionRef, err := DetectBaseRef(ghClient, jiraClient, meta)
    76  	if err != nil {
    77  		return errs.Wrap(err, "failed to detect base ref")
    78  	}
    79  	finish()
    80  
    81  	// Create branch
    82  	finish = PrintStart("Creating version branch, name: %s, forked from: %s", meta.GetVersionBranchName(), prevVersionRef)
    83  	dryRun := os.Getenv("DRYRUN") == "true"
    84  	if !dryRun {
    85  		if err := wh.CreateBranch(ghClient, meta.GetVersionBranchName(), prevVersionRef); err != nil {
    86  			if !strings.Contains(err.Error(), "Reference already exists") {
    87  				return errs.Wrap(err, "failed to create branch")
    88  			}
    89  			Print("Branch already exists, continuing")
    90  		}
    91  	} else {
    92  		Print("DRYRUN: skip")
    93  	}
    94  	finish()
    95  
    96  	// Create commit with version.txt change
    97  	finish = PrintStart("Creating commit with version.txt change")
    98  	parentSha, err := wh.CreateFileUpdateCommit(ghClient, meta.GetVersionBranchName(), "version.txt", meta.GetVersion().String(), wh.UpdateVersionCommitMessage)
    99  	if err != nil {
   100  		return errs.Wrap(err, "failed to create commit")
   101  	}
   102  	Print("Created commit SHA: %s", parentSha)
   103  	finish()
   104  
   105  	// Prepare PR Body
   106  	body := fmt.Sprintf(`[View %s tickets on Jira](%s)`,
   107  		meta.GetVersion(),
   108  		"https://activestatef.atlassian.net/jira/software/c/projects/DX/issues/?jql="+
   109  			url.QueryEscape(fmt.Sprintf(`project = "DX" AND fixVersion=%s ORDER BY created DESC`, meta.GetJiraVersion())),
   110  	)
   111  
   112  	// Create PR
   113  	finish = PrintStart("Creating version PR, name: %s", meta.GetVersionPRName())
   114  	if !dryRun {
   115  		versionPR, err := wh.CreatePR(ghClient, meta.GetVersionPRName(), meta.GetVersionBranchName(), wh.StagingBranch, body)
   116  		if err != nil {
   117  			return errs.Wrap(err, "failed to create target PR")
   118  		}
   119  
   120  		if err := wh.LabelPR(ghClient, versionPR.GetNumber(), []string{"Test: all"}); err != nil {
   121  			return errs.Wrap(err, "failed to label PR")
   122  		}
   123  	} else {
   124  		fmt.Printf("DRYRUN: would create PR with body:\n%s\n", body)
   125  	}
   126  	finish()
   127  
   128  	return nil
   129  }