From a0ed1eb75481e4e404781c4970e0b6495240d99b Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Wed, 28 Dec 2022 08:27:39 -0500 Subject: [PATCH 01/19] Test arduino help functionality in CI --- .github/workflows/linux.yaml | 1 + .github/workflows/macos.yaml | 1 + .github/workflows/windows.yaml | 1 + 3 files changed, 3 insertions(+) diff --git a/.github/workflows/linux.yaml b/.github/workflows/linux.yaml index 1b29e833..5a0ce875 100644 --- a/.github/workflows/linux.yaml +++ b/.github/workflows/linux.yaml @@ -44,6 +44,7 @@ jobs: bundle install cd SampleProjects/TestSomething bundle install + bundle exec arduino_ci.rb --help bundle exec arduino_ci.rb NetworkLib: diff --git a/.github/workflows/macos.yaml b/.github/workflows/macos.yaml index 6d8eaa2c..4bb63563 100644 --- a/.github/workflows/macos.yaml +++ b/.github/workflows/macos.yaml @@ -44,6 +44,7 @@ jobs: bundle install cd SampleProjects/TestSomething bundle install + bundle exec arduino_ci.rb --help bundle exec arduino_ci.rb NetworkLib: diff --git a/.github/workflows/windows.yaml b/.github/workflows/windows.yaml index 3ebf158b..c43cfe4b 100644 --- a/.github/workflows/windows.yaml +++ b/.github/workflows/windows.yaml @@ -44,6 +44,7 @@ jobs: bundle install cd SampleProjects/TestSomething bundle install + bundle exec arduino_ci.rb --help bundle exec arduino_ci.rb NetworkLib: From abf4cc2a9be871b99aa032c0a9424a5c7dc5a9f8 Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Wed, 28 Dec 2022 08:31:01 -0500 Subject: [PATCH 02/19] fix crash when generating test runner help text --- CHANGELOG.md | 1 + exe/arduino_ci.rb | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4f710a0..c61b8c7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Removed ### Fixed +- `arduino_ci.rb --help` no longer crashes - Fix missing `LED_BUILTIN` definition for Arduino Due, Zero and Circuit Playground. diff --git a/exe/arduino_ci.rb b/exe/arduino_ci.rb index c73522dd..e02dc412 100755 --- a/exe/arduino_ci.rb +++ b/exe/arduino_ci.rb @@ -69,7 +69,6 @@ def self.parse(options) puts " - #{VAR_USE_SUBDIR} - if set, the script will install the library from this subdirectory of the cwd" puts " - #{VAR_EXPECT_EXAMPLES} - if set, testing will fail if no example sketches are present" puts " - #{VAR_EXPECT_UNITTESTS} - if set, testing will fail if no unit tests are present" - puts " - #{VAR_SKIP_LIBPROPS} - if set, testing will skip [experimental] library.properties validation" exit end end From 3e13017ac2dc5b9b5dfa765867ca001779c44f93 Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Wed, 28 Dec 2022 08:37:20 -0500 Subject: [PATCH 03/19] document --min-free-space option --- REFERENCE.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/REFERENCE.md b/REFERENCE.md index 1253e914..7767251e 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -44,6 +44,11 @@ This allows a file (or glob) pattern to be executed in your tests directory, cre 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. +### `--min-free-space` option + +This specifies the minimum free SRAM memory for stack/heap, in bytes, that _must_ be leftover after compilation. This value applies globally -- to _all_ platforms that will be included in a test run. + + ### `CUSTOM_INIT_SCRIPT` environment variable If set, testing will execute (using `/bin/sh`) the script referred to by this variable -- relative to the current working directory (i.e. the root directory of the library). The script will _run_ in the Arduino Libraries directory (changing to the Libraries directory, running the script, and returning to the individual library root afterward). This enables use cases like the GitHub action to install custom library versions (i.e. a version of a library that is different than what the library manager would automatically install by name) prior to CI test runs. From 6f326f8070e619802ff6efe07bc3340313806d1f Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Sat, 31 Dec 2022 10:18:46 -0500 Subject: [PATCH 04/19] Add comment about verification of LED_BUILTIN --- cpp/arduino/ArduinoDefines.h | 1 + 1 file changed, 1 insertion(+) diff --git a/cpp/arduino/ArduinoDefines.h b/cpp/arduino/ArduinoDefines.h index ef80d546..3f4de7ad 100644 --- a/cpp/arduino/ArduinoDefines.h +++ b/cpp/arduino/ArduinoDefines.h @@ -90,6 +90,7 @@ #define TIMER5C 18 #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__SAM3X8E__) || defined(__SAMD21G18A__) + // Verified on these platforms, see https://github.com/Arduino-CI/arduino_ci/pull/341#issuecomment-1368118880 #define LED_BUILTIN 13 #endif From 6cf52170603cd02e63bdd4ccd6ee6a71ff0c0091 Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Sat, 31 Dec 2022 10:50:17 -0500 Subject: [PATCH 05/19] Add defines to indicate ARDUINO_CI builds --- CHANGELOG.md | 1 + cpp/arduino/Arduino.h | 5 +++++ cpp/arduino/Godmode.h | 3 +++ 3 files changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c61b8c7b..ac23afda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Added +- C++ definitions of `ARDUINO_CI_COMPILATION_MOCKS` and `ARDUINO_CI_GODMODE` to aid in compilation macros ### Changed diff --git a/cpp/arduino/Arduino.h b/cpp/arduino/Arduino.h index b301ec21..4b433e2b 100644 --- a/cpp/arduino/Arduino.h +++ b/cpp/arduino/Arduino.h @@ -5,6 +5,11 @@ Mock Arduino.h library. Where possible, variable names from the Arduino library are used to avoid conflicts */ + +// signal to the developer that we are in an arduino_ci mocked environment +#define ARDUINO_CI_COMPILATION_MOCKS + + // Chars and strings #include "ArduinoDefines.h" diff --git a/cpp/arduino/Godmode.h b/cpp/arduino/Godmode.h index ee332025..cac197d5 100644 --- a/cpp/arduino/Godmode.h +++ b/cpp/arduino/Godmode.h @@ -6,6 +6,9 @@ #include "WString.h" #include "PinHistory.h" +// signal to the developer that we are in an arduino_ci mocked environment +#define ARDUINO_CI_GODMODE + // random void randomSeed(unsigned long seed); long random(long vmax); From 5e632415900cd2491774fd73c70282f7c306f901 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20L=C3=B8vdal?= Date: Mon, 26 Dec 2022 12:12:24 +0100 Subject: [PATCH 06/19] Fixed typo --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac23afda..27518720 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,7 +32,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Support for `dtostrf()` - Added a CI workflow to lint the code base - Added a CI workflow to check for spelling errors -- Extraction of byes usage in a compiled sketch is now calculated in a method: `ArduinoBackend.last_bytes_usage` +- Extraction of bytes usage in a compiled sketch is now calculated in a method: `ArduinoBackend.last_bytes_usage` - Added ```nano_every``` platform to represent ```arduino:megaavr``` architecture - Working directory is now printed in test runner output - Explicitly include `irb` via rubygems From f4dc005e3aa8c1812049b10920c1506eb9d8441c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20L=C3=B8vdal?= Date: Sun, 25 Dec 2022 23:59:07 +0100 Subject: [PATCH 07/19] Add function to merge results from multiple run_and_capture invocations --- lib/arduino_ci/host.rb | 10 ++++++++++ spec/host_spec.rb | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/lib/arduino_ci/host.rb b/lib/arduino_ci/host.rb index 4cd5e243..3650e0c1 100644 --- a/lib/arduino_ci/host.rb +++ b/lib/arduino_ci/host.rb @@ -35,6 +35,16 @@ def self.run_and_capture(*args, **kwargs) { out: stdout, err: stderr, success: status.exitstatus.zero? } end + def self.merge_capture_results(args) + result = { out: "", err: "", success: true } + args.each do |a| + result[:out] = result[:out] + a[:out] + result[:err] = result[:err] + a[:err] + result[:success] = a[:success] unless a[:success] + end + result + end + def self.run_and_output(*args, **kwargs) system(*args, **kwargs) end diff --git a/spec/host_spec.rb b/spec/host_spec.rb index b1883461..9d4f037c 100644 --- a/spec/host_spec.rb +++ b/spec/host_spec.rb @@ -71,4 +71,23 @@ def with_tmpdir(path) end end + context "merge_capture_results" do + it "merges results" do + a1 = { out: "one", err: "ONE", success: true } + a2 = { out: "two", err: "TWO", success: false } + a3 = { out: "three", err: "THREE", success: true } + res = ArduinoCI::Host.merge_capture_results([a1, a2, a3]) + expect(res[:out]).to eq("onetwothree") + expect(res[:err]).to eq("ONETWOTHREE") + expect(res[:success]).to eq(false) + end + + it "handles empty input" do + res = ArduinoCI::Host.merge_capture_results([]) + expect(res[:out]).to eq("") + expect(res[:err]).to eq("") + expect(res[:success]).to eq(true) + end + end + end From b712b509690a1d12f15297b671b4c126f65ef841 Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Sat, 31 Dec 2022 11:32:20 -0500 Subject: [PATCH 08/19] Clean up contributed merge_capture_results: idiomatic ruby --- lib/arduino_ci/host.rb | 26 ++++++++++++++++++-------- spec/host_spec.rb | 4 ++-- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/lib/arduino_ci/host.rb b/lib/arduino_ci/host.rb index 3650e0c1..1bf9b314 100644 --- a/lib/arduino_ci/host.rb +++ b/lib/arduino_ci/host.rb @@ -30,21 +30,31 @@ def self.which(cmd) nil end + # Execute a shell command and capture stdout, stderr, and status + # + # @see Process.spawn + # @see https://docs.ruby-lang.org/en/2.0.0/Process.html#method-c-spawn + # @return [Hash] with keys "stdout" (String), "stderr" (String), and "success" (bool) def self.run_and_capture(*args, **kwargs) stdout, stderr, status = Open3.capture3(*args, **kwargs) { out: stdout, err: stderr, success: status.exitstatus.zero? } end - def self.merge_capture_results(args) - result = { out: "", err: "", success: true } - args.each do |a| - result[:out] = result[:out] + a[:out] - result[:err] = result[:err] + a[:err] - result[:success] = a[:success] unless a[:success] - end - result + # Merge multiple capture results into one aggregate value + # + # @param args [Array] Array of hashes from `run_and_capture` + # @return [Hash] with keys "stdout" (String), "stderr" (String), and "success" (bool) + def self.merge_capture_results(*args) + { + out: args.map { |a| a[:out] }.join, + err: args.map { |a| a[:err] }.join, + success: args.all? { |a| a[:success] } + } end + # Execute a shell command + # + # @see system def self.run_and_output(*args, **kwargs) system(*args, **kwargs) end diff --git a/spec/host_spec.rb b/spec/host_spec.rb index 9d4f037c..5d94b93e 100644 --- a/spec/host_spec.rb +++ b/spec/host_spec.rb @@ -76,14 +76,14 @@ def with_tmpdir(path) a1 = { out: "one", err: "ONE", success: true } a2 = { out: "two", err: "TWO", success: false } a3 = { out: "three", err: "THREE", success: true } - res = ArduinoCI::Host.merge_capture_results([a1, a2, a3]) + res = ArduinoCI::Host.merge_capture_results(a1, a2, a3) expect(res[:out]).to eq("onetwothree") expect(res[:err]).to eq("ONETWOTHREE") expect(res[:success]).to eq(false) end it "handles empty input" do - res = ArduinoCI::Host.merge_capture_results([]) + res = ArduinoCI::Host.merge_capture_results() expect(res[:out]).to eq("") expect(res[:err]).to eq("") expect(res[:success]).to eq(true) From dc1f822fb45837dd230eae564b18ce6fee4990a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20L=C3=B8vdal?= Date: Mon, 26 Dec 2022 00:03:29 +0100 Subject: [PATCH 09/19] Run "core update-index" before "core install" Running $HOME/arduino-cli --format json core install adafruit:avr --additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json for the first time fails with error message Error initializing instance: Loading index file: loading json index file $HOME/.arduino15/package_adafruit_index.json: open $HOME/.arduino15/package_adafruit_index.json: no such file or directory Error initializing instance: Loading index file: loading json index file $HOME/.arduino15/package_adafruit_index.json: open $HOME/.arduino15/package_adafruit_index.json: no such file or directory Invalid argument passed: Found 0 platform for reference "adafruit:avr": However by running an update-index command first, then it succeeds, e.g. $HOME/arduino-cli --format json core update-index --additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json $HOME/arduino-cli --format json core install adafruit:avr --additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json https://arduino.github.io/arduino-cli/0.29/getting-started/#adding-3rd-party-cores --- lib/arduino_ci/arduino_backend.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/arduino_ci/arduino_backend.rb b/lib/arduino_ci/arduino_backend.rb index 96fca45b..a0449204 100644 --- a/lib/arduino_ci/arduino_backend.rb +++ b/lib/arduino_ci/arduino_backend.rb @@ -182,7 +182,10 @@ def install_boards(boardfamily) result = if @additional_urls.empty? run_and_capture("core", "install", boardfamily) else - run_and_capture("core", "install", boardfamily, "--additional-urls", @additional_urls.join(",")) + urls = @additional_urls.join(",") + res1 = run_and_capture("core", "update-index", "--additional-urls", urls) + res2 = run_and_capture("core", "install", boardfamily, "--additional-urls", urls) + Host.merge_capture_results([res1, res2]) end result[:success] end From 5e542a6f03f11b592a63a8da46d3acc225bfff81 Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Sat, 31 Dec 2022 12:01:28 -0500 Subject: [PATCH 10/19] Run library installation tasks independently --- lib/arduino_ci/arduino_backend.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/arduino_ci/arduino_backend.rb b/lib/arduino_ci/arduino_backend.rb index a0449204..98d190e9 100644 --- a/lib/arduino_ci/arduino_backend.rb +++ b/lib/arduino_ci/arduino_backend.rb @@ -183,9 +183,9 @@ def install_boards(boardfamily) run_and_capture("core", "install", boardfamily) else urls = @additional_urls.join(",") - res1 = run_and_capture("core", "update-index", "--additional-urls", urls) - res2 = run_and_capture("core", "install", boardfamily, "--additional-urls", urls) - Host.merge_capture_results([res1, res2]) + # update the index, then install. if the update step fails, return that result + updater = run_and_capture("core", "update-index", "--additional-urls", urls) + updater[:success] ? run_and_capture("core", "install", boardfamily, "--additional-urls", urls) : updater end result[:success] end From 0f47a7ea20d243d98ead573d512bae8860d3cc00 Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Sat, 31 Dec 2022 12:17:49 -0500 Subject: [PATCH 11/19] Update documentation on running 'bundle install' locally --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 70a0e04f..cb05e63b 100644 --- a/README.md +++ b/README.md @@ -118,11 +118,11 @@ gem 'arduino_ci', path: '/path/to/development/dir/for/arduino_ci' ### Installing the Dependencies -Fulfilling the `arduino_ci` library dependency is as easy as running either of these two commands: +Fulfilling the `arduino_ci` library dependency is as easy as running one or both of these commands: ```console -$ bundle install # adds packages to global library (may require admin rights) -$ bundle install --path vendor/bundle # adds packages to local library +$ bundle config set --local path 'vendor/bundle' # if you lack administrative privileges to install globally +$ bundle install ``` This will create a `Gemfile.lock` in your project directory, which you may optionally check into source control. A broader introduction to ruby dependencies is outside the scope of this document. From e53358dc13050e9431489700f6b47ad675871d40 Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Sat, 31 Dec 2022 13:01:16 -0500 Subject: [PATCH 12/19] Convert ci_config to use pathname --- CHANGELOG.md | 1 + lib/arduino_ci/ci_config.rb | 11 ++++++----- spec/ci_config_spec.rb | 8 ++++---- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27518720..60afc14b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - C++ definitions of `ARDUINO_CI_COMPILATION_MOCKS` and `ARDUINO_CI_GODMODE` to aid in compilation macros ### Changed +- `CIConfig` now uses `Pathname` instead of strings ### Deprecated diff --git a/lib/arduino_ci/ci_config.rb b/lib/arduino_ci/ci_config.rb index 623100a0..5be1cdab 100644 --- a/lib/arduino_ci/ci_config.rb +++ b/lib/arduino_ci/ci_config.rb @@ -1,4 +1,5 @@ require 'yaml' +require 'pathname' # base config (platforms) # project config - .arduino_ci_platforms.yml @@ -58,7 +59,7 @@ class << self def default ret = new ret.instance_variable_set("@is_default", true) - ret.load_yaml(File.expand_path("../../misc/default.yml", __dir__)) + ret.load_yaml((Pathname.new(__dir__) + "../../misc/default.yml").realpath) ret end end @@ -205,8 +206,8 @@ def with_override_config(config_hash) # @return [ArduinoCI::CIConfig] def with_config(base_dir, val_when_no_match) CONFIG_FILENAMES.each do |f| - path = base_dir.nil? ? f : File.join(base_dir, f) - return (yield path) if File.exist?(path) + path = base_dir.nil? ? Pathname.new(f) : base_dir + f + return (yield path) if path.exist? end val_when_no_match end @@ -219,10 +220,10 @@ def from_project_library # Produce a configuration override taken from an Arduino library example path # handle either path to example file or example dir - # @param path [String] the path to the settings yaml file + # @param path [Pathname] the path to the settings yaml file # @return [ArduinoCI::CIConfig] the new settings object def from_example(example_path) - base_dir = File.directory?(example_path) ? example_path : File.dirname(example_path) + base_dir = example_path.directory? ? example_path : example_path.dirname with_config(base_dir, self) { |path| with_override(path) } end diff --git a/spec/ci_config_spec.rb b/spec/ci_config_spec.rb index c838a6e1..84b99213 100644 --- a/spec/ci_config_spec.rb +++ b/spec/ci_config_spec.rb @@ -43,7 +43,7 @@ context "hash" do it "converts to hash" do base = ArduinoCI::CIConfig.new - base.load_yaml(File.join(File.dirname(__FILE__), "yaml", "o2.yaml")) + base.load_yaml(Pathname.new(__dir__) + "yaml" + "o2.yaml") expect(base.to_h).to eq( packages: {}, @@ -82,7 +82,7 @@ context "with_override" do it "loads from yaml" do - override_file = File.join(File.dirname(__FILE__), "yaml", "o1.yaml") + override_file = Pathname.new(__dir__) + "yaml" + "o1.yaml" base = ArduinoCI::CIConfig.default expect(base.is_default).to be true combined_config = base.with_override(override_file) @@ -123,7 +123,7 @@ context "with_config" do it "loads from yaml" do - override_dir = File.join(File.dirname(__FILE__), "yaml", "override1") + override_dir = Pathname.new(__dir__) + "yaml" + "override1" base_config = ArduinoCI::CIConfig.default combined_config = base_config.from_example(override_dir) @@ -188,7 +188,7 @@ "mars.cpp" ]) - override_file = File.join(File.dirname(__FILE__), "yaml", "o1.yaml") + override_file = Pathname.new(__dir__) + "yaml" + "o1.yaml" combined_config = ArduinoCI::CIConfig.default.with_override(override_file) expect(combined_config.unittest_info[:testfiles][:select]).to match_array(["*-*.*"]) expect(combined_config.unittest_info[:testfiles][:reject]).to match_array(["sam-squamsh.*"]) From 0001550ee43083392a3d4d01ba326feb85a23003 Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Sat, 31 Dec 2022 13:51:45 -0500 Subject: [PATCH 13/19] Expose more information about config overrides --- CHANGELOG.md | 3 +++ lib/arduino_ci/ci_config.rb | 42 +++++++++++++++++++++++-------------- spec/ci_config_spec.rb | 6 +++++- 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60afc14b..3991a9bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Added - C++ definitions of `ARDUINO_CI_COMPILATION_MOCKS` and `ARDUINO_CI_GODMODE` to aid in compilation macros +- `CIConfig.available_override_config_path()` to search for available override files in standard locations +- `CIConfig.override_file_from_project_library` and `CIConfig.override_file_from_example` to expose config locations ### Changed - `CIConfig` now uses `Pathname` instead of strings @@ -15,6 +17,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Deprecated ### Removed +- `CIConfig.with_config`, which was only used internally ### Fixed - `arduino_ci.rb --help` no longer crashes diff --git a/lib/arduino_ci/ci_config.rb b/lib/arduino_ci/ci_config.rb index 5be1cdab..fa69b192 100644 --- a/lib/arduino_ci/ci_config.rb +++ b/lib/arduino_ci/ci_config.rb @@ -196,26 +196,36 @@ def with_override_config(config_hash) overridden_config end - # Get the config file at a given path, if it exists, and pass that to a block. - # Many config files may exist, but only the first match is used + # Get available configuration file, if one exists # @param base_dir [String] The directory in which to search for a config file - # @param val_when_no_match [Object] The value to return if no config files are found - # @yield [path] Process the configuration file at the given path - # @yieldparam [String] The path of an existing config file - # @yieldreturn [ArduinoCI::CIConfig] a settings object - # @return [ArduinoCI::CIConfig] - def with_config(base_dir, val_when_no_match) - CONFIG_FILENAMES.each do |f| - path = base_dir.nil? ? Pathname.new(f) : base_dir + f - return (yield path) if path.exist? - end - val_when_no_match + # @return [Pathname] the first available config file we could find, or nil + def available_override_config_path(base_dir = nil) + CONFIG_FILENAMES.map { |f| base_dir.nil? ? Pathname.new(f) : base_dir + f }.find(&:exist?) + end + + # Find an available override file from the project directory + # + # @todo this is currently reliant on launching the arduino_ci.rb test runner from + # the correct working directory + # @return [Pathname] A file that can override project config, or nil if none was found + def override_file_from_project_library + available_override_config_path(nil) + end + + # Find an available override file from an example sketch + # + # @param path [Pathname] the path to the example or example directory + # @return [Pathname] A file that can override project config, or nil if none was found + def override_file_from_example(example_path) + base_dir = example_path.directory? ? example_path : example_path.dirname + available_override_config_path(base_dir) end # Produce a configuration, assuming the CI script runs from the working directory of the base project # @return [ArduinoCI::CIConfig] the new settings object def from_project_library - with_config(nil, self) { |path| with_override(path) } + ovr = override_file_from_project_library + ovr.nil? ? self : with_override(ovr) end # Produce a configuration override taken from an Arduino library example path @@ -223,8 +233,8 @@ def from_project_library # @param path [Pathname] the path to the settings yaml file # @return [ArduinoCI::CIConfig] the new settings object def from_example(example_path) - base_dir = example_path.directory? ? example_path : example_path.dirname - with_config(base_dir, self) { |path| with_override(path) } + ovr = override_file_from_example(example_path) + ovr.nil? ? self : with_override(ovr) end # get information about a given platform: board name, package name, compiler stuff, etc diff --git a/spec/ci_config_spec.rb b/spec/ci_config_spec.rb index 84b99213..7b00c692 100644 --- a/spec/ci_config_spec.rb +++ b/spec/ci_config_spec.rb @@ -121,10 +121,14 @@ end end - context "with_config" do + context "with overrides from files" do it "loads from yaml" do override_dir = Pathname.new(__dir__) + "yaml" + "override1" base_config = ArduinoCI::CIConfig.default + found_override_file = base_config.override_file_from_example(override_dir) + expect(found_override_file).to_not be(nil) + expect(found_override_file).to be_a(Pathname) + expect(found_override_file).to exist combined_config = base_config.from_example(override_dir) expect(combined_config).not_to be nil From ae8bf89fbdd5693e5a9b16864d68b4ea7bd8fcfd Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Sat, 31 Dec 2022 14:00:59 -0500 Subject: [PATCH 14/19] Explicitly report config overrides and their paths --- CHANGELOG.md | 1 + exe/arduino_ci.rb | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3991a9bd..7e1ec44a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - C++ definitions of `ARDUINO_CI_COMPILATION_MOCKS` and `ARDUINO_CI_GODMODE` to aid in compilation macros - `CIConfig.available_override_config_path()` to search for available override files in standard locations - `CIConfig.override_file_from_project_library` and `CIConfig.override_file_from_example` to expose config locations +- CI runner script now expliclty informs about config overrides ### Changed - `CIConfig` now uses `Pathname` instead of strings diff --git a/exe/arduino_ci.rb b/exe/arduino_ci.rb index e02dc412..fb1b5994 100755 --- a/exe/arduino_ci.rb +++ b/exe/arduino_ci.rb @@ -193,6 +193,13 @@ def assured_platform(purpose, name, config) platform_definition end +def inform_override(from_where, &block) + inform("Using configuration override from #{from_where}") do + file = block.call + file.nil? ? "" : file + end +end + # Return true if the file (or one of the dirs containing it) is hidden def file_is_hidden_somewhere?(path) # this is clunkly but pre-2.2-ish ruby doesn't return ascend as an enumerator @@ -493,7 +500,9 @@ def perform_example_compilation_tests(cpp_library, config) puts inform("Discovered example sketch") { example_name } - ovr_config = config.from_example(example_path) + inform_override("example") { ex_config.override_file_from_example(example_path) } + ovr_config = ex_config.from_example(example_path) + platforms = choose_platform_set(ovr_config, "library example", ovr_config.platforms_to_build, cpp_library.library_properties) # having no platforms defined is probably an error @@ -541,7 +550,10 @@ def perform_example_compilation_tests(cpp_library, config) inform("Working directory") { Dir.pwd } # initialize command and config -config = ArduinoCI::CIConfig.default.from_project_library +default_config = ArduinoCI::CIConfig.default +inform_override("project") { default_config.override_file_from_project_library } +config = default_config.from_project_library + @backend = ArduinoCI::ArduinoInstallation.autolocate! inform("Located arduino-cli binary") { @backend.binary_path.to_s } if @backend.lib_dir.exist? From 047ee723d9b394d2fb37503a24448513681d7d6d Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Sat, 31 Dec 2022 14:34:29 -0500 Subject: [PATCH 15/19] Allow configuration overrides in examples directory --- CHANGELOG.md | 1 + SampleProjects/TestSomething/examples/.arduino-ci.yml | 4 ++++ .../examples/TestSomethingExample/.arduino-ci.yml | 4 ++++ exe/arduino_ci.rb | 3 +++ 4 files changed, 12 insertions(+) create mode 100644 SampleProjects/TestSomething/examples/.arduino-ci.yml create mode 100644 SampleProjects/TestSomething/examples/TestSomethingExample/.arduino-ci.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e1ec44a..be284aec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - `CIConfig.available_override_config_path()` to search for available override files in standard locations - `CIConfig.override_file_from_project_library` and `CIConfig.override_file_from_example` to expose config locations - CI runner script now expliclty informs about config overrides +- A project `examples/` directory can now provide its own configuration override file, which provides no new flexibility but simply mirrors the behavior for `tests/`. ### Changed - `CIConfig` now uses `Pathname` instead of strings diff --git a/SampleProjects/TestSomething/examples/.arduino-ci.yml b/SampleProjects/TestSomething/examples/.arduino-ci.yml new file mode 100644 index 00000000..5f233439 --- /dev/null +++ b/SampleProjects/TestSomething/examples/.arduino-ci.yml @@ -0,0 +1,4 @@ +compile: + platforms: + - uno + - due diff --git a/SampleProjects/TestSomething/examples/TestSomethingExample/.arduino-ci.yml b/SampleProjects/TestSomething/examples/TestSomethingExample/.arduino-ci.yml new file mode 100644 index 00000000..5f233439 --- /dev/null +++ b/SampleProjects/TestSomething/examples/TestSomethingExample/.arduino-ci.yml @@ -0,0 +1,4 @@ +compile: + platforms: + - uno + - due diff --git a/exe/arduino_ci.rb b/exe/arduino_ci.rb index fb1b5994..f00235f9 100755 --- a/exe/arduino_ci.rb +++ b/exe/arduino_ci.rb @@ -495,6 +495,9 @@ def perform_example_compilation_tests(cpp_library, config) return end + inform_override("examples") { config.override_file_from_example(cpp_library.examples_dir) } + ex_config = config.from_example(cpp_library.examples_dir) + library_examples.each do |example_path| example_name = File.basename(example_path) puts From 75250806425946c18963e07e468b2775fbe0f28f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20L=C3=B8vdal?= Date: Thu, 3 Feb 2022 19:26:51 +0100 Subject: [PATCH 16/19] Increment @failure_count if build_shared_library fails --- CHANGELOG.md | 2 ++ exe/arduino_ci.rb | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be284aec..0c51eafc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - `arduino_ci.rb --help` no longer crashes - Fix missing `LED_BUILTIN` definition for Arduino Due, Zero and Circuit Playground. +- No longer ignore failures if the first step of compiling files for the + unit test fails. ### Security diff --git a/exe/arduino_ci.rb b/exe/arduino_ci.rb index f00235f9..d54066f3 100755 --- a/exe/arduino_ci.rb +++ b/exe/arduino_ci.rb @@ -442,7 +442,9 @@ def perform_unit_tests(cpp_library, file_config) puts compilers.each do |gcc_binary| # before compiling the tests, build a shared library of everything except the test code - next unless build_shared_library(gcc_binary, p, config, cpp_library) + build_result = build_shared_library(gcc_binary, p, config, cpp_library) + @failure_count += 1 unless build_result + next unless build_result # now build and run each test using the shared library build above config.allowable_unittest_files(cpp_library.test_files).each do |unittest_path| From 59ad7dcdeb11c7131780ec03a0f901d03a36c541 Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Sat, 31 Dec 2022 14:47:08 -0500 Subject: [PATCH 17/19] Style cleanup --- CHANGELOG.md | 3 +-- exe/arduino_ci.rb | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c51eafc..b10b9822 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,8 +25,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - `arduino_ci.rb --help` no longer crashes - Fix missing `LED_BUILTIN` definition for Arduino Due, Zero and Circuit Playground. -- No longer ignore failures if the first step of compiling files for the - unit test fails. +- No longer ignore failures if the first step of compiling files for the unit test fails. ### Security diff --git a/exe/arduino_ci.rb b/exe/arduino_ci.rb index d54066f3..25430c53 100755 --- a/exe/arduino_ci.rb +++ b/exe/arduino_ci.rb @@ -442,9 +442,7 @@ def perform_unit_tests(cpp_library, file_config) puts compilers.each do |gcc_binary| # before compiling the tests, build a shared library of everything except the test code - build_result = build_shared_library(gcc_binary, p, config, cpp_library) - @failure_count += 1 unless build_result - next unless build_result + next @failure_count += 1 unless build_shared_library(gcc_binary, p, config, cpp_library) # now build and run each test using the shared library build above config.allowable_unittest_files(cpp_library.test_files).each do |unittest_path| From 4aad21064811d43a7ba837dee50d7a5fdf33241b Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Sun, 1 Jan 2023 22:22:05 -0500 Subject: [PATCH 18/19] Upgrade checkout action to avoid deprecation warning --- .github/workflows/linter.yaml | 2 +- .github/workflows/linux.yaml | 10 +++++----- .github/workflows/macos.yaml | 10 +++++----- .github/workflows/spelling.yaml | 2 +- .github/workflows/windows.yaml | 10 +++++----- README.md | 2 +- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/linter.yaml b/.github/workflows/linter.yaml index 78bb3234..002829ed 100644 --- a/.github/workflows/linter.yaml +++ b/.github/workflows/linter.yaml @@ -15,7 +15,7 @@ jobs: steps: - name: Checkout Code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: # Full git history is needed to get a proper list of changed files within `super-linter` fetch-depth: 0 diff --git a/.github/workflows/linux.yaml b/.github/workflows/linux.yaml index 5a0ce875..d3a35a75 100644 --- a/.github/workflows/linux.yaml +++ b/.github/workflows/linux.yaml @@ -7,7 +7,7 @@ jobs: "rubocop": runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 with: ruby-version: 2.6 @@ -21,7 +21,7 @@ jobs: "rspec-linux": runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 with: ruby-version: 2.6 @@ -34,7 +34,7 @@ jobs: "TestSomething": runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 with: ruby-version: 2.6 @@ -50,7 +50,7 @@ jobs: NetworkLib: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 with: ruby-version: 2.6 @@ -66,7 +66,7 @@ jobs: SharedLibrary: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 with: ruby-version: 2.6 diff --git a/.github/workflows/macos.yaml b/.github/workflows/macos.yaml index 4bb63563..857f547b 100644 --- a/.github/workflows/macos.yaml +++ b/.github/workflows/macos.yaml @@ -7,7 +7,7 @@ jobs: "rubocop": runs-on: macos-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 with: ruby-version: 2.6 @@ -21,7 +21,7 @@ jobs: "rspec-macos": runs-on: macos-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 with: ruby-version: 2.6 @@ -34,7 +34,7 @@ jobs: "TestSomething": runs-on: macos-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 with: ruby-version: 2.6 @@ -50,7 +50,7 @@ jobs: NetworkLib: runs-on: macos-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 with: ruby-version: 2.6 @@ -66,7 +66,7 @@ jobs: SharedLibrary: runs-on: macos-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 with: ruby-version: 2.6 diff --git a/.github/workflows/spelling.yaml b/.github/workflows/spelling.yaml index 3450600c..7beff1e1 100644 --- a/.github/workflows/spelling.yaml +++ b/.github/workflows/spelling.yaml @@ -15,7 +15,7 @@ jobs: steps: - name: Checkout Code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: # Full git history is needed to get a proper list of changed files within `super-linter` fetch-depth: 0 diff --git a/.github/workflows/windows.yaml b/.github/workflows/windows.yaml index c43cfe4b..a67dbda0 100644 --- a/.github/workflows/windows.yaml +++ b/.github/workflows/windows.yaml @@ -7,7 +7,7 @@ jobs: "rubocop": runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 with: ruby-version: 2.6 @@ -21,7 +21,7 @@ jobs: "rspec-windows": runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 with: ruby-version: 2.6 @@ -34,7 +34,7 @@ jobs: TestSomething: runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 with: ruby-version: 2.6 @@ -50,7 +50,7 @@ jobs: NetworkLib: runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 with: ruby-version: 2.6 @@ -66,7 +66,7 @@ jobs: SharedLibrary: runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 with: ruby-version: 2.6 diff --git a/README.md b/README.md index cb05e63b..cafd0f22 100644 --- a/README.md +++ b/README.md @@ -169,7 +169,7 @@ jobs: runTest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 with: ruby-version: 2.6 From 890425546478a0b99faf26d482e69cd28535eef9 Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Tue, 17 Jan 2023 10:48:32 -0500 Subject: [PATCH 19/19] Report backend version in CI runner script --- exe/arduino_ci.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/exe/arduino_ci.rb b/exe/arduino_ci.rb index 25430c53..72d455ed 100755 --- a/exe/arduino_ci.rb +++ b/exe/arduino_ci.rb @@ -559,6 +559,7 @@ def perform_example_compilation_tests(cpp_library, config) @backend = ArduinoCI::ArduinoInstallation.autolocate! inform("Located arduino-cli binary") { @backend.binary_path.to_s } +inform("Using arduino-cli version") { @backend.version.to_s } if @backend.lib_dir.exist? inform("Found libraries directory") { @backend.lib_dir } else