github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/scripts/start-story/main.go (about) 1 package main 2 3 import ( 4 "os" 5 "strings" 6 7 "github.com/ActiveState/cli/internal/environment" 8 "github.com/ActiveState/cli/internal/errs" 9 "github.com/ActiveState/cli/internal/osutils" 10 wc "github.com/ActiveState/cli/scripts/internal/workflow-controllers" 11 wh "github.com/ActiveState/cli/scripts/internal/workflow-helpers" 12 "github.com/andygrunwald/go-jira" 13 "github.com/blang/semver" 14 "github.com/google/go-github/v45/github" 15 "github.com/thoas/go-funk" 16 ) 17 18 func main() { 19 if err := run(); err != nil { 20 wc.Print("Error: %s\n", errs.JoinMessage(err)) 21 } 22 } 23 24 type Meta struct { 25 Version semver.Version 26 JiraIssue *jira.Issue 27 JiraVersion string 28 VersionPRName string 29 VersionBranchName string 30 VersionPR *github.PullRequest 31 } 32 33 func (m Meta) GetVersion() semver.Version { 34 return m.Version 35 } 36 37 func (m Meta) GetJiraVersion() string { 38 return m.JiraVersion 39 } 40 41 func (m Meta) GetVersionBranchName() string { 42 return m.VersionBranchName 43 } 44 45 func (m Meta) GetVersionPRName() string { 46 return m.VersionPRName 47 } 48 49 func run() error { 50 finish := wc.PrintStart("Initializing clients") 51 // Initialize Clients 52 ghClient := wh.InitGHClient() 53 jiraClient, err := wh.InitJiraClient() 54 if err != nil { 55 return errs.Wrap(err, "failed to initialize Jira client") 56 } 57 finish() 58 59 finish = wc.PrintStart("Verifying input") 60 // Grab input 61 if len(os.Args) < 2 { 62 return errs.New("Usage: start-story <story-id> [branch-name]") 63 } 64 jiraIssueID := os.Args[1] 65 66 branchName := jiraIssueID 67 if len(os.Args) > 2 { 68 branchName = os.Args[1] 69 detectedIssueID, err := wh.ParseJiraKey(branchName) 70 if err != nil { 71 return errs.Wrap(err, "failed to parse Jira key from branch name") 72 } 73 if !strings.EqualFold(detectedIssueID, jiraIssueID) { 74 return errs.New("Branch name contains story ID %s, but story being targeted is %s", detectedIssueID, jiraIssueID) 75 } 76 } 77 finish() 78 79 finish = wc.PrintStart("Fetching meta for story %s", jiraIssueID) 80 // Collect meta information about the PR and all it's related resources 81 meta, err := fetchMeta(ghClient, jiraClient, jiraIssueID) 82 if err != nil { 83 return errs.Wrap(err, "failed to fetch meta") 84 } 85 finish() 86 87 ref := "" 88 if meta.VersionPR != nil { 89 ref = meta.VersionPR.Head.GetRef() 90 } else { 91 finish := wc.PrintStart("Detecting base ref to fork from") 92 ref, err = wc.DetectBaseRef(ghClient, jiraClient, meta) 93 if err != nil { 94 return errs.Wrap(err, "failed to detect base ref") 95 } 96 finish() 97 } 98 99 finish = wc.PrintStart("Creating branch: %s from ref: %s", branchName, ref) 100 if os.Getenv("DRYRUN") == "true" { 101 wc.Print("DRY RUN: Skipping") 102 finish() 103 return nil 104 } 105 106 stdout, stderr, err := osutils.ExecSimpleFromDir(environment.GetRootPathUnsafe(), "git", []string{"checkout", ref}, nil) 107 if err != nil { 108 return errs.Wrap(err, "failed to checkout base ref, stdout:\n%s\nstderr:\n%s", stdout, stderr) 109 } 110 stdout, stderr, err = osutils.ExecSimpleFromDir(environment.GetRootPathUnsafe(), "git", []string{"pull", "--rebase"}, nil) 111 if err != nil { 112 return errs.Wrap(err, "failed to pull latest changes, stdout:\n%s\nstderr:\n%s", stdout, stderr) 113 } 114 stdout, stderr, err = osutils.ExecSimpleFromDir(environment.GetRootPathUnsafe(), "git", []string{"branch", branchName}, nil) 115 if err != nil { 116 return errs.Wrap(err, "failed to create branch, stdout:\n%s\nstderr:\n%s", stdout, stderr) 117 } 118 stdout, stderr, err = osutils.ExecSimpleFromDir(environment.GetRootPathUnsafe(), "git", []string{"checkout", branchName}, nil) 119 if err != nil { 120 return errs.Wrap(err, "failed to checkout branch, stdout:\n%s\nstderr:\n%s", stdout, stderr) 121 } 122 finish() 123 124 if meta.JiraIssue.Fields.Status.Name == wh.JiraStatusTodo || meta.JiraIssue.Fields.Status.Name == wh.JiraStatusPending { 125 finish = wc.PrintStart("Updating jira issue to In Progress") 126 if err := wh.UpdateJiraStatus(jiraClient, meta.JiraIssue, wh.JiraStatusInProgress); err != nil { 127 return errs.Wrap(err, "failed to update Jira status") 128 } 129 finish() 130 } 131 132 wc.Print("All Done") 133 134 return nil 135 } 136 137 func fetchMeta(ghClient *github.Client, jiraClient *jira.Client, jiraIssueID string) (Meta, error) { 138 // Retrieve Relevant Jira Issue for PR being handled 139 finish := wc.PrintStart("Fetching Jira issue") 140 jiraIssue, err := wh.FetchJiraIssue(jiraClient, jiraIssueID) 141 if err != nil { 142 return Meta{}, errs.Wrap(err, "failed to get Jira issue") 143 } 144 finish() 145 146 if len(jiraIssue.Fields.FixVersions) == 0 || jiraIssue.Fields.FixVersions[0] == nil { 147 return Meta{}, errs.New("Jira issue does not have a fix version") 148 } 149 fixVersion := jiraIssue.Fields.FixVersions[0] 150 151 if fixVersion.Archived != nil && *fixVersion.Archived || fixVersion.Released != nil && *fixVersion.Released { 152 return Meta{}, errs.New("Target issue has fixVersion '%s', which has either been archived or released\n", fixVersion.Name) 153 } 154 155 if !funk.ContainsString([]string{wh.JiraStatusTodo, wh.JiraStatusInProgress, wh.JiraStatusPending}, jiraIssue.Fields.Status.Name) { 156 return Meta{}, errs.New("Story is in the %s state, but only '%s', '%s' and '%s' are valid states to start a story from.", 157 jiraIssue.Fields.Status.Name, wh.JiraStatusTodo, wh.JiraStatusInProgress, wh.JiraStatusPending) 158 } 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 finish = wc.PrintStart("Parsing version") 168 version, jiraVersion, err := wh.ParseTargetFixVersion(jiraIssue, availableVersions) 169 if err != nil { 170 return Meta{}, errs.Wrap(err, "failed to parse version") 171 } 172 finish() 173 174 var versionPR *github.PullRequest 175 var versionPRName string 176 if version.NE(wh.VersionMaster) { 177 versionPRName = wh.VersionedPRTitle(version.Version) 178 179 // Retrieve Relevant Fixversion Pr 180 finish = wc.PrintStart("Checking if Version PR with title '%s' exists", versionPRName) 181 versionPR, err = wh.FetchPRByTitle(ghClient, versionPRName) 182 if err != nil { 183 return Meta{}, errs.Wrap(err, "failed to get target PR") 184 } 185 wc.Print("Exists: %v", versionPR != nil) 186 finish() 187 } 188 189 return Meta{ 190 Version: version.Version, 191 JiraIssue: jiraIssue, 192 JiraVersion: jiraVersion.Name, 193 VersionPR: versionPR, 194 VersionPRName: versionPRName, 195 VersionBranchName: wh.VersionedBranchName(version.Version), 196 }, nil 197 }