commit
e0dbf37b5a
3 changed files with 157 additions and 1 deletions
|
|
@ -953,6 +953,27 @@ func PullRequestMerge(client *Client, repo ghrepo.Interface, pr *PullRequest, m
|
|||
return err
|
||||
}
|
||||
|
||||
func PullRequestReady(client *Client, repo ghrepo.Interface, pr *PullRequest) error {
|
||||
var mutation struct {
|
||||
MarkPullRequestReadyForReviewInput struct {
|
||||
PullRequest struct {
|
||||
ID githubv4.ID
|
||||
}
|
||||
} `graphql:"markPullRequestReadyForReview(input: $input)"`
|
||||
}
|
||||
|
||||
type MarkPullRequestReadyForReviewInput struct {
|
||||
PullRequestID githubv4.ID `json:"pullRequestId"`
|
||||
}
|
||||
|
||||
input := MarkPullRequestReadyForReviewInput{PullRequestID: pr.ID}
|
||||
|
||||
v4 := githubv4.NewClient(client.http)
|
||||
err := v4.Mutate(context.Background(), &mutation, input, nil)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func min(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ func init() {
|
|||
prMergeCmd.Flags().BoolP("merge", "m", true, "Merge the commits with the base branch")
|
||||
prMergeCmd.Flags().BoolP("rebase", "r", false, "Rebase the commits onto the base branch")
|
||||
prMergeCmd.Flags().BoolP("squash", "s", false, "Squash the commits into one commit and merge it into the base branch")
|
||||
prCmd.AddCommand(prReadyCmd)
|
||||
|
||||
prCmd.AddCommand(prListCmd)
|
||||
prListCmd.Flags().IntP("limit", "L", 30, "Maximum number of items to fetch")
|
||||
|
|
@ -84,13 +85,18 @@ var prReopenCmd = &cobra.Command{
|
|||
Args: cobra.ExactArgs(1),
|
||||
RunE: prReopen,
|
||||
}
|
||||
|
||||
var prMergeCmd = &cobra.Command{
|
||||
Use: "merge [<number> | <url> | <branch>]",
|
||||
Short: "Merge a pull request",
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
RunE: prMerge,
|
||||
}
|
||||
var prReadyCmd = &cobra.Command{
|
||||
Use: "ready [<number> | <url> | <branch>]",
|
||||
Short: "Make a pull request as ready for review",
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
RunE: prReady,
|
||||
}
|
||||
|
||||
func prStatus(cmd *cobra.Command, args []string) error {
|
||||
ctx := contextForCommand(cmd)
|
||||
|
|
@ -551,6 +557,66 @@ func printPrPreview(out io.Writer, pr *api.PullRequest) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func prReady(cmd *cobra.Command, args []string) error {
|
||||
ctx := contextForCommand(cmd)
|
||||
apiClient, err := apiClientForContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
baseRepo, err := determineBaseRepo(apiClient, cmd, ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var pr *api.PullRequest
|
||||
if len(args) > 0 {
|
||||
var prNumber string
|
||||
n, _ := prFromURL(args[0])
|
||||
if n != "" {
|
||||
prNumber = n
|
||||
} else {
|
||||
prNumber = args[0]
|
||||
}
|
||||
|
||||
pr, err = prFromArg(apiClient, baseRepo, prNumber)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
prNumber, branchWithOwner, err := prSelectorForCurrentBranch(ctx, baseRepo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if prNumber != 0 {
|
||||
pr, err = api.PullRequestByNumber(apiClient, baseRepo, prNumber)
|
||||
} else {
|
||||
pr, err = api.PullRequestForBranch(apiClient, baseRepo, "", branchWithOwner)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if pr.Closed {
|
||||
err := fmt.Errorf("%s Pull request #%d is closed. Only draft pull requests can be marked as \"ready for review\"", utils.Red("!"), pr.Number)
|
||||
return err
|
||||
} else if !pr.IsDraft {
|
||||
fmt.Fprintf(colorableErr(cmd), "%s Pull request #%d is already \"ready for review\"\n", utils.Yellow("!"), pr.Number)
|
||||
return nil
|
||||
}
|
||||
|
||||
err = api.PullRequestReady(apiClient, baseRepo, pr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("API call failed: %w", err)
|
||||
}
|
||||
|
||||
fmt.Fprintf(colorableErr(cmd), "%s Pull request #%d is marked as \"ready for review\"\n", utils.Green("✔"), pr.Number)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Ref. https://developer.github.com/v4/enum/pullrequestreviewstate/
|
||||
const (
|
||||
requestedReviewState = "REQUESTED" // This is our own state for review request
|
||||
|
|
|
|||
|
|
@ -1093,3 +1093,72 @@ func TestPrMerge_alreadyMerged(t *testing.T) {
|
|||
t.Fatalf("output did not match regexp /%s/\n> output\n%q\n", r, output.Stderr())
|
||||
}
|
||||
}
|
||||
|
||||
func TestPRReady(t *testing.T) {
|
||||
initBlankContext("", "OWNER/REPO", "master")
|
||||
http := initFakeHTTP()
|
||||
http.StubRepoResponse("OWNER", "REPO")
|
||||
http.StubResponse(200, bytes.NewBufferString(`
|
||||
{ "data": { "repository": {
|
||||
"pullRequest": { "number": 444, "closed": false, "isDraft": true}
|
||||
} } }
|
||||
`))
|
||||
http.StubResponse(200, bytes.NewBufferString(`{"id": "THE-ID"}`))
|
||||
|
||||
output, err := RunCommand("pr ready 444")
|
||||
if err != nil {
|
||||
t.Fatalf("error running command `pr ready`: %v", err)
|
||||
}
|
||||
|
||||
r := regexp.MustCompile(`Pull request #444 is marked as "ready for review"`)
|
||||
|
||||
if !r.MatchString(output.Stderr()) {
|
||||
t.Fatalf("output did not match regexp /%s/\n> output\n%q\n", r, output.Stderr())
|
||||
}
|
||||
}
|
||||
|
||||
func TestPRReady_alreadyReady(t *testing.T) {
|
||||
initBlankContext("", "OWNER/REPO", "master")
|
||||
http := initFakeHTTP()
|
||||
http.StubRepoResponse("OWNER", "REPO")
|
||||
http.StubResponse(200, bytes.NewBufferString(`
|
||||
{ "data": { "repository": {
|
||||
"pullRequest": { "number": 445, "closed": false, "isDraft": false}
|
||||
} } }
|
||||
`))
|
||||
http.StubResponse(200, bytes.NewBufferString(`{"id": "THE-ID"}`))
|
||||
|
||||
output, err := RunCommand("pr ready 445")
|
||||
if err != nil {
|
||||
t.Fatalf("error running command `pr ready`: %v", err)
|
||||
}
|
||||
|
||||
r := regexp.MustCompile(`Pull request #445 is already "ready for review"`)
|
||||
|
||||
if !r.MatchString(output.Stderr()) {
|
||||
t.Fatalf("output did not match regexp /%s/\n> output\n%q\n", r, output.Stderr())
|
||||
}
|
||||
}
|
||||
|
||||
func TestPRReady_closed(t *testing.T) {
|
||||
initBlankContext("", "OWNER/REPO", "master")
|
||||
http := initFakeHTTP()
|
||||
http.StubRepoResponse("OWNER", "REPO")
|
||||
http.StubResponse(200, bytes.NewBufferString(`
|
||||
{ "data": { "repository": {
|
||||
"pullRequest": { "number": 446, "closed": true, "isDraft": true}
|
||||
} } }
|
||||
`))
|
||||
http.StubResponse(200, bytes.NewBufferString(`{"id": "THE-ID"}`))
|
||||
|
||||
_, err := RunCommand("pr ready 446")
|
||||
if err == nil {
|
||||
t.Fatalf("expected an error running command `pr ready` on a review that is closed!: %v", err)
|
||||
}
|
||||
|
||||
r := regexp.MustCompile(`Pull request #446 is closed. Only draft pull requests can be marked as "ready for review"`)
|
||||
|
||||
if !r.MatchString(err.Error()) {
|
||||
t.Fatalf("output did not match regexp /%s/\n> output\n%q\n", r, err.Error())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue