Skip to content

Commit 37c96b0

Browse files
committed
fix workflow name in workflow payload
* add workflow_run action trigger + webhook test * loads the workflow and fill the name key if present
1 parent 3e3be37 commit 37c96b0

File tree

6 files changed

+281
-44
lines changed

6 files changed

+281
-44
lines changed

models/fixtures/action_run.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,23 @@
7474
updated: 1683636626
7575
need_approval: 0
7676
approved_by: 0
77+
78+
-
79+
id: 802
80+
title: "workflow run list"
81+
repo_id: 4
82+
owner_id: 1
83+
workflow_id: "test.yaml"
84+
index: 191
85+
trigger_user_id: 1
86+
ref: "refs/heads/test"
87+
commit_sha: "c2d72f548424103f01ee1dc02889c1e2bff816b0"
88+
event: "push"
89+
is_fork_pull_request: 0
90+
status: 1
91+
started: 1683636528
92+
stopped: 1683636626
93+
created: 1683636108
94+
updated: 1683636626
95+
need_approval: 0
96+
approved_by: 0

models/fixtures/action_run_job.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,19 @@
6969
status: 5
7070
started: 1683636528
7171
stopped: 1683636626
72+
73+
-
74+
id: 203
75+
run_id: 802
76+
repo_id: 4
77+
owner_id: 1
78+
commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
79+
is_fork_pull_request: 0
80+
name: job2
81+
attempt: 1
82+
job_id: job2
83+
needs: '["job1"]'
84+
task_id: 51
85+
status: 5
86+
started: 1683636528
87+
stopped: 1683636626

services/convert/convert.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package convert
66

77
import (
8+
"bytes"
89
"context"
910
"fmt"
1011
"net/url"
@@ -34,6 +35,7 @@ import (
3435
"code.gitea.io/gitea/modules/util"
3536
asymkey_service "code.gitea.io/gitea/services/asymkey"
3637
"code.gitea.io/gitea/services/gitdiff"
38+
"github.com/nektos/act/pkg/model"
3739

3840
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
3941
)
@@ -423,9 +425,25 @@ func getActionWorkflowEntry(ctx context.Context, repo *repo_model.Repository, co
423425
createdAt := commit.Author.When
424426
updatedAt := commit.Author.When
425427

428+
content, err := actions.GetContentFromEntry(entry)
429+
name := entry.Name()
430+
if err == nil {
431+
workflow, err := model.ReadWorkflow(bytes.NewReader(content))
432+
if err == nil {
433+
// Only use the name when specified in the workflow file
434+
if workflow.Name != "" {
435+
name = workflow.Name
436+
}
437+
} else {
438+
log.Error("getActionWorkflowEntry: Failed to parse workflow: %v", err)
439+
}
440+
} else {
441+
log.Error("getActionWorkflowEntry: Failed to get content from entry: %v", err)
442+
}
443+
426444
return &api.ActionWorkflow{
427445
ID: entry.Name(),
428-
Name: entry.Name(),
446+
Name: name,
429447
Path: path.Join(folder, entry.Name()),
430448
State: state,
431449
CreatedAt: createdAt,
@@ -464,7 +482,7 @@ func GetActionWorkflow(ctx context.Context, gitrepo *git.Repository, repo *repo_
464482
}
465483

466484
for _, entry := range entries {
467-
if entry.Name == workflowID {
485+
if entry.ID == workflowID {
468486
return entry, nil
469487
}
470488
}

tests/integration/actions_trigger_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,7 @@ func TestWorkflowDispatchPublicApi(t *testing.T) {
719719
{
720720
Operation: "create",
721721
TreePath: ".gitea/workflows/dispatch.yml",
722-
ContentReader: strings.NewReader(`name: test
722+
ContentReader: strings.NewReader(`
723723
on:
724724
workflow_dispatch
725725
jobs:
@@ -799,7 +799,7 @@ func TestWorkflowDispatchPublicApiWithInputs(t *testing.T) {
799799
{
800800
Operation: "create",
801801
TreePath: ".gitea/workflows/dispatch.yml",
802-
ContentReader: strings.NewReader(`name: test
802+
ContentReader: strings.NewReader(`
803803
on:
804804
workflow_dispatch: { inputs: { myinput: { default: def }, myinput2: { default: def2 }, myinput3: { type: boolean, default: false } } }
805805
jobs:
@@ -890,7 +890,7 @@ func TestWorkflowDispatchPublicApiJSON(t *testing.T) {
890890
{
891891
Operation: "create",
892892
TreePath: ".gitea/workflows/dispatch.yml",
893-
ContentReader: strings.NewReader(`name: test
893+
ContentReader: strings.NewReader(`
894894
on:
895895
workflow_dispatch: { inputs: { myinput: { default: def }, myinput2: { default: def2 }, myinput3: { type: boolean, default: false } } }
896896
jobs:
@@ -976,7 +976,7 @@ func TestWorkflowDispatchPublicApiWithInputsJSON(t *testing.T) {
976976
{
977977
Operation: "create",
978978
TreePath: ".gitea/workflows/dispatch.yml",
979-
ContentReader: strings.NewReader(`name: test
979+
ContentReader: strings.NewReader(`
980980
on:
981981
workflow_dispatch: { inputs: { myinput: { default: def }, myinput2: { default: def2 }, myinput3: { type: boolean, default: false } } }
982982
jobs:
@@ -1070,7 +1070,7 @@ func TestWorkflowDispatchPublicApiWithInputsNonDefaultBranchJSON(t *testing.T) {
10701070
{
10711071
Operation: "create",
10721072
TreePath: ".gitea/workflows/dispatch.yml",
1073-
ContentReader: strings.NewReader(`name: test
1073+
ContentReader: strings.NewReader(`
10741074
on:
10751075
workflow_dispatch
10761076
jobs:
@@ -1106,7 +1106,7 @@ jobs:
11061106
{
11071107
Operation: "update",
11081108
TreePath: ".gitea/workflows/dispatch.yml",
1109-
ContentReader: strings.NewReader(`name: test
1109+
ContentReader: strings.NewReader(`
11101110
on:
11111111
workflow_dispatch: { inputs: { myinput: { default: def }, myinput2: { default: def2 }, myinput3: { type: boolean, default: false } } }
11121112
jobs:
@@ -1207,7 +1207,7 @@ func TestWorkflowApi(t *testing.T) {
12071207
{
12081208
Operation: "create",
12091209
TreePath: ".gitea/workflows/dispatch.yml",
1210-
ContentReader: strings.NewReader(`name: test
1210+
ContentReader: strings.NewReader(`
12111211
on:
12121212
workflow_dispatch: { inputs: { myinput: { default: def }, myinput2: { default: def2 }, myinput3: { type: boolean, default: false } } }
12131213
jobs:

tests/integration/repo_webhook_test.go

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,3 +749,204 @@ jobs:
749749
assert.Len(t, payloads[6].WorkflowJob.Steps, 2)
750750
})
751751
}
752+
753+
type workflowRunWebhook struct {
754+
URL string
755+
payloads []api.WorkflowRunPayload
756+
triggeredEvent string
757+
}
758+
759+
func Test_WebhookWorkflowRun(t *testing.T) {
760+
webhookData := &workflowRunWebhook{}
761+
provider := newMockWebhookProvider(func(r *http.Request) {
762+
assert.Contains(t, r.Header["X-Github-Event-Type"], "workflow_run", "X-GitHub-Event-Type should contain workflow_run")
763+
assert.Contains(t, r.Header["X-Gitea-Event-Type"], "workflow_run", "X-Gitea-Event-Type should contain workflow_run")
764+
assert.Contains(t, r.Header["X-Gogs-Event-Type"], "workflow_run", "X-Gogs-Event-Type should contain workflow_run")
765+
content, _ := io.ReadAll(r.Body)
766+
var payload api.WorkflowRunPayload
767+
err := json.Unmarshal(content, &payload)
768+
assert.NoError(t, err)
769+
webhookData.payloads = append(webhookData.payloads, payload)
770+
webhookData.triggeredEvent = "workflow_run"
771+
}, http.StatusOK)
772+
defer provider.Close()
773+
webhookData.URL = provider.URL()
774+
775+
tests := []struct {
776+
name string
777+
callback func(t *testing.T, webhookData *workflowRunWebhook)
778+
}{
779+
{
780+
name: "WorkflowRun",
781+
callback: testWebhookWorkflowRun,
782+
},
783+
{
784+
name: "WorkflowRunDepthLimit",
785+
callback: testWebhookWorkflowRunDepthLimit,
786+
},
787+
}
788+
for _, test := range tests {
789+
t.Run(test.name, func(t *testing.T) {
790+
webhookData.payloads = nil
791+
webhookData.triggeredEvent = ""
792+
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
793+
test.callback(t, webhookData)
794+
})
795+
})
796+
}
797+
}
798+
799+
func testWebhookWorkflowRun(t *testing.T, webhookData *workflowRunWebhook) {
800+
// 1. create a new webhook with special webhook for repo1
801+
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
802+
session := loginUser(t, "user2")
803+
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
804+
805+
testAPICreateWebhookForRepo(t, session, "user2", "repo1", webhookData.URL, "workflow_run")
806+
807+
repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1})
808+
809+
gitRepo1, err := gitrepo.OpenRepository(t.Context(), repo1)
810+
assert.NoError(t, err)
811+
812+
runner := newMockRunner()
813+
runner.registerAsRepoRunner(t, "user2", "repo1", "mock-runner", []string{"ubuntu-latest"}, false)
814+
815+
// 2.1 add workflow_run workflow file to the repo
816+
817+
opts := getWorkflowCreateFileOptions(user2, repo1.DefaultBranch, "create "+"dispatch.yml", `
818+
on:
819+
workflow_run:
820+
workflows: ["Push"]
821+
types:
822+
- completed
823+
jobs:
824+
dispatch:
825+
runs-on: ubuntu-latest
826+
steps:
827+
- run: echo 'test the webhook'
828+
`)
829+
createWorkflowFile(t, token, "user2", "repo1", ".gitea/workflows/dispatch.yml", opts)
830+
831+
// 2.2 trigger the webhooks
832+
833+
// add workflow file to the repo
834+
// init the workflow
835+
wfTreePath := ".gitea/workflows/push.yml"
836+
wfFileContent := `name: Push
837+
on: push
838+
jobs:
839+
wf1-job:
840+
runs-on: ubuntu-latest
841+
steps:
842+
- run: echo 'test the webhook'
843+
wf2-job:
844+
runs-on: ubuntu-latest
845+
needs: wf1-job
846+
steps:
847+
- run: echo 'cmd 1'
848+
- run: echo 'cmd 2'
849+
`
850+
opts = getWorkflowCreateFileOptions(user2, repo1.DefaultBranch, "create "+wfTreePath, wfFileContent)
851+
createWorkflowFile(t, token, "user2", "repo1", wfTreePath, opts)
852+
853+
commitID, err := gitRepo1.GetBranchCommitID(repo1.DefaultBranch)
854+
assert.NoError(t, err)
855+
856+
// 3. validate the webhook is triggered
857+
assert.Equal(t, "workflow_run", webhookData.triggeredEvent)
858+
assert.Len(t, webhookData.payloads, 1)
859+
assert.Equal(t, "requested", webhookData.payloads[0].Action)
860+
assert.Equal(t, "queued", webhookData.payloads[0].WorkflowRun.Status)
861+
assert.Equal(t, repo1.DefaultBranch, webhookData.payloads[0].WorkflowRun.HeadBranch)
862+
assert.Equal(t, commitID, webhookData.payloads[0].WorkflowRun.HeadSha)
863+
assert.Equal(t, "repo1", webhookData.payloads[0].Repo.Name)
864+
assert.Equal(t, "user2/repo1", webhookData.payloads[0].Repo.FullName)
865+
866+
// 4. Execute two Jobs
867+
task := runner.fetchTask(t)
868+
outcome := &mockTaskOutcome{
869+
result: runnerv1.Result_RESULT_SUCCESS,
870+
execTime: time.Millisecond,
871+
}
872+
runner.execTask(t, task, outcome)
873+
874+
task = runner.fetchTask(t)
875+
outcome = &mockTaskOutcome{
876+
result: runnerv1.Result_RESULT_FAILURE,
877+
execTime: time.Millisecond,
878+
}
879+
runner.execTask(t, task, outcome)
880+
881+
// 7. validate the webhook is triggered
882+
assert.Equal(t, "workflow_run", webhookData.triggeredEvent)
883+
assert.Len(t, webhookData.payloads, 3)
884+
assert.Equal(t, "completed", webhookData.payloads[1].Action)
885+
assert.Equal(t, "push", webhookData.payloads[1].WorkflowRun.Event)
886+
887+
// 3. validate the webhook is triggered
888+
assert.Equal(t, "workflow_run", webhookData.triggeredEvent)
889+
assert.Len(t, webhookData.payloads, 3)
890+
assert.Equal(t, "requested", webhookData.payloads[2].Action)
891+
assert.Equal(t, "queued", webhookData.payloads[2].WorkflowRun.Status)
892+
assert.Equal(t, "workflow_run", webhookData.payloads[2].WorkflowRun.Event)
893+
assert.Equal(t, repo1.DefaultBranch, webhookData.payloads[2].WorkflowRun.HeadBranch)
894+
assert.Equal(t, commitID, webhookData.payloads[2].WorkflowRun.HeadSha)
895+
assert.Equal(t, "repo1", webhookData.payloads[2].Repo.Name)
896+
assert.Equal(t, "user2/repo1", webhookData.payloads[2].Repo.FullName)
897+
}
898+
899+
func testWebhookWorkflowRunDepthLimit(t *testing.T, webhookData *workflowRunWebhook) {
900+
// 1. create a new webhook with special webhook for repo1
901+
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
902+
session := loginUser(t, "user2")
903+
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
904+
905+
testAPICreateWebhookForRepo(t, session, "user2", "repo1", webhookData.URL, "workflow_run")
906+
907+
repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1})
908+
909+
gitRepo1, err := gitrepo.OpenRepository(t.Context(), repo1)
910+
assert.NoError(t, err)
911+
912+
// 2. trigger the webhooks
913+
914+
// add workflow file to the repo
915+
// init the workflow
916+
wfTreePath := ".gitea/workflows/push.yml"
917+
wfFileContent := `name: Endless Loop
918+
on:
919+
push:
920+
workflow_run:
921+
types:
922+
- requested
923+
jobs:
924+
dispatch:
925+
runs-on: ubuntu-latest
926+
steps:
927+
- run: echo 'test the webhook'
928+
`
929+
opts := getWorkflowCreateFileOptions(user2, repo1.DefaultBranch, "create "+wfTreePath, wfFileContent)
930+
createWorkflowFile(t, token, "user2", "repo1", wfTreePath, opts)
931+
932+
commitID, err := gitRepo1.GetBranchCommitID(repo1.DefaultBranch)
933+
assert.NoError(t, err)
934+
935+
// 3. validate the webhook is triggered
936+
assert.Equal(t, "workflow_run", webhookData.triggeredEvent)
937+
// 1x push + 5x workflow_run requested chain
938+
assert.Len(t, webhookData.payloads, 6)
939+
for i := 0; i < 6; i++ {
940+
assert.Equal(t, "requested", webhookData.payloads[i].Action)
941+
assert.Equal(t, "queued", webhookData.payloads[i].WorkflowRun.Status)
942+
assert.Equal(t, repo1.DefaultBranch, webhookData.payloads[i].WorkflowRun.HeadBranch)
943+
assert.Equal(t, commitID, webhookData.payloads[i].WorkflowRun.HeadSha)
944+
if i == 0 {
945+
assert.Equal(t, "push", webhookData.payloads[i].WorkflowRun.Event)
946+
} else {
947+
assert.Equal(t, "workflow_run", webhookData.payloads[i].WorkflowRun.Event)
948+
}
949+
assert.Equal(t, "repo1", webhookData.payloads[i].Repo.Name)
950+
assert.Equal(t, "user2/repo1", webhookData.payloads[i].Repo.FullName)
951+
}
952+
}

0 commit comments

Comments
 (0)