pull.go 19 KB

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