hook.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  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 cmd
  5. import (
  6. "bufio"
  7. "bytes"
  8. "crypto/tls"
  9. "os"
  10. "os/exec"
  11. "path/filepath"
  12. "strings"
  13. "github.com/Unknwon/com"
  14. "github.com/urfave/cli"
  15. log "gopkg.in/clog.v1"
  16. "github.com/gogits/git-module"
  17. "github.com/gogits/gogs/models"
  18. "github.com/gogits/gogs/modules/httplib"
  19. "github.com/gogits/gogs/modules/setting"
  20. http "github.com/gogits/gogs/routers/repo"
  21. )
  22. var (
  23. CmdHook = cli.Command{
  24. Name: "hook",
  25. Usage: "Delegate commands to corresponding Git hooks",
  26. Description: "All sub-commands should only be called by Git",
  27. Flags: []cli.Flag{
  28. stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"),
  29. },
  30. Subcommands: []cli.Command{
  31. subcmdHookPreReceive,
  32. subcmdHookUpadte,
  33. subcmdHookPostReceive,
  34. },
  35. }
  36. subcmdHookPreReceive = cli.Command{
  37. Name: "pre-receive",
  38. Usage: "Delegate pre-receive Git hook",
  39. Description: "This command should only be called by Git",
  40. Action: runHookPreReceive,
  41. }
  42. subcmdHookUpadte = cli.Command{
  43. Name: "update",
  44. Usage: "Delegate update Git hook",
  45. Description: "This command should only be called by Git",
  46. Action: runHookUpdate,
  47. }
  48. subcmdHookPostReceive = cli.Command{
  49. Name: "post-receive",
  50. Usage: "Delegate post-receive Git hook",
  51. Description: "This command should only be called by Git",
  52. Action: runHookPostReceive,
  53. }
  54. )
  55. func runHookPreReceive(c *cli.Context) error {
  56. if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
  57. return nil
  58. }
  59. setup(c, "hooks/pre-receive.log", false)
  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. }
  66. customHooksPath := filepath.Join(os.Getenv(http.ENV_REPO_CUSTOM_HOOKS_PATH), "pre-receive")
  67. if !com.IsFile(customHooksPath) {
  68. return nil
  69. }
  70. hookCmd := exec.Command(customHooksPath)
  71. hookCmd.Stdout = os.Stdout
  72. hookCmd.Stdin = buf
  73. hookCmd.Stderr = os.Stderr
  74. if err := hookCmd.Run(); err != nil {
  75. fail("Internal error", "Fail to execute custom pre-receive hook: %v", err)
  76. }
  77. return nil
  78. }
  79. func runHookUpdate(c *cli.Context) error {
  80. if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
  81. return nil
  82. }
  83. setup(c, "hooks/update.log", false)
  84. args := c.Args()
  85. if len(args) != 3 {
  86. fail("Arguments received are not equal to three", "Arguments received are not equal to three")
  87. } else if len(args[0]) == 0 {
  88. fail("First argument 'refName' is empty", "First argument 'refName' is empty")
  89. }
  90. customHooksPath := filepath.Join(os.Getenv(http.ENV_REPO_CUSTOM_HOOKS_PATH), "update")
  91. if !com.IsFile(customHooksPath) {
  92. return nil
  93. }
  94. hookCmd := exec.Command(customHooksPath, args...)
  95. hookCmd.Stdout = os.Stdout
  96. hookCmd.Stdin = os.Stdin
  97. hookCmd.Stderr = os.Stderr
  98. if err := hookCmd.Run(); err != nil {
  99. fail("Internal error", "Fail to execute custom pre-receive hook: %v", err)
  100. }
  101. return nil
  102. }
  103. func runHookPostReceive(c *cli.Context) error {
  104. if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
  105. return nil
  106. }
  107. setup(c, "hooks/post-receive.log", true)
  108. isWiki := strings.Contains(os.Getenv(http.ENV_REPO_CUSTOM_HOOKS_PATH), ".wiki.git/")
  109. buf := bytes.NewBuffer(nil)
  110. scanner := bufio.NewScanner(os.Stdin)
  111. for scanner.Scan() {
  112. buf.Write(scanner.Bytes())
  113. buf.WriteByte('\n')
  114. // TODO: support news feeds for wiki
  115. if isWiki {
  116. continue
  117. }
  118. fields := bytes.Fields(scanner.Bytes())
  119. if len(fields) != 3 {
  120. continue
  121. }
  122. options := models.PushUpdateOptions{
  123. OldCommitID: string(fields[0]),
  124. NewCommitID: string(fields[1]),
  125. RefFullName: string(fields[2]),
  126. PusherID: com.StrTo(os.Getenv(http.ENV_AUTH_USER_ID)).MustInt64(),
  127. PusherName: os.Getenv(http.ENV_AUTH_USER_NAME),
  128. RepoUserName: os.Getenv(http.ENV_REPO_OWNER_NAME),
  129. RepoName: os.Getenv(http.ENV_REPO_NAME),
  130. }
  131. if err := models.PushUpdate(options); err != nil {
  132. log.Error(2, "PushUpdate: %v", err)
  133. }
  134. // Ask for running deliver hook and test pull request tasks.
  135. reqURL := setting.LocalURL + options.RepoUserName + "/" + options.RepoName + "/tasks/trigger?branch=" +
  136. strings.TrimPrefix(options.RefFullName, git.BRANCH_PREFIX) +
  137. "&secret=" + os.Getenv(http.ENV_REPO_OWNER_SALT_MD5) +
  138. "&pusher=" + os.Getenv(http.ENV_AUTH_USER_ID)
  139. log.Trace("Trigger task: %s", reqURL)
  140. resp, err := httplib.Head(reqURL).SetTLSClientConfig(&tls.Config{
  141. InsecureSkipVerify: true,
  142. }).Response()
  143. if err == nil {
  144. resp.Body.Close()
  145. if resp.StatusCode/100 != 2 {
  146. log.Error(2, "Fail to trigger task: not 2xx response code")
  147. }
  148. } else {
  149. log.Error(2, "Fail to trigger task: %v", err)
  150. }
  151. }
  152. customHooksPath := filepath.Join(os.Getenv(http.ENV_REPO_CUSTOM_HOOKS_PATH), "post-receive")
  153. if !com.IsFile(customHooksPath) {
  154. return nil
  155. }
  156. hookCmd := exec.Command(customHooksPath)
  157. hookCmd.Stdout = os.Stdout
  158. hookCmd.Stdin = buf
  159. hookCmd.Stderr = os.Stderr
  160. if err := hookCmd.Run(); err != nil {
  161. fail("Internal error", "Fail to execute custom post-receive hook: %v", err)
  162. }
  163. return nil
  164. }