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