List linked branches works

This commit is contained in:
Chris Westra 2022-09-13 07:28:33 -04:00
parent 8cf8a16e6a
commit ac4fc388bf
4 changed files with 144 additions and 8 deletions

View file

@ -1,5 +1,7 @@
package api
import "github.com/cli/cli/v2/internal/ghrepo"
type BranchIssueReference struct {
ID string
BranchName string
@ -58,6 +60,61 @@ func CreateBranchIssueReference(client *Client, repo *Repository, params map[str
}
func ListLinkedBranches(client *Client, repo ghrepo.Interface, issueNumber int) ([]string, error) {
// query uses name and owner
query := `
query BranchIssueReferenceListLinkedBranches($repositoryName: String!, $repositoryOwner: String!, $issueNumber: Int!) {
repository(name: $repositoryName, owner: $repositoryOwner) {
issue(number: $issueNumber) {
linkedBranches(first: 30) {
edges {
node {
ref {
name
}
}
}
}
}
}
}
`
variables := map[string]interface{}{
"repositoryName": repo.RepoName(),
"repositoryOwner": repo.RepoOwner(),
"issueNumber": issueNumber,
}
result := struct {
Repository struct {
Issue struct {
LinkedBranches struct {
Edges []struct {
Node struct {
Ref struct {
Name string
}
}
}
}
}
}
}{}
err := client.GraphQL(repo.RepoHost(), query, variables, &result)
var branchNames []string
if err != nil {
return branchNames, err
}
for _, edge := range result.Repository.Issue.LinkedBranches.Edges {
branchNames = append(branchNames, edge.Node.Ref.Name)
}
return branchNames, nil
}
func FindBaseOid(client *Client, repo *Repository, ref string) (string, string, error) {
query := `
query BranchIssueReferenceFindBaseOid($repositoryName: String!, $repositoryOwner: String!, $ref: String!) {

View file

@ -24,11 +24,12 @@ type DevelopOptions struct {
BaseRepo func() (ghrepo.Interface, error)
Remotes func() (context.Remotes, error)
IssueRepo string
IssueSelector string
Name string
BaseBranch string
Checkout bool
IssueRepoSelector string
IssueSelector string
Name string
BaseBranch string
Checkout bool
List bool
}
func NewCmdDevelop(f *cmdutil.Factory, runF func(*DevelopOptions) error) *cobra.Command {
@ -45,23 +46,28 @@ func NewCmdDevelop(f *cmdutil.Factory, runF func(*DevelopOptions) error) *cobra.
Short: "Manage linked branches for an issue",
Example: heredoc.Doc(`
$ gh issue develop --list 123 # list branches for issue 123
$ gh issue develop --issue-repo "github/cli" 123 list branches for issue 123 in repo "github/cli"
$ gh issue develop --list --issue-repo "github/cli" 123 list branches for issue 123 in repo "github/cli"
$ gh issue develop --list https://github.com/github/cli/issues/123 # list branches for issue 123 in repo "github/cli"
$ gh issue develop 123 --name "my-branch" --head main
$ gh issue develop 123 --checkout # checkout the branch for issue 123 after creating it
`),
Args: cmdutil.ExactArgs(1, "issue number is required"),
Args: cmdutil.ExactArgs(1, "issue number or url is required"),
RunE: func(cmd *cobra.Command, args []string) error {
if runF != nil {
return runF(opts)
}
opts.IssueSelector = args[0]
if opts.List {
return developRunList(opts)
}
return developRun(opts)
},
}
fl := cmd.Flags()
fl.StringVarP(&opts.BaseBranch, "base-branch", "b", "", "Name of the base branch")
fl.BoolVarP(&opts.Checkout, "checkout", "c", false, "Checkout the branch after creating it")
fl.StringVarP(&opts.IssueRepo, "issue-repo", "i", "", "Name or URL of the issue's repository")
fl.StringVarP(&opts.IssueRepoSelector, "issue-repo", "i", "", "Name or URL of the issue's repository")
fl.BoolVarP(&opts.List, "list", "l", false, "List branches for the issue")
fl.StringVarP(&opts.Name, "name", "n", "", "Name of the branch to create")
return cmd
}
@ -120,6 +126,58 @@ func developRun(opts *DevelopOptions) (err error) {
return
}
func developRunList(opts *DevelopOptions) (err error) {
httpClient, err := opts.HttpClient()
if err != nil {
return err
}
apiClient := api.NewClientFromHTTP(httpClient)
baseRepo, err := opts.BaseRepo()
if err != nil {
return err
}
opts.IO.StartProgressIndicator()
var issueRepo ghrepo.Interface
if opts.IssueRepoSelector != "" {
issueRepo, err = ghrepo.FromFullNameWithHost(opts.IssueRepoSelector, baseRepo.RepoHost())
if err != nil {
return err
}
}
targetRepo := baseRepo
if issueRepo != nil {
targetRepo = issueRepo
}
issueNumber, issueRepo, err := shared.IssueNumberAndRepoFromArg(opts.IssueSelector, targetRepo)
if err != nil {
return err
}
branches, err := api.ListLinkedBranches(apiClient, issueRepo, issueNumber)
if err != nil {
return err
}
opts.IO.StopProgressIndicator()
if len(branches) == 0 {
return cmdutil.NewNoResultsError(fmt.Sprintf("no linked branches found for %s/%s#%d", issueRepo.RepoOwner(), issueRepo.RepoName(), issueNumber))
}
if opts.IO.IsStdoutTTY() {
fmt.Fprintf(opts.IO.Out, "\nShowing linked branches for %s/%s#%d\n\n", issueRepo.RepoOwner(), issueRepo.RepoName(), issueNumber)
}
for _, branch := range branches {
fmt.Fprintf(opts.IO.Out, "%s\n", branch)
}
return nil
}
func checkoutBranch(opts *DevelopOptions, baseRepo ghrepo.Interface, checkoutBranch string) (err error) {
remotes, err := opts.Remotes()

View file

@ -22,6 +22,7 @@ func listIssues(client *api.Client, repo ghrepo.Interface, filters prShared.Filt
}
fragments := fmt.Sprintf("fragment issue on Issue {%s}", api.PullRequestGraphQL(filters.Fields))
// TODO try to paginate like this
query := fragments + `
query IssueList($owner: String!, $repo: String!, $limit: Int, $endCursor: String, $states: [IssueState!] = OPEN, $assignee: String, $author: String, $mention: String) {
repository(owner: $owner, name: $repo) {

View file

@ -60,6 +60,26 @@ func issueMetadataFromURL(s string) (int, ghrepo.Interface) {
return issueNumber, repo
}
//TODO: Returns the issue number and base repo if the issue URL is provided, falling back to the
// supplied repo if the base repo is not specified in the URL.
func IssueNumberAndRepoFromArg(arg string, fallbackRepo ghrepo.Interface) (int, ghrepo.Interface, error) {
issueNumber, baseRepo := issueMetadataFromURL(arg)
if issueNumber == 0 {
var err error
issueNumber, err = strconv.Atoi(strings.TrimPrefix(arg, "#"))
if err != nil {
return 0, nil, fmt.Errorf("invalid issue format: %q", arg)
}
}
if baseRepo == nil {
baseRepo = fallbackRepo
}
return issueNumber, baseRepo, nil
}
type PartialLoadError struct {
error
}