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