Skip to content

Commit

Permalink
Add command output key translation for Arduino CLI 1.0.0
Browse files Browse the repository at this point in the history
The action parses the output of the `arduino-cli core list --format json` command.

The name of one of the keys in that output data used by the action was changed in the 1.0.0 release of Arduino CLI,
breaking the action when used with that version of Arduino CLI (which is the default behavior).

The action code base already has a key name translation system, which was implemented to handle breakage caused by a
previous round of key name changes. However, that system was designed under the assumption that the key names would be
stable following the comprehensive redesign that caused the previous changes. It was not designed to handle multiple
changes to the name of a given key as has now happened. For this reason, the translation system has been redesigned to
support any number of key name changes that might occur.
  • Loading branch information
per1234 committed Jun 13, 2024
1 parent a5fd631 commit 26705b3
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 24 deletions.
50 changes: 35 additions & 15 deletions compilesketches/compilesketches.py
Original file line number Diff line number Diff line change
Expand Up @@ -560,13 +560,13 @@ def __init__(self):
command_data = self.run_arduino_cli_command(command=["core", "list", "--format", "json"])
installed_platform_list = self.cli_core_list_platform_list(json.loads(command_data.stdout))
for installed_platform in installed_platform_list:
if installed_platform[self.cli_json_key("core list", "ID")] == platform[self.dependency_name_key]:
if installed_platform[self.cli_json_key("core list", "id")] == platform[self.dependency_name_key]:
# The platform has been installed via Board Manager, so do an overwrite
platform_installation_path.path = self.board_manager_platforms_path.joinpath(
platform_vendor,
"hardware",
platform_architecture,
installed_platform[self.cli_json_key("core list", "Installed")],
installed_platform[self.cli_json_key("core list", "installed_version")],
)
platform_installation_path.is_overwrite = True

Expand Down Expand Up @@ -1457,29 +1457,49 @@ def cli_core_list_platform_list(self, data):

return data

def cli_json_key(self, command, original_key_name):
def cli_json_key(self, command, key_name):
"""Return the appropriate JSON output key name for the Arduino CLI version in use.
Keyword arguments:
command -- Arduino CLI command (e.g., "core list")
original_key_name -- key name used by the original Arduino CLI JSON interface
key_name -- key name used by the current Arduino CLI JSON interface
"""
final_original_interface_version = "0.17.0" # Interface was changed in the next Arduino CLI release

key_translation = {
key_translations = {
"core list": {
"ID": "id",
"Installed": "installed"
"id": [
{"constraints": [">=0.0.0", "<=0.17.0"], "name": "ID"},
# https://arduino.github.io/arduino-cli/dev/UPGRADING/#arduino-cli-json-output-breaking-changes
{"constraints": [">0.17.0"], "name": "id"},
],
"installed_version": [
{"constraints": [">=0.0.0", "<=0.17.0"], "name": "Installed"},
# https://arduino.github.io/arduino-cli/dev/UPGRADING/#arduino-cli-json-output-breaking-changes
{"constraints": [">0.17.0", "<1.0.0"], "name": "installed"},
# https://arduino.github.io/arduino-cli/dev/UPGRADING/#cli-core-list-and-core-search-changed-json-output
{"constraints": [">=1.0.0"], "name": "installed_version"},
],
}
}

if (
not semver.VersionInfo.is_valid(version=self.cli_version)
or semver.Version.parse(version=self.cli_version).compare(other=final_original_interface_version) > 0
) and (command in key_translation and original_key_name in key_translation[command]):
return key_translation[command][original_key_name]
if not semver.VersionInfo.is_valid(version=self.cli_version):
# cli_version is "latest", so use the current key name
return key_name

for translation in key_translations[command][key_name]:
match = True
for constraint in translation["constraints"]:
if not semver.Version.parse(version=self.cli_version).match(match_expr=constraint):
# The Arduino CLI version does not match the translation's version constraints
match = False
break

if match:
# The Arduino CLI version matches the translation's version constraints
return translation["name"]

return original_key_name
raise RuntimeError(
f"Translation not implemented for `{key_name}` key of `arduino-cli {command}` for version {self.cli_version}"
) # pragma: no cover


def parse_list_input(list_input):
Expand Down
16 changes: 7 additions & 9 deletions compilesketches/tests/test_compilesketches.py
Original file line number Diff line number Diff line change
Expand Up @@ -2899,20 +2899,18 @@ def test_cli_core_list_platform_list(cli_version, data, assertion):


@pytest.mark.parametrize(
"cli_version, command, original_key, expected_key",
"cli_version, command, key_name, expected_key",
[
("latest", "core list", "ID", "id"), # Non-semver
("1.0.0", "core list", "ID", "id"), # >
("0.17.0", "core list", "ID", "ID"), # ==
("0.14.0-rc2", "core list", "ID", "ID"), # <
("1.0.0", "foo", "ID", "ID"), # Command has no translation
("1.0.0", "core list", "foo", "foo"), # Key has no translation
("latest", "core list", "installed_version", "installed_version"), # Non-semver
("0.1.2", "core list", "installed_version", "Installed"),
("0.17.1", "core list", "installed_version", "installed"),
("1.2.3", "core list", "installed_version", "installed_version"),
],
)
def test_cli_json_key(cli_version, command, original_key, expected_key):
def test_cli_json_key(cli_version, command, key_name, expected_key):
compile_sketches = get_compilesketches_object(cli_version=cli_version)

assert compile_sketches.cli_json_key(command, original_key) == expected_key
assert compile_sketches.cli_json_key(command, key_name) == expected_key


@pytest.mark.parametrize("verbose", ["true", "false"])
Expand Down

0 comments on commit 26705b3

Please sign in to comment.