github.com/LGUG2Z/story@v0.4.1/cli/merge.go (about)

     1  package cli
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net/http"
     7  	"time"
     8  
     9  	"github.com/LGUG2Z/story/git"
    10  	"github.com/LGUG2Z/story/manifest"
    11  	"github.com/fatih/color"
    12  	"github.com/google/go-github/github"
    13  	"github.com/spf13/afero"
    14  	"github.com/urfave/cli"
    15  )
    16  
    17  func MergeCmd(fs afero.Fs) cli.Command {
    18  	return cli.Command{
    19  		Name:  "merge",
    20  		Usage: "Merges prepared code to master branches across the current story",
    21  		Flags: []cli.Flag{
    22  			cli.BoolFlag{Name: "github", Usage: "Use the GitHub squash and merge implementation via API"},
    23  			cli.StringFlag{Name: "github-api-token", EnvVar: "GITHUB_API_TOKEN", Usage: "GitHub API token to authenticate with"},
    24  		},
    25  		Action: cli.ActionFunc(func(c *cli.Context) error {
    26  			if !isStory {
    27  				return ErrNotWorkingOnAStory
    28  			}
    29  
    30  			if c.Args().Present() {
    31  				return ErrCommandTakesNoArguments
    32  			}
    33  
    34  			currentBranch, err := git.GetCurrentBranch(fs, ".")
    35  			if err != nil {
    36  				return err
    37  			}
    38  
    39  			story, err := manifest.LoadStoryFromBranchName(fs, currentBranch)
    40  			if err != nil {
    41  				return err
    42  			}
    43  
    44  			messages := []string{fmt.Sprintf("[story merge] Merge branch '%s'", story.Name)}
    45  
    46  			if c.Bool("github") {
    47  				if len(c.String("github-api-token")) == 0 {
    48  					return ErrGitHubAPITokenRequired
    49  				}
    50  
    51  				ctx := context.Background()
    52  				client := getGitHubClient(ctx, c.String("github-api-token"))
    53  
    54  				story.Projects[metarepo] = ""
    55  
    56  				for project := range story.Projects {
    57  					color.Green(project)
    58  					// Get the open pull request
    59  					openPullRequest, err := getOpenPullRequest(client, ctx, story, project)
    60  					if err != nil {
    61  						switch err.Error() {
    62  						// If there is no open pull request
    63  						case ErrCouldNotFindOpenPullRequest(story.Name).Error():
    64  							// Get the closed pull request
    65  							closedPullRequest, err := getClosedPullRequest(client, ctx, story, project)
    66  							if err != nil {
    67  								switch err.Error() {
    68  								// If there is no closed pull request, a pull request was never opened
    69  								case ErrCouldNotFindClosedPullRequest(story.Name).Error():
    70  									fmt.Printf("could not find an open or closed pull request for %s\n", story.Name)
    71  									continue
    72  								// Something else went wrong here with the call to list closed pull requests
    73  								default:
    74  									fmt.Println(err)
    75  									continue
    76  								}
    77  							}
    78  
    79  							// Report that the pull request has already been closed with a link
    80  							fmt.Println("pull request has already been closed")
    81  							fmt.Println(*closedPullRequest.HTMLURL)
    82  							continue
    83  						// Something else went wrong here with the call to list open pull requests
    84  						default:
    85  							return err
    86  						}
    87  					}
    88  
    89  					_, resp, err := client.PullRequests.Merge(ctx, story.Orgranisation, project, *openPullRequest.Number, "", &github.PullRequestOptions{
    90  						CommitTitle: messages[0],
    91  						MergeMethod: "squash",
    92  						SHA:         story.Hashes[project],
    93  					})
    94  
    95  					if err != nil {
    96  						return err
    97  					}
    98  
    99  					switch resp.StatusCode {
   100  					case http.StatusOK:
   101  						fmt.Println("pull request successfully merged")
   102  					case http.StatusMethodNotAllowed:
   103  						fmt.Println("pull request is not mergeable")
   104  					case http.StatusConflict:
   105  						fmt.Println("head branch was modified, review and try the merge again")
   106  					}
   107  
   108  					fmt.Println(*openPullRequest.HTMLURL)
   109  					time.Sleep(1 * time.Second)
   110  				}
   111  
   112  				return nil
   113  			}
   114  
   115  			// Checkout master and merge story in all projects
   116  			for project := range story.Projects {
   117  				color.Green(project)
   118  				checkoutBranchOutput, err := git.CheckoutBranch(git.CheckoutBranchOpts{
   119  					Branch:  trunk,
   120  					Project: project,
   121  					Create:  false,
   122  				})
   123  
   124  				if err != nil {
   125  					return err
   126  				}
   127  
   128  				fmt.Printf("%s\n\n", checkoutBranchOutput)
   129  
   130  				mergeOutput, err := git.Merge(git.MergeOpts{
   131  					SourceBranch:      story.Name,
   132  					DestinationBranch: trunk,
   133  					Project:           project,
   134  					Squash:            true,
   135  				})
   136  
   137  				if err != nil {
   138  					return err
   139  				}
   140  
   141  				fmt.Printf("%s\n\n", mergeOutput)
   142  
   143  				commitOutput, err := git.Commit(
   144  					git.CommitOpts{
   145  						Project:  project,
   146  						Messages: messages,
   147  					},
   148  				)
   149  
   150  				if err != nil {
   151  					return err
   152  				}
   153  
   154  				fmt.Println(commitOutput)
   155  			}
   156  
   157  			color.Green(metarepo)
   158  			checkoutBranchOutput, err := git.CheckoutBranch(git.CheckoutBranchOpts{
   159  				Branch: trunk,
   160  				Create: false,
   161  			})
   162  
   163  			if err != nil {
   164  				return err
   165  			}
   166  
   167  			fmt.Printf("%s\n\n", checkoutBranchOutput)
   168  
   169  			// Merge story into master on the metarepo
   170  			mergeOutput, err := git.Merge(git.MergeOpts{
   171  				SourceBranch:      story.Name,
   172  				DestinationBranch: trunk,
   173  				Squash:            true,
   174  			})
   175  
   176  			if err != nil {
   177  				return err
   178  			}
   179  
   180  			fmt.Printf("%s\n\n", mergeOutput)
   181  
   182  			commitOutput, err := git.Commit(git.CommitOpts{Messages: messages})
   183  			if err != nil {
   184  				return err
   185  			}
   186  
   187  			fmt.Println(commitOutput)
   188  
   189  			return nil
   190  		}),
   191  	}
   192  }