microsoft/hve-core

Public

mirrored from https://github.com/microsoft/hve-coreAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
7226b4c1944c0773b20eeb1b3be5a4aebf11d4e9

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

.github/instructions/coding-standards/bash/bash.instructions.md

393lines · modecode

1---
2applyTo: '**/*.sh'
3description: 'Instructions for bash script implementation - Brought to you by microsoft/hve-core'
4---
5
6# Bash Script Instructions
7
8These instructions define conventions for authoring Bash scripts in this repository. Scripts follow Bash 5.x conventions with strict error handling and ShellCheck compliance.
9
10## Script Structure
11
12Scripts follow a consistent structure with shebang, header comment, strict mode, and a main function pattern.
13
14<!-- <template-script-structure> -->
15```bash
16#!/usr/bin/env bash
17#
18# script-name.sh
19# Brief description of what this script does
20
21set -euo pipefail
22
23main() {
24 # Script logic here
25 echo "Executing..."
26}
27
28main "$@"
29```
30<!-- </template-script-structure> -->
31
32### Shebang
33
34Use `#!/usr/bin/env bash` for portability across systems.
35
36### Strict Mode
37
38Enable strict error handling at the top of every script:
39
40```bash
41set -euo pipefail
42```
43
44This configuration:
45
46* `-e`: Exits immediately on command failure
47* `-u`: Treats unset variables as errors
48* `-o pipefail`: Propagates pipeline failures
49
50### Main Function Pattern
51
52Encapsulate script logic in a `main()` function called at the end. This pattern:
53
54* Ensures all functions are defined before use
55* Supports sourcing scripts for testing
56* Provides clear entry point
57
58## Copyright Headers
59
60Every `.sh` file requires a copyright header immediately after the shebang line.
61
62Two required lines:
63
64* `# Copyright (c) Microsoft Corporation.`
65* `# SPDX-License-Identifier: MIT`
66
67Placement: after `#!/usr/bin/env bash`, before any other content.
68
69CI validates copyright headers through the repository's copyright validation script, if one is configured. Check `package.json` for a copyright validation command.
70
71<!-- <example-copyright-header> -->
72```bash
73#!/usr/bin/env bash
74# Copyright (c) Microsoft Corporation.
75# SPDX-License-Identifier: MIT
76#
77# script-name.sh
78# Brief description of script purpose
79
80set -euo pipefail
81```
82<!-- </example-copyright-header> -->
83
84## Formatting and Style
85
86### Indentation and Line Length
87
88* Use 2 spaces for indentation, never tabs
89* Limit lines to 80 characters when practical
90* Long commands use backslash continuation
91
92```bash
93az resource show \
94 --resource-group "$RESOURCE_GROUP_NAME" \
95 --name "$RESOURCE_NAME" \
96 --query id \
97 --output tsv
98```
99
100### Control Structures
101
102Place `then` and `do` on the same line as their control keyword:
103
104```bash
105if [[ -n "${VAR:-}" ]]; then
106 echo "Variable is set"
107fi
108
109for item in "${items[@]}"; do
110 process "$item"
111done
112```
113
114### Conditionals and Tests
115
116* Use `[[ ... ]]` instead of `[ ... ]` or `test`
117* Use `(( ... ))` for arithmetic operations
118
119```bash
120if [[ "${ENVIRONMENT}" == "prod" ]]; then
121 echo "Production environment"
122fi
123
124if (( count > 10 )); then
125 echo "Count exceeds threshold"
126fi
127```
128
129## Variables and Naming
130
131### Naming Conventions
132
133| Type | Convention | Example |
134|-----------------------|----------------------------------|--------------------------|
135| Environment variables | UPPER_SNAKE_CASE | `RESOURCE_GROUP_NAME` |
136| Constants | UPPER_SNAKE_CASE with `readonly` | `readonly MAX_RETRIES=3` |
137| Local variables | lower_snake_case | `local file_path` |
138| Function names | lower_snake_case | `validate_input()` |
139
140### Variable Expansion
141
142* Use braces for clarity: `"${var}"` over `"$var"`
143* Quote all variable expansions unless word splitting is intentional
144* Use command substitution with `$()`: never backticks
145
146```bash
147# Variable with default
148ENVIRONMENT="${ENVIRONMENT:-dev}"
149
150# Required variable check
151if [[ -z "${REQUIRED_VAR:-}" ]]; then
152 echo "ERROR: REQUIRED_VAR must be set" >&2
153 exit 1
154fi
155```
156
157### Arrays
158
159Use arrays for lists of elements:
160
161```bash
162declare -a files=("file1.txt" "file2.txt" "file3.txt")
163
164for file in "${files[@]}"; do
165 process "$file"
166done
167```
168
169## Functions
170
171Define functions before use. Use `local` for function-scoped variables.
172
173```bash
174log() {
175 local message="$1"
176 printf "========== %s ==========\n" "$message"
177}
178
179err() {
180 local message="$1"
181 printf "ERROR: %s\n" "$message" >&2
182 exit 1
183}
184
185validate_input() {
186 local input="$1"
187 if [[ -z "${input}" ]]; then
188 err "Input cannot be empty"
189 fi
190}
191```
192
193## Error Handling
194
195### Error Functions
196
197Implement consistent error reporting:
198
199```bash
200err() {
201 printf "ERROR: %s\n" "$1" >&2
202 exit 1
203}
204```
205
206### Command Validation
207
208Check for required commands before use:
209
210```bash
211if ! command -v "az" &>/dev/null; then
212 err "'az' command is required but not installed"
213fi
214```
215
216### Error Visibility
217
218Allow commands to fail naturally with their native error messages. Avoid redirecting stderr to `/dev/null` unless errors are genuinely irrelevant. Let tools display their built-in error information.
219
220## Comments
221
222Keep comments minimal. Add them only when logic requires explanation:
223
224* Complex regex patterns
225* Non-obvious conditionals
226* Workarounds with context
227
228```bash
229# Match semantic version pattern: major.minor.patch
230if [[ "${version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
231 echo "Valid version"
232fi
233```
234
235Document environment variables at the top of scripts that require them:
236
237```bash
238## Required Environment Variables:
239# ENVIRONMENT - Target environment (dev, prod)
240# RESOURCE_GROUP - Azure resource group name
241
242## Optional Environment Variables:
243# DEBUG - Enable verbose output when set
244```
245
246## Usage Functions
247
248Scripts with arguments include a usage function:
249
250```bash
251usage() {
252 echo "Usage: ${0##*/} [OPTIONS]"
253 echo ""
254 echo "Options:"
255 echo " --help, -h Show this help message"
256 echo " --verbose Enable verbose output"
257 exit 1
258}
259```
260
261## Argument Parsing
262
263Use `case` statements for argument handling:
264
265```bash
266while [[ $# -gt 0 ]]; do
267 case "$1" in
268 --verbose)
269 VERBOSE=true
270 shift
271 ;;
272 --output)
273 if [[ -z "${2:-}" || "$2" == --* ]]; then
274 echo "Error: --output requires an argument" >&2
275 usage
276 fi
277 OUTPUT_FILE="$2"
278 shift 2
279 ;;
280 --help|-h)
281 usage
282 ;;
283 *)
284 echo "Unknown option: $1" >&2
285 usage
286 ;;
287 esac
288done
289```
290
291## File Operations
292
293Create directories safely and handle paths properly:
294
295```bash
296mkdir -p "$(dirname "$OUTPUT_FILE")"
297
298if [[ -f "${config_file}" ]]; then
299 source "${config_file}"
300fi
301```
302
303## Security Practices
304
305### Variable Quoting
306
307Quote variables to prevent word splitting and command injection:
308
309```bash
310# Correct
311rm -f "${temp_file}"
312grep "${pattern}" "${file}"
313
314# Avoid
315rm -f $temp_file
316grep $pattern $file
317```
318
319### File Permissions
320
321Set appropriate permissions for sensitive files:
322
323```bash
324chmod 0600 "${HOME}/.kube/config"
325```
326
327### Checksum Verification
328
329Verify downloaded files before execution:
330
331```bash
332EXPECTED_SHA256="abc123..."
333if ! echo "${EXPECTED_SHA256} ${downloaded_file}" | sha256sum -c --quiet -; then
334 echo "ERROR: Checksum verification failed" >&2
335 rm "${downloaded_file}"
336 exit 1
337fi
338```
339
340## ShellCheck Compliance
341
342All scripts pass ShellCheck validation. Use the VS Code problems panel or run ShellCheck directly:
343
344```bash
345shellcheck script.sh
346```
347
348When a specific rule needs suppression, add a directive with justification:
349
350```bash
351# shellcheck disable=SC2034 # Variable used by sourced script
352EXPORTED_CONFIG="value"
353```
354
355## Azure CLI Patterns
356
357When working with Azure CLI commands:
358
359### Output Handling
360
361* Use `--output tsv` for single values in scripts
362* TSV output returns empty strings for null values (not the string "null")
363* Use `--query` with JMESPath for filtering results
364
365```bash
366resource_id=$(az resource show \
367 --resource-group "$RESOURCE_GROUP" \
368 --name "$RESOURCE_NAME" \
369 --resource-type "Microsoft.Storage/storageAccounts" \
370 --query id \
371 --output tsv)
372
373if [[ -z "${resource_id}" ]]; then
374 err "Resource not found"
375fi
376```
377
378### Conditional Command Arguments
379
380Build commands with arrays when arguments are conditional:
381
382```bash
383az_cmd=("az" "connectedk8s" "connect"
384 "--name" "$RESOURCE_NAME"
385 "--resource-group" "$RESOURCE_GROUP"
386)
387
388if [[ "${AUTO_UPGRADE:-true}" == "false" ]]; then
389 az_cmd+=("--disable-auto-upgrade")
390fi
391
392"${az_cmd[@]}"
393```
394