docs: extend CONTRIBUTING.md with code guidelines#4202
Conversation
gmlewis
left a comment
There was a problem hiding this comment.
Thank you, @jlaportebot.
LGTM.
cc: @alexandear
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #4202 +/- ##
=======================================
Coverage 97.45% 97.45%
=======================================
Files 189 189
Lines 19164 19164
=======================================
Hits 18677 18677
Misses 270 270
Partials 217 217 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
alexandear
left a comment
There was a problem hiding this comment.
@jlaportebot Thank you. I left a few comments regarding excessive formatting and redundant information. Could you also review the entire CONTRIBUTING.md document and consolidate duplicated content?
Also, I think this PR should be reviewed by everyone listed in the REVIEWERS file.
|
|
||
| [Go Doc Comments]: https://go.dev/doc/comment | ||
|
|
||
| ## Code Guidelines |
There was a problem hiding this comment.
I think the "Code Comments" section above should be under "Code Guidelines".
| #### Generated Documentation | ||
|
|
||
| Documentation links are automatically generated from `openapi_operations.yaml`. | ||
| Run `script/generate.sh` to update these links. |
There was a problem hiding this comment.
These lines are not needed.
They are already in "Submitting a patch", "Metadata", and "Scripts".
Can be removed.
| #### Linter Rules | ||
|
|
||
| The repository uses custom linter rules to enforce consistency: | ||
| - `sliceofpointers` - Ensures slice fields use pointers | ||
| - `structfield` - Ensures struct fields follow naming conventions |
There was a problem hiding this comment.
We have more linters. Let's simply remove this section.
| State string `json:"state"` // Required field | ||
| // ... |
There was a problem hiding this comment.
Please use TABs instead of spaces for all examples:
| State string `json:"state"` // Required field | |
| // ... | |
| State string `json:"state"` // Required field | |
| // ... |
|
|
||
| ### Naming Conventions | ||
|
|
||
| #### File Names |
There was a problem hiding this comment.
Should we remove the "Other notes on code organization" section?
| #### Enterprise and Organization Scoped Methods | ||
|
|
||
| Methods that operate on enterprise or organization resources include the scope | ||
| in their name: | ||
|
|
||
| ```go | ||
| // Enterprise-scoped methods | ||
| func (s *EnterpriseService) GetLicenseInfo(ctx context.Context) (*LicenseInfo, *Response, error) | ||
|
|
||
| // Organization-scoped methods | ||
| func (s *OrganizationsService) ListMembers(ctx context.Context, org string, opts *OrganizationListMembersOptions) ([]*User, *Response, error) | ||
| ``` |
There was a problem hiding this comment.
Actually, I think this subsection may be incorrect - see #3761.
|
|
||
| When defining structs that represent a request body (sent via POST/PUT/PATCH): | ||
|
|
||
| 1. **Required fields** should be non-pointer types without `omitempty`: |
There was a problem hiding this comment.
Please do not use excessive LLM-like formatting:
| 1. **Required fields** should be non-pointer types without `omitempty`: | |
| 1. Required fields should be non-pointer types without `omitempty`: |
| 2. **Handle nil options** in your methods: | ||
|
|
||
| ```go | ||
| func (s *RepositoriesService) List(ctx context.Context, user string, opts *RepositoryListOptions) ([]*Repository, *Response, error) { | ||
| if opts == nil { | ||
| opts = &RepositoryListOptions{} | ||
| } | ||
| // ... | ||
| } | ||
| ``` |
There was a problem hiding this comment.
This can be removed. We have the addOptions to handle nil options.
|
@stevehipwell @zyfy29 @Not-Dhananjay-Mishra @munlicode please review when you have time |
|
@alexandear did you not want your review comments addressing before someone else weighs in? |
|
|
||
| ### Naming Conventions | ||
|
|
||
| #### File Names |
There was a problem hiding this comment.
Maybe remove "Other notes on code organization" as @alexandear suggested, and put this:
Files are organized by service and API endpoint, following the pattern
`{service}_{api}.go`. For example:
- `repos_contents.go` - Repository contents API methods
- `users_ssh_signing_keys.go` - User SSH signing keys API methods
- `orgs_rules.go` - Organization rules API methods
Test files follow the pattern `{service}_{api}_test.go`.
These services map directly to how the [GitHub API documentation](https://docs.github.com/en/rest) is organized, so use that as your guide for where to put new methods.
For example, methods defined at <https://docs.github.com/en/rest/webhooks/repos> live in [repos_hooks.go][https://github.com/google/go-github/blob/master/github/repos_hooks.go].
@stevehipwell I prefer that all reviewers contribute to the guidelines regardless of my comments, since my feedback is ultimately opinionated as well. |
stevehipwell
left a comment
There was a problem hiding this comment.
This is looking like a really useful resource for contributions. I've added some comments/suggestions.
| Request body types (for POST/PUT/PATCH requests) are named after the method | ||
| they modify, with the suffix `Options`: |
There was a problem hiding this comment.
Should request body types not use the Request suffix? The use of Options here is overloaded and it looks to me like the current usage is split roughly even across the wtwo patterns.
| - `Create` - Create a new resource | ||
| - `Update` - Update an existing resource | ||
| - `Delete` - Delete a resource | ||
| - `Edit` - Edit an existing resource (alternative to Update) |
There was a problem hiding this comment.
I don't think we should have Edit as an "alternative", the GitHub API isn't consistent but that doesn't mean we can't make this SDK consistent (as far as is supported by the API).
| Methods that operate on enterprise or organization resources include the scope | ||
| in their name: |
There was a problem hiding this comment.
This comment doesn't line up with the example below it and also doesn't match the last agreed practice of NOT including the scope in the name where the scope is already defined by the service.
| - `ListOptions` - For offset-based pagination (page/per_page) | ||
| - `ListCursorOptions` - For cursor-based pagination |
There was a problem hiding this comment.
Do we want to move away from the use of some of the common structs that don't directly map to the API surface and instead start to add specific structs?
There was a problem hiding this comment.
This suggestion is out of scope for this PR. Let's create a separate issue.
| 3. **Use `omitzero` for structs and slices** where you want to omit empty values | ||
| (not just nil): | ||
|
|
||
| ```go | ||
| type ActivityNotificationOptions struct { | ||
| SubjectType string `json:"subject_type,omitempty"` | ||
| Subject *string `json:"subject,omitempty"` | ||
| LastReadAt Timestamp `json:"last_read_at,omitzero"` | ||
| } | ||
| ``` |
There was a problem hiding this comment.
I don't think this comment is correct, for structs and time.Time using omitzero will omit the value from the payload; but for slices and maps it does the opposite and keeps empty ones and only omits them if they're nil. See the use in RepositoryRuleset.
|
|
||
| ### Pagination | ||
|
|
||
| The go-github library supports two types of pagination: |
There was a problem hiding this comment.
Is this still correct, I thought it was fuzzier?
| } | ||
| ``` | ||
|
|
||
| 3. **Use iterators** for list methods that support pagination. The library |
There was a problem hiding this comment.
We probably out to mention the custom pagination configuration for non-standard pagination (e.g. commit files).
| type Repository struct { | ||
| ID *int64 `json:"id,omitempty"` | ||
| // ... | ||
| } | ||
|
|
||
| type User struct { | ||
| ID *int64 `json:"id,omitempty"` | ||
| // ... | ||
| } |
There was a problem hiding this comment.
It might be better to choose an example where the ID isn't a pointer.
| CreatedAt *Timestamp `json:"created_at,omitempty"` | ||
| UpdatedAt *Timestamp `json:"updated_at,omitempty"` | ||
| PushedAt *Timestamp `json:"pushed_at,omitempty"` |
There was a problem hiding this comment.
Do these still need to be pointers or can we use omitzero? If so should we?
| Boolean fields are always `*bool` (pointer to bool) to distinguish between | ||
| `false` and `not set`: |
There was a problem hiding this comment.
If the boolean is required I'm not sure I see the value in this?
| - `Delete` - Delete a resource | ||
| - `Edit` - Edit an existing resource (alternative to Update) | ||
|
|
||
| Common local variable names: |
There was a problem hiding this comment.
We can add opts in this list too.
As opts is more commonly used throughout the repository #3887
| Committer *CommitAuthor `json:"committer,omitempty"` | ||
| } | ||
| ``` | ||
|
|
There was a problem hiding this comment.
In my opinion it is worth mentioning about the use of value parameters instead of pointers where appropriate #3644
| ### JSON Tags for Request Bodies | ||
|
|
||
| When defining structs that represent a request body (sent via POST/PUT/PATCH): |
There was a problem hiding this comment.
We have similar kind of rules around pointer usage and omitempty/omitzero for response bodies as well, so I think it would be worth mentioning them too.
Maybe we can combine the request and response body sections into a single section or should we make separate section?
|
@jlaportebot, are you planning to continue working on this? |
|
@alexandear Yes, I'm planning to continue working on this. I'll address the requested changes around excessive formatting, redundant information, and duplicated content shortly. Thanks for the patience. |
|
Addressed all review feedback in a new commit (6dc10b8):
Please take another look — happy to make further adjustments. |
|
Thanks for the detailed reviews! I've pushed a comprehensive update addressing the feedback:
Other improvements:
I'd appreciate another round of review. Happy to make further adjustments. |
|
Awaiting approval from all the reviewers who commented: |
|
Thank you all for the thorough review feedback. I've addressed the following in the latest push:
I'll continue working through the remaining comments and will address them in follow-up commits. There are several design discussion points (e.g., request/response body section consolidation, pointer usage in response types) that may benefit from broader input from the REVIEWERS list. |
| this][modified-comment]. | ||
|
|
||
| [git-aliases]: https://github.com/willnorris/dotfiles/blob/d640d010c23b1116bdb3d4dc12088ed26120d87d/git/.gitconfig#L13-L15 | ||
| [git-aliases]: https://github.com/willnorris/dotfiles/blob/d640d010c23b1116bdb3d4dc12088ed26120d87b/git/.gitconfig#L13-L15 |
There was a problem hiding this comment.
Please revert this change because the link became broken after the update.
| For APIs with non-standard pagination (e.g., commit files), you may need | ||
| to implement custom pagination configuration instead of using the | ||
| standard `ListOptions` or `ListCursorOptions`. |
There was a problem hiding this comment.
This feel incorrect.
For APIs with non-standard pagination we have configuration settings in gen-iterators.go L157-185 that can be adjusted as needed.
There was a problem hiding this comment.
I agree with this. My original comment was a question about the actual options object to be used in the List methods, not about the iterator pattern.
| Most fields in response types are pointers with `omitempty`, since the | ||
| GitHub API may omit fields from responses. For required fields with |
There was a problem hiding this comment.
Most fields in response types are pointers with
omitempty, since the
GitHub API may omit fields from responses.
I'm not sure this is actually correct, and I don't think it's helpful as it undoes some of the framing in previous sections. Also for that reason I'm not 100% convinced we should be using Repository in the examples as the current struct doesn't match the API, where ID & Name are required.
| For APIs with non-standard pagination (e.g., commit files), you may need | ||
| to implement custom pagination configuration instead of using the | ||
| standard `ListOptions` or `ListCursorOptions`. |
There was a problem hiding this comment.
I agree with this. My original comment was a question about the actual options object to be used in the List methods, not about the iterator pattern.
|
Pushed an update addressing the latest review feedback:
I believe all outstanding feedback has now been addressed. Happy to make further adjustments as needed. |
|
Addressed the latest review feedback:
Please take another look when you have a chance. |
| GitHub API IDs are always `int64`. In request bodies, use non-pointer `int64` | ||
| for required fields and `*int64` for optional fields. In response bodies, use | ||
| `*int64` with `omitempty`: |
There was a problem hiding this comment.
| GitHub API IDs are always `int64`. In request bodies, use non-pointer `int64` | |
| for required fields and `*int64` for optional fields. In response bodies, use | |
| `*int64` with `omitempty`: | |
| GitHub API IDs are always `int64`. In request bodies, use non-pointer `int64` | |
| if the ID is required and `*int64` if the ID is optional. In response bodies, | |
| use non-pointer `int64` if the ID is required and `*int64` with `omitempty` | |
| if the ID is optional: |
This needs changing.
|
|
||
| ```go | ||
| type Repository struct { | ||
| NodeID *string `json:"node_id,omitempty"` |
There was a problem hiding this comment.
This is probably not a good example as the struct has NodeID as optional but in the schema it's required for the response bodies.
| type Repository struct { | ||
| ID *int64 `json:"id,omitempty"` | ||
| Name *string `json:"name,omitempty"` | ||
| FullName *string `json:"full_name,omitempty"` | ||
| Description *string `json:"description,omitempty"` | ||
| // ... | ||
| } |
There was a problem hiding this comment.
This isn't a good example as the struct doesn't match the response schema, where all of the above fields are required.
|
Thanks for the thorough review, @stevehipwell. I'll work through all your feedback — particularly the points about: omitzero behavior for slices/maps, the Edit vs Update naming, request body type naming conventions, and the incorrect examples. Will push updates shortly. |
|
Thanks for the review, @alexandear. I'll address all your feedback:
I'll also check if REVIEWERS-listed folks have had a chance to look. Will push updates shortly. |
@jlaportebot you've already covered some of that, the comments belong against specific commits and you need to reconcile that. @gmlewis this PR looks useful, but I'm not sure it's worth this level of slop!? |
Add detailed code style and documentation guidelines including: - Method documentation conventions with godoc examples - API endpoint documentation patterns - Error handling guidelines - Type naming and struct conventions - Testing requirements and patterns Co-authored-by: review feedback from google/go-github maintainers
9e20dc8 to
4b63726
Compare
stevehipwell
left a comment
There was a problem hiding this comment.
The code formatting is also off, specifically for the structs.
Summary
This PR extends CONTRIBUTING.md with a comprehensive section on code guidelines and conventions, addressing issue #4023.
Changes
Added a new "Code Guidelines" section that documents:
Naming Conventions
JSON Tags for Request Bodies
URL Tags for Query Parameters
Pagination
Common Types
Generation Patterns
Benefits
Testing
This is a documentation-only change. No code changes or tests needed.
Closes #4023