summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/google/go-github/v39/github/projects.go
blob: 12c00bc3b703e27085b88d23f802ebc10aca3e00 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
// Copyright 2016 The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package github

import (
	"context"
	"fmt"
)

// ProjectsService provides access to the projects functions in the
// GitHub API.
//
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/projects/
type ProjectsService service

// Project represents a GitHub Project.
type Project struct {
	ID         *int64     `json:"id,omitempty"`
	URL        *string    `json:"url,omitempty"`
	HTMLURL    *string    `json:"html_url,omitempty"`
	ColumnsURL *string    `json:"columns_url,omitempty"`
	OwnerURL   *string    `json:"owner_url,omitempty"`
	Name       *string    `json:"name,omitempty"`
	Body       *string    `json:"body,omitempty"`
	Number     *int       `json:"number,omitempty"`
	State      *string    `json:"state,omitempty"`
	CreatedAt  *Timestamp `json:"created_at,omitempty"`
	UpdatedAt  *Timestamp `json:"updated_at,omitempty"`
	NodeID     *string    `json:"node_id,omitempty"`

	// The User object that generated the project.
	Creator *User `json:"creator,omitempty"`
}

func (p Project) String() string {
	return Stringify(p)
}

// GetProject gets a GitHub Project for a repo.
//
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/projects/#get-a-project
func (s *ProjectsService) GetProject(ctx context.Context, id int64) (*Project, *Response, error) {
	u := fmt.Sprintf("projects/%v", id)
	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept headers when APIs fully launch.
	req.Header.Set("Accept", mediaTypeProjectsPreview)

	project := &Project{}
	resp, err := s.client.Do(ctx, req, project)
	if err != nil {
		return nil, resp, err
	}

	return project, resp, nil
}

// ProjectOptions specifies the parameters to the
// RepositoriesService.CreateProject and
// ProjectsService.UpdateProject methods.
type ProjectOptions struct {
	// The name of the project. (Required for creation; optional for update.)
	Name *string `json:"name,omitempty"`
	// The body of the project. (Optional.)
	Body *string `json:"body,omitempty"`

	// The following field(s) are only applicable for update.
	// They should be left with zero values for creation.

	// State of the project. Either "open" or "closed". (Optional.)
	State *string `json:"state,omitempty"`
	// The permission level that all members of the project's organization
	// will have on this project.
	// Setting the organization permission is only available
	// for organization projects. (Optional.)
	OrganizationPermission *string `json:"organization_permission,omitempty"`
	// Sets visibility of the project within the organization.
	// Setting visibility is only available
	// for organization projects.(Optional.)
	Public *bool `json:"public,omitempty"`
}

// UpdateProject updates a repository project.
//
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/projects/#update-a-project
func (s *ProjectsService) UpdateProject(ctx context.Context, id int64, opts *ProjectOptions) (*Project, *Response, error) {
	u := fmt.Sprintf("projects/%v", id)
	req, err := s.client.NewRequest("PATCH", u, opts)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept headers when APIs fully launch.
	req.Header.Set("Accept", mediaTypeProjectsPreview)

	project := &Project{}
	resp, err := s.client.Do(ctx, req, project)
	if err != nil {
		return nil, resp, err
	}

	return project, resp, nil
}

// DeleteProject deletes a GitHub Project from a repository.
//
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/projects/#delete-a-project
func (s *ProjectsService) DeleteProject(ctx context.Context, id int64) (*Response, error) {
	u := fmt.Sprintf("projects/%v", id)
	req, err := s.client.NewRequest("DELETE", u, nil)
	if err != nil {
		return nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeProjectsPreview)

	return s.client.Do(ctx, req, nil)
}

// ProjectColumn represents a column of a GitHub Project.
//
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/projects/
type ProjectColumn struct {
	ID         *int64     `json:"id,omitempty"`
	Name       *string    `json:"name,omitempty"`
	URL        *string    `json:"url,omitempty"`
	ProjectURL *string    `json:"project_url,omitempty"`
	CardsURL   *string    `json:"cards_url,omitempty"`
	CreatedAt  *Timestamp `json:"created_at,omitempty"`
	UpdatedAt  *Timestamp `json:"updated_at,omitempty"`
	NodeID     *string    `json:"node_id,omitempty"`
}

// ListProjectColumns lists the columns of a GitHub Project for a repo.
//
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/projects/#list-project-columns
func (s *ProjectsService) ListProjectColumns(ctx context.Context, projectID int64, opts *ListOptions) ([]*ProjectColumn, *Response, error) {
	u := fmt.Sprintf("projects/%v/columns", projectID)
	u, err := addOptions(u, opts)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept headers when APIs fully launch.
	req.Header.Set("Accept", mediaTypeProjectsPreview)

	columns := []*ProjectColumn{}
	resp, err := s.client.Do(ctx, req, &columns)
	if err != nil {
		return nil, resp, err
	}

	return columns, resp, nil
}

// GetProjectColumn gets a column of a GitHub Project for a repo.
//
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/projects/#get-a-project-column
func (s *ProjectsService) GetProjectColumn(ctx context.Context, id int64) (*ProjectColumn, *Response, error) {
	u := fmt.Sprintf("projects/columns/%v", id)
	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept headers when APIs fully launch.
	req.Header.Set("Accept", mediaTypeProjectsPreview)

	column := &ProjectColumn{}
	resp, err := s.client.Do(ctx, req, column)
	if err != nil {
		return nil, resp, err
	}

	return column, resp, nil
}

// ProjectColumnOptions specifies the parameters to the
// ProjectsService.CreateProjectColumn and
// ProjectsService.UpdateProjectColumn methods.
type ProjectColumnOptions struct {
	// The name of the project column. (Required for creation and update.)
	Name string `json:"name"`
}

// CreateProjectColumn creates a column for the specified (by number) project.
//
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/projects/#create-a-project-column
func (s *ProjectsService) CreateProjectColumn(ctx context.Context, projectID int64, opts *ProjectColumnOptions) (*ProjectColumn, *Response, error) {
	u := fmt.Sprintf("projects/%v/columns", projectID)
	req, err := s.client.NewRequest("POST", u, opts)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept headers when APIs fully launch.
	req.Header.Set("Accept", mediaTypeProjectsPreview)

	column := &ProjectColumn{}
	resp, err := s.client.Do(ctx, req, column)
	if err != nil {
		return nil, resp, err
	}

	return column, resp, nil
}

// UpdateProjectColumn updates a column of a GitHub Project.
//
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/projects/#update-an-existing-project-column
func (s *ProjectsService) UpdateProjectColumn(ctx context.Context, columnID int64, opts *ProjectColumnOptions) (*ProjectColumn, *Response, error) {
	u := fmt.Sprintf("projects/columns/%v", columnID)
	req, err := s.client.NewRequest("PATCH", u, opts)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept headers when APIs fully launch.
	req.Header.Set("Accept", mediaTypeProjectsPreview)

	column := &ProjectColumn{}
	resp, err := s.client.Do(ctx, req, column)
	if err != nil {
		return nil, resp, err
	}

	return column, resp, nil
}

// DeleteProjectColumn deletes a column from a GitHub Project.
//
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/projects/#delete-a-project-column
func (s *ProjectsService) DeleteProjectColumn(ctx context.Context, columnID int64) (*Response, error) {
	u := fmt.Sprintf("projects/columns/%v", columnID)
	req, err := s.client.NewRequest("DELETE", u, nil)
	if err != nil {
		return nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeProjectsPreview)

	return s.client.Do(ctx, req, nil)
}

// ProjectColumnMoveOptions specifies the parameters to the
// ProjectsService.MoveProjectColumn method.
type ProjectColumnMoveOptions struct {
	// Position can be one of "first", "last", or "after:<column-id>", where
	// <column-id> is the ID of a column in the same project. (Required.)
	Position string `json:"position"`
}

// MoveProjectColumn moves a column within a GitHub Project.
//
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/projects/#move-a-project-column
func (s *ProjectsService) MoveProjectColumn(ctx context.Context, columnID int64, opts *ProjectColumnMoveOptions) (*Response, error) {
	u := fmt.Sprintf("projects/columns/%v/moves", columnID)
	req, err := s.client.NewRequest("POST", u, opts)
	if err != nil {
		return nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeProjectsPreview)

	return s.client.Do(ctx, req, nil)
}

// ProjectCard represents a card in a column of a GitHub Project.
//
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/projects/cards/#get-a-project-card
type ProjectCard struct {
	URL        *string    `json:"url,omitempty"`
	ColumnURL  *string    `json:"column_url,omitempty"`
	ContentURL *string    `json:"content_url,omitempty"`
	ID         *int64     `json:"id,omitempty"`
	Note       *string    `json:"note,omitempty"`
	Creator    *User      `json:"creator,omitempty"`
	CreatedAt  *Timestamp `json:"created_at,omitempty"`
	UpdatedAt  *Timestamp `json:"updated_at,omitempty"`
	NodeID     *string    `json:"node_id,omitempty"`
	Archived   *bool      `json:"archived,omitempty"`

	// The following fields are only populated by Webhook events.
	ColumnID *int64 `json:"column_id,omitempty"`

	// The following fields are only populated by Events API.
	ProjectID          *int64  `json:"project_id,omitempty"`
	ProjectURL         *string `json:"project_url,omitempty"`
	ColumnName         *string `json:"column_name,omitempty"`
	PreviousColumnName *string `json:"previous_column_name,omitempty"` // Populated in "moved_columns_in_project" event deliveries.
}

// ProjectCardListOptions specifies the optional parameters to the
// ProjectsService.ListProjectCards method.
type ProjectCardListOptions struct {
	// ArchivedState is used to list all, archived, or not_archived project cards.
	// Defaults to not_archived when you omit this parameter.
	ArchivedState *string `url:"archived_state,omitempty"`

	ListOptions
}

// ListProjectCards lists the cards in a column of a GitHub Project.
//
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/projects/#list-project-cards
func (s *ProjectsService) ListProjectCards(ctx context.Context, columnID int64, opts *ProjectCardListOptions) ([]*ProjectCard, *Response, error) {
	u := fmt.Sprintf("projects/columns/%v/cards", columnID)
	u, err := addOptions(u, opts)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept headers when APIs fully launch.
	req.Header.Set("Accept", mediaTypeProjectsPreview)

	cards := []*ProjectCard{}
	resp, err := s.client.Do(ctx, req, &cards)
	if err != nil {
		return nil, resp, err
	}

	return cards, resp, nil
}

// GetProjectCard gets a card in a column of a GitHub Project.
//
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/projects/#get-a-project-card
func (s *ProjectsService) GetProjectCard(ctx context.Context, cardID int64) (*ProjectCard, *Response, error) {
	u := fmt.Sprintf("projects/columns/cards/%v", cardID)
	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept headers when APIs fully launch.
	req.Header.Set("Accept", mediaTypeProjectsPreview)

	card := &ProjectCard{}
	resp, err := s.client.Do(ctx, req, card)
	if err != nil {
		return nil, resp, err
	}

	return card, resp, nil
}

// ProjectCardOptions specifies the parameters to the
// ProjectsService.CreateProjectCard and
// ProjectsService.UpdateProjectCard methods.
type ProjectCardOptions struct {
	// The note of the card. Note and ContentID are mutually exclusive.
	Note string `json:"note,omitempty"`
	// The ID (not Number) of the Issue to associate with this card.
	// Note and ContentID are mutually exclusive.
	ContentID int64 `json:"content_id,omitempty"`
	// The type of content to associate with this card. Possible values are: "Issue" and "PullRequest".
	ContentType string `json:"content_type,omitempty"`
	// Use true to archive a project card.
	// Specify false if you need to restore a previously archived project card.
	Archived *bool `json:"archived,omitempty"`
}

// CreateProjectCard creates a card in the specified column of a GitHub Project.
//
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/projects/#create-a-project-card
func (s *ProjectsService) CreateProjectCard(ctx context.Context, columnID int64, opts *ProjectCardOptions) (*ProjectCard, *Response, error) {
	u := fmt.Sprintf("projects/columns/%v/cards", columnID)
	req, err := s.client.NewRequest("POST", u, opts)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept headers when APIs fully launch.
	req.Header.Set("Accept", mediaTypeProjectsPreview)

	card := &ProjectCard{}
	resp, err := s.client.Do(ctx, req, card)
	if err != nil {
		return nil, resp, err
	}

	return card, resp, nil
}

// UpdateProjectCard updates a card of a GitHub Project.
//
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/projects/#update-an-existing-project-card
func (s *ProjectsService) UpdateProjectCard(ctx context.Context, cardID int64, opts *ProjectCardOptions) (*ProjectCard, *Response, error) {
	u := fmt.Sprintf("projects/columns/cards/%v", cardID)
	req, err := s.client.NewRequest("PATCH", u, opts)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept headers when APIs fully launch.
	req.Header.Set("Accept", mediaTypeProjectsPreview)

	card := &ProjectCard{}
	resp, err := s.client.Do(ctx, req, card)
	if err != nil {
		return nil, resp, err
	}

	return card, resp, nil
}

// DeleteProjectCard deletes a card from a GitHub Project.
//
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/projects/#delete-a-project-card
func (s *ProjectsService) DeleteProjectCard(ctx context.Context, cardID int64) (*Response, error) {
	u := fmt.Sprintf("projects/columns/cards/%v", cardID)
	req, err := s.client.NewRequest("DELETE", u, nil)
	if err != nil {
		return nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeProjectsPreview)

	return s.client.Do(ctx, req, nil)
}

// ProjectCardMoveOptions specifies the parameters to the
// ProjectsService.MoveProjectCard method.
type ProjectCardMoveOptions struct {
	// Position can be one of "top", "bottom", or "after:<card-id>", where
	// <card-id> is the ID of a card in the same project.
	Position string `json:"position"`
	// ColumnID is the ID of a column in the same project. Note that ColumnID
	// is required when using Position "after:<card-id>" when that card is in
	// another column; otherwise it is optional.
	ColumnID int64 `json:"column_id,omitempty"`
}

// MoveProjectCard moves a card within a GitHub Project.
//
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/projects/#move-a-project-card
func (s *ProjectsService) MoveProjectCard(ctx context.Context, cardID int64, opts *ProjectCardMoveOptions) (*Response, error) {
	u := fmt.Sprintf("projects/columns/cards/%v/moves", cardID)
	req, err := s.client.NewRequest("POST", u, opts)
	if err != nil {
		return nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeProjectsPreview)

	return s.client.Do(ctx, req, nil)
}

// ProjectCollaboratorOptions specifies the optional parameters to the
// ProjectsService.AddProjectCollaborator method.
type ProjectCollaboratorOptions struct {
	// Permission specifies the permission to grant to the collaborator.
	// Possible values are:
	//     "read" - can read, but not write to or administer this project.
	//     "write" - can read and write, but not administer this project.
	//     "admin" - can read, write and administer this project.
	//
	// Default value is "write"
	Permission *string `json:"permission,omitempty"`
}

// AddProjectCollaborator adds a collaborator to an organization project and sets
// their permission level. You must be an organization owner or a project admin to add a collaborator.
//
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/projects/#add-project-collaborator
func (s *ProjectsService) AddProjectCollaborator(ctx context.Context, id int64, username string, opts *ProjectCollaboratorOptions) (*Response, error) {
	u := fmt.Sprintf("projects/%v/collaborators/%v", id, username)
	req, err := s.client.NewRequest("PUT", u, opts)
	if err != nil {
		return nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeProjectsPreview)

	return s.client.Do(ctx, req, nil)
}

// RemoveProjectCollaborator removes a collaborator from an organization project.
// You must be an organization owner or a project admin to remove a collaborator.
//
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/projects/#remove-user-as-a-collaborator
func (s *ProjectsService) RemoveProjectCollaborator(ctx context.Context, id int64, username string) (*Response, error) {
	u := fmt.Sprintf("projects/%v/collaborators/%v", id, username)
	req, err := s.client.NewRequest("DELETE", u, nil)
	if err != nil {
		return nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeProjectsPreview)

	return s.client.Do(ctx, req, nil)
}

// ListCollaboratorOptions specifies the optional parameters to the
// ProjectsService.ListProjectCollaborators method.
type ListCollaboratorOptions struct {
	// Affiliation specifies how collaborators should be filtered by their affiliation.
	// Possible values are:
	//     "outside" - All outside collaborators of an organization-owned repository
	//     "direct" - All collaborators with permissions to an organization-owned repository,
	//              regardless of organization membership status
	//     "all" - All collaborators the authenticated user can see
	//
	// Default value is "all".
	Affiliation *string `url:"affiliation,omitempty"`

	ListOptions
}

// ListProjectCollaborators lists the collaborators for an organization project. For a project,
// the list of collaborators includes outside collaborators, organization members that are direct
// collaborators, organization members with access through team memberships, organization members
// with access through default organization permissions, and organization owners. You must be an
// organization owner or a project admin to list collaborators.
//
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/projects/#list-project-collaborators
func (s *ProjectsService) ListProjectCollaborators(ctx context.Context, id int64, opts *ListCollaboratorOptions) ([]*User, *Response, error) {
	u := fmt.Sprintf("projects/%v/collaborators", id)
	u, err := addOptions(u, opts)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeProjectsPreview)

	var users []*User
	resp, err := s.client.Do(ctx, req, &users)
	if err != nil {
		return nil, resp, err
	}

	return users, resp, nil
}

// ProjectPermissionLevel represents the permission level an organization
// member has for a given project.
type ProjectPermissionLevel struct {
	// Possible values: "admin", "write", "read", "none"
	Permission *string `json:"permission,omitempty"`

	User *User `json:"user,omitempty"`
}

// ReviewProjectCollaboratorPermission returns the collaborator's permission level for an organization
// project. Possible values for the permission key: "admin", "write", "read", "none".
// You must be an organization owner or a project admin to review a user's permission level.
//
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/projects/#get-project-permission-for-a-user
func (s *ProjectsService) ReviewProjectCollaboratorPermission(ctx context.Context, id int64, username string) (*ProjectPermissionLevel, *Response, error) {
	u := fmt.Sprintf("projects/%v/collaborators/%v/permission", id, username)
	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeProjectsPreview)

	ppl := new(ProjectPermissionLevel)
	resp, err := s.client.Do(ctx, req, ppl)
	if err != nil {
		return nil, resp, err
	}
	return ppl, resp, nil
}