Skip to content

Commit 4e8e601

Browse files
authored
print when cli is running something (#115)
1 parent 31d7534 commit 4e8e601

File tree

5 files changed

+231
-133
lines changed

5 files changed

+231
-133
lines changed

bootdev

16.7 MB
Binary file not shown.

checks/checks.go

Lines changed: 136 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@ import (
1515
"time"
1616

1717
api "github.com/bootdotdev/bootdev/client"
18+
"github.com/bootdotdev/bootdev/messages"
19+
tea "github.com/charmbracelet/bubbletea"
1820
"github.com/itchyny/gojq"
1921
"github.com/spf13/cobra"
22+
"github.com/spf13/viper"
2023
)
2124

2225
func runCLICommand(command api.CLIStepCLICommand, variables map[string]string) (result api.CLICommandResult) {
@@ -124,7 +127,7 @@ func runHTTPRequest(
124127
return result
125128
}
126129

127-
func CLIChecks(cliData api.CLIData, overrideBaseURL string) (results []api.CLIStepResult) {
130+
func CLIChecks(cliData api.CLIData, overrideBaseURL string, ch chan tea.Msg) (results []api.CLIStepResult) {
128131
client := &http.Client{}
129132
variables := make(map[string]string)
130133
results = make([]api.CLIStepResult, len(cliData.Steps))
@@ -140,23 +143,155 @@ func CLIChecks(cliData api.CLIData, overrideBaseURL string) (results []api.CLISt
140143
}
141144

142145
for i, step := range cliData.Steps {
146+
// This is the magic of the initial message sent before executing the test
147+
if step.CLICommand != nil {
148+
ch <- messages.StartStepMsg{CMD: step.CLICommand.Command}
149+
} else if step.HTTPRequest != nil {
150+
finalBaseURL := baseURL
151+
overrideURL := viper.GetString("override_base_url")
152+
if overrideURL != "" {
153+
finalBaseURL = overrideURL
154+
}
155+
fullURL := strings.Replace(step.HTTPRequest.Request.FullURL, api.BaseURLPlaceholder, finalBaseURL, 1)
156+
interpolatedURL := InterpolateVariables(fullURL, variables)
157+
158+
ch <- messages.StartStepMsg{
159+
URL: interpolatedURL,
160+
Method: step.HTTPRequest.Request.Method,
161+
ResponseVariables: step.HTTPRequest.ResponseVariables,
162+
}
163+
}
164+
143165
switch {
144166
case step.CLICommand != nil:
145167
result := runCLICommand(*step.CLICommand, variables)
146168
results[i].CLICommandResult = &result
169+
170+
sendCLICommandResults(ch, *step.CLICommand, result, i)
171+
147172
case step.HTTPRequest != nil:
148173
result := runHTTPRequest(client, baseURL, variables, *step.HTTPRequest)
149174
results[i].HTTPRequestResult = &result
150175
if result.Variables != nil {
151176
variables = result.Variables
152177
}
178+
179+
sendHTTPRequestResults(ch, *step.HTTPRequest, result, i)
180+
153181
default:
154182
cobra.CheckErr("unable to run lesson: missing step")
155183
}
156184
}
157185
return results
158186
}
159187

188+
func sendCLICommandResults(ch chan tea.Msg, cmd api.CLIStepCLICommand, result api.CLICommandResult, index int) {
189+
for _, test := range cmd.Tests {
190+
ch <- messages.StartTestMsg{Text: prettyPrintCLICommand(test, result.Variables)}
191+
}
192+
193+
for j := range cmd.Tests {
194+
ch <- messages.ResolveTestMsg{Index: j}
195+
}
196+
197+
ch <- messages.ResolveStepMsg{
198+
Index: index,
199+
Result: &api.CLIStepResult{
200+
CLICommandResult: &result,
201+
},
202+
}
203+
}
204+
205+
func sendHTTPRequestResults(ch chan tea.Msg, req api.CLIStepHTTPRequest, result api.HTTPRequestResult, index int) {
206+
for _, test := range req.Tests {
207+
ch <- messages.StartTestMsg{Text: prettyPrintHTTPTest(test, result.Variables)}
208+
}
209+
210+
for j := range req.Tests {
211+
ch <- messages.ResolveTestMsg{Index: j}
212+
}
213+
214+
ch <- messages.ResolveStepMsg{
215+
Index: index,
216+
Result: &api.CLIStepResult{
217+
HTTPRequestResult: &result,
218+
},
219+
}
220+
}
221+
222+
func prettyPrintCLICommand(test api.CLICommandTest, variables map[string]string) string {
223+
if test.ExitCode != nil {
224+
return fmt.Sprintf("Expect exit code %d", *test.ExitCode)
225+
}
226+
if test.StdoutLinesGt != nil {
227+
return fmt.Sprintf("Expect > %d lines on stdout", *test.StdoutLinesGt)
228+
}
229+
if test.StdoutContainsAll != nil {
230+
str := "Expect stdout to contain all of:"
231+
for _, contains := range test.StdoutContainsAll {
232+
interpolatedContains := InterpolateVariables(contains, variables)
233+
str += fmt.Sprintf("\n - '%s'", interpolatedContains)
234+
}
235+
return str
236+
}
237+
if test.StdoutContainsNone != nil {
238+
str := "Expect stdout to contain none of:"
239+
for _, containsNone := range test.StdoutContainsNone {
240+
interpolatedContainsNone := InterpolateVariables(containsNone, variables)
241+
str += fmt.Sprintf("\n - '%s'", interpolatedContainsNone)
242+
}
243+
return str
244+
}
245+
return ""
246+
}
247+
248+
func prettyPrintHTTPTest(test api.HTTPRequestTest, variables map[string]string) string {
249+
if test.StatusCode != nil {
250+
return fmt.Sprintf("Expecting status code: %d", *test.StatusCode)
251+
}
252+
if test.BodyContains != nil {
253+
interpolated := InterpolateVariables(*test.BodyContains, variables)
254+
return fmt.Sprintf("Expecting body to contain: %s", interpolated)
255+
}
256+
if test.BodyContainsNone != nil {
257+
interpolated := InterpolateVariables(*test.BodyContainsNone, variables)
258+
return fmt.Sprintf("Expecting JSON body to not contain: %s", interpolated)
259+
}
260+
if test.HeadersContain != nil {
261+
interpolatedKey := InterpolateVariables(test.HeadersContain.Key, variables)
262+
interpolatedValue := InterpolateVariables(test.HeadersContain.Value, variables)
263+
return fmt.Sprintf("Expecting headers to contain: '%s: %v'", interpolatedKey, interpolatedValue)
264+
}
265+
if test.TrailersContain != nil {
266+
interpolatedKey := InterpolateVariables(test.TrailersContain.Key, variables)
267+
interpolatedValue := InterpolateVariables(test.TrailersContain.Value, variables)
268+
return fmt.Sprintf("Expecting trailers to contain: '%s: %v'", interpolatedKey, interpolatedValue)
269+
}
270+
if test.JSONValue != nil {
271+
var val any
272+
var op any
273+
if test.JSONValue.IntValue != nil {
274+
val = *test.JSONValue.IntValue
275+
} else if test.JSONValue.StringValue != nil {
276+
val = *test.JSONValue.StringValue
277+
} else if test.JSONValue.BoolValue != nil {
278+
val = *test.JSONValue.BoolValue
279+
}
280+
if test.JSONValue.Operator == api.OpEquals {
281+
op = "to be equal to"
282+
} else if test.JSONValue.Operator == api.OpGreaterThan {
283+
op = "to be greater than"
284+
} else if test.JSONValue.Operator == api.OpContains {
285+
op = "contains"
286+
} else if test.JSONValue.Operator == api.OpNotContains {
287+
op = "to not contain"
288+
}
289+
expecting := fmt.Sprintf("Expecting JSON at %v %s %v", test.JSONValue.Path, op, val)
290+
return InterpolateVariables(expecting, variables)
291+
}
292+
return ""
293+
}
294+
160295
// truncateAndStringifyBody
161296
// in some lessons we yeet the entire body up to the server, but we really shouldn't ever care
162297
// about more than 100,000 stringified characters of it, so this protects against giant bodies

cmd/submit.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77

88
"github.com/bootdotdev/bootdev/checks"
99
api "github.com/bootdotdev/bootdev/client"
10+
tea "github.com/charmbracelet/bubbletea"
11+
1012
"github.com/bootdotdev/bootdev/render"
1113
"github.com/spf13/cobra"
1214
"github.com/spf13/viper"
@@ -62,15 +64,20 @@ func submissionHandler(cmd *cobra.Command, args []string) error {
6264
fmt.Printf("You can reset to the default with `bootdev config base_url --reset`\n\n")
6365
}
6466

65-
results := checks.CLIChecks(data, overrideBaseURL)
67+
ch := make(chan tea.Msg, 1)
68+
// StartRenderer and returns immediately, finalise function blocks the execution until the renderer is closed.
69+
finalise := render.StartRenderer(data, isSubmit, ch)
70+
71+
results := checks.CLIChecks(data, overrideBaseURL, ch)
72+
6673
if isSubmit {
6774
failure, err := api.SubmitCLILesson(lessonUUID, results)
6875
if err != nil {
6976
return err
7077
}
71-
render.RenderSubmission(data, results, failure)
78+
finalise(failure)
7279
} else {
73-
render.RenderRun(data, results)
80+
finalise(nil)
7481
}
7582
return nil
7683
}

messages/messages.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package messages
2+
3+
import api "github.com/bootdotdev/bootdev/client"
4+
5+
type StartStepMsg struct {
6+
ResponseVariables []api.HTTPRequestResponseVariable
7+
CMD string
8+
URL string
9+
Method string
10+
}
11+
12+
type StartTestMsg struct {
13+
Text string
14+
}
15+
16+
type ResolveTestMsg struct {
17+
Index int
18+
Passed *bool
19+
}
20+
21+
type DoneStepMsg struct {
22+
Failure *api.VerificationResultStructuredErrCLI
23+
}
24+
25+
type ResolveStepMsg struct {
26+
Index int
27+
Passed *bool
28+
Result *api.CLIStepResult
29+
}

0 commit comments

Comments
 (0)