commits.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. // Copyright 2018 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. "net/http"
  7. "strings"
  8. "time"
  9. "github.com/gogs/git-module"
  10. api "github.com/gogs/go-gogs-client"
  11. "gogs.io/gogs/internal/conf"
  12. "gogs.io/gogs/internal/context"
  13. "gogs.io/gogs/internal/database"
  14. "gogs.io/gogs/internal/gitutil"
  15. )
  16. // GetAllCommits returns a slice of commits starting from HEAD.
  17. func GetAllCommits(c *context.APIContext) {
  18. // Get pagesize, set default if it is not specified.
  19. pageSize := c.QueryInt("pageSize")
  20. if pageSize == 0 {
  21. pageSize = 30
  22. }
  23. gitRepo, err := git.Open(c.Repo.Repository.RepoPath())
  24. if err != nil {
  25. c.Error(err, "open repository")
  26. return
  27. }
  28. // The response object returned as JSON
  29. result := make([]*api.Commit, 0, pageSize)
  30. commits, err := gitRepo.Log("HEAD", git.LogOptions{MaxCount: pageSize})
  31. if err != nil {
  32. c.Error(err, "git log")
  33. }
  34. for _, commit := range commits {
  35. apiCommit, err := gitCommitToAPICommit(commit, c)
  36. if err != nil {
  37. c.Error(err, "convert git commit to api commit")
  38. return
  39. }
  40. result = append(result, apiCommit)
  41. }
  42. c.JSONSuccess(result)
  43. }
  44. // GetSingleCommit will return a single Commit object based on the specified SHA.
  45. func GetSingleCommit(c *context.APIContext) {
  46. if strings.Contains(c.Req.Header.Get("Accept"), api.MediaApplicationSHA) {
  47. c.SetParams("*", c.Params(":sha"))
  48. GetReferenceSHA(c)
  49. return
  50. }
  51. gitRepo, err := git.Open(c.Repo.Repository.RepoPath())
  52. if err != nil {
  53. c.Error(err, "open repository")
  54. return
  55. }
  56. commit, err := gitRepo.CatFileCommit(c.Params(":sha"))
  57. if err != nil {
  58. c.NotFoundOrError(gitutil.NewError(err), "get commit")
  59. return
  60. }
  61. apiCommit, err := gitCommitToAPICommit(commit, c)
  62. if err != nil {
  63. c.Error(err, "convert git commit to api commit")
  64. }
  65. c.JSONSuccess(apiCommit)
  66. }
  67. func GetReferenceSHA(c *context.APIContext) {
  68. gitRepo, err := git.Open(c.Repo.Repository.RepoPath())
  69. if err != nil {
  70. c.Error(err, "open repository")
  71. return
  72. }
  73. ref := c.Params("*")
  74. refType := 0 // 0-unknown, 1-branch, 2-tag
  75. if strings.HasPrefix(ref, git.RefsHeads) {
  76. ref = strings.TrimPrefix(ref, git.RefsHeads)
  77. refType = 1
  78. } else if strings.HasPrefix(ref, git.RefsTags) {
  79. ref = strings.TrimPrefix(ref, git.RefsTags)
  80. refType = 2
  81. } else {
  82. if gitRepo.HasBranch(ref) {
  83. refType = 1
  84. } else if gitRepo.HasTag(ref) {
  85. refType = 2
  86. } else {
  87. c.NotFound()
  88. return
  89. }
  90. }
  91. var sha string
  92. if refType == 1 {
  93. sha, err = gitRepo.BranchCommitID(ref)
  94. } else if refType == 2 {
  95. sha, err = gitRepo.TagCommitID(ref)
  96. }
  97. if err != nil {
  98. c.NotFoundOrError(gitutil.NewError(err), "get reference commit ID")
  99. return
  100. }
  101. c.PlainText(http.StatusOK, sha)
  102. }
  103. // gitCommitToApiCommit is a helper function to convert git commit object to API commit.
  104. func gitCommitToAPICommit(commit *git.Commit, c *context.APIContext) (*api.Commit, error) {
  105. // Retrieve author and committer information
  106. var apiAuthor, apiCommitter *api.User
  107. author, err := database.Handle.Users().GetByEmail(c.Req.Context(), commit.Author.Email)
  108. if err != nil && !database.IsErrUserNotExist(err) {
  109. return nil, err
  110. } else if err == nil {
  111. apiAuthor = author.APIFormat()
  112. }
  113. // Save one query if the author is also the committer
  114. if commit.Committer.Email == commit.Author.Email {
  115. apiCommitter = apiAuthor
  116. } else {
  117. committer, err := database.Handle.Users().GetByEmail(c.Req.Context(), commit.Committer.Email)
  118. if err != nil && !database.IsErrUserNotExist(err) {
  119. return nil, err
  120. } else if err == nil {
  121. apiCommitter = committer.APIFormat()
  122. }
  123. }
  124. // Retrieve parent(s) of the commit
  125. apiParents := make([]*api.CommitMeta, commit.ParentsCount())
  126. for i := 0; i < commit.ParentsCount(); i++ {
  127. sha, _ := commit.ParentID(i)
  128. apiParents[i] = &api.CommitMeta{
  129. URL: c.BaseURL + "/repos/" + c.Repo.Repository.FullName() + "/commits/" + sha.String(),
  130. SHA: sha.String(),
  131. }
  132. }
  133. return &api.Commit{
  134. CommitMeta: &api.CommitMeta{
  135. URL: conf.Server.ExternalURL + c.Link[1:],
  136. SHA: commit.ID.String(),
  137. },
  138. HTMLURL: c.Repo.Repository.HTMLURL() + "/commits/" + commit.ID.String(),
  139. RepoCommit: &api.RepoCommit{
  140. URL: conf.Server.ExternalURL + c.Link[1:],
  141. Author: &api.CommitUser{
  142. Name: commit.Author.Name,
  143. Email: commit.Author.Email,
  144. Date: commit.Author.When.Format(time.RFC3339),
  145. },
  146. Committer: &api.CommitUser{
  147. Name: commit.Committer.Name,
  148. Email: commit.Committer.Email,
  149. Date: commit.Committer.When.Format(time.RFC3339),
  150. },
  151. Message: commit.Summary(),
  152. Tree: &api.CommitMeta{
  153. URL: c.BaseURL + "/repos/" + c.Repo.Repository.FullName() + "/tree/" + commit.ID.String(),
  154. SHA: commit.ID.String(),
  155. },
  156. },
  157. Author: apiAuthor,
  158. Committer: apiCommitter,
  159. Parents: apiParents,
  160. }, nil
  161. }