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 3.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // Copyright 2015 The Gogs Authors. All rights reserved.
  2. // Copyright 2021 The Gitea Authors. All rights reserved.
  3. // SPDX-License-Identifier: MIT
  4. package git
  5. import (
  6. "errors"
  7. "os"
  8. "path"
  9. "path/filepath"
  10. "strings"
  11. "code.gitea.io/gitea/modules/log"
  12. "code.gitea.io/gitea/modules/util"
  13. )
  14. // hookNames is a list of Git server hooks' name that are supported.
  15. var hookNames = []string{
  16. "pre-receive",
  17. "update",
  18. "post-receive",
  19. }
  20. // ErrNotValidHook error when a git hook is not valid
  21. var ErrNotValidHook = errors.New("not a valid Git hook")
  22. // IsValidHookName returns true if given name is a valid Git hook.
  23. func IsValidHookName(name string) bool {
  24. for _, hn := range hookNames {
  25. if hn == name {
  26. return true
  27. }
  28. }
  29. return false
  30. }
  31. // Hook represents a Git hook.
  32. type Hook struct {
  33. name string
  34. IsActive bool // Indicates whether repository has this hook.
  35. Content string // Content of hook if it's active.
  36. Sample string // Sample content from Git.
  37. path string // Hook file path.
  38. }
  39. // GetHook returns a Git hook by given name and repository.
  40. func GetHook(repoPath, name string) (*Hook, error) {
  41. if !IsValidHookName(name) {
  42. return nil, ErrNotValidHook
  43. }
  44. h := &Hook{
  45. name: name,
  46. path: path.Join(repoPath, "hooks", name+".d", name),
  47. }
  48. samplePath := filepath.Join(repoPath, "hooks", name+".sample")
  49. if isFile(h.path) {
  50. data, err := os.ReadFile(h.path)
  51. if err != nil {
  52. return nil, err
  53. }
  54. h.IsActive = true
  55. h.Content = string(data)
  56. } else if isFile(samplePath) {
  57. data, err := os.ReadFile(samplePath)
  58. if err != nil {
  59. return nil, err
  60. }
  61. h.Sample = string(data)
  62. }
  63. return h, nil
  64. }
  65. // Name return the name of the hook
  66. func (h *Hook) Name() string {
  67. return h.name
  68. }
  69. // Update updates hook settings.
  70. func (h *Hook) Update() error {
  71. if len(strings.TrimSpace(h.Content)) == 0 {
  72. if isExist(h.path) {
  73. err := util.Remove(h.path)
  74. if err != nil {
  75. return err
  76. }
  77. }
  78. h.IsActive = false
  79. return nil
  80. }
  81. d := filepath.Dir(h.path)
  82. if err := os.MkdirAll(d, os.ModePerm); err != nil {
  83. return err
  84. }
  85. err := os.WriteFile(h.path, []byte(strings.ReplaceAll(h.Content, "\r", "")), os.ModePerm)
  86. if err != nil {
  87. return err
  88. }
  89. h.IsActive = true
  90. return nil
  91. }
  92. // ListHooks returns a list of Git hooks of given repository.
  93. func ListHooks(repoPath string) (_ []*Hook, err error) {
  94. if !isDir(path.Join(repoPath, "hooks")) {
  95. return nil, errors.New("hooks path does not exist")
  96. }
  97. hooks := make([]*Hook, len(hookNames))
  98. for i, name := range hookNames {
  99. hooks[i], err = GetHook(repoPath, name)
  100. if err != nil {
  101. return nil, err
  102. }
  103. }
  104. return hooks, nil
  105. }
  106. const (
  107. // HookPathUpdate hook update path
  108. HookPathUpdate = "hooks/update"
  109. )
  110. // SetUpdateHook writes given content to update hook of the repository.
  111. func SetUpdateHook(repoPath, content string) (err error) {
  112. log.Debug("Setting update hook: %s", repoPath)
  113. hookPath := path.Join(repoPath, HookPathUpdate)
  114. isExist, err := util.IsExist(hookPath)
  115. if err != nil {
  116. log.Debug("Unable to check if %s exists. Error: %v", hookPath, err)
  117. return err
  118. }
  119. if isExist {
  120. err = util.Remove(hookPath)
  121. } else {
  122. err = os.MkdirAll(path.Dir(hookPath), os.ModePerm)
  123. }
  124. if err != nil {
  125. return err
  126. }
  127. return os.WriteFile(hookPath, []byte(content), 0o777)
  128. }