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
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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722
  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/context"
  15. "github.com/gogits/gogs/modules/log"
  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 *context.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 *context.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 *context.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 *context.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.GetPullRequest(); err != nil {
  132. ctx.Handle(500, "GetPullRequest", err)
  133. return nil
  134. } else if err = issue.GetHeadRepo(); err != nil {
  135. ctx.Handle(500, "GetHeadRepo", err)
  136. return nil
  137. }
  138. if ctx.IsSigned {
  139. // Update issue-user.
  140. if err = issue.ReadBy(ctx.User.ID); err != nil {
  141. ctx.Handle(500, "ReadBy", err)
  142. return nil
  143. }
  144. }
  145. return issue
  146. }
  147. func PrepareMergedViewPullInfo(ctx *context.Context, pull *models.Issue) {
  148. ctx.Data["HasMerged"] = true
  149. var err error
  150. if err = pull.GetMerger(); err != nil {
  151. ctx.Handle(500, "GetMerger", err)
  152. return
  153. }
  154. ctx.Data["HeadTarget"] = pull.HeadUserName + "/" + pull.HeadBranch
  155. ctx.Data["BaseTarget"] = ctx.Repo.Owner.Name + "/" + pull.BaseBranch
  156. ctx.Data["NumCommits"], err = ctx.Repo.GitRepo.CommitsCountBetween(pull.MergeBase, pull.MergedCommitID)
  157. if err != nil {
  158. ctx.Handle(500, "Repo.GitRepo.CommitsCountBetween", err)
  159. return
  160. }
  161. ctx.Data["NumFiles"], err = ctx.Repo.GitRepo.FilesCountBetween(pull.MergeBase, pull.MergedCommitID)
  162. if err != nil {
  163. ctx.Handle(500, "Repo.GitRepo.FilesCountBetween", err)
  164. return
  165. }
  166. }
  167. func PrepareViewPullInfo(ctx *context.Context, pull *models.Issue) *git.PullRequestInfo {
  168. repo := ctx.Repo.Repository
  169. ctx.Data["HeadTarget"] = pull.HeadUserName + "/" + pull.HeadBranch
  170. ctx.Data["BaseTarget"] = ctx.Repo.Owner.Name + "/" + pull.BaseBranch
  171. var (
  172. headGitRepo *git.Repository
  173. err error
  174. )
  175. if err = pull.GetHeadRepo(); err != nil {
  176. ctx.Handle(500, "GetHeadRepo", err)
  177. return nil
  178. }
  179. if pull.HeadRepo != nil {
  180. headGitRepo, err = git.OpenRepository(pull.HeadRepo.RepoPath())
  181. if err != nil {
  182. ctx.Handle(500, "OpenRepository", err)
  183. return nil
  184. }
  185. }
  186. if pull.HeadRepo == nil || !headGitRepo.IsBranchExist(pull.HeadBranch) {
  187. ctx.Data["IsPullReuqestBroken"] = true
  188. ctx.Data["HeadTarget"] = "deleted"
  189. ctx.Data["NumCommits"] = 0
  190. ctx.Data["NumFiles"] = 0
  191. return nil
  192. }
  193. prInfo, err := headGitRepo.GetPullRequestInfo(models.RepoPath(repo.Owner.Name, repo.Name),
  194. pull.BaseBranch, pull.HeadBranch)
  195. if err != nil {
  196. if strings.Contains(err.Error(), "fatal: Not a valid object name") {
  197. ctx.Data["IsPullReuqestBroken"] = true
  198. ctx.Data["BaseTarget"] = "deleted"
  199. ctx.Data["NumCommits"] = 0
  200. ctx.Data["NumFiles"] = 0
  201. return nil
  202. }
  203. ctx.Handle(500, "GetPullRequestInfo", err)
  204. return nil
  205. }
  206. ctx.Data["NumCommits"] = prInfo.Commits.Len()
  207. ctx.Data["NumFiles"] = prInfo.NumFiles
  208. return prInfo
  209. }
  210. func ViewPullCommits(ctx *context.Context) {
  211. ctx.Data["PageIsPullCommits"] = true
  212. pull := checkPullInfo(ctx)
  213. if ctx.Written() {
  214. return
  215. }
  216. ctx.Data["Username"] = pull.HeadUserName
  217. ctx.Data["Reponame"] = pull.HeadRepo.Name
  218. var commits *list.List
  219. if pull.HasMerged {
  220. PrepareMergedViewPullInfo(ctx, pull)
  221. if ctx.Written() {
  222. return
  223. }
  224. startCommit, err := ctx.Repo.GitRepo.GetCommit(pull.MergeBase)
  225. if err != nil {
  226. ctx.Handle(500, "Repo.GitRepo.GetCommit", err)
  227. return
  228. }
  229. endCommit, err := ctx.Repo.GitRepo.GetCommit(pull.MergedCommitID)
  230. if err != nil {
  231. ctx.Handle(500, "Repo.GitRepo.GetCommit", err)
  232. return
  233. }
  234. commits, err = ctx.Repo.GitRepo.CommitsBetween(endCommit, startCommit)
  235. if err != nil {
  236. ctx.Handle(500, "Repo.GitRepo.CommitsBetween", err)
  237. return
  238. }
  239. } else {
  240. prInfo := PrepareViewPullInfo(ctx, pull)
  241. if ctx.Written() {
  242. return
  243. } else if prInfo == nil {
  244. ctx.Handle(404, "ViewPullCommits", nil)
  245. return
  246. }
  247. commits = prInfo.Commits
  248. }
  249. commits = models.ValidateCommitsWithEmails(commits)
  250. ctx.Data["Commits"] = commits
  251. ctx.Data["CommitCount"] = commits.Len()
  252. ctx.HTML(200, PULL_COMMITS)
  253. }
  254. func ViewPullFiles(ctx *context.Context) {
  255. ctx.Data["PageIsPullFiles"] = true
  256. pull := checkPullInfo(ctx)
  257. if ctx.Written() {
  258. return
  259. }
  260. var (
  261. diffRepoPath string
  262. startCommitID string
  263. endCommitID string
  264. gitRepo *git.Repository
  265. )
  266. if pull.HasMerged {
  267. PrepareMergedViewPullInfo(ctx, pull)
  268. if ctx.Written() {
  269. return
  270. }
  271. diffRepoPath = ctx.Repo.GitRepo.Path
  272. startCommitID = pull.MergeBase
  273. endCommitID = pull.MergedCommitID
  274. gitRepo = ctx.Repo.GitRepo
  275. } else {
  276. prInfo := PrepareViewPullInfo(ctx, pull)
  277. if ctx.Written() {
  278. return
  279. } else if prInfo == nil {
  280. ctx.Handle(404, "ViewPullFiles", nil)
  281. return
  282. }
  283. headRepoPath := models.RepoPath(pull.HeadUserName, pull.HeadRepo.Name)
  284. headGitRepo, err := git.OpenRepository(headRepoPath)
  285. if err != nil {
  286. ctx.Handle(500, "OpenRepository", err)
  287. return
  288. }
  289. headCommitID, err := headGitRepo.GetBranchCommitID(pull.HeadBranch)
  290. if err != nil {
  291. ctx.Handle(500, "GetBranchCommitID", err)
  292. return
  293. }
  294. diffRepoPath = headRepoPath
  295. startCommitID = prInfo.MergeBase
  296. endCommitID = headCommitID
  297. gitRepo = headGitRepo
  298. }
  299. diff, err := models.GetDiffRange(diffRepoPath,
  300. startCommitID, endCommitID, setting.Git.MaxGitDiffLines,
  301. setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles)
  302. if err != nil {
  303. ctx.Handle(500, "GetDiffRange", err)
  304. return
  305. }
  306. ctx.Data["Diff"] = diff
  307. ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
  308. commit, err := gitRepo.GetCommit(endCommitID)
  309. if err != nil {
  310. ctx.Handle(500, "GetCommit", err)
  311. return
  312. }
  313. headTarget := path.Join(pull.HeadUserName, pull.HeadRepo.Name)
  314. ctx.Data["IsSplitStyle"] = ctx.Query("style") == "split"
  315. ctx.Data["Username"] = pull.HeadUserName
  316. ctx.Data["Reponame"] = pull.HeadRepo.Name
  317. ctx.Data["IsImageFile"] = commit.IsImageFile
  318. ctx.Data["SourcePath"] = setting.AppSubUrl + "/" + path.Join(headTarget, "src", endCommitID)
  319. ctx.Data["BeforeSourcePath"] = setting.AppSubUrl + "/" + path.Join(headTarget, "src", startCommitID)
  320. ctx.Data["RawPath"] = setting.AppSubUrl + "/" + path.Join(headTarget, "raw", endCommitID)
  321. ctx.Data["RequireHighlightJS"] = true
  322. ctx.HTML(200, PULL_FILES)
  323. }
  324. func MergePullRequest(ctx *context.Context) {
  325. issue := checkPullInfo(ctx)
  326. if ctx.Written() {
  327. return
  328. }
  329. if issue.IsClosed {
  330. ctx.Handle(404, "MergePullRequest", nil)
  331. return
  332. }
  333. pr, err := models.GetPullRequestByIssueID(issue.ID)
  334. if err != nil {
  335. if models.IsErrPullRequestNotExist(err) {
  336. ctx.Handle(404, "GetPullRequestByIssueID", nil)
  337. } else {
  338. ctx.Handle(500, "GetPullRequestByIssueID", err)
  339. }
  340. return
  341. }
  342. if !pr.CanAutoMerge() || pr.HasMerged {
  343. ctx.Handle(404, "MergePullRequest", nil)
  344. return
  345. }
  346. pr.Issue = issue
  347. pr.Issue.Repo = ctx.Repo.Repository
  348. if err = pr.Merge(ctx.User, ctx.Repo.GitRepo); err != nil {
  349. ctx.Handle(500, "Merge", err)
  350. return
  351. }
  352. log.Trace("Pull request merged: %d", pr.ID)
  353. ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pr.Index))
  354. }
  355. func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *git.Repository, *git.PullRequestInfo, string, string) {
  356. baseRepo := ctx.Repo.Repository
  357. // Get compared branches information
  358. // format: <base branch>...[<head repo>:]<head branch>
  359. // base<-head: master...head:feature
  360. // same repo: master...feature
  361. infos := strings.Split(ctx.Params("*"), "...")
  362. if len(infos) != 2 {
  363. log.Trace("ParseCompareInfo[%d]: not enough compared branches information %s", baseRepo.ID, infos)
  364. ctx.Handle(404, "CompareAndPullRequest", nil)
  365. return nil, nil, nil, nil, "", ""
  366. }
  367. baseBranch := infos[0]
  368. ctx.Data["BaseBranch"] = baseBranch
  369. var (
  370. headUser *models.User
  371. headBranch string
  372. isSameRepo bool
  373. err error
  374. )
  375. // If there is no head repository, it means pull request between same repository.
  376. headInfos := strings.Split(infos[1], ":")
  377. if len(headInfos) == 1 {
  378. isSameRepo = true
  379. headUser = ctx.Repo.Owner
  380. headBranch = headInfos[0]
  381. } else if len(headInfos) == 2 {
  382. headUser, err = models.GetUserByName(headInfos[0])
  383. if err != nil {
  384. if models.IsErrUserNotExist(err) {
  385. ctx.Handle(404, "GetUserByName", nil)
  386. } else {
  387. ctx.Handle(500, "GetUserByName", err)
  388. }
  389. return nil, nil, nil, nil, "", ""
  390. }
  391. headBranch = headInfos[1]
  392. } else {
  393. ctx.Handle(404, "CompareAndPullRequest", nil)
  394. return nil, nil, nil, nil, "", ""
  395. }
  396. ctx.Data["HeadUser"] = headUser
  397. ctx.Data["HeadBranch"] = headBranch
  398. ctx.Repo.PullRequest.SameRepo = isSameRepo
  399. // Check if base branch is valid.
  400. if !ctx.Repo.GitRepo.IsBranchExist(baseBranch) {
  401. ctx.Handle(404, "IsBranchExist", nil)
  402. return nil, nil, nil, nil, "", ""
  403. }
  404. // Check if current user has fork of repository or in the same repository.
  405. headRepo, has := models.HasForkedRepo(headUser.ID, baseRepo.ID)
  406. if !has && !isSameRepo {
  407. log.Trace("ParseCompareInfo[%d]: does not have fork or in same repository", baseRepo.ID)
  408. ctx.Handle(404, "ParseCompareInfo", nil)
  409. return nil, nil, nil, nil, "", ""
  410. }
  411. var headGitRepo *git.Repository
  412. if isSameRepo {
  413. headRepo = ctx.Repo.Repository
  414. headGitRepo = ctx.Repo.GitRepo
  415. } else {
  416. headGitRepo, err = git.OpenRepository(models.RepoPath(headUser.Name, headRepo.Name))
  417. if err != nil {
  418. ctx.Handle(500, "OpenRepository", err)
  419. return nil, nil, nil, nil, "", ""
  420. }
  421. }
  422. if !ctx.User.IsWriterOfRepo(headRepo) && !ctx.User.IsAdmin {
  423. log.Trace("ParseCompareInfo[%d]: does not have write access or site admin", baseRepo.ID)
  424. ctx.Handle(404, "ParseCompareInfo", nil)
  425. return nil, nil, nil, nil, "", ""
  426. }
  427. // Check if head branch is valid.
  428. if !headGitRepo.IsBranchExist(headBranch) {
  429. ctx.Handle(404, "IsBranchExist", nil)
  430. return nil, nil, nil, nil, "", ""
  431. }
  432. headBranches, err := headGitRepo.GetBranches()
  433. if err != nil {
  434. ctx.Handle(500, "GetBranches", err)
  435. return nil, nil, nil, nil, "", ""
  436. }
  437. ctx.Data["HeadBranches"] = headBranches
  438. prInfo, err := headGitRepo.GetPullRequestInfo(models.RepoPath(baseRepo.Owner.Name, baseRepo.Name), baseBranch, headBranch)
  439. if err != nil {
  440. ctx.Handle(500, "GetPullRequestInfo", err)
  441. return nil, nil, nil, nil, "", ""
  442. }
  443. ctx.Data["BeforeCommitID"] = prInfo.MergeBase
  444. return headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch
  445. }
  446. func PrepareCompareDiff(
  447. ctx *context.Context,
  448. headUser *models.User,
  449. headRepo *models.Repository,
  450. headGitRepo *git.Repository,
  451. prInfo *git.PullRequestInfo,
  452. baseBranch, headBranch string) bool {
  453. var (
  454. repo = ctx.Repo.Repository
  455. err error
  456. )
  457. // Get diff information.
  458. ctx.Data["CommitRepoLink"] = headRepo.Link()
  459. headCommitID, err := headGitRepo.GetBranchCommitID(headBranch)
  460. if err != nil {
  461. ctx.Handle(500, "GetBranchCommitID", err)
  462. return false
  463. }
  464. ctx.Data["AfterCommitID"] = headCommitID
  465. if headCommitID == prInfo.MergeBase {
  466. ctx.Data["IsNothingToCompare"] = true
  467. return true
  468. }
  469. diff, err := models.GetDiffRange(models.RepoPath(headUser.Name, headRepo.Name),
  470. prInfo.MergeBase, headCommitID, setting.Git.MaxGitDiffLines,
  471. setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles)
  472. if err != nil {
  473. ctx.Handle(500, "GetDiffRange", err)
  474. return false
  475. }
  476. ctx.Data["Diff"] = diff
  477. ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
  478. headCommit, err := headGitRepo.GetCommit(headCommitID)
  479. if err != nil {
  480. ctx.Handle(500, "GetCommit", err)
  481. return false
  482. }
  483. prInfo.Commits = models.ValidateCommitsWithEmails(prInfo.Commits)
  484. ctx.Data["Commits"] = prInfo.Commits
  485. ctx.Data["CommitCount"] = prInfo.Commits.Len()
  486. ctx.Data["Username"] = headUser.Name
  487. ctx.Data["Reponame"] = headRepo.Name
  488. ctx.Data["IsImageFile"] = headCommit.IsImageFile
  489. headTarget := path.Join(headUser.Name, repo.Name)
  490. ctx.Data["SourcePath"] = setting.AppSubUrl + "/" + path.Join(headTarget, "src", headCommitID)
  491. ctx.Data["BeforeSourcePath"] = setting.AppSubUrl + "/" + path.Join(headTarget, "src", prInfo.MergeBase)
  492. ctx.Data["RawPath"] = setting.AppSubUrl + "/" + path.Join(headTarget, "raw", headCommitID)
  493. return false
  494. }
  495. func CompareAndPullRequest(ctx *context.Context) {
  496. ctx.Data["Title"] = ctx.Tr("repo.pulls.compare_changes")
  497. ctx.Data["PageIsComparePull"] = true
  498. ctx.Data["IsDiffCompare"] = true
  499. ctx.Data["RequireHighlightJS"] = true
  500. setTemplateIfExists(ctx, PULL_REQUEST_TEMPLATE_KEY, PullRequestTemplateCandidates)
  501. renderAttachmentSettings(ctx)
  502. headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch := ParseCompareInfo(ctx)
  503. if ctx.Written() {
  504. return
  505. }
  506. pr, err := models.GetUnmergedPullRequest(headRepo.ID, ctx.Repo.Repository.ID, headBranch, baseBranch)
  507. if err != nil {
  508. if !models.IsErrPullRequestNotExist(err) {
  509. ctx.Handle(500, "GetUnmergedPullRequest", err)
  510. return
  511. }
  512. } else {
  513. ctx.Data["HasPullRequest"] = true
  514. ctx.Data["PullRequest"] = pr
  515. ctx.HTML(200, COMPARE_PULL)
  516. return
  517. }
  518. nothingToCompare := PrepareCompareDiff(ctx, headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch)
  519. if ctx.Written() {
  520. return
  521. }
  522. if !nothingToCompare {
  523. // Setup information for new form.
  524. RetrieveRepoMetas(ctx, ctx.Repo.Repository)
  525. if ctx.Written() {
  526. return
  527. }
  528. }
  529. ctx.HTML(200, COMPARE_PULL)
  530. }
  531. func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm) {
  532. ctx.Data["Title"] = ctx.Tr("repo.pulls.compare_changes")
  533. ctx.Data["PageIsComparePull"] = true
  534. ctx.Data["IsDiffCompare"] = true
  535. renderAttachmentSettings(ctx)
  536. var (
  537. repo = ctx.Repo.Repository
  538. attachments []string
  539. )
  540. headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch := ParseCompareInfo(ctx)
  541. if ctx.Written() {
  542. return
  543. }
  544. patch, err := headGitRepo.GetPatch(prInfo.MergeBase, headBranch)
  545. if err != nil {
  546. ctx.Handle(500, "GetPatch", err)
  547. return
  548. }
  549. labelIDs, milestoneID, assigneeID := ValidateRepoMetas(ctx, form)
  550. if ctx.Written() {
  551. return
  552. }
  553. if setting.AttachmentEnabled {
  554. attachments = form.Attachments
  555. }
  556. if ctx.HasError() {
  557. ctx.HTML(200, COMPARE_PULL)
  558. return
  559. }
  560. pullIssue := &models.Issue{
  561. RepoID: repo.ID,
  562. Index: repo.NextIssueIndex(),
  563. Name: form.Title,
  564. PosterID: ctx.User.ID,
  565. Poster: ctx.User,
  566. MilestoneID: milestoneID,
  567. AssigneeID: assigneeID,
  568. IsPull: true,
  569. Content: form.Content,
  570. }
  571. pullRequest := &models.PullRequest{
  572. HeadRepoID: headRepo.ID,
  573. BaseRepoID: repo.ID,
  574. HeadUserName: headUser.Name,
  575. HeadBranch: headBranch,
  576. BaseBranch: baseBranch,
  577. HeadRepo: headRepo,
  578. BaseRepo: repo,
  579. MergeBase: prInfo.MergeBase,
  580. Type: models.PULL_REQUEST_GOGS,
  581. }
  582. if err := models.NewPullRequest(repo, pullIssue, labelIDs, attachments, pullRequest, patch); err != nil {
  583. ctx.Handle(500, "NewPullRequest", err)
  584. return
  585. } else if err := pullRequest.PushToBaseRepo(); err != nil {
  586. ctx.Handle(500, "PushToBaseRepo", err)
  587. return
  588. }
  589. log.Trace("Pull request created: %d/%d", repo.ID, pullIssue.ID)
  590. ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pullIssue.Index))
  591. }
  592. func TriggerTask(ctx *context.Context) {
  593. branch := ctx.Query("branch")
  594. secret := ctx.Query("secret")
  595. if len(branch) == 0 || len(secret) == 0 {
  596. ctx.Error(404)
  597. log.Trace("TriggerTask: branch or secret is empty")
  598. return
  599. }
  600. owner, repo := parseOwnerAndRepo(ctx)
  601. if ctx.Written() {
  602. return
  603. }
  604. if secret != base.EncodeMD5(owner.Salt) {
  605. ctx.Error(404)
  606. log.Trace("TriggerTask [%s/%s]: invalid secret", owner.Name, repo.Name)
  607. return
  608. }
  609. log.Trace("TriggerTask [%d].(new request): %s", repo.ID, branch)
  610. go models.HookQueue.Add(repo.ID)
  611. go models.AddTestPullRequestTask(repo.ID, branch)
  612. ctx.Status(202)
  613. }