github.com/google/go-github/v57@v57.0.0/github/projects.go (about) 1 // Copyright 2016 The go-github AUTHORS. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 package github 7 8 import ( 9 "context" 10 "fmt" 11 ) 12 13 // ProjectsService provides access to the projects functions in the 14 // GitHub API. 15 // 16 // GitHub API docs: https://docs.github.com/rest/projects 17 type ProjectsService service 18 19 // Project represents a GitHub Project. 20 type Project struct { 21 ID *int64 `json:"id,omitempty"` 22 URL *string `json:"url,omitempty"` 23 HTMLURL *string `json:"html_url,omitempty"` 24 ColumnsURL *string `json:"columns_url,omitempty"` 25 OwnerURL *string `json:"owner_url,omitempty"` 26 Name *string `json:"name,omitempty"` 27 Body *string `json:"body,omitempty"` 28 Number *int `json:"number,omitempty"` 29 State *string `json:"state,omitempty"` 30 CreatedAt *Timestamp `json:"created_at,omitempty"` 31 UpdatedAt *Timestamp `json:"updated_at,omitempty"` 32 NodeID *string `json:"node_id,omitempty"` 33 OrganizationPermission *string `json:"organization_permission,omitempty"` 34 Private *bool `json:"private,omitempty"` 35 36 // The User object that generated the project. 37 Creator *User `json:"creator,omitempty"` 38 } 39 40 func (p Project) String() string { 41 return Stringify(p) 42 } 43 44 // GetProject gets a GitHub Project for a repo. 45 // 46 // GitHub API docs: https://docs.github.com/rest/projects/projects#get-a-project 47 // 48 //meta:operation GET /projects/{project_id} 49 func (s *ProjectsService) GetProject(ctx context.Context, id int64) (*Project, *Response, error) { 50 u := fmt.Sprintf("projects/%v", id) 51 req, err := s.client.NewRequest("GET", u, nil) 52 if err != nil { 53 return nil, nil, err 54 } 55 56 // TODO: remove custom Accept headers when APIs fully launch. 57 req.Header.Set("Accept", mediaTypeProjectsPreview) 58 59 project := &Project{} 60 resp, err := s.client.Do(ctx, req, project) 61 if err != nil { 62 return nil, resp, err 63 } 64 65 return project, resp, nil 66 } 67 68 // ProjectOptions specifies the parameters to the 69 // RepositoriesService.CreateProject and 70 // ProjectsService.UpdateProject methods. 71 type ProjectOptions struct { 72 // The name of the project. (Required for creation; optional for update.) 73 Name *string `json:"name,omitempty"` 74 // The body of the project. (Optional.) 75 Body *string `json:"body,omitempty"` 76 77 // The following field(s) are only applicable for update. 78 // They should be left with zero values for creation. 79 80 // State of the project. Either "open" or "closed". (Optional.) 81 State *string `json:"state,omitempty"` 82 // The permission level that all members of the project's organization 83 // will have on this project. 84 // Setting the organization permission is only available 85 // for organization projects. (Optional.) 86 OrganizationPermission *string `json:"organization_permission,omitempty"` 87 // Sets visibility of the project within the organization. 88 // Setting visibility is only available 89 // for organization projects.(Optional.) 90 Private *bool `json:"private,omitempty"` 91 } 92 93 // UpdateProject updates a repository project. 94 // 95 // GitHub API docs: https://docs.github.com/rest/projects/projects#update-a-project 96 // 97 //meta:operation PATCH /projects/{project_id} 98 func (s *ProjectsService) UpdateProject(ctx context.Context, id int64, opts *ProjectOptions) (*Project, *Response, error) { 99 u := fmt.Sprintf("projects/%v", id) 100 req, err := s.client.NewRequest("PATCH", u, opts) 101 if err != nil { 102 return nil, nil, err 103 } 104 105 // TODO: remove custom Accept headers when APIs fully launch. 106 req.Header.Set("Accept", mediaTypeProjectsPreview) 107 108 project := &Project{} 109 resp, err := s.client.Do(ctx, req, project) 110 if err != nil { 111 return nil, resp, err 112 } 113 114 return project, resp, nil 115 } 116 117 // DeleteProject deletes a GitHub Project from a repository. 118 // 119 // GitHub API docs: https://docs.github.com/rest/projects/projects#delete-a-project 120 // 121 //meta:operation DELETE /projects/{project_id} 122 func (s *ProjectsService) DeleteProject(ctx context.Context, id int64) (*Response, error) { 123 u := fmt.Sprintf("projects/%v", id) 124 req, err := s.client.NewRequest("DELETE", u, nil) 125 if err != nil { 126 return nil, err 127 } 128 129 // TODO: remove custom Accept header when this API fully launches. 130 req.Header.Set("Accept", mediaTypeProjectsPreview) 131 132 return s.client.Do(ctx, req, nil) 133 } 134 135 // ProjectColumn represents a column of a GitHub Project. 136 // 137 // GitHub API docs: https://docs.github.com/rest/repos/projects/ 138 type ProjectColumn struct { 139 ID *int64 `json:"id,omitempty"` 140 Name *string `json:"name,omitempty"` 141 URL *string `json:"url,omitempty"` 142 ProjectURL *string `json:"project_url,omitempty"` 143 CardsURL *string `json:"cards_url,omitempty"` 144 CreatedAt *Timestamp `json:"created_at,omitempty"` 145 UpdatedAt *Timestamp `json:"updated_at,omitempty"` 146 NodeID *string `json:"node_id,omitempty"` 147 } 148 149 // ListProjectColumns lists the columns of a GitHub Project for a repo. 150 // 151 // GitHub API docs: https://docs.github.com/rest/projects/columns#list-project-columns 152 // 153 //meta:operation GET /projects/{project_id}/columns 154 func (s *ProjectsService) ListProjectColumns(ctx context.Context, projectID int64, opts *ListOptions) ([]*ProjectColumn, *Response, error) { 155 u := fmt.Sprintf("projects/%v/columns", projectID) 156 u, err := addOptions(u, opts) 157 if err != nil { 158 return nil, nil, err 159 } 160 161 req, err := s.client.NewRequest("GET", u, nil) 162 if err != nil { 163 return nil, nil, err 164 } 165 166 // TODO: remove custom Accept headers when APIs fully launch. 167 req.Header.Set("Accept", mediaTypeProjectsPreview) 168 169 columns := []*ProjectColumn{} 170 resp, err := s.client.Do(ctx, req, &columns) 171 if err != nil { 172 return nil, resp, err 173 } 174 175 return columns, resp, nil 176 } 177 178 // GetProjectColumn gets a column of a GitHub Project for a repo. 179 // 180 // GitHub API docs: https://docs.github.com/rest/projects/columns#get-a-project-column 181 // 182 //meta:operation GET /projects/columns/{column_id} 183 func (s *ProjectsService) GetProjectColumn(ctx context.Context, id int64) (*ProjectColumn, *Response, error) { 184 u := fmt.Sprintf("projects/columns/%v", id) 185 req, err := s.client.NewRequest("GET", u, nil) 186 if err != nil { 187 return nil, nil, err 188 } 189 190 // TODO: remove custom Accept headers when APIs fully launch. 191 req.Header.Set("Accept", mediaTypeProjectsPreview) 192 193 column := &ProjectColumn{} 194 resp, err := s.client.Do(ctx, req, column) 195 if err != nil { 196 return nil, resp, err 197 } 198 199 return column, resp, nil 200 } 201 202 // ProjectColumnOptions specifies the parameters to the 203 // ProjectsService.CreateProjectColumn and 204 // ProjectsService.UpdateProjectColumn methods. 205 type ProjectColumnOptions struct { 206 // The name of the project column. (Required for creation and update.) 207 Name string `json:"name"` 208 } 209 210 // CreateProjectColumn creates a column for the specified (by number) project. 211 // 212 // GitHub API docs: https://docs.github.com/rest/projects/columns#create-a-project-column 213 // 214 //meta:operation POST /projects/{project_id}/columns 215 func (s *ProjectsService) CreateProjectColumn(ctx context.Context, projectID int64, opts *ProjectColumnOptions) (*ProjectColumn, *Response, error) { 216 u := fmt.Sprintf("projects/%v/columns", projectID) 217 req, err := s.client.NewRequest("POST", u, opts) 218 if err != nil { 219 return nil, nil, err 220 } 221 222 // TODO: remove custom Accept headers when APIs fully launch. 223 req.Header.Set("Accept", mediaTypeProjectsPreview) 224 225 column := &ProjectColumn{} 226 resp, err := s.client.Do(ctx, req, column) 227 if err != nil { 228 return nil, resp, err 229 } 230 231 return column, resp, nil 232 } 233 234 // UpdateProjectColumn updates a column of a GitHub Project. 235 // 236 // GitHub API docs: https://docs.github.com/rest/projects/columns#update-an-existing-project-column 237 // 238 //meta:operation PATCH /projects/columns/{column_id} 239 func (s *ProjectsService) UpdateProjectColumn(ctx context.Context, columnID int64, opts *ProjectColumnOptions) (*ProjectColumn, *Response, error) { 240 u := fmt.Sprintf("projects/columns/%v", columnID) 241 req, err := s.client.NewRequest("PATCH", u, opts) 242 if err != nil { 243 return nil, nil, err 244 } 245 246 // TODO: remove custom Accept headers when APIs fully launch. 247 req.Header.Set("Accept", mediaTypeProjectsPreview) 248 249 column := &ProjectColumn{} 250 resp, err := s.client.Do(ctx, req, column) 251 if err != nil { 252 return nil, resp, err 253 } 254 255 return column, resp, nil 256 } 257 258 // DeleteProjectColumn deletes a column from a GitHub Project. 259 // 260 // GitHub API docs: https://docs.github.com/rest/projects/columns#delete-a-project-column 261 // 262 //meta:operation DELETE /projects/columns/{column_id} 263 func (s *ProjectsService) DeleteProjectColumn(ctx context.Context, columnID int64) (*Response, error) { 264 u := fmt.Sprintf("projects/columns/%v", columnID) 265 req, err := s.client.NewRequest("DELETE", u, nil) 266 if err != nil { 267 return nil, err 268 } 269 270 // TODO: remove custom Accept header when this API fully launches. 271 req.Header.Set("Accept", mediaTypeProjectsPreview) 272 273 return s.client.Do(ctx, req, nil) 274 } 275 276 // ProjectColumnMoveOptions specifies the parameters to the 277 // ProjectsService.MoveProjectColumn method. 278 type ProjectColumnMoveOptions struct { 279 // Position can be one of "first", "last", or "after:<column-id>", where 280 // <column-id> is the ID of a column in the same project. (Required.) 281 Position string `json:"position"` 282 } 283 284 // MoveProjectColumn moves a column within a GitHub Project. 285 // 286 // GitHub API docs: https://docs.github.com/rest/projects/columns#move-a-project-column 287 // 288 //meta:operation POST /projects/columns/{column_id}/moves 289 func (s *ProjectsService) MoveProjectColumn(ctx context.Context, columnID int64, opts *ProjectColumnMoveOptions) (*Response, error) { 290 u := fmt.Sprintf("projects/columns/%v/moves", columnID) 291 req, err := s.client.NewRequest("POST", u, opts) 292 if err != nil { 293 return nil, err 294 } 295 296 // TODO: remove custom Accept header when this API fully launches. 297 req.Header.Set("Accept", mediaTypeProjectsPreview) 298 299 return s.client.Do(ctx, req, nil) 300 } 301 302 // ProjectCard represents a card in a column of a GitHub Project. 303 // 304 // GitHub API docs: https://docs.github.com/rest/projects/cards/#get-a-project-card 305 type ProjectCard struct { 306 URL *string `json:"url,omitempty"` 307 ColumnURL *string `json:"column_url,omitempty"` 308 ContentURL *string `json:"content_url,omitempty"` 309 ID *int64 `json:"id,omitempty"` 310 Note *string `json:"note,omitempty"` 311 Creator *User `json:"creator,omitempty"` 312 CreatedAt *Timestamp `json:"created_at,omitempty"` 313 UpdatedAt *Timestamp `json:"updated_at,omitempty"` 314 NodeID *string `json:"node_id,omitempty"` 315 Archived *bool `json:"archived,omitempty"` 316 317 // The following fields are only populated by Webhook events. 318 ColumnID *int64 `json:"column_id,omitempty"` 319 320 // The following fields are only populated by Events API. 321 ProjectID *int64 `json:"project_id,omitempty"` 322 ProjectURL *string `json:"project_url,omitempty"` 323 ColumnName *string `json:"column_name,omitempty"` 324 PreviousColumnName *string `json:"previous_column_name,omitempty"` // Populated in "moved_columns_in_project" event deliveries. 325 } 326 327 // ProjectCardListOptions specifies the optional parameters to the 328 // ProjectsService.ListProjectCards method. 329 type ProjectCardListOptions struct { 330 // ArchivedState is used to list all, archived, or not_archived project cards. 331 // Defaults to not_archived when you omit this parameter. 332 ArchivedState *string `url:"archived_state,omitempty"` 333 334 ListOptions 335 } 336 337 // ListProjectCards lists the cards in a column of a GitHub Project. 338 // 339 // GitHub API docs: https://docs.github.com/rest/projects/cards#list-project-cards 340 // 341 //meta:operation GET /projects/columns/{column_id}/cards 342 func (s *ProjectsService) ListProjectCards(ctx context.Context, columnID int64, opts *ProjectCardListOptions) ([]*ProjectCard, *Response, error) { 343 u := fmt.Sprintf("projects/columns/%v/cards", columnID) 344 u, err := addOptions(u, opts) 345 if err != nil { 346 return nil, nil, err 347 } 348 349 req, err := s.client.NewRequest("GET", u, nil) 350 if err != nil { 351 return nil, nil, err 352 } 353 354 // TODO: remove custom Accept headers when APIs fully launch. 355 req.Header.Set("Accept", mediaTypeProjectsPreview) 356 357 cards := []*ProjectCard{} 358 resp, err := s.client.Do(ctx, req, &cards) 359 if err != nil { 360 return nil, resp, err 361 } 362 363 return cards, resp, nil 364 } 365 366 // GetProjectCard gets a card in a column of a GitHub Project. 367 // 368 // GitHub API docs: https://docs.github.com/rest/projects/cards#get-a-project-card 369 // 370 //meta:operation GET /projects/columns/cards/{card_id} 371 func (s *ProjectsService) GetProjectCard(ctx context.Context, cardID int64) (*ProjectCard, *Response, error) { 372 u := fmt.Sprintf("projects/columns/cards/%v", cardID) 373 req, err := s.client.NewRequest("GET", u, nil) 374 if err != nil { 375 return nil, nil, err 376 } 377 378 // TODO: remove custom Accept headers when APIs fully launch. 379 req.Header.Set("Accept", mediaTypeProjectsPreview) 380 381 card := &ProjectCard{} 382 resp, err := s.client.Do(ctx, req, card) 383 if err != nil { 384 return nil, resp, err 385 } 386 387 return card, resp, nil 388 } 389 390 // ProjectCardOptions specifies the parameters to the 391 // ProjectsService.CreateProjectCard and 392 // ProjectsService.UpdateProjectCard methods. 393 type ProjectCardOptions struct { 394 // The note of the card. Note and ContentID are mutually exclusive. 395 Note string `json:"note,omitempty"` 396 // The ID (not Number) of the Issue to associate with this card. 397 // Note and ContentID are mutually exclusive. 398 ContentID int64 `json:"content_id,omitempty"` 399 // The type of content to associate with this card. Possible values are: "Issue" and "PullRequest". 400 ContentType string `json:"content_type,omitempty"` 401 // Use true to archive a project card. 402 // Specify false if you need to restore a previously archived project card. 403 Archived *bool `json:"archived,omitempty"` 404 } 405 406 // CreateProjectCard creates a card in the specified column of a GitHub Project. 407 // 408 // GitHub API docs: https://docs.github.com/rest/projects/cards#create-a-project-card 409 // 410 //meta:operation POST /projects/columns/{column_id}/cards 411 func (s *ProjectsService) CreateProjectCard(ctx context.Context, columnID int64, opts *ProjectCardOptions) (*ProjectCard, *Response, error) { 412 u := fmt.Sprintf("projects/columns/%v/cards", columnID) 413 req, err := s.client.NewRequest("POST", u, opts) 414 if err != nil { 415 return nil, nil, err 416 } 417 418 // TODO: remove custom Accept headers when APIs fully launch. 419 req.Header.Set("Accept", mediaTypeProjectsPreview) 420 421 card := &ProjectCard{} 422 resp, err := s.client.Do(ctx, req, card) 423 if err != nil { 424 return nil, resp, err 425 } 426 427 return card, resp, nil 428 } 429 430 // UpdateProjectCard updates a card of a GitHub Project. 431 // 432 // GitHub API docs: https://docs.github.com/rest/projects/cards#update-an-existing-project-card 433 // 434 //meta:operation PATCH /projects/columns/cards/{card_id} 435 func (s *ProjectsService) UpdateProjectCard(ctx context.Context, cardID int64, opts *ProjectCardOptions) (*ProjectCard, *Response, error) { 436 u := fmt.Sprintf("projects/columns/cards/%v", cardID) 437 req, err := s.client.NewRequest("PATCH", u, opts) 438 if err != nil { 439 return nil, nil, err 440 } 441 442 // TODO: remove custom Accept headers when APIs fully launch. 443 req.Header.Set("Accept", mediaTypeProjectsPreview) 444 445 card := &ProjectCard{} 446 resp, err := s.client.Do(ctx, req, card) 447 if err != nil { 448 return nil, resp, err 449 } 450 451 return card, resp, nil 452 } 453 454 // DeleteProjectCard deletes a card from a GitHub Project. 455 // 456 // GitHub API docs: https://docs.github.com/rest/projects/cards#delete-a-project-card 457 // 458 //meta:operation DELETE /projects/columns/cards/{card_id} 459 func (s *ProjectsService) DeleteProjectCard(ctx context.Context, cardID int64) (*Response, error) { 460 u := fmt.Sprintf("projects/columns/cards/%v", cardID) 461 req, err := s.client.NewRequest("DELETE", u, nil) 462 if err != nil { 463 return nil, err 464 } 465 466 // TODO: remove custom Accept header when this API fully launches. 467 req.Header.Set("Accept", mediaTypeProjectsPreview) 468 469 return s.client.Do(ctx, req, nil) 470 } 471 472 // ProjectCardMoveOptions specifies the parameters to the 473 // ProjectsService.MoveProjectCard method. 474 type ProjectCardMoveOptions struct { 475 // Position can be one of "top", "bottom", or "after:<card-id>", where 476 // <card-id> is the ID of a card in the same project. 477 Position string `json:"position"` 478 // ColumnID is the ID of a column in the same project. Note that ColumnID 479 // is required when using Position "after:<card-id>" when that card is in 480 // another column; otherwise it is optional. 481 ColumnID int64 `json:"column_id,omitempty"` 482 } 483 484 // MoveProjectCard moves a card within a GitHub Project. 485 // 486 // GitHub API docs: https://docs.github.com/rest/projects/cards#move-a-project-card 487 // 488 //meta:operation POST /projects/columns/cards/{card_id}/moves 489 func (s *ProjectsService) MoveProjectCard(ctx context.Context, cardID int64, opts *ProjectCardMoveOptions) (*Response, error) { 490 u := fmt.Sprintf("projects/columns/cards/%v/moves", cardID) 491 req, err := s.client.NewRequest("POST", u, opts) 492 if err != nil { 493 return nil, err 494 } 495 496 // TODO: remove custom Accept header when this API fully launches. 497 req.Header.Set("Accept", mediaTypeProjectsPreview) 498 499 return s.client.Do(ctx, req, nil) 500 } 501 502 // ProjectCollaboratorOptions specifies the optional parameters to the 503 // ProjectsService.AddProjectCollaborator method. 504 type ProjectCollaboratorOptions struct { 505 // Permission specifies the permission to grant to the collaborator. 506 // Possible values are: 507 // "read" - can read, but not write to or administer this project. 508 // "write" - can read and write, but not administer this project. 509 // "admin" - can read, write and administer this project. 510 // 511 // Default value is "write" 512 Permission *string `json:"permission,omitempty"` 513 } 514 515 // AddProjectCollaborator adds a collaborator to an organization project and sets 516 // their permission level. You must be an organization owner or a project admin to add a collaborator. 517 // 518 // GitHub API docs: https://docs.github.com/rest/projects/collaborators#add-project-collaborator 519 // 520 //meta:operation PUT /projects/{project_id}/collaborators/{username} 521 func (s *ProjectsService) AddProjectCollaborator(ctx context.Context, id int64, username string, opts *ProjectCollaboratorOptions) (*Response, error) { 522 u := fmt.Sprintf("projects/%v/collaborators/%v", id, username) 523 req, err := s.client.NewRequest("PUT", u, opts) 524 if err != nil { 525 return nil, err 526 } 527 528 // TODO: remove custom Accept header when this API fully launches. 529 req.Header.Set("Accept", mediaTypeProjectsPreview) 530 531 return s.client.Do(ctx, req, nil) 532 } 533 534 // RemoveProjectCollaborator removes a collaborator from an organization project. 535 // You must be an organization owner or a project admin to remove a collaborator. 536 // 537 // GitHub API docs: https://docs.github.com/rest/projects/collaborators#remove-user-as-a-collaborator 538 // 539 //meta:operation DELETE /projects/{project_id}/collaborators/{username} 540 func (s *ProjectsService) RemoveProjectCollaborator(ctx context.Context, id int64, username string) (*Response, error) { 541 u := fmt.Sprintf("projects/%v/collaborators/%v", id, username) 542 req, err := s.client.NewRequest("DELETE", u, nil) 543 if err != nil { 544 return nil, err 545 } 546 547 // TODO: remove custom Accept header when this API fully launches. 548 req.Header.Set("Accept", mediaTypeProjectsPreview) 549 550 return s.client.Do(ctx, req, nil) 551 } 552 553 // ListCollaboratorOptions specifies the optional parameters to the 554 // ProjectsService.ListProjectCollaborators method. 555 type ListCollaboratorOptions struct { 556 // Affiliation specifies how collaborators should be filtered by their affiliation. 557 // Possible values are: 558 // "outside" - All outside collaborators of an organization-owned repository 559 // "direct" - All collaborators with permissions to an organization-owned repository, 560 // regardless of organization membership status 561 // "all" - All collaborators the authenticated user can see 562 // 563 // Default value is "all". 564 Affiliation *string `url:"affiliation,omitempty"` 565 566 ListOptions 567 } 568 569 // ListProjectCollaborators lists the collaborators for an organization project. For a project, 570 // the list of collaborators includes outside collaborators, organization members that are direct 571 // collaborators, organization members with access through team memberships, organization members 572 // with access through default organization permissions, and organization owners. You must be an 573 // organization owner or a project admin to list collaborators. 574 // 575 // GitHub API docs: https://docs.github.com/rest/projects/collaborators#list-project-collaborators 576 // 577 //meta:operation GET /projects/{project_id}/collaborators 578 func (s *ProjectsService) ListProjectCollaborators(ctx context.Context, id int64, opts *ListCollaboratorOptions) ([]*User, *Response, error) { 579 u := fmt.Sprintf("projects/%v/collaborators", id) 580 u, err := addOptions(u, opts) 581 if err != nil { 582 return nil, nil, err 583 } 584 585 req, err := s.client.NewRequest("GET", u, nil) 586 if err != nil { 587 return nil, nil, err 588 } 589 590 // TODO: remove custom Accept header when this API fully launches. 591 req.Header.Set("Accept", mediaTypeProjectsPreview) 592 593 var users []*User 594 resp, err := s.client.Do(ctx, req, &users) 595 if err != nil { 596 return nil, resp, err 597 } 598 599 return users, resp, nil 600 } 601 602 // ProjectPermissionLevel represents the permission level an organization 603 // member has for a given project. 604 type ProjectPermissionLevel struct { 605 // Possible values: "admin", "write", "read", "none" 606 Permission *string `json:"permission,omitempty"` 607 608 User *User `json:"user,omitempty"` 609 } 610 611 // ReviewProjectCollaboratorPermission returns the collaborator's permission level for an organization 612 // project. Possible values for the permission key: "admin", "write", "read", "none". 613 // You must be an organization owner or a project admin to review a user's permission level. 614 // 615 // GitHub API docs: https://docs.github.com/rest/projects/collaborators#get-project-permission-for-a-user 616 // 617 //meta:operation GET /projects/{project_id}/collaborators/{username}/permission 618 func (s *ProjectsService) ReviewProjectCollaboratorPermission(ctx context.Context, id int64, username string) (*ProjectPermissionLevel, *Response, error) { 619 u := fmt.Sprintf("projects/%v/collaborators/%v/permission", id, username) 620 req, err := s.client.NewRequest("GET", u, nil) 621 if err != nil { 622 return nil, nil, err 623 } 624 625 // TODO: remove custom Accept header when this API fully launches. 626 req.Header.Set("Accept", mediaTypeProjectsPreview) 627 628 ppl := new(ProjectPermissionLevel) 629 resp, err := s.client.Do(ctx, req, ppl) 630 if err != nil { 631 return nil, resp, err 632 } 633 return ppl, resp, nil 634 }