google / go-github

Go library for accessing the GitHub v3 API

Home Page:https://pkg.go.dev/github.com/google/go-github/v62/github

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add support for Label exclusion in IssuesListOptions

chesmat opened this issue · comments

Currently, the go-github library supports GitHub Issue labels filtering as an "inclusion" filter, meaning it matches issues containing the provided labels. However, it's important to note that the GitHub API (as well as the user interface) offers support for both positive (inclusion) and negative (exclusion) label matches.

image

image

https://github.com/google/go-github/issues?q=is%3Aopen+is%3Aissue+-label%3Abug

Indeed, label exclusion functionality can be crucial for various use cases when listing issues. It allows users to filter out issues that have specific labels, which can be valuable for focusing on particular subsets of issues or excluding those that are irrelevant to a specific task or context. Integrating label exclusion support into the go-github library would enhance its flexibility and usefulness for managing GitHub issues programmatically.

This worked fine for me:

package main

import (
	"context"
	"log"

	dbg "github.com/gmlewis/go-httpdebug/httpdebug"
	"github.com/google/go-github/v59/github"
	"golang.org/x/oauth2"
)

func main() {
	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: SECRET},
	)
	tc := oauth2.NewClient(oauth2.NoContext, ts)
	tp := dbg.New(dbg.WithTransport(tc.Transport))
	client := github.NewClient(tp.Client())
	ctx := context.Background()

	q := "is:open is:issue -label:bug repo:google/go-github"
	log.Printf("q=%v", q)
	opts := &github.SearchOptions{TextMatch: true}
	pulls, _, err := client.Search.Issues(ctx, q, opts)
	if err != nil {
		log.Fatal(err)
	}

	log.Printf("Total: %v", pulls.GetTotal())
	log.Printf("Incomplete Results: %v", pulls.GetIncompleteResults())

	for i, pr := range pulls.Issues {
		log.Printf("\n\nPullRequest #%v:", i+1)
		log.Printf("  URL: %v", pr.GetHTMLURL())
	}
}

results in:

go run main.go
2024/02/20 08:54:16 q=is:open is:issue -label:bug repo:google/go-github
2024/02/20 08:54:16 curl -X GET \
  https://api.github.com/search/issues?q=is%3Aopen+is%3Aissue+-label%3Abug+repo%3Agoogle%2Fgo-github \
  -H 'Accept: application/vnd.github.squirrel-girl-preview, application/vnd.github.v3.text-match+json' \
  -H 'User-Agent: go-github/v59.0.0' \
  -H 'X-Github-Api-Version: 2022-11-28'
2024/02/20 08:54:16 Total: 63
2024/02/20 08:54:16 Incomplete Results: false
2024/02/20 08:54:16 

PullRequest #1:
2024/02/20 08:54:16   URL: https://github.com/google/go-github/issues/3083
2024/02/20 08:54:16 

...

which matches your example query as of this moment in time:

works-fine-2024-02-20_08-57-18

This worked fine for me:

@gmlewis , thank you for taking the look and for the reply.

While I agree, there are various ways to accomplish the desired outcome, this specific request deals with "IssueListOptions" https://github.com/google/go-github/blob/master/github/issues.go#L96

As a go-github library caller, I think it would be helpful to enhance the existing IssueListOptions to allow the following (mock-up) functionality:

        listOptions := &github.IssueListByRepoOptions{
		State:    "all",
		Assignee: "user",
		Labels:   []{"foo"},
		ExcludeLabels: []{"bar"},
	}
	issues, res, err := c.client.ListIssuesByRepo(ctx, "owner", "reop", listOptions)

In other words, the caller can leverage existing "List" operations and primitives instead of using "query" semantics.

What do you think?

Naively thinking, something like this could do the trick. I tested this, and it seems to work. However, I would defer to go-github maintainers.

--- a/github/issues.go
+++ b/github/issues.go
@@ -105,6 +105,9 @@ type IssueListOptions struct {
        // Labels filters issues based on their label.
        Labels []string `url:"labels,comma,omitempty"`
 
+       // ExcludeLabels filters issues based on their label.
+       ExcludeLabels []string `url:"-labels,comma,omitempty"`
+
        // Sort specifies how to sort issues. Possible values are: created, updated,
        // and comments. Default value is "created".
        Sort string `url:"sort,omitempty"`

If needed, I don't mind creating a PR. However, I would like to run it by the maintainers first to get a 👍 .

Looking at https://docs.github.com/en/rest/issues/issues?apiVersion=2022-11-28#list-repository-issues
I'm wondering how you are going to pull this off?

If the GitHub v3 API doesn't support what you are trying to do, then it will be nearly impossible for you to implement it in this repo, since this is a Go client library for the GitHub v3 API.

If I'm reading the official documentation properly, they have not provided a way for you to exclude labels through that endpoint.

Therefore, if you wish to exclude labels, you are forced to use query semantics.

Or maybe I'm missing something?

Hi @gmlewis,

Thank you for taking a look and for replying. I apologize for the delayed response.

If the GitHub v3 API doesn't support what you are trying to do, then it will be nearly impossible for you to implement it in this repo, since this is a Go client library for the GitHub v3 API.

To clarify what you meant by "doesn't support", did you mean that it is not documented, or that it won't work?

The "list-repository-issues" API supports the "labels" path parameter. Although it does not explicitly state the support or lack thereof for the "-labels" path parameter, if this was your point, I agree. The "-labels" path parameter is precisely what GitHub UI uses when listing issues with labels "exclusion" (as captured in the screenshot above).

To clarify what you meant by "doesn't support", did you mean that it is not documented, or that it won't work?

By "doesn't support" I mean that you cannot construct an equivalent curl command to do what you are trying to do (using their v3 API) because their API doesn't provide that capability.

So my point is that it doesn't really matter what their user interface is capable of doing (and therefore, a screenshot of their user interface isn't really helpful) unless they are strictly using their v3 API and you can figure out how to do the same thing (typically, by searching through their v3 API documentation). If, for example, they are using their v4 (graphql) API or some other mechanism to implement their UI, then we won't be able to duplicate this functionality unless the v3 (RESTful) API supports it.

I hope this makes sense, but please let me know if this is still unclear.

Glenn, I truly appreciate the detailed explanation you've provided. It has shed light on the importance of explicit support for the REST API query parameter, even if it's not officially documented. Your clarification makes perfect sense.

Regarding your comment about the limitations of constructing an equivalent curl command "using their v3 API," I completely understand the distinction you're making, with emphasis on v3 API list issues query parameters support (or lack thereof). Because, if the point is otherwise different, it appears, I can construct the following curl:

2024/03/11 13:40:57 curl -X GET \
  https://api.github.com/repos/google/go-github/issues?-labels=foo&state=all \
  -H 'Accept: application/vnd.github.squirrel-girl-preview' \
  -H 'User-Agent: go-github/v60.0.0' \
  -H 'X-Github-Api-Version: 2022-11-28'
2024/03/11 13:40:58 listed: 30 issues

The bottom line is that we don't want to add support for features that rely on unsupported/undocumented v3 RESTful API elements, irrespective of the actual state (working), because of taking the risk of some other mechanism not supporting said elements.

Ah! That indeed looks like a valid v3 API URL!
So I'm guessing this is not officially documented from your description.
However, I'm not unwilling to add it to the repo if you want to make a PR and note in the comments that this is an undocumented endpoint.