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.

workflows.go 5.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. // Copyright 2022 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package actions
  4. import (
  5. "bytes"
  6. "io"
  7. "strings"
  8. "code.gitea.io/gitea/modules/git"
  9. "code.gitea.io/gitea/modules/log"
  10. api "code.gitea.io/gitea/modules/structs"
  11. webhook_module "code.gitea.io/gitea/modules/webhook"
  12. "github.com/gobwas/glob"
  13. "github.com/nektos/act/pkg/jobparser"
  14. "github.com/nektos/act/pkg/model"
  15. )
  16. func ListWorkflows(commit *git.Commit) (git.Entries, error) {
  17. tree, err := commit.SubTree(".gitea/workflows")
  18. if _, ok := err.(git.ErrNotExist); ok {
  19. tree, err = commit.SubTree(".github/workflows")
  20. }
  21. if _, ok := err.(git.ErrNotExist); ok {
  22. return nil, nil
  23. }
  24. if err != nil {
  25. return nil, err
  26. }
  27. entries, err := tree.ListEntriesRecursiveFast()
  28. if err != nil {
  29. return nil, err
  30. }
  31. ret := make(git.Entries, 0, len(entries))
  32. for _, entry := range entries {
  33. if strings.HasSuffix(entry.Name(), ".yml") || strings.HasSuffix(entry.Name(), ".yaml") {
  34. ret = append(ret, entry)
  35. }
  36. }
  37. return ret, nil
  38. }
  39. func DetectWorkflows(commit *git.Commit, triggedEvent webhook_module.HookEventType, payload api.Payloader) (map[string][]byte, error) {
  40. entries, err := ListWorkflows(commit)
  41. if err != nil {
  42. return nil, err
  43. }
  44. workflows := make(map[string][]byte, len(entries))
  45. for _, entry := range entries {
  46. f, err := entry.Blob().DataAsync()
  47. if err != nil {
  48. return nil, err
  49. }
  50. content, err := io.ReadAll(f)
  51. _ = f.Close()
  52. if err != nil {
  53. return nil, err
  54. }
  55. workflow, err := model.ReadWorkflow(bytes.NewReader(content))
  56. if err != nil {
  57. log.Warn("ignore invalid workflow %q: %v", entry.Name(), err)
  58. continue
  59. }
  60. events, err := jobparser.ParseRawOn(&workflow.RawOn)
  61. if err != nil {
  62. log.Warn("ignore invalid workflow %q: %v", entry.Name(), err)
  63. continue
  64. }
  65. for _, evt := range events {
  66. if evt.Name != triggedEvent.Event() {
  67. continue
  68. }
  69. if detectMatched(commit, triggedEvent, payload, evt) {
  70. workflows[entry.Name()] = content
  71. }
  72. }
  73. }
  74. return workflows, nil
  75. }
  76. func detectMatched(commit *git.Commit, triggedEvent webhook_module.HookEventType, payload api.Payloader, evt *jobparser.Event) bool {
  77. if len(evt.Acts) == 0 {
  78. return true
  79. }
  80. switch triggedEvent {
  81. case webhook_module.HookEventCreate:
  82. fallthrough
  83. case webhook_module.HookEventDelete:
  84. fallthrough
  85. case webhook_module.HookEventFork:
  86. log.Warn("unsupported event %q", triggedEvent.Event())
  87. return false
  88. case webhook_module.HookEventPush:
  89. pushPayload := payload.(*api.PushPayload)
  90. matchTimes := 0
  91. // all acts conditions should be satisfied
  92. for cond, vals := range evt.Acts {
  93. switch cond {
  94. case "branches", "tags":
  95. for _, val := range vals {
  96. if glob.MustCompile(val, '/').Match(pushPayload.Ref) {
  97. matchTimes++
  98. break
  99. }
  100. }
  101. case "paths":
  102. filesChanged, err := commit.GetFilesChangedSinceCommit(pushPayload.Before)
  103. if err != nil {
  104. log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", commit.ID.String(), err)
  105. } else {
  106. for _, val := range vals {
  107. matched := false
  108. for _, file := range filesChanged {
  109. if glob.MustCompile(val, '/').Match(file) {
  110. matched = true
  111. break
  112. }
  113. }
  114. if matched {
  115. matchTimes++
  116. break
  117. }
  118. }
  119. }
  120. default:
  121. log.Warn("unsupported condition %q", cond)
  122. }
  123. }
  124. return matchTimes == len(evt.Acts)
  125. case webhook_module.HookEventIssues:
  126. fallthrough
  127. case webhook_module.HookEventIssueAssign:
  128. fallthrough
  129. case webhook_module.HookEventIssueLabel:
  130. fallthrough
  131. case webhook_module.HookEventIssueMilestone:
  132. fallthrough
  133. case webhook_module.HookEventIssueComment:
  134. fallthrough
  135. case webhook_module.HookEventPullRequest:
  136. prPayload := payload.(*api.PullRequestPayload)
  137. matchTimes := 0
  138. // all acts conditions should be satisfied
  139. for cond, vals := range evt.Acts {
  140. switch cond {
  141. case "types":
  142. for _, val := range vals {
  143. if glob.MustCompile(val, '/').Match(string(prPayload.Action)) {
  144. matchTimes++
  145. break
  146. }
  147. }
  148. case "branches":
  149. for _, val := range vals {
  150. if glob.MustCompile(val, '/').Match(prPayload.PullRequest.Base.Ref) {
  151. matchTimes++
  152. break
  153. }
  154. }
  155. case "paths":
  156. filesChanged, err := commit.GetFilesChangedSinceCommit(prPayload.PullRequest.Base.Ref)
  157. if err != nil {
  158. log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", commit.ID.String(), err)
  159. } else {
  160. for _, val := range vals {
  161. matched := false
  162. for _, file := range filesChanged {
  163. if glob.MustCompile(val, '/').Match(file) {
  164. matched = true
  165. break
  166. }
  167. }
  168. if matched {
  169. matchTimes++
  170. break
  171. }
  172. }
  173. }
  174. default:
  175. log.Warn("unsupported condition %q", cond)
  176. }
  177. }
  178. return matchTimes == len(evt.Acts)
  179. case webhook_module.HookEventPullRequestAssign:
  180. fallthrough
  181. case webhook_module.HookEventPullRequestLabel:
  182. fallthrough
  183. case webhook_module.HookEventPullRequestMilestone:
  184. fallthrough
  185. case webhook_module.HookEventPullRequestComment:
  186. fallthrough
  187. case webhook_module.HookEventPullRequestReviewApproved:
  188. fallthrough
  189. case webhook_module.HookEventPullRequestReviewRejected:
  190. fallthrough
  191. case webhook_module.HookEventPullRequestReviewComment:
  192. fallthrough
  193. case webhook_module.HookEventPullRequestSync:
  194. fallthrough
  195. case webhook_module.HookEventWiki:
  196. fallthrough
  197. case webhook_module.HookEventRepository:
  198. fallthrough
  199. case webhook_module.HookEventRelease:
  200. fallthrough
  201. case webhook_module.HookEventPackage:
  202. fallthrough
  203. default:
  204. log.Warn("unsupported event %q", triggedEvent.Event())
  205. }
  206. return false
  207. }