mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-08-31 06:34:00 +00:00
Actions Failure, Succes, Recover Webhooks (#7508)
Implement Actions Success, Failure and Recover webhooks for Forgejo, Gitea, Gogs, Slack, Discord, DingTalk, Telegram, Microsoft Teams, Feishu / Lark Suite, Matrix, WeCom (Wechat Work), Packagist. Some of these webhooks have not been manually tested. Implement settings for these new webhooks. ## Checklist The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. There also are a few [conditions for merging Pull Requests in Forgejo repositories](https://codeberg.org/forgejo/governance/src/branch/main/PullRequestsAgreement.md). You are also welcome to join the [Forgejo development chatroom](https://matrix.to/#/#forgejo-development:matrix.org). ### Tests - I added test coverage for Go changes... - [x] in their respective `*_test.go` for unit tests. - [x] in the `tests/integration` directory if it involves interactions with a live Forgejo server. - I added test coverage for JavaScript changes... - [ ] in `web_src/js/*.test.js` if it can be unit tested. - [ ] in `tests/e2e/*.test.e2e.js` if it requires interactions with a live Forgejo server (see also the [developer guide for JavaScript testing](https://codeberg.org/forgejo/forgejo/src/branch/forgejo/tests/e2e/README.md#end-to-end-tests)). ### Documentation - [ ] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change. - [x] I did not document these changes and I do not expect someone else to do it. ### Release notes - [ ] I do not want this change to show in the release notes. - [x] I want the title to show in the release notes with a link to this pull request. - [ ] I want the content of the `release-notes/<pull request number>.md` to be be used for the release notes instead of the title. <!--start release-notes-assistant--> ## Release notes <!--URL:https://codeberg.org/forgejo/forgejo--> - Features - [PR](https://codeberg.org/forgejo/forgejo/pulls/7508): <!--number 7508 --><!--line 0 --><!--description QWN0aW9ucyBGYWlsdXJlLCBTdWNjZXMsIFJlY292ZXIgV2ViaG9va3M=-->Actions Failure, Succes, Recover Webhooks<!--description--> <!--end release-notes-assistant--> Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/7508 Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org> Co-authored-by: christopher-besch <mail@chris-besch.com> Co-committed-by: christopher-besch <mail@chris-besch.com>
This commit is contained in:
parent
6ce9d764bc
commit
d17aa98262
27 changed files with 683 additions and 12 deletions
|
@ -207,6 +207,12 @@ func (dc dingtalkConvertor) Package(p *api.PackagePayload) (DingtalkPayload, err
|
|||
return createDingtalkPayload(text, text, "view package", p.Package.HTMLURL), nil
|
||||
}
|
||||
|
||||
func (dc dingtalkConvertor) Action(p *api.ActionPayload) (DingtalkPayload, error) {
|
||||
text, _ := getActionPayloadInfo(p, noneLinkFormatter)
|
||||
|
||||
return createDingtalkPayload(text, text, "view action", p.Run.HTMLURL), nil
|
||||
}
|
||||
|
||||
func createDingtalkPayload(title, text, singleTitle, singleURL string) DingtalkPayload {
|
||||
return DingtalkPayload{
|
||||
MsgType: "actionCard",
|
||||
|
|
|
@ -325,6 +325,12 @@ func (d discordConvertor) Package(p *api.PackagePayload) (DiscordPayload, error)
|
|||
return d.createPayload(p.Sender, text, "", p.Package.HTMLURL, color), nil
|
||||
}
|
||||
|
||||
func (d discordConvertor) Action(p *api.ActionPayload) (DiscordPayload, error) {
|
||||
text, color := getActionPayloadInfo(p, noneLinkFormatter)
|
||||
|
||||
return d.createPayload(p.Run.TriggerUser, text, "", p.Run.HTMLURL, color), nil
|
||||
}
|
||||
|
||||
var _ shared.PayloadConvertor[DiscordPayload] = discordConvertor{}
|
||||
|
||||
func (discordHandler) NewRequest(ctx context.Context, w *webhook_model.Webhook, t *webhook_model.HookTask) (*http.Request, []byte, error) {
|
||||
|
|
|
@ -191,6 +191,12 @@ func (fc feishuConvertor) Package(p *api.PackagePayload) (FeishuPayload, error)
|
|||
return newFeishuTextPayload(text), nil
|
||||
}
|
||||
|
||||
func (fc feishuConvertor) Action(p *api.ActionPayload) (FeishuPayload, error) {
|
||||
text, _ := getActionPayloadInfo(p, noneLinkFormatter)
|
||||
|
||||
return newFeishuTextPayload(text), nil
|
||||
}
|
||||
|
||||
type feishuConvertor struct{}
|
||||
|
||||
var _ shared.PayloadConvertor[FeishuPayload] = feishuConvertor{}
|
||||
|
|
|
@ -304,6 +304,25 @@ func getPackagePayloadInfo(p *api.PackagePayload, linkFormatter linkFormatter, w
|
|||
return text, color
|
||||
}
|
||||
|
||||
func getActionPayloadInfo(p *api.ActionPayload, linkFormatter linkFormatter) (text string, color int) {
|
||||
runLink := linkFormatter(p.Run.HTMLURL, p.Run.Title)
|
||||
repoLink := linkFormatter(p.Run.Repo.HTMLURL, p.Run.Repo.FullName)
|
||||
|
||||
switch p.Action {
|
||||
case api.HookActionFailure:
|
||||
text = fmt.Sprintf("%s Action Failed in %s %s", runLink, repoLink, p.Run.PrettyRef)
|
||||
color = redColor
|
||||
case api.HookActionRecover:
|
||||
text = fmt.Sprintf("%s Action Recovered in %s %s", runLink, repoLink, p.Run.PrettyRef)
|
||||
color = greenColor
|
||||
case api.HookActionSuccess:
|
||||
text = fmt.Sprintf("%s Action Succeeded in %s %s", runLink, repoLink, p.Run.PrettyRef)
|
||||
color = greenColor
|
||||
}
|
||||
|
||||
return text, color
|
||||
}
|
||||
|
||||
// ToHook convert models.Webhook to api.Hook
|
||||
// This function is not part of the convert package to prevent an import cycle
|
||||
func ToHook(repoLink string, w *webhook_model.Webhook) (*api.Hook, error) {
|
||||
|
|
|
@ -270,6 +270,22 @@ func pullReleaseTestPayload() *api.ReleasePayload {
|
|||
}
|
||||
}
|
||||
|
||||
func ActionTestPayload() *api.ActionPayload {
|
||||
// this is not a complete action payload but enough for testing purposes
|
||||
return &api.ActionPayload{
|
||||
Run: &api.ActionRun{
|
||||
Repo: &api.Repository{
|
||||
HTMLURL: "http://localhost:3000/test/repo",
|
||||
Name: "repo",
|
||||
FullName: "test/repo",
|
||||
},
|
||||
PrettyRef: "main",
|
||||
HTMLURL: "http://localhost:3000/test/repo/actions/runs/69",
|
||||
Title: "Build release",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func pullRequestTestPayload() *api.PullRequestPayload {
|
||||
return &api.PullRequestPayload{
|
||||
Action: api.HookIssueOpened,
|
||||
|
@ -675,3 +691,36 @@ func TestGetIssueCommentPayloadInfo(t *testing.T) {
|
|||
assert.Equal(t, c.color, color, "case %d", i)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetActionPayloadInfo(t *testing.T) {
|
||||
p := ActionTestPayload()
|
||||
|
||||
cases := []struct {
|
||||
action api.HookActionAction
|
||||
text string
|
||||
color int
|
||||
}{
|
||||
{
|
||||
api.HookActionFailure,
|
||||
"Build release Action Failed in test/repo main",
|
||||
redColor,
|
||||
},
|
||||
{
|
||||
api.HookActionSuccess,
|
||||
"Build release Action Succeeded in test/repo main",
|
||||
greenColor,
|
||||
},
|
||||
{
|
||||
api.HookActionRecover,
|
||||
"Build release Action Recovered in test/repo main",
|
||||
greenColor,
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
p.Action = c.action
|
||||
text, color := getActionPayloadInfo(p, noneLinkFormatter)
|
||||
assert.Equal(t, c.text, text, "case %d", i)
|
||||
assert.Equal(t, c.color, color, "case %d", i)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -273,6 +273,12 @@ func (m matrixConvertor) Package(p *api.PackagePayload) (MatrixPayload, error) {
|
|||
return m.newPayload(text)
|
||||
}
|
||||
|
||||
func (m matrixConvertor) Action(p *api.ActionPayload) (MatrixPayload, error) {
|
||||
text, _ := getActionPayloadInfo(p, htmlLinkFormatter)
|
||||
|
||||
return m.newPayload(text)
|
||||
}
|
||||
|
||||
var urlRegex = regexp.MustCompile(`<a [^>]*?href="([^">]*?)">(.*?)</a>`)
|
||||
|
||||
func getMessageBody(htmlText string) string {
|
||||
|
|
|
@ -326,6 +326,23 @@ func (m msteamsConvertor) Package(p *api.PackagePayload) (MSTeamsPayload, error)
|
|||
), nil
|
||||
}
|
||||
|
||||
func (m msteamsConvertor) Action(p *api.ActionPayload) (MSTeamsPayload, error) {
|
||||
title, color := getActionPayloadInfo(p, noneLinkFormatter)
|
||||
|
||||
// TODO: is TriggerUser correct here?
|
||||
// if you'd like to test these proprietary services, see the discussion on: https://codeberg.org/forgejo/forgejo/pulls/7508
|
||||
return createMSTeamsPayload(
|
||||
p.Run.Repo,
|
||||
p.Run.TriggerUser,
|
||||
title,
|
||||
"",
|
||||
p.Run.HTMLURL,
|
||||
color,
|
||||
// TODO: does this make any sense?
|
||||
&MSTeamsFact{"Action:", p.Run.Title},
|
||||
), nil
|
||||
}
|
||||
|
||||
func createMSTeamsPayload(r *api.Repository, s *api.User, title, text, actionTarget string, color int, fact *MSTeamsFact) MSTeamsPayload {
|
||||
facts := make([]MSTeamsFact, 0, 2)
|
||||
if r != nil {
|
||||
|
|
|
@ -6,6 +6,7 @@ package webhook
|
|||
import (
|
||||
"context"
|
||||
|
||||
actions_model "forgejo.org/models/actions"
|
||||
issues_model "forgejo.org/models/issues"
|
||||
packages_model "forgejo.org/models/packages"
|
||||
"forgejo.org/models/perm"
|
||||
|
@ -887,6 +888,38 @@ func (m *webhookNotifier) PackageDelete(ctx context.Context, doer *user_model.Us
|
|||
notifyPackage(ctx, doer, pd, api.HookPackageDeleted)
|
||||
}
|
||||
|
||||
func (m *webhookNotifier) ActionRunNowDone(ctx context.Context, run *actions_model.ActionRun, priorStatus actions_model.Status, lastRun *actions_model.ActionRun) {
|
||||
source := EventSource{
|
||||
Repository: run.Repo,
|
||||
Owner: run.TriggerUser,
|
||||
}
|
||||
|
||||
payload := &api.ActionPayload{
|
||||
Run: convert.ToActionRun(ctx, run),
|
||||
LastRun: convert.ToActionRun(ctx, lastRun),
|
||||
PriorStatus: priorStatus.String(),
|
||||
}
|
||||
|
||||
if run.Status.IsSuccess() {
|
||||
payload.Action = api.HookActionSuccess
|
||||
if err := PrepareWebhooks(ctx, source, webhook_module.HookEventActionRunSuccess, payload); err != nil {
|
||||
log.Error("PrepareWebhooks: %v", err)
|
||||
}
|
||||
// send another event when this is a recover
|
||||
if lastRun != nil && !lastRun.Status.IsSuccess() {
|
||||
payload.Action = api.HookActionRecover
|
||||
if err := PrepareWebhooks(ctx, source, webhook_module.HookEventActionRunRecover, payload); err != nil {
|
||||
log.Error("PrepareWebhooks: %v", err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
payload.Action = api.HookActionFailure
|
||||
if err := PrepareWebhooks(ctx, source, webhook_module.HookEventActionRunFailure, payload); err != nil {
|
||||
log.Error("PrepareWebhooks: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func notifyPackage(ctx context.Context, sender *user_model.User, pd *packages_model.PackageDescriptor, action api.HookPackageAction) {
|
||||
source := EventSource{
|
||||
Repository: pd.Repository,
|
||||
|
|
|
@ -6,6 +6,7 @@ package webhook
|
|||
import (
|
||||
"testing"
|
||||
|
||||
actions_model "forgejo.org/models/actions"
|
||||
"forgejo.org/models/db"
|
||||
repo_model "forgejo.org/models/repo"
|
||||
"forgejo.org/models/unittest"
|
||||
|
@ -13,10 +14,12 @@ import (
|
|||
webhook_model "forgejo.org/models/webhook"
|
||||
"forgejo.org/modules/git"
|
||||
"forgejo.org/modules/json"
|
||||
"forgejo.org/modules/log"
|
||||
"forgejo.org/modules/repository"
|
||||
"forgejo.org/modules/setting"
|
||||
"forgejo.org/modules/structs"
|
||||
"forgejo.org/modules/test"
|
||||
webhook_module "forgejo.org/modules/webhook"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -119,3 +122,190 @@ func TestPushCommits(t *testing.T) {
|
|||
assert.Equal(t, "2c54faec6c45d31c1abfaecdab471eac6633738a", payloadContent.Commits[0].ID)
|
||||
})
|
||||
}
|
||||
|
||||
func assertActionEqual(t *testing.T, expectedRun *actions_model.ActionRun, actualRun *structs.ActionRun) {
|
||||
assert.NotNil(t, expectedRun)
|
||||
assert.NotNil(t, actualRun)
|
||||
// only test a few things
|
||||
assert.Equal(t, expectedRun.ID, actualRun.ID)
|
||||
assert.Equal(t, expectedRun.Status.String(), actualRun.Status)
|
||||
assert.Equal(t, expectedRun.Index, actualRun.Index)
|
||||
assert.Equal(t, expectedRun.RepoID, actualRun.Repo.ID)
|
||||
// convert to unix because of time zones
|
||||
assert.Equal(t, expectedRun.Stopped.AsTime().Unix(), actualRun.Stopped.Unix())
|
||||
assert.Equal(t, expectedRun.Title, actualRun.Title)
|
||||
assert.Equal(t, expectedRun.WorkflowID, actualRun.WorkflowID)
|
||||
}
|
||||
|
||||
func TestAction(t *testing.T) {
|
||||
defer unittest.OverrideFixtures("services/webhook/TestPushCommits")()
|
||||
require.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
triggerUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2, OwnerID: triggerUser.ID})
|
||||
|
||||
oldSuccessRun := &actions_model.ActionRun{
|
||||
ID: 1,
|
||||
Status: actions_model.StatusSuccess,
|
||||
Index: 1,
|
||||
RepoID: repo.ID,
|
||||
Stopped: 1693648027,
|
||||
WorkflowID: "some_workflow",
|
||||
Title: "oldSuccessRun",
|
||||
TriggerUser: triggerUser,
|
||||
TriggerUserID: triggerUser.ID,
|
||||
TriggerEvent: "push",
|
||||
}
|
||||
oldSuccessRun.LoadAttributes(db.DefaultContext)
|
||||
oldFailureRun := &actions_model.ActionRun{
|
||||
ID: 1,
|
||||
Status: actions_model.StatusFailure,
|
||||
Index: 1,
|
||||
RepoID: repo.ID,
|
||||
Stopped: 1693648027,
|
||||
WorkflowID: "some_workflow",
|
||||
Title: "oldFailureRun",
|
||||
TriggerUser: triggerUser,
|
||||
TriggerUserID: triggerUser.ID,
|
||||
TriggerEvent: "push",
|
||||
}
|
||||
oldFailureRun.LoadAttributes(db.DefaultContext)
|
||||
newSuccessRun := &actions_model.ActionRun{
|
||||
ID: 1,
|
||||
Status: actions_model.StatusSuccess,
|
||||
Index: 1,
|
||||
RepoID: repo.ID,
|
||||
Stopped: 1693648327,
|
||||
WorkflowID: "some_workflow",
|
||||
Title: "newSuccessRun",
|
||||
TriggerUser: triggerUser,
|
||||
TriggerUserID: triggerUser.ID,
|
||||
TriggerEvent: "push",
|
||||
}
|
||||
newSuccessRun.LoadAttributes(db.DefaultContext)
|
||||
newFailureRun := &actions_model.ActionRun{
|
||||
ID: 1,
|
||||
Status: actions_model.StatusFailure,
|
||||
Index: 1,
|
||||
RepoID: repo.ID,
|
||||
Stopped: 1693648327,
|
||||
WorkflowID: "some_workflow",
|
||||
Title: "newFailureRun",
|
||||
TriggerUser: triggerUser,
|
||||
TriggerUserID: triggerUser.ID,
|
||||
TriggerEvent: "push",
|
||||
}
|
||||
newFailureRun.LoadAttributes(db.DefaultContext)
|
||||
|
||||
t.Run("Successful Run after Nothing", func(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.Webhook.PayloadCommitLimit, 10)()
|
||||
|
||||
NewNotifier().ActionRunNowDone(db.DefaultContext, newSuccessRun, actions_model.StatusWaiting, nil)
|
||||
|
||||
// there's only one of these at the time
|
||||
hookTask := unittest.AssertExistsAndLoadBean(t, &webhook_model.HookTask{}, unittest.Cond("event_type == 'action_run_success' AND payload_content LIKE '%success%newSuccessRun%'"))
|
||||
assert.Equal(t, webhook_module.HookEventActionRunSuccess, hookTask.EventType)
|
||||
|
||||
var payloadContent structs.ActionPayload
|
||||
require.NoError(t, json.Unmarshal([]byte(hookTask.PayloadContent), &payloadContent))
|
||||
assert.Equal(t, structs.HookActionSuccess, payloadContent.Action)
|
||||
assert.Equal(t, actions_model.StatusWaiting.String(), payloadContent.PriorStatus)
|
||||
assertActionEqual(t, newSuccessRun, payloadContent.Run)
|
||||
assert.Nil(t, payloadContent.LastRun)
|
||||
})
|
||||
|
||||
t.Run("Successful Run after Failure", func(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.Webhook.PayloadCommitLimit, 10)()
|
||||
|
||||
NewNotifier().ActionRunNowDone(db.DefaultContext, newSuccessRun, actions_model.StatusWaiting, oldFailureRun)
|
||||
|
||||
{
|
||||
hookTask := unittest.AssertExistsAndLoadBean(t, &webhook_model.HookTask{}, unittest.Cond("event_type == 'action_run_success' AND payload_content LIKE '%success%newSuccessRun%oldFailureRun%'"))
|
||||
assert.Equal(t, webhook_module.HookEventActionRunSuccess, hookTask.EventType)
|
||||
|
||||
var payloadContent structs.ActionPayload
|
||||
require.NoError(t, json.Unmarshal([]byte(hookTask.PayloadContent), &payloadContent))
|
||||
assert.Equal(t, structs.HookActionSuccess, payloadContent.Action)
|
||||
assert.Equal(t, actions_model.StatusWaiting.String(), payloadContent.PriorStatus)
|
||||
assertActionEqual(t, newSuccessRun, payloadContent.Run)
|
||||
assertActionEqual(t, oldFailureRun, payloadContent.LastRun)
|
||||
}
|
||||
{
|
||||
hookTask := unittest.AssertExistsAndLoadBean(t, &webhook_model.HookTask{}, unittest.Cond("event_type == 'action_run_recover' AND payload_content LIKE '%recover%newSuccessRun%oldFailureRun%'"))
|
||||
assert.Equal(t, webhook_module.HookEventActionRunRecover, hookTask.EventType)
|
||||
|
||||
log.Error("something: %s", hookTask.PayloadContent)
|
||||
var payloadContent structs.ActionPayload
|
||||
require.NoError(t, json.Unmarshal([]byte(hookTask.PayloadContent), &payloadContent))
|
||||
assert.Equal(t, structs.HookActionRecover, payloadContent.Action)
|
||||
assert.Equal(t, actions_model.StatusWaiting.String(), payloadContent.PriorStatus)
|
||||
assertActionEqual(t, newSuccessRun, payloadContent.Run)
|
||||
assertActionEqual(t, oldFailureRun, payloadContent.LastRun)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Successful Run after Success", func(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.Webhook.PayloadCommitLimit, 10)()
|
||||
|
||||
NewNotifier().ActionRunNowDone(db.DefaultContext, newSuccessRun, actions_model.StatusWaiting, oldSuccessRun)
|
||||
|
||||
hookTask := unittest.AssertExistsAndLoadBean(t, &webhook_model.HookTask{}, unittest.Cond("event_type == 'action_run_success' AND payload_content LIKE '%success%newSuccessRun%oldSuccessRun%'"))
|
||||
assert.Equal(t, webhook_module.HookEventActionRunSuccess, hookTask.EventType)
|
||||
|
||||
var payloadContent structs.ActionPayload
|
||||
require.NoError(t, json.Unmarshal([]byte(hookTask.PayloadContent), &payloadContent))
|
||||
assert.Equal(t, structs.HookActionSuccess, payloadContent.Action)
|
||||
assert.Equal(t, actions_model.StatusWaiting.String(), payloadContent.PriorStatus)
|
||||
assertActionEqual(t, newSuccessRun, payloadContent.Run)
|
||||
assertActionEqual(t, oldSuccessRun, payloadContent.LastRun)
|
||||
})
|
||||
|
||||
t.Run("Failed Run after Nothing", func(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.Webhook.PayloadCommitLimit, 10)()
|
||||
|
||||
NewNotifier().ActionRunNowDone(db.DefaultContext, newFailureRun, actions_model.StatusWaiting, nil)
|
||||
|
||||
// there should only be this one at the time
|
||||
hookTask := unittest.AssertExistsAndLoadBean(t, &webhook_model.HookTask{}, unittest.Cond("event_type == 'action_run_failure' AND payload_content LIKE '%failure%newFailureRun%'"))
|
||||
assert.Equal(t, webhook_module.HookEventActionRunFailure, hookTask.EventType)
|
||||
|
||||
var payloadContent structs.ActionPayload
|
||||
require.NoError(t, json.Unmarshal([]byte(hookTask.PayloadContent), &payloadContent))
|
||||
assert.Equal(t, structs.HookActionFailure, payloadContent.Action)
|
||||
assert.Equal(t, actions_model.StatusWaiting.String(), payloadContent.PriorStatus)
|
||||
assertActionEqual(t, newFailureRun, payloadContent.Run)
|
||||
assert.Nil(t, payloadContent.LastRun)
|
||||
})
|
||||
|
||||
t.Run("Failed Run after Failure", func(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.Webhook.PayloadCommitLimit, 10)()
|
||||
|
||||
NewNotifier().ActionRunNowDone(db.DefaultContext, newFailureRun, actions_model.StatusWaiting, oldFailureRun)
|
||||
|
||||
hookTask := unittest.AssertExistsAndLoadBean(t, &webhook_model.HookTask{}, unittest.Cond("event_type == 'action_run_failure' AND payload_content LIKE '%failure%newFailureRun%oldFailureRun%'"))
|
||||
assert.Equal(t, webhook_module.HookEventActionRunFailure, hookTask.EventType)
|
||||
|
||||
var payloadContent structs.ActionPayload
|
||||
require.NoError(t, json.Unmarshal([]byte(hookTask.PayloadContent), &payloadContent))
|
||||
assert.Equal(t, structs.HookActionFailure, payloadContent.Action)
|
||||
assert.Equal(t, actions_model.StatusWaiting.String(), payloadContent.PriorStatus)
|
||||
assertActionEqual(t, newFailureRun, payloadContent.Run)
|
||||
assertActionEqual(t, oldFailureRun, payloadContent.LastRun)
|
||||
})
|
||||
|
||||
t.Run("Failed Run after Success", func(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.Webhook.PayloadCommitLimit, 10)()
|
||||
|
||||
NewNotifier().ActionRunNowDone(db.DefaultContext, newFailureRun, actions_model.StatusWaiting, oldSuccessRun)
|
||||
|
||||
hookTask := unittest.AssertExistsAndLoadBean(t, &webhook_model.HookTask{}, unittest.Cond("event_type == 'action_run_failure' AND payload_content LIKE '%failure%newFailureRun%oldSuccessRun%'"))
|
||||
assert.Equal(t, webhook_module.HookEventActionRunFailure, hookTask.EventType)
|
||||
|
||||
var payloadContent structs.ActionPayload
|
||||
require.NoError(t, json.Unmarshal([]byte(hookTask.PayloadContent), &payloadContent))
|
||||
assert.Equal(t, structs.HookActionFailure, payloadContent.Action)
|
||||
assert.Equal(t, actions_model.StatusWaiting.String(), payloadContent.PriorStatus)
|
||||
assertActionEqual(t, newFailureRun, payloadContent.Run)
|
||||
assertActionEqual(t, oldSuccessRun, payloadContent.LastRun)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ type PayloadConvertor[T any] interface {
|
|||
Release(*api.ReleasePayload) (T, error)
|
||||
Wiki(*api.WikiPayload) (T, error)
|
||||
Package(*api.PackagePayload) (T, error)
|
||||
Action(*api.ActionPayload) (T, error)
|
||||
}
|
||||
|
||||
func convertUnmarshalledJSON[T, P any](convert func(P) (T, error), data []byte) (T, error) {
|
||||
|
@ -86,6 +87,8 @@ func NewPayload[T any](rc PayloadConvertor[T], data []byte, event webhook_module
|
|||
return convertUnmarshalledJSON(rc.Wiki, data)
|
||||
case webhook_module.HookEventPackage:
|
||||
return convertUnmarshalledJSON(rc.Package, data)
|
||||
case webhook_module.HookEventActionRunFailure, webhook_module.HookEventActionRunRecover, webhook_module.HookEventActionRunSuccess:
|
||||
return convertUnmarshalledJSON(rc.Action, data)
|
||||
}
|
||||
var t T
|
||||
return t, fmt.Errorf("newPayload unsupported event: %s", event)
|
||||
|
|
|
@ -142,6 +142,7 @@ func SlackLinkToRef(repoURL, ref string) string {
|
|||
return SlackLinkFormatter(url, refName)
|
||||
}
|
||||
|
||||
// TODO: fix spelling to Converter
|
||||
// Create implements payloadConvertor Create method
|
||||
func (s slackConvertor) Create(p *api.CreatePayload) (SlackPayload, error) {
|
||||
refLink := SlackLinkToRef(p.Repo.HTMLURL, p.Ref)
|
||||
|
@ -311,6 +312,12 @@ func (s slackConvertor) Repository(p *api.RepositoryPayload) (SlackPayload, erro
|
|||
return s.createPayload(text, nil), nil
|
||||
}
|
||||
|
||||
func (s slackConvertor) Action(p *api.ActionPayload) (SlackPayload, error) {
|
||||
text, _ := getActionPayloadInfo(p, SlackLinkFormatter)
|
||||
|
||||
return s.createPayload(text, nil), nil
|
||||
}
|
||||
|
||||
func (s slackConvertor) createPayload(text string, attachments []SlackAttachment) SlackPayload {
|
||||
return SlackPayload{
|
||||
Channel: s.Channel,
|
||||
|
|
|
@ -190,6 +190,10 @@ func (pc sourcehutConvertor) Package(_ *api.PackagePayload) (graphqlPayload[buil
|
|||
return graphqlPayload[buildsVariables]{}, shared.ErrPayloadTypeNotSupported
|
||||
}
|
||||
|
||||
func (pc sourcehutConvertor) Action(_ *api.ActionPayload) (graphqlPayload[buildsVariables], error) {
|
||||
return graphqlPayload[buildsVariables]{}, shared.ErrPayloadTypeNotSupported
|
||||
}
|
||||
|
||||
// newPayload opens and adjusts the manifest to submit to the builds service
|
||||
//
|
||||
// in case of an error the Error field will be set, to be visible by the end-user under recent deliveries
|
||||
|
|
|
@ -205,6 +205,12 @@ func (t telegramConvertor) Package(p *api.PackagePayload) (TelegramPayload, erro
|
|||
return createTelegramPayload(text), nil
|
||||
}
|
||||
|
||||
func (telegramConvertor) Action(p *api.ActionPayload) (TelegramPayload, error) {
|
||||
text, _ := getActionPayloadInfo(p, htmlLinkFormatter)
|
||||
|
||||
return createTelegramPayload(text), nil
|
||||
}
|
||||
|
||||
func createTelegramPayload(message string) TelegramPayload {
|
||||
return TelegramPayload{
|
||||
Message: markup.Sanitize(strings.TrimSpace(message)),
|
||||
|
|
|
@ -103,7 +103,7 @@ type EventSource struct {
|
|||
Owner *user_model.User
|
||||
}
|
||||
|
||||
// handle delivers hook tasks
|
||||
// handler delivers hook tasks
|
||||
func handler(items ...int64) []int64 {
|
||||
ctx := graceful.GetManager().HammerContext()
|
||||
|
||||
|
|
|
@ -201,6 +201,12 @@ func (wc wechatworkConvertor) Package(p *api.PackagePayload) (WechatworkPayload,
|
|||
return newWechatworkMarkdownPayload(text), nil
|
||||
}
|
||||
|
||||
func (wc wechatworkConvertor) Action(p *api.ActionPayload) (WechatworkPayload, error) {
|
||||
text, _ := getActionPayloadInfo(p, noneLinkFormatter)
|
||||
|
||||
return newWechatworkMarkdownPayload(text), nil
|
||||
}
|
||||
|
||||
type wechatworkConvertor struct{}
|
||||
|
||||
var _ shared.PayloadConvertor[WechatworkPayload] = wechatworkConvertor{}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue