Skip to content

Commit 03973f0

Browse files
authoredDec 2, 2020
Merge pull request #232 from Arduino-CI/2020-12-01_fixes
Fixes for GitHub Action
·
v1.6.2v1.1.0
2 parents a1139a2 + 89d5a81 commit 03973f0

18 files changed

+227
-240
lines changed
 

‎.github/workflows/linux.yaml‎

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,23 @@
11
# This is the name of the workflow, visible on GitHub UI
22
name: linux
33

4-
# Run on a Push or a Pull Request
5-
on: [push, pull_request]
4+
on: [pull_request]
65

76
jobs:
8-
rspec:
7+
"unittest_lint_sampleproject":
98
runs-on: ubuntu-latest
109
steps:
1110
- uses: actions/checkout@v2
1211
- uses: ruby/setup-ruby@v1
1312
with:
1413
ruby-version: 2.6
15-
16-
# Install and run Arduino CI tests for rspec
17-
- name: Build and Execute
14+
- name: Check style, funcionality, and usage
1815
run: |
1916
g++ -v
20-
bundle install
21-
bundle exec rspec --backtrace
22-
23-
rubocop:
24-
runs-on: ubuntu-latest
25-
steps:
26-
- uses: actions/checkout@v2
27-
- uses: ruby/setup-ruby@v1
28-
with:
29-
ruby-version: 2.6
30-
31-
# Install and run Arduino CI tests for rubocop
32-
- name: Build and Execute
33-
run: |
3417
bundle install
3518
bundle exec rubocop --version
3619
bundle exec rubocop -D .
37-
38-
TestSomething:
39-
runs-on: ubuntu-latest
40-
steps:
41-
- uses: actions/checkout@v2
42-
- uses: ruby/setup-ruby@v1
43-
with:
44-
ruby-version: 2.6
45-
46-
# Install and run Arduino CI tests for TestSomething
47-
- name: Build and Execute
48-
run: |
49-
g++ -v
20+
bundle exec rspec --backtrace
5021
cd SampleProjects/TestSomething
5122
bundle install
5223
bundle exec arduino_ci.rb
@@ -58,9 +29,7 @@ jobs:
5829
- uses: ruby/setup-ruby@v1
5930
with:
6031
ruby-version: 2.6
61-
62-
# Install and run Arduino CI tests for NetworkLib
63-
- name: Build and Execute
32+
- name: Test NetworkLib from scratch
6433
run: |
6534
g++ -v
6635
cd SampleProjects/NetworkLib

‎.github/workflows/macos.yaml‎

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,23 @@
11
# This is the name of the workflow, visible on GitHub UI
22
name: macos
33

4-
# Run on a Push or a Pull Request
5-
on: [push, pull_request]
4+
on: [pull_request]
65

76
jobs:
8-
rspec:
7+
"unittest_lint_sampleproject":
98
runs-on: macos-latest
109
steps:
1110
- uses: actions/checkout@v2
1211
- uses: ruby/setup-ruby@v1
1312
with:
1413
ruby-version: 2.6
15-
16-
# Install and run Arduino CI tests for rspec
17-
- name: Build and Execute
14+
- name: Check style, funcionality, and usage
1815
run: |
1916
g++ -v
20-
bundle install
21-
bundle exec rspec --backtrace
22-
23-
rubocop:
24-
runs-on: macos-latest
25-
steps:
26-
- uses: actions/checkout@v2
27-
- uses: ruby/setup-ruby@v1
28-
with:
29-
ruby-version: 2.6
30-
31-
# Install and run Arduino CI tests for rubocop
32-
- name: Build and Execute
33-
run: |
3417
bundle install
3518
bundle exec rubocop --version
3619
bundle exec rubocop -D .
37-
38-
TestSomething:
39-
runs-on: macos-latest
40-
steps:
41-
- uses: actions/checkout@v2
42-
- uses: ruby/setup-ruby@v1
43-
with:
44-
ruby-version: 2.6
45-
46-
# Install and run Arduino CI tests for TestSomething
47-
- name: Build and Execute
48-
run: |
49-
g++ -v
20+
bundle exec rspec --backtrace
5021
cd SampleProjects/TestSomething
5122
bundle install
5223
bundle exec arduino_ci.rb
@@ -58,9 +29,7 @@ jobs:
5829
- uses: ruby/setup-ruby@v1
5930
with:
6031
ruby-version: 2.6
61-
62-
# Install and run Arduino CI tests for NetworkLib
63-
- name: Build and Execute
32+
- name: Test NetworkLib from scratch
6433
run: |
6534
g++ -v
6635
cd SampleProjects/NetworkLib

‎.github/workflows/windows.yaml‎

Lines changed: 7 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,35 @@
11
# This is the name of the workflow, visible on GitHub UI
22
name: windows
33

4-
# Run on a Push or a Pull Request
5-
on: [push, pull_request]
4+
on: [pull_request]
65

76
jobs:
8-
rspec:
9-
runs-on: windows-latest
7+
"unittest_lint_sampleproject":
8+
runs-on: ubuntu-latest
109
steps:
1110
- uses: actions/checkout@v2
1211
- uses: ruby/setup-ruby@v1
1312
with:
1413
ruby-version: 2.6
15-
16-
# Install and run Arduino CI tests for rspec
17-
- name: Build and Execute
14+
- name: Check style, funcionality, and usage
1815
run: |
1916
g++ -v
20-
bundle install
21-
bundle exec rspec --backtrace
22-
23-
rubocop:
24-
runs-on: windows-latest
25-
steps:
26-
- uses: actions/checkout@v2
27-
- uses: ruby/setup-ruby@v1
28-
with:
29-
ruby-version: 2.6
30-
31-
# Install and run Arduino CI tests for rubocop
32-
- name: Build and Execute
33-
run: |
3417
bundle install
3518
bundle exec rubocop --version
3619
bundle exec rubocop -D .
37-
38-
TestSomething:
39-
runs-on: windows-latest
40-
steps:
41-
- uses: actions/checkout@v2
42-
- uses: ruby/setup-ruby@v1
43-
with:
44-
ruby-version: 2.6
45-
46-
# Install and run Arduino CI tests for TestSomething
47-
- name: Build and Execute
48-
run: |
49-
g++ -v
20+
bundle exec rspec --backtrace
5021
cd SampleProjects/TestSomething
5122
bundle install
5223
bundle exec arduino_ci.rb
5324
5425
NetworkLib:
55-
runs-on: windows-latest
26+
runs-on: ubuntu-latest
5627
steps:
5728
- uses: actions/checkout@v2
5829
- uses: ruby/setup-ruby@v1
5930
with:
6031
ruby-version: 2.6
61-
62-
# Install and run Arduino CI tests for Network
63-
- name: Build and Execute
32+
- name: Test NetworkLib from scratch
6433
run: |
6534
g++ -v
6635
cd SampleProjects/NetworkLib

‎.rubocop.yml‎

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
AllCops:
2+
TargetRubyVersion: 2.6
3+
NewCops: enable
4+
SuggestExtensions: false
25
Exclude:
36
- '*.gemspec'
47
- 'spec/*.rb'
@@ -13,6 +16,24 @@ Style/RescueStandardError:
1316
Security/Open:
1417
Enabled: false
1518

19+
Style/FrozenStringLiteralComment:
20+
Enabled: false
21+
22+
# broken :( https://github.com/rubocop-hq/rubocop/issues/9144
23+
Style/StringConcatenation:
24+
Enabled: false
25+
26+
# Ruins git diffs
27+
Style/AccessorGrouping:
28+
Enabled: false
29+
30+
# Ruins keeping the upper half of the conditional smaller
31+
Style/NegatedIfElseCondition:
32+
Enabled: false
33+
34+
# affects calling style?
35+
Style/OptionalBooleanParameter:
36+
Enabled: false
1637

1738
# Extra lines for readability
1839
Layout/EmptyLinesAroundClassBody:
@@ -37,9 +58,7 @@ Layout/EndAlignment:
3758
Layout/CaseIndentation:
3859
EnforcedStyle: end
3960

40-
Metrics/LineLength:
41-
Description: Limit lines to 80 characters.
42-
StyleGuide: https://github.com/bbatsov/ruby-style-guide#80-character-limits
61+
Layout/LineLength:
4362
Enabled: true
4463
Max: 130
4564

‎CHANGELOG.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99
### Added
10+
- `ensure_arduino_installation.rb` now ensures the existence of the library directory as well
11+
- Environment variables to escalate unit tests or examples not being found during CI testing
1012

1113
### Changed
14+
- Conserve CI testing minutes by grouping CI into fewer runs
1215

1316
### Deprecated
1417

1518
### Removed
1619

1720
### Fixed
21+
- Improper reference to `Host` in `arduino_ci.rb` test runner is now properly qualified
22+
- Failure to set board manager URLs (for 3rd party board providers) has been fixed
1823

1924
### Security
2025

‎Gemfile‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ gemspec
88
gem "bundler", "> 1.15", require: false, group: :test
99
gem "keepachangelog_manager", "~> 0.0.2", require: false, group: :test
1010
gem "rspec", "~> 3.0", require: false, group: :test
11-
gem 'rubocop', '~>0.59.0', require: false, group: :test
11+
gem 'rubocop', '~>1.5.0', require: false, group: :test
1212
gem 'simplecov', require: false, group: :test
1313
gem 'yard', '~>0.9.11', require: false, group: :test

‎REFERENCE.md‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,22 @@ This completely skips the compilation tests (of library examples) portion of the
3333

3434
This allows a file (or glob) pattern to be executed in your tests directory, creating a whitelist of files to test. E.g. `--testfile-select=test_animal_*.cpp` would match `test_animal_cat.cpp` and `test_animal_dog.cpp` (testing only those) and not `test_plant_rose.cpp`.
3535

36+
3637
### `--testfile-reject` option
3738

3839
This allows a file (or glob) pattern to be executed in your tests directory, creating a blacklist of files to skip. E.g. `--testfile-reject=test_animal_*.cpp` would match `test_animal_cat.cpp` and `test_animal_dog.cpp` (skipping those) and test only `test_plant_rose.cpp`, `test_plant_daisy.cpp`, etc.
3940

4041

42+
### `EXPECT_UNITTESTS` environment variable
43+
44+
If set, testing will fail if no unit test files are detected (or if the directory does not exist). This is to avoid communicating a passing status in cases where a commit may have accidentally moved or deleted the test files.
45+
46+
47+
### `EXPECT_EXAMPLES` environment variable
48+
49+
If set, testing will fail if no example sketches are detected. This is to avoid communicating a passing status in cases where a commit may have accidentally moved or deleted the examples.
50+
51+
4152
## Indirectly Overriding Build Behavior (medium term use), and Advanced Options
4253

4354
For build behavior that you'd like to persist across commits (e.g. defining the set of platforms to test against, disabling a test that you expect to re-enable at some future point), a special configuration file called `.arduino-ci.yml` can be used. There are 3 places you can put them:
@@ -53,7 +64,7 @@ For build behavior that you'd like to persist across commits (e.g. defining the
5364

5465
Arduino boards are typically named in the form `manufacturer:family:model`. These definitions are not arbitrary -- they are defined in an Arduino _package_. For all but the built-in packages, you will need a package URL. Here is Adafruit's: https://adafruit.github.io/arduino-board-index/package_adafruit_index.json
5566

56-
Here is how you would declare a package that includes the `potato:salad` family of boards in your `.arduino-ci.yml`:
67+
Here is how you would declare a package that includes the `potato:salad` set of platforms (aka "board family") in your `.arduino-ci.yml`:
5768

5869
```yaml
5970
packages:

‎exe/arduino_ci.rb‎

Lines changed: 127 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
require 'optparse'
66

77
WIDTH = 80
8-
FIND_FILES_INDENT = 4
8+
VAR_EXPECT_EXAMPLES = "EXPECT_EXAMPLES".freeze
9+
VAR_EXPECT_UNITTESTS = "EXPECT_UNITTESTS".freeze
910

1011
@failure_count = 0
1112
@passfail = proc { |result| result ? "✓" : "✗" }
@@ -48,6 +49,10 @@ def self.parse(options)
4849

4950
opts.on("-h", "--help", "Prints this help") do
5051
puts opts
52+
puts
53+
puts "Additionally, the following environment variables control the script:"
54+
puts " - #{VAR_EXPECT_EXAMPLES} - if set, testing will fail if no example sketches are present"
55+
puts " - #{VAR_EXPECT_UNITTESTS} - if set, testing will fail if no unit tests are present"
5156
exit
5257
end
5358
end
@@ -93,7 +98,7 @@ def perform_action(message, multiline, mark_fn, on_fail_msg, tally_on_fail, abor
9398
else
9499
print line
95100
end
96-
STDOUT.flush
101+
$stdout.flush
97102
result = yield
98103
mark = mark_fn.nil? ? "" : mark_fn.call(result)
99104
# if multline, put checkmark at full width
@@ -119,7 +124,7 @@ def attempt_multiline(message, &block)
119124
end
120125

121126
# Make a nice status for something that kills the script immediately on failure
122-
FAILED_ASSURANCE_MESSAGE = "This may indicate a problem with ArduinoCI, or your configuration".freeze
127+
FAILED_ASSURANCE_MESSAGE = "This may indicate a problem with your configuration; halting here".freeze
123128
def assure(message, &block)
124129
perform_action(message, false, @passfail, FAILED_ASSURANCE_MESSAGE, true, true, &block)
125130
end
@@ -139,9 +144,7 @@ def inform_multiline(message, &block)
139144
# Assure that a platform exists and return its definition
140145
def assured_platform(purpose, name, config)
141146
platform_definition = config.platform_definition(name)
142-
assure("Requested #{purpose} platform '#{name}' is defined in 'platforms' YML") do
143-
!platform_definition.nil?
144-
end
147+
assure("Requested #{purpose} platform '#{name}' is defined in 'platforms' YML") { !platform_definition.nil? }
145148
platform_definition
146149
end
147150

@@ -157,24 +160,22 @@ def file_is_hidden_somewhere?(path)
157160
# print out some files
158161
def display_files(pathname)
159162
# `find` doesn't follow symlinks, so we should instead
160-
realpath = Host.symlink?(pathname) ? Host.readlink(pathname) : pathname
163+
realpath = ArduinoCI::Host.symlink?(pathname) ? ArduinoCI::Host.readlink(pathname) : pathname
161164

162165
# suppress directories and dotfile-based things
163166
all_files = realpath.find.select(&:file?)
164167
non_hidden = all_files.reject { |path| file_is_hidden_somewhere?(path) }
165168

166169
# print files with an indent
167-
margin = " " * FIND_FILES_INDENT
168-
non_hidden.each { |p| puts "#{margin}#{p}" }
170+
puts " Files (excluding hidden files): #{non_hidden.size}"
171+
non_hidden.each { |p| puts " #{p}" }
169172
end
170173

171174
# @return [Array<String>] The list of installed libraries
172175
def install_arduino_library_dependencies(library_names, on_behalf_of, already_installed = [])
173176
installed = already_installed.clone
174-
library_names.map { |n| @backend.library_of_name(n) }.each do |l|
175-
if installed.include?(l)
176-
# do nothing
177-
elsif l.installed?
177+
(library_names.map { |n| @backend.library_of_name(n) } - installed).each do |l|
178+
if l.installed?
178179
inform("Using pre-existing dependency of #{on_behalf_of}") { l.name }
179180
else
180181
assure("Installing dependency of #{on_behalf_of}: '#{l.name}'") do
@@ -189,13 +190,77 @@ def install_arduino_library_dependencies(library_names, on_behalf_of, already_in
189190
installed
190191
end
191192

192-
def perform_unit_tests(cpp_library, file_config)
193-
if @cli_options[:skip_unittests]
194-
inform("Skipping unit tests") { "as requested via command line" }
195-
return
193+
# @param example_platform_info [Hash] mapping of platform name to package information
194+
# @param board_package_url [Hash] mapping of package name to URL
195+
def install_all_packages(example_platform_info, board_package_url)
196+
# with all platform info, we can extract unique packages and their urls
197+
# do that, set the URLs, and download the packages
198+
all_packages = example_platform_info.values.map { |v| v[:package] }.uniq.reject(&:nil?)
199+
200+
# make sure any non-builtin package has a URL defined
201+
all_packages.each { |p| assure("Board package #{p} has a defined URL") { board_package_url[p] } }
202+
203+
# set up all the board manager URLs.
204+
# we can safely reject nils now, they would be for the builtins
205+
all_urls = all_packages.map { |p| board_package_url[p] }.uniq.reject(&:nil?)
206+
unless all_urls.empty?
207+
assure_multiline("Setting board manager URLs") do
208+
@backend.board_manager_urls = all_urls
209+
result = @backend.board_manager_urls
210+
result.each { |u| puts " #{u}" }
211+
(all_urls - result).empty? # check that all_urls is completely contained in the result
212+
end
196213
end
197-
config = file_config.with_override_config(@cli_options[:ci_config])
214+
all_packages.each { |p| assure("Installing board package #{p}") { @backend.install_boards(p) } }
215+
end
198216

217+
# @param expectation_envvar [String] the name of the env var to check
218+
# @param operation [String] a description of what operation we might be skipping
219+
# @param filegroup_name [String] a description of the set of files without which we effectively skip the operation
220+
# @param dir_description [String] a description of the directory where we looked for the files
221+
# @param dir [Pathname] the directory where we looked for the files
222+
def handle_expectation_of_files(expectation_envvar, operation, filegroup_name, dir_description, dir_path)
223+
# alert future me about running the script from the wrong directory, instead of doing the huge file dump
224+
# otherwise, assume that the user might be running the script on a library with no actual unit tests
225+
if Pathname.new(__dir__).parent == Pathname.new(Dir.pwd)
226+
inform_multiline("arduino_ci seems to be trying to test itself") do
227+
[
228+
"arduino_ci (the ruby gem) isn't an arduino project itself, so running the CI test script against",
229+
"the core library isn't really a valid thing to do... but it's easy for a developer (including the",
230+
"owner) to mistakenly do just that. Hello future me, you probably meant to run this against one of",
231+
"the sample projects in SampleProjects/ ... if not, please submit a bug report; what a wild case!"
232+
].each { |l| puts " #{l}" }
233+
false
234+
end
235+
exit(1)
236+
end
237+
238+
# either the directory is empty, or it doesn't exist at all. message accordingly.
239+
(problem, dir_desc, dir) = if dir_path.exist?
240+
["No #{filegroup_name} were found in", dir_description, dir_path]
241+
else
242+
["No #{dir_description} at", "base directory", dir_path.parent]
243+
end
244+
245+
inform(problem) { dir_path }
246+
inform("Environment variable #{expectation_envvar} is") { "(#{ENV[expectation_envvar].class}) #{ENV[expectation_envvar]}" }
247+
if ENV[expectation_envvar].nil?
248+
inform_multiline("Skipping #{operation}") do
249+
puts " In case that's an error, this is what was found in the #{dir_desc}:"
250+
display_files(dir)
251+
puts " To force an error in this case, set the environment variable #{expectation_envvar}"
252+
true
253+
end
254+
else
255+
assure_multiline("Dumping project's #{dir_desc} before exit") do
256+
display_files(dir)
257+
false
258+
end
259+
end
260+
end
261+
262+
# report and return the set of compilers
263+
def get_annotated_compilers(config, cpp_library)
199264
# check GCC
200265
compilers = config.compilers_to_use
201266
assure("The set of compilers (#{compilers.length}) isn't empty") { !compilers.empty? }
@@ -209,66 +274,54 @@ def perform_unit_tests(cpp_library, file_config)
209274
end
210275
inform("libasan availability for #{gcc_binary}") { cpp_library.libasan?(gcc_binary) }
211276
end
277+
compilers
278+
end
279+
280+
def perform_unit_tests(cpp_library, file_config)
281+
if @cli_options[:skip_unittests]
282+
inform("Skipping unit tests") { "as requested via command line" }
283+
return
284+
end
212285

213-
# Ensure platforms exist for unit test, and save their info in all_platform_info keyed by name
214-
all_platform_info = {}
215-
config.platforms_to_unittest.each { |p| all_platform_info[p] = assured_platform("unittest", p, config) }
286+
config = file_config.with_override_config(@cli_options[:ci_config])
287+
compilers = get_annotated_compilers(config, cpp_library)
288+
config.platforms_to_unittest.each_with_object({}) { |p, acc| acc[p] = assured_platform("unittest", p, config) }
216289

217290
inform("Library conforms to Arduino library specification") { cpp_library.one_point_five? ? "1.5" : "1.0" }
218291

219-
# iterate boards / tests
220-
if !cpp_library.tests_dir.exist?
221-
# alert future me about running the script from the wrong directory, instead of doing the huge file dump
222-
# otherwise, assume that the user might be running the script on a library with no actual unit tests
223-
if Pathname.new(__dir__).parent == Pathname.new(Dir.pwd)
224-
inform_multiline("arduino_ci seems to be trying to test itself") do
225-
[
226-
"arduino_ci (the ruby gem) isn't an arduino project itself, so running the CI test script against",
227-
"the core library isn't really a valid thing to do... but it's easy for a developer (including the",
228-
"owner) to mistakenly do just that. Hello future me, you probably meant to run this against one of",
229-
"the sample projects in SampleProjects/ ... if not, please submit a bug report; what a wild case!"
230-
].each { |l| puts " #{l}" }
231-
false
232-
end
233-
exit(1)
234-
else
235-
inform_multiline("Skipping unit tests; no tests dir at #{cpp_library.tests_dir}") do
236-
puts " In case that's an error, this is what was found in the library:"
237-
display_files(cpp_library.tests_dir.parent)
238-
true
239-
end
240-
end
241-
elsif cpp_library.test_files.empty?
242-
inform_multiline("Skipping unit tests; no test files were found in #{cpp_library.tests_dir}") do
243-
puts " In case that's an error, this is what was found in the tests directory:"
244-
display_files(cpp_library.tests_dir)
245-
true
246-
end
247-
elsif config.platforms_to_unittest.empty?
292+
# Handle lack of test files
293+
if cpp_library.test_files.empty?
294+
handle_expectation_of_files(VAR_EXPECT_UNITTESTS, "unit tests", "test files", "tests directory", cpp_library.tests_dir)
295+
return
296+
end
297+
298+
# Handle lack of platforms
299+
if config.platforms_to_unittest.empty?
248300
inform("Skipping unit tests") { "no platforms were requested" }
249-
else
250-
install_arduino_library_dependencies(config.aux_libraries_for_unittest, "<unittest/libraries>")
251-
252-
config.platforms_to_unittest.each do |p|
253-
config.allowable_unittest_files(cpp_library.test_files).each do |unittest_path|
254-
unittest_name = unittest_path.basename.to_s
255-
compilers.each do |gcc_binary|
256-
attempt_multiline("Unit testing #{unittest_name} with #{gcc_binary} for #{p}") do
257-
exe = cpp_library.build_for_test_with_configuration(
258-
unittest_path,
259-
config.aux_libraries_for_unittest,
260-
gcc_binary,
261-
config.gcc_config(p)
262-
)
263-
puts
264-
unless exe
265-
puts "Last command: #{cpp_library.last_cmd}"
266-
puts cpp_library.last_out
267-
puts cpp_library.last_err
268-
next false
269-
end
270-
cpp_library.run_test_file(exe)
301+
return
302+
end
303+
304+
install_arduino_library_dependencies(config.aux_libraries_for_unittest, "<unittest/libraries>")
305+
306+
config.platforms_to_unittest.each do |p|
307+
config.allowable_unittest_files(cpp_library.test_files).each do |unittest_path|
308+
unittest_name = unittest_path.basename.to_s
309+
compilers.each do |gcc_binary|
310+
attempt_multiline("Unit testing #{unittest_name} with #{gcc_binary} for #{p}") do
311+
exe = cpp_library.build_for_test_with_configuration(
312+
unittest_path,
313+
config.aux_libraries_for_unittest,
314+
gcc_binary,
315+
config.gcc_config(p)
316+
)
317+
puts
318+
unless exe
319+
puts "Last command: #{cpp_library.last_cmd}"
320+
puts cpp_library.last_out
321+
puts cpp_library.last_err
322+
next false
271323
end
324+
cpp_library.run_test_file(exe)
272325
end
273326
end
274327
end
@@ -306,40 +359,14 @@ def perform_example_compilation_tests(cpp_library, config)
306359
aux_libraries.merge(ovr_config.aux_libraries_for_build)
307360
end
308361

309-
# with all platform info, we can extract unique packages and their urls
310-
# do that, set the URLs, and download the packages
311-
all_packages = example_platform_info.values.map { |v| v[:package] }.uniq.reject(&:nil?)
312-
313-
# make sure any non-builtin package has a URL defined
314-
all_packages.each do |p|
315-
assure("Board package #{p} has a defined URL") { board_package_url[p] }
316-
end
317-
318-
# set up all the board manager URLs.
319-
# we can safely reject nils now, they would be for the builtins
320-
all_urls = all_packages.map { |p| board_package_url[p] }.uniq.reject(&:nil?)
321-
322-
unless all_urls.empty?
323-
assure("Setting board manager URLs") do
324-
@backend.board_manager_urls = all_urls
325-
end
326-
end
327-
328-
all_packages.each do |p|
329-
assure("Installing board package #{p}") do
330-
@backend.install_boards(p)
331-
end
332-
end
333-
362+
install_all_packages(example_platform_info, board_package_url)
334363
install_arduino_library_dependencies(aux_libraries, "<compile/libraries>")
335364

336365
if config.platforms_to_build.empty?
337366
inform("Skipping builds") { "no platforms were requested" }
338367
return
339368
elsif library_examples.empty?
340-
inform_multiline("Skipping builds; no examples found in #{installed_library_path}") do
341-
display_files(installed_library_path)
342-
end
369+
handle_expectation_of_files(VAR_EXPECT_EXAMPLES, "builds", "examples", "the examples directory", cpp_library.examples_dir)
343370
return
344371
end
345372

‎exe/arduino_ci_remote.rb‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
#!/usr/bin/env ruby
22
puts "arduino_ci_remote.rb is deprecated in favor of arduino_ci.rb."
3-
require_relative "arduino_ci.rb"
3+
require_relative "arduino_ci"

‎exe/ensure_arduino_installation.rb‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,10 @@
22
require 'arduino_ci'
33

44
# this will exit after Arduino is located and/or forcibly installed
5-
ArduinoCI::ArduinoInstallation.autolocate!
5+
backend = ArduinoCI::ArduinoInstallation.autolocate!
6+
lib_dir = backend.lib_dir
7+
8+
unless lib_dir.exist?
9+
puts "Creating libraries directory #{lib_dir}"
10+
lib_dir.mkpath
11+
end

‎lib/arduino_ci/arduino_backend.rb‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ def initialize(binary_path)
5050

5151
def _wrap_run(work_fn, *args, **kwargs)
5252
# do some work to extract & merge environment variables if they exist
53-
has_env = !args.empty? && args[0].class == Hash
53+
has_env = !args.empty? && args[0].instance_of?(Hash)
5454
env_vars = has_env ? args[0] : {}
55-
actual_args = has_env ? args[1..-1] : args # need to shift over if we extracted args
55+
actual_args = has_env ? args[1..] : args # need to shift over if we extracted args
5656
custom_config = @config_dir.nil? ? [] : ["--config-file", @config_dir.to_s]
5757
full_args = [binary_path.to_s, "--format", "json"] + custom_config + actual_args
5858
full_cmd = env_vars.empty? ? full_args : [env_vars] + full_args
@@ -121,7 +121,11 @@ def board_installed?(boardname)
121121
# @param name [String] the board name
122122
# @return [bool] whether the command succeeded
123123
def install_boards(boardfamily)
124-
result = run_and_capture("core", "install", boardfamily)
124+
result = if @additional_urls.empty?
125+
run_and_capture("core", "install", boardfamily)
126+
else
127+
run_and_capture("core", "install", boardfamily, "--additional-urls", @additional_urls.join(","))
128+
end
125129
result[:success]
126130
end
127131

‎lib/arduino_ci/arduino_downloader.rb‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def download
104104
total_size += size
105105
needed_dots = (total_size / chunk_size).to_i
106106
unprinted_dots = needed_dots - dots
107-
@output.print("." * unprinted_dots) if unprinted_dots > 0
107+
@output.print("." * unprinted_dots) if unprinted_dots.positive?
108108
dots = needed_dots
109109
end
110110

‎lib/arduino_ci/ci_config.rb‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ def default
6666
attr_accessor :platform_info
6767
attr_accessor :compile_info
6868
attr_accessor :unittest_info
69+
6970
def initialize
7071
@package_info = {}
7172
@platform_info = {}
@@ -107,15 +108,15 @@ def validate_data(rootname, source, schema)
107108
good_data = {}
108109
source.each do |key, value|
109110
ksym = key.to_sym
110-
expected_type = schema[ksym].class == Class ? schema[ksym] : Hash
111+
expected_type = schema[ksym].instance_of?(Class) ? schema[ksym] : Hash
111112
if !schema.include?(ksym)
112113
puts "Warning: unknown field '#{ksym}' under definition for #{rootname}"
113114
elsif value.nil?
114115
good_data[ksym] = nil
115116
elsif value.class != expected_type
116117
puts "Warning: expected field '#{ksym}' of #{rootname} to be '#{expected_type}', got '#{value.class}'"
117118
else
118-
good_data[ksym] = value.class == Hash ? validate_data(key, value, schema[ksym]) : value
119+
good_data[ksym] = value.instance_of?(Hash) ? validate_data(key, value, schema[ksym]) : value
119120
end
120121
end
121122
good_data

‎lib/arduino_ci/cpp_library.rb‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ def path
8282
@backend.lib_dir + name_on_disk
8383
end
8484

85+
# @return [String] The parent directory of all examples
86+
def examples_dir
87+
path + "examples"
88+
end
89+
8590
# Determine whether a library is present in the lib dir
8691
#
8792
# Note that `true` doesn't guarantee that the library is valid/installed
@@ -402,8 +407,7 @@ def all_arduino_library_dependencies!(additional_libraries = [])
402407
other_lib.install unless other_lib.installed?
403408
other_lib.all_arduino_library_dependencies!
404409
end.flatten
405-
ret = (additional_libraries + recursive).uniq
406-
ret
410+
(additional_libraries + recursive).uniq
407411
end
408412

409413
# Arduino library directories containing sources -- only those of the dependencies
@@ -517,7 +521,7 @@ def build_for_test_with_configuration(test_file, aux_libraries, gcc_binary, ci_g
517521
# @param executable [Pathname] the path to the test file
518522
def print_stack_dump(executable)
519523
possible_dumpfiles = [
520-
executable.sub_ext(executable.extname + ".stackdump")
524+
executable.sub_ext("#{executable.extname}.stackdump")
521525
]
522526
possible_dumpfiles.select(&:exist?).each do |dump|
523527
puts "========== Stack dump from #{dump}:"

‎lib/arduino_ci/host.rb‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ module ArduinoCI
88
class Host
99
# TODO: this came from https://stackoverflow.com/a/22716582/2063546
1010
# and I'm not sure if it can be replaced by self.os == :windows
11-
WINDOWS_VARIANT_REGEX = /mswin32|cygwin|mingw|bccwin/
11+
WINDOWS_VARIANT_REGEX = /mswin32|cygwin|mingw|bccwin/.freeze
1212

1313
# e.g. 11/27/2020 01:02 AM <SYMLINKD> ExcludeSomething [C:\projects\arduino-ci\SampleProjects\ExcludeSomething]
14-
DIR_SYMLINK_REGEX = %r{\d+/\d+/\d+\s+[^<]+<SYMLINKD?>\s+(.*) \[([^\]]+)\]}
14+
DIR_SYMLINK_REGEX = %r{\d+/\d+/\d+\s+[^<]+<SYMLINKD?>\s+(.*) \[([^\]]+)\]}.freeze
1515

1616
# Cross-platform way of finding an executable in the $PATH.
1717
# via https://stackoverflow.com/a/5471032/2063546

‎spec/arduino_ci_spec.rb‎

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,3 @@
88
end
99
end
1010
end
11-
12-
RSpec.describe ArduinoCI::Host do
13-
next if skip_ruby_tests
14-
context "which" do
15-
it "can find things with which" do
16-
ruby_path = ArduinoCI::Host.which("ruby")
17-
expect(ruby_path).not_to be nil
18-
expect(ruby_path.include? "ruby").to be true
19-
end
20-
end
21-
22-
end

‎spec/cpp_library_spec.rb‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,13 @@ def verified_install(backend, path)
217217
end
218218
end
219219

220+
context "examples_dir" do
221+
it "locates the examples directory" do
222+
relative_path = @cpp_library.examples_dir.relative_path_from(@base_dir)
223+
expect(relative_path.to_s).to eq("#{sampleproject}/examples")
224+
end
225+
end
226+
220227
context "test_files" do
221228
it "finds cpp files in directory" do
222229
relative_paths = @cpp_library.test_files.map { |f| f.relative_path_from(@base_dir) }

‎spec/host_spec.rb‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,12 @@ def with_tmpdir(path)
5050
end
5151
end
5252

53+
context "which" do
54+
it "can find things with which" do
55+
ruby_path = ArduinoCI::Host.which("ruby")
56+
expect(ruby_path).not_to be nil
57+
expect(ruby_path.include? "ruby").to be true
58+
end
59+
end
60+
5361
end

0 commit comments

Comments
 (0)
Please sign in to comment.