Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit259d517

Browse files
committed
Merge branch 'main' into statusbar/presleyp/1032
2 parents72c856e +50ad2f8 commit259d517

File tree

51 files changed

+1403
-314
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1403
-314
lines changed

‎.github/workflows/release.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
DOCKER_CLI_EXPERIMENTAL:"enabled"
1414
steps:
1515
# Docker is not included on macos-latest
16-
-uses:docker-practice/actions-setup-docker@v1
16+
-uses:docker-practice/actions-setup-docker@v1.0.8
1717

1818
-uses:actions/checkout@v3
1919
with:

‎cli/autostart.go

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,54 @@ func autostart() *cobra.Command {
2323
Short:"schedule a workspace to automatically start at a regular time",
2424
Long:autostartDescriptionLong,
2525
Example:"coder autostart enable my-workspace --minute 30 --hour 9 --days 1-5 --tz Europe/Dublin",
26-
Hidden:true,
2726
}
2827

28+
autostartCmd.AddCommand(autostartShow())
2929
autostartCmd.AddCommand(autostartEnable())
3030
autostartCmd.AddCommand(autostartDisable())
3131

3232
returnautostartCmd
3333
}
3434

35+
funcautostartShow()*cobra.Command {
36+
cmd:=&cobra.Command{
37+
Use:"show <workspace_name>",
38+
Args:cobra.ExactArgs(1),
39+
RunE:func(cmd*cobra.Command,args []string)error {
40+
client,err:=createClient(cmd)
41+
iferr!=nil {
42+
returnerr
43+
}
44+
organization,err:=currentOrganization(cmd,client)
45+
iferr!=nil {
46+
returnerr
47+
}
48+
49+
workspace,err:=client.WorkspaceByOwnerAndName(cmd.Context(),organization.ID,codersdk.Me,args[0])
50+
iferr!=nil {
51+
returnerr
52+
}
53+
54+
ifworkspace.AutostartSchedule=="" {
55+
_,_=fmt.Fprintf(cmd.OutOrStdout(),"not enabled\n")
56+
returnnil
57+
}
58+
59+
validSchedule,err:=schedule.Weekly(workspace.AutostartSchedule)
60+
iferr!=nil {
61+
// This should never happen.
62+
_,_=fmt.Fprintf(cmd.OutOrStdout(),"invalid autostart schedule %q for workspace %s: %s\n",workspace.AutostartSchedule,workspace.Name,err.Error())
63+
returnnil
64+
}
65+
66+
_,_=fmt.Fprintf(cmd.OutOrStdout(),"schedule: %s\nnext: %s\n",workspace.AutostartSchedule,validSchedule.Next(time.Now()))
67+
68+
returnnil
69+
},
70+
}
71+
returncmd
72+
}
73+
3574
funcautostartEnable()*cobra.Command {
3675
// yes some of these are technically numbers but the cron library will do that work
3776
varautostartMinutestring

‎cli/autostart_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,43 @@ import (
1111

1212
"github.com/coder/coder/cli/clitest"
1313
"github.com/coder/coder/coderd/coderdtest"
14+
"github.com/coder/coder/codersdk"
1415
)
1516

1617
funcTestAutostart(t*testing.T) {
1718
t.Parallel()
1819

20+
t.Run("ShowOK",func(t*testing.T) {
21+
t.Parallel()
22+
23+
var (
24+
ctx=context.Background()
25+
client=coderdtest.New(t,nil)
26+
_=coderdtest.NewProvisionerDaemon(t,client)
27+
user=coderdtest.CreateFirstUser(t,client)
28+
version=coderdtest.CreateTemplateVersion(t,client,user.OrganizationID,nil)
29+
_=coderdtest.AwaitTemplateVersionJob(t,client,version.ID)
30+
project=coderdtest.CreateTemplate(t,client,user.OrganizationID,version.ID)
31+
workspace=coderdtest.CreateWorkspace(t,client,user.OrganizationID,project.ID)
32+
cmdArgs= []string{"autostart","show",workspace.Name}
33+
sched="CRON_TZ=Europe/Dublin 30 17 * * 1-5"
34+
stdoutBuf=&bytes.Buffer{}
35+
)
36+
37+
err:=client.UpdateWorkspaceAutostart(ctx,workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{
38+
Schedule:sched,
39+
})
40+
require.NoError(t,err)
41+
42+
cmd,root:=clitest.New(t,cmdArgs...)
43+
clitest.SetupConfig(t,client,root)
44+
cmd.SetOut(stdoutBuf)
45+
46+
err=cmd.Execute()
47+
require.NoError(t,err,"unexpected error")
48+
require.Contains(t,stdoutBuf.String(),"schedule: "+sched)
49+
})
50+
1951
t.Run("EnableDisableOK",func(t*testing.T) {
2052
t.Parallel()
2153

‎cli/autostop.go

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,59 @@ The default autostop schedule is at 18:00 in your local timezone (TZ env, UTC by
1818

1919
funcautostop()*cobra.Command {
2020
autostopCmd:=&cobra.Command{
21-
Use:"autostop enable <workspace>",
22-
Short:"schedule a workspace to automatically stop at a regular time",
23-
Long:autostopDescriptionLong,
24-
Example:"coder autostop enable my-workspace --minute 0 --hour 18 --days 1-5 -tz Europe/Dublin",
25-
Hidden:true,
21+
Annotations:workspaceCommand,
22+
Use:"autostop enable <workspace>",
23+
Short:"schedule a workspace to automatically stop at a regular time",
24+
Long:autostopDescriptionLong,
25+
Example:"coder autostop enable my-workspace --minute 0 --hour 18 --days 1-5 -tz Europe/Dublin",
2626
}
2727

28+
autostopCmd.AddCommand(autostopShow())
2829
autostopCmd.AddCommand(autostopEnable())
2930
autostopCmd.AddCommand(autostopDisable())
3031

3132
returnautostopCmd
3233
}
3334

35+
funcautostopShow()*cobra.Command {
36+
cmd:=&cobra.Command{
37+
Use:"show <workspace_name>",
38+
Args:cobra.ExactArgs(1),
39+
RunE:func(cmd*cobra.Command,args []string)error {
40+
client,err:=createClient(cmd)
41+
iferr!=nil {
42+
returnerr
43+
}
44+
organization,err:=currentOrganization(cmd,client)
45+
iferr!=nil {
46+
returnerr
47+
}
48+
49+
workspace,err:=client.WorkspaceByOwnerAndName(cmd.Context(),organization.ID,codersdk.Me,args[0])
50+
iferr!=nil {
51+
returnerr
52+
}
53+
54+
ifworkspace.AutostopSchedule=="" {
55+
_,_=fmt.Fprintf(cmd.OutOrStdout(),"not enabled\n")
56+
returnnil
57+
}
58+
59+
validSchedule,err:=schedule.Weekly(workspace.AutostopSchedule)
60+
iferr!=nil {
61+
// This should never happen.
62+
_,_=fmt.Fprintf(cmd.OutOrStdout(),"invalid autostop schedule %q for workspace %s: %s\n",workspace.AutostopSchedule,workspace.Name,err.Error())
63+
returnnil
64+
}
65+
66+
_,_=fmt.Fprintf(cmd.OutOrStdout(),"schedule: %s\nnext: %s\n",workspace.AutostopSchedule,validSchedule.Next(time.Now()))
67+
68+
returnnil
69+
},
70+
}
71+
returncmd
72+
}
73+
3474
funcautostopEnable()*cobra.Command {
3575
// yes some of these are technically numbers but the cron library will do that work
3676
varautostopMinutestring

‎cli/autostop_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,43 @@ import (
1111

1212
"github.com/coder/coder/cli/clitest"
1313
"github.com/coder/coder/coderd/coderdtest"
14+
"github.com/coder/coder/codersdk"
1415
)
1516

1617
funcTestAutostop(t*testing.T) {
1718
t.Parallel()
1819

20+
t.Run("ShowOK",func(t*testing.T) {
21+
t.Parallel()
22+
23+
var (
24+
ctx=context.Background()
25+
client=coderdtest.New(t,nil)
26+
_=coderdtest.NewProvisionerDaemon(t,client)
27+
user=coderdtest.CreateFirstUser(t,client)
28+
version=coderdtest.CreateTemplateVersion(t,client,user.OrganizationID,nil)
29+
_=coderdtest.AwaitTemplateVersionJob(t,client,version.ID)
30+
project=coderdtest.CreateTemplate(t,client,user.OrganizationID,version.ID)
31+
workspace=coderdtest.CreateWorkspace(t,client,user.OrganizationID,project.ID)
32+
cmdArgs= []string{"autostop","show",workspace.Name}
33+
sched="CRON_TZ=Europe/Dublin 30 17 * * 1-5"
34+
stdoutBuf=&bytes.Buffer{}
35+
)
36+
37+
err:=client.UpdateWorkspaceAutostop(ctx,workspace.ID, codersdk.UpdateWorkspaceAutostopRequest{
38+
Schedule:sched,
39+
})
40+
require.NoError(t,err)
41+
42+
cmd,root:=clitest.New(t,cmdArgs...)
43+
clitest.SetupConfig(t,client,root)
44+
cmd.SetOut(stdoutBuf)
45+
46+
err=cmd.Execute()
47+
require.NoError(t,err,"unexpected error")
48+
require.Contains(t,stdoutBuf.String(),"schedule: "+sched)
49+
})
50+
1951
t.Run("EnableDisableOK",func(t*testing.T) {
2052
t.Parallel()
2153

‎cli/list.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func list() *cobra.Command {
4949
}
5050

5151
tableWriter:=cliui.Table()
52-
header:= table.Row{"workspace","template","status","last built","outdated"}
52+
header:= table.Row{"workspace","template","status","last built","outdated","autostart","autostop"}
5353
tableWriter.AppendHeader(header)
5454
tableWriter.SortBy([]table.SortBy{{
5555
Name:"workspace",
@@ -108,13 +108,25 @@ func list() *cobra.Command {
108108
durationDisplay=durationDisplay[:len(durationDisplay)-2]
109109
}
110110

111+
autostartDisplay:="not enabled"
112+
ifworkspace.AutostartSchedule!="" {
113+
autostartDisplay=workspace.AutostartSchedule
114+
}
115+
116+
autostopDisplay:="not enabled"
117+
ifworkspace.AutostopSchedule!="" {
118+
autostopDisplay=workspace.AutostopSchedule
119+
}
120+
111121
user:=usersByID[workspace.OwnerID]
112122
tableWriter.AppendRow(table.Row{
113123
user.Username+"/"+workspace.Name,
114124
workspace.TemplateName,
115125
status,
116126
durationDisplay,
117127
workspace.Outdated,
128+
autostartDisplay,
129+
autostopDisplay,
118130
})
119131
}
120132
_,err=fmt.Fprintln(cmd.OutOrStdout(),tableWriter.Render())

‎cli/ssh.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@ package cli
22

33
import (
44
"context"
5+
"fmt"
56
"io"
67
"os"
8+
"path/filepath"
79
"strings"
10+
"time"
811

12+
"github.com/gen2brain/beeep"
13+
"github.com/gofrs/flock"
914
"github.com/google/uuid"
1015
"github.com/mattn/go-isatty"
1116
"github.com/spf13/cobra"
@@ -15,10 +20,15 @@ import (
1520

1621
"github.com/coder/coder/cli/cliflag"
1722
"github.com/coder/coder/cli/cliui"
23+
"github.com/coder/coder/coderd/autobuild/notify"
24+
"github.com/coder/coder/coderd/autobuild/schedule"
1825
"github.com/coder/coder/coderd/database"
1926
"github.com/coder/coder/codersdk"
2027
)
2128

29+
varautostopPollInterval=30*time.Second
30+
varautostopNotifyCountdown= []time.Duration{5*time.Minute}
31+
2232
funcssh()*cobra.Command {
2333
var (
2434
stdiobool
@@ -108,6 +118,9 @@ func ssh() *cobra.Command {
108118
}
109119
deferconn.Close()
110120

121+
stopPolling:=tryPollWorkspaceAutostop(cmd.Context(),client,workspace)
122+
deferstopPolling()
123+
111124
ifstdio {
112125
rawSSH,err:=conn.SSH()
113126
iferr!=nil {
@@ -179,3 +192,57 @@ func ssh() *cobra.Command {
179192

180193
returncmd
181194
}
195+
196+
// Attempt to poll workspace autostop. We write a per-workspace lockfile to
197+
// avoid spamming the user with notifications in case of multiple instances
198+
// of the CLI running simultaneously.
199+
functryPollWorkspaceAutostop(ctx context.Context,client*codersdk.Client,workspace codersdk.Workspace) (stopfunc()) {
200+
lock:=flock.New(filepath.Join(os.TempDir(),"coder-autostop-notify-"+workspace.ID.String()))
201+
condition:=notifyCondition(ctx,client,workspace.ID,lock)
202+
returnnotify.Notify(condition,autostopPollInterval,autostopNotifyCountdown...)
203+
}
204+
205+
// Notify the user if the workspace is due to shutdown.
206+
funcnotifyCondition(ctx context.Context,client*codersdk.Client,workspaceID uuid.UUID,lock*flock.Flock) notify.Condition {
207+
returnfunc(now time.Time) (deadline time.Time,callbackfunc()) {
208+
// Keep trying to regain the lock.
209+
locked,err:=lock.TryLockContext(ctx,autostopPollInterval)
210+
iferr!=nil||!locked {
211+
return time.Time{},nil
212+
}
213+
214+
ws,err:=client.Workspace(ctx,workspaceID)
215+
iferr!=nil {
216+
return time.Time{},nil
217+
}
218+
219+
ifws.AutostopSchedule=="" {
220+
return time.Time{},nil
221+
}
222+
223+
sched,err:=schedule.Weekly(ws.AutostopSchedule)
224+
iferr!=nil {
225+
return time.Time{},nil
226+
}
227+
228+
deadline=sched.Next(now)
229+
callback=func() {
230+
ttl:=deadline.Sub(now)
231+
vartitle,bodystring
232+
ifttl>time.Minute {
233+
title=fmt.Sprintf(`Workspace %s stopping in %.0f mins`,ws.Name,ttl.Minutes())
234+
body=fmt.Sprintf(
235+
`Your Coder workspace %s is scheduled to stop at %s.`,
236+
ws.Name,
237+
deadline.Format(time.Kitchen),
238+
)
239+
}else {
240+
title=fmt.Sprintf("Workspace %s stopping!",ws.Name)
241+
body=fmt.Sprintf("Your Coder workspace %s is stopping any time now!",ws.Name)
242+
}
243+
// notify user with a native system notification (best effort)
244+
_=beeep.Notify(title,body,"")
245+
}
246+
returndeadline.Truncate(time.Minute),callback
247+
}
248+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp