@@ -151,7 +151,13 @@ tips (which are frequently ignored by AI-driven PRs):
151151* When possible, try to make smaller, focused PRs (which are easier to review
152152 and easier for others to understand).
153153
154- ## Code Comments
154+ ## Code Guidelines
155+
156+ This section documents common code patterns and conventions used throughout
157+ the go-github repository. Following these guidelines helps maintain consistency
158+ and makes the codebase easier to understand and maintain.
159+
160+ ### Code Comments
155161
156162Every exported method and type needs to have code comments that follow
157163[ Go Doc Comments] [ ] . A typical method's comments will look like this:
@@ -165,18 +171,18 @@ Every exported method and type needs to have code comments that follow
165171func (s *RepositoriesService ) Get (ctx context .Context , owner , repo string ) (*Repository , *Response , error ) {
166172 u := fmt.Sprintf (" repos/%v /%v " , owner, repo)
167173 req , err := s.client .NewRequest (ctx, " GET" , u, nil )
168- // ...
174+ ...
169175}
170176```
171177And the returned type ` Repository ` will have comments like this:
172178
173179``` go
174180// Repository represents a GitHub repository.
175181type Repository struct {
176- ID *int64 ` json:"id,omitempty"`
182+ ID *int64 ` json:"id,omitempty"`
177183 NodeID *string ` json:"node_id,omitempty"`
178- Owner *User ` json:"owner,omitempty"`
179- // ...
184+ Owner *User ` json:"owner,omitempty"`
185+ ...
180186}
181187```
182188
@@ -199,6 +205,273 @@ description.
199205
200206[ Go Doc Comments ] : https://go.dev/doc/comment
201207
208+ ### File Organization
209+
210+ Files are organized by service and API endpoint, following the pattern
211+ ` {service}_{api}.go ` . For example:
212+ - ` repos_contents.go ` - Repository contents API methods
213+ - ` users_ssh_signing_keys.go ` - User SSH signing keys API methods
214+ - ` orgs_rules.go ` - Organization rules API methods
215+
216+ Test files follow the pattern ` {service}_{api}_test.go ` .
217+
218+ These services map directly to how the [ GitHub API documentation] [ ] is
219+ organized, so use that as your guide for where to put new methods.
220+
221+ 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 ) .
222+
223+ [ GitHub API documentation ] : https://docs.github.com/en/rest
224+
225+ ### Naming Conventions
226+
227+ #### Receiver Names
228+
229+ Service method receivers consistently use the single letter ` s ` :
230+
231+ ``` go
232+ func (s *RepositoriesService ) Get (ctx context .Context , owner , repo string ) (*Repository , *Response , error ) {
233+ // ...
234+ }
235+ ```
236+
237+ #### Method Names
238+
239+ Methods use descriptive names that clearly indicate their action.
240+ The method name should not repeat the scope already defined by the service:
241+
242+ ``` go
243+ // On OrganizationsService, the scope is already "organization":
244+ func (s *OrganizationsService ) ListMembers (ctx context .Context , org string , opts *OrganizationListMembersOptions ) ([]*User , *Response , error )
245+
246+ // On EnterpriseService, the scope is already "enterprise":
247+ func (s *EnterpriseService) GetLicenseInfo(ctx context.Context) (*LicenseInfo, *Response, error)
248+ ```
249+
250+ Common method name prefixes:
251+ - `Get` - Retrieve a single resource
252+ - `List` - Retrieve multiple resources (supports pagination)
253+ - `Create` - Create a new resource
254+ - `Update` - Update an existing resource
255+ - `Delete` - Delete a resource
256+
257+ #### Common Variable Names
258+
259+ - `ctx` - Context
260+ - `u` - URL string
261+ - `req` - HTTP request
262+ - `resp` - HTTP response
263+ - `result` - Result from API call
264+ - `err` - Error
265+ - `opts` - Options parameter
266+ - `owner` - Repository owner (username or organization)
267+ - `repo` - Repository name
268+ - `org` - Organization name
269+ - `user` - Username
270+ - `team` - Team name or slug
271+ - `project` - Project name or number
272+
273+ ### Type Conventions
274+
275+ #### Value vs Pointer Parameters
276+
277+ Prefer value types over pointer types for parameters where the distinction
278+ between "zero" and "unset" is not needed, or where the type is small and
279+ cheap to copy (e.g., `string`, `int`, `int64`, `bool`). Use pointer types
280+ when you need to distinguish between an unset value and a zero value.
281+ See [#3644][] and [#3887][] for background discussion.
282+
283+ [#3644]: https:// github.com/google/go-github/pull/3644
284+ [#3887]: https:// github.com/google/go-github/pull/3887
285+
286+ #### Request Option Types
287+
288+ Request option types (for query parameters) are named after the method they
289+ modify, with the suffix `Options`:
290+
291+ ```go
292+ type RepositoryListOptions struct {
293+ Type string ` url:"type,omitempty"`
294+ Sort string ` url:"sort,omitempty"`
295+ Direction string ` url:"direction,omitempty"`
296+ ListOptions
297+ }
298+ ```
299+
300+ #### Request Body Types
301+
302+ Request body types (for POST/PUT/PATCH requests) should use the ` Request `
303+ suffix for create and update operations:
304+
305+ ``` go
306+ type CreateHostedRunnerRequest struct {
307+ Name string ` json:"name"`
308+ RunnerGroupId int64 ` json:"runner_group_id"` // Required, non-pointer
309+ EnableStaticIP *bool ` json:"enable_static_ip,omitempty"`
310+ Image string ` json:"image"`
311+ VMSize string ` json:"vm_size"`
312+ }
313+ ```
314+
315+ #### Response Types
316+
317+ Response types are named after the resource they represent, typically without
318+ any suffix:
319+
320+ ``` go
321+ type Repository struct {
322+ ID *int64 ` json:"id,omitempty"`
323+ Name *string ` json:"name,omitempty"`
324+ FullName *string ` json:"full_name,omitempty"`
325+ Description *string ` json:"description,omitempty"`
326+ // ...
327+ }
328+ ```
329+
330+ #### Common Structs
331+
332+ - ` ListOptions ` - For offset-based pagination (page/per_page)
333+ - ` ListCursorOptions ` - For cursor-based pagination
334+ - ` UploadOptions ` - For file uploads
335+ - ` Response ` - Wraps the HTTP response
336+
337+ ### JSON Tags
338+
339+ #### Request Bodies
340+
341+ Required fields should be non-pointer types without ` omitempty ` :
342+
343+ ``` go
344+ type SecretScanningAlertUpdateOptions struct {
345+ State string ` json:"state"`
346+ // ...
347+ }
348+ ```
349+
350+ Optional fields should be pointer types with ` omitempty ` :
351+
352+ ``` go
353+ type SecretScanningAlertUpdateOptions struct {
354+ State string ` json:"state"`
355+ Resolution *string ` json:"resolution,omitempty"`
356+ ResolutionComment *string ` json:"resolution_comment,omitempty"`
357+ }
358+ ```
359+
360+ Use ` omitzero ` for structs and ` time.Time ` where you want to omit
361+ empty values (not just nil). For slices and maps, ` omitzero ` has the
362+ opposite behavior: it keeps empty (non-nil) values and only omits nil
363+ values. See ` RepositoryRuleset ` for examples of ` omitzero ` usage with
364+ both slices and structs.
365+
366+ For optional boolean fields where you need to distinguish between ` false `
367+ and "not set", use ` *bool ` with ` omitzero ` .
368+
369+ #### Response Bodies
370+
371+ Follow the same conventions as request bodies for ` omitempty ` and
372+ ` omitzero ` usage. Optional fields should use pointer types with
373+ ` omitempty ` , and required fields should prefer non-pointer types.
374+ See [ Common Types] ( #common-types ) for conventions on ID, Node ID,
375+ Timestamp, and Boolean fields.
376+
377+ ### URL Tags for Query Parameters
378+
379+ All fields should use ` url ` tags with ` omitempty ` to omit zero values
380+ from the query string:
381+
382+ ``` go
383+ type RepositoryContentGetOptions struct {
384+ Ref string ` url:"ref,omitempty"`
385+ }
386+
387+ type RepositoryListOptions struct {
388+ Type string ` url:"type,omitempty"`
389+ Sort string ` url:"sort,omitempty"`
390+ Direction string ` url:"direction,omitempty"`
391+ ListOptions
392+ }
393+ ```
394+
395+ ### Pagination
396+
397+ The go-github library supports two types of pagination:
398+
399+ #### Offset-based Pagination
400+
401+ Use ` ListOptions ` for APIs that use page/per_page parameters:
402+
403+ ``` go
404+ type ListOptions struct {
405+ Page int ` url:"page,omitempty"`
406+ PerPage int ` url:"per_page,omitempty"`
407+ }
408+ ```
409+
410+ #### Cursor-based Pagination
411+
412+ Use ` ListCursorOptions ` for APIs that use cursor-based pagination:
413+
414+ ``` go
415+ type ListCursorOptions struct {
416+ Page string ` url:"page,omitempty"`
417+ PerPage int ` url:"per_page,omitempty"`
418+ First int ` url:"first,omitempty"`
419+ Last int ` url:"last,omitempty"`
420+ After string ` url:"after,omitempty"`
421+ Before string ` url:"before,omitempty"`
422+ Cursor string ` url:"cursor,omitempty"`
423+ }
424+ ```
425+
426+ Embed the appropriate pagination options in your option structs
427+ based on the API's pagination model: use ` ListOptions ` for
428+ offset-based APIs and ` ListCursorOptions ` for cursor-based APIs.
429+ The library automatically generates iterator methods (e.g., ` ListIter ` )
430+ for methods that start with ` List ` and return a slice.
431+
432+ For APIs with non-standard pagination behavior (e.g., methods that
433+ return a wrapper struct containing multiple slices), configuration maps
434+ in ` gen-iterators.go ` can be adjusted — including ` useCursorPagination ` ,
435+ ` customNames ` , ` sliceToBeUsedForIteration ` , and ` customTestJSON ` .
436+
437+ ### Common Types
438+
439+ #### ID Fields
440+
441+ GitHub API IDs are always ` int64 ` . In request bodies, use non-pointer ` int64 `
442+ for required fields and ` *int64 ` for optional fields. In response bodies, use
443+ ` *int64 ` with ` omitempty ` :
444+
445+ ``` go
446+ type CreateHostedRunnerRequest struct {
447+ RunnerGroupId int64 ` json:"runner_group_id"` // Required, non-pointer
448+ }
449+ ```
450+
451+ #### Node ID Fields
452+
453+ Node IDs are always ` string ` :
454+
455+ ``` go
456+ type Repository struct {
457+ NodeID *string ` json:"node_id,omitempty"`
458+ // ...
459+ }
460+ ```
461+
462+ #### Timestamp Fields
463+
464+ Use the ` Timestamp ` type for all date/time fields:
465+
466+ ``` go
467+ type Repository struct {
468+ CreatedAt *Timestamp ` json:"created_at,omitempty"`
469+ UpdatedAt *Timestamp ` json:"updated_at,omitempty"`
470+ PushedAt *Timestamp ` json:"pushed_at,omitempty"`
471+ // ...
472+ }
473+ ```
474+
202475## Metadata
203476
204477GitHub publishes [ OpenAPI descriptions of their API] [ ] . We use these
@@ -290,21 +563,6 @@ section for more information.
290563
291564** script/test.sh** runs tests on all modules.
292565
293- ## Other notes on code organization
294-
295- Currently, everything is defined in the main ` github ` package, with API methods
296- broken into separate service objects. These services map directly to how
297- the [ GitHub API documentation] [ ] is organized, so use that as your guide for
298- where to put new methods.
299-
300- Code is organized in files also based pretty closely on the GitHub API
301- documentation, following the format ` {service}_{api}.go ` . For example, methods
302- defined at < https://docs.github.com/en/rest/webhooks/repos > live in
303- [ repos_hooks.go] [ ] .
304-
305- [ GitHub API documentation ] : https://docs.github.com/en/rest
306- [ repos_hooks.go ] : https://github.com/google/go-github/blob/master/github/repos_hooks.go
307-
308566## Maintainer's Guide
309567
310568(These notes are mostly only for people merging in pull requests.)
0 commit comments