-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Add Copilot endpoints #2973
Add Copilot endpoints #2973
Conversation
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## master #2973 +/- ##
========================================
Coverage 97.71% 97.71%
========================================
Files 151 152 +1
Lines 13072 13241 +169
========================================
+ Hits 12773 12939 +166
- Misses 211 213 +2
- Partials 88 89 +1 ☔ View full report in Codecov by Sentry. |
CodeCov hasn't updated as of last commit, but I think it should increase the coverage to close to 100% for the new file. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, @o-sama - this is looking great!
Just a few tweaks, please, before we ask for a second review.
github/copilot.go
Outdated
InactiveThisCycle int64 `json:"inactive_this_cycle"` | ||
} | ||
|
||
type CopilotSeats struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing godoc-style comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto
"github.com/google/go-cmp/cmp" | ||
) | ||
|
||
// Test invalid JSON responses, vlaid responses are covered in the other tests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Test invalid JSON responses, vlaid responses are covered in the other tests | |
// Test invalid JSON responses, valid responses are covered in the other tests |
Thanks @gmlewis, I'll add in the changes! My bad on the http method being PUT, I was doing some other work with S3 and I think I carried that context over. |
} | ||
|
||
var copilotSeats *CopilotSeats | ||
resp, err := s.client.Do(ctx, req, &copilotSeats) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How are we handling pagination here for more than 100 users?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will be adding support for this, thanks for the callout 🙏
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pagination works in current version
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good over all. I realize I left quite a few comments, but they are mostly nit-picks about naming and comments.
github/copilot.go
Outdated
return nil, nil, err | ||
} | ||
|
||
var SeatCancellations *SeatCancellations |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The var name should be downcased "seatCancellations"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do, my bad there
github/copilot.go
Outdated
return nil, nil, err | ||
} | ||
|
||
var SeatCancellations *SeatCancellations |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Downcase seatCancellations
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto
// CopilotSeatDetails represents the details of a Copilot for Business seat. | ||
// Assignee can either be a User, Team, or Organization. | ||
type CopilotSeatDetails struct { | ||
Assignee interface{} `json:"assignee"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may be ok to use *User
here. There are a few other places where we use *User
and let users distinguish using the Type
field. @gmlewis will know what the preferred method is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like this might be a better option since we're explicitly setting the correct type for the field, but both approaches leave type-checking to the end user.
There are minor differences as far as I'm aware between the types, e.g. Team
has no Login
field, but has a Name
field, which both User
and Organization
have. Login
is used for the username in the case of a user, whereas Name
is used for team name.
I'll leave you guys with these thoughts and will be happy to make changes based on what you think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good point about Team being different. I think this might be the best way to handle it after all.
github/copilot.go
Outdated
|
||
// AddCopilotTeams Adds teams to the Copilot for Business subscription for an organization | ||
// | ||
// https://docs.github.com/en/rest/copilot/copilot-for-business#add-teams-to-the-copilot-for-business-subscription-for-an-organization |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// https://docs.github.com/en/rest/copilot/copilot-for-business#add-teams-to-the-copilot-for-business-subscription-for-an-organization | |
// GitHub API docs: https://docs.github.com/en/rest/copilot/copilot-for-business#add-teams-to-the-copilot-for-business-subscription-for-an-organization |
github/copilot.go
Outdated
|
||
// RemoveCopilotUsers Removes users from the Copilot for Business subscription for an organization | ||
// | ||
// https://docs.github.com/en/rest/copilot/copilot-for-business#remove-users-from-the-copilot-for-business-subscription-for-an-organization |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// https://docs.github.com/en/rest/copilot/copilot-for-business#remove-users-from-the-copilot-for-business-subscription-for-an-organization | |
// GitHub API docs: https://docs.github.com/en/rest/copilot/copilot-for-business#remove-users-from-the-copilot-for-business-subscription-for-an-organization |
github/copilot.go
Outdated
|
||
// GetSeatDetails Gets Copilot for Business seat assignment details for a user | ||
// | ||
// https://docs.github.com/en/rest/copilot/copilot-for-business#get-copilot-for-business-seat-assignment-details-for-a-user |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// https://docs.github.com/en/rest/copilot/copilot-for-business#get-copilot-for-business-seat-assignment-details-for-a-user | |
// GitHub API docs: https://docs.github.com/en/rest/copilot/copilot-for-business#get-copilot-for-business-seat-assignment-details-for-a-user |
Thank you, @WillAbides for your review feedback and @gauraw10 for your excellent pagination question which I seem to frequently forget about until it becomes an issue later, unfortunately. It is definitely better to add pagination support up front rather than later. 😁 I've got some work to do but see that there are some questions for me, so I will try to circle back later this afternoon and address them. |
github/copilot_test.go
Outdated
tests := map[string]struct { | ||
data string | ||
want *CopilotSeatDetails | ||
wantErr bool | ||
}{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be:
tests := map[string]struct {
name string
data string
} {
{
name: "invalid JSON",
data: `{`,
},
...
}
Two things changed here:
- Make it a slice instead of a map for defined order when testing.
- Because this only tests invalid, the "want" and "wantErr" fields are always the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can make that change but want your thoughts on keeping the want
and wantErr
fields. Reason being is as of right now I'm only testing invalid cases and the unmarshaling isn't too complex, but in the future we might be adding valid cases here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll defer to your judgement on want and wantErr. We may or may not need them in the future, and it doesn't hurt anything to keep them around.
github/copilot_test.go
Outdated
seatDetails := &CopilotSeatDetails{} | ||
|
||
t.Run(name, func(t *testing.T) { | ||
err := seatDetails.UnmarshalJSON([]byte(tc.data)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's better to test with json.Unmarshal
instead of directly calling UnmarshalJSON
because that is how users will call it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call 🙂
Co-authored-by: WillAbides <233500+WillAbides@users.noreply.github.com> Co-authored-by: Glenn Lewis <6598971+gmlewis@users.noreply.github.com>
Watching the conversations go by, I'm wondering if it might be nice to have 3 helper methods on the struct like Thoughts? |
@gmlewis Would that be while keeping |
Yes, that's what I was thinking might be nice, but I'm open to ideas. |
I think that |
Good call, I wanted to expand coverage for that 🙂 What do you think about not returning errors for unmarshaling the Assignee field once we've done the type assertions? I'm not sure we would get errors there since we know the map matches the type of the struct we're unmarshaling into, and I can't think of a way to test for that. |
In general, I would much rather have untested error branches than trust our assumption that an error can't happen and end up with a panic. Even though codecov puts a big, ugly ❌ on your PR, it isn't a hard rule that test coverage can't decrease. That said, I think it will be possible to cover those cases with just the right json data. Let me have a look and see if I can come up with something. |
@o-sama I see you have already cases that should cover those lines but don't. I think the problem is the comma at the end of |
Ah good catch @WillAbides, it's always the commas 🙃 |
OK, first let me resolve the merge conflicts, @zetaab - then maybe @valbeat has time to take a look at this one. |
Fixes: google#2996.
@zetaab - you yourself could move this PR along by performing a review and giving it an LGTM+Approval. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could not find anything else than that one type change. I am currently coding against this PR and it was little bit weird that the type is not similar than other timestamps.
// Assignee can either be a User, Team, or Organization. | ||
Assignee interface{} `json:"assignee"` | ||
AssigningTeam *Team `json:"assigning_team,omitempty"` | ||
PendingCancellationDate *string `json:"pending_cancellation_date,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
type should be *Timestamp
instead that it works in similar way than other time fields.
} | ||
|
||
var copilotSeats *CopilotSeats | ||
resp, err := s.client.Do(ctx, req, &copilotSeats) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pagination works in current version
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually that PendingCancellationDate field is date
so perhaps leave it like this.
LGTM
Thank you, @zetaab ! |
Closes #2938.