You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

pull.go 19 kB

11 years ago
10 years ago
11 years ago
11 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package repo
  5. import (
  6. "container/list"
  7. "path"
  8. "strings"
  9. "github.com/Unknwon/com"
  10. "github.com/gogits/git-module"
  11. "github.com/gogits/gogs/models"
  12. "github.com/gogits/gogs/modules/auth"
  13. "github.com/gogits/gogs/modules/base"
  14. "github.com/gogits/gogs/modules/log"
  15. "github.com/gogits/gogs/modules/middleware"
  16. "github.com/gogits/gogs/modules/setting"
  17. )
  18. const (
  19. FORK base.TplName = "repo/pulls/fork"
  20. COMPARE_PULL base.TplName = "repo/pulls/compare"
  21. PULL_COMMITS base.TplName = "repo/pulls/commits"
  22. PULL_FILES base.TplName = "repo/pulls/files"
  23. PULL_REQUEST_TEMPLATE_KEY = "PullRequestTemplate"
  24. )
  25. var (
  26. PullRequestTemplateCandidates = []string{
  27. "PULL_REQUEST.md",
  28. ".gogs/PULL_REQUEST.md",
  29. ".github/PULL_REQUEST.md",
  30. }
  31. )
  32. func getForkRepository(ctx *middleware.Context) *models.Repository {
  33. forkRepo, err := models.GetRepositoryByID(ctx.ParamsInt64(":repoid"))
  34. if err != nil {
  35. if models.IsErrRepoNotExist(err) {
  36. ctx.Handle(404, "GetRepositoryByID", nil)
  37. } else {
  38. ctx.Handle(500, "GetRepositoryByID", err)
  39. }
  40. return nil
  41. }
  42. if !forkRepo.CanBeForked() {
  43. ctx.Handle(404, "getForkRepository", nil)
  44. return nil
  45. }
  46. ctx.Data["repo_name"] = forkRepo.Name
  47. ctx.Data["description"] = forkRepo.Description
  48. ctx.Data["IsPrivate"] = forkRepo.IsPrivate
  49. if err = forkRepo.GetOwner(); err != nil {
  50. ctx.Handle(500, "GetOwner", err)
  51. return nil
  52. }
  53. ctx.Data["ForkFrom"] = forkRepo.Owner.Name + "/" + forkRepo.Name
  54. if err := ctx.User.GetOrganizations(true); err != nil {
  55. ctx.Handle(500, "GetOrganizations", err)
  56. return nil
  57. }
  58. ctx.Data["Orgs"] = ctx.User.Orgs
  59. return forkRepo
  60. }
  61. func Fork(ctx *middleware.Context) {
  62. ctx.Data["Title"] = ctx.Tr("new_fork")
  63. getForkRepository(ctx)
  64. if ctx.Written() {
  65. return
  66. }
  67. ctx.Data["ContextUser"] = ctx.User
  68. ctx.HTML(200, FORK)
  69. }
  70. func ForkPost(ctx *middleware.Context, form auth.CreateRepoForm) {
  71. ctx.Data["Title"] = ctx.Tr("new_fork")
  72. forkRepo := getForkRepository(ctx)
  73. if ctx.Written() {
  74. return
  75. }
  76. ctxUser := checkContextUser(ctx, form.Uid)
  77. if ctx.Written() {
  78. return
  79. }
  80. ctx.Data["ContextUser"] = ctxUser
  81. if ctx.HasError() {
  82. ctx.HTML(200, FORK)
  83. return
  84. }
  85. repo, has := models.HasForkedRepo(ctxUser.Id, forkRepo.ID)
  86. if has {
  87. ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + repo.Name)
  88. return
  89. }
  90. // Check ownership of organization.
  91. if ctxUser.IsOrganization() {
  92. if !ctxUser.IsOwnedBy(ctx.User.Id) {
  93. ctx.Error(403)
  94. return
  95. }
  96. }
  97. repo, err := models.ForkRepository(ctxUser, forkRepo, form.RepoName, form.Description)
  98. if err != nil {
  99. ctx.Data["Err_RepoName"] = true
  100. switch {
  101. case models.IsErrRepoAlreadyExist(err):
  102. ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), FORK, &form)
  103. case models.IsErrNameReserved(err):
  104. ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), FORK, &form)
  105. case models.IsErrNamePatternNotAllowed(err):
  106. ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), FORK, &form)
  107. default:
  108. ctx.Handle(500, "ForkPost", err)
  109. }
  110. return
  111. }
  112. log.Trace("Repository forked[%d]: %s/%s", forkRepo.ID, ctxUser.Name, repo.Name)
  113. ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + repo.Name)
  114. }
  115. func checkPullInfo(ctx *middleware.Context) *models.Issue {
  116. issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
  117. if err != nil {
  118. if models.IsErrIssueNotExist(err) {
  119. ctx.Handle(404, "GetIssueByIndex", err)
  120. } else {
  121. ctx.Handle(500, "GetIssueByIndex", err)
  122. }
  123. return nil
  124. }
  125. ctx.Data["Title"] = issue.Name
  126. ctx.Data["Issue"] = issue
  127. if !issue.IsPull {
  128. ctx.Handle(404, "ViewPullCommits", nil)
  129. return nil
  130. }
  131. if err = issue.GetPoster(); err != nil {
  132. ctx.Handle(500, "GetPoster", err)
  133. return nil
  134. } else if err = issue.GetPullRequest(); err != nil {
  135. ctx.Handle(500, "GetPullRequest", err)
  136. return nil
  137. } else if err = issue.GetHeadRepo(); err != nil {
  138. ctx.Handle(500, "GetHeadRepo", err)
  139. return nil
  140. }
  141. if ctx.IsSigned {
  142. // Update issue-user.
  143. if err = issue.ReadBy(ctx.User.Id); err != nil {
  144. ctx.Handle(500, "ReadBy", err)
  145. return nil
  146. }
  147. }
  148. return issue
  149. }
  150. func PrepareMergedViewPullInfo(ctx *middleware.Context, pull *models.Issue) {
  151. ctx.Data["HasMerged"] = true
  152. var err error
  153. if err = pull.GetMerger(); err != nil {
  154. ctx.Handle(500, "GetMerger", err)
  155. return
  156. }
  157. ctx.Data["HeadTarget"] = pull.HeadUserName + "/" + pull.HeadBranch
  158. ctx.Data["BaseTarget"] = ctx.Repo.Owner.Name + "/" + pull.BaseBranch
  159. ctx.Data["NumCommits"], err = ctx.Repo.GitRepo.CommitsCountBetween(pull.MergeBase, pull.MergedCommitID)
  160. if err != nil {
  161. ctx.Handle(500, "Repo.GitRepo.CommitsCountBetween", err)
  162. return
  163. }
  164. ctx.Data["NumFiles"], err = ctx.Repo.GitRepo.FilesCountBetween(pull.MergeBase, pull.MergedCommitID)
  165. if err != nil {
  166. ctx.Handle(500, "Repo.GitRepo.FilesCountBetween", err)
  167. return
  168. }
  169. }
  170. func PrepareViewPullInfo(ctx *middleware.Context, pull *models.Issue) *git.PullRequestInfo {
  171. repo := ctx.Repo.Repository
  172. ctx.Data["HeadTarget"] = pull.HeadUserName + "/" + pull.HeadBranch
  173. ctx.Data["BaseTarget"] = ctx.Repo.Owner.Name + "/" + pull.BaseBranch
  174. var (
  175. headGitRepo *git.Repository
  176. err error
  177. )
  178. if err = pull.GetHeadRepo(); err != nil {
  179. ctx.Handle(500, "GetHeadRepo", err)
  180. return nil
  181. }
  182. if pull.HeadRepo != nil {
  183. headGitRepo, err = git.OpenRepository(pull.HeadRepo.RepoPath())
  184. if err != nil {
  185. ctx.Handle(500, "OpenRepository", err)
  186. return nil
  187. }
  188. }
  189. if pull.HeadRepo == nil || !headGitRepo.IsBranchExist(pull.HeadBranch) {
  190. ctx.Data["IsPullReuqestBroken"] = true
  191. ctx.Data["HeadTarget"] = "deleted"
  192. ctx.Data["NumCommits"] = 0
  193. ctx.Data["NumFiles"] = 0
  194. return nil
  195. }
  196. prInfo, err := headGitRepo.GetPullRequestInfo(models.RepoPath(repo.Owner.Name, repo.Name),
  197. pull.BaseBranch, pull.HeadBranch)
  198. if err != nil {
  199. ctx.Handle(500, "GetPullRequestInfo", err)
  200. return nil
  201. }
  202. ctx.Data["NumCommits"] = prInfo.Commits.Len()
  203. ctx.Data["NumFiles"] = prInfo.NumFiles
  204. return prInfo
  205. }
  206. func ViewPullCommits(ctx *middleware.Context) {
  207. ctx.Data["PageIsPullCommits"] = true
  208. pull := checkPullInfo(ctx)
  209. if ctx.Written() {
  210. return
  211. }
  212. ctx.Data["Username"] = pull.HeadUserName
  213. ctx.Data["Reponame"] = pull.HeadRepo.Name
  214. var commits *list.List
  215. if pull.HasMerged {
  216. PrepareMergedViewPullInfo(ctx, pull)
  217. if ctx.Written() {
  218. return
  219. }
  220. startCommit, err := ctx.Repo.GitRepo.GetCommit(pull.MergeBase)
  221. if err != nil {
  222. ctx.Handle(500, "Repo.GitRepo.GetCommit", err)
  223. return
  224. }
  225. endCommit, err := ctx.Repo.GitRepo.GetCommit(pull.MergedCommitID)
  226. if err != nil {
  227. ctx.Handle(500, "Repo.GitRepo.GetCommit", err)
  228. return
  229. }
  230. commits, err = ctx.Repo.GitRepo.CommitsBetween(endCommit, startCommit)
  231. if err != nil {
  232. ctx.Handle(500, "Repo.GitRepo.CommitsBetween", err)
  233. return
  234. }
  235. } else {
  236. prInfo := PrepareViewPullInfo(ctx, pull)
  237. if ctx.Written() {
  238. return
  239. } else if prInfo == nil {
  240. ctx.Handle(404, "ViewPullCommits", nil)
  241. return
  242. }
  243. commits = prInfo.Commits
  244. }
  245. commits = models.ValidateCommitsWithEmails(commits)
  246. ctx.Data["Commits"] = commits
  247. ctx.Data["CommitCount"] = commits.Len()
  248. ctx.HTML(200, PULL_COMMITS)
  249. }
  250. func ViewPullFiles(ctx *middleware.Context) {
  251. ctx.Data["PageIsPullFiles"] = true
  252. pull := checkPullInfo(ctx)
  253. if ctx.Written() {
  254. return
  255. }
  256. var (
  257. diffRepoPath string
  258. startCommitID string
  259. endCommitID string
  260. gitRepo *git.Repository
  261. )
  262. if pull.HasMerged {
  263. PrepareMergedViewPullInfo(ctx, pull)
  264. if ctx.Written() {
  265. return
  266. }
  267. diffRepoPath = ctx.Repo.GitRepo.Path
  268. startCommitID = pull.MergeBase
  269. endCommitID = pull.MergedCommitID
  270. gitRepo = ctx.Repo.GitRepo
  271. } else {
  272. prInfo := PrepareViewPullInfo(ctx, pull)
  273. if ctx.Written() {
  274. return
  275. } else if prInfo == nil {
  276. ctx.Handle(404, "ViewPullFiles", nil)
  277. return
  278. }
  279. headRepoPath := models.RepoPath(pull.HeadUserName, pull.HeadRepo.Name)
  280. headGitRepo, err := git.OpenRepository(headRepoPath)
  281. if err != nil {
  282. ctx.Handle(500, "OpenRepository", err)
  283. return
  284. }
  285. headCommitID, err := headGitRepo.GetBranchCommitID(pull.HeadBranch)
  286. if err != nil {
  287. ctx.Handle(500, "GetBranchCommitID", err)
  288. return
  289. }
  290. diffRepoPath = headRepoPath
  291. startCommitID = prInfo.MergeBase
  292. endCommitID = headCommitID
  293. gitRepo = headGitRepo
  294. }
  295. diff, err := models.GetDiffRange(diffRepoPath,
  296. startCommitID, endCommitID, setting.Git.MaxGitDiffLines)
  297. if err != nil {
  298. ctx.Handle(500, "GetDiffRange", err)
  299. return
  300. }
  301. ctx.Data["Diff"] = diff
  302. ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
  303. commit, err := gitRepo.GetCommit(endCommitID)
  304. if err != nil {
  305. ctx.Handle(500, "GetCommit", err)
  306. return
  307. }
  308. headTarget := path.Join(pull.HeadUserName, pull.HeadRepo.Name)
  309. ctx.Data["Username"] = pull.HeadUserName
  310. ctx.Data["Reponame"] = pull.HeadRepo.Name
  311. ctx.Data["IsImageFile"] = commit.IsImageFile
  312. ctx.Data["SourcePath"] = setting.AppSubUrl + "/" + path.Join(headTarget, "src", endCommitID)
  313. ctx.Data["BeforeSourcePath"] = setting.AppSubUrl + "/" + path.Join(headTarget, "src", startCommitID)
  314. ctx.Data["RawPath"] = setting.AppSubUrl + "/" + path.Join(headTarget, "raw", endCommitID)
  315. ctx.Data["RequireHighlightJS"] = true
  316. ctx.HTML(200, PULL_FILES)
  317. }
  318. func MergePullRequest(ctx *middleware.Context) {
  319. issue := checkPullInfo(ctx)
  320. if ctx.Written() {
  321. return
  322. }
  323. if issue.IsClosed {
  324. ctx.Handle(404, "MergePullRequest", nil)
  325. return
  326. }
  327. pr, err := models.GetPullRequestByIssueID(issue.ID)
  328. if err != nil {
  329. if models.IsErrPullRequestNotExist(err) {
  330. ctx.Handle(404, "GetPullRequestByIssueID", nil)
  331. } else {
  332. ctx.Handle(500, "GetPullRequestByIssueID", err)
  333. }
  334. return
  335. }
  336. if !pr.CanAutoMerge() || pr.HasMerged {
  337. ctx.Handle(404, "MergePullRequest", nil)
  338. return
  339. }
  340. pr.Issue = issue
  341. pr.Issue.Repo = ctx.Repo.Repository
  342. if err = pr.Merge(ctx.User, ctx.Repo.GitRepo); err != nil {
  343. ctx.Handle(500, "Merge", err)
  344. return
  345. }
  346. log.Trace("Pull request merged: %d", pr.ID)
  347. ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pr.Index))
  348. }
  349. func ParseCompareInfo(ctx *middleware.Context) (*models.User, *models.Repository, *git.Repository, *git.PullRequestInfo, string, string) {
  350. baseRepo := ctx.Repo.Repository
  351. // Get compared branches information
  352. // format: <base branch>...[<head repo>:]<head branch>
  353. // base<-head: master...head:feature
  354. // same repo: master...feature
  355. infos := strings.Split(ctx.Params("*"), "...")
  356. if len(infos) != 2 {
  357. log.Trace("ParseCompareInfo[%d]: not enough compared branches information %s", baseRepo.ID, infos)
  358. ctx.Handle(404, "CompareAndPullRequest", nil)
  359. return nil, nil, nil, nil, "", ""
  360. }
  361. baseBranch := infos[0]
  362. ctx.Data["BaseBranch"] = baseBranch
  363. var (
  364. headUser *models.User
  365. headBranch string
  366. isSameRepo bool
  367. err error
  368. )
  369. // If there is no head repository, it means pull request between same repository.
  370. headInfos := strings.Split(infos[1], ":")
  371. if len(headInfos) == 1 {
  372. isSameRepo = true
  373. headUser = ctx.Repo.Owner
  374. headBranch = headInfos[0]
  375. } else if len(headInfos) == 2 {
  376. headUser, err = models.GetUserByName(headInfos[0])
  377. if err != nil {
  378. if models.IsErrUserNotExist(err) {
  379. ctx.Handle(404, "GetUserByName", nil)
  380. } else {
  381. ctx.Handle(500, "GetUserByName", err)
  382. }
  383. return nil, nil, nil, nil, "", ""
  384. }
  385. headBranch = headInfos[1]
  386. } else {
  387. ctx.Handle(404, "CompareAndPullRequest", nil)
  388. return nil, nil, nil, nil, "", ""
  389. }
  390. ctx.Data["HeadUser"] = headUser
  391. ctx.Data["HeadBranch"] = headBranch
  392. ctx.Repo.PullRequest.SameRepo = isSameRepo
  393. // Check if base branch is valid.
  394. if !ctx.Repo.GitRepo.IsBranchExist(baseBranch) {
  395. ctx.Handle(404, "IsBranchExist", nil)
  396. return nil, nil, nil, nil, "", ""
  397. }
  398. // Check if current user has fork of repository or in the same repository.
  399. headRepo, has := models.HasForkedRepo(headUser.Id, baseRepo.ID)
  400. if !has && !isSameRepo {
  401. log.Trace("ParseCompareInfo[%d]: does not have fork or in same repository", baseRepo.ID)
  402. ctx.Handle(404, "ParseCompareInfo", nil)
  403. return nil, nil, nil, nil, "", ""
  404. }
  405. var headGitRepo *git.Repository
  406. if isSameRepo {
  407. headRepo = ctx.Repo.Repository
  408. headGitRepo = ctx.Repo.GitRepo
  409. } else {
  410. headGitRepo, err = git.OpenRepository(models.RepoPath(headUser.Name, headRepo.Name))
  411. if err != nil {
  412. ctx.Handle(500, "OpenRepository", err)
  413. return nil, nil, nil, nil, "", ""
  414. }
  415. }
  416. if !ctx.User.IsWriterOfRepo(headRepo) && !ctx.User.IsAdmin {
  417. log.Trace("ParseCompareInfo[%d]: does not have write access or site admin", baseRepo.ID)
  418. ctx.Handle(404, "ParseCompareInfo", nil)
  419. return nil, nil, nil, nil, "", ""
  420. }
  421. // Check if head branch is valid.
  422. if !headGitRepo.IsBranchExist(headBranch) {
  423. ctx.Handle(404, "IsBranchExist", nil)
  424. return nil, nil, nil, nil, "", ""
  425. }
  426. headBranches, err := headGitRepo.GetBranches()
  427. if err != nil {
  428. ctx.Handle(500, "GetBranches", err)
  429. return nil, nil, nil, nil, "", ""
  430. }
  431. ctx.Data["HeadBranches"] = headBranches
  432. prInfo, err := headGitRepo.GetPullRequestInfo(models.RepoPath(baseRepo.Owner.Name, baseRepo.Name), baseBranch, headBranch)
  433. if err != nil {
  434. ctx.Handle(500, "GetPullRequestInfo", err)
  435. return nil, nil, nil, nil, "", ""
  436. }
  437. ctx.Data["BeforeCommitID"] = prInfo.MergeBase
  438. return headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch
  439. }
  440. func PrepareCompareDiff(
  441. ctx *middleware.Context,
  442. headUser *models.User,
  443. headRepo *models.Repository,
  444. headGitRepo *git.Repository,
  445. prInfo *git.PullRequestInfo,
  446. baseBranch, headBranch string) bool {
  447. var (
  448. repo = ctx.Repo.Repository
  449. err error
  450. )
  451. // Get diff information.
  452. ctx.Data["CommitRepoLink"] = headRepo.RepoLink()
  453. headCommitID, err := headGitRepo.GetBranchCommitID(headBranch)
  454. if err != nil {
  455. ctx.Handle(500, "GetBranchCommitID", err)
  456. return false
  457. }
  458. ctx.Data["AfterCommitID"] = headCommitID
  459. if headCommitID == prInfo.MergeBase {
  460. ctx.Data["IsNothingToCompare"] = true
  461. return true
  462. }
  463. diff, err := models.GetDiffRange(models.RepoPath(headUser.Name, headRepo.Name),
  464. prInfo.MergeBase, headCommitID, setting.Git.MaxGitDiffLines)
  465. if err != nil {
  466. ctx.Handle(500, "GetDiffRange", err)
  467. return false
  468. }
  469. ctx.Data["Diff"] = diff
  470. ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
  471. headCommit, err := headGitRepo.GetCommit(headCommitID)
  472. if err != nil {
  473. ctx.Handle(500, "GetCommit", err)
  474. return false
  475. }
  476. prInfo.Commits = models.ValidateCommitsWithEmails(prInfo.Commits)
  477. ctx.Data["Commits"] = prInfo.Commits
  478. ctx.Data["CommitCount"] = prInfo.Commits.Len()
  479. ctx.Data["Username"] = headUser.Name
  480. ctx.Data["Reponame"] = headRepo.Name
  481. ctx.Data["IsImageFile"] = headCommit.IsImageFile
  482. headTarget := path.Join(headUser.Name, repo.Name)
  483. ctx.Data["SourcePath"] = setting.AppSubUrl + "/" + path.Join(headTarget, "src", headCommitID)
  484. ctx.Data["BeforeSourcePath"] = setting.AppSubUrl + "/" + path.Join(headTarget, "src", prInfo.MergeBase)
  485. ctx.Data["RawPath"] = setting.AppSubUrl + "/" + path.Join(headTarget, "raw", headCommitID)
  486. return false
  487. }
  488. func CompareAndPullRequest(ctx *middleware.Context) {
  489. ctx.Data["Title"] = ctx.Tr("repo.pulls.compare_changes")
  490. ctx.Data["PageIsComparePull"] = true
  491. ctx.Data["IsDiffCompare"] = true
  492. ctx.Data["RequireHighlightJS"] = true
  493. setTemplateIfExists(ctx, PULL_REQUEST_TEMPLATE_KEY, PullRequestTemplateCandidates)
  494. renderAttachmentSettings(ctx)
  495. headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch := ParseCompareInfo(ctx)
  496. if ctx.Written() {
  497. return
  498. }
  499. pr, err := models.GetUnmergedPullRequest(headRepo.ID, ctx.Repo.Repository.ID, headBranch, baseBranch)
  500. if err != nil {
  501. if !models.IsErrPullRequestNotExist(err) {
  502. ctx.Handle(500, "GetUnmergedPullRequest", err)
  503. return
  504. }
  505. } else {
  506. ctx.Data["HasPullRequest"] = true
  507. ctx.Data["PullRequest"] = pr
  508. ctx.HTML(200, COMPARE_PULL)
  509. return
  510. }
  511. nothingToCompare := PrepareCompareDiff(ctx, headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch)
  512. if ctx.Written() {
  513. return
  514. }
  515. if !nothingToCompare {
  516. // Setup information for new form.
  517. RetrieveRepoMetas(ctx, ctx.Repo.Repository)
  518. if ctx.Written() {
  519. return
  520. }
  521. }
  522. ctx.HTML(200, COMPARE_PULL)
  523. }
  524. func CompareAndPullRequestPost(ctx *middleware.Context, form auth.CreateIssueForm) {
  525. ctx.Data["Title"] = ctx.Tr("repo.pulls.compare_changes")
  526. ctx.Data["PageIsComparePull"] = true
  527. ctx.Data["IsDiffCompare"] = true
  528. renderAttachmentSettings(ctx)
  529. var (
  530. repo = ctx.Repo.Repository
  531. attachments []string
  532. )
  533. headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch := ParseCompareInfo(ctx)
  534. if ctx.Written() {
  535. return
  536. }
  537. patch, err := headGitRepo.GetPatch(prInfo.MergeBase, headBranch)
  538. if err != nil {
  539. ctx.Handle(500, "GetPatch", err)
  540. return
  541. }
  542. labelIDs, milestoneID, assigneeID := ValidateRepoMetas(ctx, form)
  543. if ctx.Written() {
  544. return
  545. }
  546. if setting.AttachmentEnabled {
  547. attachments = form.Attachments
  548. }
  549. if ctx.HasError() {
  550. ctx.HTML(200, COMPARE_PULL)
  551. return
  552. }
  553. pullIssue := &models.Issue{
  554. RepoID: repo.ID,
  555. Index: repo.NextIssueIndex(),
  556. Name: form.Title,
  557. PosterID: ctx.User.Id,
  558. Poster: ctx.User,
  559. MilestoneID: milestoneID,
  560. AssigneeID: assigneeID,
  561. IsPull: true,
  562. Content: form.Content,
  563. }
  564. pullRequest := &models.PullRequest{
  565. HeadRepoID: headRepo.ID,
  566. BaseRepoID: repo.ID,
  567. HeadUserName: headUser.Name,
  568. HeadBranch: headBranch,
  569. BaseBranch: baseBranch,
  570. HeadRepo: headRepo,
  571. BaseRepo: repo,
  572. MergeBase: prInfo.MergeBase,
  573. Type: models.PULL_REQUEST_GOGS,
  574. }
  575. if err := models.NewPullRequest(repo, pullIssue, labelIDs, attachments, pullRequest, patch); err != nil {
  576. ctx.Handle(500, "NewPullRequest", err)
  577. return
  578. } else if err := pullRequest.PushToBaseRepo(); err != nil {
  579. ctx.Handle(500, "PushToBaseRepo", err)
  580. return
  581. }
  582. notifyWatchersAndMentions(ctx, pullIssue)
  583. if ctx.Written() {
  584. return
  585. }
  586. log.Trace("Pull request created: %d/%d", repo.ID, pullIssue.ID)
  587. ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pullIssue.Index))
  588. }
  589. func TriggerTask(ctx *middleware.Context) {
  590. branch := ctx.Query("branch")
  591. secret := ctx.Query("secret")
  592. if len(branch) == 0 || len(secret) == 0 {
  593. ctx.Error(404)
  594. log.Trace("TriggerTask: branch or secret is empty")
  595. return
  596. }
  597. owner, repo := parseOwnerAndRepo(ctx)
  598. if ctx.Written() {
  599. return
  600. }
  601. if secret != base.EncodeMD5(owner.Salt) {
  602. ctx.Error(404)
  603. log.Trace("TriggerTask [%s/%s]: invalid secret", owner.Name, repo.Name)
  604. return
  605. }
  606. log.Trace("TriggerTask [%d].(new request): %s", repo.ID, branch)
  607. go models.HookQueue.Add(repo.ID)
  608. go models.AddTestPullRequestTask(repo.ID, branch)
  609. ctx.Status(202)
  610. }