mirror of
https://github.com/platformio/platformio-core.git
synced 2025-07-29 17:47:14 +02:00
Added a new --lint option to the pio project config command // Resolve #4644
This commit is contained in:
@ -18,6 +18,7 @@ PlatformIO Core 6
|
||||
6.1.8 (2023-??-??)
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Added a new ``--lint`` option to the `pio project config <https://docs.platformio.org/en/latest/core/userguide/project/cmd_config.html>`__ command, enabling users to efficiently perform linting on the |PIOCONF|
|
||||
* Enhanced the parsing of the |PIOCONF| to provide comprehensive diagnostic information
|
||||
* Optimized project integration templates to address the issue of long paths on Windows (`issue #4652 <https://github.com/platformio/platformio-core/issues/4652>`_)
|
||||
* Refactored |UNITTESTING| engine to resolve compiler warnings with "-Wpedantic" option (`pull #4671 <https://github.com/platformio/platformio-core/pull/4671>`_)
|
||||
|
@ -30,16 +30,23 @@ from platformio.project.helpers import is_platformio_project
|
||||
default=os.getcwd,
|
||||
type=click.Path(exists=True, file_okay=False, dir_okay=True),
|
||||
)
|
||||
@click.option("--lint", is_flag=True)
|
||||
@click.option("--json-output", is_flag=True)
|
||||
def project_config_cmd(project_dir, json_output):
|
||||
def project_config_cmd(project_dir, lint, json_output):
|
||||
if not is_platformio_project(project_dir):
|
||||
raise NotPlatformIOProjectError(project_dir)
|
||||
with fs.cd(project_dir):
|
||||
config = ProjectConfig.get_instance()
|
||||
if lint:
|
||||
return lint_configuration(json_output)
|
||||
return print_configuration(json_output)
|
||||
|
||||
|
||||
def print_configuration(json_output=False):
|
||||
config = ProjectConfig.get_instance()
|
||||
if json_output:
|
||||
return click.echo(config.to_json())
|
||||
click.echo(
|
||||
"Computed project configuration for %s" % click.style(project_dir, fg="cyan")
|
||||
"Computed project configuration for %s" % click.style(os.getcwd(), fg="cyan")
|
||||
)
|
||||
for section, options in config.as_tuple():
|
||||
click.secho(section, fg="cyan")
|
||||
@ -55,3 +62,43 @@ def project_config_cmd(project_dir, json_output):
|
||||
)
|
||||
click.echo()
|
||||
return None
|
||||
|
||||
|
||||
def lint_configuration(json_output=False):
|
||||
result = ProjectConfig.lint()
|
||||
errors = result["errors"]
|
||||
warnings = result["warnings"]
|
||||
if json_output:
|
||||
return click.echo(result)
|
||||
if not errors and not warnings:
|
||||
return click.secho(
|
||||
'The "platformio.ini" configuration file is free from linting errors.',
|
||||
fg="green",
|
||||
)
|
||||
if errors:
|
||||
click.echo(
|
||||
tabulate(
|
||||
[
|
||||
(
|
||||
click.style(error["type"], fg="red"),
|
||||
error["message"],
|
||||
error.get("source", "") + (f":{error.get('lineno')}")
|
||||
if "lineno" in error
|
||||
else "",
|
||||
)
|
||||
for error in errors
|
||||
],
|
||||
tablefmt="plain",
|
||||
)
|
||||
)
|
||||
if warnings:
|
||||
click.echo(
|
||||
tabulate(
|
||||
[
|
||||
(click.style("Warning", fg="yellow"), warning)
|
||||
for warning in warnings
|
||||
],
|
||||
tablefmt="plain",
|
||||
)
|
||||
)
|
||||
return None
|
||||
|
@ -433,7 +433,41 @@ class ProjectConfigDirsMixin:
|
||||
return self.get("platformio", f"{name}_dir")
|
||||
|
||||
|
||||
class ProjectConfig(ProjectConfigBase, ProjectConfigDirsMixin):
|
||||
class ProjectConfigLintMixin:
|
||||
@classmethod
|
||||
def lint(cls, path=None):
|
||||
errors = []
|
||||
warnings = []
|
||||
try:
|
||||
config = cls.get_instance(path)
|
||||
config.validate(silent=True)
|
||||
warnings = config.warnings
|
||||
config.as_tuple()
|
||||
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||
if exc.__cause__ is not None:
|
||||
exc = exc.__cause__
|
||||
|
||||
item = {"type": exc.__class__.__name__, "message": str(exc)}
|
||||
for attr in ("lineno", "source"):
|
||||
if hasattr(exc, attr):
|
||||
item[attr] = getattr(exc, attr)
|
||||
|
||||
if item["type"] == "ParsingError" and hasattr(exc, "errors"):
|
||||
for lineno, line in getattr(exc, "errors"):
|
||||
errors.append(
|
||||
{
|
||||
"type": item["type"],
|
||||
"message": f"Parsing error: {line}",
|
||||
"lineno": lineno,
|
||||
"source": item["source"],
|
||||
}
|
||||
)
|
||||
else:
|
||||
errors.append(item)
|
||||
return {"errors": errors, "warnings": warnings}
|
||||
|
||||
|
||||
class ProjectConfig(ProjectConfigBase, ProjectConfigDirsMixin, ProjectConfigLintMixin):
|
||||
_instances = {}
|
||||
|
||||
@staticmethod
|
||||
|
@ -684,3 +684,34 @@ def test_invalid_env_names(tmp_path: Path):
|
||||
config = ProjectConfig(str(project_conf))
|
||||
with pytest.raises(InvalidEnvNameError, match=r".*Invalid environment name 'app:1"):
|
||||
config.validate()
|
||||
|
||||
|
||||
def test_linting_errors(tmp_path: Path):
|
||||
project_conf = tmp_path / "platformio.ini"
|
||||
project_conf.write_text(
|
||||
"""
|
||||
[env:app1]
|
||||
lib_use = 1
|
||||
broken_line
|
||||
"""
|
||||
)
|
||||
result = ProjectConfig.lint(str(project_conf))
|
||||
assert not result["warnings"]
|
||||
assert result["errors"] and len(result["errors"]) == 1
|
||||
error = result["errors"][0]
|
||||
assert error["type"] == "ParsingError"
|
||||
assert error["lineno"] == 4
|
||||
|
||||
|
||||
def test_linting_warnings(tmp_path: Path):
|
||||
project_conf = tmp_path / "platformio.ini"
|
||||
project_conf.write_text(
|
||||
"""
|
||||
[env:app1]
|
||||
lib_use = 1
|
||||
"""
|
||||
)
|
||||
result = ProjectConfig.lint(str(project_conf))
|
||||
assert not result["errors"]
|
||||
assert result["warnings"] and len(result["warnings"]) == 1
|
||||
assert "deprecated" in result["warnings"][0]
|
||||
|
Reference in New Issue
Block a user