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

Commit8766a33

Browse files
committed
Add create workspace support
1 parentbff96b6 commit8766a33

File tree

9 files changed

+366
-69
lines changed

9 files changed

+366
-69
lines changed

‎.vscode/settings.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
"nhooyr",
4545
"nolint",
4646
"nosec",
47+
"ntqry",
4748
"oneof",
4849
"parameterscopeid",
4950
"promptui",

‎cli/clitest/clitest.go‎

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,36 @@
11
package clitest
22

33
import (
4+
"archive/tar"
45
"bufio"
6+
"bytes"
57
"context"
8+
"errors"
69
"io"
10+
"os"
11+
"path/filepath"
12+
"regexp"
713
"testing"
814

915
"github.com/spf13/cobra"
1016
"github.com/stretchr/testify/require"
17+
"golang.org/x/xerrors"
1118

1219
"github.com/coder/coder/cli"
1320
"github.com/coder/coder/cli/config"
1421
"github.com/coder/coder/coderd"
1522
"github.com/coder/coder/coderd/coderdtest"
1623
"github.com/coder/coder/codersdk"
24+
"github.com/coder/coder/provisioner/echo"
1725
)
1826

27+
var (
28+
// Used to ensure terminal output doesn't have anything crazy!
29+
stripAnsi=regexp.MustCompile("[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))")
30+
)
31+
32+
// New creates a CLI instance with a configuration pointed to a
33+
// temporary testing directory.
1934
funcNew(t*testing.T,args...string) (*cobra.Command, config.Root) {
2035
cmd:=cli.Root()
2136
dir:=t.TempDir()
@@ -24,6 +39,8 @@ func New(t *testing.T, args ...string) (*cobra.Command, config.Root) {
2439
returncmd,root
2540
}
2641

42+
// CreateInitialUser creates the initial user and write's the session
43+
// token to the config root provided.
2744
funcCreateInitialUser(t*testing.T,client*codersdk.Client,root config.Root) coderd.CreateInitialUserRequest {
2845
user:=coderdtest.CreateInitialUser(t,client)
2946
resp,err:=client.LoginWithPassword(context.Background(), coderd.LoginWithPasswordRequest{
@@ -38,6 +55,19 @@ func CreateInitialUser(t *testing.T, client *codersdk.Client, root config.Root)
3855
returnuser
3956
}
4057

58+
// CreateProjectVersionSource writes the echo provisioner responses into a
59+
// new temporary testing directory.
60+
funcCreateProjectVersionSource(t*testing.T,responses*echo.Responses)string {
61+
directory:=t.TempDir()
62+
data,err:=echo.Tar(responses)
63+
require.NoError(t,err)
64+
err=extractTar(data,directory)
65+
require.NoError(t,err)
66+
returndirectory
67+
}
68+
69+
// StdoutLogs provides a writer to t.Log that strips
70+
// all ANSI escape codes.
4171
funcStdoutLogs(t*testing.T) io.Writer {
4272
reader,writer:=io.Pipe()
4373
scanner:=bufio.NewScanner(reader)
@@ -50,8 +80,52 @@ func StdoutLogs(t *testing.T) io.Writer {
5080
ifscanner.Err()!=nil {
5181
return
5282
}
53-
t.Log(scanner.Text())
83+
t.Log(stripAnsi.ReplaceAllString(scanner.Text(),""))
5484
}
5585
}()
5686
returnwriter
5787
}
88+
89+
funcextractTar(data []byte,directorystring)error {
90+
reader:=tar.NewReader(bytes.NewBuffer(data))
91+
for {
92+
header,err:=reader.Next()
93+
iferrors.Is(err,io.EOF) {
94+
break
95+
}
96+
iferr!=nil {
97+
returnxerrors.Errorf("read project source archive: %w",err)
98+
}
99+
path:=filepath.Join(directory,header.Name)
100+
mode:=header.FileInfo().Mode()
101+
ifmode==0 {
102+
mode=0600
103+
}
104+
switchheader.Typeflag {
105+
casetar.TypeDir:
106+
err=os.MkdirAll(path,mode)
107+
iferr!=nil {
108+
returnxerrors.Errorf("mkdir: %w",err)
109+
}
110+
casetar.TypeReg:
111+
file,err:=os.OpenFile(path,os.O_CREATE|os.O_RDWR,mode)
112+
iferr!=nil {
113+
returnxerrors.Errorf("create file %q: %w",path,err)
114+
}
115+
// Max file size of 10MB.
116+
_,err=io.CopyN(file,reader, (1<<20)*10)
117+
iferrors.Is(err,io.EOF) {
118+
err=nil
119+
}
120+
iferr!=nil {
121+
_=file.Close()
122+
returnerr
123+
}
124+
err=file.Close()
125+
iferr!=nil {
126+
returnerr
127+
}
128+
}
129+
}
130+
returnnil
131+
}

‎cli/login.go‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func login() *cobra.Command {
4949
}
5050
_,_=fmt.Fprintf(cmd.OutOrStdout(),"%s Your Coder deployment hasn't been set up!\n",color.HiBlackString(">"))
5151

52-
_,err:=runPrompt(cmd,&promptui.Prompt{
52+
_,err:=prompt(cmd,&promptui.Prompt{
5353
Label:"Would you like to create the first user?",
5454
IsConfirm:true,
5555
Default:"y",
@@ -61,23 +61,23 @@ func login() *cobra.Command {
6161
iferr!=nil {
6262
returnxerrors.Errorf("get current user: %w",err)
6363
}
64-
username,err:=runPrompt(cmd,&promptui.Prompt{
64+
username,err:=prompt(cmd,&promptui.Prompt{
6565
Label:"What username would you like?",
6666
Default:currentUser.Username,
6767
})
6868
iferr!=nil {
6969
returnxerrors.Errorf("pick username prompt: %w",err)
7070
}
7171

72-
organization,err:=runPrompt(cmd,&promptui.Prompt{
72+
organization,err:=prompt(cmd,&promptui.Prompt{
7373
Label:"What is the name of your organization?",
7474
Default:"acme-corp",
7575
})
7676
iferr!=nil {
7777
returnxerrors.Errorf("pick organization prompt: %w",err)
7878
}
7979

80-
email,err:=runPrompt(cmd,&promptui.Prompt{
80+
email,err:=prompt(cmd,&promptui.Prompt{
8181
Label:"What's your email?",
8282
Validate:func(sstring)error {
8383
err:=validator.New().Var(s,"email")
@@ -91,7 +91,7 @@ func login() *cobra.Command {
9191
returnxerrors.Errorf("specify email prompt: %w",err)
9292
}
9393

94-
password,err:=runPrompt(cmd,&promptui.Prompt{
94+
password,err:=prompt(cmd,&promptui.Prompt{
9595
Label:"Enter a password:",
9696
Mask:'*',
9797
})

‎cli/projectcreate.go‎

Lines changed: 35 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,18 @@ package cli
33
import (
44
"archive/tar"
55
"bytes"
6+
"errors"
67
"fmt"
78
"io"
89
"os"
910
"path/filepath"
10-
"strings"
1111
"time"
1212

1313
"github.com/briandowns/spinner"
1414
"github.com/fatih/color"
1515
"github.com/google/uuid"
1616
"github.com/manifoldco/promptui"
1717
"github.com/spf13/cobra"
18-
"github.com/xlab/treeprint"
1918
"golang.org/x/xerrors"
2019

2120
"github.com/coder/coder/coderd"
@@ -27,7 +26,8 @@ import (
2726

2827
funcprojectCreate()*cobra.Command {
2928
var (
30-
directorystring
29+
directorystring
30+
provisionerstring
3131
)
3232
cmd:=&cobra.Command{
3333
Use:"create",
@@ -41,16 +41,19 @@ func projectCreate() *cobra.Command {
4141
iferr!=nil {
4242
returnerr
4343
}
44-
_,err=runPrompt(cmd,&promptui.Prompt{
44+
_,err=prompt(cmd,&promptui.Prompt{
4545
Default:"y",
4646
IsConfirm:true,
4747
Label:fmt.Sprintf("Set up %s in your organization?",color.New(color.FgHiCyan).Sprintf("%q",directory)),
4848
})
4949
iferr!=nil {
50+
iferrors.Is(err,promptui.ErrAbort) {
51+
returnnil
52+
}
5053
returnerr
5154
}
5255

53-
name,err:=runPrompt(cmd,&promptui.Prompt{
56+
name,err:=prompt(cmd,&promptui.Prompt{
5457
Default:filepath.Base(directory),
5558
Label:"What's your project's name?",
5659
Validate:func(sstring)error {
@@ -65,7 +68,7 @@ func projectCreate() *cobra.Command {
6568
returnerr
6669
}
6770

68-
job,err:=doProjectLoop(cmd,client,organization,directory, []coderd.CreateParameterValueRequest{})
71+
job,err:=validateProjectVersionSource(cmd,client,organization,database.ProvisionerType(provisioner),directory)
6972
iferr!=nil {
7073
returnerr
7174
}
@@ -77,27 +80,44 @@ func projectCreate() *cobra.Command {
7780
returnerr
7881
}
7982

83+
_,err=prompt(cmd,&promptui.Prompt{
84+
Label:"Create project?",
85+
IsConfirm:true,
86+
Default:"y",
87+
})
88+
iferr!=nil {
89+
iferrors.Is(err,promptui.ErrAbort) {
90+
returnnil
91+
}
92+
returnerr
93+
}
94+
8095
_,_=fmt.Fprintf(cmd.OutOrStdout(),"%s The %s project has been created!\n",color.HiBlackString(">"),color.HiCyanString(project.Name))
81-
_,err=runPrompt(cmd,&promptui.Prompt{
96+
_,err=prompt(cmd,&promptui.Prompt{
8297
Label:"Create a new workspace?",
8398
IsConfirm:true,
8499
Default:"y",
85100
})
86101
iferr!=nil {
102+
iferrors.Is(err,promptui.ErrAbort) {
103+
returnnil
104+
}
87105
returnerr
88106
}
89107

90-
fmt.Printf("Create a new workspace now!\n")
91108
returnnil
92109
},
93110
}
94111
currentDirectory,_:=os.Getwd()
95112
cmd.Flags().StringVarP(&directory,"directory","d",currentDirectory,"Specify the directory to create from")
113+
cmd.Flags().StringVarP(&provisioner,"provisioner","p","terraform","Customize the provisioner backend")
114+
// This is for testing! There's only 1 provisioner type right now.
115+
cmd.Flags().MarkHidden("provisioner")
96116

97117
returncmd
98118
}
99119

100-
funcdoProjectLoop(cmd*cobra.Command,client*codersdk.Client,organization coderd.Organization,directorystring,params []coderd.CreateParameterValueRequest) (*coderd.ProvisionerJob,error) {
120+
funcvalidateProjectVersionSource(cmd*cobra.Command,client*codersdk.Client,organization coderd.Organization,provisioner database.ProvisionerType,directorystring,parameters...coderd.CreateParameterValueRequest) (*coderd.ProvisionerJob,error) {
101121
spin:=spinner.New(spinner.CharSets[5],100*time.Millisecond)
102122
spin.Writer=cmd.OutOrStdout()
103123
spin.Suffix=" Uploading current directory..."
@@ -118,8 +138,8 @@ func doProjectLoop(cmd *cobra.Command, client *codersdk.Client, organization cod
118138
job,err:=client.CreateProjectVersionImportProvisionerJob(cmd.Context(),organization.Name, coderd.CreateProjectImportJobRequest{
119139
StorageMethod:database.ProvisionerStorageMethodFile,
120140
StorageSource:resp.Hash,
121-
Provisioner:database.ProvisionerTypeTerraform,
122-
ParameterValues:params,
141+
Provisioner:provisioner,
142+
ParameterValues:parameters,
123143
})
124144
iferr!=nil {
125145
returnnil,err
@@ -168,20 +188,20 @@ func doProjectLoop(cmd *cobra.Command, client *codersdk.Client, organization cod
168188
ifparameterSchema.Name==parameter.CoderWorkspaceTransition {
169189
continue
170190
}
171-
value,err:=runPrompt(cmd,&promptui.Prompt{
191+
value,err:=prompt(cmd,&promptui.Prompt{
172192
Label:fmt.Sprintf("Enter value for %s:",color.HiCyanString(parameterSchema.Name)),
173193
})
174194
iferr!=nil {
175195
returnnil,err
176196
}
177-
params=append(params, coderd.CreateParameterValueRequest{
197+
parameters=append(parameters, coderd.CreateParameterValueRequest{
178198
Name:parameterSchema.Name,
179199
SourceValue:value,
180200
SourceScheme:database.ParameterSourceSchemeData,
181201
DestinationScheme:parameterSchema.DefaultDestinationScheme,
182202
})
183203
}
184-
returndoProjectLoop(cmd,client,organization,directory,params)
204+
returnvalidateProjectVersionSource(cmd,client,organization,provisioner,directory,parameters...)
185205
}
186206

187207
ifjob.Status!=coderd.ProvisionerJobStatusSucceeded {
@@ -198,50 +218,7 @@ func doProjectLoop(cmd *cobra.Command, client *codersdk.Client, organization cod
198218
iferr!=nil {
199219
returnnil,err
200220
}
201-
return&job,outputProjectInformation(cmd,parameterSchemas,parameterValues,resources)
202-
}
203-
204-
funcoutputProjectInformation(cmd*cobra.Command,parameterSchemas []coderd.ParameterSchema,parameterValues []coderd.ComputedParameterValue,resources []coderd.ProjectImportJobResource)error {
205-
schemaByID:=map[string]coderd.ParameterSchema{}
206-
for_,schema:=rangeparameterSchemas {
207-
schemaByID[schema.ID.String()]=schema
208-
}
209-
210-
_,_=fmt.Fprintf(cmd.OutOrStdout(),"\n %s\n\n",color.HiBlackString("Parameters"))
211-
for_,value:=rangeparameterValues {
212-
schema,ok:=schemaByID[value.SchemaID.String()]
213-
if!ok {
214-
returnxerrors.Errorf("schema not found: %s",value.Name)
215-
}
216-
displayValue:=value.SourceValue
217-
if!schema.RedisplayValue {
218-
displayValue="<redacted>"
219-
}
220-
output:=fmt.Sprintf("%s %s %s",color.HiCyanString(value.Name),color.HiBlackString("="),displayValue)
221-
ifvalue.DefaultSourceValue {
222-
output+=" (default value)"
223-
}elseifvalue.Scope!=database.ParameterScopeImportJob {
224-
output+=fmt.Sprintf(" (inherited from %s)",value.Scope)
225-
}
226-
227-
root:=treeprint.NewWithRoot(output)
228-
ifschema.Description!="" {
229-
root.AddBranch(fmt.Sprintf("%s\n%s\n",color.HiBlackString("Description"),schema.Description))
230-
}
231-
ifschema.AllowOverrideSource {
232-
root.AddBranch(fmt.Sprintf("%s Users can customize this value!",color.HiYellowString("+")))
233-
}
234-
_,_=fmt.Fprintln(cmd.OutOrStdout()," "+strings.Join(strings.Split(root.String(),"\n"),"\n "))
235-
}
236-
_,_=fmt.Fprintf(cmd.OutOrStdout()," %s\n\n",color.HiBlackString("Resources"))
237-
for_,resource:=rangeresources {
238-
transition:=color.HiGreenString("start")
239-
ifresource.Transition==database.WorkspaceTransitionStop {
240-
transition=color.HiRedString("stop")
241-
}
242-
_,_=fmt.Fprintf(cmd.OutOrStdout()," %s %s on %s\n\n",color.HiCyanString(resource.Type),color.HiCyanString(resource.Name),transition)
243-
}
244-
returnnil
221+
return&job,displayProjectImportInfo(cmd,parameterSchemas,parameterValues,resources)
245222
}
246223

247224
functarDirectory(directorystring) ([]byte,error) {

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp