From fe567d26c1d4374f02dfb7487af321ec5029062f Mon Sep 17 00:00:00 2001 From: Julian Scholle Date: Fri, 21 Aug 2026 01:06:44 +0200 Subject: [PATCH] fix(actions): allow larger scheduled workflows (#38985) MySQL stores `action_schedule.content` as `BLOB`, limiting scheduled workflow definitions to 65,535 bytes. Oversized workflows fail schedule refresh and can also suppress default-branch push handling. Store scheduled workflow content as `LONGBLOB`, migrate existing MySQL columns, and cover the migration by persisting 65,536 bytes. Fixes https://github.com/go-gitea/gitea/issues/38613 --- modelmigration/migrations.go | 1 + modelmigration/v28/v349.go | 29 ++++++++++++++++++++ modelmigration/v28/v349_test.go | 47 +++++++++++++++++++++++++++++++++ models/actions/schedule.go | 4 +-- 4 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 modelmigration/v28/v349.go create mode 100644 modelmigration/v28/v349_test.go diff --git a/modelmigration/migrations.go b/modelmigration/migrations.go index 9b2a793db74..42563f729be 100644 --- a/modelmigration/migrations.go +++ b/modelmigration/migrations.go @@ -422,6 +422,7 @@ func prepareMigrationTasks() []*migration { newMigration(346, "Add license_path column to repo_license and backfill", v28.AddLicensePathToRepoLicense), newMigration(347, "Add watch options", v28.AddWatchOptions), newMigration(348, "Recreate email_hash table for SHA256 avatar hashes", v28.RecreateEmailHashTable), + newMigration(349, "Expand action_schedule content column", v28.ExpandActionScheduleContent), } return preparedMigrations } diff --git a/modelmigration/v28/v349.go b/modelmigration/v28/v349.go new file mode 100644 index 00000000000..7d4d6638800 --- /dev/null +++ b/modelmigration/v28/v349.go @@ -0,0 +1,29 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v28 + +import ( + "context" + + "gitea.dev/modelmigration/base" + "gitea.dev/modules/setting" + + "xorm.io/xorm/schemas" +) + +func ExpandActionScheduleContent(ctx context.Context, x base.EngineMigration) error { + if !setting.Database.Type.IsMySQL() { + return nil + } + + return base.ModifyColumn(ctx, x, "action_schedule", &schemas.Column{ + Name: "content", + SQLType: schemas.SQLType{ + Name: "LONGBLOB", + }, + Length: 0, + Nullable: true, + DefaultIsEmpty: true, + }) +} diff --git a/modelmigration/v28/v349_test.go b/modelmigration/v28/v349_test.go new file mode 100644 index 00000000000..9f7c77ff20c --- /dev/null +++ b/modelmigration/v28/v349_test.go @@ -0,0 +1,47 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v28 + +import ( + "bytes" + "testing" + + "gitea.dev/modelmigration/migrationtest" + "gitea.dev/modules/setting" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestExpandActionScheduleContent(t *testing.T) { + if !setting.Database.Type.IsMySQL() { + t.Skip("Only MySQL limits BLOB columns to 65,535 bytes") + } + + type ActionSchedule struct { + ID int64 `xorm:"pk autoincr"` + Content []byte `xorm:"BLOB"` + } + + x, deferable := migrationtest.PrepareTestEnv(t, 0, new(ActionSchedule)) + defer deferable() + if x == nil || t.Failed() { + return + } + + require.NoError(t, ExpandActionScheduleContent(t.Context(), x)) + + tables := migrationtest.LoadTableSchemasMap(t, x) + assert.Equal(t, "LONGBLOB", tables["action_schedule"].GetColumn("content").SQLType.Name) + + content := bytes.Repeat([]byte("x"), 65_536) + _, err := x.Insert(&ActionSchedule{Content: content}) + require.NoError(t, err) + + var stored ActionSchedule + has, err := x.Get(&stored) + require.NoError(t, err) + require.True(t, has) + assert.Equal(t, content, stored.Content) +} diff --git a/models/actions/schedule.go b/models/actions/schedule.go index 031ea8350d0..91171cc8827 100644 --- a/models/actions/schedule.go +++ b/models/actions/schedule.go @@ -30,8 +30,8 @@ type ActionSchedule struct { Ref string CommitSHA string Event webhook_module.HookEventType - EventPayload string `xorm:"LONGTEXT"` - Content []byte + EventPayload string `xorm:"LONGTEXT"` + Content []byte `xorm:"LONGBLOB"` Created timeutil.TimeStamp `xorm:"created"` Updated timeutil.TimeStamp `xorm:"updated"` }