github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/scripts/ci/target-version-pr/main.go (about)

     1  package main
     2  
     3  import (
     4  	"os"
     5  	"strconv"
     6  	"strings"
     7  
     8  	"github.com/ActiveState/cli/internal/errs"
     9  	wc "github.com/ActiveState/cli/scripts/internal/workflow-controllers"
    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  func main() {
    18  	if err := run(); err != nil {
    19  		wc.Print("Error: %s\n", errs.JoinMessage(err))
    20  		os.Exit(1)
    21  	}
    22  }
    23  
    24  type Meta struct {
    25  	Repo              *github.Repository
    26  	ActivePR          *github.PullRequest
    27  	ActiveStory       *jira.Issue
    28  	ActiveVersion     wh.Version
    29  	ActiveJiraVersion string
    30  	VersionPRName     string
    31  	TargetBranchName  string
    32  	VersionPR         *github.PullRequest
    33  	IsVersionPR       bool
    34  }
    35  
    36  func (m Meta) GetVersion() semver.Version {
    37  	return m.ActiveVersion.Version
    38  }
    39  
    40  func (m Meta) GetJiraVersion() string {
    41  	return m.ActiveJiraVersion
    42  }
    43  
    44  func (m Meta) GetVersionBranchName() string {
    45  	return m.TargetBranchName
    46  }
    47  
    48  func (m Meta) GetVersionPRName() string {
    49  	return m.VersionPRName
    50  }
    51  
    52  func run() error {
    53  	finish := wc.PrintStart("Initializing clients")
    54  	// Initialize Clients
    55  	ghClient := wh.InitGHClient()
    56  	jiraClient, err := wh.InitJiraClient()
    57  	if err != nil {
    58  		return errs.Wrap(err, "failed to initialize Jira client")
    59  	}
    60  	finish()
    61  
    62  	// Grab input
    63  	if len(os.Args) != 2 {
    64  		return errs.New("Usage: target-version-branch <pr-number>")
    65  	}
    66  	prNumber, err := strconv.Atoi(os.Args[1])
    67  	if err != nil {
    68  		return errs.Wrap(err, "pr number should be numeric")
    69  	}
    70  
    71  	finish = wc.PrintStart("Fetching meta for PR %d", prNumber)
    72  	// Collect meta information about the PR and all it's related resources
    73  	meta, err := fetchMeta(ghClient, jiraClient, prNumber)
    74  	if err != nil {
    75  		return errs.Wrap(err, "failed to fetch meta")
    76  	}
    77  	finish()
    78  
    79  	// Create version PR if it doesn't exist yet
    80  	if !meta.IsVersionPR && meta.VersionPR == nil && !meta.ActiveVersion.EQ(wh.VersionMaster) {
    81  		finish = wc.PrintStart("Creating version PR for fixVersion %s", meta.ActiveVersion)
    82  		err := wc.CreateVersionPR(ghClient, jiraClient, meta)
    83  		if err != nil {
    84  			return errs.Wrap(err, "failed to create version PR")
    85  		}
    86  		finish()
    87  	}
    88  
    89  	// Set the target branch for our PR
    90  	finish = wc.PrintStart("Setting target branch to %s", meta.TargetBranchName)
    91  	if strings.HasSuffix(meta.ActivePR.GetBase().GetRef(), meta.TargetBranchName) {
    92  		wc.Print("PR already targets version branch %s", meta.TargetBranchName)
    93  	} else {
    94  		if os.Getenv("DRYRUN") != "true" {
    95  			if err := wh.UpdatePRTargetBranch(ghClient, meta.ActivePR.GetNumber(), meta.TargetBranchName); err != nil {
    96  				return errs.Wrap(err, "failed to update PR target branch")
    97  			}
    98  		} else {
    99  			wc.Print("DRYRUN: would update PR target branch to %s", meta.TargetBranchName)
   100  		}
   101  	}
   102  	finish()
   103  
   104  	// Set the fixVersion
   105  	if !meta.IsVersionPR {
   106  		finish = wc.PrintStart("Setting fixVersion to %s", meta.ActiveVersion)
   107  		if len(meta.ActiveStory.Fields.FixVersions) == 0 || meta.ActiveStory.Fields.FixVersions[0].ID != meta.ActiveVersion.JiraID {
   108  			if os.Getenv("DRYRUN") != "true" {
   109  				if err := wh.UpdateJiraFixVersion(jiraClient, meta.ActiveStory, meta.ActiveVersion.JiraID); err != nil {
   110  					return errs.Wrap(err, "failed to update Jira fixVersion")
   111  				}
   112  			} else {
   113  				wc.Print("DRYRUN: would set fixVersion to %s", meta.ActiveVersion.String())
   114  			}
   115  		} else {
   116  			wc.Print("Jira issue already has fixVersion %s", meta.ActiveVersion.String())
   117  		}
   118  		finish()
   119  	}
   120  
   121  	wc.Print("All Done")
   122  
   123  	return nil
   124  }
   125  
   126  func fetchMeta(ghClient *github.Client, jiraClient *jira.Client, prNumber int) (Meta, error) {
   127  	// Grab PR information about the PR that this automation is being ran on
   128  	finish := wc.PrintStart("Fetching Active PR %d", prNumber)
   129  	prBeingHandled, _, err := ghClient.PullRequests.Get(context.Background(), "ActiveState", "cli", prNumber)
   130  	if err != nil {
   131  		return Meta{}, errs.Wrap(err, "failed to get PR")
   132  	}
   133  	wc.Print("PR retrieved: %s", prBeingHandled.GetTitle())
   134  	finish()
   135  
   136  	if wh.IsVersionBranch(prBeingHandled.Head.GetRef()) {
   137  		return Meta{
   138  			Repo:             &github.Repository{},
   139  			ActivePR:         prBeingHandled,
   140  			TargetBranchName: "beta",
   141  			IsVersionPR:      true,
   142  		}, nil
   143  	}
   144  	finish = wc.PrintStart("Extracting Jira Issue ID from Active PR: %s", prBeingHandled.GetTitle())
   145  	jiraIssueID, err := wh.ExtractJiraIssueID(prBeingHandled)
   146  	if err != nil {
   147  		return Meta{}, errs.Wrap(err, "PR does not have Jira issue ID associated with it: %s", prBeingHandled.Links.GetHTML().GetHRef())
   148  	}
   149  	wc.Print("Extracted Jira Issue ID: %s", jiraIssueID)
   150  	finish()
   151  
   152  	// Retrieve Relevant Jira Issue for PR being handled
   153  	finish = wc.PrintStart("Fetching Jira issue")
   154  	jiraIssue, err := wh.FetchJiraIssue(jiraClient, jiraIssueID)
   155  	if err != nil {
   156  		return Meta{}, errs.Wrap(err, "failed to get Jira issue")
   157  	}
   158  	finish()
   159  
   160  	finish = wc.PrintStart("Fetching Jira Versions")
   161  	availableVersions, err := wh.FetchAvailableVersions(jiraClient)
   162  	if err != nil {
   163  		return Meta{}, errs.Wrap(err, "Failed to fetch JIRA issue")
   164  	}
   165  	finish()
   166  
   167  	// Retrieve Relevant Fixversion
   168  	finish = wc.PrintStart("Extracting target fixVersion from Jira issue")
   169  	fixVersion, jiraVersion, err := wh.ParseTargetFixVersion(jiraIssue, availableVersions)
   170  	if err != nil {
   171  		return Meta{}, errs.Wrap(err, "failed to get fixVersion")
   172  	}
   173  	wc.Print("Extracted fixVersion: %s", fixVersion)
   174  	finish()
   175  
   176  	var versionPRName string
   177  	var versionPR *github.PullRequest
   178  	if fixVersion.NE(wh.VersionMaster) {
   179  		versionPRName := wh.VersionedPRTitle(fixVersion.Version)
   180  
   181  		// Retrieve Relevant Fixversion Pr
   182  		finish = wc.PrintStart("Fetching Version PR by name: '%s'", versionPRName)
   183  		versionPR, err = wh.FetchPRByTitle(ghClient, versionPRName)
   184  		if err != nil {
   185  			return Meta{}, errs.Wrap(err, "failed to get target PR")
   186  		}
   187  		if versionPR != nil && versionPR.GetState() != "open" {
   188  			return Meta{}, errs.New("PR status for %s is not open, make sure your jira fixVersion is targeting an unreleased version", versionPR.GetTitle())
   189  		}
   190  		if versionPR == nil {
   191  			wc.Print("No version PR found")
   192  		}
   193  		finish()
   194  	}
   195  
   196  	result := Meta{
   197  		Repo:              &github.Repository{},
   198  		ActivePR:          prBeingHandled,
   199  		ActiveStory:       jiraIssue,
   200  		ActiveVersion:     fixVersion,
   201  		ActiveJiraVersion: jiraVersion.Name,
   202  		VersionPRName:     versionPRName,
   203  		TargetBranchName:  wh.VersionedBranchName(fixVersion.Version),
   204  		VersionPR:         versionPR,
   205  	}
   206  
   207  	return result, nil
   208  }