Skip to content

Commit 1924bc8

Browse files
authored
use Action CI to build all examples (#403)
1 parent 43fa67c commit 1924bc8

File tree

4 files changed

+227
-42
lines changed

4 files changed

+227
-42
lines changed

.github/workflows/githubci.yml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
name: Build
2+
3+
on: [pull_request, push]
4+
5+
jobs:
6+
build:
7+
strategy:
8+
fail-fast: false
9+
matrix:
10+
arduino-platform: ['feather52832', 'feather52840', 'cplaynrf52840', 'itsybitsy52840', 'cluenrf52840' ]
11+
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- name: Setup Python
16+
uses: actions/setup-python@v1
17+
with:
18+
python-version: '3.x'
19+
20+
- name: Checkout code
21+
uses: actions/checkout@v2
22+
23+
- name: Checkout submodules
24+
shell: bash
25+
run: |
26+
auth_header="$(git config --local --get http.https://github.com/.extraheader)"
27+
git submodule sync --recursive
28+
git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive
29+
30+
- name: Install Arduino CLI and Tools
31+
run: |
32+
pip3 install adafruit-nrfutil
33+
# make all our directories we need for files and libraries
34+
mkdir $HOME/.arduino15
35+
mkdir $HOME/.arduino15/packages
36+
mkdir $HOME/Arduino
37+
mkdir $HOME/Arduino/libraries
38+
curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh
39+
echo "::add-path::$GITHUB_WORKSPACE/bin"
40+
41+
- name: Install BSP and Libraries
42+
env:
43+
BSP_URL: https://adafruit.github.io/arduino-board-index/package_adafruit_index.json
44+
run: |
45+
arduino-cli config init
46+
arduino-cli core update-index
47+
arduino-cli core update-index --additional-urls $BSP_URL
48+
arduino-cli core install adafruit:nrf52 --additional-urls $BSP_URL
49+
BSP_PATH=$HOME/.arduino15/packages/adafruit/hardware/nrf52
50+
BSP_VERSION=`eval ls $BSP_PATH`
51+
rm -r $BSP_PATH/*
52+
ln -s $GITHUB_WORKSPACE $BSP_PATH/$BSP_VERSION
53+
arduino-cli lib install "Adafruit NeoPixel" "Adafruit NeoMatrix" "Adafruit GFX Library" "Adafruit SSD1306" "MIDI Library" "Adafruit ILI9341" "Adafruit HX8357 Library" "Adafruit Circuit Playground" "Firmata"
54+
55+
- name: Build examples
56+
run: python3 tools/build_all.py ${{ matrix.arduino-platform }}

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,4 @@ install:
6565
before_script:
6666

6767
script:
68-
- python3 tools/build_all.py
68+
- python3 tools/build_all_travis.py

tools/build_all.py

Lines changed: 21 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -23,29 +23,33 @@
2323
build_separator = '-' * 78
2424

2525
variants_dict = {
26+
'feather52832': 'Feather nRF52832',
2627
'feather52840': 'Feather nRF52840 Express',
2728
'cplaynrf52840': 'Circuit Playground Bluefruit Express',
2829
'itsybitsy52840': 'ItsyBitsy nRF52840 Express',
29-
'cluenrf52840': 'Clue nRF52840',
30-
'feather52832': 'Feather nRF52832'
30+
'cluenrf52840': 'CLUE nRF52840'
3131
}
3232

33-
# STDERR receives output that starts with the following text, none of which should be considered a warning or error...
34-
output_to_ignore = (
35-
'Picked up JAVA_TOOL_OPTIONS:',
36-
'Loading configuration...',
37-
'Initializing packages...',
38-
'Preparing boards...',
39-
'Verifying...',
40-
)
33+
all_variants = []
34+
35+
# build all variants if input not existed
36+
if len(sys.argv) > 1:
37+
if (sys.argv[1] in variants_dict):
38+
all_variants.append(sys.argv[1])
39+
else:
40+
print('\033[31INTERNAL ERR\033[0m - invalid variant name "{}"'.format(sys.argv[1]))
41+
sys.exit(-1)
42+
else:
43+
all_variants = list(variants_dict.keys())
44+
45+
print(all_variants)
46+
exit
4147

4248
def errorOutputFilter(line):
4349
if len(line) == 0:
4450
return False
4551
if line.isspace(): # Note: empty string does not match here!
4652
return False
47-
if line.startswith(output_to_ignore): # alternatively, can trim() each line, but that would create lots of short-lived strings...
48-
return False
4953
# TODO: additional items to remove?
5054
return True
5155

@@ -59,12 +63,8 @@ def build_examples(variant):
5963
print(build_separator)
6064
print((build_format + '| {:6} |').format('Library', 'Example', 'Result', 'Time'))
6165
print(build_separator)
62-
subprocess.run("arduino --board adafruit:nrf52:{}:softdevice={},debug=l0 --save-prefs".format(variant, 's140v6' if variant != 'feather52832' else 's132v6'), shell=True,
63-
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
6466

65-
if all_warnings:
66-
subprocess.run("arduino --pref 'compiler.warning_level=all' --save-prefs", shell=True,
67-
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
67+
fqbn = "adafruit:nrf52:{}:softdevice={},debug=l0".format(variant, 's140v6' if variant != 'feather52832' else 's132v6')
6868

6969
for sketch in glob.iglob('libraries/**/*.ino', recursive=True):
7070
start_time = time.monotonic()
@@ -80,9 +80,9 @@ def build_examples(variant):
8080
# preferably, would use Python logging handler to get both distinct outputs and one merged output
8181
# for now, split STDERR when building with all warnings enabled, so can detect warning/error output.
8282
if all_warnings:
83-
build_result = subprocess.run("arduino --verify {}".format(sketch), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
83+
build_result = subprocess.run("arduino-cli compile --warnings all --fqbn {} {}".format(fqbn, sketch), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
8484
else:
85-
build_result = subprocess.run("arduino --verify {}".format(sketch), shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
85+
build_result = subprocess.run("arduino-cli compile --warnings default --fqbn {} {}".format(fqbn, sketch), shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
8686

8787
# get stderr into a form where len(warningLines) indicates a true warning was output to stderr
8888
warningLines = [];
@@ -104,9 +104,6 @@ def build_examples(variant):
104104

105105
build_duration = time.monotonic() - start_time
106106

107-
if travis:
108-
print('travis_fold:start:build-{}\\r'.format(sketch))
109-
110107
print((build_format + '| {:5.2f}s |').format(sketch.split(os.path.sep)[1], os.path.basename(sketch), success, build_duration))
111108

112109
if success != "skipped":
@@ -118,28 +115,11 @@ def build_examples(variant):
118115
for line in warningLines:
119116
print(line)
120117

121-
if travis:
122-
print('travis_fold:end:build-{}\\r'.format(sketch))
123-
124118

125119
build_time = time.monotonic()
126120

127-
128-
# build only one variant if the environment variable is specified
129-
if (ENV_VARIABLE_NAME in os.environ):
130-
variant = os.environ.get(ENV_VARIABLE_NAME)
131-
# only use the environment variable if the variant exists in the dictionary
132-
if (variant in variants_dict):
133-
build_examples(variant)
134-
else:
135-
print('\033[31INTERNAL ERR\033[0m - invalid variant name "{}"'.format(variant))
136-
fail_count += 1
137-
exit_status = -1
138-
139-
else: # no environment variable specified, so build all variants
140-
for var in variants_dict:
141-
build_examples(var)
142-
121+
for var in all_variants:
122+
build_examples(var)
143123

144124
print(build_separator)
145125
build_time = time.monotonic() - build_time

tools/build_all_travis.py

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import os
2+
import glob
3+
import sys
4+
import subprocess
5+
import time
6+
7+
travis = False
8+
if "TRAVIS" in os.environ and os.environ["TRAVIS"] == "true":
9+
travis = True
10+
11+
all_warnings = False
12+
if "ALL_WARNINGS" in os.environ and os.environ["ALL_WARNINGS"] == "true":
13+
all_warnings = True
14+
15+
ENV_VARIABLE_NAME = 'VARIANT'
16+
17+
18+
exit_status = 0
19+
success_count = 0
20+
fail_count = 0
21+
22+
build_format = '| {:20} | {:30} | {:9} '
23+
build_separator = '-' * 78
24+
25+
variants_dict = {
26+
'feather52840': 'Feather nRF52840 Express',
27+
'cplaynrf52840': 'Circuit Playground Bluefruit Express',
28+
'itsybitsy52840': 'ItsyBitsy nRF52840 Express',
29+
'cluenrf52840': 'Clue nRF52840',
30+
'feather52832': 'Feather nRF52832'
31+
}
32+
33+
# STDERR receives output that starts with the following text, none of which should be considered a warning or error...
34+
output_to_ignore = (
35+
'Picked up JAVA_TOOL_OPTIONS:',
36+
'Loading configuration...',
37+
'Initializing packages...',
38+
'Preparing boards...',
39+
'Verifying...',
40+
)
41+
42+
def errorOutputFilter(line):
43+
if len(line) == 0:
44+
return False
45+
if line.isspace(): # Note: empty string does not match here!
46+
return False
47+
if line.startswith(output_to_ignore): # alternatively, can trim() each line, but that would create lots of short-lived strings...
48+
return False
49+
# TODO: additional items to remove?
50+
return True
51+
52+
53+
def build_examples(variant):
54+
global exit_status, success_count, fail_count, build_format, build_separator
55+
56+
print('\n')
57+
print(build_separator)
58+
print('| {:^74} |'.format(variants_dict[variant]))
59+
print(build_separator)
60+
print((build_format + '| {:6} |').format('Library', 'Example', 'Result', 'Time'))
61+
print(build_separator)
62+
subprocess.run("arduino --board adafruit:nrf52:{}:softdevice={},debug=l0 --save-prefs".format(variant, 's140v6' if variant != 'feather52832' else 's132v6'), shell=True,
63+
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
64+
65+
if all_warnings:
66+
subprocess.run("arduino --pref 'compiler.warning_level=all' --save-prefs", shell=True,
67+
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
68+
69+
for sketch in glob.iglob('libraries/**/*.ino', recursive=True):
70+
start_time = time.monotonic()
71+
72+
# skip if example contains: ".skip" or ".skip.variant"
73+
# however ".build.variant" file can overwrite ".skip", used to build a specific variant only
74+
sketchdir = os.path.dirname(sketch)
75+
if ( (os.path.exists(sketchdir + '/.skip') or os.path.exists(sketchdir + '/.skip.' + variant)) and
76+
not os.path.exists(sketchdir + '/.build.' + variant)):
77+
success = "skipped"
78+
else:
79+
# TODO - preferably, would have STDERR show up in **both** STDOUT and STDERR.
80+
# preferably, would use Python logging handler to get both distinct outputs and one merged output
81+
# for now, split STDERR when building with all warnings enabled, so can detect warning/error output.
82+
if all_warnings:
83+
build_result = subprocess.run("arduino --verify {}".format(sketch), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
84+
else:
85+
build_result = subprocess.run("arduino --verify {}".format(sketch), shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
86+
87+
# get stderr into a form where len(warningLines) indicates a true warning was output to stderr
88+
warningLines = [];
89+
if all_warnings and build_result.stderr:
90+
tmpWarningLines = build_result.stderr.decode("utf-8").splitlines()
91+
warningLines = list(filter(errorOutputFilter, (tmpWarningLines)))
92+
93+
if build_result.returncode != 0:
94+
exit_status = build_result.returncode
95+
success = "\033[31mfailed\033[0m "
96+
fail_count += 1
97+
elif len(warningLines) != 0:
98+
exit_status = -1
99+
success = "\033[31mwarnings\033[0m "
100+
fail_count += 1
101+
else:
102+
success = "\033[32msucceeded\033[0m"
103+
success_count += 1
104+
105+
build_duration = time.monotonic() - start_time
106+
107+
if travis:
108+
print('travis_fold:start:build-{}\\r'.format(sketch))
109+
110+
print((build_format + '| {:5.2f}s |').format(sketch.split(os.path.sep)[1], os.path.basename(sketch), success, build_duration))
111+
112+
if success != "skipped":
113+
if build_result.returncode != 0:
114+
print(build_result.stdout.decode("utf-8"))
115+
if (build_result.stderr):
116+
print(build_result.stderr.decode("utf-8"))
117+
if len(warningLines) != 0:
118+
for line in warningLines:
119+
print(line)
120+
121+
if travis:
122+
print('travis_fold:end:build-{}\\r'.format(sketch))
123+
124+
125+
build_time = time.monotonic()
126+
127+
128+
# build only one variant if the environment variable is specified
129+
if (ENV_VARIABLE_NAME in os.environ):
130+
variant = os.environ.get(ENV_VARIABLE_NAME)
131+
# only use the environment variable if the variant exists in the dictionary
132+
if (variant in variants_dict):
133+
build_examples(variant)
134+
else:
135+
print('\033[31INTERNAL ERR\033[0m - invalid variant name "{}"'.format(variant))
136+
fail_count += 1
137+
exit_status = -1
138+
139+
else: # no environment variable specified, so build all variants
140+
for var in variants_dict:
141+
build_examples(var)
142+
143+
144+
print(build_separator)
145+
build_time = time.monotonic() - build_time
146+
print("Build Summary: {} \033[32msucceeded\033[0m, {} \033[31mfailed\033[0m and took {:.2f}s".format(success_count, fail_count, build_time))
147+
print(build_separator)
148+
149+
sys.exit(exit_status)

0 commit comments

Comments
 (0)