Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Get Groups by Custom Attribute #1617

Open
adrianliechti opened this issue Jan 3, 2023 · 5 comments · May be fixed by #1649
Open

Feature Request: Get Groups by Custom Attribute #1617

adrianliechti opened this issue Jan 3, 2023 · 5 comments · May be fixed by #1649

Comments

@adrianliechti
Copy link

According the GitLab Docs, there is a handy query to get groups by custom attributes:
You can filter by custom attributes](https://docs.gitlab.com/ee/api/custom_attributes.html with:
GET /groups?custom_attributes[key]=value&custom_attributes[other_key]=other_value

I have not found this option in the current version (of this amazing lib).
Could you consider an option to do it? Maybe using a map on the ListGroupsOptions? or by having a RequestOptionFunc WithCustomQuery(key, value)

In the meantime, I used this workaround:

func (g *GitLab) groupByAttribute(ctx context.Context, key, value string) (*gitlab.Group, error) {
	opt := &gitlab.ListGroupsOptions{
		WithCustomAttributes: gitlab.Bool(true),
	}

	withCustomAttribute := func() gitlab.RequestOptionFunc {
		return func(req *retryablehttp.Request) error {
			query := fmt.Sprintf("custom_attributes[%s]=%s", key, value)

			if req.URL.RawQuery != "" {
				query += "&" + req.URL.RawQuery
			}

			req.URL.RawQuery = query

			return nil
		}
	}

	groups, _, err := g.client.Groups.ListGroups(opt, gitlab.WithContext(ctx), withCustomAttribute())

	if err != nil {
		return nil, err
	}

	if len(groups) == 0 {
		return nil, errors.New("no group found with key: " + key)
	}

	if len(groups) > 1 {
		return nil, errors.New("multiple groups found with key: " + key)
	}

	return groups[0], nil
}
@theoriginalstove
Copy link
Contributor

Going with the RequestOptionFunc seems the most straightforward way to go about this imo.

@svanharmelen
Copy link
Member

If supported and documented it should probably become a field in the appropriate options struct.

@theoriginalstove
Copy link
Contributor

https://docs.gitlab.com/ee/api/groups.html#list-groups looks to be documented at the end of the list-groups section but only as a URL param. So then the new field could be a map on the ListGroupOptions like so?

type ListGroupsOptions struct {
	...
	CustomAttributes map[string]string `url:"custom_attributes,omitempty" json:"-"`
}

@theoriginalstove
Copy link
Contributor

theoriginalstove commented Feb 10, 2023

So this is turning out to be a little trickier to implement than I thought with adding the CustomAttributes as a field in the ListGroupsOptions struct. After trying out a few things, I think I discovered it won't work with CustomAttributes as a map[string]string lol.

I'm trying to follow the examples go-querystring has of using nested structs to encode nested values in order to get custom_attributes[key]=value but I think it could get messy for developers if they want to use this field.

Maybe my test is wrong (and I'm sure I'm making some dumb mistakes after a long day of writing code at work lol) but testing the params results in:

gitlab_test.go:89: Request query: custom_attributes=%7Bvalue%7D, want custom_attributes[key]=value

when the struct for ListGroupsOptions looks like:

type ListGroupsOptions struct {
    ...
    CustomAttributes interface{} `url:"custom_attributes,omitempty" json:"-"`
}

and in the tests ListGroupsOptions is declared as:

opts := &ListGroupsOptions{
	CustomAttributes: struct {
		Key string `url:"key"`
	}{
		Key: "value",
	},
}

the brackets [] are getting url encoded, and for some reason I can't think of at this moment. I'll have to come back to this when I find some time with fresh eyes as well.

@adrianliechti
Copy link
Author

adrianliechti commented Feb 10, 2023

not sure if this is any helpful, but i used this included helper in
the rest past

q := url.Values{}
q.Add("a", "value-a")
q.Add("b", "value-b")

encoded := q.Encode()
print(encoded)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants