From f1644fc5e2dbf10c543dd9989d9be592519b9dcf Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 21 Apr 2026 13:30:21 -0700 Subject: [PATCH] Add event.schedule context for schedule actions task (#37320) Fix #35452 --------- Co-authored-by: silverwind Co-authored-by: Claude (Opus 4.7) Co-authored-by: Giteabot --- services/actions/schedule_tasks.go | 33 +++++++++++++++++--- services/actions/schedule_tasks_test.go | 41 +++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 services/actions/schedule_tasks_test.go diff --git a/services/actions/schedule_tasks.go b/services/actions/schedule_tasks.go index 037bf5cddd1..b2dc3f98407 100644 --- a/services/actions/schedule_tasks.go +++ b/services/actions/schedule_tasks.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" + "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/timeutil" webhook_module "code.gitea.io/gitea/modules/webhook" @@ -67,7 +68,7 @@ func startTasks(ctx context.Context) error { continue } - if err := CreateScheduleTask(ctx, row.Schedule); err != nil { + if err := CreateScheduleTask(ctx, row); err != nil { log.Error("CreateScheduleTask: %v", err) return err } @@ -97,9 +98,12 @@ func startTasks(ctx context.Context) error { return nil } -// CreateScheduleTask creates a scheduled task from a cron action schedule. +// CreateScheduleTask creates a scheduled task from a cron action schedule spec. // It creates an action run based on the schedule, inserts it into the database, and creates commit statuses for each job. -func CreateScheduleTask(ctx context.Context, cron *actions_model.ActionSchedule) error { +func CreateScheduleTask(ctx context.Context, spec *actions_model.ActionScheduleSpec) error { + cron := spec.Schedule + eventPayload := withScheduleInEventPayload(cron.EventPayload, spec.Spec) + // Create a new action run based on the schedule run := &actions_model.ActionRun{ Title: cron.Title, @@ -110,7 +114,7 @@ func CreateScheduleTask(ctx context.Context, cron *actions_model.ActionSchedule) Ref: cron.Ref, CommitSHA: cron.CommitSHA, Event: cron.Event, - EventPayload: cron.EventPayload, + EventPayload: eventPayload, TriggerEvent: string(webhook_module.HookEventSchedule), ScheduleID: cron.ID, Status: actions_model.StatusWaiting, @@ -126,3 +130,24 @@ func CreateScheduleTask(ctx context.Context, cron *actions_model.ActionSchedule) // Return nil if no errors occurred return nil } + +func withScheduleInEventPayload(eventPayload, schedule string) string { + if schedule == "" || eventPayload == "" { + return eventPayload + } + + event := map[string]any{} + if err := json.Unmarshal([]byte(eventPayload), &event); err != nil { + log.Error("withScheduleInEventPayload: unmarshal: %v", err) + return eventPayload + } + + event["schedule"] = schedule + updatedPayload, err := json.Marshal(event) + if err != nil { + log.Error("withScheduleInEventPayload: marshal: %v", err) + return eventPayload + } + + return string(updatedPayload) +} diff --git a/services/actions/schedule_tasks_test.go b/services/actions/schedule_tasks_test.go new file mode 100644 index 00000000000..770b8426232 --- /dev/null +++ b/services/actions/schedule_tasks_test.go @@ -0,0 +1,41 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package actions + +import ( + "testing" + + "code.gitea.io/gitea/modules/json" + + "github.com/stretchr/testify/assert" +) + +func TestWithScheduleInEventPayload(t *testing.T) { + t.Run("adds schedule to existing payload", func(t *testing.T) { + payload := `{"ref":"refs/heads/main"}` + updated := withScheduleInEventPayload(payload, "*/5 * * * *") + + event := map[string]any{} + assert.NoError(t, json.Unmarshal([]byte(updated), &event)) + assert.Equal(t, "*/5 * * * *", event["schedule"]) + assert.Equal(t, "refs/heads/main", event["ref"]) + }) + + t.Run("keeps empty payload", func(t *testing.T) { + updated := withScheduleInEventPayload("", "37 12 5 1 2") + assert.Empty(t, updated) + }) + + t.Run("keeps payload when schedule empty", func(t *testing.T) { + payload := `{"ref":"refs/heads/main"}` + updated := withScheduleInEventPayload(payload, "") + assert.Equal(t, payload, updated) + }) + + t.Run("keeps payload when malformed JSON", func(t *testing.T) { + payload := `not a json object` + updated := withScheduleInEventPayload(payload, "*/5 * * * *") + assert.Equal(t, payload, updated) + }) +}