diff --git a/docs/docs/20-usage/45-cron.md b/docs/docs/20-usage/45-cron.md index 95ee8202e..2cb088122 100644 --- a/docs/docs/20-usage/45-cron.md +++ b/docs/docs/20-usage/45-cron.md @@ -23,12 +23,6 @@ To configure cron jobs you need at least push access to the repository. ![cron settings](./cron-settings.png) - The supported schedule syntax can be found at . If you need general understanding of the cron syntax is a good place to start and experiment. + The supported schedule syntax can be found at . If you need general understanding of the cron syntax is a good place to start and experiment. - Examples: `@every 5m`, `@daily`, `0 30 * * * *` ... - - :::info - Woodpeckers cron syntax starts with seconds instead of minutes as used by most linux cron schedulers. - - Example: "At minute 30 every hour" would be `0 30 * * * *` instead of `30 * * * *` - ::: + Examples: `@every 5m`, `@daily`, `30 * * * *` ... diff --git a/docs/docs/91-migrations.md b/docs/docs/91-migrations.md index d0fd5b8ef..33b716173 100644 --- a/docs/docs/91-migrations.md +++ b/docs/docs/91-migrations.md @@ -6,6 +6,7 @@ Some versions need some changes to the server configuration or the pipeline conf ## 3.0.0 - Update all webhooks by pressing the "Repair all" button in the admin settings as the webhook token claims have changed +- Crons now use standard Linux syntax without seconds --> diff --git a/go.mod b/go.mod index 47362655d..fe13b7995 100644 --- a/go.mod +++ b/go.mod @@ -26,6 +26,7 @@ require ( github.com/expr-lang/expr v1.16.9 github.com/franela/goblin v0.0.0-20211003143422-0a4f594942bf github.com/fsnotify/fsnotify v1.7.0 + github.com/gdgvda/cron v0.2.0 github.com/getkin/kin-openapi v0.126.0 github.com/gin-gonic/gin v1.10.0 github.com/gitsight/go-vcsurl v1.0.1 @@ -49,7 +50,6 @@ require ( github.com/oklog/ulid/v2 v2.1.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.19.1 - github.com/robfig/cron v1.2.0 github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.9.0 github.com/swaggo/files v1.0.1 diff --git a/go.sum b/go.sum index 964957cdf..0a723d15e 100644 --- a/go.sum +++ b/go.sum @@ -145,6 +145,8 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= +github.com/gdgvda/cron v0.2.0 h1:oX8qdLZq4tC5StnCsZsTNs2BIzaRjcjmPZ4o+BArKX4= +github.com/gdgvda/cron v0.2.0/go.mod h1:VEwidZXB255kESB5DcUGRWTYZS8KkOBYD1YBn8Wiyx8= github.com/getkin/kin-openapi v0.126.0 h1:c2cSgLnAsS0xYfKsgt5oBV6MYRM/giU8/RtwUY4wyfY= github.com/getkin/kin-openapi v0.126.0/go.mod h1:7mONz8IwmSRg6RttPu6v8U/OJ+gr+J99qSFNjPGSQqw= github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= @@ -459,8 +461,6 @@ github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qq github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ= -github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= diff --git a/server/cron/cron.go b/server/cron/cron.go index 0dc05ee65..9fa35aa8c 100644 --- a/server/cron/cron.go +++ b/server/cron/cron.go @@ -19,7 +19,7 @@ import ( "fmt" "time" - "github.com/robfig/cron" + "github.com/gdgvda/cron" "github.com/rs/zerolog/log" "go.woodpecker-ci.org/woodpecker/v2/server" @@ -31,7 +31,7 @@ import ( const ( // Specifies the interval woodpecker checks for new crons to exec. - checkTime = 10 * time.Second + checkTime = time.Minute // Specifies the batch size of crons to retrieve per check from database. checkItems = 10 @@ -71,7 +71,7 @@ func CalcNewNext(schedule string, now time.Time) (time.Time, error) { // TODO: allow the users / the admin to set a specific timezone - c, err := cron.Parse(schedule) + c, err := cron.ParseStandard(schedule) if err != nil { return time.Time{}, fmt.Errorf("cron parse schedule: %w", err) } diff --git a/server/model/cron.go b/server/model/cron.go index 42467de35..fb72665c7 100644 --- a/server/model/cron.go +++ b/server/model/cron.go @@ -17,7 +17,7 @@ package model import ( "fmt" - "github.com/robfig/cron" + "github.com/gdgvda/cron" ) type Cron struct { @@ -46,7 +46,7 @@ func (c *Cron) Validate() error { return fmt.Errorf("schedule is required") } - _, err := cron.Parse(c.Schedule) + _, err := cron.ParseStandard(c.Schedule) if err != nil { return fmt.Errorf("can't parse schedule: %w", err) } diff --git a/server/store/datastore/migration/033_cron_without_sec.go b/server/store/datastore/migration/033_cron_without_sec.go new file mode 100644 index 000000000..a170401b3 --- /dev/null +++ b/server/store/datastore/migration/033_cron_without_sec.go @@ -0,0 +1,53 @@ +// Copyright 2024 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package migration + +import ( + "fmt" + "strings" + + "src.techknowlogick.com/xormigrate" + "xorm.io/xorm" + + "go.woodpecker-ci.org/woodpecker/v2/server/model" +) + +var cronWithoutSec = xormigrate.Migration{ + ID: "cron-without-sec", + MigrateSession: func(sess *xorm.Session) error { + if err := sess.Sync(new(model.Cron)); err != nil { + return fmt.Errorf("sync new models failed: %w", err) + } + + var crons []*model.Cron + if err := sess.Find(&crons); err != nil { + return err + } + + for _, c := range crons { + if strings.HasPrefix(strings.TrimSpace(c.Schedule), "@") { + // something like "@daily" + continue + } + + c.Schedule = strings.SplitN(strings.TrimSpace(c.Schedule), " ", 2)[1] + if _, err := sess.Update(c); err != nil { + return err + } + } + + return nil + }, +} diff --git a/server/store/datastore/migration/migration.go b/server/store/datastore/migration/migration.go index 4c905e66e..a2a42b96b 100644 --- a/server/store/datastore/migration/migration.go +++ b/server/store/datastore/migration/migration.go @@ -63,6 +63,7 @@ var migrationTasks = []*xormigrate.Migration{ &setForgeID, &unifyColumnsTables, &alterTableRegistriesFixRequiredFields, + &cronWithoutSec, } var allBeans = []any{ diff --git a/web/src/components/repo/settings/CronTab.vue b/web/src/components/repo/settings/CronTab.vue index 98d27cdef..e19c9f0a0 100644 --- a/web/src/components/repo/settings/CronTab.vue +++ b/web/src/components/repo/settings/CronTab.vue @@ -60,7 +60,7 @@