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

hook.go 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. // Copyright 2017 The Gitea 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 cmd
  5. import (
  6. "bufio"
  7. "bytes"
  8. "fmt"
  9. "net/http"
  10. "os"
  11. "strconv"
  12. "strings"
  13. "code.gitea.io/gitea/models"
  14. "code.gitea.io/gitea/modules/git"
  15. "code.gitea.io/gitea/modules/private"
  16. "github.com/urfave/cli"
  17. )
  18. var (
  19. // CmdHook represents the available hooks sub-command.
  20. CmdHook = cli.Command{
  21. Name: "hook",
  22. Usage: "Delegate commands to corresponding Git hooks",
  23. Description: "This should only be called by Git",
  24. Subcommands: []cli.Command{
  25. subcmdHookPreReceive,
  26. subcmdHookUpdate,
  27. subcmdHookPostReceive,
  28. },
  29. }
  30. subcmdHookPreReceive = cli.Command{
  31. Name: "pre-receive",
  32. Usage: "Delegate pre-receive Git hook",
  33. Description: "This command should only be called by Git",
  34. Action: runHookPreReceive,
  35. }
  36. subcmdHookUpdate = cli.Command{
  37. Name: "update",
  38. Usage: "Delegate update Git hook",
  39. Description: "This command should only be called by Git",
  40. Action: runHookUpdate,
  41. }
  42. subcmdHookPostReceive = cli.Command{
  43. Name: "post-receive",
  44. Usage: "Delegate post-receive Git hook",
  45. Description: "This command should only be called by Git",
  46. Action: runHookPostReceive,
  47. }
  48. )
  49. func runHookPreReceive(c *cli.Context) error {
  50. if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
  51. return nil
  52. }
  53. setup("hooks/pre-receive.log")
  54. // the environment setted on serv command
  55. isWiki := (os.Getenv(models.EnvRepoIsWiki) == "true")
  56. username := os.Getenv(models.EnvRepoUsername)
  57. reponame := os.Getenv(models.EnvRepoName)
  58. userID, _ := strconv.ParseInt(os.Getenv(models.EnvPusherID), 10, 64)
  59. prID, _ := strconv.ParseInt(os.Getenv(models.ProtectedBranchPRID), 10, 64)
  60. buf := bytes.NewBuffer(nil)
  61. scanner := bufio.NewScanner(os.Stdin)
  62. for scanner.Scan() {
  63. buf.Write(scanner.Bytes())
  64. buf.WriteByte('\n')
  65. // TODO: support news feeds for wiki
  66. if isWiki {
  67. continue
  68. }
  69. fields := bytes.Fields(scanner.Bytes())
  70. if len(fields) != 3 {
  71. continue
  72. }
  73. oldCommitID := string(fields[0])
  74. newCommitID := string(fields[1])
  75. refFullName := string(fields[2])
  76. // If the ref is a branch, check if it's protected
  77. if strings.HasPrefix(refFullName, git.BranchPrefix) {
  78. statusCode, msg := private.HookPreReceive(username, reponame, private.HookOptions{
  79. OldCommitID: oldCommitID,
  80. NewCommitID: newCommitID,
  81. RefFullName: refFullName,
  82. UserID: userID,
  83. GitAlternativeObjectDirectories: os.Getenv(private.GitAlternativeObjectDirectories),
  84. GitObjectDirectory: os.Getenv(private.GitObjectDirectory),
  85. ProtectedBranchID: prID,
  86. })
  87. switch statusCode {
  88. case http.StatusInternalServerError:
  89. fail("Internal Server Error", msg)
  90. case http.StatusForbidden:
  91. fail(msg, "")
  92. }
  93. }
  94. }
  95. return nil
  96. }
  97. func runHookUpdate(c *cli.Context) error {
  98. if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
  99. return nil
  100. }
  101. setup("hooks/update.log")
  102. return nil
  103. }
  104. func runHookPostReceive(c *cli.Context) error {
  105. if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
  106. return nil
  107. }
  108. setup("hooks/post-receive.log")
  109. // the environment setted on serv command
  110. repoUser := os.Getenv(models.EnvRepoUsername)
  111. isWiki := (os.Getenv(models.EnvRepoIsWiki) == "true")
  112. repoName := os.Getenv(models.EnvRepoName)
  113. pusherID, _ := strconv.ParseInt(os.Getenv(models.EnvPusherID), 10, 64)
  114. pusherName := os.Getenv(models.EnvPusherName)
  115. buf := bytes.NewBuffer(nil)
  116. scanner := bufio.NewScanner(os.Stdin)
  117. for scanner.Scan() {
  118. buf.Write(scanner.Bytes())
  119. buf.WriteByte('\n')
  120. // TODO: support news feeds for wiki
  121. if isWiki {
  122. continue
  123. }
  124. fields := bytes.Fields(scanner.Bytes())
  125. if len(fields) != 3 {
  126. continue
  127. }
  128. oldCommitID := string(fields[0])
  129. newCommitID := string(fields[1])
  130. refFullName := string(fields[2])
  131. res, err := private.HookPostReceive(repoUser, repoName, private.HookOptions{
  132. OldCommitID: oldCommitID,
  133. NewCommitID: newCommitID,
  134. RefFullName: refFullName,
  135. UserID: pusherID,
  136. UserName: pusherName,
  137. })
  138. if res == nil {
  139. fail("Internal Server Error", err)
  140. }
  141. if res["message"] == false {
  142. continue
  143. }
  144. fmt.Fprintln(os.Stderr, "")
  145. if res["create"] == true {
  146. fmt.Fprintf(os.Stderr, "Create a new pull request for '%s':\n", res["branch"])
  147. fmt.Fprintf(os.Stderr, " %s\n", res["url"])
  148. } else {
  149. fmt.Fprint(os.Stderr, "Visit the existing pull request:\n")
  150. fmt.Fprintf(os.Stderr, " %s\n", res["url"])
  151. }
  152. fmt.Fprintln(os.Stderr, "")
  153. }
  154. return nil
  155. }