Skip to content

Commit 7e604eb

Browse files
committed
ci: Enhance boards test validation
1 parent c2bd3c9 commit 7e604eb

File tree

5 files changed

+340
-8
lines changed

5 files changed

+340
-8
lines changed

.github/scripts/find_new_boards.sh

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,25 @@ echo "$modified_lines"
2727
boards_array=()
2828
previous_board=""
2929

30+
# Define excluded entries that are not actual boards
31+
excluded_entries=("" "+" "-" "esp32_family" "menu")
32+
3033
# Extract board names from the modified lines, and add them to the boards_array
3134
while read -r line; do
3235
board_name=$(echo "$line" | cut -d '.' -f1 | cut -d '#' -f1)
3336
# remove + or - from the board name at the beginning
3437
board_name=${board_name#[-+]}
35-
if [ "$board_name" != "" ] && [ "$board_name" != "+" ] && [ "$board_name" != "-" ] && [ "$board_name" != "esp32_family" ]; then
38+
39+
# Check if board_name is in excluded entries
40+
is_excluded=false
41+
for excluded in "${excluded_entries[@]}"; do
42+
if [ "$board_name" = "$excluded" ]; then
43+
is_excluded=true
44+
break
45+
fi
46+
done
47+
48+
if [ "$is_excluded" = false ]; then
3649
if [ "$board_name" != "$previous_board" ]; then
3750
boards_array+=("espressif:esp32:$board_name")
3851
previous_board="$board_name"

.github/scripts/validate_board.sh

Lines changed: 292 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,292 @@
1+
#!/bin/bash
2+
3+
# Board validation script for ESP32 Arduino Core
4+
# This script validates board definitions in boards.txt
5+
6+
set -e
7+
8+
# Function to print output
9+
print_error() {
10+
echo "Error: $1"
11+
}
12+
13+
print_success() {
14+
echo "$1"
15+
}
16+
17+
# Function to validate a single board
18+
validate_board() {
19+
local board_name="$1"
20+
local boards_file="boards.txt"
21+
22+
echo "Validating board: $board_name"
23+
24+
# Rule 1: Check build.board format
25+
validate_build_board_format "$board_name" "$boards_file"
26+
27+
# Rule 2: Check for required board properties
28+
validate_required_properties "$board_name" "$boards_file"
29+
30+
# Rule 3: Check for valid partition schemes for available flash sizes
31+
validate_partition_schemes "$board_name" "$boards_file"
32+
33+
# Rule 4: Check for VID and PID consistency
34+
validate_vid_pid_consistency "$board_name" "$boards_file"
35+
36+
# Add more validation rules here as needed
37+
# Rule 5: Future validation rules can be added here
38+
print_success "Board '$board_name' validation passed"
39+
}
40+
41+
# Rule 1: Check build.board format
42+
validate_build_board_format() {
43+
local board_name="$1"
44+
local boards_file="$2"
45+
46+
# Get the build.board value
47+
local build_board_value
48+
build_board_value=$(grep "^$board_name.build.board=" "$boards_file" | cut -d'=' -f2)
49+
50+
if [ -z "$build_board_value" ]; then
51+
print_error "build.board property not found for '$board_name'"
52+
exit 1
53+
fi
54+
55+
# Check for invalid characters (anything that's not uppercase letter, number, or underscore)
56+
if echo "$build_board_value" | grep -q '[^A-Z0-9_]'; then
57+
local invalid_chars
58+
invalid_chars=$(echo "$build_board_value" | grep -o '[^A-Z0-9_]' | sort -u | tr -d '\n')
59+
print_error "$board_name.build.board contains invalid characters: '$invalid_chars' (only A-Z, 0-9, and _ are allowed)"
60+
exit 1
61+
fi
62+
63+
# Check if it's all uppercase
64+
if echo "$build_board_value" | grep -q '[a-z]'; then
65+
print_error "build.board must be uppercase: '$build_board_value' (found lowercase letters)"
66+
exit 1
67+
fi
68+
69+
print_success "build.board is valid: '$build_board_value'"
70+
}
71+
72+
# Rule 2: Check for required board properties
73+
validate_required_properties() {
74+
local board_name="$1"
75+
local boards_file="$2"
76+
77+
echo "Checking required board properties..."
78+
local required_props=("upload.flags" "upload.extra_flags")
79+
local missing_props=()
80+
81+
for prop in "${required_props[@]}"; do
82+
if ! grep -q "^$board_name.$prop=" "$boards_file"; then
83+
missing_props+=("$prop")
84+
fi
85+
done
86+
87+
if [ ${#missing_props[@]} -gt 0 ]; then
88+
print_error "Missing required properties for board '$board_name':"
89+
printf ' - %s\n' "${missing_props[@]}"
90+
exit 1
91+
fi
92+
}
93+
94+
# Rule 3: Check for valid partition schemes for available flash sizes
95+
validate_partition_schemes() {
96+
local board_name="$1"
97+
local boards_file="$2"
98+
99+
echo "Checking partition schemes for available flash sizes..."
100+
101+
# Get all available flash sizes for this board
102+
local flash_sizes
103+
flash_sizes=$(grep "^$board_name.menu.FlashSize\." "$boards_file" | grep "\.build\.flash_size=" | cut -d'=' -f2 | sort -V)
104+
105+
# Check if board has menu.FlashSize entries
106+
if [ -z "$flash_sizes" ]; then
107+
# If no menu.FlashSize entries, check if board has any build.flash_size entry
108+
local has_flash_size
109+
has_flash_size=$(grep "^$board_name\." "$boards_file" | grep "\.build\.flash_size=" | head -1)
110+
111+
if [ -z "$has_flash_size" ]; then
112+
print_error "No flash size options found for board '$board_name' (needs either menu.FlashSize entries or build.flash_size entry)"
113+
exit 1
114+
else
115+
print_success "Board '$board_name' has build.flash_size entry (no menu.FlashSize required)"
116+
return 0
117+
fi
118+
fi
119+
120+
# Convert flash sizes to MB for comparison
121+
local flash_sizes_mb=()
122+
while IFS= read -r size; do
123+
if [[ "$size" =~ ^([0-9]+)MB$ ]]; then
124+
flash_sizes_mb+=("${BASH_REMATCH[1]}")
125+
fi
126+
done <<< "$flash_sizes"
127+
128+
# Find the maximum flash size available
129+
local max_flash_mb=0
130+
for size_mb in "${flash_sizes_mb[@]}"; do
131+
if [ "$size_mb" -gt "$max_flash_mb" ]; then
132+
max_flash_mb="$size_mb"
133+
fi
134+
done
135+
136+
echo " Maximum flash size available: ${max_flash_mb}MB"
137+
138+
# Find all partition schemes for this board
139+
local partition_schemes
140+
partition_schemes=$(grep "^$board_name.menu.PartitionScheme\." "$boards_file" | grep "\.build\.partitions=" | cut -d'=' -f2 | sort -u)
141+
142+
if [ -n "$partition_schemes" ]; then
143+
# Validate each partition scheme against the maximum flash size
144+
while IFS= read -r scheme; do
145+
validate_partition_scheme_size "$scheme" "$max_flash_mb" "$board_name" "$boards_file"
146+
done <<< "$partition_schemes"
147+
fi
148+
149+
150+
print_success "Partition scheme validation completed"
151+
}
152+
153+
# Helper function to validate individual partition scheme
154+
validate_partition_scheme_size() {
155+
local scheme="$1"
156+
local max_flash_mb="$2"
157+
local board_name="$3"
158+
local boards_file="$4"
159+
160+
# Extract size from partition scheme name (e.g., "default_8MB" -> 8)
161+
if [[ "$scheme" =~ _([0-9]+)MB$ ]]; then
162+
local scheme_size_mb="${BASH_REMATCH[1]}"
163+
164+
if [ "$scheme_size_mb" -gt "$max_flash_mb" ]; then
165+
print_error "Partition scheme '$scheme' (${scheme_size_mb}MB) exceeds available flash size (${max_flash_mb}MB) for board '$board_name'"
166+
exit 1
167+
fi
168+
elif [[ "$scheme" =~ _([0-9]+)M$ ]]; then
169+
# Handle cases like "default_8M" (without B)
170+
local scheme_size_mb="${BASH_REMATCH[1]}"
171+
172+
if [ "$scheme_size_mb" -gt "$max_flash_mb" ]; then
173+
print_error "Partition scheme '$scheme' (${scheme_size_mb}MB) exceeds available flash size (${max_flash_mb}MB) for board '$board_name'"
174+
exit 1
175+
fi
176+
else
177+
# For schemes without size in name (like "default", "minimal"), check upload maximum size
178+
validate_scheme_upload_size "$scheme" "$board_name" "$boards_file" "$max_flash_mb"
179+
fi
180+
}
181+
182+
# Rule 4: Check for VID and PID consistency
183+
validate_vid_pid_consistency() {
184+
local board_name="$1"
185+
local boards_file="$2"
186+
187+
echo "Checking VID and PID consistency..."
188+
189+
# Get all VID and PID entries for this board
190+
local vid_entries
191+
local pid_entries
192+
193+
vid_entries=$(grep "^$board_name\.vid\." "$boards_file" | sort)
194+
pid_entries=$(grep "^$board_name\.pid\." "$boards_file" | sort)
195+
196+
# Check for duplicate VID entries with same index but different values
197+
local vid_duplicates
198+
vid_duplicates=$(echo "$vid_entries" | cut -d'=' -f1 | sort | uniq -d)
199+
200+
if [ -n "$vid_duplicates" ]; then
201+
print_error "Found duplicate VID entries with different values for board '$board_name':"
202+
echo "$vid_duplicates"
203+
exit 1
204+
fi
205+
206+
# Check for duplicate PID entries with same index but different values
207+
local pid_duplicates
208+
pid_duplicates=$(echo "$pid_entries" | cut -d'=' -f1 | sort | uniq -d)
209+
210+
if [ -n "$pid_duplicates" ]; then
211+
print_error "Found duplicate PID entries with different values for board '$board_name':"
212+
echo "$pid_duplicates"
213+
exit 1
214+
fi
215+
216+
# Check for missing corresponding PID for each VID (and vice versa)
217+
local vid_indices
218+
local pid_indices
219+
220+
vid_indices=$(echo "$vid_entries" | cut -d'=' -f1 | sed "s/^$board_name\.vid\.//" | sort -n)
221+
pid_indices=$(echo "$pid_entries" | cut -d'=' -f1 | sed "s/^$board_name\.pid\.//" | sort -n)
222+
223+
# Check if VID and PID indices match
224+
if [ "$vid_indices" != "$pid_indices" ]; then
225+
print_error "VID and PID indices don't match for board '$board_name'"
226+
echo "VID indices: $vid_indices"
227+
echo "PID indices: $pid_indices"
228+
exit 1
229+
fi
230+
231+
print_success "VID and PID consistency check passed"
232+
}
233+
234+
# Helper function to validate upload maximum size for a specific partition scheme
235+
validate_scheme_upload_size() {
236+
local scheme="$1"
237+
local board_name="$2"
238+
local boards_file="$3"
239+
local max_flash_mb="$4"
240+
241+
# Get upload maximum size for this specific scheme
242+
local upload_size
243+
upload_size=$(grep "^$board_name.menu.PartitionScheme\..*\.build\.partitions=$scheme" "$boards_file" -A1 | grep "\.upload\.maximum_size=" | head -1 | cut -d'=' -f2)
244+
245+
if [ -z "$upload_size" ]; then
246+
print_success "Partition scheme '$scheme' is valid for ${max_flash_mb}MB flash (no upload size limit)"
247+
return 0
248+
fi
249+
250+
# Convert flash size to bytes for comparison
251+
local max_flash_bytes=$((max_flash_mb * 1024 * 1024))
252+
253+
# Check upload size against maximum flash size
254+
if [ "$upload_size" -gt "$max_flash_bytes" ]; then
255+
local upload_mb=$((upload_size / 1024 / 1024))
256+
print_error "Partition scheme '$scheme' upload size (${upload_mb}MB, ${upload_size} bytes) exceeds available flash size (${max_flash_mb}MB) for board '$board_name'"
257+
exit 1
258+
fi
259+
260+
local upload_mb=$((upload_size / 1024 / 1024))
261+
print_success "Partition scheme '$scheme' is valid for ${max_flash_mb}MB flash (upload size: ${upload_mb}MB)"
262+
}
263+
264+
# Future validation rules can be added here
265+
# Example:
266+
# validate_custom_rule() {
267+
# local board_name="$1"
268+
# local boards_file="$2"
269+
# # Add custom validation logic here
270+
# }
271+
272+
# Main execution
273+
main() {
274+
if [ $# -ne 1 ]; then
275+
echo "Usage: $0 <board_name>"
276+
echo "Example: $0 esp32s3"
277+
exit 1
278+
fi
279+
280+
local board_name="$1"
281+
local boards_file="boards.txt"
282+
283+
if [ ! -f "$boards_file" ]; then
284+
print_error "Boards file '$boards_file' not found"
285+
exit 1
286+
fi
287+
288+
validate_board "$board_name"
289+
}
290+
291+
# Run main function with all arguments
292+
main "$@"

.github/workflows/allboards.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,36 @@ jobs:
7272
env:
7373
FQBN: ${{ toJSON(matrix.chunk) }}
7474

75+
- name: Make validation script executable
76+
run: chmod +x ./.github/scripts/validate_board.sh
77+
78+
- name: Validate boards in chunk
79+
run: |
80+
echo "Starting board validation for chunk..."
81+
failed_boards=()
82+
83+
# Extract board names from FQBNs (remove espressif:esp32: prefix)
84+
boards_json=$(cat fqbns.json)
85+
board_names=$(echo "$boards_json" | jq -r '.[]' | sed 's/espressif:esp32://')
86+
87+
for board in $board_names; do
88+
echo "Validating board: $board"
89+
if ! ./.github/scripts/validate_board.sh "$board"; then
90+
echo "❌ Validation failed for board: $board"
91+
failed_boards+=("$board")
92+
else
93+
echo "✅ Validation passed for board: $board"
94+
fi
95+
done
96+
97+
if [ ${#failed_boards[@]} -gt 0 ]; then
98+
echo "❌ Board validation failed for the following boards:"
99+
printf ' - %s\n' "${failed_boards[@]}"
100+
exit 1
101+
else
102+
echo "✅ All board validations in chunk passed!"
103+
fi
104+
75105
- name: Compile sketch
76106
uses: P-R-O-C-H-Y/compile-sketches@a62f069b92dc8f5053da4ac439ea6d1950cf6379 # main
77107
with:

.github/workflows/boards.yml

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,10 @@ jobs:
4949
- name: Checkout repository
5050
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
5151

52-
- name: Check if build.board is uppercase
52+
- name: Validate board definition
5353
run: |
5454
board_name=$(echo ${{ matrix.fqbn }} | awk -F':' '{print $NF}')
55-
if grep -q "^$board_name.build.board=[A-Z0-9_]*$" boards.txt; then
56-
echo "$board_name.build.board is valid.";
57-
else
58-
echo "Error: $board_name.build.board is not uppercase!";
59-
exit 1;
60-
fi
55+
./.github/scripts/validate_board.sh "$board_name"
6156
6257
- name: Get libs cache
6358
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3

boards.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42280,6 +42280,8 @@ nano_nora.upload.tool.network=esp_ota
4228042280
nano_nora.upload.protocol=serial
4228142281
nano_nora.upload.maximum_size=3145728
4228242282
nano_nora.upload.maximum_data_size=327680
42283+
nano_nora.upload.flags=
42284+
nano_nora.upload.extra_flags=
4228342285
nano_nora.upload.use_1200bps_touch=false
4228442286
nano_nora.upload.wait_for_upload_port=false
4228542287

0 commit comments

Comments
 (0)