Skip to content

refactor(coderd/schedule): move cron schedule to cron package #9507

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cli/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (

"github.com/coder/coder/v2/cli/clibase"
"github.com/coder/coder/v2/cli/cliui"
"github.com/coder/coder/v2/coderd/schedule"
"github.com/coder/coder/v2/coderd/schedule/cron"
"github.com/coder/coder/v2/coderd/util/ptr"
"github.com/coder/coder/v2/codersdk"
)
Expand Down Expand Up @@ -39,7 +39,7 @@ func workspaceListRowFromWorkspace(now time.Time, usersByID map[uuid.UUID]coders
lastBuilt := now.UTC().Sub(workspace.LatestBuild.Job.CreatedAt).Truncate(time.Second)
autostartDisplay := "-"
if !ptr.NilOrEmpty(workspace.AutostartSchedule) {
if sched, err := schedule.Weekly(*workspace.AutostartSchedule); err == nil {
if sched, err := cron.Weekly(*workspace.AutostartSchedule); err == nil {
autostartDisplay = fmt.Sprintf("%s %s (%s)", sched.Time(), sched.DaysOfWeek(), sched.Location())
}
}
Expand Down
4 changes: 2 additions & 2 deletions cli/schedule.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (

"github.com/coder/coder/v2/cli/clibase"
"github.com/coder/coder/v2/cli/cliui"
"github.com/coder/coder/v2/coderd/schedule"
"github.com/coder/coder/v2/coderd/schedule/cron"
"github.com/coder/coder/v2/coderd/util/ptr"
"github.com/coder/coder/v2/coderd/util/tz"
"github.com/coder/coder/v2/codersdk"
Expand Down Expand Up @@ -255,7 +255,7 @@ func displaySchedule(workspace codersdk.Workspace, out io.Writer) error {
schedNextStop = "-"
)
if !ptr.NilOrEmpty(workspace.AutostartSchedule) {
sched, err := schedule.Weekly(ptr.NilToEmpty(workspace.AutostartSchedule))
sched, err := cron.Weekly(ptr.NilToEmpty(workspace.AutostartSchedule))
if err != nil {
// This should never happen.
_, _ = fmt.Fprintf(out, "Invalid autostart schedule %q for workspace %s: %s\n", *workspace.AutostartSchedule, workspace.Name, err.Error())
Expand Down
6 changes: 3 additions & 3 deletions cli/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (

"golang.org/x/xerrors"

"github.com/coder/coder/v2/coderd/schedule"
"github.com/coder/coder/v2/coderd/schedule/cron"
"github.com/coder/coder/v2/coderd/util/tz"
)

Expand Down Expand Up @@ -74,7 +74,7 @@ func relative(d time.Duration) string {
}

// parseCLISchedule parses a schedule in the format HH:MM{AM|PM} [DOW] [LOCATION]
func parseCLISchedule(parts ...string) (*schedule.Schedule, error) {
func parseCLISchedule(parts ...string) (*cron.Schedule, error) {
// If the user was careful and quoted the schedule, un-quote it.
// In the case that only time was specified, this will be a no-op.
if len(parts) == 1 {
Expand Down Expand Up @@ -121,7 +121,7 @@ func parseCLISchedule(parts ...string) (*schedule.Schedule, error) {
}
}

sched, err := schedule.Weekly(fmt.Sprintf(
sched, err := cron.Weekly(fmt.Sprintf(
"CRON_TZ=%s %d %d * * %s",
loc.String(),
minute,
Expand Down
3 changes: 2 additions & 1 deletion coderd/autobuild/lifecycle_executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/coder/coder/v2/coderd/database/dbauthz"
"github.com/coder/coder/v2/coderd/database/dbtime"
"github.com/coder/coder/v2/coderd/schedule"
"github.com/coder/coder/v2/coderd/schedule/cron"
"github.com/coder/coder/v2/coderd/wsbuilder"
"github.com/coder/coder/v2/codersdk"
)
Expand Down Expand Up @@ -306,7 +307,7 @@ func isEligibleForAutostart(ws database.Workspace, build database.WorkspaceBuild
return false
}

sched, err := schedule.Weekly(ws.AutostartSchedule.String)
sched, err := cron.Weekly(ws.AutostartSchedule.String)
if err != nil {
return false
}
Expand Down
5 changes: 3 additions & 2 deletions coderd/autobuild/lifecycle_executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/coder/coder/v2/coderd/coderdtest"
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/schedule"
"github.com/coder/coder/v2/coderd/schedule/cron"
"github.com/coder/coder/v2/coderd/util/ptr"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/provisioner/echo"
Expand Down Expand Up @@ -784,9 +785,9 @@ func mustProvisionWorkspaceWithParameters(t *testing.T, client *codersdk.Client,
return coderdtest.MustWorkspace(t, client, ws.ID)
}

func mustSchedule(t *testing.T, s string) *schedule.Schedule {
func mustSchedule(t *testing.T, s string) *cron.Schedule {
t.Helper()
sched, err := schedule.Weekly(s)
sched, err := cron.Weekly(s)
require.NoError(t, err)
return sched
}
Expand Down
3 changes: 2 additions & 1 deletion coderd/provisionerdserver/provisionerdserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/coder/coder/v2/coderd/gitauth"
"github.com/coder/coder/v2/coderd/provisionerdserver"
"github.com/coder/coder/v2/coderd/schedule"
"github.com/coder/coder/v2/coderd/schedule/cron"
"github.com/coder/coder/v2/coderd/telemetry"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/provisionerd/proto"
Expand Down Expand Up @@ -1330,7 +1331,7 @@ func TestCompleteJob(t *testing.T) {
}, nil
}

sched, err := schedule.Daily(c.userQuietHoursSchedule)
sched, err := cron.Daily(c.userQuietHoursSchedule)
if !assert.NoError(t, err) {
return schedule.UserQuietHoursScheduleOptions{}, err
}
Expand Down
3 changes: 2 additions & 1 deletion coderd/schedule/autostop_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/coder/coder/v2/coderd/database/dbtestutil"
"github.com/coder/coder/v2/coderd/database/dbtime"
"github.com/coder/coder/v2/coderd/schedule"
"github.com/coder/coder/v2/coderd/schedule/cron"
"github.com/coder/coder/v2/testutil"
)

Expand Down Expand Up @@ -432,7 +433,7 @@ func TestCalculateAutoStop(t *testing.T) {
}, nil
}

sched, err := schedule.Daily(c.userQuietHoursSchedule)
sched, err := cron.Daily(c.userQuietHoursSchedule)
if !assert.NoError(t, err) {
return schedule.UserQuietHoursScheduleOptions{}, err
}
Expand Down
20 changes: 10 additions & 10 deletions coderd/schedule/cron.go → coderd/schedule/cron/cron.go
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
// package schedule provides utilities for managing template and workspace
// autostart and autostop schedules. This includes utilities for parsing and
// deserializing cron-style expressions.
package schedule
package cron

import (
"fmt"
"strings"
"time"

"github.com/robfig/cron/v3"
rbcron "github.com/robfig/cron/v3"
"golang.org/x/xerrors"
)

// For the purposes of this library, we only need minute, hour, and
// day-of-week. However to ensure interoperability we will use the standard
// five-valued cron format. Descriptors are not supported.
const parserFormat = cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow
const parserFormat = rbcron.Minute | rbcron.Hour | rbcron.Dom | rbcron.Month | rbcron.Dow

var defaultParser = cron.NewParser(parserFormat)
var defaultParser = rbcron.NewParser(parserFormat)

// Weekly parses a Schedule from spec scoped to a recurring weekly event.
// Spec consists of the following space-delimited fields, in the following order:
Expand All @@ -30,11 +30,11 @@ var defaultParser = cron.NewParser(parserFormat)
//
// Example Usage:
//
// local_sched, _ := schedule.Weekly("59 23 *")
// local_sched, _ := cron.Weekly("59 23 *")
// fmt.Println(sched.Next(time.Now().Format(time.RFC3339)))
// // Output: 2022-04-04T23:59:00Z
//
// us_sched, _ := schedule.Weekly("CRON_TZ=US/Central 30 9 1-5")
// us_sched, _ := cron.Weekly("CRON_TZ=US/Central 30 9 1-5")
// fmt.Println(sched.Next(time.Now()).Format(time.RFC3339))
// // Output: 2022-04-04T14:30:00Z
func Weekly(raw string) (*Schedule, error) {
Expand All @@ -56,11 +56,11 @@ func Weekly(raw string) (*Schedule, error) {
//
// Example Usage:
//
// local_sched, _ := schedule.Weekly("59 23 * * *")
// local_sched, _ := cron.Weekly("59 23 * * *")
// fmt.Println(sched.Next(time.Now().Format(time.RFC3339)))
// // Output: 2022-04-04T23:59:00Z
//
// us_sched, _ := schedule.Weekly("CRON_TZ=US/Central 30 9 * * *")
// us_sched, _ := cron.Weekly("CRON_TZ=US/Central 30 9 * * *")
// fmt.Println(sched.Next(time.Now()).Format(time.RFC3339))
// // Output: 2022-04-04T14:30:00Z
func Daily(raw string) (*Schedule, error) {
Expand All @@ -83,7 +83,7 @@ func parse(raw string) (*Schedule, error) {
return nil, xerrors.Errorf("parse schedule: %w", err)
}

schedule, ok := specSched.(*cron.SpecSchedule)
schedule, ok := specSched.(*rbcron.SpecSchedule)
if !ok {
return nil, xerrors.Errorf("expected *cron.SpecSchedule but got %T", specSched)
}
Expand All @@ -110,7 +110,7 @@ func parse(raw string) (*Schedule, error) {
// It's essentially a wrapper for robfig/cron/v3 that has additional
// convenience methods.
type Schedule struct {
sched *cron.SpecSchedule
sched *rbcron.SpecSchedule
// XXX: there isn't any nice way for robfig/cron to serialize
cronStr string
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package schedule_test
package cron_test

import (
"testing"
"time"

"github.com/stretchr/testify/require"

"github.com/coder/coder/v2/coderd/schedule"
"github.com/coder/coder/v2/coderd/schedule/cron"
)

func Test_Weekly(t *testing.T) {
Expand Down Expand Up @@ -144,7 +144,7 @@ func Test_Weekly(t *testing.T) {
testCase := testCase
t.Run(testCase.name, func(t *testing.T) {
t.Parallel()
actual, err := schedule.Weekly(testCase.spec)
actual, err := cron.Weekly(testCase.spec)
if testCase.expectedError == "" {
nextTime := actual.Next(testCase.at)
require.NoError(t, err)
Expand Down
3 changes: 2 additions & 1 deletion coderd/schedule/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/google/uuid"

"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/schedule/cron"
)

type UserQuietHoursScheduleOptions struct {
Expand All @@ -17,7 +18,7 @@ type UserQuietHoursScheduleOptions struct {
// schedule (and UserSet will be false). If quiet hours schedules are not
// entitled or disabled instance-wide, this value will be nil to denote that
// quiet hours windows should not be used.
Schedule *Schedule
Schedule *cron.Schedule
UserSet bool
}

Expand Down
4 changes: 2 additions & 2 deletions coderd/workspaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
"github.com/coder/coder/v2/coderd/httpapi"
"github.com/coder/coder/v2/coderd/httpmw"
"github.com/coder/coder/v2/coderd/rbac"
"github.com/coder/coder/v2/coderd/schedule"
"github.com/coder/coder/v2/coderd/schedule/cron"
"github.com/coder/coder/v2/coderd/searchquery"
"github.com/coder/coder/v2/coderd/telemetry"
"github.com/coder/coder/v2/coderd/util/ptr"
Expand Down Expand Up @@ -1306,7 +1306,7 @@ func validWorkspaceSchedule(s *string) (sql.NullString, error) {
return sql.NullString{}, nil
}

_, err := schedule.Weekly(*s)
_, err := cron.Weekly(*s)
if err != nil {
return sql.NullString{}, err
}
Expand Down
3 changes: 2 additions & 1 deletion coderd/workspaces_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/coder/coder/v2/coderd/parameter"
"github.com/coder/coder/v2/coderd/rbac"
"github.com/coder/coder/v2/coderd/schedule"
"github.com/coder/coder/v2/coderd/schedule/cron"
"github.com/coder/coder/v2/coderd/util/ptr"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/codersdk/agentsdk"
Expand Down Expand Up @@ -1869,7 +1870,7 @@ func TestWorkspaceUpdateAutostart(t *testing.T) {

require.EqualValues(t, *testCase.schedule, *updated.AutostartSchedule, "expected autostart schedule to equal requested")

sched, err := schedule.Weekly(*updated.AutostartSchedule)
sched, err := cron.Weekly(*updated.AutostartSchedule)
require.NoError(t, err, "parse returned schedule")

next := sched.Next(testCase.at)
Expand Down
3 changes: 2 additions & 1 deletion enterprise/coderd/schedule/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/coder/coder/v2/coderd/database"
agpl "github.com/coder/coder/v2/coderd/schedule"
"github.com/coder/coder/v2/coderd/schedule/cron"
"github.com/coder/coder/v2/coderd/tracing"
)

Expand Down Expand Up @@ -49,7 +50,7 @@ func (s *enterpriseUserQuietHoursScheduleStore) parseSchedule(ctx context.Contex
rawSchedule = s.defaultSchedule
}

sched, err := agpl.Daily(rawSchedule)
sched, err := cron.Daily(rawSchedule)
if err != nil {
// This shouldn't get hit during Gets, only Sets.
return agpl.UserQuietHoursScheduleOptions{}, xerrors.Errorf("parse daily schedule %q: %w", rawSchedule, err)
Expand Down
10 changes: 5 additions & 5 deletions enterprise/coderd/users_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"github.com/stretchr/testify/require"

"github.com/coder/coder/v2/coderd/coderdtest"
"github.com/coder/coder/v2/coderd/schedule"
"github.com/coder/coder/v2/coderd/schedule/cron"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/enterprise/coderd/coderdenttest"
"github.com/coder/coder/v2/enterprise/coderd/license"
Expand All @@ -22,14 +22,14 @@ func TestUserQuietHours(t *testing.T) {
t.Parallel()

defaultQuietHoursSchedule := "CRON_TZ=America/Chicago 0 0 * * *"
defaultScheduleParsed, err := schedule.Daily(defaultQuietHoursSchedule)
defaultScheduleParsed, err := cron.Daily(defaultQuietHoursSchedule)
require.NoError(t, err)
nextTime := defaultScheduleParsed.Next(time.Now().In(defaultScheduleParsed.Location()))
if time.Until(nextTime) < time.Hour {
// Use a different default schedule instead, because we want to avoid
// the schedule "ticking over" during this test run.
defaultQuietHoursSchedule = "CRON_TZ=America/Chicago 0 12 * * *"
defaultScheduleParsed, err = schedule.Daily(defaultQuietHoursSchedule)
defaultScheduleParsed, err = cron.Daily(defaultQuietHoursSchedule)
require.NoError(t, err)
}

Expand Down Expand Up @@ -61,14 +61,14 @@ func TestUserQuietHours(t *testing.T) {

// Set their quiet hours.
customQuietHoursSchedule := "CRON_TZ=Australia/Sydney 0 0 * * *"
customScheduleParsed, err := schedule.Daily(customQuietHoursSchedule)
customScheduleParsed, err := cron.Daily(customQuietHoursSchedule)
require.NoError(t, err)
nextTime = customScheduleParsed.Next(time.Now().In(customScheduleParsed.Location()))
if time.Until(nextTime) < time.Hour {
// Use a different default schedule instead, because we want to avoid
// the schedule "ticking over" during this test run.
customQuietHoursSchedule = "CRON_TZ=Australia/Sydney 0 12 * * *"
customScheduleParsed, err = schedule.Daily(customQuietHoursSchedule)
customScheduleParsed, err = cron.Daily(customQuietHoursSchedule)
require.NoError(t, err)
}

Expand Down
3 changes: 2 additions & 1 deletion enterprise/coderd/workspaces_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/coder/coder/v2/coderd/coderdtest"
"github.com/coder/coder/v2/coderd/database"
agplschedule "github.com/coder/coder/v2/coderd/schedule"
"github.com/coder/coder/v2/coderd/schedule/cron"
"github.com/coder/coder/v2/coderd/util/ptr"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/enterprise/coderd/coderdenttest"
Expand Down Expand Up @@ -585,7 +586,7 @@ func TestWorkspaceAutobuild(t *testing.T) {

template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)

sched, err := agplschedule.Weekly("CRON_TZ=UTC 0 * * * *")
sched, err := cron.Weekly("CRON_TZ=UTC 0 * * * *")
require.NoError(t, err)

ws := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) {
Expand Down