Add API endpoint to get changed files of a PR (#21177)
This adds an api endpoint `/files` to PRs that allows to get a list of changed files. built upon #18228, reviews there are included closes https://github.com/go-gitea/gitea/issues/654 Co-authored-by: Anton Bracke <anton@ju60.de> Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
		
							parent
							
								
									78c15dabf3
								
							
						
					
					
						commit
						1dfa28ffa5
					
				| @ -60,8 +60,8 @@ | |||||||
|   head_repo_id: 1 |   head_repo_id: 1 | ||||||
|   base_repo_id: 1 |   base_repo_id: 1 | ||||||
|   head_branch: pr-to-update |   head_branch: pr-to-update | ||||||
|   base_branch: branch1 |   base_branch: branch2 | ||||||
|   merge_base: 1234567890abcdef |   merge_base: 985f0301dba5e7b34be866819cd15ad3d8f508ee | ||||||
|   has_merged: false |   has_merged: false | ||||||
| 
 | 
 | ||||||
| - | - | ||||||
|  | |||||||
| @ -27,6 +27,7 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	api "code.gitea.io/gitea/modules/structs" | 	api "code.gitea.io/gitea/modules/structs" | ||||||
| 	"code.gitea.io/gitea/modules/util" | 	"code.gitea.io/gitea/modules/util" | ||||||
|  | 	"code.gitea.io/gitea/services/gitdiff" | ||||||
| 	webhook_service "code.gitea.io/gitea/services/webhook" | 	webhook_service "code.gitea.io/gitea/services/webhook" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @ -414,3 +415,36 @@ func ToLFSLock(l *git_model.LFSLock) *api.LFSLock { | |||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // ToChangedFile convert a gitdiff.DiffFile to api.ChangedFile
 | ||||||
|  | func ToChangedFile(f *gitdiff.DiffFile, repo *repo_model.Repository, commit string) *api.ChangedFile { | ||||||
|  | 	status := "changed" | ||||||
|  | 	if f.IsDeleted { | ||||||
|  | 		status = "deleted" | ||||||
|  | 	} else if f.IsCreated { | ||||||
|  | 		status = "added" | ||||||
|  | 	} else if f.IsRenamed && f.Type == gitdiff.DiffFileCopy { | ||||||
|  | 		status = "copied" | ||||||
|  | 	} else if f.IsRenamed && f.Type == gitdiff.DiffFileRename { | ||||||
|  | 		status = "renamed" | ||||||
|  | 	} else if f.Addition == 0 && f.Deletion == 0 { | ||||||
|  | 		status = "unchanged" | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	file := &api.ChangedFile{ | ||||||
|  | 		Filename:    f.GetDiffFileName(), | ||||||
|  | 		Status:      status, | ||||||
|  | 		Additions:   f.Addition, | ||||||
|  | 		Deletions:   f.Deletion, | ||||||
|  | 		Changes:     f.Addition + f.Deletion, | ||||||
|  | 		HTMLURL:     fmt.Sprint(repo.HTMLURL(), "/src/commit/", commit, "/", util.PathEscapeSegments(f.GetDiffFileName())), | ||||||
|  | 		ContentsURL: fmt.Sprint(repo.APIURL(), "/contents/", util.PathEscapeSegments(f.GetDiffFileName()), "?ref=", commit), | ||||||
|  | 		RawURL:      fmt.Sprint(repo.HTMLURL(), "/raw/commit/", commit, "/", util.PathEscapeSegments(f.GetDiffFileName())), | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if status == "rename" { | ||||||
|  | 		file.PreviousFilename = f.OldName | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return file | ||||||
|  | } | ||||||
|  | |||||||
| @ -95,3 +95,16 @@ type EditPullRequestOption struct { | |||||||
| 	RemoveDeadline      *bool      `json:"unset_due_date"` | 	RemoveDeadline      *bool      `json:"unset_due_date"` | ||||||
| 	AllowMaintainerEdit *bool      `json:"allow_maintainer_edit"` | 	AllowMaintainerEdit *bool      `json:"allow_maintainer_edit"` | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // ChangedFile store information about files affected by the pull request
 | ||||||
|  | type ChangedFile struct { | ||||||
|  | 	Filename         string `json:"filename"` | ||||||
|  | 	PreviousFilename string `json:"previous_filename,omitempty"` | ||||||
|  | 	Status           string `json:"status"` | ||||||
|  | 	Additions        int    `json:"additions"` | ||||||
|  | 	Deletions        int    `json:"deletions"` | ||||||
|  | 	Changes          int    `json:"changes"` | ||||||
|  | 	HTMLURL          string `json:"html_url,omitempty"` | ||||||
|  | 	ContentsURL      string `json:"contents_url,omitempty"` | ||||||
|  | 	RawURL           string `json:"raw_url,omitempty"` | ||||||
|  | } | ||||||
|  | |||||||
| @ -1002,6 +1002,7 @@ func Routes(ctx gocontext.Context) *web.Route { | |||||||
| 						m.Get(".{diffType:diff|patch}", repo.DownloadPullDiffOrPatch) | 						m.Get(".{diffType:diff|patch}", repo.DownloadPullDiffOrPatch) | ||||||
| 						m.Post("/update", reqToken(), repo.UpdatePullRequest) | 						m.Post("/update", reqToken(), repo.UpdatePullRequest) | ||||||
| 						m.Get("/commits", repo.GetPullRequestCommits) | 						m.Get("/commits", repo.GetPullRequestCommits) | ||||||
|  | 						m.Get("/files", repo.GetPullRequestFiles) | ||||||
| 						m.Combo("/merge").Get(repo.IsPullRequestMerged). | 						m.Combo("/merge").Get(repo.IsPullRequestMerged). | ||||||
| 							Post(reqToken(), mustNotBeArchived, bind(forms.MergePullRequestForm{}), repo.MergePullRequest). | 							Post(reqToken(), mustNotBeArchived, bind(forms.MergePullRequestForm{}), repo.MergePullRequest). | ||||||
| 							Delete(reqToken(), mustNotBeArchived, repo.CancelScheduledAutoMerge) | 							Delete(reqToken(), mustNotBeArchived, repo.CancelScheduledAutoMerge) | ||||||
|  | |||||||
| @ -26,6 +26,7 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/git" | 	"code.gitea.io/gitea/modules/git" | ||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	"code.gitea.io/gitea/modules/notification" | 	"code.gitea.io/gitea/modules/notification" | ||||||
|  | 	"code.gitea.io/gitea/modules/setting" | ||||||
| 	api "code.gitea.io/gitea/modules/structs" | 	api "code.gitea.io/gitea/modules/structs" | ||||||
| 	"code.gitea.io/gitea/modules/timeutil" | 	"code.gitea.io/gitea/modules/timeutil" | ||||||
| 	"code.gitea.io/gitea/modules/web" | 	"code.gitea.io/gitea/modules/web" | ||||||
| @ -33,6 +34,7 @@ import ( | |||||||
| 	asymkey_service "code.gitea.io/gitea/services/asymkey" | 	asymkey_service "code.gitea.io/gitea/services/asymkey" | ||||||
| 	"code.gitea.io/gitea/services/automerge" | 	"code.gitea.io/gitea/services/automerge" | ||||||
| 	"code.gitea.io/gitea/services/forms" | 	"code.gitea.io/gitea/services/forms" | ||||||
|  | 	"code.gitea.io/gitea/services/gitdiff" | ||||||
| 	issue_service "code.gitea.io/gitea/services/issue" | 	issue_service "code.gitea.io/gitea/services/issue" | ||||||
| 	pull_service "code.gitea.io/gitea/services/pull" | 	pull_service "code.gitea.io/gitea/services/pull" | ||||||
| 	repo_service "code.gitea.io/gitea/services/repository" | 	repo_service "code.gitea.io/gitea/services/repository" | ||||||
| @ -1323,3 +1325,137 @@ func GetPullRequestCommits(ctx *context.APIContext) { | |||||||
| 
 | 
 | ||||||
| 	ctx.JSON(http.StatusOK, &apiCommits) | 	ctx.JSON(http.StatusOK, &apiCommits) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // GetPullRequestFiles gets all changed files associated with a given PR
 | ||||||
|  | func GetPullRequestFiles(ctx *context.APIContext) { | ||||||
|  | 	// swagger:operation GET /repos/{owner}/{repo}/pulls/{index}/files repository repoGetPullRequestFiles
 | ||||||
|  | 	// ---
 | ||||||
|  | 	// summary: Get changed files for a pull request
 | ||||||
|  | 	// produces:
 | ||||||
|  | 	// - application/json
 | ||||||
|  | 	// parameters:
 | ||||||
|  | 	// - name: owner
 | ||||||
|  | 	//   in: path
 | ||||||
|  | 	//   description: owner of the repo
 | ||||||
|  | 	//   type: string
 | ||||||
|  | 	//   required: true
 | ||||||
|  | 	// - name: repo
 | ||||||
|  | 	//   in: path
 | ||||||
|  | 	//   description: name of the repo
 | ||||||
|  | 	//   type: string
 | ||||||
|  | 	//   required: true
 | ||||||
|  | 	// - name: index
 | ||||||
|  | 	//   in: path
 | ||||||
|  | 	//   description: index of the pull request to get
 | ||||||
|  | 	//   type: integer
 | ||||||
|  | 	//   format: int64
 | ||||||
|  | 	//   required: true
 | ||||||
|  | 	// - name: skip-to
 | ||||||
|  | 	//   in: query
 | ||||||
|  | 	//   description: skip to given file
 | ||||||
|  | 	//   type: string
 | ||||||
|  | 	// - name: whitespace
 | ||||||
|  | 	//   in: query
 | ||||||
|  | 	//   description: whitespace behavior
 | ||||||
|  | 	//   type: string
 | ||||||
|  | 	//   enum: [ignore-all, ignore-change, ignore-eol, show-all]
 | ||||||
|  | 	// - name: page
 | ||||||
|  | 	//   in: query
 | ||||||
|  | 	//   description: page number of results to return (1-based)
 | ||||||
|  | 	//   type: integer
 | ||||||
|  | 	// - name: limit
 | ||||||
|  | 	//   in: query
 | ||||||
|  | 	//   description: page size of results
 | ||||||
|  | 	//   type: integer
 | ||||||
|  | 	// responses:
 | ||||||
|  | 	//   "200":
 | ||||||
|  | 	//     "$ref": "#/responses/ChangedFileList"
 | ||||||
|  | 	//   "404":
 | ||||||
|  | 	//     "$ref": "#/responses/notFound"
 | ||||||
|  | 
 | ||||||
|  | 	pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) | ||||||
|  | 	if err != nil { | ||||||
|  | 		if issues_model.IsErrPullRequestNotExist(err) { | ||||||
|  | 			ctx.NotFound() | ||||||
|  | 		} else { | ||||||
|  | 			ctx.Error(http.StatusInternalServerError, "GetPullRequestByIndex", err) | ||||||
|  | 		} | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if err := pr.LoadBaseRepo(); err != nil { | ||||||
|  | 		ctx.InternalServerError(err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if err := pr.LoadHeadRepo(); err != nil { | ||||||
|  | 		ctx.InternalServerError(err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	baseGitRepo := ctx.Repo.GitRepo | ||||||
|  | 
 | ||||||
|  | 	var prInfo *git.CompareInfo | ||||||
|  | 	if pr.HasMerged { | ||||||
|  | 		prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.MergeBase, pr.GetGitRefName(), true, false) | ||||||
|  | 	} else { | ||||||
|  | 		prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitRefName(), true, false) | ||||||
|  | 	} | ||||||
|  | 	if err != nil { | ||||||
|  | 		ctx.ServerError("GetCompareInfo", err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	headCommitID, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName()) | ||||||
|  | 	if err != nil { | ||||||
|  | 		ctx.ServerError("GetRefCommitID", err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	startCommitID := prInfo.MergeBase | ||||||
|  | 	endCommitID := headCommitID | ||||||
|  | 
 | ||||||
|  | 	maxLines, maxFiles := setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffFiles | ||||||
|  | 
 | ||||||
|  | 	diff, err := gitdiff.GetDiff(baseGitRepo, | ||||||
|  | 		&gitdiff.DiffOptions{ | ||||||
|  | 			BeforeCommitID:     startCommitID, | ||||||
|  | 			AfterCommitID:      endCommitID, | ||||||
|  | 			SkipTo:             ctx.FormString("skip-to"), | ||||||
|  | 			MaxLines:           maxLines, | ||||||
|  | 			MaxLineCharacters:  setting.Git.MaxGitDiffLineCharacters, | ||||||
|  | 			MaxFiles:           maxFiles, | ||||||
|  | 			WhitespaceBehavior: gitdiff.GetWhitespaceFlag(ctx.FormString("whitespace")), | ||||||
|  | 		}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		ctx.ServerError("GetDiff", err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	listOptions := utils.GetListOptions(ctx) | ||||||
|  | 
 | ||||||
|  | 	totalNumberOfFiles := diff.NumFiles | ||||||
|  | 	totalNumberOfPages := int(math.Ceil(float64(totalNumberOfFiles) / float64(listOptions.PageSize))) | ||||||
|  | 
 | ||||||
|  | 	start, end := listOptions.GetStartEnd() | ||||||
|  | 
 | ||||||
|  | 	if end > totalNumberOfFiles { | ||||||
|  | 		end = totalNumberOfFiles | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	apiFiles := make([]*api.ChangedFile, 0, end-start) | ||||||
|  | 	for i := start; i < end; i++ { | ||||||
|  | 		apiFiles = append(apiFiles, convert.ToChangedFile(diff.Files[i], pr.HeadRepo, endCommitID)) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	ctx.SetLinkHeader(totalNumberOfFiles, listOptions.PageSize) | ||||||
|  | 	ctx.SetTotalCountHeader(int64(totalNumberOfFiles)) | ||||||
|  | 
 | ||||||
|  | 	ctx.RespHeader().Set("X-Page", strconv.Itoa(listOptions.Page)) | ||||||
|  | 	ctx.RespHeader().Set("X-PerPage", strconv.Itoa(listOptions.PageSize)) | ||||||
|  | 	ctx.RespHeader().Set("X-PageCount", strconv.Itoa(totalNumberOfPages)) | ||||||
|  | 	ctx.RespHeader().Set("X-HasMore", strconv.FormatBool(listOptions.Page < totalNumberOfPages)) | ||||||
|  | 	ctx.AppendAccessControlExposeHeaders("X-Page", "X-PerPage", "X-PageCount", "X-HasMore") | ||||||
|  | 
 | ||||||
|  | 	ctx.JSON(http.StatusOK, &apiFiles) | ||||||
|  | } | ||||||
|  | |||||||
| @ -254,6 +254,28 @@ type swaggerCommitList struct { | |||||||
| 	Body []api.Commit `json:"body"` | 	Body []api.Commit `json:"body"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // ChangedFileList
 | ||||||
|  | // swagger:response ChangedFileList
 | ||||||
|  | type swaggerChangedFileList struct { | ||||||
|  | 	// The current page
 | ||||||
|  | 	Page int `json:"X-Page"` | ||||||
|  | 
 | ||||||
|  | 	// Commits per page
 | ||||||
|  | 	PerPage int `json:"X-PerPage"` | ||||||
|  | 
 | ||||||
|  | 	// Total commit count
 | ||||||
|  | 	Total int `json:"X-Total"` | ||||||
|  | 
 | ||||||
|  | 	// Total number of pages
 | ||||||
|  | 	PageCount int `json:"X-PageCount"` | ||||||
|  | 
 | ||||||
|  | 	// True if there is another page
 | ||||||
|  | 	HasMore bool `json:"X-HasMore"` | ||||||
|  | 
 | ||||||
|  | 	// in: body
 | ||||||
|  | 	Body []api.ChangedFile `json:"body"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // Note
 | // Note
 | ||||||
| // swagger:response Note
 | // swagger:response Note
 | ||||||
| type swaggerNote struct { | type swaggerNote struct { | ||||||
|  | |||||||
| @ -8019,6 +8019,80 @@ | |||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "/repos/{owner}/{repo}/pulls/{index}/files": { | ||||||
|  |       "get": { | ||||||
|  |         "produces": [ | ||||||
|  |           "application/json" | ||||||
|  |         ], | ||||||
|  |         "tags": [ | ||||||
|  |           "repository" | ||||||
|  |         ], | ||||||
|  |         "summary": "Get changed files for a pull request", | ||||||
|  |         "operationId": "repoGetPullRequestFiles", | ||||||
|  |         "parameters": [ | ||||||
|  |           { | ||||||
|  |             "type": "string", | ||||||
|  |             "description": "owner of the repo", | ||||||
|  |             "name": "owner", | ||||||
|  |             "in": "path", | ||||||
|  |             "required": true | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             "type": "string", | ||||||
|  |             "description": "name of the repo", | ||||||
|  |             "name": "repo", | ||||||
|  |             "in": "path", | ||||||
|  |             "required": true | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             "type": "integer", | ||||||
|  |             "format": "int64", | ||||||
|  |             "description": "index of the pull request to get", | ||||||
|  |             "name": "index", | ||||||
|  |             "in": "path", | ||||||
|  |             "required": true | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             "type": "string", | ||||||
|  |             "description": "skip to given file", | ||||||
|  |             "name": "skip-to", | ||||||
|  |             "in": "query" | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             "enum": [ | ||||||
|  |               "ignore-all", | ||||||
|  |               "ignore-change", | ||||||
|  |               "ignore-eol", | ||||||
|  |               "show-all" | ||||||
|  |             ], | ||||||
|  |             "type": "string", | ||||||
|  |             "description": "whitespace behavior", | ||||||
|  |             "name": "whitespace", | ||||||
|  |             "in": "query" | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             "type": "integer", | ||||||
|  |             "description": "page number of results to return (1-based)", | ||||||
|  |             "name": "page", | ||||||
|  |             "in": "query" | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             "type": "integer", | ||||||
|  |             "description": "page size of results", | ||||||
|  |             "name": "limit", | ||||||
|  |             "in": "query" | ||||||
|  |           } | ||||||
|  |         ], | ||||||
|  |         "responses": { | ||||||
|  |           "200": { | ||||||
|  |             "$ref": "#/responses/ChangedFileList" | ||||||
|  |           }, | ||||||
|  |           "404": { | ||||||
|  |             "$ref": "#/responses/notFound" | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "/repos/{owner}/{repo}/pulls/{index}/merge": { |     "/repos/{owner}/{repo}/pulls/{index}/merge": { | ||||||
|       "get": { |       "get": { | ||||||
|         "produces": [ |         "produces": [ | ||||||
| @ -13715,6 +13789,52 @@ | |||||||
|       }, |       }, | ||||||
|       "x-go-package": "code.gitea.io/gitea/modules/structs" |       "x-go-package": "code.gitea.io/gitea/modules/structs" | ||||||
|     }, |     }, | ||||||
|  |     "ChangedFile": { | ||||||
|  |       "description": "ChangedFile store information about files affected by the pull request", | ||||||
|  |       "type": "object", | ||||||
|  |       "properties": { | ||||||
|  |         "additions": { | ||||||
|  |           "type": "integer", | ||||||
|  |           "format": "int64", | ||||||
|  |           "x-go-name": "Additions" | ||||||
|  |         }, | ||||||
|  |         "changes": { | ||||||
|  |           "type": "integer", | ||||||
|  |           "format": "int64", | ||||||
|  |           "x-go-name": "Changes" | ||||||
|  |         }, | ||||||
|  |         "contents_url": { | ||||||
|  |           "type": "string", | ||||||
|  |           "x-go-name": "ContentsURL" | ||||||
|  |         }, | ||||||
|  |         "deletions": { | ||||||
|  |           "type": "integer", | ||||||
|  |           "format": "int64", | ||||||
|  |           "x-go-name": "Deletions" | ||||||
|  |         }, | ||||||
|  |         "filename": { | ||||||
|  |           "type": "string", | ||||||
|  |           "x-go-name": "Filename" | ||||||
|  |         }, | ||||||
|  |         "html_url": { | ||||||
|  |           "type": "string", | ||||||
|  |           "x-go-name": "HTMLURL" | ||||||
|  |         }, | ||||||
|  |         "previous_filename": { | ||||||
|  |           "type": "string", | ||||||
|  |           "x-go-name": "PreviousFilename" | ||||||
|  |         }, | ||||||
|  |         "raw_url": { | ||||||
|  |           "type": "string", | ||||||
|  |           "x-go-name": "RawURL" | ||||||
|  |         }, | ||||||
|  |         "status": { | ||||||
|  |           "type": "string", | ||||||
|  |           "x-go-name": "Status" | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       "x-go-package": "code.gitea.io/gitea/modules/structs" | ||||||
|  |     }, | ||||||
|     "CombinedStatus": { |     "CombinedStatus": { | ||||||
|       "description": "CombinedStatus holds the combined state of several statuses for a single commit", |       "description": "CombinedStatus holds the combined state of several statuses for a single commit", | ||||||
|       "type": "object", |       "type": "object", | ||||||
| @ -19173,6 +19293,41 @@ | |||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "ChangedFileList": { | ||||||
|  |       "description": "ChangedFileList", | ||||||
|  |       "schema": { | ||||||
|  |         "type": "array", | ||||||
|  |         "items": { | ||||||
|  |           "$ref": "#/definitions/ChangedFile" | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       "headers": { | ||||||
|  |         "X-HasMore": { | ||||||
|  |           "type": "boolean", | ||||||
|  |           "description": "True if there is another page" | ||||||
|  |         }, | ||||||
|  |         "X-Page": { | ||||||
|  |           "type": "integer", | ||||||
|  |           "format": "int64", | ||||||
|  |           "description": "The current page" | ||||||
|  |         }, | ||||||
|  |         "X-PageCount": { | ||||||
|  |           "type": "integer", | ||||||
|  |           "format": "int64", | ||||||
|  |           "description": "Total number of pages" | ||||||
|  |         }, | ||||||
|  |         "X-PerPage": { | ||||||
|  |           "type": "integer", | ||||||
|  |           "format": "int64", | ||||||
|  |           "description": "Commits per page" | ||||||
|  |         }, | ||||||
|  |         "X-Total": { | ||||||
|  |           "type": "integer", | ||||||
|  |           "format": "int64", | ||||||
|  |           "description": "Total commit count" | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "CombinedStatus": { |     "CombinedStatus": { | ||||||
|       "description": "CombinedStatus", |       "description": "CombinedStatus", | ||||||
|       "schema": { |       "schema": { | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ package integration | |||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"io/ioutil" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"testing" | 	"testing" | ||||||
| 
 | 
 | ||||||
| @ -27,15 +28,35 @@ func TestAPIViewPulls(t *testing.T) { | |||||||
| 	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) | 	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) | ||||||
| 	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) | 	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) | ||||||
| 
 | 
 | ||||||
| 	session := loginUser(t, "user2") | 	ctx := NewAPITestContext(t, "user2", repo.Name) | ||||||
| 	token := getTokenForLoggedInUser(t, session) | 
 | ||||||
| 	req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/pulls?state=all&token="+token, owner.Name, repo.Name) | 	req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/pulls?state=all&token="+ctx.Token, owner.Name, repo.Name) | ||||||
| 	resp := session.MakeRequest(t, req, http.StatusOK) | 	resp := ctx.Session.MakeRequest(t, req, http.StatusOK) | ||||||
| 
 | 
 | ||||||
| 	var pulls []*api.PullRequest | 	var pulls []*api.PullRequest | ||||||
| 	DecodeJSON(t, resp, &pulls) | 	DecodeJSON(t, resp, &pulls) | ||||||
| 	expectedLen := unittest.GetCount(t, &issues_model.Issue{RepoID: repo.ID}, unittest.Cond("is_pull = ?", true)) | 	expectedLen := unittest.GetCount(t, &issues_model.Issue{RepoID: repo.ID}, unittest.Cond("is_pull = ?", true)) | ||||||
| 	assert.Len(t, pulls, expectedLen) | 	assert.Len(t, pulls, expectedLen) | ||||||
|  | 
 | ||||||
|  | 	pull := pulls[0] | ||||||
|  | 	if assert.EqualValues(t, 5, pull.ID) { | ||||||
|  | 		resp = ctx.Session.MakeRequest(t, NewRequest(t, "GET", pull.DiffURL), http.StatusOK) | ||||||
|  | 		_, err := ioutil.ReadAll(resp.Body) | ||||||
|  | 		assert.NoError(t, err) | ||||||
|  | 		// TODO: use diff to generate stats to test against
 | ||||||
|  | 
 | ||||||
|  | 		t.Run(fmt.Sprintf("APIGetPullFiles_%d", pull.ID), | ||||||
|  | 			doAPIGetPullFiles(ctx, pull, func(t *testing.T, files []*api.ChangedFile) { | ||||||
|  | 				if assert.Len(t, files, 1) { | ||||||
|  | 					assert.EqualValues(t, "File-WoW", files[0].Filename) | ||||||
|  | 					assert.EqualValues(t, "", files[0].PreviousFilename) | ||||||
|  | 					assert.EqualValues(t, 1, files[0].Additions) | ||||||
|  | 					assert.EqualValues(t, 1, files[0].Changes) | ||||||
|  | 					assert.EqualValues(t, 0, files[0].Deletions) | ||||||
|  | 					assert.EqualValues(t, "added", files[0].Status) | ||||||
|  | 				} | ||||||
|  | 			})) | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // TestAPIMergePullWIP ensures that we can't merge a WIP pull request
 | // TestAPIMergePullWIP ensures that we can't merge a WIP pull request
 | ||||||
| @ -183,3 +204,22 @@ func TestAPIEditPull(t *testing.T) { | |||||||
| 	}) | 	}) | ||||||
| 	session.MakeRequest(t, req, http.StatusNotFound) | 	session.MakeRequest(t, req, http.StatusNotFound) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func doAPIGetPullFiles(ctx APITestContext, pr *api.PullRequest, callback func(*testing.T, []*api.ChangedFile)) func(*testing.T) { | ||||||
|  | 	return func(t *testing.T) { | ||||||
|  | 		url := fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/files?token=%s", ctx.Username, ctx.Reponame, pr.Index, ctx.Token) | ||||||
|  | 
 | ||||||
|  | 		req := NewRequest(t, http.MethodGet, url) | ||||||
|  | 		if ctx.ExpectedCode == 0 { | ||||||
|  | 			ctx.ExpectedCode = http.StatusOK | ||||||
|  | 		} | ||||||
|  | 		resp := ctx.Session.MakeRequest(t, req, ctx.ExpectedCode) | ||||||
|  | 
 | ||||||
|  | 		files := make([]*api.ChangedFile, 0, 1) | ||||||
|  | 		DecodeJSON(t, resp, &files) | ||||||
|  | 
 | ||||||
|  | 		if callback != nil { | ||||||
|  | 			callback(t, files) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user