Skip to content

Commit dc86c0e

Browse files
committed
Create project fully works!!!
1 parent 79a56b6 commit dc86c0e

File tree

4 files changed

+162
-136
lines changed

4 files changed

+162
-136
lines changed

cli/projectcreate.go

Lines changed: 152 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,19 @@ import (
77
"io"
88
"os"
99
"path/filepath"
10+
"strings"
1011
"time"
1112

1213
"github.com/briandowns/spinner"
1314
"github.com/fatih/color"
1415
"github.com/google/uuid"
1516
"github.com/manifoldco/promptui"
1617
"github.com/spf13/cobra"
18+
"github.com/xlab/treeprint"
1719
"golang.org/x/xerrors"
1820

1921
"github.com/coder/coder/coderd"
22+
"github.com/coder/coder/coderd/parameter"
2023
"github.com/coder/coder/codersdk"
2124
"github.com/coder/coder/database"
2225
"github.com/coder/coder/provisionerd"
@@ -62,150 +65,178 @@ func projectCreate() *cobra.Command {
6265
return err
6366
}
6467

65-
spin := spinner.New(spinner.CharSets[0], 25*time.Millisecond)
66-
spin.Suffix = " Uploading current directory..."
67-
spin.Start()
68-
69-
defer spin.Stop()
70-
71-
bytes, err := tarDirectory(directory)
68+
job, err := doProjectLoop(cmd, client, organization, directory, []coderd.CreateParameterValueRequest{})
7269
if err != nil {
7370
return err
7471
}
75-
76-
resp, err := client.UploadFile(cmd.Context(), codersdk.ContentTypeTar, bytes)
72+
project, err := client.CreateProject(cmd.Context(), organization.Name, coderd.CreateProjectRequest{
73+
Name: name,
74+
VersionImportJobID: job.ID,
75+
})
7776
if err != nil {
7877
return err
7978
}
8079

81-
job, err := client.CreateProjectVersionImportProvisionerJob(cmd.Context(), organization.Name, coderd.CreateProjectImportJobRequest{
82-
StorageMethod: database.ProvisionerStorageMethodFile,
83-
StorageSource: resp.Hash,
84-
Provisioner: database.ProvisionerTypeTerraform,
80+
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s The %s project has been created!\n", color.HiBlackString(">"), color.HiCyanString(project.Name))
81+
_, err = runPrompt(cmd, &promptui.Prompt{
82+
Label: "Create a new workspace?",
83+
IsConfirm: true,
84+
Default: "y",
8585
})
8686
if err != nil {
8787
return err
8888
}
89-
spin.Stop()
9089

91-
logs, err := client.FollowProvisionerJobLogsAfter(cmd.Context(), organization.Name, job.ID, time.Time{})
92-
if err != nil {
93-
return err
94-
}
95-
for {
96-
log, ok := <-logs
97-
if !ok {
98-
break
99-
}
100-
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s %s\n", color.HiGreenString("[tf]"), log.Output)
101-
}
90+
fmt.Printf("Create a new workspace now!\n")
91+
return nil
92+
},
93+
}
94+
currentDirectory, _ := os.Getwd()
95+
cmd.Flags().StringVarP(&directory, "directory", "d", currentDirectory, "Specify the directory to create from")
10296

103-
job, err = client.ProvisionerJob(cmd.Context(), organization.Name, job.ID)
104-
if err != nil {
105-
return err
106-
}
97+
return cmd
98+
}
10799

108-
if provisionerd.IsMissingParameterError(job.Error) {
109-
fmt.Printf("Missing something!\n")
110-
return nil
111-
}
100+
func doProjectLoop(cmd *cobra.Command, client *codersdk.Client, organization coderd.Organization, directory string, params []coderd.CreateParameterValueRequest) (*coderd.ProvisionerJob, error) {
101+
spin := spinner.New(spinner.CharSets[5], 100*time.Millisecond)
102+
spin.Writer = cmd.OutOrStdout()
103+
spin.Suffix = " Uploading current directory..."
104+
spin.Color("fgHiGreen")
105+
spin.Start()
106+
defer spin.Stop()
112107

113-
resources, err := client.ProvisionerJobResources(cmd.Context(), organization.Name, job.ID)
114-
if err != nil {
115-
return err
116-
}
108+
bytes, err := tarDirectory(directory)
109+
if err != nil {
110+
return nil, err
111+
}
112+
113+
resp, err := client.UploadFile(cmd.Context(), codersdk.ContentTypeTar, bytes)
114+
if err != nil {
115+
return nil, err
116+
}
117117

118-
fmt.Printf("Resources: %+v\n", resources)
118+
job, err := client.CreateProjectVersionImportProvisionerJob(cmd.Context(), organization.Name, coderd.CreateProjectImportJobRequest{
119+
StorageMethod: database.ProvisionerStorageMethodFile,
120+
StorageSource: resp.Hash,
121+
Provisioner: database.ProvisionerTypeTerraform,
122+
ParameterValues: params,
123+
})
124+
if err != nil {
125+
return nil, err
126+
}
119127

120-
project, err := client.CreateProject(cmd.Context(), organization.Name, coderd.CreateProjectRequest{
121-
Name: name,
122-
VersionImportJobID: job.ID,
128+
spin.Suffix = " Waiting for the import to complete..."
129+
130+
logs, err := client.FollowProvisionerJobLogsAfter(cmd.Context(), organization.Name, job.ID, time.Time{})
131+
if err != nil {
132+
return nil, err
133+
}
134+
for {
135+
_, ok := <-logs
136+
if !ok {
137+
break
138+
}
139+
// _, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s %s\n", color.HiGreenString("[tf]"), log.Output)
140+
}
141+
142+
job, err = client.ProvisionerJob(cmd.Context(), organization.Name, job.ID)
143+
if err != nil {
144+
return nil, err
145+
}
146+
147+
parameterSchemas, err := client.ProvisionerJobParameterSchemas(cmd.Context(), organization.Name, job.ID)
148+
if err != nil {
149+
return nil, err
150+
}
151+
parameterValues, err := client.ProvisionerJobParameterValues(cmd.Context(), organization.Name, job.ID)
152+
if err != nil {
153+
return nil, err
154+
}
155+
spin.Stop()
156+
157+
if provisionerd.IsMissingParameterError(job.Error) {
158+
valuesBySchemaID := map[string]coderd.ComputedParameterValue{}
159+
for _, parameterValue := range parameterValues {
160+
valuesBySchemaID[parameterValue.SchemaID.String()] = parameterValue
161+
}
162+
for _, parameterSchema := range parameterSchemas {
163+
_, ok := valuesBySchemaID[parameterSchema.ID.String()]
164+
if ok {
165+
continue
166+
}
167+
if parameterSchema.Name == parameter.CoderWorkspaceTransition {
168+
continue
169+
}
170+
value, err := runPrompt(cmd, &promptui.Prompt{
171+
Label: fmt.Sprintf("Enter value for %s:", color.HiCyanString(parameterSchema.Name)),
123172
})
124173
if err != nil {
125-
return err
174+
return nil, err
126175
}
176+
params = append(params, coderd.CreateParameterValueRequest{
177+
Name: parameterSchema.Name,
178+
SourceValue: value,
179+
SourceScheme: database.ParameterSourceSchemeData,
180+
DestinationScheme: parameterSchema.DefaultDestinationScheme,
181+
})
182+
}
183+
return doProjectLoop(cmd, client, organization, directory, params)
184+
}
127185

128-
fmt.Printf("Project: %+v\n", project)
129-
130-
// _, _ = fmt.Fprintf(cmd.OutOrStdout(), "Parsed project source... displaying parameters:")
131-
132-
// schemas, err := client.ProvisionerJobParameterSchemas(cmd.Context(), organization.Name, job.ID)
133-
// if err != nil {
134-
// return err
135-
// }
136-
137-
// values, err := client.ProvisionerJobParameterValues(cmd.Context(), organization.Name, job.ID)
138-
// if err != nil {
139-
// return err
140-
// }
141-
// valueBySchemaID := map[string]coderd.ComputedParameterValue{}
142-
// for _, value := range values {
143-
// valueBySchemaID[value.SchemaID.String()] = value
144-
// }
145-
146-
// for _, schema := range schemas {
147-
// if value, ok := valueBySchemaID[schema.ID.String()]; ok {
148-
// fmt.Printf("Value for: %s %s\n", value.Name, value.SourceValue)
149-
// continue
150-
// }
151-
// fmt.Printf("No value for: %s\n", schema.Name)
152-
// }
153-
154-
// schemas, err := client.ProvisionerJobParameterSchemas(cmd.Context(), organization.Name, job.ID)
155-
// if err != nil {
156-
// return err
157-
// }
158-
// _, _ = fmt.Fprintf(cmd.OutOrStdout(), "\n %s\n\n", color.HiBlackString("Parameters"))
159-
160-
// for _, param := range params {
161-
// if param.Value == nil {
162-
// _, _ = fmt.Fprintf(cmd.OutOrStdout(), " %s = must be set\n", color.HiRedString(param.Schema.Name))
163-
// continue
164-
// }
165-
// value := param.Value.DestinationValue
166-
// if !param.Schema.RedisplayValue {
167-
// value = "<redacted>"
168-
// }
169-
// output := fmt.Sprintf(" %s = %s", color.HiGreenString(param.Value.SourceValue), color.CyanString(value))
170-
// param.Value.DefaultSourceValue = false
171-
// param.Value.Scope = database.ParameterScopeOrganization
172-
// param.Value.ScopeID = organization.ID
173-
// if param.Value.DefaultSourceValue {
174-
// output += " (default value)"
175-
// } else {
176-
// output += fmt.Sprintf(" (inherited from %s)", param.Value.Scope)
177-
// }
178-
// root := treeprint.NewWithRoot(output)
179-
// root.AddNode(color.HiBlackString("Description") + "\n" + param.Schema.Description)
180-
// fmt.Fprintln(cmd.OutOrStdout(), strings.Join(strings.Split(root.String(), "\n"), "\n "))
181-
// }
182-
183-
// for _, param := range params {
184-
// if param.Value != nil {
185-
// continue
186-
// }
187-
188-
// value, err := runPrompt(cmd, &promptui.Prompt{
189-
// Label: "Specify value for " + color.HiCyanString(param.Schema.Name),
190-
// Validate: func(s string) error {
191-
// // param.Schema.Vali
192-
// return nil
193-
// },
194-
// })
195-
// if err != nil {
196-
// continue
197-
// }
198-
// fmt.Printf(": %s\n", value)
199-
// }
200-
201-
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "Create project %q!\n", name)
202-
return nil
203-
},
186+
if job.Status != coderd.ProvisionerJobStatusSucceeded {
187+
return nil, xerrors.New(job.Error)
204188
}
205-
currentDirectory, _ := os.Getwd()
206-
cmd.Flags().StringVarP(&directory, "directory", "d", currentDirectory, "Specify the directory to create from")
207189

208-
return cmd
190+
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s Successfully imported project source!\n", color.HiGreenString("✓"))
191+
192+
resources, err := client.ProvisionerJobResources(cmd.Context(), organization.Name, job.ID)
193+
if err != nil {
194+
return nil, err
195+
}
196+
return &job, outputProjectInformation(cmd, parameterSchemas, parameterValues, resources)
197+
}
198+
199+
func outputProjectInformation(cmd *cobra.Command, parameterSchemas []coderd.ParameterSchema, parameterValues []coderd.ComputedParameterValue, resources []coderd.ProjectImportJobResource) error {
200+
schemaByID := map[string]coderd.ParameterSchema{}
201+
for _, schema := range parameterSchemas {
202+
schemaByID[schema.ID.String()] = schema
203+
}
204+
205+
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "\n %s\n\n", color.HiBlackString("Parameters"))
206+
for _, value := range parameterValues {
207+
schema, ok := schemaByID[value.SchemaID.String()]
208+
if !ok {
209+
return xerrors.Errorf("schema not found: %s", value.Name)
210+
}
211+
displayValue := value.SourceValue
212+
if !schema.RedisplayValue {
213+
displayValue = "<redacted>"
214+
}
215+
output := fmt.Sprintf("%s %s %s", color.HiCyanString(value.Name), color.HiBlackString("="), displayValue)
216+
if value.DefaultSourceValue {
217+
output += " (default value)"
218+
} else if value.Scope != database.ParameterScopeImportJob {
219+
output += fmt.Sprintf(" (inherited from %s)", value.Scope)
220+
}
221+
222+
root := treeprint.NewWithRoot(output)
223+
if schema.Description != "" {
224+
root.AddBranch(fmt.Sprintf("%s\n%s\n", color.HiBlackString("Description"), schema.Description))
225+
}
226+
if schema.AllowOverrideSource {
227+
root.AddBranch(fmt.Sprintf("%s Users can customize this value!", color.HiYellowString("+")))
228+
}
229+
_, _ = fmt.Fprintln(cmd.OutOrStdout(), " "+strings.Join(strings.Split(root.String(), "\n"), "\n "))
230+
}
231+
_, _ = fmt.Fprintf(cmd.OutOrStdout(), " %s\n\n", color.HiBlackString("Resources"))
232+
for _, resource := range resources {
233+
transition := color.HiGreenString("start")
234+
if resource.Transition == database.WorkspaceTransitionStop {
235+
transition = color.HiRedString("stop")
236+
}
237+
_, _ = fmt.Fprintf(cmd.OutOrStdout(), " %s %s on %s\n\n", color.HiCyanString(resource.Type), color.HiCyanString(resource.Name), transition)
238+
}
239+
return nil
209240
}
210241

211242
func tarDirectory(directory string) ([]byte, error) {

provisioner/terraform/parse.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ func convertVariableToParameter(variable *tfconfig.Variable) (*proto.ParameterSc
4646
Description: variable.Description,
4747
RedisplayValue: !variable.Sensitive,
4848
ValidationValueType: variable.Type,
49+
DefaultDestination: &proto.ParameterDestination{
50+
Scheme: proto.ParameterDestination_PROVISIONER_VARIABLE,
51+
},
4952
}
5053

5154
if variable.Default != nil {
@@ -57,9 +60,6 @@ func convertVariableToParameter(variable *tfconfig.Variable) (*proto.ParameterSc
5760
Scheme: proto.ParameterSource_DATA,
5861
Value: string(defaultData),
5962
}
60-
schema.DefaultDestination = &proto.ParameterDestination{
61-
Scheme: proto.ParameterDestination_PROVISIONER_VARIABLE,
62-
}
6363
}
6464

6565
if len(variable.Validations) > 0 && variable.Validations[0].Condition != nil {

provisioner/terraform/parse_test.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ func TestParse(t *testing.T) {
5555
Name: "A",
5656
RedisplayValue: true,
5757
Description: "Testing!",
58+
DefaultDestination: &proto.ParameterDestination{
59+
Scheme: proto.ParameterDestination_PROVISIONER_VARIABLE,
60+
},
5861
}},
5962
},
6063
},
@@ -100,8 +103,10 @@ func TestParse(t *testing.T) {
100103
RedisplayValue: true,
101104
ValidationCondition: `var.A == "value"`,
102105
ValidationTypeSystem: proto.ParameterSchema_HCL,
103-
},
104-
},
106+
DefaultDestination: &proto.ParameterDestination{
107+
Scheme: proto.ParameterDestination_PROVISIONER_VARIABLE,
108+
},
109+
}},
105110
},
106111
},
107112
},

provisionerd/proto/provisionerd.proto

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,6 @@ message CancelledJob {
3535
string error = 2;
3636
}
3737

38-
// TransitionedResource represents a resource that knows whether
39-
// it's existence is dependent on stop or not.
40-
//
41-
// This is used on import to display start + stopped resources
42-
// for the lifecycle of a workspace.
43-
message TransitionedResource {
44-
provisioner.Resource resource = 1;
45-
bool destroy_on_stop = 2;
46-
}
47-
4838
// CompletedJob is sent when the provisioner daemon completes a job.
4939
message CompletedJob {
5040
message WorkspaceProvision {

0 commit comments

Comments
 (0)