1package gerrit 2 3import ( 4 "errors" 5 "fmt" 6 "io/ioutil" 7 "net/http" 8) 9 10// ChangesService contains Change related REST endpoints 11// 12// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html 13type ChangesService struct { 14 client *Client 15} 16 17// WebLinkInfo entity describes a link to an external site. 18// 19// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#web-link-info 20type WebLinkInfo struct { 21 Name string `json:"name"` 22 URL string `json:"url"` 23 ImageURL string `json:"image_url"` 24} 25 26// GitPersonInfo entity contains information about the author/committer of a commit. 27type GitPersonInfo struct { 28 Name string `json:"name"` 29 Email string `json:"email"` 30 Date Timestamp `json:"date"` 31 TZ int `json:"tz"` 32} 33 34// NotifyInfo entity contains detailed information about who should be 35// notified about an update 36type NotifyInfo struct { 37 Accounts []AccountInfo `json:"accounts"` 38} 39 40// AbandonInput entity contains information for abandoning a change. 41type AbandonInput struct { 42 Message string `json:"message,omitempty"` 43 Notify string `json:"notify"` 44 NotifyDetails []NotifyInfo `json:"notify_details"` 45} 46 47// ApprovalInfo entity contains information about an approval from a user for a label on a change. 48type ApprovalInfo struct { 49 AccountInfo 50 Value int `json:"value,omitempty"` 51 Date string `json:"date,omitempty"` 52} 53 54// ChangeEditInput entity contains information for restoring a path within change edit. 55type ChangeEditInput struct { 56 RestorePath string `json:"restore_path,omitempty"` 57 OldPath string `json:"old_path,omitempty"` 58 NewPath string `json:"new_path,omitempty"` 59} 60 61// ChangeEditMessageInput entity contains information for changing the commit message within a change edit. 62type ChangeEditMessageInput struct { 63 Message string `json:"message"` 64} 65 66// ChangeMessageInfo entity contains information about a message attached to a change. 67type ChangeMessageInfo struct { 68 ID string `json:"id"` 69 Author AccountInfo `json:"author,omitempty"` 70 Date Timestamp `json:"date"` 71 Message string `json:"message"` 72 Tag string `json:"tag,omitempty"` 73 RevisionNumber int `json:"_revision_number,omitempty"` 74} 75 76// CherryPickInput entity contains information for cherry-picking a change to a new branch. 77type CherryPickInput struct { 78 Message string `json:"message"` 79 Destination string `json:"destination"` 80} 81 82// CommentRange entity describes the range of an inline comment. 83type CommentRange struct { 84 StartLine int `json:"start_line"` 85 StartCharacter int `json:"start_character"` 86 EndLine int `json:"end_line"` 87 EndCharacter int `json:"end_character"` 88} 89 90// DiffFileMetaInfo entity contains meta information about a file diff 91type DiffFileMetaInfo struct { 92 Name string `json:"name"` 93 ContentType string `json:"content_type"` 94 Lines int `json:"lines"` 95 WebLinks []WebLinkInfo `json:"web_links,omitempty"` 96} 97 98// DiffWebLinkInfo entity describes a link on a diff screen to an external site. 99type DiffWebLinkInfo struct { 100 Name string `json:"name"` 101 URL string `json:"url"` 102 ImageURL string `json:"image_url"` 103 ShowOnSideBySideDiffView bool `json:"show_on_side_by_side_diff_view"` 104 ShowOnUnifiedDiffView bool `json:"show_on_unified_diff_view"` 105} 106 107// FetchInfo entity contains information about how to fetch a patch set via a certain protocol. 108type FetchInfo struct { 109 URL string `json:"url"` 110 Ref string `json:"ref"` 111 Commands map[string]string `json:"commands,omitempty"` 112} 113 114// FixInput entity contains options for fixing commits using the fix change endpoint. 115type FixInput struct { 116 DeletePatchSetIfCommitMissing bool `json:"delete_patch_set_if_commit_missing"` 117 ExpectMergedAs string `json:"expect_merged_as"` 118} 119 120// GroupBaseInfo entity contains base information about the group. 121type GroupBaseInfo struct { 122 ID int `json:"id"` 123 Name string `json:"name"` 124} 125 126// IncludedInInfo entity contains information about the branches a change was merged into and tags it was tagged with. 127type IncludedInInfo struct { 128 Branches []string `json:"branches"` 129 Tags []string `json:"tags"` 130 External map[string]string `json:"external,omitempty"` 131} 132 133// ProblemInfo entity contains a description of a potential consistency problem with a change. 134// These are not related to the code review process, but rather indicate some inconsistency in Gerrit’s database or repository metadata related to the enclosing change. 135type ProblemInfo struct { 136 Message string `json:"message"` 137 Status string `json:"status,omitempty"` 138 Outcome string `json:"outcome,omitempty"` 139} 140 141// RebaseInput entity contains information for changing parent when rebasing. 142type RebaseInput struct { 143 Base string `json:"base,omitempty"` 144} 145 146// RestoreInput entity contains information for restoring a change. 147type RestoreInput struct { 148 Message string `json:"message,omitempty"` 149} 150 151// RevertInput entity contains information for reverting a change. 152type RevertInput struct { 153 Message string `json:"message,omitempty"` 154} 155 156// ReviewInfo entity contains information about a review. 157type ReviewInfo struct { 158 Labels map[string]int `json:"labels"` 159} 160 161// ReviewResult entity contains information regarding the updates that were 162// made to a review. 163type ReviewResult struct { 164 ReviewInfo 165 Reviewers map[string]AddReviewerResult `json:"reviewers,omitempty"` 166 Ready bool `json:"ready,omitempty"` 167} 168 169// TopicInput entity contains information for setting a topic. 170type TopicInput struct { 171 Topic string `json:"topic,omitempty"` 172} 173 174// SubmitRecord entity describes results from a submit_rule. 175type SubmitRecord struct { 176 Status string `json:"status"` 177 Ok map[string]map[string]AccountInfo `json:"ok,omitempty"` 178 Reject map[string]map[string]AccountInfo `json:"reject,omitempty"` 179 Need map[string]interface{} `json:"need,omitempty"` 180 May map[string]map[string]AccountInfo `json:"may,omitempty"` 181 Impossible map[string]interface{} `json:"impossible,omitempty"` 182 ErrorMessage string `json:"error_message,omitempty"` 183} 184 185// SubmitInput entity contains information for submitting a change. 186type SubmitInput struct { 187 WaitForMerge bool `json:"wait_for_merge"` 188} 189 190// SubmitInfo entity contains information about the change status after submitting. 191type SubmitInfo struct { 192 Status string `json:"status"` 193 OnBehalfOf string `json:"on_behalf_of,omitempty"` 194} 195 196// RuleInput entity contains information to test a Prolog rule. 197type RuleInput struct { 198 Rule string `json:"rule"` 199 Filters string `json:"filters,omitempty"` 200} 201 202// ReviewerInput entity contains information for adding a reviewer to a change. 203type ReviewerInput struct { 204 Reviewer string `json:"reviewer"` 205 Confirmed bool `json:"confirmed,omitempty"` 206} 207 208// ReviewInput entity contains information for adding a review to a revision. 209type ReviewInput struct { 210 Message string `json:"message,omitempty"` 211 Tag string `json:"tag,omitempty"` 212 Labels map[string]string `json:"labels,omitempty"` 213 Comments map[string][]CommentInput `json:"comments,omitempty"` 214 RobotComments map[string][]RobotCommentInput `json:"robot_comments,omitempty"` 215 StrictLabels bool `json:"strict_labels,omitempty"` 216 Drafts string `json:"drafts,omitempty"` 217 Notify string `json:"notify,omitempty"` 218 OmitDuplicateComments bool `json:"omit_duplicate_comments,omitempty"` 219 OnBehalfOf string `json:"on_behalf_of,omitempty"` 220} 221 222// RelatedChangeAndCommitInfo entity contains information about a related change and commit. 223type RelatedChangeAndCommitInfo struct { 224 ChangeID string `json:"change_id,omitempty"` 225 Commit CommitInfo `json:"commit"` 226 ChangeNumber int `json:"_change_number,omitempty"` 227 RevisionNumber int `json:"_revision_number,omitempty"` 228 CurrentRevisionNumber int `json:"_current_revision_number,omitempty"` 229 Status string `json:"status,omitempty"` 230} 231 232// DiffContent entity contains information about the content differences in a file. 233type DiffContent struct { 234 A []string `json:"a,omitempty"` 235 B []string `json:"b,omitempty"` 236 AB []string `json:"ab,omitempty"` 237 EditA DiffIntralineInfo `json:"edit_a,omitempty"` 238 EditB DiffIntralineInfo `json:"edit_b,omitempty"` 239 Skip int `json:"skip,omitempty"` 240 Common bool `json:"common,omitempty"` 241} 242 243// CommentInput entity contains information for creating an inline comment. 244type CommentInput struct { 245 ID string `json:"id,omitempty"` 246 Path string `json:"path,omitempty"` 247 Side string `json:"side,omitempty"` 248 Line int `json:"line,omitempty"` 249 Range *CommentRange `json:"range,omitempty"` 250 InReplyTo string `json:"in_reply_to,omitempty"` 251 Updated *Timestamp `json:"updated,omitempty"` 252 Message string `json:"message,omitempty"` 253} 254 255// RobotCommentInput entity contains information for creating an inline robot comment. 256// https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#robot-comment-input 257type RobotCommentInput struct { 258 CommentInput 259 260 // The ID of the robot that generated this comment. 261 RobotID string `json:"robot_id"` 262 // An ID of the run of the robot. 263 RobotRunID string `json:"robot_run_id"` 264 // URL to more information. 265 URL string `json:"url,omitempty"` 266 // Robot specific properties as map that maps arbitrary keys to values. 267 Properties *map[string]*string `json:"properties,omitempty"` 268 // Suggested fixes for this robot comment as a list of FixSuggestionInfo 269 // entities. 270 FixSuggestions *FixSuggestionInfo `json:"fix_suggestions,omitempty"` 271} 272 273// RobotCommentInfo entity contains information about a robot inline comment 274// RobotCommentInfo has the same fields as CommentInfo. In addition RobotCommentInfo has the following fields: 275// https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#robot-comment-info 276type RobotCommentInfo struct { 277 CommentInfo 278 279 // The ID of the robot that generated this comment. 280 RobotID string `json:"robot_id"` 281 // An ID of the run of the robot. 282 RobotRunID string `json:"robot_run_id"` 283 // URL to more information. 284 URL string `json:"url,omitempty"` 285 // Robot specific properties as map that maps arbitrary keys to values. 286 Properties map[string]string `json:"properties,omitempty"` 287 // Suggested fixes for this robot comment as a list of FixSuggestionInfo 288 // entities. 289 FixSuggestions *FixSuggestionInfo `json:"fix_suggestions,omitempty"` 290} 291 292// FixSuggestionInfo entity represents a suggested fix. 293// https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#fix-suggestion-info 294type FixSuggestionInfo struct { 295 // The UUID of the suggested fix. It will be generated automatically and 296 // hence will be ignored if it’s set for input objects. 297 FixID string `json:"fix_id"` 298 // A description of the suggested fix. 299 Description string `json:"description"` 300 // A list of FixReplacementInfo entities indicating how the content of one or 301 // several files should be modified. Within a file, they should refer to 302 // non-overlapping regions. 303 Replacements FixReplacementInfo `json:"replacements"` 304} 305 306// FixReplacementInfo entity describes how the content of a file should be replaced by another content. 307// https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#fix-replacement-info 308type FixReplacementInfo struct { 309 // The path of the file which should be modified. Any file in the repository may be modified. 310 Path string `json:"path"` 311 312 // A CommentRange indicating which content of the file should be replaced. 313 // Lines in the file are assumed to be separated by the line feed character, 314 // the carriage return character, the carriage return followed by the line 315 // feed character, or one of the other Unicode linebreak sequences supported 316 // by Java. 317 Range CommentRange `json:"range"` 318 319 // The content which should be used instead of the current one. 320 Replacement string `json:"replacement,omitempty"` 321} 322 323// DiffIntralineInfo entity contains information about intraline edits in a file. 324// 325// The information consists of a list of <skip length, mark length> pairs, 326// where the skip length is the number of characters between the end of 327// the previous edit and the start of this edit, and the mark length is the 328// number of edited characters following the skip. The start of the edits 329// is from the beginning of the related diff content lines. 330// 331// Note that the implied newline character at the end of each line 332// is included in the length calculation, and thus it is possible for 333// the edits to span newlines. 334type DiffIntralineInfo [][2]int 335 336// ChangeInfo entity contains information about a change. 337type ChangeInfo struct { 338 ID string `json:"id"` 339 URL string `json:"url,omitempty"` 340 Project string `json:"project"` 341 Branch string `json:"branch"` 342 Topic string `json:"topic,omitempty"` 343 Hashtags []string `json:"hashtags,omitempty"` 344 ChangeID string `json:"change_id"` 345 Subject string `json:"subject"` 346 Status string `json:"status"` 347 Created Timestamp `json:"created"` 348 Updated Timestamp `json:"updated"` 349 Submitted *Timestamp `json:"submitted,omitempty"` 350 Starred bool `json:"starred,omitempty"` 351 Reviewed bool `json:"reviewed,omitempty"` 352 Mergeable bool `json:"mergeable,omitempty"` 353 Insertions int `json:"insertions"` 354 Deletions int `json:"deletions"` 355 Number int `json:"_number"` 356 Owner AccountInfo `json:"owner"` 357 Actions map[string]ActionInfo `json:"actions,omitempty"` 358 Labels map[string]LabelInfo `json:"labels,omitempty"` 359 PermittedLabels map[string][]string `json:"permitted_labels,omitempty"` 360 RemovableReviewers []AccountInfo `json:"removable_reviewers,omitempty"` 361 Reviewers map[string][]AccountInfo `json:"reviewers,omitempty"` 362 Messages []ChangeMessageInfo `json:"messages,omitempty"` 363 CurrentRevision string `json:"current_revision,omitempty"` 364 Revisions map[string]RevisionInfo `json:"revisions,omitempty"` 365 MoreChanges bool `json:"_more_changes,omitempty"` 366 Problems []ProblemInfo `json:"problems,omitempty"` 367 BaseChange string `json:"base_change,omitempty"` 368} 369 370// LabelInfo entity contains information about a label on a change, always corresponding to the current patch set. 371type LabelInfo struct { 372 Optional bool `json:"optional,omitempty"` 373 374 // Fields set by LABELS 375 Approved AccountInfo `json:"approved,omitempty"` 376 Rejected AccountInfo `json:"rejected,omitempty"` 377 Recommended AccountInfo `json:"recommended,omitempty"` 378 Disliked AccountInfo `json:"disliked,omitempty"` 379 Blocking bool `json:"blocking,omitempty"` 380 Value int `json:"value,omitempty"` 381 DefaultValue int `json:"default_value,omitempty"` 382 383 // Fields set by DETAILED_LABELS 384 All []ApprovalInfo `json:"all,omitempty"` 385 Values map[string]string `json:"values,omitempty"` 386} 387 388// RevisionInfo entity contains information about a patch set. 389type RevisionInfo struct { 390 Draft bool `json:"draft,omitempty"` 391 Number int `json:"_number"` 392 Created Timestamp `json:"created"` 393 Uploader AccountInfo `json:"uploader"` 394 Ref string `json:"ref"` 395 Fetch map[string]FetchInfo `json:"fetch"` 396 Commit CommitInfo `json:"commit,omitempty"` 397 Files map[string]FileInfo `json:"files,omitempty"` 398 Actions map[string]ActionInfo `json:"actions,omitempty"` 399 Reviewed bool `json:"reviewed,omitempty"` 400 MessageWithFooter string `json:"messageWithFooter,omitempty"` 401} 402 403// CommentInfo entity contains information about an inline comment. 404type CommentInfo struct { 405 PatchSet int `json:"patch_set,omitempty"` 406 ID string `json:"id"` 407 Path string `json:"path,omitempty"` 408 Side string `json:"side,omitempty"` 409 Line int `json:"line,omitempty"` 410 Range *CommentRange `json:"range,omitempty"` 411 InReplyTo string `json:"in_reply_to,omitempty"` 412 Message string `json:"message,omitempty"` 413 Updated *Timestamp `json:"updated"` 414 Author AccountInfo `json:"author,omitempty"` 415} 416 417// QueryOptions specifies global parameters to query changes / reviewers. 418// 419// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#list-changes 420type QueryOptions struct { 421 // Query parameter 422 // Clients are allowed to specify more than one query by setting the q parameter multiple times. 423 // In this case the result is an array of arrays, one per query in the same order the queries were given in. 424 // 425 // Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/user-search.html#_search_operators 426 Query []string `url:"q,omitempty"` 427 428 // The n parameter can be used to limit the returned results. 429 // If the n query parameter is supplied and additional changes exist that match the query beyond the end, the last change object has a _more_changes: true JSON field set. 430 Limit int `url:"n,omitempty"` 431} 432 433// QueryChangeOptions specifies the parameters to the ChangesService.QueryChanges. 434// 435// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#list-changes 436type QueryChangeOptions struct { 437 QueryOptions 438 439 // The S or start query parameter can be supplied to skip a number of changes from the list. 440 Skip int `url:"S,omitempty"` 441 Start int `url:"start,omitempty"` 442 443 ChangeOptions 444} 445 446// ChangeOptions specifies the parameters for Query changes. 447// 448// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#list-changes 449type ChangeOptions struct { 450 // Additional fields can be obtained by adding o parameters, each option requires more database lookups and slows down the query response time to the client so they are generally disabled by default. 451 // 452 // Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#list-changes 453 AdditionalFields []string `url:"o,omitempty"` 454} 455 456// QueryChanges lists changes visible to the caller. 457// The query string must be provided by the q parameter. 458// The n parameter can be used to limit the returned results. 459// 460// The change output is sorted by the last update time, most recently updated to oldest updated. 461// 462// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#list-changes 463func (s *ChangesService) QueryChanges(opt *QueryChangeOptions) (*[]ChangeInfo, *Response, error) { 464 u := "changes/" 465 466 u, err := addOptions(u, opt) 467 if err != nil { 468 return nil, nil, err 469 } 470 471 req, err := s.client.NewRequest("GET", u, nil) 472 if err != nil { 473 return nil, nil, err 474 } 475 476 v := new([]ChangeInfo) 477 resp, err := s.client.Do(req, v) 478 if err != nil { 479 return nil, resp, err 480 } 481 482 return v, resp, err 483} 484 485// GetChange retrieves a change. 486// Additional fields can be obtained by adding o parameters, each option requires more database lookups and slows down the query response time to the client so they are generally disabled by default. 487// 488// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#get-change 489func (s *ChangesService) GetChange(changeID string, opt *ChangeOptions) (*ChangeInfo, *Response, error) { 490 u := fmt.Sprintf("changes/%s", changeID) 491 return s.getChangeInfoResponse(u, opt) 492} 493 494// GetChangeDetail retrieves a change with labels, detailed labels, detailed accounts, and messages. 495// Additional fields can be obtained by adding o parameters, each option requires more database lookups and slows down the query response time to the client so they are generally disabled by default. 496// 497// This response will contain all votes for each label and include one combined vote. 498// The combined label vote is calculated in the following order (from highest to lowest): REJECTED > APPROVED > DISLIKED > RECOMMENDED. 499// 500// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#get-change-detail 501func (s *ChangesService) GetChangeDetail(changeID string, opt *ChangeOptions) (*ChangeInfo, *Response, error) { 502 u := fmt.Sprintf("changes/%s/detail", changeID) 503 return s.getChangeInfoResponse(u, opt) 504} 505 506// getChangeInfoResponse retrieved a single ChangeInfo Response for a GET request 507func (s *ChangesService) getChangeInfoResponse(u string, opt *ChangeOptions) (*ChangeInfo, *Response, error) { 508 u, err := addOptions(u, opt) 509 if err != nil { 510 return nil, nil, err 511 } 512 513 req, err := s.client.NewRequest("GET", u, nil) 514 if err != nil { 515 return nil, nil, err 516 } 517 518 v := new(ChangeInfo) 519 resp, err := s.client.Do(req, v) 520 if err != nil { 521 return nil, resp, err 522 } 523 524 return v, resp, err 525} 526 527// GetTopic retrieves the topic of a change. 528// 529// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#get-topic 530func (s *ChangesService) GetTopic(changeID string) (string, *Response, error) { 531 u := fmt.Sprintf("changes/%s/topic", changeID) 532 return getStringResponseWithoutOptions(s.client, u) 533} 534 535// ChangesSubmittedTogether returns a list of all changes which are submitted when {submit} is called for this change, including the current change itself. 536// An empty list is returned if this change will be submitted by itself (no other changes). 537// 538// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#submitted_together 539func (s *ChangesService) ChangesSubmittedTogether(changeID string) (*[]ChangeInfo, *Response, error) { 540 u := fmt.Sprintf("changes/%s/submitted_together", changeID) 541 542 req, err := s.client.NewRequest("GET", u, nil) 543 if err != nil { 544 return nil, nil, err 545 } 546 547 v := new([]ChangeInfo) 548 resp, err := s.client.Do(req, v) 549 if err != nil { 550 return nil, resp, err 551 } 552 553 return v, resp, err 554} 555 556// GetIncludedIn retrieves the branches and tags in which a change is included. 557// 558// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#get-included-in 559func (s *ChangesService) GetIncludedIn(changeID string) (*IncludedInInfo, *Response, error) { 560 u := fmt.Sprintf("changes/%s/in", changeID) 561 562 req, err := s.client.NewRequest("GET", u, nil) 563 if err != nil { 564 return nil, nil, err 565 } 566 567 v := new(IncludedInInfo) 568 resp, err := s.client.Do(req, v) 569 if err != nil { 570 return nil, resp, err 571 } 572 573 return v, resp, err 574} 575 576// ListChangeComments lists the published comments of all revisions of the change. 577// The entries in the map are sorted by file path, and the comments for each path are sorted by patch set number. 578// Each comment has the patch_set and author fields set. 579// 580// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#list-change-comments 581func (s *ChangesService) ListChangeComments(changeID string) (*map[string][]CommentInfo, *Response, error) { 582 u := fmt.Sprintf("changes/%s/comments", changeID) 583 return s.getCommentInfoMapResponse(u) 584} 585 586// ListChangeDrafts lLists the draft comments of all revisions of the change that belong to the calling user. 587// The entries in the map are sorted by file path, and the comments for each path are sorted by patch set number. 588// Each comment has the patch_set field set, and no author. 589// 590// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#list-change-drafts 591func (s *ChangesService) ListChangeDrafts(changeID string) (*map[string][]CommentInfo, *Response, error) { 592 u := fmt.Sprintf("changes/%s/drafts", changeID) 593 return s.getCommentInfoMapResponse(u) 594} 595 596// getCommentInfoMapResponse retrieved a map of CommentInfo Response for a GET request 597func (s *ChangesService) getCommentInfoMapResponse(u string) (*map[string][]CommentInfo, *Response, error) { 598 req, err := s.client.NewRequest("GET", u, nil) 599 if err != nil { 600 return nil, nil, err 601 } 602 603 v := new(map[string][]CommentInfo) 604 resp, err := s.client.Do(req, v) 605 if err != nil { 606 return nil, resp, err 607 } 608 609 return v, resp, err 610} 611 612// CheckChange performs consistency checks on the change, and returns a ChangeInfo entity with the problems field set to a list of ProblemInfo entities. 613// Depending on the type of problem, some fields not marked optional may be missing from the result. 614// At least id, project, branch, and _number will be present. 615// 616// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#check-change 617func (s *ChangesService) CheckChange(changeID string) (*ChangeInfo, *Response, error) { 618 u := fmt.Sprintf("changes/%s/check", changeID) 619 return s.getChangeInfoResponse(u, nil) 620} 621 622// getCommentInfoResponse retrieved a CommentInfo Response for a GET request 623func (s *ChangesService) getCommentInfoResponse(u string) (*CommentInfo, *Response, error) { 624 req, err := s.client.NewRequest("GET", u, nil) 625 if err != nil { 626 return nil, nil, err 627 } 628 629 v := new(CommentInfo) 630 resp, err := s.client.Do(req, v) 631 if err != nil { 632 return nil, resp, err 633 } 634 635 return v, resp, err 636} 637 638// getCommentInfoMapSliceResponse retrieved a map with a slice of CommentInfo Response for a GET request 639func (s *ChangesService) getCommentInfoMapSliceResponse(u string) (*map[string][]CommentInfo, *Response, error) { 640 req, err := s.client.NewRequest("GET", u, nil) 641 if err != nil { 642 return nil, nil, err 643 } 644 645 v := new(map[string][]CommentInfo) 646 resp, err := s.client.Do(req, v) 647 if err != nil { 648 return nil, resp, err 649 } 650 651 return v, resp, err 652} 653 654// CreateChange creates a new change. 655// The change info ChangeInfo entity must be provided in the request body. 656// Only the following attributes are honored: project, branch, subject, status and topic. 657// The first three attributes are mandatory. 658// Valid values for status are: DRAFT and NEW. 659// 660// As response a ChangeInfo entity is returned that describes the resulting change. 661// 662// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#create-change 663func (s *ChangesService) CreateChange(input *ChangeInfo) (*ChangeInfo, *Response, error) { 664 u := "changes/" 665 666 req, err := s.client.NewRequest("POST", u, input) 667 if err != nil { 668 return nil, nil, err 669 } 670 671 v := new(ChangeInfo) 672 resp, err := s.client.Do(req, v) 673 if err != nil { 674 return nil, resp, err 675 } 676 677 return v, resp, err 678} 679 680// SetTopic sets the topic of a change. 681// The new topic must be provided in the request body inside a TopicInput entity. 682// 683// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#set-topic 684func (s *ChangesService) SetTopic(changeID string, input *TopicInput) (*string, *Response, error) { 685 u := fmt.Sprintf("changes/%s/topic", changeID) 686 687 req, err := s.client.NewRequest("PUT", u, input) 688 if err != nil { 689 return nil, nil, err 690 } 691 692 v := new(string) 693 resp, err := s.client.Do(req, v) 694 if err != nil { 695 return nil, resp, err 696 } 697 698 return v, resp, err 699} 700 701// DeleteTopic deletes the topic of a change. 702// The request body does not need to include a TopicInput entity if no review comment is added. 703// 704// Please note that some proxies prohibit request bodies for DELETE requests. 705// In this case, if you want to specify a commit message, use PUT to delete the topic. 706// 707// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#delete-topic 708func (s *ChangesService) DeleteTopic(changeID string) (*Response, error) { 709 u := fmt.Sprintf("changes/%s/topic", changeID) 710 return s.client.DeleteRequest(u, nil) 711} 712 713// DeleteDraftChange deletes a draft change. 714// 715// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#delete-draft-change 716func (s *ChangesService) DeleteDraftChange(changeID string) (*Response, error) { 717 u := fmt.Sprintf("changes/%s", changeID) 718 return s.client.DeleteRequest(u, nil) 719} 720 721// PublishDraftChange publishes a draft change. 722// 723// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#publish-draft-change 724func (s *ChangesService) PublishDraftChange(changeID, notify string) (*Response, error) { 725 u := fmt.Sprintf("changes/%s/publish", changeID) 726 727 req, err := s.client.NewRequest("POST", u, map[string]string{ 728 "notify": notify, 729 }) 730 if err != nil { 731 return nil, err 732 } 733 return s.client.Do(req, nil) 734} 735 736// IndexChange adds or updates the change in the secondary index. 737// 738// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#index-change 739func (s *ChangesService) IndexChange(changeID string) (*Response, error) { 740 u := fmt.Sprintf("changes/%s/index", changeID) 741 742 req, err := s.client.NewRequest("POST", u, nil) 743 if err != nil { 744 return nil, err 745 } 746 return s.client.Do(req, nil) 747} 748 749// FixChange performs consistency checks on the change as with GET /check, and additionally fixes any problems that can be fixed automatically. 750// The returned field values reflect any fixes. 751// 752// Some fixes have options controlling their behavior, which can be set in the FixInput entity body. 753// Only the change owner, a project owner, or an administrator may fix changes. 754// 755// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#fix-change 756func (s *ChangesService) FixChange(changeID string, input *FixInput) (*ChangeInfo, *Response, error) { 757 u := fmt.Sprintf("changes/%s/check", changeID) 758 759 req, err := s.client.NewRequest("PUT", u, input) 760 if err != nil { 761 return nil, nil, err 762 } 763 764 v := new(ChangeInfo) 765 resp, err := s.client.Do(req, v) 766 if err != nil { 767 return nil, resp, err 768 } 769 770 return v, resp, err 771} 772 773// change is an internal function to consolidate code used by SubmitChange, 774// AbandonChange and other similar functions. 775func (s *ChangesService) change(tail string, changeID string, input interface{}) (*ChangeInfo, *Response, error) { 776 u := fmt.Sprintf("changes/%s/%s", changeID, tail) 777 req, err := s.client.NewRequest("POST", u, input) 778 if err != nil { 779 return nil, nil, err 780 } 781 782 v := new(ChangeInfo) 783 resp, err := s.client.Do(req, v) 784 if err != nil { 785 return nil, resp, err 786 } 787 if resp.StatusCode == http.StatusConflict { 788 body, err := ioutil.ReadAll(resp.Body) 789 if err != nil { 790 return v, resp, err 791 } 792 return v, resp, errors.New(string(body[:])) 793 } 794 return v, resp, nil 795} 796 797// SubmitChange submits a change. 798// 799// The request body only needs to include a SubmitInput entity if submitting on behalf of another user. 800// 801// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#submit-change 802func (s *ChangesService) SubmitChange(changeID string, input *SubmitInput) (*ChangeInfo, *Response, error) { 803 return s.change("submit", changeID, input) 804} 805 806// AbandonChange abandons a change. 807// 808// The request body does not need to include a AbandonInput entity if no review 809// comment is added. 810// 811// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#abandon-change 812func (s *ChangesService) AbandonChange(changeID string, input *AbandonInput) (*ChangeInfo, *Response, error) { 813 return s.change("abandon", changeID, input) 814} 815 816// RebaseChange rebases a change. 817// 818// Optionally, the parent revision can be changed to another patch set through 819// the RebaseInput entity. 820// 821// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#rebase-change 822func (s *ChangesService) RebaseChange(changeID string, input *RebaseInput) (*ChangeInfo, *Response, error) { 823 return s.change("rebase", changeID, input) 824} 825 826// RestoreChange restores a change. 827// 828// The request body does not need to include a RestoreInput entity if no review 829// comment is added. 830// 831// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#restore-change 832func (s *ChangesService) RestoreChange(changeID string, input *RestoreInput) (*ChangeInfo, *Response, error) { 833 return s.change("restore", changeID, input) 834} 835 836// RevertChange reverts a change. 837// 838// The request body does not need to include a RevertInput entity if no 839// review comment is added. 840// 841// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#revert-change 842func (s *ChangesService) RevertChange(changeID string, input *RevertInput) (*ChangeInfo, *Response, error) { 843 return s.change("revert", changeID, input) 844} 845