From ab68fbab4cebf2c6218ebf9515e8a56e7f1b78e7 Mon Sep 17 00:00:00 2001 From: Dennis Whitney Date: Fri, 22 Nov 2024 00:34:27 -0800 Subject: [PATCH] Added additional galaxy[tags] checks --- .../changelogs/changelog.yaml | 0 .../galaxy_tags/galaxy_count_tags/galaxy.yml | 33 +++++++++ .../galaxy_count_tags}/meta/runtime.yml | 0 .../changelogs/changelog.yaml | 0 .../galaxy_invalid_format_tags/galaxy.yml | 14 ++++ .../meta/runtime.yml | 0 .../changelogs/changelog.yaml | 2 + .../galaxy_invalid_length_tags/galaxy.yml | 15 ++++ .../meta/runtime.yml | 0 .../changelogs/changelog.yaml | 2 + .../galaxy_no_required_tags}/galaxy.yml | 1 + .../galaxy_no_required_tags/meta/runtime.yml | 0 .../pass/changelogs/changelog.yaml | 2 + .../pass/galaxy.yml | 0 examples/galaxy_tags/pass/meta/runtime.yml | 0 src/ansiblelint/constants.py | 4 + src/ansiblelint/rules/galaxy.md | 5 ++ src/ansiblelint/rules/galaxy.py | 73 ++++++++++++++++++- tox.ini | 2 +- 19 files changed, 149 insertions(+), 4 deletions(-) rename examples/{galaxy_no_required_tags/fail => galaxy_tags/galaxy_count_tags}/changelogs/changelog.yaml (100%) create mode 100644 examples/galaxy_tags/galaxy_count_tags/galaxy.yml rename examples/{galaxy_no_required_tags/fail => galaxy_tags/galaxy_count_tags}/meta/runtime.yml (100%) rename examples/{galaxy_no_required_tags/pass => galaxy_tags/galaxy_invalid_format_tags}/changelogs/changelog.yaml (100%) create mode 100644 examples/galaxy_tags/galaxy_invalid_format_tags/galaxy.yml rename examples/{galaxy_no_required_tags/pass => galaxy_tags/galaxy_invalid_format_tags}/meta/runtime.yml (100%) create mode 100644 examples/galaxy_tags/galaxy_invalid_length_tags/changelogs/changelog.yaml create mode 100644 examples/galaxy_tags/galaxy_invalid_length_tags/galaxy.yml create mode 100644 examples/galaxy_tags/galaxy_invalid_length_tags/meta/runtime.yml create mode 100644 examples/galaxy_tags/galaxy_no_required_tags/changelogs/changelog.yaml rename examples/{galaxy_no_required_tags/fail => galaxy_tags/galaxy_no_required_tags}/galaxy.yml (89%) create mode 100644 examples/galaxy_tags/galaxy_no_required_tags/meta/runtime.yml create mode 100644 examples/galaxy_tags/pass/changelogs/changelog.yaml rename examples/{galaxy_no_required_tags => galaxy_tags}/pass/galaxy.yml (100%) create mode 100644 examples/galaxy_tags/pass/meta/runtime.yml diff --git a/examples/galaxy_no_required_tags/fail/changelogs/changelog.yaml b/examples/galaxy_tags/galaxy_count_tags/changelogs/changelog.yaml similarity index 100% rename from examples/galaxy_no_required_tags/fail/changelogs/changelog.yaml rename to examples/galaxy_tags/galaxy_count_tags/changelogs/changelog.yaml diff --git a/examples/galaxy_tags/galaxy_count_tags/galaxy.yml b/examples/galaxy_tags/galaxy_count_tags/galaxy.yml new file mode 100644 index 0000000000..47635d0c1b --- /dev/null +++ b/examples/galaxy_tags/galaxy_count_tags/galaxy.yml @@ -0,0 +1,33 @@ +--- +namespace: bar +name: foo +version: "1.0.0" # <-- that version is not valid, should be 1.0.0 or greater +authors: + - John +readme: ../README.md +description: "..." +license: + - Apache-2.0 +repository: https://github.com/ansible-collections/community.REPO_NAME +tags: + - application + - tag2 + - tag3 + - tag4 + - tag5 + - tag6 + - tag7 + - tag8 + - tag9 + - tag10 + - tag11 + - tag12 + - tag13 + - tag14 + - tag15 + - tag16 + - tag17 + - tag18 + - tag19 + - tag20 + - tag21 diff --git a/examples/galaxy_no_required_tags/fail/meta/runtime.yml b/examples/galaxy_tags/galaxy_count_tags/meta/runtime.yml similarity index 100% rename from examples/galaxy_no_required_tags/fail/meta/runtime.yml rename to examples/galaxy_tags/galaxy_count_tags/meta/runtime.yml diff --git a/examples/galaxy_no_required_tags/pass/changelogs/changelog.yaml b/examples/galaxy_tags/galaxy_invalid_format_tags/changelogs/changelog.yaml similarity index 100% rename from examples/galaxy_no_required_tags/pass/changelogs/changelog.yaml rename to examples/galaxy_tags/galaxy_invalid_format_tags/changelogs/changelog.yaml diff --git a/examples/galaxy_tags/galaxy_invalid_format_tags/galaxy.yml b/examples/galaxy_tags/galaxy_invalid_format_tags/galaxy.yml new file mode 100644 index 0000000000..cf8e3fa1c8 --- /dev/null +++ b/examples/galaxy_tags/galaxy_invalid_format_tags/galaxy.yml @@ -0,0 +1,14 @@ +--- +namespace: bar +name: foo +version: "1.0.0" +authors: + - John +readme: ../README.md +description: "..." +license: + - Apache-2.0 +repository: https://github.com/ansible-collections/community.REPO_NAME +tags: + - application + - invalid-tag-format diff --git a/examples/galaxy_no_required_tags/pass/meta/runtime.yml b/examples/galaxy_tags/galaxy_invalid_format_tags/meta/runtime.yml similarity index 100% rename from examples/galaxy_no_required_tags/pass/meta/runtime.yml rename to examples/galaxy_tags/galaxy_invalid_format_tags/meta/runtime.yml diff --git a/examples/galaxy_tags/galaxy_invalid_length_tags/changelogs/changelog.yaml b/examples/galaxy_tags/galaxy_invalid_length_tags/changelogs/changelog.yaml new file mode 100644 index 0000000000..52e7f388be --- /dev/null +++ b/examples/galaxy_tags/galaxy_invalid_length_tags/changelogs/changelog.yaml @@ -0,0 +1,2 @@ +--- +releases: {} diff --git a/examples/galaxy_tags/galaxy_invalid_length_tags/galaxy.yml b/examples/galaxy_tags/galaxy_invalid_length_tags/galaxy.yml new file mode 100644 index 0000000000..ada68e304d --- /dev/null +++ b/examples/galaxy_tags/galaxy_invalid_length_tags/galaxy.yml @@ -0,0 +1,15 @@ +--- +namespace: bar +name: foo +version: "1.0.0" +authors: + - John +readme: ../README.md +description: "..." +license: + - Apache-2.0 +repository: https://github.com/ansible-collections/community.REPO_NAME +tags: + - application + - this_is_an_utterly_ridiculous_and_insanely_long_tag_length_eye_roll + - also_a_ridiculously_long_tag_but_within_the_limits diff --git a/examples/galaxy_tags/galaxy_invalid_length_tags/meta/runtime.yml b/examples/galaxy_tags/galaxy_invalid_length_tags/meta/runtime.yml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/galaxy_tags/galaxy_no_required_tags/changelogs/changelog.yaml b/examples/galaxy_tags/galaxy_no_required_tags/changelogs/changelog.yaml new file mode 100644 index 0000000000..52e7f388be --- /dev/null +++ b/examples/galaxy_tags/galaxy_no_required_tags/changelogs/changelog.yaml @@ -0,0 +1,2 @@ +--- +releases: {} diff --git a/examples/galaxy_no_required_tags/fail/galaxy.yml b/examples/galaxy_tags/galaxy_no_required_tags/galaxy.yml similarity index 89% rename from examples/galaxy_no_required_tags/fail/galaxy.yml rename to examples/galaxy_tags/galaxy_no_required_tags/galaxy.yml index 48ee5873fa..37d1a4d474 100644 --- a/examples/galaxy_no_required_tags/fail/galaxy.yml +++ b/examples/galaxy_tags/galaxy_no_required_tags/galaxy.yml @@ -9,3 +9,4 @@ description: "..." license: - Apache-2.0 repository: https://github.com/ansible-collections/community.REPO_NAME +tags: [no_required_tag_here] diff --git a/examples/galaxy_tags/galaxy_no_required_tags/meta/runtime.yml b/examples/galaxy_tags/galaxy_no_required_tags/meta/runtime.yml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/galaxy_tags/pass/changelogs/changelog.yaml b/examples/galaxy_tags/pass/changelogs/changelog.yaml new file mode 100644 index 0000000000..52e7f388be --- /dev/null +++ b/examples/galaxy_tags/pass/changelogs/changelog.yaml @@ -0,0 +1,2 @@ +--- +releases: {} diff --git a/examples/galaxy_no_required_tags/pass/galaxy.yml b/examples/galaxy_tags/pass/galaxy.yml similarity index 100% rename from examples/galaxy_no_required_tags/pass/galaxy.yml rename to examples/galaxy_tags/pass/galaxy.yml diff --git a/examples/galaxy_tags/pass/meta/runtime.yml b/examples/galaxy_tags/pass/meta/runtime.yml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/ansiblelint/constants.py b/src/ansiblelint/constants.py index 56cf71bf43..10bf1d5f38 100644 --- a/src/ansiblelint/constants.py +++ b/src/ansiblelint/constants.py @@ -1,9 +1,13 @@ """Constants used by AnsibleLint.""" +import re from enum import Enum from pathlib import Path from typing import Literal +TAG_NAME_REGEXP = re.compile(r"^(?!.*__)[a-z]+[0-9a-z_]*$") +MAX_TAGS_COUNT = 20 +MAX_LENGTH_TAG = 64 DEFAULT_RULESDIR = Path(__file__).parent / "rules" CUSTOM_RULESDIR_ENVVAR = "ANSIBLE_LINT_CUSTOM_RULESDIR" RULE_DOC_URL = "https://ansible.readthedocs.io/projects/lint/rules/" diff --git a/src/ansiblelint/rules/galaxy.md b/src/ansiblelint/rules/galaxy.md index d719e30b93..1252d27427 100644 --- a/src/ansiblelint/rules/galaxy.md +++ b/src/ansiblelint/rules/galaxy.md @@ -26,6 +26,11 @@ This rule can produce messages such: - `galaxy[tags]` - `galaxy.yaml` must have one of the required tags: `application`, `cloud`, `database`, `infrastructure`, `linux`, `monitoring`, `networking`, `security`, `storage`, `tools`, `windows`. +- `galaxy[tags-format]` - `galaxy.yal` tags must be formatted correctly + matching regex. +- `galaxy[tags-length]` - `galaxy.yml` tags character count cannot exceed 64 + characters in length +- `galaxy[tags-count]` - `galaxy.yml` tag count cannot exceed 20 - `galaxy[invalid-dependency-version]` = Invalid collection metadata. Dependency version spec range is invalid diff --git a/src/ansiblelint/rules/galaxy.py b/src/ansiblelint/rules/galaxy.py index fd4483c7bc..90e378cd56 100644 --- a/src/ansiblelint/rules/galaxy.py +++ b/src/ansiblelint/rules/galaxy.py @@ -5,7 +5,13 @@ import sys from typing import TYPE_CHECKING, Any -from ansiblelint.constants import FILENAME_KEY, LINE_NUMBER_KEY +from ansiblelint.constants import ( + FILENAME_KEY, + LINE_NUMBER_KEY, + MAX_LENGTH_TAG, + MAX_TAGS_COUNT, + TAG_NAME_REGEXP, +) from ansiblelint.rules import AnsibleLintRule if TYPE_CHECKING: @@ -23,6 +29,9 @@ class GalaxyRule(AnsibleLintRule): version_added = "v6.11.0 (last update)" _ids = { "galaxy[tags]": "galaxy.yaml must have one of the required tags", + "galaxy[tags-format]": "galaxy.yaml one or more tags are not formatted properly.", + "galaxy[tags-length]": "galaxy.yaml one or more tags exceed character length.", + "galaxy[tags-count]": "galaxy.yaml has too many tags.", "galaxy[no-changelog]": "No changelog found. Please add a changelog file. Refer to the galaxy.md file for more info.", "galaxy[version-missing]": "galaxy.yaml should have version tag.", "galaxy[no-runtime]": "meta/runtime.yml file not found.", @@ -65,6 +74,13 @@ def matchplay(self, file: Lintable, data: dict[str, Any]) -> list[MatchError]: if path.is_file(): changelog_found = 1 galaxy_tag_list = data.get("tags") + galaxy_tag_invalid_format = [ + tag for tag in galaxy_tag_list if not TAG_NAME_REGEXP.match(tag) + ] + galaxy_tag_invalid_length = [ + tag for tag in galaxy_tag_list if len(tag) > MAX_LENGTH_TAG + ] + collection_deps = data.get("dependencies") if collection_deps: for dep, ver in collection_deps.items(): @@ -105,6 +121,42 @@ def matchplay(self, file: Lintable, data: dict[str, Any]) -> list[MatchError]: ), ) + # Checking if galaxy.yml tags are formatted correctly + if galaxy_tag_invalid_format: + results.append( + self.create_matcherror( + message=( + f"galaxy.yaml must have properly formatted tags. Invalid tags: {','.join(galaxy_tag_invalid_format)}" + ), + tag="galaxy[tags-format]", + filename=file, + ), + ) + + # Checking if galaxy.yml tags length are within limits + if galaxy_tag_invalid_length: + results.append( + self.create_matcherror( + message=( + f"galaxy.yaml tags must not exceed {MAX_LENGTH_TAG} characters. Invalid tags: {','.join(galaxy_tag_invalid_length)}" + ), + tag="galaxy[tags-length]", + filename=file, + ), + ) + + # Checking if galaxy.yml tags does not exceed the max number + if len(galaxy_tag_list) > MAX_TAGS_COUNT: + results.append( + self.create_matcherror( + message=( + f"galaxy.yaml exceeds {MAX_TAGS_COUNT} tags. Current count: {len(galaxy_tag_list)}" + ), + tag="galaxy[tags-count]", + filename=file, + ), + ) + if "version" not in data: results.append( self.create_matcherror( @@ -149,12 +201,27 @@ def test_galaxy_no_collection_version() -> None: ("file", "expected"), ( pytest.param( - "examples/galaxy_no_required_tags/fail/galaxy.yml", + "examples/galaxy_tags/galaxy_invalid_format_tags/galaxy.yml", + ["galaxy[tags-format]"], + id="tags-format", + ), + pytest.param( + "examples/galaxy_tags/galaxy_invalid_length_tags/galaxy.yml", + ["galaxy[tags-length]"], + id="tags-length", + ), + pytest.param( + "examples/galaxy_tags/galaxy_count_tags/galaxy.yml", + ["galaxy[tags-count]"], + id="tags-count", + ), + pytest.param( + "examples/galaxy_tags/galaxy_no_required_tags/galaxy.yml", ["galaxy[tags]"], id="tags", ), pytest.param( - "examples/galaxy_no_required_tags/pass/galaxy.yml", + "examples/galaxy_tags/pass/galaxy.yml", [], id="pass", ), diff --git a/tox.ini b/tox.ini index bae58b10df..b5390e9b58 100644 --- a/tox.ini +++ b/tox.ini @@ -76,7 +76,7 @@ setenv = PRE_COMMIT_COLOR = always # Number of expected test passes, safety measure for accidental skip of # tests. Update value if you add/remove tests. (tox-extra) - PYTEST_REQPASS = 895 + PYTEST_REQPASS = 898 FORCE_COLOR = 1 pre: PIP_PRE = 1 allowlist_externals =