From 5d1b52e79db668e5990671a02159366f20247099 Mon Sep 17 00:00:00 2001 From: srafi1 Date: Fri, 15 Nov 2019 16:07:47 -0500 Subject: [PATCH 01/19] empty transfer command --- commands/issue.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/commands/issue.go b/commands/issue.go index 4fd238eda..c9690e692 100644 --- a/commands/issue.go +++ b/commands/issue.go @@ -218,6 +218,11 @@ hub-pr(1), hub(1) --color `, } + + cmdTransferIssue = &Command{ + Key: "transfer", + Run: transferIssue, + } ) func init() { @@ -710,3 +715,7 @@ func milestoneValueToNumber(value string, client *github.Client, project *github return 0, fmt.Errorf("error: no milestone found with name '%s'", value) } + +func transferIssue(cmd *Command, args *Args) { + ui.Println("transferring issue") +} From 14dc440aeefeee90dff3143271adf93c64908454 Mon Sep 17 00:00:00 2001 From: srafi1 Date: Fri, 15 Nov 2019 16:31:33 -0500 Subject: [PATCH 02/19] registered command to be used --- commands/issue.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/commands/issue.go b/commands/issue.go index c9690e692..6f102b603 100644 --- a/commands/issue.go +++ b/commands/issue.go @@ -219,16 +219,17 @@ hub-pr(1), hub(1) `, } - cmdTransferIssue = &Command{ - Key: "transfer", - Run: transferIssue, - } + cmdTransfer = &Command{ + Key: "transfer", + Run: transferIssue, + } ) func init() { cmdIssue.Use(cmdShowIssue) cmdIssue.Use(cmdCreateIssue) cmdIssue.Use(cmdLabel) + cmdIssue.Use(cmdTransfer) CmdRunner.Use(cmdIssue) } @@ -717,5 +718,6 @@ func milestoneValueToNumber(value string, client *github.Client, project *github } func transferIssue(cmd *Command, args *Args) { - ui.Println("transferring issue") + ui.Println("transferring issue") + args.NoForward() } From 58e8a890748b4c4abf19c92338eefe3b396982bd Mon Sep 17 00:00:00 2001 From: srafi1 Date: Sat, 16 Nov 2019 19:19:57 -0500 Subject: [PATCH 03/19] get issueid using graphql --- commands/issue.go | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/commands/issue.go b/commands/issue.go index 6f102b603..97ad6cafc 100644 --- a/commands/issue.go +++ b/commands/issue.go @@ -2,6 +2,7 @@ package commands import ( "fmt" + "io" "os" "strconv" "strings" @@ -718,6 +719,33 @@ func milestoneValueToNumber(value string, client *github.Client, project *github } func transferIssue(cmd *Command, args *Args) { - ui.Println("transferring issue") + issueNumber := args.GetParam(0) + //targetRepo := args.GetParam(1) + + localRepo, err := github.LocalRepo() + utils.Check(err) + + project, err := localRepo.MainProject() + utils.Check(err) + + owner := project.Owner + currRepo := project.Name + host := project.Host + + query := fmt.Sprintf(`query($issue: Int = %s, $owner: String = "%s", $repo: String = "%s") { + repository(owner: $owner, name: $repo) { + issue(number: $issue) { + id + } + } + }`, issueNumber, owner, currRepo) + body := make(map[string]interface{}) + body["query"] = query + + gh := github.NewClient(host) + response, err := gh.GenericAPIRequest("POST", "graphql", body, nil, 0) + utils.Check(err) + io.Copy(ui.Stdout, response.Body) + args.NoForward() } From 7f124dfbee6b7c0cbcb59302246878350f90da48 Mon Sep 17 00:00:00 2001 From: srafi1 Date: Sat, 16 Nov 2019 20:06:13 -0500 Subject: [PATCH 04/19] unmarshal issueID out of response data --- commands/issue.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/commands/issue.go b/commands/issue.go index 97ad6cafc..31fa058ae 100644 --- a/commands/issue.go +++ b/commands/issue.go @@ -2,7 +2,6 @@ package commands import ( "fmt" - "io" "os" "strconv" "strings" @@ -745,7 +744,16 @@ func transferIssue(cmd *Command, args *Args) { gh := github.NewClient(host) response, err := gh.GenericAPIRequest("POST", "graphql", body, nil, 0) utils.Check(err) - io.Copy(ui.Stdout, response.Body) + + responseData := make(map[string]interface{}) + err = response.Unmarshal(&responseData) + utils.Check(err) + + data := responseData["data"].(map[string]interface{}) + repository := data["repository"].(map[string]interface{}) + issue := repository["issue"].(map[string]interface{}) + issueID := issue["id"].(string) + ui.Printf("issueID: %s\n", issueID) args.NoForward() } From c313ea8fe25acc7cd3d3d41b90477a5b9f3306d0 Mon Sep 17 00:00:00 2001 From: srafi1 Date: Sat, 16 Nov 2019 20:37:47 -0500 Subject: [PATCH 05/19] request and unmarshal repositoryID --- commands/issue.go | 59 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/commands/issue.go b/commands/issue.go index 31fa058ae..69819e6fa 100644 --- a/commands/issue.go +++ b/commands/issue.go @@ -719,7 +719,7 @@ func milestoneValueToNumber(value string, client *github.Client, project *github func transferIssue(cmd *Command, args *Args) { issueNumber := args.GetParam(0) - //targetRepo := args.GetParam(1) + targetRepo := args.GetParam(1) localRepo, err := github.LocalRepo() utils.Check(err) @@ -730,30 +730,55 @@ func transferIssue(cmd *Command, args *Args) { owner := project.Owner currRepo := project.Name host := project.Host + gh := github.NewClient(host) - query := fmt.Sprintf(`query($issue: Int = %s, $owner: String = "%s", $repo: String = "%s") { - repository(owner: $owner, name: $repo) { - issue(number: $issue) { - id - } - } - }`, issueNumber, owner, currRepo) + query := fmt.Sprintf(` + query($issue: Int = %s, $owner: String = "%s", $repo: String = "%s") { + repository(owner: $owner, name: $repo) { + issue(number: $issue) { + id + } + } + }`, issueNumber, owner, currRepo) body := make(map[string]interface{}) body["query"] = query - gh := github.NewClient(host) response, err := gh.GenericAPIRequest("POST", "graphql", body, nil, 0) utils.Check(err) - responseData := make(map[string]interface{}) - err = response.Unmarshal(&responseData) - utils.Check(err) + ui.Printf("status: %d\n", response.StatusCode) + + responseData := make(map[string]interface{}) + err = response.Unmarshal(&responseData) + utils.Check(err) + + data := responseData["data"].(map[string]interface{}) + repository := data["repository"].(map[string]interface{}) + issue := repository["issue"].(map[string]interface{}) + issueID := issue["id"].(string) + ui.Printf("issueID: %s\n", issueID) + + query = fmt.Sprintf(` + query($owner: String = "%s", $repo: String = "%s") { + repository(owner: $owner, name: $repo) { + id + } + }`, owner, targetRepo) + body["query"] = query + + response, err = gh.GenericAPIRequest("POST", "graphql", body, nil, 0) + utils.Check(err) + + ui.Printf("status: %d\n", response.StatusCode) + + responseData = make(map[string]interface{}) + err = response.Unmarshal(&responseData) + utils.Check(err) - data := responseData["data"].(map[string]interface{}) - repository := data["repository"].(map[string]interface{}) - issue := repository["issue"].(map[string]interface{}) - issueID := issue["id"].(string) - ui.Printf("issueID: %s\n", issueID) + data = responseData["data"].(map[string]interface{}) + repository = data["repository"].(map[string]interface{}) + repositoryID := repository["id"].(string) + ui.Printf("repositoryID: %s\n", repositoryID) args.NoForward() } From 493fc9cefd6f4e00fcf22bc839e3d29644e9f97f Mon Sep 17 00:00:00 2001 From: srafi1 Date: Sat, 16 Nov 2019 20:52:09 -0500 Subject: [PATCH 06/19] error checking --- commands/issue.go | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/commands/issue.go b/commands/issue.go index 69819e6fa..4f69470d3 100644 --- a/commands/issue.go +++ b/commands/issue.go @@ -718,6 +718,11 @@ func milestoneValueToNumber(value string, client *github.Client, project *github } func transferIssue(cmd *Command, args *Args) { + if args.ParamsSize() < 2 { + ui.Errorln("error: expected two parameters") + os.Exit(1) + } + issueNumber := args.GetParam(0) targetRepo := args.GetParam(1) @@ -746,17 +751,20 @@ func transferIssue(cmd *Command, args *Args) { response, err := gh.GenericAPIRequest("POST", "graphql", body, nil, 0) utils.Check(err) - ui.Printf("status: %d\n", response.StatusCode) - responseData := make(map[string]interface{}) err = response.Unmarshal(&responseData) utils.Check(err) - data := responseData["data"].(map[string]interface{}) - repository := data["repository"].(map[string]interface{}) - issue := repository["issue"].(map[string]interface{}) - issueID := issue["id"].(string) - ui.Printf("issueID: %s\n", issueID) + if _, keyExists := responseData["errors"]; keyExists { + ui.Errorf("Error finding issue number: %s\n", issueNumber) + os.Exit(1) + } else { + data := responseData["data"].(map[string]interface{}) + repository := data["repository"].(map[string]interface{}) + issue := repository["issue"].(map[string]interface{}) + issueID := issue["id"].(string) + ui.Printf("issueID: %s\n", issueID) + } query = fmt.Sprintf(` query($owner: String = "%s", $repo: String = "%s") { @@ -764,21 +772,24 @@ func transferIssue(cmd *Command, args *Args) { id } }`, owner, targetRepo) - body["query"] = query + body["query"] = query response, err = gh.GenericAPIRequest("POST", "graphql", body, nil, 0) utils.Check(err) - ui.Printf("status: %d\n", response.StatusCode) - responseData = make(map[string]interface{}) err = response.Unmarshal(&responseData) utils.Check(err) - data = responseData["data"].(map[string]interface{}) - repository = data["repository"].(map[string]interface{}) - repositoryID := repository["id"].(string) - ui.Printf("repositoryID: %s\n", repositoryID) + if _, keyExists := responseData["errors"]; keyExists { + ui.Errorf("Error finding repository: %s\n", targetRepo) + os.Exit(1) + } else { + data := responseData["data"].(map[string]interface{}) + repository := data["repository"].(map[string]interface{}) + repositoryID := repository["id"].(string) + ui.Printf("repositoryID: %s\n", repositoryID) + } args.NoForward() } From 9915cbd98110f1bc304d8ab9db7b2757f5b3fc90 Mon Sep 17 00:00:00 2001 From: srafi1 Date: Sat, 16 Nov 2019 21:22:15 -0500 Subject: [PATCH 07/19] transfer issue and check for errors --- commands/issue.go | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/commands/issue.go b/commands/issue.go index 4f69470d3..75794b07e 100644 --- a/commands/issue.go +++ b/commands/issue.go @@ -719,13 +719,15 @@ func milestoneValueToNumber(value string, client *github.Client, project *github func transferIssue(cmd *Command, args *Args) { if args.ParamsSize() < 2 { - ui.Errorln("error: expected two parameters") + ui.Errorln("Error: expected two parameters") os.Exit(1) } issueNumber := args.GetParam(0) targetRepo := args.GetParam(1) + var issueID, repositoryID string + localRepo, err := github.LocalRepo() utils.Check(err) @@ -762,8 +764,7 @@ func transferIssue(cmd *Command, args *Args) { data := responseData["data"].(map[string]interface{}) repository := data["repository"].(map[string]interface{}) issue := repository["issue"].(map[string]interface{}) - issueID := issue["id"].(string) - ui.Printf("issueID: %s\n", issueID) + issueID = issue["id"].(string) } query = fmt.Sprintf(` @@ -782,13 +783,37 @@ func transferIssue(cmd *Command, args *Args) { utils.Check(err) if _, keyExists := responseData["errors"]; keyExists { - ui.Errorf("Error finding repository: %s\n", targetRepo) + ui.Errorf("Error finding repository: %s/%s\n", owner, targetRepo) os.Exit(1) } else { data := responseData["data"].(map[string]interface{}) repository := data["repository"].(map[string]interface{}) - repositoryID := repository["id"].(string) - ui.Printf("repositoryID: %s\n", repositoryID) + repositoryID = repository["id"].(string) + } + + query = fmt.Sprintf(` + mutation($issue: ID = "%s", $repo: ID = "%s") { + transferIssue(input: {issueId: $issue, repositoryId: $repo}) { + issue { + url + } + } + } + `, issueID, repositoryID) + body["query"] = query + + response, err = gh.GenericAPIRequest("POST", "graphql", body, nil, 0) + utils.Check(err) + + responseData = make(map[string]interface{}) + err = response.Unmarshal(&responseData) + utils.Check(err) + + if _, keyExists := responseData["errors"]; keyExists { + ui.Errorf("Error transferring the issue\n") + os.Exit(1) + } else { + ui.Printf("Transferred issue #%s to %s/%s\n", issueNumber, owner, targetRepo) } args.NoForward() From 05ad803de27ae750185b0813a121515750b1c0d5 Mon Sep 17 00:00:00 2001 From: srafi1 Date: Sat, 16 Nov 2019 21:30:27 -0500 Subject: [PATCH 08/19] transfer issue docs --- commands/issue.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/commands/issue.go b/commands/issue.go index 75794b07e..688b70c54 100644 --- a/commands/issue.go +++ b/commands/issue.go @@ -21,6 +21,7 @@ issue [-a ] [-c ] [-@ ] [-s ] [-f ] [-M issue show [-f ] issue create [-oc] [-m |-F ] [--edit] [-a ] [-M ] [-l ] issue labels [--color] +issue transfer `, Long: `Manage GitHub Issues for the current repository. @@ -37,6 +38,9 @@ With no arguments, show a list of open issues. * _labels_: List the labels available in this repository. + * _transfer_: + Transfer an issue to another repository. + ## Options: -a, --assignee In list mode, display only issues assigned to . @@ -719,14 +723,14 @@ func milestoneValueToNumber(value string, client *github.Client, project *github func transferIssue(cmd *Command, args *Args) { if args.ParamsSize() < 2 { - ui.Errorln("Error: expected two parameters") + ui.Errorln("Usage: hub issue transfer ") os.Exit(1) } issueNumber := args.GetParam(0) targetRepo := args.GetParam(1) - var issueID, repositoryID string + var issueID, repositoryID string localRepo, err := github.LocalRepo() utils.Check(err) @@ -791,7 +795,7 @@ func transferIssue(cmd *Command, args *Args) { repositoryID = repository["id"].(string) } - query = fmt.Sprintf(` + query = fmt.Sprintf(` mutation($issue: ID = "%s", $repo: ID = "%s") { transferIssue(input: {issueId: $issue, repositoryId: $repo}) { issue { @@ -800,7 +804,7 @@ func transferIssue(cmd *Command, args *Args) { } } `, issueID, repositoryID) - body["query"] = query + body["query"] = query response, err = gh.GenericAPIRequest("POST", "graphql", body, nil, 0) utils.Check(err) @@ -813,7 +817,7 @@ func transferIssue(cmd *Command, args *Args) { ui.Errorf("Error transferring the issue\n") os.Exit(1) } else { - ui.Printf("Transferred issue #%s to %s/%s\n", issueNumber, owner, targetRepo) + ui.Printf("Transferred issue #%s to %s/%s\n", issueNumber, owner, targetRepo) } args.NoForward() From 83a19478eecb17d1f0080528035c63842fe7a0f0 Mon Sep 17 00:00:00 2001 From: srafi1 Date: Thu, 21 Nov 2019 14:14:18 -0500 Subject: [PATCH 09/19] usage error fix --- commands/issue.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/commands/issue.go b/commands/issue.go index 83504e191..52886856a 100644 --- a/commands/issue.go +++ b/commands/issue.go @@ -224,8 +224,9 @@ hub-pr(1), hub(1) } cmdTransfer = &Command{ - Key: "transfer", - Run: transferIssue, + Key: "transfer", + Run: transferIssue, + Usage: "Usage: hub issue transfer ", } ) @@ -723,8 +724,7 @@ func milestoneValueToNumber(value string, client *github.Client, project *github func transferIssue(cmd *Command, args *Args) { if args.ParamsSize() < 2 { - ui.Errorln("Usage: hub issue transfer ") - os.Exit(1) + utils.Check(cmd.UsageError("")) } issueNumber := args.GetParam(0) From c278240b3598c9ca8ba644a92fcc7d218b717af9 Mon Sep 17 00:00:00 2001 From: srafi1 Date: Thu, 21 Nov 2019 14:41:52 -0500 Subject: [PATCH 10/19] fix parameter doc format --- commands/issue.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/issue.go b/commands/issue.go index 52886856a..5656f69d3 100644 --- a/commands/issue.go +++ b/commands/issue.go @@ -21,7 +21,7 @@ issue [-a ] [-c ] [-@ ] [-s ] [-f ] [-M issue show [-f ] issue create [-oc] [-m |-F ] [--edit] [-a ] [-M ] [-l ] issue labels [--color] -issue transfer +issue transfer `, Long: `Manage GitHub Issues for the current repository. From 127f2d5a6718fb0e849a47ac0753e1a4f9d89ea4 Mon Sep 17 00:00:00 2001 From: srafi1 Date: Thu, 21 Nov 2019 15:02:55 -0500 Subject: [PATCH 11/19] better unmarshalling strategy --- commands/issue.go | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/commands/issue.go b/commands/issue.go index 5656f69d3..3062b62c6 100644 --- a/commands/issue.go +++ b/commands/issue.go @@ -757,18 +757,27 @@ func transferIssue(cmd *Command, args *Args) { response, err := gh.GenericAPIRequest("POST", "graphql", body, nil, 0) utils.Check(err) - responseData := make(map[string]interface{}) - err = response.Unmarshal(&responseData) - utils.Check(err) + responseData := struct { + Data struct { + Repository struct { + Issue struct { + ID string `json:"id"` + } + ID string `json:"id"` + } + } + Errors []struct { + Message string + } + }{} + err = response.Unmarshal(&responseData) + utils.Check(err) - if _, keyExists := responseData["errors"]; keyExists { + if len(responseData.Errors) > 0 { ui.Errorf("Error finding issue number: %s\n", issueNumber) os.Exit(1) } else { - data := responseData["data"].(map[string]interface{}) - repository := data["repository"].(map[string]interface{}) - issue := repository["issue"].(map[string]interface{}) - issueID = issue["id"].(string) + issueID = responseData.Data.Repository.Issue.ID } query = fmt.Sprintf(` @@ -782,17 +791,14 @@ func transferIssue(cmd *Command, args *Args) { response, err = gh.GenericAPIRequest("POST", "graphql", body, nil, 0) utils.Check(err) - responseData = make(map[string]interface{}) err = response.Unmarshal(&responseData) utils.Check(err) - if _, keyExists := responseData["errors"]; keyExists { + if len(responseData.Errors) > 0 { ui.Errorf("Error finding repository: %s/%s\n", owner, targetRepo) os.Exit(1) } else { - data := responseData["data"].(map[string]interface{}) - repository := data["repository"].(map[string]interface{}) - repositoryID = repository["id"].(string) + repositoryID = responseData.Data.Repository.ID } query = fmt.Sprintf(` @@ -809,11 +815,10 @@ func transferIssue(cmd *Command, args *Args) { response, err = gh.GenericAPIRequest("POST", "graphql", body, nil, 0) utils.Check(err) - responseData = make(map[string]interface{}) err = response.Unmarshal(&responseData) utils.Check(err) - if _, keyExists := responseData["errors"]; keyExists { + if len(responseData.Errors) > 0 { ui.Errorf("Error transferring the issue\n") os.Exit(1) } else { From 872c82a8fb5fcf56f2550b6378ecc92a8dff993a Mon Sep 17 00:00:00 2001 From: srafi1 Date: Thu, 21 Nov 2019 15:04:19 -0500 Subject: [PATCH 12/19] fixed usage message --- commands/issue.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/issue.go b/commands/issue.go index 3062b62c6..96c18a1ff 100644 --- a/commands/issue.go +++ b/commands/issue.go @@ -226,7 +226,7 @@ hub-pr(1), hub(1) cmdTransfer = &Command{ Key: "transfer", Run: transferIssue, - Usage: "Usage: hub issue transfer ", + Usage: "issue transfer ", } ) From 4e60f9309da251f287566d9caec225fe3e211787 Mon Sep 17 00:00:00 2001 From: srafi1 Date: Thu, 21 Nov 2019 15:04:44 -0500 Subject: [PATCH 13/19] formatted with gofmt --- commands/issue.go | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/commands/issue.go b/commands/issue.go index 96c18a1ff..a5e466a44 100644 --- a/commands/issue.go +++ b/commands/issue.go @@ -757,21 +757,21 @@ func transferIssue(cmd *Command, args *Args) { response, err := gh.GenericAPIRequest("POST", "graphql", body, nil, 0) utils.Check(err) - responseData := struct { - Data struct { - Repository struct { - Issue struct { - ID string `json:"id"` - } - ID string `json:"id"` - } - } - Errors []struct { - Message string - } - }{} - err = response.Unmarshal(&responseData) - utils.Check(err) + responseData := struct { + Data struct { + Repository struct { + Issue struct { + ID string `json:"id"` + } + ID string `json:"id"` + } + } + Errors []struct { + Message string + } + }{} + err = response.Unmarshal(&responseData) + utils.Check(err) if len(responseData.Errors) > 0 { ui.Errorf("Error finding issue number: %s\n", issueNumber) From 4f85bc36f587d9058e0bb1dcc98e2437e014f8d0 Mon Sep 17 00:00:00 2001 From: srafi1 Date: Thu, 21 Nov 2019 15:12:21 -0500 Subject: [PATCH 14/19] more concise error messages --- commands/issue.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/commands/issue.go b/commands/issue.go index a5e466a44..ad807c111 100644 --- a/commands/issue.go +++ b/commands/issue.go @@ -774,8 +774,7 @@ func transferIssue(cmd *Command, args *Args) { utils.Check(err) if len(responseData.Errors) > 0 { - ui.Errorf("Error finding issue number: %s\n", issueNumber) - os.Exit(1) + utils.Check(fmt.Errorf("Error finding issue number: %s\n", issueNumber)) } else { issueID = responseData.Data.Repository.Issue.ID } @@ -795,8 +794,7 @@ func transferIssue(cmd *Command, args *Args) { utils.Check(err) if len(responseData.Errors) > 0 { - ui.Errorf("Error finding repository: %s/%s\n", owner, targetRepo) - os.Exit(1) + utils.Check(fmt.Errorf("Error finding repository: %s/%s\n", owner, targetRepo)) } else { repositoryID = responseData.Data.Repository.ID } @@ -819,8 +817,7 @@ func transferIssue(cmd *Command, args *Args) { utils.Check(err) if len(responseData.Errors) > 0 { - ui.Errorf("Error transferring the issue\n") - os.Exit(1) + utils.Check(fmt.Errorf("Error transferring the issue\n")) } else { ui.Printf("Transferred issue #%s to %s/%s\n", issueNumber, owner, targetRepo) } From 4d398ba983667f21b6130dd238faccf7972641f8 Mon Sep 17 00:00:00 2001 From: srafi1 Date: Mon, 25 Nov 2019 14:06:46 -0500 Subject: [PATCH 15/19] use a variables field in GraphQL requests --- commands/issue.go | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/commands/issue.go b/commands/issue.go index ad807c111..d6011eddc 100644 --- a/commands/issue.go +++ b/commands/issue.go @@ -730,6 +730,9 @@ func transferIssue(cmd *Command, args *Args) { issueNumber := args.GetParam(0) targetRepo := args.GetParam(1) + issueInt, err := strconv.ParseInt(issueNumber, 10, 64) + utils.Check(err) + var issueID, repositoryID string localRepo, err := github.LocalRepo() @@ -744,15 +747,22 @@ func transferIssue(cmd *Command, args *Args) { gh := github.NewClient(host) query := fmt.Sprintf(` - query($issue: Int = %s, $owner: String = "%s", $repo: String = "%s") { + query($issue: Int!, $owner: String!, $repo: String!) { repository(owner: $owner, name: $repo) { issue(number: $issue) { id } } - }`, issueNumber, owner, currRepo) - body := make(map[string]interface{}) - body["query"] = query + }`) + variables := map[string]interface{}{ + "issue": issueInt, + "owner": owner, + "repo": currRepo, + } + body := make(map[string]interface{}) + body["query"] = query + body["variables"] = variables + ui.Println(body) response, err := gh.GenericAPIRequest("POST", "graphql", body, nil, 0) utils.Check(err) @@ -780,12 +790,17 @@ func transferIssue(cmd *Command, args *Args) { } query = fmt.Sprintf(` - query($owner: String = "%s", $repo: String = "%s") { + query($owner: String!, $repo: String!) { repository(owner: $owner, name: $repo) { id } - }`, owner, targetRepo) + }`) + variables = map[string]interface{}{ + "owner": owner, + "repo": targetRepo, + } body["query"] = query + body["variables"] = variables response, err = gh.GenericAPIRequest("POST", "graphql", body, nil, 0) utils.Check(err) @@ -800,15 +815,20 @@ func transferIssue(cmd *Command, args *Args) { } query = fmt.Sprintf(` - mutation($issue: ID = "%s", $repo: ID = "%s") { + mutation($issue: ID!, $repo: ID!) { transferIssue(input: {issueId: $issue, repositoryId: $repo}) { issue { url } } } - `, issueID, repositoryID) + `) + variables = map[string]interface{}{ + "issue": issueID, + "repo": repositoryID, + } body["query"] = query + body["variables"] = variables response, err = gh.GenericAPIRequest("POST", "graphql", body, nil, 0) utils.Check(err) From 4786bcd817522eedd4bb28b673bff55f152e33f2 Mon Sep 17 00:00:00 2001 From: srafi1 Date: Mon, 25 Nov 2019 14:09:26 -0500 Subject: [PATCH 16/19] formatted with gofmt --- commands/issue.go | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/commands/issue.go b/commands/issue.go index d6011eddc..293dc8bd8 100644 --- a/commands/issue.go +++ b/commands/issue.go @@ -730,7 +730,7 @@ func transferIssue(cmd *Command, args *Args) { issueNumber := args.GetParam(0) targetRepo := args.GetParam(1) - issueInt, err := strconv.ParseInt(issueNumber, 10, 64) + issueInt, err := strconv.ParseInt(issueNumber, 10, 64) utils.Check(err) var issueID, repositoryID string @@ -754,15 +754,15 @@ func transferIssue(cmd *Command, args *Args) { } } }`) - variables := map[string]interface{}{ - "issue": issueInt, - "owner": owner, - "repo": currRepo, - } - body := make(map[string]interface{}) - body["query"] = query - body["variables"] = variables - ui.Println(body) + variables := map[string]interface{}{ + "issue": issueInt, + "owner": owner, + "repo": currRepo, + } + body := make(map[string]interface{}) + body["query"] = query + body["variables"] = variables + ui.Println(body) response, err := gh.GenericAPIRequest("POST", "graphql", body, nil, 0) utils.Check(err) @@ -795,12 +795,12 @@ func transferIssue(cmd *Command, args *Args) { id } }`) - variables = map[string]interface{}{ - "owner": owner, - "repo": targetRepo, - } + variables = map[string]interface{}{ + "owner": owner, + "repo": targetRepo, + } body["query"] = query - body["variables"] = variables + body["variables"] = variables response, err = gh.GenericAPIRequest("POST", "graphql", body, nil, 0) utils.Check(err) @@ -823,12 +823,12 @@ func transferIssue(cmd *Command, args *Args) { } } `) - variables = map[string]interface{}{ - "issue": issueID, - "repo": repositoryID, - } + variables = map[string]interface{}{ + "issue": issueID, + "repo": repositoryID, + } body["query"] = query - body["variables"] = variables + body["variables"] = variables response, err = gh.GenericAPIRequest("POST", "graphql", body, nil, 0) utils.Check(err) From dbecf7b0c8e50ca85a33f9d5f6750d1f2315a3b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Sun, 15 Dec 2019 20:48:11 +0100 Subject: [PATCH 17/19] [issue] Cleanup `transfer` implementation --- commands/issue.go | 158 ++++++++++++++++------------------------------ github/client.go | 39 ++++++++++++ 2 files changed, 94 insertions(+), 103 deletions(-) diff --git a/commands/issue.go b/commands/issue.go index 293dc8bd8..892d0e1dd 100644 --- a/commands/issue.go +++ b/commands/issue.go @@ -21,7 +21,7 @@ issue [-a ] [-c ] [-@ ] [-s ] [-f ] [-M issue show [-f ] issue create [-oc] [-m |-F ] [--edit] [-a ] [-M ] [-l ] issue labels [--color] -issue transfer +issue transfer `, Long: `Manage GitHub Issues for the current repository. @@ -224,9 +224,8 @@ hub-pr(1), hub(1) } cmdTransfer = &Command{ - Key: "transfer", - Run: transferIssue, - Usage: "issue transfer ", + Key: "transfer", + Run: transferIssue, } ) @@ -727,120 +726,73 @@ func transferIssue(cmd *Command, args *Args) { utils.Check(cmd.UsageError("")) } - issueNumber := args.GetParam(0) - targetRepo := args.GetParam(1) - - issueInt, err := strconv.ParseInt(issueNumber, 10, 64) - utils.Check(err) - - var issueID, repositoryID string - localRepo, err := github.LocalRepo() utils.Check(err) project, err := localRepo.MainProject() utils.Check(err) - owner := project.Owner - currRepo := project.Name - host := project.Host - gh := github.NewClient(host) - - query := fmt.Sprintf(` - query($issue: Int!, $owner: String!, $repo: String!) { - repository(owner: $owner, name: $repo) { - issue(number: $issue) { - id - } - } - }`) - variables := map[string]interface{}{ - "issue": issueInt, - "owner": owner, - "repo": currRepo, - } - body := make(map[string]interface{}) - body["query"] = query - body["variables"] = variables - ui.Println(body) - - response, err := gh.GenericAPIRequest("POST", "graphql", body, nil, 0) + issueNumber, err := strconv.Atoi(args.GetParam(0)) utils.Check(err) + targetOwner := project.Owner + targetRepo := args.GetParam(1) + if strings.Contains(targetRepo, "/") { + parts := strings.SplitN(targetRepo, "/", 2) + targetOwner = parts[0] + targetRepo = parts[1] + } - responseData := struct { - Data struct { - Repository struct { - Issue struct { - ID string `json:"id"` - } - ID string `json:"id"` + gh := github.NewClient(project.Host) + + nodeIDsResponse := struct { + Source struct { + Issue struct { + ID string } } - Errors []struct { - Message string + Target struct { + ID string } }{} - err = response.Unmarshal(&responseData) - utils.Check(err) - - if len(responseData.Errors) > 0 { - utils.Check(fmt.Errorf("Error finding issue number: %s\n", issueNumber)) - } else { - issueID = responseData.Data.Repository.Issue.ID - } - - query = fmt.Sprintf(` - query($owner: String!, $repo: String!) { - repository(owner: $owner, name: $repo) { - id - } - }`) - variables = map[string]interface{}{ - "owner": owner, - "repo": targetRepo, - } - body["query"] = query - body["variables"] = variables - - response, err = gh.GenericAPIRequest("POST", "graphql", body, nil, 0) - utils.Check(err) - - err = response.Unmarshal(&responseData) - utils.Check(err) - - if len(responseData.Errors) > 0 { - utils.Check(fmt.Errorf("Error finding repository: %s/%s\n", owner, targetRepo)) - } else { - repositoryID = responseData.Data.Repository.ID - } - - query = fmt.Sprintf(` - mutation($issue: ID!, $repo: ID!) { - transferIssue(input: {issueId: $issue, repositoryId: $repo}) { - issue { - url - } - } - } - `) - variables = map[string]interface{}{ - "issue": issueID, - "repo": repositoryID, - } - body["query"] = query - body["variables"] = variables - - response, err = gh.GenericAPIRequest("POST", "graphql", body, nil, 0) + err = gh.GraphQL(` + query($issue: Int!, $sourceOwner: String!, $sourceRepo: String!, $targetOwner: String!, $targetRepo: String!) { + source: repository(owner: $sourceOwner, name: $sourceRepo) { + issue(number: $issue) { + id + } + } + target: repository(owner: $targetOwner, name: $targetRepo) { + id + } + }`, map[string]interface{}{ + "issue": issueNumber, + "sourceOwner": project.Owner, + "sourceRepo": project.Name, + "targetOwner": targetOwner, + "targetRepo": targetRepo, + }, &nodeIDsResponse) utils.Check(err) - err = response.Unmarshal(&responseData) + issueResponse := struct { + TransferIssue struct { + Issue struct { + URL string + } + } + }{} + err = gh.GraphQL(` + mutation($issue: ID!, $repo: ID!) { + transferIssue(input: {issueId: $issue, repositoryId: $repo}) { + issue { + url + } + } + }`, map[string]interface{}{ + "issue": nodeIDsResponse.Source.Issue.ID, + "repo": nodeIDsResponse.Target.ID, + }, &issueResponse) utils.Check(err) - if len(responseData.Errors) > 0 { - utils.Check(fmt.Errorf("Error transferring the issue\n")) - } else { - ui.Printf("Transferred issue #%s to %s/%s\n", issueNumber, owner, targetRepo) - } - + ui.Println(issueResponse.TransferIssue.Issue.URL) args.NoForward() } diff --git a/github/client.go b/github/client.go index 45394435b..1a58319bd 100644 --- a/github/client.go +++ b/github/client.go @@ -887,6 +887,45 @@ func (client *Client) GenericAPIRequest(method, path string, data interface{}, h }) } +// GraphQL facilitates performing a GraphQL request and parsing the response +func (client *Client) GraphQL(query string, variables interface{}, data interface{}) error { + api, err := client.simpleApi() + if err != nil { + return err + } + + payload := map[string]interface{}{ + "query": query, + "variables": variables, + } + resp, err := api.PostJSON("graphql", payload) + if err = checkStatus(200, "performing GraphQL", resp, err); err != nil { + return err + } + + responseData := struct { + Data interface{} + Errors []struct { + Message string + } + }{ + Data: data, + } + err = resp.Unmarshal(&responseData) + if err != nil { + return err + } + + if len(responseData.Errors) > 0 { + messages := []string{} + for _, e := range responseData.Errors { + messages = append(messages, e.Message) + } + return fmt.Errorf("API error: %s", strings.Join(messages, "; ")) + } + return nil +} + func (client *Client) CurrentUser() (user *User, err error) { api, err := client.simpleApi() if err != nil { From d147a422d493f6fc49ae38e3b4d3cb45173a062d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Sun, 15 Dec 2019 20:48:45 +0100 Subject: [PATCH 18/19] [issue] Add `transfer` tests --- features/issue-transfer.feature | 73 ++++++++++++++++++++++++++++++++ features/support/local_server.rb | 23 +++++----- 2 files changed, 84 insertions(+), 12 deletions(-) create mode 100644 features/issue-transfer.feature diff --git a/features/issue-transfer.feature b/features/issue-transfer.feature new file mode 100644 index 000000000..37ed6d3f5 --- /dev/null +++ b/features/issue-transfer.feature @@ -0,0 +1,73 @@ +Feature: hub issue transfer + Background: + Given I am in "git://github.com/octocat/hello-world.git" git repo + And I am "srafi1" on github.com with OAuth token "OTOKEN" + + Scenario: Transfer issue + Given the GitHub API server: + """ + count = 0 + post('/graphql') { + halt 401 unless request.env['HTTP_AUTHORIZATION'] == 'token OTOKEN' + count += 1 + case count + when 1 + assert :query => /\A\s*query\(/, + :variables => { + :issue => 123, + :sourceOwner => "octocat", + :sourceRepo => "hello-world", + :targetOwner => "octocat", + :targetRepo => "spoon-knife", + } + json :data => { + :source => { :issue => { :id => "ISSUE-ID" } }, + :target => { :id => "REPO-ID" }, + } + when 2 + assert :query => /\A\s*mutation\(/, + :variables => { + :issue => "ISSUE-ID", + :repo => "REPO-ID", + } + json :data => { + :transferIssue => { :issue => { :url => "the://url" } } + } + else + status 400 + json :message => "request not stubbed" + end + } + """ + When I successfully run `hub issue transfer 123 spoon-knife` + Then the output should contain exactly "the://url\n" + + Scenario: Transfer to another owner + Given the GitHub API server: + """ + count = 0 + post('/graphql') { + count += 1 + case count + when 1 + assert :variables => { + :targetOwner => "monalisa", + :targetRepo => "playground", + } + json :data => {} + when 2 + json :errors => [ + { :message => "New repository must have the same owner as the current repository" }, + ] + else + status 400 + json :message => "request not stubbed" + end + } + """ + When I run `hub issue transfer 123 monalisa/playground` + Then the exit status should be 1 + Then the stderr should contain exactly: + """ + API error: New repository must have the same owner as the current repository\n + """ diff --git a/features/support/local_server.rb b/features/support/local_server.rb index af761470f..5c3921465 100644 --- a/features/support/local_server.rb +++ b/features/support/local_server.rb @@ -67,22 +67,21 @@ def json(value) JSON.generate value end - def assert(expected) + def assert(expected, data = params) expected.each do |key, value| if :no == value halt 422, json( - :message => "expected %s not to be passed; got %s" % [ - key.inspect, - params[key].inspect - ] - ) if params.key?(key.to_s) - elsif params[key] != value + :message => "did not expect any value for %p; got %p" % [key, data[key]] + ) if data.key?(key.to_s) + elsif Regexp === value halt 422, json( - :message => "expected %s to be %s; got %s" % [ - key.inspect, - value.inspect, - params[key].inspect - ] + :message => "expected %p to match %p; got %p" % [key, value, data[key] ] + ) unless value =~ data[key] + elsif Hash === value + assert(value, data[key]) + elsif data[key] != value + halt 422, json( + :message => "expected %p to be %p; got %p" % [key, value, data[key]] ) end end From 8efca94d7ac2a039f4f5a6e5c6a4bd00052ba773 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Sun, 15 Dec 2019 20:56:14 +0100 Subject: [PATCH 19/19] [ci] Increase minimum test coverage treshold --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 23b6368c1..5f6d75743 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ ifneq ($(GOFLAGS),) unexport GOPATH endif -MIN_COVERAGE = 89.4 +MIN_COVERAGE = 90.2 HELP_CMD = \ share/man/man1/hub-alias.1 \