| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338 |
- // Copyright 2023 The Gitea Authors. All rights reserved.
- // SPDX-License-Identifier: MIT
-
- package actions
-
- import (
- "testing"
-
- "code.gitea.io/gitea/modules/git"
- api "code.gitea.io/gitea/modules/structs"
- webhook_module "code.gitea.io/gitea/modules/webhook"
-
- "github.com/stretchr/testify/assert"
- )
-
- func TestDetectMatched(t *testing.T) {
- testCases := []struct {
- desc string
- commit *git.Commit
- triggedEvent webhook_module.HookEventType
- payload api.Payloader
- yamlOn string
- expected bool
- }{
- {
- desc: "HookEventCreate(create) matches GithubEventCreate(create)",
- triggedEvent: webhook_module.HookEventCreate,
- payload: nil,
- yamlOn: "on: create",
- expected: true,
- },
- {
- desc: "HookEventIssues(issues) `opened` action matches GithubEventIssues(issues)",
- triggedEvent: webhook_module.HookEventIssues,
- payload: &api.IssuePayload{Action: api.HookIssueOpened},
- yamlOn: "on: issues",
- expected: true,
- },
- {
- desc: "HookEventIssues(issues) `milestoned` action matches GithubEventIssues(issues)",
- triggedEvent: webhook_module.HookEventIssues,
- payload: &api.IssuePayload{Action: api.HookIssueMilestoned},
- yamlOn: "on: issues",
- expected: true,
- },
- {
- desc: "HookEventPullRequestSync(pull_request_sync) matches GithubEventPullRequest(pull_request)",
- triggedEvent: webhook_module.HookEventPullRequestSync,
- payload: &api.PullRequestPayload{Action: api.HookIssueSynchronized},
- yamlOn: "on: pull_request",
- expected: true,
- },
- {
- desc: "HookEventPullRequest(pull_request) `label_updated` action doesn't match GithubEventPullRequest(pull_request) with no activity type",
- triggedEvent: webhook_module.HookEventPullRequest,
- payload: &api.PullRequestPayload{Action: api.HookIssueLabelUpdated},
- yamlOn: "on: pull_request",
- expected: false,
- },
- {
- desc: "HookEventPullRequest(pull_request) `closed` action doesn't match GithubEventPullRequest(pull_request) with no activity type",
- triggedEvent: webhook_module.HookEventPullRequest,
- payload: &api.PullRequestPayload{Action: api.HookIssueClosed},
- yamlOn: "on: pull_request",
- expected: false,
- },
- {
- desc: "HookEventPullRequest(pull_request) `closed` action doesn't match GithubEventPullRequest(pull_request) with branches",
- triggedEvent: webhook_module.HookEventPullRequest,
- payload: &api.PullRequestPayload{
- Action: api.HookIssueClosed,
- PullRequest: &api.PullRequest{
- Base: &api.PRBranchInfo{},
- },
- },
- yamlOn: "on:\n pull_request:\n branches: [main]",
- expected: false,
- },
- {
- desc: "HookEventPullRequest(pull_request) `label_updated` action matches GithubEventPullRequest(pull_request) with `label` activity type",
- triggedEvent: webhook_module.HookEventPullRequest,
- payload: &api.PullRequestPayload{Action: api.HookIssueLabelUpdated},
- yamlOn: "on:\n pull_request:\n types: [labeled]",
- expected: true,
- },
- {
- desc: "HookEventPullRequestReviewComment(pull_request_review_comment) matches GithubEventPullRequestReviewComment(pull_request_review_comment)",
- triggedEvent: webhook_module.HookEventPullRequestReviewComment,
- payload: &api.PullRequestPayload{Action: api.HookIssueReviewed},
- yamlOn: "on:\n pull_request_review_comment:\n types: [created]",
- expected: true,
- },
- {
- desc: "HookEventPullRequestReviewRejected(pull_request_review_rejected) doesn't match GithubEventPullRequestReview(pull_request_review) with `dismissed` activity type (we don't support `dismissed` at present)",
- triggedEvent: webhook_module.HookEventPullRequestReviewRejected,
- payload: &api.PullRequestPayload{Action: api.HookIssueReviewed},
- yamlOn: "on:\n pull_request_review:\n types: [dismissed]",
- expected: false,
- },
- {
- desc: "HookEventRelease(release) `published` action matches GithubEventRelease(release) with `published` activity type",
- triggedEvent: webhook_module.HookEventRelease,
- payload: &api.ReleasePayload{Action: api.HookReleasePublished},
- yamlOn: "on:\n release:\n types: [published]",
- expected: true,
- },
- {
- desc: "HookEventPackage(package) `created` action doesn't match GithubEventRegistryPackage(registry_package) with `updated` activity type",
- triggedEvent: webhook_module.HookEventPackage,
- payload: &api.PackagePayload{Action: api.HookPackageCreated},
- yamlOn: "on:\n registry_package:\n types: [updated]",
- expected: false,
- },
- {
- desc: "HookEventWiki(wiki) matches GithubEventGollum(gollum)",
- triggedEvent: webhook_module.HookEventWiki,
- payload: nil,
- yamlOn: "on: gollum",
- expected: true,
- },
- {
- desc: "HookEventSchedue(schedule) matches GithubEventSchedule(schedule)",
- triggedEvent: webhook_module.HookEventSchedule,
- payload: nil,
- yamlOn: "on: schedule",
- expected: true,
- },
- {
- desc: "push to tag matches workflow with paths condition (should skip paths check)",
- triggedEvent: webhook_module.HookEventPush,
- payload: &api.PushPayload{
- Ref: "refs/tags/v1.0.0",
- Before: "0000000",
- Commits: []*api.PayloadCommit{
- {
- ID: "abcdef123456",
- Added: []string{"src/main.go"},
- Message: "Release v1.0.0",
- },
- },
- },
- commit: nil,
- yamlOn: "on:\n push:\n paths:\n - src/**",
- expected: true,
- },
- }
-
- for _, tc := range testCases {
- t.Run(tc.desc, func(t *testing.T) {
- evts, err := GetEventsFromContent([]byte(tc.yamlOn))
- assert.NoError(t, err)
- assert.Len(t, evts, 1)
- assert.Equal(t, tc.expected, detectMatched(nil, tc.commit, tc.triggedEvent, tc.payload, evts[0]))
- })
- }
- }
-
- func TestMatchIssuesEvent(t *testing.T) {
- testCases := []struct {
- desc string
- payload *api.IssuePayload
- yamlOn string
- expected bool
- eventType string
- }{
- {
- desc: "Label deletion should trigger unlabeled event",
- payload: &api.IssuePayload{
- Action: api.HookIssueLabelUpdated,
- Issue: &api.Issue{
- Labels: []*api.Label{},
- },
- Changes: &api.ChangesPayload{
- RemovedLabels: []*api.Label{
- {ID: 123, Name: "deleted-label"},
- },
- },
- },
- yamlOn: "on:\n issues:\n types: [unlabeled]",
- expected: true,
- eventType: "unlabeled",
- },
- {
- desc: "Label deletion with existing labels should trigger unlabeled event",
- payload: &api.IssuePayload{
- Action: api.HookIssueLabelUpdated,
- Issue: &api.Issue{
- Labels: []*api.Label{
- {ID: 456, Name: "existing-label"},
- },
- },
- Changes: &api.ChangesPayload{
- AddedLabels: nil,
- RemovedLabels: []*api.Label{
- {ID: 123, Name: "deleted-label"},
- },
- },
- },
- yamlOn: "on:\n issues:\n types: [unlabeled]",
- expected: true,
- eventType: "unlabeled",
- },
- {
- desc: "Label addition should trigger labeled event",
- payload: &api.IssuePayload{
- Action: api.HookIssueLabelUpdated,
- Issue: &api.Issue{
- Labels: []*api.Label{
- {ID: 123, Name: "new-label"},
- },
- },
- Changes: &api.ChangesPayload{
- AddedLabels: []*api.Label{
- {ID: 123, Name: "new-label"},
- },
- RemovedLabels: []*api.Label{}, // Empty array, no labels removed
- },
- },
- yamlOn: "on:\n issues:\n types: [labeled]",
- expected: true,
- eventType: "labeled",
- },
- {
- desc: "Label clear should trigger unlabeled event",
- payload: &api.IssuePayload{
- Action: api.HookIssueLabelCleared,
- Issue: &api.Issue{
- Labels: []*api.Label{},
- },
- },
- yamlOn: "on:\n issues:\n types: [unlabeled]",
- expected: true,
- eventType: "unlabeled",
- },
- {
- desc: "Both adding and removing labels should trigger labeled event",
- payload: &api.IssuePayload{
- Action: api.HookIssueLabelUpdated,
- Issue: &api.Issue{
- Labels: []*api.Label{
- {ID: 789, Name: "new-label"},
- },
- },
- Changes: &api.ChangesPayload{
- AddedLabels: []*api.Label{
- {ID: 789, Name: "new-label"},
- },
- RemovedLabels: []*api.Label{
- {ID: 123, Name: "deleted-label"},
- },
- },
- },
- yamlOn: "on:\n issues:\n types: [labeled]",
- expected: true,
- eventType: "labeled",
- },
- {
- desc: "Both adding and removing labels should trigger unlabeled event",
- payload: &api.IssuePayload{
- Action: api.HookIssueLabelUpdated,
- Issue: &api.Issue{
- Labels: []*api.Label{
- {ID: 789, Name: "new-label"},
- },
- },
- Changes: &api.ChangesPayload{
- AddedLabels: []*api.Label{
- {ID: 789, Name: "new-label"},
- },
- RemovedLabels: []*api.Label{
- {ID: 123, Name: "deleted-label"},
- },
- },
- },
- yamlOn: "on:\n issues:\n types: [unlabeled]",
- expected: true,
- eventType: "unlabeled",
- },
- {
- desc: "Both adding and removing labels should trigger both events",
- payload: &api.IssuePayload{
- Action: api.HookIssueLabelUpdated,
- Issue: &api.Issue{
- Labels: []*api.Label{
- {ID: 789, Name: "new-label"},
- },
- },
- Changes: &api.ChangesPayload{
- AddedLabels: []*api.Label{
- {ID: 789, Name: "new-label"},
- },
- RemovedLabels: []*api.Label{
- {ID: 123, Name: "deleted-label"},
- },
- },
- },
- yamlOn: "on:\n issues:\n types: [labeled, unlabeled]",
- expected: true,
- eventType: "multiple",
- },
- }
-
- for _, tc := range testCases {
- t.Run(tc.desc, func(t *testing.T) {
- evts, err := GetEventsFromContent([]byte(tc.yamlOn))
- assert.NoError(t, err)
- assert.Len(t, evts, 1)
-
- // Test if the event matches as expected
- assert.Equal(t, tc.expected, matchIssuesEvent(tc.payload, evts[0]))
-
- // For extra validation, check that action mapping works correctly
- if tc.eventType == "multiple" {
- // Skip direct action mapping validation for multiple events case
- // as one action can map to multiple event types
- return
- }
-
- // Determine expected action for single event case
- var expectedAction string
- switch tc.payload.Action {
- case api.HookIssueLabelUpdated:
- if tc.eventType == "labeled" {
- expectedAction = "labeled"
- } else if tc.eventType == "unlabeled" {
- expectedAction = "unlabeled"
- }
- case api.HookIssueLabelCleared:
- expectedAction = "unlabeled"
- default:
- expectedAction = string(tc.payload.Action)
- }
-
- assert.Equal(t, expectedAction, tc.eventType, "Event type should match expected")
- })
- }
- }
|