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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  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. "github.com/nektos/act/pkg/workflowpattern"
  16. "gopkg.in/yaml.v3"
  17. )
  18. type DetectedWorkflow struct {
  19. EntryName string
  20. TriggerEvent *jobparser.Event
  21. Content []byte
  22. }
  23. func init() {
  24. model.OnDecodeNodeError = func(node yaml.Node, out any, err error) {
  25. // Log the error instead of panic or fatal.
  26. // It will be a big job to refactor act/pkg/model to return decode error,
  27. // so we just log the error and return empty value, and improve it later.
  28. log.Error("Failed to decode node %v into %T: %v", node, out, err)
  29. }
  30. }
  31. func IsWorkflow(path string) bool {
  32. if (!strings.HasSuffix(path, ".yaml")) && (!strings.HasSuffix(path, ".yml")) {
  33. return false
  34. }
  35. return strings.HasPrefix(path, ".gitea/workflows") || strings.HasPrefix(path, ".github/workflows")
  36. }
  37. func ListWorkflows(commit *git.Commit) (git.Entries, error) {
  38. tree, err := commit.SubTree(".gitea/workflows")
  39. if _, ok := err.(git.ErrNotExist); ok {
  40. tree, err = commit.SubTree(".github/workflows")
  41. }
  42. if _, ok := err.(git.ErrNotExist); ok {
  43. return nil, nil
  44. }
  45. if err != nil {
  46. return nil, err
  47. }
  48. entries, err := tree.ListEntriesRecursiveFast()
  49. if err != nil {
  50. return nil, err
  51. }
  52. ret := make(git.Entries, 0, len(entries))
  53. for _, entry := range entries {
  54. if strings.HasSuffix(entry.Name(), ".yml") || strings.HasSuffix(entry.Name(), ".yaml") {
  55. ret = append(ret, entry)
  56. }
  57. }
  58. return ret, nil
  59. }
  60. func GetContentFromEntry(entry *git.TreeEntry) ([]byte, error) {
  61. f, err := entry.Blob().DataAsync()
  62. if err != nil {
  63. return nil, err
  64. }
  65. content, err := io.ReadAll(f)
  66. _ = f.Close()
  67. if err != nil {
  68. return nil, err
  69. }
  70. return content, nil
  71. }
  72. func GetEventsFromContent(content []byte) ([]*jobparser.Event, error) {
  73. workflow, err := model.ReadWorkflow(bytes.NewReader(content))
  74. if err != nil {
  75. return nil, err
  76. }
  77. events, err := jobparser.ParseRawOn(&workflow.RawOn)
  78. if err != nil {
  79. return nil, err
  80. }
  81. return events, nil
  82. }
  83. func DetectWorkflows(
  84. gitRepo *git.Repository,
  85. commit *git.Commit,
  86. triggedEvent webhook_module.HookEventType,
  87. payload api.Payloader,
  88. detectSchedule bool,
  89. ) ([]*DetectedWorkflow, []*DetectedWorkflow, error) {
  90. entries, err := ListWorkflows(commit)
  91. if err != nil {
  92. return nil, nil, err
  93. }
  94. workflows := make([]*DetectedWorkflow, 0, len(entries))
  95. schedules := make([]*DetectedWorkflow, 0, len(entries))
  96. for _, entry := range entries {
  97. content, err := GetContentFromEntry(entry)
  98. if err != nil {
  99. return nil, nil, err
  100. }
  101. // one workflow may have multiple events
  102. events, err := GetEventsFromContent(content)
  103. if err != nil {
  104. log.Warn("ignore invalid workflow %q: %v", entry.Name(), err)
  105. continue
  106. }
  107. for _, evt := range events {
  108. log.Trace("detect workflow %q for event %#v matching %q", entry.Name(), evt, triggedEvent)
  109. if evt.IsSchedule() {
  110. if detectSchedule {
  111. dwf := &DetectedWorkflow{
  112. EntryName: entry.Name(),
  113. TriggerEvent: evt,
  114. Content: content,
  115. }
  116. schedules = append(schedules, dwf)
  117. }
  118. } else if detectMatched(gitRepo, commit, triggedEvent, payload, evt) {
  119. dwf := &DetectedWorkflow{
  120. EntryName: entry.Name(),
  121. TriggerEvent: evt,
  122. Content: content,
  123. }
  124. workflows = append(workflows, dwf)
  125. }
  126. }
  127. }
  128. return workflows, schedules, nil
  129. }
  130. func detectMatched(gitRepo *git.Repository, commit *git.Commit, triggedEvent webhook_module.HookEventType, payload api.Payloader, evt *jobparser.Event) bool {
  131. if !canGithubEventMatch(evt.Name, triggedEvent) {
  132. return false
  133. }
  134. switch triggedEvent {
  135. case // events with no activity types
  136. webhook_module.HookEventCreate,
  137. webhook_module.HookEventDelete,
  138. webhook_module.HookEventFork,
  139. webhook_module.HookEventWiki,
  140. webhook_module.HookEventSchedule:
  141. if len(evt.Acts()) != 0 {
  142. log.Warn("Ignore unsupported %s event arguments %v", triggedEvent, evt.Acts())
  143. }
  144. // no special filter parameters for these events, just return true if name matched
  145. return true
  146. case // push
  147. webhook_module.HookEventPush:
  148. return matchPushEvent(commit, payload.(*api.PushPayload), evt)
  149. case // issues
  150. webhook_module.HookEventIssues,
  151. webhook_module.HookEventIssueAssign,
  152. webhook_module.HookEventIssueLabel,
  153. webhook_module.HookEventIssueMilestone:
  154. return matchIssuesEvent(commit, payload.(*api.IssuePayload), evt)
  155. case // issue_comment
  156. webhook_module.HookEventIssueComment,
  157. // `pull_request_comment` is same as `issue_comment`
  158. // See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_comment-use-issue_comment
  159. webhook_module.HookEventPullRequestComment:
  160. return matchIssueCommentEvent(commit, payload.(*api.IssueCommentPayload), evt)
  161. case // pull_request
  162. webhook_module.HookEventPullRequest,
  163. webhook_module.HookEventPullRequestSync,
  164. webhook_module.HookEventPullRequestAssign,
  165. webhook_module.HookEventPullRequestLabel:
  166. return matchPullRequestEvent(gitRepo, commit, payload.(*api.PullRequestPayload), evt)
  167. case // pull_request_review
  168. webhook_module.HookEventPullRequestReviewApproved,
  169. webhook_module.HookEventPullRequestReviewRejected:
  170. return matchPullRequestReviewEvent(commit, payload.(*api.PullRequestPayload), evt)
  171. case // pull_request_review_comment
  172. webhook_module.HookEventPullRequestReviewComment:
  173. return matchPullRequestReviewCommentEvent(commit, payload.(*api.PullRequestPayload), evt)
  174. case // release
  175. webhook_module.HookEventRelease:
  176. return matchReleaseEvent(commit, payload.(*api.ReleasePayload), evt)
  177. case // registry_package
  178. webhook_module.HookEventPackage:
  179. return matchPackageEvent(commit, payload.(*api.PackagePayload), evt)
  180. default:
  181. log.Warn("unsupported event %q", triggedEvent)
  182. return false
  183. }
  184. }
  185. func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobparser.Event) bool {
  186. // with no special filter parameters
  187. if len(evt.Acts()) == 0 {
  188. return true
  189. }
  190. matchTimes := 0
  191. hasBranchFilter := false
  192. hasTagFilter := false
  193. refName := git.RefName(pushPayload.Ref)
  194. // all acts conditions should be satisfied
  195. for cond, vals := range evt.Acts() {
  196. switch cond {
  197. case "branches":
  198. hasBranchFilter = true
  199. if !refName.IsBranch() {
  200. break
  201. }
  202. patterns, err := workflowpattern.CompilePatterns(vals...)
  203. if err != nil {
  204. break
  205. }
  206. if !workflowpattern.Skip(patterns, []string{refName.BranchName()}, &workflowpattern.EmptyTraceWriter{}) {
  207. matchTimes++
  208. }
  209. case "branches-ignore":
  210. hasBranchFilter = true
  211. if !refName.IsBranch() {
  212. break
  213. }
  214. patterns, err := workflowpattern.CompilePatterns(vals...)
  215. if err != nil {
  216. break
  217. }
  218. if !workflowpattern.Filter(patterns, []string{refName.BranchName()}, &workflowpattern.EmptyTraceWriter{}) {
  219. matchTimes++
  220. }
  221. case "tags":
  222. hasTagFilter = true
  223. if !refName.IsTag() {
  224. break
  225. }
  226. patterns, err := workflowpattern.CompilePatterns(vals...)
  227. if err != nil {
  228. break
  229. }
  230. if !workflowpattern.Skip(patterns, []string{refName.TagName()}, &workflowpattern.EmptyTraceWriter{}) {
  231. matchTimes++
  232. }
  233. case "tags-ignore":
  234. hasTagFilter = true
  235. if !refName.IsTag() {
  236. break
  237. }
  238. patterns, err := workflowpattern.CompilePatterns(vals...)
  239. if err != nil {
  240. break
  241. }
  242. if !workflowpattern.Filter(patterns, []string{refName.TagName()}, &workflowpattern.EmptyTraceWriter{}) {
  243. matchTimes++
  244. }
  245. case "paths":
  246. filesChanged, err := commit.GetFilesChangedSinceCommit(pushPayload.Before)
  247. if err != nil {
  248. log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", commit.ID.String(), err)
  249. } else {
  250. patterns, err := workflowpattern.CompilePatterns(vals...)
  251. if err != nil {
  252. break
  253. }
  254. if !workflowpattern.Skip(patterns, filesChanged, &workflowpattern.EmptyTraceWriter{}) {
  255. matchTimes++
  256. }
  257. }
  258. case "paths-ignore":
  259. filesChanged, err := commit.GetFilesChangedSinceCommit(pushPayload.Before)
  260. if err != nil {
  261. log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", commit.ID.String(), err)
  262. } else {
  263. patterns, err := workflowpattern.CompilePatterns(vals...)
  264. if err != nil {
  265. break
  266. }
  267. if !workflowpattern.Filter(patterns, filesChanged, &workflowpattern.EmptyTraceWriter{}) {
  268. matchTimes++
  269. }
  270. }
  271. default:
  272. log.Warn("push event unsupported condition %q", cond)
  273. }
  274. }
  275. // if both branch and tag filter are defined in the workflow only one needs to match
  276. if hasBranchFilter && hasTagFilter {
  277. matchTimes++
  278. }
  279. return matchTimes == len(evt.Acts())
  280. }
  281. func matchIssuesEvent(commit *git.Commit, issuePayload *api.IssuePayload, evt *jobparser.Event) bool {
  282. // with no special filter parameters
  283. if len(evt.Acts()) == 0 {
  284. return true
  285. }
  286. matchTimes := 0
  287. // all acts conditions should be satisfied
  288. for cond, vals := range evt.Acts() {
  289. switch cond {
  290. case "types":
  291. // See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#issues
  292. // Actions with the same name:
  293. // opened, edited, closed, reopened, assigned, unassigned, milestoned, demilestoned
  294. // Actions need to be converted:
  295. // label_updated -> labeled
  296. // label_cleared -> unlabeled
  297. // Unsupported activity types:
  298. // deleted, transferred, pinned, unpinned, locked, unlocked
  299. action := issuePayload.Action
  300. switch action {
  301. case api.HookIssueLabelUpdated:
  302. action = "labeled"
  303. case api.HookIssueLabelCleared:
  304. action = "unlabeled"
  305. }
  306. for _, val := range vals {
  307. if glob.MustCompile(val, '/').Match(string(action)) {
  308. matchTimes++
  309. break
  310. }
  311. }
  312. default:
  313. log.Warn("issue event unsupported condition %q", cond)
  314. }
  315. }
  316. return matchTimes == len(evt.Acts())
  317. }
  318. func matchPullRequestEvent(gitRepo *git.Repository, commit *git.Commit, prPayload *api.PullRequestPayload, evt *jobparser.Event) bool {
  319. acts := evt.Acts()
  320. activityTypeMatched := false
  321. matchTimes := 0
  322. if vals, ok := acts["types"]; !ok {
  323. // defaultly, only pull request `opened`, `reopened` and `synchronized` will trigger workflow
  324. // See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request
  325. activityTypeMatched = prPayload.Action == api.HookIssueSynchronized || prPayload.Action == api.HookIssueOpened || prPayload.Action == api.HookIssueReOpened
  326. } else {
  327. // See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request
  328. // Actions with the same name:
  329. // opened, edited, closed, reopened, assigned, unassigned
  330. // Actions need to be converted:
  331. // synchronized -> synchronize
  332. // label_updated -> labeled
  333. // label_cleared -> unlabeled
  334. // Unsupported activity types:
  335. // converted_to_draft, ready_for_review, locked, unlocked, review_requested, review_request_removed, auto_merge_enabled, auto_merge_disabled
  336. action := prPayload.Action
  337. switch action {
  338. case api.HookIssueSynchronized:
  339. action = "synchronize"
  340. case api.HookIssueLabelUpdated:
  341. action = "labeled"
  342. case api.HookIssueLabelCleared:
  343. action = "unlabeled"
  344. }
  345. log.Trace("matching pull_request %s with %v", action, vals)
  346. for _, val := range vals {
  347. if glob.MustCompile(val, '/').Match(string(action)) {
  348. activityTypeMatched = true
  349. matchTimes++
  350. break
  351. }
  352. }
  353. }
  354. var (
  355. headCommit = commit
  356. err error
  357. )
  358. if evt.Name == GithubEventPullRequestTarget && (len(acts["paths"]) > 0 || len(acts["paths-ignore"]) > 0) {
  359. headCommit, err = gitRepo.GetCommit(prPayload.PullRequest.Head.Sha)
  360. if err != nil {
  361. log.Error("GetCommit [ref: %s]: %v", prPayload.PullRequest.Head.Sha, err)
  362. return false
  363. }
  364. }
  365. // all acts conditions should be satisfied
  366. for cond, vals := range acts {
  367. switch cond {
  368. case "branches":
  369. refName := git.RefName(prPayload.PullRequest.Base.Ref)
  370. patterns, err := workflowpattern.CompilePatterns(vals...)
  371. if err != nil {
  372. break
  373. }
  374. if !workflowpattern.Skip(patterns, []string{refName.ShortName()}, &workflowpattern.EmptyTraceWriter{}) {
  375. matchTimes++
  376. }
  377. case "branches-ignore":
  378. refName := git.RefName(prPayload.PullRequest.Base.Ref)
  379. patterns, err := workflowpattern.CompilePatterns(vals...)
  380. if err != nil {
  381. break
  382. }
  383. if !workflowpattern.Filter(patterns, []string{refName.ShortName()}, &workflowpattern.EmptyTraceWriter{}) {
  384. matchTimes++
  385. }
  386. case "paths":
  387. filesChanged, err := headCommit.GetFilesChangedSinceCommit(prPayload.PullRequest.Base.Ref)
  388. if err != nil {
  389. log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", headCommit.ID.String(), err)
  390. } else {
  391. patterns, err := workflowpattern.CompilePatterns(vals...)
  392. if err != nil {
  393. break
  394. }
  395. if !workflowpattern.Skip(patterns, filesChanged, &workflowpattern.EmptyTraceWriter{}) {
  396. matchTimes++
  397. }
  398. }
  399. case "paths-ignore":
  400. filesChanged, err := headCommit.GetFilesChangedSinceCommit(prPayload.PullRequest.Base.Ref)
  401. if err != nil {
  402. log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", headCommit.ID.String(), err)
  403. } else {
  404. patterns, err := workflowpattern.CompilePatterns(vals...)
  405. if err != nil {
  406. break
  407. }
  408. if !workflowpattern.Filter(patterns, filesChanged, &workflowpattern.EmptyTraceWriter{}) {
  409. matchTimes++
  410. }
  411. }
  412. default:
  413. log.Warn("pull request event unsupported condition %q", cond)
  414. }
  415. }
  416. return activityTypeMatched && matchTimes == len(evt.Acts())
  417. }
  418. func matchIssueCommentEvent(commit *git.Commit, issueCommentPayload *api.IssueCommentPayload, evt *jobparser.Event) bool {
  419. // with no special filter parameters
  420. if len(evt.Acts()) == 0 {
  421. return true
  422. }
  423. matchTimes := 0
  424. // all acts conditions should be satisfied
  425. for cond, vals := range evt.Acts() {
  426. switch cond {
  427. case "types":
  428. // See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#issue_comment
  429. // Actions with the same name:
  430. // created, edited, deleted
  431. // Actions need to be converted:
  432. // NONE
  433. // Unsupported activity types:
  434. // NONE
  435. for _, val := range vals {
  436. if glob.MustCompile(val, '/').Match(string(issueCommentPayload.Action)) {
  437. matchTimes++
  438. break
  439. }
  440. }
  441. default:
  442. log.Warn("issue comment event unsupported condition %q", cond)
  443. }
  444. }
  445. return matchTimes == len(evt.Acts())
  446. }
  447. func matchPullRequestReviewEvent(commit *git.Commit, prPayload *api.PullRequestPayload, evt *jobparser.Event) bool {
  448. // with no special filter parameters
  449. if len(evt.Acts()) == 0 {
  450. return true
  451. }
  452. matchTimes := 0
  453. // all acts conditions should be satisfied
  454. for cond, vals := range evt.Acts() {
  455. switch cond {
  456. case "types":
  457. // See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_review
  458. // Activity types with the same name:
  459. // NONE
  460. // Activity types need to be converted:
  461. // reviewed -> submitted
  462. // reviewed -> edited
  463. // Unsupported activity types:
  464. // dismissed
  465. actions := make([]string, 0)
  466. if prPayload.Action == api.HookIssueReviewed {
  467. // the `reviewed` HookIssueAction can match the two activity types: `submitted` and `edited`
  468. // See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_review
  469. actions = append(actions, "submitted", "edited")
  470. }
  471. matched := false
  472. for _, val := range vals {
  473. for _, action := range actions {
  474. if glob.MustCompile(val, '/').Match(action) {
  475. matched = true
  476. break
  477. }
  478. }
  479. if matched {
  480. break
  481. }
  482. }
  483. if matched {
  484. matchTimes++
  485. }
  486. default:
  487. log.Warn("pull request review event unsupported condition %q", cond)
  488. }
  489. }
  490. return matchTimes == len(evt.Acts())
  491. }
  492. func matchPullRequestReviewCommentEvent(commit *git.Commit, prPayload *api.PullRequestPayload, evt *jobparser.Event) bool {
  493. // with no special filter parameters
  494. if len(evt.Acts()) == 0 {
  495. return true
  496. }
  497. matchTimes := 0
  498. // all acts conditions should be satisfied
  499. for cond, vals := range evt.Acts() {
  500. switch cond {
  501. case "types":
  502. // See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_review_comment
  503. // Activity types with the same name:
  504. // NONE
  505. // Activity types need to be converted:
  506. // reviewed -> created
  507. // reviewed -> edited
  508. // Unsupported activity types:
  509. // deleted
  510. actions := make([]string, 0)
  511. if prPayload.Action == api.HookIssueReviewed {
  512. // the `reviewed` HookIssueAction can match the two activity types: `created` and `edited`
  513. // See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_review_comment
  514. actions = append(actions, "created", "edited")
  515. }
  516. matched := false
  517. for _, val := range vals {
  518. for _, action := range actions {
  519. if glob.MustCompile(val, '/').Match(action) {
  520. matched = true
  521. break
  522. }
  523. }
  524. if matched {
  525. break
  526. }
  527. }
  528. if matched {
  529. matchTimes++
  530. }
  531. default:
  532. log.Warn("pull request review comment event unsupported condition %q", cond)
  533. }
  534. }
  535. return matchTimes == len(evt.Acts())
  536. }
  537. func matchReleaseEvent(commit *git.Commit, payload *api.ReleasePayload, evt *jobparser.Event) bool {
  538. // with no special filter parameters
  539. if len(evt.Acts()) == 0 {
  540. return true
  541. }
  542. matchTimes := 0
  543. // all acts conditions should be satisfied
  544. for cond, vals := range evt.Acts() {
  545. switch cond {
  546. case "types":
  547. // See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#release
  548. // Activity types with the same name:
  549. // published
  550. // Activity types need to be converted:
  551. // updated -> edited
  552. // Unsupported activity types:
  553. // unpublished, created, deleted, prereleased, released
  554. action := payload.Action
  555. switch action {
  556. case api.HookReleaseUpdated:
  557. action = "edited"
  558. }
  559. for _, val := range vals {
  560. if glob.MustCompile(val, '/').Match(string(action)) {
  561. matchTimes++
  562. break
  563. }
  564. }
  565. default:
  566. log.Warn("release event unsupported condition %q", cond)
  567. }
  568. }
  569. return matchTimes == len(evt.Acts())
  570. }
  571. func matchPackageEvent(commit *git.Commit, payload *api.PackagePayload, evt *jobparser.Event) bool {
  572. // with no special filter parameters
  573. if len(evt.Acts()) == 0 {
  574. return true
  575. }
  576. matchTimes := 0
  577. // all acts conditions should be satisfied
  578. for cond, vals := range evt.Acts() {
  579. switch cond {
  580. case "types":
  581. // See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#registry_package
  582. // Activity types with the same name:
  583. // NONE
  584. // Activity types need to be converted:
  585. // created -> published
  586. // Unsupported activity types:
  587. // updated
  588. action := payload.Action
  589. switch action {
  590. case api.HookPackageCreated:
  591. action = "published"
  592. }
  593. for _, val := range vals {
  594. if glob.MustCompile(val, '/').Match(string(action)) {
  595. matchTimes++
  596. break
  597. }
  598. }
  599. default:
  600. log.Warn("package event unsupported condition %q", cond)
  601. }
  602. }
  603. return matchTimes == len(evt.Acts())
  604. }