mirror of https://github.com/go-gitea/gitea.git
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.
1745 lines
62 KiB
1745 lines
62 KiB
// Copyright 2024 The Gitea Authors. All rights reserved. |
|
// SPDX-License-Identifier: MIT |
|
|
|
package integration |
|
|
|
import ( |
|
"fmt" |
|
"io" |
|
"net/http" |
|
"net/http/httptest" |
|
"net/url" |
|
"path" |
|
"strings" |
|
"testing" |
|
"time" |
|
|
|
auth_model "code.gitea.io/gitea/models/auth" |
|
"code.gitea.io/gitea/models/perm" |
|
"code.gitea.io/gitea/models/repo" |
|
"code.gitea.io/gitea/models/unittest" |
|
user_model "code.gitea.io/gitea/models/user" |
|
"code.gitea.io/gitea/models/webhook" |
|
"code.gitea.io/gitea/modules/commitstatus" |
|
"code.gitea.io/gitea/modules/git" |
|
"code.gitea.io/gitea/modules/gitrepo" |
|
"code.gitea.io/gitea/modules/json" |
|
"code.gitea.io/gitea/modules/setting" |
|
api "code.gitea.io/gitea/modules/structs" |
|
"code.gitea.io/gitea/modules/test" |
|
webhook_module "code.gitea.io/gitea/modules/webhook" |
|
"code.gitea.io/gitea/services/actions" |
|
"code.gitea.io/gitea/tests" |
|
|
|
runnerv1 "code.gitea.io/actions-proto-go/runner/v1" |
|
"github.com/PuerkitoBio/goquery" |
|
"github.com/stretchr/testify/assert" |
|
"github.com/stretchr/testify/require" |
|
) |
|
|
|
func TestNewWebHookLink(t *testing.T) { |
|
defer tests.PrepareTestEnv(t)() |
|
session := loginUser(t, "user2") |
|
|
|
baseurl := "/user2/repo1/settings/hooks" |
|
tests := []string{ |
|
// webhook list page |
|
baseurl, |
|
// new webhook page |
|
baseurl + "/gitea/new", |
|
// edit webhook page |
|
baseurl + "/1", |
|
} |
|
|
|
for _, url := range tests { |
|
resp := session.MakeRequest(t, NewRequest(t, "GET", url), http.StatusOK) |
|
htmlDoc := NewHTMLParser(t, resp.Body) |
|
menus := htmlDoc.doc.Find(".ui.top.attached.header .ui.dropdown .menu a") |
|
menus.Each(func(i int, menu *goquery.Selection) { |
|
url, exist := menu.Attr("href") |
|
assert.True(t, exist) |
|
assert.True(t, strings.HasPrefix(url, baseurl)) |
|
}) |
|
} |
|
} |
|
|
|
func testAPICreateWebhookForRepo(t *testing.T, session *TestSession, userName, repoName, url, event string, branchFilter ...string) { |
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeAll) |
|
var branchFilterString string |
|
if len(branchFilter) > 0 { |
|
branchFilterString = branchFilter[0] |
|
} |
|
req := NewRequestWithJSON(t, "POST", "/api/v1/repos/"+userName+"/"+repoName+"/hooks", api.CreateHookOption{ |
|
Type: "gitea", |
|
Config: api.CreateHookOptionConfig{ |
|
"content_type": "json", |
|
"url": url, |
|
}, |
|
Events: []string{event}, |
|
Active: true, |
|
BranchFilter: branchFilterString, |
|
}).AddTokenAuth(token) |
|
MakeRequest(t, req, http.StatusCreated) |
|
} |
|
|
|
func testCreateWebhookForRepo(t *testing.T, session *TestSession, webhookType, userName, repoName, url, eventKind string) { |
|
csrf := GetUserCSRFToken(t, session) |
|
req := NewRequestWithValues(t, "POST", "/"+userName+"/"+repoName+"/settings/hooks/"+webhookType+"/new", map[string]string{ |
|
"_csrf": csrf, |
|
"payload_url": url, |
|
"events": eventKind, |
|
"active": "true", |
|
"content_type": fmt.Sprintf("%d", webhook.ContentTypeJSON), |
|
"http_method": "POST", |
|
}) |
|
session.MakeRequest(t, req, http.StatusSeeOther) |
|
} |
|
|
|
func testAPICreateWebhookForOrg(t *testing.T, session *TestSession, userName, url, event string) { |
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeAll) |
|
req := NewRequestWithJSON(t, "POST", "/api/v1/orgs/"+userName+"/hooks", api.CreateHookOption{ |
|
Type: "gitea", |
|
Config: api.CreateHookOptionConfig{ |
|
"content_type": "json", |
|
"url": url, |
|
}, |
|
Events: []string{event}, |
|
Active: true, |
|
}).AddTokenAuth(token) |
|
MakeRequest(t, req, http.StatusCreated) |
|
} |
|
|
|
type mockWebhookProvider struct { |
|
server *httptest.Server |
|
} |
|
|
|
func newMockWebhookProvider(callback func(r *http.Request), status int) *mockWebhookProvider { |
|
m := &mockWebhookProvider{} |
|
m.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
callback(r) |
|
w.WriteHeader(status) |
|
})) |
|
return m |
|
} |
|
|
|
func (m *mockWebhookProvider) URL() string { |
|
if m.server == nil { |
|
return "" |
|
} |
|
return m.server.URL |
|
} |
|
|
|
// Close closes the mock webhook http server |
|
func (m *mockWebhookProvider) Close() { |
|
if m.server != nil { |
|
m.server.Close() |
|
m.server = nil |
|
} |
|
} |
|
|
|
func Test_WebhookCreate(t *testing.T) { |
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { |
|
var payloads []api.CreatePayload |
|
var triggeredEvent string |
|
provider := newMockWebhookProvider(func(r *http.Request) { |
|
content, _ := io.ReadAll(r.Body) |
|
var payload api.CreatePayload |
|
err := json.Unmarshal(content, &payload) |
|
assert.NoError(t, err) |
|
payloads = append(payloads, payload) |
|
triggeredEvent = string(webhook_module.HookEventCreate) |
|
}, http.StatusOK) |
|
defer provider.Close() |
|
|
|
// 1. create a new webhook with special webhook for repo1 |
|
session := loginUser(t, "user2") |
|
|
|
testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "create") |
|
|
|
// 2. trigger the webhook |
|
testAPICreateBranch(t, session, "user2", "repo1", "master", "master2", http.StatusCreated) |
|
|
|
// 3. validate the webhook is triggered |
|
assert.Len(t, payloads, 1) |
|
assert.Equal(t, string(webhook_module.HookEventCreate), triggeredEvent) |
|
assert.Equal(t, "repo1", payloads[0].Repo.Name) |
|
assert.Equal(t, "user2/repo1", payloads[0].Repo.FullName) |
|
assert.Equal(t, "master2", payloads[0].Ref) |
|
assert.Equal(t, "branch", payloads[0].RefType) |
|
}) |
|
} |
|
|
|
func Test_WebhookDelete(t *testing.T) { |
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { |
|
var payloads []api.DeletePayload |
|
var triggeredEvent string |
|
provider := newMockWebhookProvider(func(r *http.Request) { |
|
content, _ := io.ReadAll(r.Body) |
|
var payload api.DeletePayload |
|
err := json.Unmarshal(content, &payload) |
|
assert.NoError(t, err) |
|
payloads = append(payloads, payload) |
|
triggeredEvent = "delete" |
|
}, http.StatusOK) |
|
defer provider.Close() |
|
|
|
// 1. create a new webhook with special webhook for repo1 |
|
session := loginUser(t, "user2") |
|
|
|
testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "delete") |
|
|
|
// 2. trigger the webhook |
|
testAPICreateBranch(t, session, "user2", "repo1", "master", "master2", http.StatusCreated) |
|
testAPIDeleteBranch(t, "master2", http.StatusNoContent) |
|
|
|
// 3. validate the webhook is triggered |
|
assert.Equal(t, "delete", triggeredEvent) |
|
assert.Len(t, payloads, 1) |
|
assert.Equal(t, "repo1", payloads[0].Repo.Name) |
|
assert.Equal(t, "user2/repo1", payloads[0].Repo.FullName) |
|
assert.Equal(t, "master2", payloads[0].Ref) |
|
assert.Equal(t, "branch", payloads[0].RefType) |
|
}) |
|
} |
|
|
|
func Test_WebhookFork(t *testing.T) { |
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { |
|
var payloads []api.ForkPayload |
|
var triggeredEvent string |
|
provider := newMockWebhookProvider(func(r *http.Request) { |
|
content, _ := io.ReadAll(r.Body) |
|
var payload api.ForkPayload |
|
err := json.Unmarshal(content, &payload) |
|
assert.NoError(t, err) |
|
payloads = append(payloads, payload) |
|
triggeredEvent = "fork" |
|
}, http.StatusOK) |
|
defer provider.Close() |
|
|
|
// 1. create a new webhook with special webhook for repo1 |
|
session := loginUser(t, "user1") |
|
|
|
testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "fork") |
|
|
|
// 2. trigger the webhook |
|
testRepoFork(t, session, "user2", "repo1", "user1", "repo1-fork", "master") |
|
|
|
// 3. validate the webhook is triggered |
|
assert.Equal(t, "fork", triggeredEvent) |
|
assert.Len(t, payloads, 1) |
|
assert.Equal(t, "repo1-fork", payloads[0].Repo.Name) |
|
assert.Equal(t, "user1/repo1-fork", payloads[0].Repo.FullName) |
|
assert.Equal(t, "repo1", payloads[0].Forkee.Name) |
|
assert.Equal(t, "user2/repo1", payloads[0].Forkee.FullName) |
|
}) |
|
} |
|
|
|
func Test_WebhookIssueComment(t *testing.T) { |
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { |
|
var payloads []api.IssueCommentPayload |
|
var triggeredEvent string |
|
provider := newMockWebhookProvider(func(r *http.Request) { |
|
content, _ := io.ReadAll(r.Body) |
|
var payload api.IssueCommentPayload |
|
err := json.Unmarshal(content, &payload) |
|
assert.NoError(t, err) |
|
payloads = append(payloads, payload) |
|
triggeredEvent = "issue_comment" |
|
}, http.StatusOK) |
|
defer provider.Close() |
|
|
|
// 1. create a new webhook with special webhook for repo1 |
|
session := loginUser(t, "user2") |
|
|
|
testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "issue_comment") |
|
|
|
t.Run("create comment", func(t *testing.T) { |
|
// 2. trigger the webhook |
|
issueURL := testNewIssue(t, session, "user2", "repo1", "Title2", "Description2") |
|
testIssueAddComment(t, session, issueURL, "issue title2 comment1", "") |
|
|
|
// 3. validate the webhook is triggered |
|
assert.Equal(t, "issue_comment", triggeredEvent) |
|
assert.Len(t, payloads, 1) |
|
assert.EqualValues(t, "created", payloads[0].Action) |
|
assert.Equal(t, "repo1", payloads[0].Issue.Repo.Name) |
|
assert.Equal(t, "user2/repo1", payloads[0].Issue.Repo.FullName) |
|
assert.Equal(t, "Title2", payloads[0].Issue.Title) |
|
assert.Equal(t, "Description2", payloads[0].Issue.Body) |
|
assert.Equal(t, "issue title2 comment1", payloads[0].Comment.Body) |
|
}) |
|
|
|
t.Run("update comment", func(t *testing.T) { |
|
payloads = make([]api.IssueCommentPayload, 0, 2) |
|
triggeredEvent = "" |
|
|
|
// 2. trigger the webhook |
|
issueURL := testNewIssue(t, session, "user2", "repo1", "Title3", "Description3") |
|
commentID := testIssueAddComment(t, session, issueURL, "issue title3 comment1", "") |
|
modifiedContent := "issue title2 comment1 - modified" |
|
req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/comments/%d", "user2", "repo1", commentID), map[string]string{ |
|
"_csrf": GetUserCSRFToken(t, session), |
|
"content": modifiedContent, |
|
}) |
|
session.MakeRequest(t, req, http.StatusOK) |
|
|
|
// 3. validate the webhook is triggered |
|
assert.Equal(t, "issue_comment", triggeredEvent) |
|
assert.Len(t, payloads, 2) |
|
assert.EqualValues(t, "edited", payloads[1].Action) |
|
assert.Equal(t, "repo1", payloads[1].Issue.Repo.Name) |
|
assert.Equal(t, "user2/repo1", payloads[1].Issue.Repo.FullName) |
|
assert.Equal(t, "Title3", payloads[1].Issue.Title) |
|
assert.Equal(t, "Description3", payloads[1].Issue.Body) |
|
assert.Equal(t, modifiedContent, payloads[1].Comment.Body) |
|
}) |
|
|
|
t.Run("Update comment with no content change", func(t *testing.T) { |
|
payloads = make([]api.IssueCommentPayload, 0, 2) |
|
triggeredEvent = "" |
|
commentContent := "issue title3 comment1" |
|
|
|
// 2. trigger the webhook |
|
issueURL := testNewIssue(t, session, "user2", "repo1", "Title3", "Description3") |
|
commentID := testIssueAddComment(t, session, issueURL, commentContent, "") |
|
|
|
payloads = make([]api.IssueCommentPayload, 0, 2) |
|
triggeredEvent = "" |
|
req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/comments/%d", "user2", "repo1", commentID), map[string]string{ |
|
"_csrf": GetUserCSRFToken(t, session), |
|
"content": commentContent, |
|
}) |
|
session.MakeRequest(t, req, http.StatusOK) |
|
|
|
// 3. validate the webhook is not triggered because no content change |
|
assert.Empty(t, triggeredEvent) |
|
assert.Empty(t, payloads) |
|
}) |
|
}) |
|
} |
|
|
|
func Test_WebhookRelease(t *testing.T) { |
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { |
|
var payloads []api.ReleasePayload |
|
var triggeredEvent string |
|
provider := newMockWebhookProvider(func(r *http.Request) { |
|
content, _ := io.ReadAll(r.Body) |
|
var payload api.ReleasePayload |
|
err := json.Unmarshal(content, &payload) |
|
assert.NoError(t, err) |
|
payloads = append(payloads, payload) |
|
triggeredEvent = "release" |
|
}, http.StatusOK) |
|
defer provider.Close() |
|
|
|
// 1. create a new webhook with special webhook for repo1 |
|
session := loginUser(t, "user2") |
|
|
|
testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "release") |
|
|
|
// 2. trigger the webhook |
|
createNewRelease(t, session, "/user2/repo1", "v0.0.99", "v0.0.99", false, false) |
|
|
|
// 3. validate the webhook is triggered |
|
assert.Equal(t, "release", triggeredEvent) |
|
assert.Len(t, payloads, 1) |
|
assert.Equal(t, "repo1", payloads[0].Repository.Name) |
|
assert.Equal(t, "user2/repo1", payloads[0].Repository.FullName) |
|
assert.Equal(t, "v0.0.99", payloads[0].Release.TagName) |
|
assert.False(t, payloads[0].Release.IsDraft) |
|
assert.False(t, payloads[0].Release.IsPrerelease) |
|
}) |
|
} |
|
|
|
func Test_WebhookPush(t *testing.T) { |
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { |
|
var payloads []api.PushPayload |
|
var triggeredEvent string |
|
provider := newMockWebhookProvider(func(r *http.Request) { |
|
content, _ := io.ReadAll(r.Body) |
|
var payload api.PushPayload |
|
err := json.Unmarshal(content, &payload) |
|
assert.NoError(t, err) |
|
payloads = append(payloads, payload) |
|
triggeredEvent = "push" |
|
}, http.StatusOK) |
|
defer provider.Close() |
|
|
|
// 1. create a new webhook with special webhook for repo1 |
|
session := loginUser(t, "user2") |
|
|
|
testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "push") |
|
|
|
// 2. trigger the webhook |
|
testCreateFile(t, session, "user2", "repo1", "master", "", "test_webhook_push.md", "# a test file for webhook push") |
|
|
|
// 3. validate the webhook is triggered |
|
assert.Equal(t, "push", triggeredEvent) |
|
assert.Len(t, payloads, 1) |
|
assert.Equal(t, "repo1", payloads[0].Repo.Name) |
|
assert.Equal(t, "user2/repo1", payloads[0].Repo.FullName) |
|
assert.Len(t, payloads[0].Commits, 1) |
|
assert.Equal(t, []string{"test_webhook_push.md"}, payloads[0].Commits[0].Added) |
|
}) |
|
} |
|
|
|
func Test_WebhookPushDevBranch(t *testing.T) { |
|
var payloads []api.PushPayload |
|
var triggeredEvent string |
|
provider := newMockWebhookProvider(func(r *http.Request) { |
|
content, _ := io.ReadAll(r.Body) |
|
var payload api.PushPayload |
|
err := json.Unmarshal(content, &payload) |
|
assert.NoError(t, err) |
|
payloads = append(payloads, payload) |
|
triggeredEvent = "push" |
|
}, http.StatusOK) |
|
defer provider.Close() |
|
|
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { |
|
// 1. create a new webhook with special webhook for repo1 |
|
session := loginUser(t, "user2") |
|
|
|
// only for dev branch |
|
testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "push", "develop") |
|
|
|
// 2. this should not trigger the webhook |
|
testCreateFile(t, session, "user2", "repo1", "master", "", "test_webhook_push.md", "# a test file for webhook push") |
|
assert.Empty(t, triggeredEvent) |
|
assert.Empty(t, payloads) |
|
|
|
repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1}) |
|
gitRepo, err := gitrepo.OpenRepository(t.Context(), repo1) |
|
assert.NoError(t, err) |
|
defer gitRepo.Close() |
|
|
|
beforeCommitID, err := gitRepo.GetBranchCommitID("develop") |
|
assert.NoError(t, err) |
|
|
|
// 3. trigger the webhook |
|
testCreateFile(t, session, "user2", "repo1", "develop", "", "test_webhook_push.md", "# a test file for webhook push") |
|
|
|
afterCommitID, err := gitRepo.GetBranchCommitID("develop") |
|
assert.NoError(t, err) |
|
|
|
// 4. validate the webhook is triggered |
|
assert.Equal(t, "push", triggeredEvent) |
|
assert.Len(t, payloads, 1) |
|
assert.Equal(t, "refs/heads/develop", payloads[0].Ref) |
|
assert.Equal(t, beforeCommitID, payloads[0].Before) |
|
assert.Equal(t, afterCommitID, payloads[0].After) |
|
assert.Equal(t, "repo1", payloads[0].Repo.Name) |
|
assert.Equal(t, "develop", payloads[0].Branch()) |
|
assert.Equal(t, "user2/repo1", payloads[0].Repo.FullName) |
|
assert.Len(t, payloads[0].Commits, 1) |
|
assert.Equal(t, afterCommitID, payloads[0].Commits[0].ID) |
|
assert.Equal(t, setting.AppURL+"user2/repo1/compare/"+beforeCommitID+"..."+afterCommitID, payloads[0].CompareURL) |
|
assert.Equal(t, []string{"test_webhook_push.md"}, payloads[0].Commits[0].Added) |
|
assert.Empty(t, payloads[0].Commits[0].Removed) |
|
}) |
|
} |
|
|
|
func Test_WebhookPushToNewBranch(t *testing.T) { |
|
var payloads []api.PushPayload |
|
var triggeredEvent string |
|
provider := newMockWebhookProvider(func(r *http.Request) { |
|
content, _ := io.ReadAll(r.Body) |
|
var payload api.PushPayload |
|
err := json.Unmarshal(content, &payload) |
|
assert.NoError(t, err) |
|
payloads = append(payloads, payload) |
|
triggeredEvent = "push" |
|
}, http.StatusOK) |
|
defer provider.Close() |
|
|
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { |
|
// 1. create a new webhook with special webhook for repo1 |
|
session := loginUser(t, "user2") |
|
|
|
// only for dev branch |
|
testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "push", "new_branch") |
|
|
|
repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1}) |
|
gitRepo, err := gitrepo.OpenRepository(t.Context(), repo1) |
|
assert.NoError(t, err) |
|
defer gitRepo.Close() |
|
|
|
beforeCommitID, err := gitRepo.GetBranchCommitID("master") |
|
assert.NoError(t, err) |
|
|
|
// 2. trigger the webhook |
|
testCreateFile(t, session, "user2", "repo1", "master", "new_branch", "test_webhook_push.md", "# a new push from new branch") |
|
|
|
afterCommitID, err := gitRepo.GetBranchCommitID("new_branch") |
|
assert.NoError(t, err) |
|
emptyCommitID := git.Sha1ObjectFormat.EmptyObjectID().String() |
|
|
|
// 4. validate the webhook is triggered |
|
assert.Equal(t, "push", triggeredEvent) |
|
assert.Len(t, payloads, 1) |
|
assert.Equal(t, "refs/heads/new_branch", payloads[0].Ref) |
|
assert.Equal(t, emptyCommitID, payloads[0].Before) |
|
assert.Equal(t, afterCommitID, payloads[0].After) |
|
assert.Equal(t, "repo1", payloads[0].Repo.Name) |
|
assert.Equal(t, "new_branch", payloads[0].Branch()) |
|
assert.Equal(t, "user2/repo1", payloads[0].Repo.FullName) |
|
assert.Len(t, payloads[0].Commits, 1) |
|
assert.Equal(t, afterCommitID, payloads[0].Commits[0].ID) |
|
assert.Equal(t, setting.AppURL+"user2/repo1/compare/"+beforeCommitID+"..."+afterCommitID, payloads[0].CompareURL) |
|
assert.Equal(t, []string{"test_webhook_push.md"}, payloads[0].Commits[0].Added) |
|
assert.Empty(t, payloads[0].Commits[0].Removed) |
|
}) |
|
} |
|
|
|
func Test_WebhookIssue(t *testing.T) { |
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { |
|
var payloads []api.IssuePayload |
|
var triggeredEvent string |
|
provider := newMockWebhookProvider(func(r *http.Request) { |
|
content, _ := io.ReadAll(r.Body) |
|
var payload api.IssuePayload |
|
err := json.Unmarshal(content, &payload) |
|
assert.NoError(t, err) |
|
payloads = append(payloads, payload) |
|
triggeredEvent = "issues" |
|
}, http.StatusOK) |
|
defer provider.Close() |
|
|
|
// 1. create a new webhook with special webhook for repo1 |
|
session := loginUser(t, "user2") |
|
|
|
testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "issues") |
|
|
|
// 2. trigger the webhook |
|
testNewIssue(t, session, "user2", "repo1", "Title1", "Description1") |
|
|
|
// 3. validate the webhook is triggered |
|
assert.Equal(t, "issues", triggeredEvent) |
|
assert.Len(t, payloads, 1) |
|
assert.EqualValues(t, "opened", payloads[0].Action) |
|
assert.Equal(t, "repo1", payloads[0].Issue.Repo.Name) |
|
assert.Equal(t, "user2/repo1", payloads[0].Issue.Repo.FullName) |
|
assert.Equal(t, "Title1", payloads[0].Issue.Title) |
|
assert.Equal(t, "Description1", payloads[0].Issue.Body) |
|
assert.Positive(t, payloads[0].Issue.Created.Unix()) |
|
assert.Positive(t, payloads[0].Issue.Updated.Unix()) |
|
}) |
|
} |
|
|
|
func Test_WebhookIssueDelete(t *testing.T) { |
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { |
|
var payloads []api.IssuePayload |
|
var triggeredEvent string |
|
provider := newMockWebhookProvider(func(r *http.Request) { |
|
content, _ := io.ReadAll(r.Body) |
|
var payload api.IssuePayload |
|
err := json.Unmarshal(content, &payload) |
|
assert.NoError(t, err) |
|
payloads = append(payloads, payload) |
|
triggeredEvent = "issue" |
|
}, http.StatusOK) |
|
defer provider.Close() |
|
|
|
// 1. create a new webhook with special webhook for repo1 |
|
session := loginUser(t, "user2") |
|
testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "issues") |
|
issueURL := testNewIssue(t, session, "user2", "repo1", "Title1", "Description1") |
|
|
|
// 2. trigger the webhook |
|
testIssueDelete(t, session, issueURL) |
|
|
|
// 3. validate the webhook is triggered |
|
assert.Equal(t, "issue", triggeredEvent) |
|
require.Len(t, payloads, 2) |
|
assert.EqualValues(t, "deleted", payloads[1].Action) |
|
assert.Equal(t, "repo1", payloads[1].Issue.Repo.Name) |
|
assert.Equal(t, "user2/repo1", payloads[1].Issue.Repo.FullName) |
|
assert.Equal(t, "Title1", payloads[1].Issue.Title) |
|
assert.Equal(t, "Description1", payloads[1].Issue.Body) |
|
}) |
|
} |
|
|
|
func Test_WebhookIssueAssign(t *testing.T) { |
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { |
|
var payloads []api.PullRequestPayload |
|
var triggeredEvent string |
|
provider := newMockWebhookProvider(func(r *http.Request) { |
|
content, _ := io.ReadAll(r.Body) |
|
var payload api.PullRequestPayload |
|
err := json.Unmarshal(content, &payload) |
|
assert.NoError(t, err) |
|
payloads = append(payloads, payload) |
|
triggeredEvent = "pull_request_assign" |
|
}, http.StatusOK) |
|
defer provider.Close() |
|
|
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) |
|
repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1}) |
|
|
|
// 1. create a new webhook with special webhook for repo1 |
|
session := loginUser(t, "user2") |
|
|
|
testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "pull_request_assign") |
|
|
|
// 2. trigger the webhook, issue 2 is a pull request |
|
testIssueAssign(t, session, repo1.Link(), 2, user2.ID) |
|
|
|
// 3. validate the webhook is triggered |
|
assert.Equal(t, "pull_request_assign", triggeredEvent) |
|
assert.Len(t, payloads, 1) |
|
assert.EqualValues(t, "assigned", payloads[0].Action) |
|
assert.Equal(t, "repo1", payloads[0].PullRequest.Base.Repository.Name) |
|
assert.Equal(t, "user2/repo1", payloads[0].PullRequest.Base.Repository.FullName) |
|
assert.Equal(t, "issue2", payloads[0].PullRequest.Title) |
|
assert.Equal(t, "content for the second issue", payloads[0].PullRequest.Body) |
|
assert.Equal(t, user2.ID, payloads[0].PullRequest.Assignee.ID) |
|
}) |
|
} |
|
|
|
func Test_WebhookIssueMilestone(t *testing.T) { |
|
var payloads []api.IssuePayload |
|
var triggeredEvent string |
|
provider := newMockWebhookProvider(func(r *http.Request) { |
|
content, _ := io.ReadAll(r.Body) |
|
var payload api.IssuePayload |
|
err := json.Unmarshal(content, &payload) |
|
assert.NoError(t, err) |
|
payloads = append(payloads, payload) |
|
triggeredEvent = "issues" |
|
}, http.StatusOK) |
|
defer provider.Close() |
|
|
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { |
|
// create a new webhook with special webhook for repo1 |
|
session := loginUser(t, "user2") |
|
repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1}) |
|
testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "issue_milestone") |
|
|
|
t.Run("assign a milestone", func(t *testing.T) { |
|
// trigger the webhook |
|
testIssueChangeMilestone(t, session, repo1.Link(), 1, 1) |
|
|
|
// validate the webhook is triggered |
|
assert.Equal(t, "issues", triggeredEvent) |
|
assert.Len(t, payloads, 1) |
|
assert.Equal(t, "milestoned", string(payloads[0].Action)) |
|
assert.Equal(t, "repo1", payloads[0].Issue.Repo.Name) |
|
assert.Equal(t, "user2/repo1", payloads[0].Issue.Repo.FullName) |
|
assert.Equal(t, "issue1", payloads[0].Issue.Title) |
|
assert.Equal(t, "content for the first issue", payloads[0].Issue.Body) |
|
assert.EqualValues(t, 1, payloads[0].Issue.Milestone.ID) |
|
}) |
|
|
|
t.Run("change a milestong", func(t *testing.T) { |
|
// trigger the webhook again |
|
triggeredEvent = "" |
|
payloads = make([]api.IssuePayload, 0, 1) |
|
// change milestone to 2 |
|
testIssueChangeMilestone(t, session, repo1.Link(), 1, 2) |
|
|
|
// validate the webhook is triggered |
|
assert.Equal(t, "issues", triggeredEvent) |
|
assert.Len(t, payloads, 1) |
|
assert.Equal(t, "milestoned", string(payloads[0].Action)) |
|
assert.Equal(t, "repo1", payloads[0].Issue.Repo.Name) |
|
assert.Equal(t, "user2/repo1", payloads[0].Issue.Repo.FullName) |
|
assert.Equal(t, "issue1", payloads[0].Issue.Title) |
|
assert.Equal(t, "content for the first issue", payloads[0].Issue.Body) |
|
assert.EqualValues(t, 2, payloads[0].Issue.Milestone.ID) |
|
}) |
|
|
|
t.Run("remove a milestone", func(t *testing.T) { |
|
// trigger the webhook again |
|
triggeredEvent = "" |
|
payloads = make([]api.IssuePayload, 0, 1) |
|
// change milestone to 0 |
|
testIssueChangeMilestone(t, session, repo1.Link(), 1, 0) |
|
|
|
// validate the webhook is triggered |
|
assert.Equal(t, "issues", triggeredEvent) |
|
assert.Len(t, payloads, 1) |
|
assert.Equal(t, "demilestoned", string(payloads[0].Action)) |
|
assert.Equal(t, "repo1", payloads[0].Issue.Repo.Name) |
|
assert.Equal(t, "user2/repo1", payloads[0].Issue.Repo.FullName) |
|
assert.Equal(t, "issue1", payloads[0].Issue.Title) |
|
assert.Equal(t, "content for the first issue", payloads[0].Issue.Body) |
|
assert.Nil(t, payloads[0].Issue.Milestone) |
|
}) |
|
}) |
|
} |
|
|
|
func Test_WebhookPullRequest(t *testing.T) { |
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { |
|
var payloads []api.PullRequestPayload |
|
var triggeredEvent string |
|
provider := newMockWebhookProvider(func(r *http.Request) { |
|
content, _ := io.ReadAll(r.Body) |
|
var payload api.PullRequestPayload |
|
err := json.Unmarshal(content, &payload) |
|
assert.NoError(t, err) |
|
payloads = append(payloads, payload) |
|
triggeredEvent = "pull_request" |
|
}, http.StatusOK) |
|
defer provider.Close() |
|
|
|
testCtx := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeAll) |
|
// add user4 as collabrator so that it can be a reviewer |
|
doAPIAddCollaborator(testCtx, "user4", perm.AccessModeWrite)(t) |
|
|
|
// 1. create a new webhook with special webhook for repo1 |
|
sessionUser2 := loginUser(t, "user2") |
|
sessionUser4 := loginUser(t, "user4") |
|
|
|
// ignore the possible review_requested event to keep the test deterministic |
|
testAPICreateWebhookForRepo(t, sessionUser2, "user2", "repo1", provider.URL(), "pull_request_only") |
|
|
|
testAPICreateBranch(t, sessionUser2, "user2", "repo1", "master", "master2", http.StatusCreated) |
|
// 2. trigger the webhook |
|
repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1}) |
|
testPullCreateDirectly(t, sessionUser4, createPullRequestOptions{ |
|
BaseRepoOwner: repo1.OwnerName, |
|
BaseRepoName: repo1.Name, |
|
BaseBranch: repo1.DefaultBranch, |
|
HeadRepoOwner: "", |
|
HeadRepoName: "", |
|
HeadBranch: "master2", |
|
Title: "first pull request", |
|
ReviewerIDs: "2", // add user2 as reviewer |
|
}) |
|
|
|
// 3. validate the webhook is triggered |
|
assert.Equal(t, "pull_request", triggeredEvent) |
|
require.Len(t, payloads, 1) |
|
assert.Equal(t, "repo1", payloads[0].PullRequest.Base.Repository.Name) |
|
assert.Equal(t, "user2/repo1", payloads[0].PullRequest.Base.Repository.FullName) |
|
assert.Equal(t, "repo1", payloads[0].PullRequest.Head.Repository.Name) |
|
assert.Equal(t, "user2/repo1", payloads[0].PullRequest.Head.Repository.FullName) |
|
assert.Equal(t, 0, *payloads[0].PullRequest.Additions) |
|
assert.Equal(t, 0, *payloads[0].PullRequest.ChangedFiles) |
|
assert.Equal(t, 0, *payloads[0].PullRequest.Deletions) |
|
assert.Len(t, payloads[0].PullRequest.RequestedReviewers, 1) |
|
assert.Equal(t, int64(2), payloads[0].PullRequest.RequestedReviewers[0].ID) |
|
}) |
|
} |
|
|
|
func Test_WebhookPullRequestDelete(t *testing.T) { |
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { |
|
var payloads []api.PullRequestPayload |
|
var triggeredEvent string |
|
provider := newMockWebhookProvider(func(r *http.Request) { |
|
content, _ := io.ReadAll(r.Body) |
|
var payload api.PullRequestPayload |
|
err := json.Unmarshal(content, &payload) |
|
assert.NoError(t, err) |
|
payloads = append(payloads, payload) |
|
triggeredEvent = "pull_request" |
|
}, http.StatusOK) |
|
defer provider.Close() |
|
|
|
// 1. create a new webhook with special webhook for repo1 |
|
session := loginUser(t, "user2") |
|
testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "pull_request") |
|
|
|
testAPICreateBranch(t, session, "user2", "repo1", "master", "master2", http.StatusCreated) |
|
|
|
repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1}) |
|
issueURL := testCreatePullToDefaultBranch(t, session, repo1, repo1, "master2", "first pull request") |
|
|
|
// 2. trigger the webhook |
|
testIssueDelete(t, session, path.Join(repo1.Link(), "pulls", issueURL)) |
|
|
|
// 3. validate the webhook is triggered |
|
assert.Equal(t, "pull_request", triggeredEvent) |
|
require.Len(t, payloads, 2) |
|
assert.EqualValues(t, "deleted", payloads[1].Action) |
|
assert.Equal(t, "repo1", payloads[1].PullRequest.Base.Repository.Name) |
|
assert.Equal(t, "user2/repo1", payloads[1].PullRequest.Base.Repository.FullName) |
|
assert.Equal(t, 0, *payloads[1].PullRequest.Additions) |
|
assert.Equal(t, 0, *payloads[1].PullRequest.ChangedFiles) |
|
assert.Equal(t, 0, *payloads[1].PullRequest.Deletions) |
|
}) |
|
} |
|
|
|
func Test_WebhookPullRequestComment(t *testing.T) { |
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { |
|
var payloads []api.IssueCommentPayload |
|
var triggeredEvent string |
|
provider := newMockWebhookProvider(func(r *http.Request) { |
|
content, _ := io.ReadAll(r.Body) |
|
var payload api.IssueCommentPayload |
|
err := json.Unmarshal(content, &payload) |
|
assert.NoError(t, err) |
|
payloads = append(payloads, payload) |
|
triggeredEvent = "pull_request_comment" |
|
}, http.StatusOK) |
|
defer provider.Close() |
|
|
|
// 1. create a new webhook with special webhook for repo1 |
|
session := loginUser(t, "user2") |
|
|
|
testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "pull_request_comment") |
|
|
|
// 2. trigger the webhook |
|
testAPICreateBranch(t, session, "user2", "repo1", "master", "master2", http.StatusCreated) |
|
repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1}) |
|
prID := testCreatePullToDefaultBranch(t, session, repo1, repo1, "master2", "first pull request") |
|
|
|
testIssueAddComment(t, session, "/user2/repo1/pulls/"+prID, "pull title2 comment1", "") |
|
|
|
// 3. validate the webhook is triggered |
|
assert.Equal(t, "pull_request_comment", triggeredEvent) |
|
assert.Len(t, payloads, 1) |
|
assert.EqualValues(t, "created", payloads[0].Action) |
|
assert.Equal(t, "repo1", payloads[0].Issue.Repo.Name) |
|
assert.Equal(t, "user2/repo1", payloads[0].Issue.Repo.FullName) |
|
assert.Equal(t, "first pull request", payloads[0].Issue.Title) |
|
assert.Empty(t, payloads[0].Issue.Body) |
|
assert.Equal(t, "pull title2 comment1", payloads[0].Comment.Body) |
|
}) |
|
} |
|
|
|
func Test_WebhookWiki(t *testing.T) { |
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { |
|
var payloads []api.WikiPayload |
|
var triggeredEvent string |
|
provider := newMockWebhookProvider(func(r *http.Request) { |
|
content, _ := io.ReadAll(r.Body) |
|
var payload api.WikiPayload |
|
err := json.Unmarshal(content, &payload) |
|
assert.NoError(t, err) |
|
payloads = append(payloads, payload) |
|
triggeredEvent = "wiki" |
|
}, http.StatusOK) |
|
defer provider.Close() |
|
|
|
// 1. create a new webhook with special webhook for repo1 |
|
session := loginUser(t, "user2") |
|
|
|
testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "wiki") |
|
|
|
// 2. trigger the webhook |
|
testAPICreateWikiPage(t, session, "user2", "repo1", "Test Wiki Page", http.StatusCreated) |
|
|
|
// 3. validate the webhook is triggered |
|
assert.Equal(t, "wiki", triggeredEvent) |
|
assert.Len(t, payloads, 1) |
|
assert.EqualValues(t, "created", payloads[0].Action) |
|
assert.Equal(t, "repo1", payloads[0].Repository.Name) |
|
assert.Equal(t, "user2/repo1", payloads[0].Repository.FullName) |
|
assert.Equal(t, "Test-Wiki-Page", payloads[0].Page) |
|
}) |
|
} |
|
|
|
func Test_WebhookRepository(t *testing.T) { |
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { |
|
var payloads []api.RepositoryPayload |
|
var triggeredEvent string |
|
provider := newMockWebhookProvider(func(r *http.Request) { |
|
content, _ := io.ReadAll(r.Body) |
|
var payload api.RepositoryPayload |
|
err := json.Unmarshal(content, &payload) |
|
assert.NoError(t, err) |
|
payloads = append(payloads, payload) |
|
triggeredEvent = "repository" |
|
}, http.StatusOK) |
|
defer provider.Close() |
|
|
|
// 1. create a new webhook with special webhook for repo1 |
|
session := loginUser(t, "user1") |
|
|
|
testAPICreateWebhookForOrg(t, session, "org3", provider.URL(), "repository") |
|
|
|
// 2. trigger the webhook |
|
testAPIOrgCreateRepo(t, session, "org3", "repo_new", http.StatusCreated) |
|
|
|
// 3. validate the webhook is triggered |
|
assert.Equal(t, "repository", triggeredEvent) |
|
assert.Len(t, payloads, 1) |
|
assert.EqualValues(t, "created", payloads[0].Action) |
|
assert.Equal(t, "org3", payloads[0].Organization.UserName) |
|
assert.Equal(t, "repo_new", payloads[0].Repository.Name) |
|
assert.Equal(t, "org3/repo_new", payloads[0].Repository.FullName) |
|
}) |
|
} |
|
|
|
func Test_WebhookPackage(t *testing.T) { |
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { |
|
var payloads []api.PackagePayload |
|
var triggeredEvent string |
|
provider := newMockWebhookProvider(func(r *http.Request) { |
|
content, _ := io.ReadAll(r.Body) |
|
var payload api.PackagePayload |
|
err := json.Unmarshal(content, &payload) |
|
assert.NoError(t, err) |
|
payloads = append(payloads, payload) |
|
triggeredEvent = "package" |
|
}, http.StatusOK) |
|
defer provider.Close() |
|
|
|
// 1. create a new webhook with special webhook for repo1 |
|
session := loginUser(t, "user1") |
|
|
|
testAPICreateWebhookForOrg(t, session, "org3", provider.URL(), "package") |
|
|
|
// 2. trigger the webhook |
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeAll) |
|
url := fmt.Sprintf("/api/packages/%s/generic/%s/%s", "org3", "gitea", "v1.24.0") |
|
req := NewRequestWithBody(t, "PUT", url+"/gitea", strings.NewReader("This is a dummy file")). |
|
AddTokenAuth(token) |
|
MakeRequest(t, req, http.StatusCreated) |
|
|
|
// 3. validate the webhook is triggered |
|
assert.Equal(t, "package", triggeredEvent) |
|
assert.Len(t, payloads, 1) |
|
assert.EqualValues(t, "created", payloads[0].Action) |
|
assert.Equal(t, "gitea", payloads[0].Package.Name) |
|
assert.Equal(t, "generic", payloads[0].Package.Type) |
|
assert.Equal(t, "org3", payloads[0].Organization.UserName) |
|
assert.Equal(t, "v1.24.0", payloads[0].Package.Version) |
|
}) |
|
} |
|
|
|
func Test_WebhookStatus(t *testing.T) { |
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { |
|
var payloads []api.CommitStatusPayload |
|
var triggeredEvent string |
|
provider := newMockWebhookProvider(func(r *http.Request) { |
|
assert.Contains(t, r.Header["X-Github-Event-Type"], "status", "X-GitHub-Event-Type should contain status") |
|
assert.Contains(t, r.Header["X-Github-Hook-Installation-Target-Type"], "repository", "X-GitHub-Hook-Installation-Target-Type should contain repository") |
|
assert.Contains(t, r.Header["X-Gitea-Event-Type"], "status", "X-Gitea-Event-Type should contain status") |
|
assert.Contains(t, r.Header["X-Gitea-Hook-Installation-Target-Type"], "repository", "X-Gitea-Hook-Installation-Target-Type should contain repository") |
|
assert.Contains(t, r.Header["X-Gogs-Event-Type"], "status", "X-Gogs-Event-Type should contain status") |
|
content, _ := io.ReadAll(r.Body) |
|
var payload api.CommitStatusPayload |
|
err := json.Unmarshal(content, &payload) |
|
assert.NoError(t, err) |
|
payloads = append(payloads, payload) |
|
triggeredEvent = "status" |
|
}, http.StatusOK) |
|
defer provider.Close() |
|
|
|
// 1. create a new webhook with special webhook for repo1 |
|
session := loginUser(t, "user2") |
|
|
|
testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "status") |
|
|
|
repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1}) |
|
|
|
gitRepo1, err := gitrepo.OpenRepository(t.Context(), repo1) |
|
assert.NoError(t, err) |
|
commitID, err := gitRepo1.GetBranchCommitID(repo1.DefaultBranch) |
|
assert.NoError(t, err) |
|
|
|
// 2. trigger the webhook |
|
testCtx := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeAll) |
|
|
|
// update a status for a commit via API |
|
doAPICreateCommitStatus(testCtx, commitID, api.CreateStatusOption{ |
|
State: commitstatus.CommitStatusSuccess, |
|
TargetURL: "http://test.ci/", |
|
Description: "", |
|
Context: "testci", |
|
})(t) |
|
|
|
// 3. validate the webhook is triggered |
|
assert.Equal(t, "status", triggeredEvent) |
|
assert.Len(t, payloads, 1) |
|
assert.Equal(t, commitID, payloads[0].Commit.ID) |
|
assert.Equal(t, "repo1", payloads[0].Repo.Name) |
|
assert.Equal(t, "user2/repo1", payloads[0].Repo.FullName) |
|
assert.Equal(t, "testci", payloads[0].Context) |
|
assert.Equal(t, commitID, payloads[0].SHA) |
|
}) |
|
} |
|
|
|
func Test_WebhookStatus_NoWrongTrigger(t *testing.T) { |
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { |
|
var trigger string |
|
provider := newMockWebhookProvider(func(r *http.Request) { |
|
assert.NotContains(t, r.Header["X-Github-Event-Type"], "status", "X-GitHub-Event-Type should not contain status") |
|
assert.NotContains(t, r.Header["X-Gitea-Event-Type"], "status", "X-Gitea-Event-Type should not contain status") |
|
assert.NotContains(t, r.Header["X-Gogs-Event-Type"], "status", "X-Gogs-Event-Type should not contain status") |
|
trigger = "push" |
|
}, http.StatusOK) |
|
defer provider.Close() |
|
|
|
// 1. create a new webhook with special webhook for repo1 |
|
session := loginUser(t, "user2") |
|
|
|
// create a push_only webhook from web UI |
|
testCreateWebhookForRepo(t, session, "gitea", "user2", "repo1", provider.URL(), "push_only") |
|
|
|
// 2. trigger the webhook with a push action |
|
testCreateFile(t, session, "user2", "repo1", "master", "", "test_webhook_push.md", "# a test file for webhook push") |
|
|
|
// 3. validate the webhook is triggered with right event |
|
assert.Equal(t, "push", trigger) |
|
}) |
|
} |
|
|
|
func Test_WebhookWorkflowJob(t *testing.T) { |
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { |
|
var payloads []api.WorkflowJobPayload |
|
var triggeredEvent string |
|
provider := newMockWebhookProvider(func(r *http.Request) { |
|
assert.Contains(t, r.Header["X-Github-Event-Type"], "workflow_job", "X-GitHub-Event-Type should contain workflow_job") |
|
assert.Contains(t, r.Header["X-Gitea-Event-Type"], "workflow_job", "X-Gitea-Event-Type should contain workflow_job") |
|
assert.Contains(t, r.Header["X-Gogs-Event-Type"], "workflow_job", "X-Gogs-Event-Type should contain workflow_job") |
|
content, _ := io.ReadAll(r.Body) |
|
var payload api.WorkflowJobPayload |
|
err := json.Unmarshal(content, &payload) |
|
assert.NoError(t, err) |
|
payloads = append(payloads, payload) |
|
triggeredEvent = "workflow_job" |
|
}, http.StatusOK) |
|
defer provider.Close() |
|
|
|
// 1. create a new webhook with special webhook for repo1 |
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) |
|
session := loginUser(t, "user2") |
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) |
|
|
|
testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "workflow_job") |
|
|
|
repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1}) |
|
|
|
gitRepo1, err := gitrepo.OpenRepository(t.Context(), repo1) |
|
assert.NoError(t, err) |
|
|
|
runner := newMockRunner() |
|
runner.registerAsRepoRunner(t, "user2", "repo1", "mock-runner", []string{"ubuntu-latest"}, false) |
|
|
|
// 2. trigger the webhooks |
|
|
|
// add workflow file to the repo |
|
// init the workflow |
|
wfTreePath := ".gitea/workflows/push.yml" |
|
wfFileContent := `name: Push |
|
on: push |
|
jobs: |
|
wf1-job: |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: echo 'test the webhook' |
|
wf2-job: |
|
runs-on: ubuntu-latest |
|
needs: wf1-job |
|
steps: |
|
- run: echo 'cmd 1' |
|
- run: echo 'cmd 2' |
|
` |
|
opts := getWorkflowCreateFileOptions(user2, repo1.DefaultBranch, "create "+wfTreePath, wfFileContent) |
|
createWorkflowFile(t, token, "user2", "repo1", wfTreePath, opts) |
|
|
|
commitID, err := gitRepo1.GetBranchCommitID(repo1.DefaultBranch) |
|
assert.NoError(t, err) |
|
|
|
// 3. validate the webhook is triggered |
|
assert.Equal(t, "workflow_job", triggeredEvent) |
|
assert.Len(t, payloads, 2) |
|
assert.Equal(t, "queued", payloads[0].Action) |
|
assert.Equal(t, "queued", payloads[0].WorkflowJob.Status) |
|
assert.Equal(t, []string{"ubuntu-latest"}, payloads[0].WorkflowJob.Labels) |
|
assert.Equal(t, commitID, payloads[0].WorkflowJob.HeadSha) |
|
assert.Equal(t, "repo1", payloads[0].Repo.Name) |
|
assert.Equal(t, "user2/repo1", payloads[0].Repo.FullName) |
|
|
|
assert.Equal(t, "waiting", payloads[1].Action) |
|
assert.Equal(t, "waiting", payloads[1].WorkflowJob.Status) |
|
assert.Equal(t, commitID, payloads[1].WorkflowJob.HeadSha) |
|
assert.Equal(t, "repo1", payloads[1].Repo.Name) |
|
assert.Equal(t, "user2/repo1", payloads[1].Repo.FullName) |
|
|
|
// 4. Execute a single Job |
|
task := runner.fetchTask(t) |
|
outcome := &mockTaskOutcome{ |
|
result: runnerv1.Result_RESULT_SUCCESS, |
|
} |
|
runner.execTask(t, task, outcome) |
|
|
|
// 5. validate the webhook is triggered |
|
assert.Equal(t, "workflow_job", triggeredEvent) |
|
assert.Len(t, payloads, 5) |
|
assert.Equal(t, "in_progress", payloads[2].Action) |
|
assert.Equal(t, "in_progress", payloads[2].WorkflowJob.Status) |
|
assert.Equal(t, "mock-runner", payloads[2].WorkflowJob.RunnerName) |
|
assert.Equal(t, commitID, payloads[2].WorkflowJob.HeadSha) |
|
assert.Equal(t, "repo1", payloads[2].Repo.Name) |
|
assert.Equal(t, "user2/repo1", payloads[2].Repo.FullName) |
|
|
|
assert.Equal(t, "completed", payloads[3].Action) |
|
assert.Equal(t, "completed", payloads[3].WorkflowJob.Status) |
|
assert.Equal(t, "mock-runner", payloads[3].WorkflowJob.RunnerName) |
|
assert.Equal(t, "success", payloads[3].WorkflowJob.Conclusion) |
|
assert.Equal(t, commitID, payloads[3].WorkflowJob.HeadSha) |
|
assert.Equal(t, "repo1", payloads[3].Repo.Name) |
|
assert.Equal(t, "user2/repo1", payloads[3].Repo.FullName) |
|
assert.Contains(t, payloads[3].WorkflowJob.URL, fmt.Sprintf("/actions/jobs/%d", payloads[3].WorkflowJob.ID)) |
|
assert.Contains(t, payloads[3].WorkflowJob.HTMLURL, fmt.Sprintf("/jobs/%d", 0)) |
|
assert.Len(t, payloads[3].WorkflowJob.Steps, 1) |
|
|
|
assert.Equal(t, "queued", payloads[4].Action) |
|
assert.Equal(t, "queued", payloads[4].WorkflowJob.Status) |
|
assert.Equal(t, []string{"ubuntu-latest"}, payloads[4].WorkflowJob.Labels) |
|
assert.Equal(t, commitID, payloads[4].WorkflowJob.HeadSha) |
|
assert.Equal(t, "repo1", payloads[4].Repo.Name) |
|
assert.Equal(t, "user2/repo1", payloads[4].Repo.FullName) |
|
|
|
// 6. Execute a single Job |
|
task = runner.fetchTask(t) |
|
outcome = &mockTaskOutcome{ |
|
result: runnerv1.Result_RESULT_FAILURE, |
|
} |
|
runner.execTask(t, task, outcome) |
|
|
|
// 7. validate the webhook is triggered |
|
assert.Equal(t, "workflow_job", triggeredEvent) |
|
assert.Len(t, payloads, 7) |
|
assert.Equal(t, "in_progress", payloads[5].Action) |
|
assert.Equal(t, "in_progress", payloads[5].WorkflowJob.Status) |
|
assert.Equal(t, "mock-runner", payloads[5].WorkflowJob.RunnerName) |
|
|
|
assert.Equal(t, commitID, payloads[5].WorkflowJob.HeadSha) |
|
assert.Equal(t, "repo1", payloads[5].Repo.Name) |
|
assert.Equal(t, "user2/repo1", payloads[5].Repo.FullName) |
|
|
|
assert.Equal(t, "completed", payloads[6].Action) |
|
assert.Equal(t, "completed", payloads[6].WorkflowJob.Status) |
|
assert.Equal(t, "failure", payloads[6].WorkflowJob.Conclusion) |
|
assert.Equal(t, "mock-runner", payloads[6].WorkflowJob.RunnerName) |
|
assert.Equal(t, commitID, payloads[6].WorkflowJob.HeadSha) |
|
assert.Equal(t, "repo1", payloads[6].Repo.Name) |
|
assert.Equal(t, "user2/repo1", payloads[6].Repo.FullName) |
|
assert.Contains(t, payloads[6].WorkflowJob.URL, fmt.Sprintf("/actions/jobs/%d", payloads[6].WorkflowJob.ID)) |
|
assert.Contains(t, payloads[6].WorkflowJob.HTMLURL, fmt.Sprintf("/jobs/%d", 1)) |
|
assert.Len(t, payloads[6].WorkflowJob.Steps, 2) |
|
}) |
|
} |
|
|
|
type workflowRunWebhook struct { |
|
URL string |
|
payloads []api.WorkflowRunPayload |
|
triggeredEvent string |
|
} |
|
|
|
func Test_WebhookWorkflowRun(t *testing.T) { |
|
testCases := []struct { |
|
name string |
|
testFunc func(t *testing.T, webhookData *workflowRunWebhook) |
|
}{ |
|
{ |
|
name: "WorkflowRun", |
|
testFunc: testWebhookWorkflowRun, |
|
}, |
|
{ |
|
name: "WorkflowRunDepthLimit", |
|
testFunc: testWebhookWorkflowRunDepthLimit, |
|
}, |
|
{ |
|
name: "WorkflowRunEvents", |
|
testFunc: testWorkflowRunEvents, |
|
}, |
|
{ |
|
name: "WorkflowRunEventsOnRerun", |
|
testFunc: testWorkflowRunEventsOnRerun, |
|
}, |
|
{ |
|
name: "WorkflowRunEventsOnCancellingAbandonedRunAllJobsAbandoned", |
|
testFunc: func(t *testing.T, webhookData *workflowRunWebhook) { |
|
testWorkflowRunEventsOnCancellingAbandonedRun(t, webhookData, true) |
|
}, |
|
}, |
|
{ |
|
name: "WorkflowRunEventsOnCancellingAbandonedRunPartiallyAbandoned", |
|
testFunc: func(t *testing.T, webhookData *workflowRunWebhook) { |
|
testWorkflowRunEventsOnCancellingAbandonedRun(t, webhookData, false) |
|
}, |
|
}, |
|
} |
|
for _, obj := range testCases { |
|
t.Run(obj.name, func(t *testing.T) { |
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { |
|
webhookData := &workflowRunWebhook{} |
|
provider := newMockWebhookProvider(func(r *http.Request) { |
|
assert.Contains(t, r.Header["X-Github-Event-Type"], "workflow_run", "X-GitHub-Event-Type should contain workflow_run") |
|
assert.Contains(t, r.Header["X-Gitea-Event-Type"], "workflow_run", "X-Gitea-Event-Type should contain workflow_run") |
|
assert.Contains(t, r.Header["X-Gogs-Event-Type"], "workflow_run", "X-Gogs-Event-Type should contain workflow_run") |
|
content, _ := io.ReadAll(r.Body) |
|
var payload api.WorkflowRunPayload |
|
err := json.Unmarshal(content, &payload) |
|
assert.NoError(t, err) |
|
webhookData.payloads = append(webhookData.payloads, payload) |
|
webhookData.triggeredEvent = "workflow_run" |
|
}, http.StatusOK) |
|
defer provider.Close() |
|
webhookData.URL = provider.URL() |
|
webhookData.payloads = nil |
|
webhookData.triggeredEvent = "" |
|
obj.testFunc(t, webhookData) |
|
}) |
|
}) |
|
} |
|
} |
|
|
|
func testWorkflowRunEvents(t *testing.T, webhookData *workflowRunWebhook) { |
|
// 1. create a new webhook with special webhook for repo1 |
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) |
|
session := loginUser(t, "user2") |
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) |
|
|
|
testAPICreateWebhookForRepo(t, session, "user2", "repo1", webhookData.URL, "workflow_run") |
|
|
|
repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1}) |
|
|
|
gitRepo1, err := gitrepo.OpenRepository(t.Context(), repo1) |
|
assert.NoError(t, err) |
|
|
|
// 2.2 trigger the webhooks |
|
|
|
// add workflow file to the repo |
|
// init the workflow |
|
wfTreePath := ".gitea/workflows/push.yml" |
|
wfFileContent := `on: |
|
push: |
|
workflow_dispatch: |
|
|
|
jobs: |
|
test: |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: exit 0 |
|
|
|
test2: |
|
needs: [test] |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: exit 0 |
|
|
|
test3: |
|
needs: [test, test2] |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: exit 0 |
|
|
|
test4: |
|
needs: [test, test2, test3] |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: exit 0 |
|
|
|
test5: |
|
needs: [test, test2, test4] |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: exit 0 |
|
|
|
test6: |
|
strategy: |
|
matrix: |
|
os: [ubuntu-20.04, ubuntu-22.04, ubuntu-24.04] |
|
needs: [test, test2, test3] |
|
runs-on: ${{ matrix.os }} |
|
steps: |
|
- run: exit 0 |
|
|
|
test7: |
|
needs: test6 |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: exit 0 |
|
|
|
test8: |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: exit 0 |
|
|
|
test9: |
|
strategy: |
|
matrix: |
|
os: [ubuntu-20.04, ubuntu-22.04, ubuntu-24.04, ubuntu-25.04, windows-2022, windows-2025, macos-13, macos-14, macos-15] |
|
runs-on: ${{ matrix.os }} |
|
steps: |
|
- run: exit 0 |
|
|
|
test10: |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: exit 0` |
|
opts := getWorkflowCreateFileOptions(user2, repo1.DefaultBranch, "create "+wfTreePath, wfFileContent) |
|
createWorkflowFile(t, token, "user2", "repo1", wfTreePath, opts) |
|
|
|
commitID, err := gitRepo1.GetBranchCommitID(repo1.DefaultBranch) |
|
assert.NoError(t, err) |
|
|
|
// 3. validate the webhook is triggered |
|
assert.Equal(t, "workflow_run", webhookData.triggeredEvent) |
|
assert.Len(t, webhookData.payloads, 1) |
|
assert.Equal(t, "requested", webhookData.payloads[0].Action) |
|
assert.Equal(t, "queued", webhookData.payloads[0].WorkflowRun.Status) |
|
assert.Equal(t, repo1.DefaultBranch, webhookData.payloads[0].WorkflowRun.HeadBranch) |
|
assert.Equal(t, commitID, webhookData.payloads[0].WorkflowRun.HeadSha) |
|
assert.Equal(t, "repo1", webhookData.payloads[0].Repo.Name) |
|
assert.Equal(t, "user2/repo1", webhookData.payloads[0].Repo.FullName) |
|
|
|
// Call cancel ui api |
|
// Only a web UI API exists for cancelling workflow runs, so use the UI endpoint. |
|
cancelURL := fmt.Sprintf("/user2/repo1/actions/runs/%d/cancel", webhookData.payloads[0].WorkflowRun.RunNumber) |
|
req := NewRequestWithValues(t, "POST", cancelURL, map[string]string{ |
|
"_csrf": GetUserCSRFToken(t, session), |
|
}) |
|
session.MakeRequest(t, req, http.StatusOK) |
|
|
|
assert.Len(t, webhookData.payloads, 2) |
|
|
|
// 4. Validate the second webhook payload |
|
assert.Equal(t, "workflow_run", webhookData.triggeredEvent) |
|
assert.Equal(t, "completed", webhookData.payloads[1].Action) |
|
assert.Equal(t, "push", webhookData.payloads[1].WorkflowRun.Event) |
|
assert.Equal(t, "completed", webhookData.payloads[1].WorkflowRun.Status) |
|
assert.Equal(t, repo1.DefaultBranch, webhookData.payloads[1].WorkflowRun.HeadBranch) |
|
assert.Equal(t, commitID, webhookData.payloads[1].WorkflowRun.HeadSha) |
|
assert.Equal(t, "repo1", webhookData.payloads[1].Repo.Name) |
|
assert.Equal(t, "user2/repo1", webhookData.payloads[1].Repo.FullName) |
|
} |
|
|
|
func testWorkflowRunEventsOnRerun(t *testing.T, webhookData *workflowRunWebhook) { |
|
// 1. create a new webhook with special webhook for repo1 |
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) |
|
session := loginUser(t, "user2") |
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) |
|
|
|
runners := make([]*mockRunner, 2) |
|
for i := range runners { |
|
runners[i] = newMockRunner() |
|
runners[i].registerAsRepoRunner(t, "user2", "repo1", fmt.Sprintf("mock-runner-%d", i), []string{"ubuntu-latest"}, false) |
|
} |
|
|
|
testAPICreateWebhookForRepo(t, session, "user2", "repo1", webhookData.URL, "workflow_run") |
|
|
|
repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1}) |
|
|
|
gitRepo1, err := gitrepo.OpenRepository(t.Context(), repo1) |
|
assert.NoError(t, err) |
|
|
|
// 2.2 trigger the webhooks |
|
|
|
// add workflow file to the repo |
|
// init the workflow |
|
wfTreePath := ".gitea/workflows/push.yml" |
|
wfFileContent := `on: |
|
push: |
|
workflow_dispatch: |
|
|
|
jobs: |
|
test: |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: exit 0 |
|
|
|
test2: |
|
needs: [test] |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: exit 0 |
|
|
|
test3: |
|
needs: [test, test2] |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: exit 0 |
|
|
|
test4: |
|
needs: [test, test2, test3] |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: exit 0 |
|
|
|
test5: |
|
needs: [test, test2, test4] |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: exit 0 |
|
|
|
test6: |
|
strategy: |
|
matrix: |
|
os: [ubuntu-20.04, ubuntu-22.04, ubuntu-24.04] |
|
needs: [test, test2, test3] |
|
runs-on: ${{ matrix.os }} |
|
steps: |
|
- run: exit 0 |
|
|
|
test7: |
|
needs: test6 |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: exit 0 |
|
|
|
test8: |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: exit 0 |
|
|
|
test9: |
|
strategy: |
|
matrix: |
|
os: [ubuntu-20.04, ubuntu-22.04, ubuntu-24.04, ubuntu-25.04, windows-2022, windows-2025, macos-13, macos-14, macos-15] |
|
runs-on: ${{ matrix.os }} |
|
steps: |
|
- run: exit 0 |
|
|
|
test10: |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: exit 0` |
|
opts := getWorkflowCreateFileOptions(user2, repo1.DefaultBranch, "create "+wfTreePath, wfFileContent) |
|
createWorkflowFile(t, token, "user2", "repo1", wfTreePath, opts) |
|
|
|
commitID, err := gitRepo1.GetBranchCommitID(repo1.DefaultBranch) |
|
assert.NoError(t, err) |
|
|
|
// 3. validate the webhook is triggered |
|
assert.Equal(t, "workflow_run", webhookData.triggeredEvent) |
|
assert.Len(t, webhookData.payloads, 1) |
|
assert.Equal(t, "requested", webhookData.payloads[0].Action) |
|
assert.Equal(t, "queued", webhookData.payloads[0].WorkflowRun.Status) |
|
assert.Equal(t, repo1.DefaultBranch, webhookData.payloads[0].WorkflowRun.HeadBranch) |
|
assert.Equal(t, commitID, webhookData.payloads[0].WorkflowRun.HeadSha) |
|
assert.Equal(t, "repo1", webhookData.payloads[0].Repo.Name) |
|
assert.Equal(t, "user2/repo1", webhookData.payloads[0].Repo.FullName) |
|
|
|
for _, runner := range runners { |
|
task := runner.fetchTask(t) |
|
runner.execTask(t, task, &mockTaskOutcome{ |
|
result: runnerv1.Result_RESULT_SUCCESS, |
|
}) |
|
} |
|
|
|
// Call cancel ui api |
|
// Only a web UI API exists for cancelling workflow runs, so use the UI endpoint. |
|
cancelURL := fmt.Sprintf("/user2/repo1/actions/runs/%d/cancel", webhookData.payloads[0].WorkflowRun.RunNumber) |
|
req := NewRequestWithValues(t, "POST", cancelURL, map[string]string{ |
|
"_csrf": GetUserCSRFToken(t, session), |
|
}) |
|
session.MakeRequest(t, req, http.StatusOK) |
|
|
|
assert.Len(t, webhookData.payloads, 2) |
|
|
|
// 4. Validate the second webhook payload |
|
assert.Equal(t, "workflow_run", webhookData.triggeredEvent) |
|
assert.Equal(t, "completed", webhookData.payloads[1].Action) |
|
assert.Equal(t, "push", webhookData.payloads[1].WorkflowRun.Event) |
|
assert.Equal(t, "completed", webhookData.payloads[1].WorkflowRun.Status) |
|
assert.Equal(t, repo1.DefaultBranch, webhookData.payloads[1].WorkflowRun.HeadBranch) |
|
assert.Equal(t, commitID, webhookData.payloads[1].WorkflowRun.HeadSha) |
|
assert.Equal(t, "repo1", webhookData.payloads[1].Repo.Name) |
|
assert.Equal(t, "user2/repo1", webhookData.payloads[1].Repo.FullName) |
|
|
|
// Call rerun ui api |
|
// Only a web UI API exists for rerunning workflow runs, so use the UI endpoint. |
|
rerunURL := fmt.Sprintf("/user2/repo1/actions/runs/%d/rerun", webhookData.payloads[0].WorkflowRun.RunNumber) |
|
req = NewRequestWithValues(t, "POST", rerunURL, map[string]string{ |
|
"_csrf": GetUserCSRFToken(t, session), |
|
}) |
|
session.MakeRequest(t, req, http.StatusOK) |
|
|
|
assert.Len(t, webhookData.payloads, 3) |
|
|
|
// 5. Validate the third webhook payload |
|
assert.Equal(t, "workflow_run", webhookData.triggeredEvent) |
|
assert.Equal(t, "requested", webhookData.payloads[2].Action) |
|
assert.Equal(t, "queued", webhookData.payloads[2].WorkflowRun.Status) |
|
assert.Equal(t, repo1.DefaultBranch, webhookData.payloads[2].WorkflowRun.HeadBranch) |
|
assert.Equal(t, commitID, webhookData.payloads[2].WorkflowRun.HeadSha) |
|
assert.Equal(t, "repo1", webhookData.payloads[2].Repo.Name) |
|
assert.Equal(t, "user2/repo1", webhookData.payloads[2].Repo.FullName) |
|
} |
|
|
|
func testWorkflowRunEventsOnCancellingAbandonedRun(t *testing.T, webhookData *workflowRunWebhook, allJobsAbandoned bool) { |
|
defer test.MockVariableValue(&setting.Actions.AbandonedJobTimeout, 0*time.Nanosecond)() |
|
|
|
// 1. create a new webhook with special webhook for repo1 |
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) |
|
session := loginUser(t, "user2") |
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) |
|
|
|
repoName := "test-workflow-run-cancelling-abandoned-run" |
|
testRepo := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: createActionsTestRepo(t, token, repoName, false).ID}) |
|
|
|
runners := make([]*mockRunner, 2) |
|
for i := range runners { |
|
runners[i] = newMockRunner() |
|
runners[i].registerAsRepoRunner(t, "user2", repoName, |
|
fmt.Sprintf("mock-runner-%d", i), []string{"ubuntu-latest"}, false) |
|
} |
|
|
|
testAPICreateWebhookForRepo(t, session, "user2", repoName, webhookData.URL, "workflow_run") |
|
|
|
ctx := t.Context() |
|
gitRepo, err := gitrepo.OpenRepository(ctx, testRepo) |
|
assert.NoError(t, err) |
|
|
|
// 2.2 trigger the webhooks |
|
|
|
// add workflow file to the repo |
|
// init the workflow |
|
wfilename := "push.yml" |
|
wfTreePath := ".gitea/workflows/" + wfilename |
|
wfFileContent := `on: |
|
push: |
|
workflow_dispatch: |
|
|
|
jobs: |
|
test: |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: exit 0 |
|
|
|
test2: |
|
needs: [test] |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: exit 0 |
|
|
|
test3: |
|
needs: [test, test2] |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: exit 0 |
|
|
|
test4: |
|
needs: [test, test2, test3] |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: exit 0 |
|
|
|
test5: |
|
needs: [test, test2, test4] |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: exit 0 |
|
|
|
test6: |
|
strategy: |
|
matrix: |
|
os: [ubuntu-20.04, ubuntu-22.04, ubuntu-24.04] |
|
needs: [test, test2, test3] |
|
runs-on: ${{ matrix.os }} |
|
steps: |
|
- run: exit 0 |
|
|
|
test7: |
|
needs: test6 |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: exit 0 |
|
|
|
test8: |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: exit 0 |
|
|
|
test9: |
|
strategy: |
|
matrix: |
|
os: [ubuntu-20.04, ubuntu-22.04, ubuntu-24.04, ubuntu-25.04, windows-2022, windows-2025, macos-13, macos-14, macos-15] |
|
runs-on: ${{ matrix.os }} |
|
steps: |
|
- run: exit 0 |
|
|
|
test10: |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: exit 0` |
|
|
|
opts := getWorkflowCreateFileOptions(user2, testRepo.DefaultBranch, "create "+wfTreePath, wfFileContent) |
|
createWorkflowFile(t, token, "user2", repoName, wfTreePath, opts) |
|
|
|
commitID, err := gitRepo.GetBranchCommitID(testRepo.DefaultBranch) |
|
assert.NoError(t, err) |
|
|
|
// 3. validate the webhook is triggered |
|
assert.Equal(t, "workflow_run", webhookData.triggeredEvent) |
|
assert.Len(t, webhookData.payloads, 1) |
|
assert.Equal(t, "requested", webhookData.payloads[0].Action) |
|
assert.Equal(t, "queued", webhookData.payloads[0].WorkflowRun.Status) |
|
assert.Equal(t, testRepo.DefaultBranch, webhookData.payloads[0].WorkflowRun.HeadBranch) |
|
assert.Equal(t, commitID, webhookData.payloads[0].WorkflowRun.HeadSha) |
|
assert.Equal(t, repoName, webhookData.payloads[0].Repo.Name) |
|
assert.Equal(t, "user2/"+repoName, webhookData.payloads[0].Repo.FullName) |
|
|
|
if !allJobsAbandoned { |
|
for _, runner := range runners { |
|
task := runner.fetchTask(t) |
|
runner.execTask(t, task, &mockTaskOutcome{ |
|
result: runnerv1.Result_RESULT_SUCCESS, |
|
}) |
|
} |
|
} |
|
|
|
// Add this sleep to ensure the func can find the tasks by timestamp. |
|
time.Sleep(time.Second) |
|
|
|
err = actions.CancelAbandonedJobs(ctx) |
|
assert.NoError(t, err) |
|
assert.Len(t, webhookData.payloads, 2) |
|
assert.Equal(t, "completed", webhookData.payloads[1].Action) |
|
assert.Equal(t, "completed", webhookData.payloads[1].WorkflowRun.Status) |
|
assert.Equal(t, testRepo.DefaultBranch, webhookData.payloads[1].WorkflowRun.HeadBranch) |
|
assert.Equal(t, commitID, webhookData.payloads[1].WorkflowRun.HeadSha) |
|
assert.Equal(t, repoName, webhookData.payloads[1].Repo.Name) |
|
assert.Equal(t, "user2/"+repoName, webhookData.payloads[1].Repo.FullName) |
|
} |
|
|
|
func testWebhookWorkflowRun(t *testing.T, webhookData *workflowRunWebhook) { |
|
// 1. create a new webhook with special webhook for repo1 |
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) |
|
session := loginUser(t, "user2") |
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) |
|
|
|
testAPICreateWebhookForRepo(t, session, "user2", "repo1", webhookData.URL, "workflow_run") |
|
|
|
repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1}) |
|
|
|
gitRepo1, err := gitrepo.OpenRepository(t.Context(), repo1) |
|
assert.NoError(t, err) |
|
|
|
runner := newMockRunner() |
|
runner.registerAsRepoRunner(t, "user2", "repo1", "mock-runner", []string{"ubuntu-latest"}, false) |
|
|
|
// 2.1 add workflow_run workflow file to the repo |
|
|
|
opts := getWorkflowCreateFileOptions(user2, repo1.DefaultBranch, "create "+"dispatch.yml", ` |
|
on: |
|
workflow_run: |
|
workflows: ["Push"] |
|
types: |
|
- completed |
|
jobs: |
|
dispatch: |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: echo 'test the webhook' |
|
`) |
|
createWorkflowFile(t, token, "user2", "repo1", ".gitea/workflows/dispatch.yml", opts) |
|
|
|
// 2.2 trigger the webhooks |
|
|
|
// add workflow file to the repo |
|
// init the workflow |
|
wfTreePath := ".gitea/workflows/push.yml" |
|
wfFileContent := `name: Push |
|
on: push |
|
jobs: |
|
wf1-job: |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: echo 'test the webhook' |
|
wf2-job: |
|
runs-on: ubuntu-latest |
|
needs: wf1-job |
|
steps: |
|
- run: echo 'cmd 1' |
|
- run: echo 'cmd 2' |
|
` |
|
opts = getWorkflowCreateFileOptions(user2, repo1.DefaultBranch, "create "+wfTreePath, wfFileContent) |
|
createWorkflowFile(t, token, "user2", "repo1", wfTreePath, opts) |
|
|
|
commitID, err := gitRepo1.GetBranchCommitID(repo1.DefaultBranch) |
|
assert.NoError(t, err) |
|
|
|
// 3. validate the webhook is triggered |
|
assert.Equal(t, "workflow_run", webhookData.triggeredEvent) |
|
assert.Len(t, webhookData.payloads, 1) |
|
assert.Equal(t, "requested", webhookData.payloads[0].Action) |
|
assert.Equal(t, "queued", webhookData.payloads[0].WorkflowRun.Status) |
|
assert.Equal(t, repo1.DefaultBranch, webhookData.payloads[0].WorkflowRun.HeadBranch) |
|
assert.Equal(t, commitID, webhookData.payloads[0].WorkflowRun.HeadSha) |
|
assert.Equal(t, "repo1", webhookData.payloads[0].Repo.Name) |
|
assert.Equal(t, "user2/repo1", webhookData.payloads[0].Repo.FullName) |
|
|
|
// 4. Execute two Jobs |
|
task := runner.fetchTask(t) |
|
outcome := &mockTaskOutcome{ |
|
result: runnerv1.Result_RESULT_SUCCESS, |
|
} |
|
runner.execTask(t, task, outcome) |
|
|
|
task = runner.fetchTask(t) |
|
outcome = &mockTaskOutcome{ |
|
result: runnerv1.Result_RESULT_FAILURE, |
|
} |
|
runner.execTask(t, task, outcome) |
|
|
|
// 7. validate the webhook is triggered |
|
assert.Equal(t, "workflow_run", webhookData.triggeredEvent) |
|
assert.Len(t, webhookData.payloads, 3) |
|
assert.Equal(t, "completed", webhookData.payloads[1].Action) |
|
assert.Equal(t, "push", webhookData.payloads[1].WorkflowRun.Event) |
|
|
|
// 3. validate the webhook is triggered |
|
assert.Equal(t, "workflow_run", webhookData.triggeredEvent) |
|
assert.Len(t, webhookData.payloads, 3) |
|
assert.Equal(t, "requested", webhookData.payloads[2].Action) |
|
assert.Equal(t, "queued", webhookData.payloads[2].WorkflowRun.Status) |
|
assert.Equal(t, "workflow_run", webhookData.payloads[2].WorkflowRun.Event) |
|
assert.Equal(t, repo1.DefaultBranch, webhookData.payloads[2].WorkflowRun.HeadBranch) |
|
assert.Equal(t, commitID, webhookData.payloads[2].WorkflowRun.HeadSha) |
|
assert.Equal(t, "repo1", webhookData.payloads[2].Repo.Name) |
|
assert.Equal(t, "user2/repo1", webhookData.payloads[2].Repo.FullName) |
|
} |
|
|
|
func testWebhookWorkflowRunDepthLimit(t *testing.T, webhookData *workflowRunWebhook) { |
|
// 1. create a new webhook with special webhook for repo1 |
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) |
|
session := loginUser(t, "user2") |
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) |
|
|
|
testAPICreateWebhookForRepo(t, session, "user2", "repo1", webhookData.URL, "workflow_run") |
|
|
|
repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1}) |
|
|
|
gitRepo1, err := gitrepo.OpenRepository(t.Context(), repo1) |
|
assert.NoError(t, err) |
|
|
|
// 2. trigger the webhooks |
|
|
|
// add workflow file to the repo |
|
// init the workflow |
|
wfTreePath := ".gitea/workflows/push.yml" |
|
wfFileContent := `name: Endless Loop |
|
on: |
|
push: |
|
workflow_run: |
|
types: |
|
- requested |
|
jobs: |
|
dispatch: |
|
runs-on: ubuntu-latest |
|
steps: |
|
- run: echo 'test the webhook' |
|
` |
|
opts := getWorkflowCreateFileOptions(user2, repo1.DefaultBranch, "create "+wfTreePath, wfFileContent) |
|
createWorkflowFile(t, token, "user2", "repo1", wfTreePath, opts) |
|
|
|
commitID, err := gitRepo1.GetBranchCommitID(repo1.DefaultBranch) |
|
assert.NoError(t, err) |
|
|
|
// 3. validate the webhook is triggered |
|
assert.Equal(t, "workflow_run", webhookData.triggeredEvent) |
|
// 1x push + 5x workflow_run requested chain |
|
assert.Len(t, webhookData.payloads, 6) |
|
for i := range 6 { |
|
assert.Equal(t, "requested", webhookData.payloads[i].Action) |
|
assert.Equal(t, "queued", webhookData.payloads[i].WorkflowRun.Status) |
|
assert.Equal(t, repo1.DefaultBranch, webhookData.payloads[i].WorkflowRun.HeadBranch) |
|
assert.Equal(t, commitID, webhookData.payloads[i].WorkflowRun.HeadSha) |
|
if i == 0 { |
|
assert.Equal(t, "push", webhookData.payloads[i].WorkflowRun.Event) |
|
} else { |
|
assert.Equal(t, "workflow_run", webhookData.payloads[i].WorkflowRun.Event) |
|
} |
|
assert.Equal(t, "repo1", webhookData.payloads[i].Repo.Name) |
|
assert.Equal(t, "user2/repo1", webhookData.payloads[i].Repo.FullName) |
|
} |
|
}
|
|
|