Skip to content

Commit 336cfec

Browse files
authored
Merge pull request #22 from gruntwork-io/handle-block-errors
Handle errors in more robust way
2 parents b3be947 + af7a5f5 commit 336cfec

14 files changed

Lines changed: 731 additions & 51 deletions

File tree

api/executable_registry.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -213,15 +213,32 @@ func (r *ExecutableRegistry) registerFileExecutable(componentID, componentType,
213213
// Resolve script path relative to runbook
214214
fullPath := filepath.Join(runbookDir, scriptPath)
215215

216-
// Check if file exists
216+
// Check if file exists - if not, add warning and skip (don't fail startup)
217217
if _, err := os.Stat(fullPath); err != nil {
218-
return fmt.Errorf("script file not found: %s", scriptPath)
218+
warning := fmt.Sprintf("<%s id=\"%s\">: Script file not found: %s", componentType, componentID, scriptPath)
219+
r.mu.Lock()
220+
r.warnings = append(r.warnings, warning)
221+
r.mu.Unlock()
222+
slog.Warn("Script file not found, skipping registration",
223+
"component_type", componentType,
224+
"component_id", componentID,
225+
"script_path", scriptPath)
226+
return nil // Continue without failing (so we can handle in UI)
219227
}
220228

221229
// Read script content
222230
content, err := os.ReadFile(fullPath)
223231
if err != nil {
224-
return fmt.Errorf("failed to read script file %s: %w", scriptPath, err)
232+
warning := fmt.Sprintf("<%s id=\"%s\">: Failed to read script file %s: %v", componentType, componentID, scriptPath, err)
233+
r.mu.Lock()
234+
r.warnings = append(r.warnings, warning)
235+
r.mu.Unlock()
236+
slog.Warn("Failed to read script file, skipping registration",
237+
"component_type", componentType,
238+
"component_id", componentID,
239+
"script_path", scriptPath,
240+
"error", err)
241+
return nil // Continue without failing (so we can handle in UI)
225242
}
226243

227244
scriptContent := string(content)
Lines changed: 305 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,305 @@
1+
# Error Scenarios Test Runbook
2+
3+
This runbook demonstrates how errors are displayed to users for each block type.
4+
5+
---
6+
7+
## 1. Command Block Errors
8+
9+
### 1.1 Command with Missing Script File
10+
11+
This Command references a script file that doesn't exist:
12+
13+
<Command
14+
id="cmd-missing-file"
15+
path="scripts/nonexistent-script.sh"
16+
title="Command with missing script file"
17+
description="This should show a file loading error"
18+
failMessage="Script execution failed"
19+
/>
20+
21+
### 1.2 Command with Syntax Error in Command
22+
23+
This Command has a redirect character that may cause parsing issues:
24+
25+
<Command
26+
id="cmd-with-redirect"
27+
command="echo 'Hello' > /tmp/greeting.txt && cat /tmp/greeting.txt"
28+
title="Command with redirect operator"
29+
description="Previously this caused a silent parsing error. Now it should work or show an error."
30+
successMessage="Redirect worked!"
31+
failMessage="Redirect failed"
32+
/>
33+
34+
### 1.3 Command with Missing Variables
35+
36+
This Command uses variables but doesn't have an Inputs component:
37+
38+
<Command
39+
id="cmd-missing-vars"
40+
command="echo 'Hello {{ .name }}, welcome to {{ .location }}!'"
41+
title="Command with unresolved variables"
42+
description="This should show a configuration required warning"
43+
successMessage="Variables resolved!"
44+
/>
45+
46+
### 1.4 Command Execution Failure
47+
48+
This Command will fail when executed (exit code 1):
49+
50+
<Command
51+
id="cmd-exec-fail"
52+
command="echo 'This will fail' && exit 1"
53+
title="Command that fails on execution"
54+
description="Click Run to see the failure error displayed"
55+
successMessage="Success!"
56+
failMessage="The command exited with a non-zero code"
57+
/>
58+
59+
### 1.5 Duplicate Command ID
60+
61+
Both of these Commands have the same ID:
62+
63+
<Command
64+
id="duplicate-cmd-id"
65+
command="echo 'First command'"
66+
title="First command with ID 'duplicate-cmd-id'"
67+
/>
68+
69+
<Command
70+
id="duplicate-cmd-id"
71+
command="echo 'Second command'"
72+
title="Second command with same ID"
73+
description="This should show a duplicate ID error"
74+
/>
75+
76+
---
77+
78+
## 2. Check Block Errors
79+
80+
### 2.1 Check with Missing Script File
81+
82+
<Check
83+
id="check-missing-file"
84+
path="checks/nonexistent-check.sh"
85+
title="Check with missing script file"
86+
description="This should show a file loading error"
87+
successMessage="Check passed!"
88+
failMessage="Check failed"
89+
/>
90+
91+
### 2.2 Check with Missing Title (Required Prop)
92+
93+
This Check is missing the required `title` prop:
94+
95+
<Check
96+
id="check-missing-title"
97+
command="echo 'No title provided'"
98+
successMessage="Check passed!"
99+
/>
100+
101+
### 2.3 Check Execution with Warning
102+
103+
This Check returns exit code 2 (warning):
104+
105+
<Check
106+
id="check-warning"
107+
command="echo 'Warning: something needs attention' && exit 2"
108+
title="Check that produces a warning"
109+
description="Click Check to see warning status"
110+
successMessage="All good!"
111+
warnMessage="Warning: needs attention"
112+
failMessage="Check failed"
113+
/>
114+
115+
### 2.4 Check Execution Failure
116+
117+
This Check returns exit code 1 (failure):
118+
119+
<Check
120+
id="check-failure"
121+
command="echo 'Error: check failed!' >&2 && exit 1"
122+
title="Check that fails"
123+
description="Click Check to see failure error displayed"
124+
successMessage="Check passed!"
125+
failMessage="Check failed with errors"
126+
/>
127+
128+
### 2.5 Duplicate Check ID
129+
130+
<Check
131+
id="duplicate-check-id"
132+
command="echo 'First check'"
133+
title="First check with ID 'duplicate-check-id'"
134+
/>
135+
136+
<Check
137+
id="duplicate-check-id"
138+
command="echo 'Second check'"
139+
title="Second check with same ID"
140+
description="This should show a duplicate ID error"
141+
/>
142+
143+
---
144+
145+
## 3. Inputs Block Errors
146+
147+
### 3.1 Inputs with Missing ID
148+
149+
<Inputs>
150+
```yaml
151+
variables:
152+
- name: test_var
153+
type: string
154+
```
155+
</Inputs>
156+
157+
### 3.2 Inputs with Invalid YAML
158+
159+
<Inputs id="invalid-yaml-inputs">
160+
```yaml
161+
variables:
162+
- name: test_var
163+
type: string
164+
invalid_indentation
165+
- another: item
166+
```
167+
</Inputs>
168+
169+
### 3.3 Inputs with Unsupported Variable Type
170+
171+
<Inputs id="unsupported-type">
172+
```yaml
173+
variables:
174+
- name: complex_var
175+
type: custom_unsupported_type
176+
description: This type is not supported
177+
```
178+
</Inputs>
179+
180+
### 3.4 Duplicate Inputs ID
181+
182+
<Inputs id="duplicate-inputs-id">
183+
```yaml
184+
variables:
185+
- name: var1
186+
type: string
187+
default: "first"
188+
```
189+
</Inputs>
190+
191+
<Inputs id="duplicate-inputs-id">
192+
```yaml
193+
variables:
194+
- name: var2
195+
type: string
196+
default: "second"
197+
```
198+
</Inputs>
199+
200+
---
201+
202+
## 4. Template Block Errors
203+
204+
### 4.1 Template with Missing Path
205+
206+
<Template
207+
id="template-missing-path"
208+
title="Template without path"
209+
description="This should show an error for missing path"
210+
/>
211+
212+
### 4.2 Template with Nonexistent Path
213+
214+
<Template
215+
id="template-nonexistent"
216+
path="templates/nonexistent-template"
217+
title="Template with invalid path"
218+
description="This should show an error when loading the template"
219+
/>
220+
221+
### 4.3 Duplicate Template ID
222+
223+
<Template
224+
id="duplicate-template-id"
225+
path="templates/test"
226+
title="First template"
227+
/>
228+
229+
<Template
230+
id="duplicate-template-id"
231+
path="templates/test2"
232+
title="Second template with same ID"
233+
/>
234+
235+
---
236+
237+
## 5. Working Examples (For Comparison)
238+
239+
These examples work correctly and show successful states:
240+
241+
### 5.1 Working Command
242+
243+
<Command
244+
id="working-cmd"
245+
command="echo 'Hello, World!' && date"
246+
title="Working command"
247+
description="This command should execute successfully"
248+
successMessage="Command completed successfully!"
249+
failMessage="Command failed"
250+
/>
251+
252+
### 5.2 Working Check
253+
254+
<Check
255+
id="working-check"
256+
command="echo 'All systems operational' && exit 0"
257+
title="Working check"
258+
description="This check should pass"
259+
successMessage="All systems operational!"
260+
warnMessage="Warning detected"
261+
failMessage="Check failed"
262+
/>
263+
264+
### 5.3 Working Inputs with Command
265+
266+
<Inputs id="working-inputs">
267+
```yaml
268+
variables:
269+
- name: greeting
270+
type: string
271+
default: "Hello"
272+
description: The greeting to display
273+
- name: name
274+
type: string
275+
default: "World"
276+
description: Who to greet
277+
```
278+
</Inputs>
279+
280+
<Command
281+
id="working-cmd-with-inputs"
282+
inputsId="working-inputs"
283+
command="echo '{{ .greeting }}, {{ .name }}!'"
284+
title="Command with inputs"
285+
description="Uses variables from the Inputs block above"
286+
successMessage="Greeting displayed!"
287+
/>
288+
289+
---
290+
291+
## Summary of Error Types
292+
293+
| Block | Error Type | How It's Displayed |
294+
|-------|-----------|-------------------|
295+
| Command/Check | Missing file | Red error box with file path |
296+
| Command/Check | Missing variables | Yellow warning with variable names |
297+
| Command/Check | Execution failure | Red error inline + fail message |
298+
| Command/Check | Duplicate ID | Red error box |
299+
| Command/Check | Executable not found | Red error inline (previously silent!) |
300+
| Inputs | Missing ID | Red error box |
301+
| Inputs | Invalid YAML | Red error with parse details |
302+
| Inputs | Duplicate ID | Red error box |
303+
| Template | Missing path | Red error box |
304+
| Template | Invalid path | Red error with API details |
305+
| Template | Duplicate ID | Red error box |

0 commit comments

Comments
 (0)