jojo/models/forgejo_migrations
forgejo-backport-action 4ca6b703af [v15.0/forgejo] feat: support timezone in scheduled workflows (#11986)
**Backport:** https://codeberg.org/forgejo/forgejo/pulls/11851

GitHub recently added the ability to [specify a time zone for scheduled workflows](https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#onschedule), thereby making it possible to run scheduled workflows at a certain local time, no matter whether daylight saving time (DST) is currently active or not. Example copied from GitHub's documentation:

```yaml
on:
  schedule:
    - cron: '30 5 * * 1-5'
      timezone: "America/New_York"
```

The workflow would run at 05:30 each morning in the America/New_York timezone every Monday through Friday. `timezone` accepts IANA time zone names. If `timezone` is absent, `Etc/UTC` is used. GitHub runs workflows that were scheduled during DST jumps forward, for example, between 2 o'clock and 3 o'clock, directly after the clock jumped forward. In this case, that would be 3 o'clock.

Forgejo already supports time zones by prepending cron schedules with `TZ=<zone-id>` or `CRON_TZ=<zone-id>`:

```yaml
on:
  schedule:
    - cron: 'CRON_TZ=America/New_York 30 5 * * 1-5'
```

However, that capability is not documented. Workflows that are scheduled to run during DST changes are skipped when the clock jumps forward and run twice when it jumps backward.

This two-part PR adds support for `timezone` to improve compatibility with GitHub. `TZ` and `CRON_TZ` continue working. When both `timezone` and `TZ` or `CRON_TZ` are present, `timezone` takes precedence. When neither `timezone` nor `TZ` nor `CRON_TZ` are present, `Etc/UTC` is used as before. Because `TZ` and `CRON_TZ` were already supported by Forgejo before GitHub introduced `timezone`, `timezone` behaves during DST changes as previous versions of Forgejo, thereby deviating from GitHub. That means that workflows that are scheduled to run during DST changes are skipped when the clock jumps forward. And they run twice when it jumps backwards. However, it is generally recommended not to schedule workflows during the time of day when DST changes occur.

This part of the PR integrates the [workflow validation and parsing of the `timezone` field](https://code.forgejo.org/forgejo/runner/pulls/1454) supplied by Forgejo Runner.

## Checklist

The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. All work and communication must conform to Forgejo's [AI Agreement](https://codeberg.org/forgejo/governance/src/branch/main/AIAgreement.md). 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 for Go changes

(can be removed for JavaScript changes)

- 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 ran...
  - [x] `make pr-go` before pushing

### Tests for JavaScript changes

(can be removed for Go changes)

- 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

- [x] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change.
    - https://codeberg.org/forgejo/docs/pulls/1853
- [ ] I did not document these changes and I do not expect someone else to do it.

### Release notes

- [x] This change will be noticed by a Forgejo user or admin (feature, bug fix, performance, etc.). I suggest to include a release note for this change.
- [ ] This change is not visible to a Forgejo user or admin (refactor, dependency upgrade, etc.). I think there is no need to add a release note for this change.

*The decision if the pull request will be shown in the release notes is up to the mergers / release team.*

The content of the `release-notes/<pull request number>.md` file will serve as the basis for the release notes. If the file does not exist, the title of the pull request will be used instead.

<!--start release-notes-assistant-->

## Release notes
<!--URL:https://codeberg.org/forgejo/forgejo-->
- Features
  - [PR](https://codeberg.org/forgejo/forgejo/pulls/11851): <!--number 11851 --><!--line 0 --><!--description c3VwcG9ydCBgdGltZXpvbmVgIGluIHNjaGVkdWxlZCB3b3JrZmxvd3M=-->support `timezone` in scheduled workflows<!--description-->
<!--end release-notes-assistant-->

Co-authored-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11986
Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org>
Co-authored-by: forgejo-backport-action <forgejo-backport-action@noreply.codeberg.org>
Co-committed-by: forgejo-backport-action <forgejo-backport-action@noreply.codeberg.org>
2026-04-04 19:16:35 +02:00
..
foreign_key_utils.go migration: update existing foreign key migrations to automatically fix inconsistencies (#10568) 2025-12-29 02:50:20 +01:00
index_utils.go fix: realign indexes on the 'action' table (#10040) 2025-11-18 18:34:25 +01:00
index_utils_test.go feat: rework notification table (#9926) 2025-11-29 23:03:56 +01:00
main_test.go feat: developer friendly migration registration 2025-10-14 14:51:50 -06:00
migrate.go ci: introduce semgrep to prevent using xorm.Sync() incorrectly in new migrations (#11142) 2026-02-07 21:52:43 +01:00
migrate_test.go chore: fix typos throughout the codebase (#10753) 2026-01-26 22:57:33 +01:00
README.md feat: developer friendly migration registration 2025-10-14 14:51:50 -06:00
v14a_actions-approval-and-trust.go [v15.0/forgejo] ci: prevent usage of live application models & services in migrations (#11907) 2026-04-01 02:57:09 +02:00
v14a_actions-approval-and-trust_test.go [v15.0/forgejo] ci: prevent usage of live application models & services in migrations (#11907) 2026-04-01 02:57:09 +02:00
v14a_add-action_task-index.go fix(perf): add missing index on action_task table (#9789) 2025-10-21 16:40:40 +02:00
v14a_add-foreign-keys-collaboration.go migration: update existing foreign key migrations to automatically fix inconsistencies (#10568) 2025-12-29 02:50:20 +01:00
v14a_add-foreign-keys-collaboration_test.go migration: update existing foreign key migrations to automatically fix inconsistencies (#10568) 2025-12-29 02:50:20 +01:00
v14a_add-foreign-keys-forgejo_auth_token.go migration: update existing foreign key migrations to automatically fix inconsistencies (#10568) 2025-12-29 02:50:20 +01:00
v14a_add-foreign-keys-forgejo_auth_token_test.go migration: update existing foreign key migrations to automatically fix inconsistencies (#10568) 2025-12-29 02:50:20 +01:00
v14a_add-foreign-keys-pull_request-1.go migration: update existing foreign key migrations to automatically fix inconsistencies (#10568) 2025-12-29 02:50:20 +01:00
v14a_add-foreign-keys-pull_request-1_test.go migration: update existing foreign key migrations to automatically fix inconsistencies (#10568) 2025-12-29 02:50:20 +01:00
v14a_add-forgejo-migrations-table.go ci: introduce semgrep to prevent using xorm.Sync() incorrectly in new migrations (#11142) 2026-02-07 21:52:43 +01:00
v14a_ap-change-fedi-handle-structure.go [v15.0/forgejo] ci: prevent usage of live application models & services in migrations (#11907) 2026-04-01 02:57:09 +02:00
v14a_migrate_task_secrets.go [v15.0/forgejo] ci: prevent usage of live application models & services in migrations (#11907) 2026-04-01 02:57:09 +02:00
v14a_migrate_task_secrets_test.go feat: cache derived keys for faster keying (#10114) 2025-11-16 14:29:14 +01:00
v14a_migrate_webhook_authorization.go [v15.0/forgejo] ci: prevent usage of live application models & services in migrations (#11907) 2026-04-01 02:57:09 +02:00
v14a_migrate_webhook_authorization_test.go [v15.0/forgejo] ci: prevent usage of live application models & services in migrations (#11907) 2026-04-01 02:57:09 +02:00
v14a_remove-is-deleted-column-from-activity-action-table.go chore: Remove IsDeleted from action (activity) table (#9829) 2025-11-08 04:20:05 +01:00
v14a_remove-is-deleted-column-from-activity-action-table_test.go chore: Remove IsDeleted from action (activity) table (#9829) 2025-11-08 04:20:05 +01:00
v14a_rework-notification.go [v15.0/forgejo] ci: prevent usage of live application models & services in migrations (#11907) 2026-04-01 02:57:09 +02:00
v14a_rm-repository-issue-stat-fields.go fix: reduce deadlocks merging PRs by using caching for repo issue count stats (#9922) 2025-10-31 23:50:05 +01:00
v14a_set_remote_user_prohibit_login.go [v15.0/forgejo] ci: prevent usage of live application models & services in migrations (#11907) 2026-04-01 02:57:09 +02:00
v14b_action-reindexing.go ci: introduce semgrep to prevent using xorm.Sync() incorrectly in new migrations (#11142) 2026-02-07 21:52:43 +01:00
v14b_action-run-add-workflow-directory.go feat(actions): make GITHUB_WORKFLOW_REF available (#10276) 2025-12-17 23:15:26 +01:00
v14b_add-action_run-preexecutionerrorcode.go i18n: translate Actions PreExecutionError for viewer (#10267) 2025-11-30 13:16:41 +01:00
v14b_rm-repository-actionrun-stat-fields.go fix: prevent deadlocks updating repo.num_action_runs/num_closed_action_runs (#9927) 2025-11-02 22:24:56 +01:00
v15a_remove-softdelete-action_runner_token.go feat: add foreign keys to the action_runner_token table (#10756) 2026-01-12 21:59:40 +01:00
v15a_remove-softdelete-action_runner_token_test.go feat: add foreign keys to the action_runner_token table (#10756) 2026-01-12 21:59:40 +01:00
v15b_add-access_token-owned-repos.go feat: backend DB model for fine-grained repo access tokens 2026-02-27 17:17:29 +01:00
v15b_add-access_token_resource.go feat: backend DB model for fine-grained repo access tokens 2026-02-27 17:17:29 +01:00
v15b_add-ephemeral_runner.go feat: implement ephemeral runners (#9962) 2026-02-16 18:56:56 +01:00
v15b_add-foreign-keys-action_runner_token.go feat: add foreign keys to the action_runner_token table (#10756) 2026-01-12 21:59:40 +01:00
v15b_add-foreign-keys-action_runner_token_test.go feat: add foreign keys to the action_runner_token table (#10756) 2026-01-12 21:59:40 +01:00
v15b_add-runner_request_key.go fix: allow Actions runner to recover tasks lost during fetching from intermittent errors (#11401) 2026-02-22 23:24:38 +01:00
v15c_add_job_handle.go feat: allow runners to request a particular job (#11676) 2026-03-25 17:27:05 +01:00
v15c_add_mirror_remoteaddressauth.go [v15.0/forgejo] fix: store pull mirror creds encrypted with keying (#11984) 2026-04-04 14:47:05 +02:00
v15c_add_schedule_spec_time_zones.go [v15.0/forgejo] feat: support timezone in scheduled workflows (#11986) 2026-04-04 19:16:35 +02:00
v15c_fix-project-sorting-unique-constraints.go fix(models): deduplicate project sorting values and add unique constraints (#11334) 2026-02-27 16:25:20 +01:00

forgejo_migrations

Forgejo has three database migration mechanisms:

  • models/gitea_migrations
    • Original database schema migrations from Forgejo's legacy as a fork of Gitea.
    • A linear set of migrations referenced in models/gitea_migrations/migrations.go, each represented by a number (eg. migration 304).
    • The current version is recorded in the database in the table version.
  • models/forgejo_migrations_legacy
    • The next 50-ish database schema migrations reflecting change in Forgejo's database structure between Forgejo v7.0 and v14.0
    • A linear set of migrations referenced in models/forgejo_migrations_legacy/migrate.go, each represented by a number (eg. migration 43).
    • The current version is recorded in the database in the table forgejo_version.
  • models/forgejo_migrations
    • The most recent database schema migrations, reflecting change in the v14.0 release cycle and onwards into the future.
    • Each migration is identified by the filename it is stored in.
    • The applied migrations are recorded in the database in the table forgejo_migration.

forgejo_migrations is designed to reduce code conflicts when multiple developers may be making schema migrations in close succession, which it does by avoiding having one code file with a long array of migrations. Instead, each file in models/forgejo_migrations registers itself as a migration, and its filename indicates the order that migration will be applied.

Files in forgejo_migrations must:

  • Define an init function which registers a function to be invoked for the migration.
  • Follow the naming convention:
    • The letter v
    • A number, representing the development cycle that the migration was created in
    • A letter, indicating any required migration ordering
    • The character _ (underscore)
    • A short descriptive identifier for the migration

For example, valid migration file names would look like this:

  • v14a_add-threaded-comments.go
  • v14a_add-federated-emojis.go
  • v14b_fix-threaded-comments-index.go

Migration Ordering

Forgejo executes registered migrations in forgejo_migrations in the strings.Compare() ordering of their filename.

There are edge cases where migrations may not be executed in this exact order:

  • If a schema change is backported to an earlier Forgejo release. For example, if a bugfix during the v15 development cycle was backported into a v14 patch release, then a migration labeled v15a_fix-unusual-data-corruption.go could be applied during a v14 software upgrade. In the future when a v15 software release occurs, that migration will be identified as already applied and will be skipped.
  • If a developer working on Forgejo switches between different branches with different schema migrations.
  • If the contents of the forgejo_migrations database table are changed outside of Forgejo modifying it.

Creating a new Migration

First, determine the filename for your migration. In general, you create a new migration by starting a file with the same prefix as the most recent migration present. If v14a_add-forgejo-migrations-table.go was the last file, most of the time you can create your migration with the same v14a_... prefix.

There are two exceptions:

  • After the release branch is cut for a release, increment the version in the migration. If v14 was cut, you would start v15a_... as the next migration.
  • If your migration requires that an earlier migration is complete first, you would increment the letter in the prefix. If you were modifying the table created by v14a_add-forgejo-migrations-table.go, then you would name your migration v14b_....

Once you've determined the migration filename, then you can copy this template into the file:

// Copyright 2025 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: GPL-3.0-or-later

package forgejo_migrations

import (
	"forgejo.org/modules/timeutil"

	"xorm.io/xorm"
)

func init() {
	registerMigration(&Migration{
		Description: "short sentence describing this migration",
		Upgrade:     myMigrationFunction, // rename
	})
}

func myMigrationFunction(x *xorm.Engine) error {
    // add migration logic here
    //
    // to prevent `make watch` from recording this migration as done when it
    // isn't authored yet, returh an error until the implementation is done
    return errors.New("not implemented yet")
}

And now it's up to you to write the contents of your migration function.

Development Notes

Once migrations are executed, a record of their execution is stored in the database table forgejo_migration.

=> SELECT * FROM forgejo_migration;
                id                 | created_unix
-----------------------------------+--------------
 v14a_add-forgejo-migrations-table |   1760402451
 v14a_example-other-migration      |   1760402453
 v14b_another-example              |   1760402455
 v15a_add-something-cool           |   1760402456
 v15a_another-example-again        |   1760402457

If your migration successfully executes once, it will be recorded in this table and it will never execute again, even if you change the migration code. It is common during development to need to re-run a migration, in which case you can delete the record that you're working on developing. The migration will be re-run as soon as the Forgejo server is restarted:

=> DELETE FROM forgejo_migration WHERE id = 'v15a_another-example-again';