diff --git a/.github/workflows/tox.yml b/.github/workflows/tox.yml index 62f1fc658a..856c6130a6 100644 --- a/.github/workflows/tox.yml +++ b/.github/workflows/tox.yml @@ -83,7 +83,7 @@ jobs: WSLENV: FORCE_COLOR:PYTEST_REQPASS:TOXENV:GITHUB_STEP_SUMMARY # Number of expected test passes, safety measure for accidental skip of # tests. Update value if you add/remove tests. - PYTEST_REQPASS: 741 + PYTEST_REQPASS: 742 steps: - name: Activate WSL1 diff --git a/examples/changelog.yml b/examples/changelog.yml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/ansiblelint/config.py b/src/ansiblelint/config.py index cb0c6f2e79..59db0febe2 100644 --- a/src/ansiblelint/config.py +++ b/src/ansiblelint/config.py @@ -73,6 +73,7 @@ {"requirements": "**/requirements.{yaml,yml}"}, # v2 and v1 {"playbook": "**/molecule/*/*.{yaml,yml}"}, # molecule playbooks {"yaml": "**/{.ansible-lint,.yamllint}"}, + {"changelog": "**/changelog.yml"}, {"yaml": "**/*.{yaml,yml}"}, {"yaml": "**/.*.{yaml,yml}"}, ] diff --git a/src/ansiblelint/schemas/__store__.json b/src/ansiblelint/schemas/__store__.json index 3d388fa873..ca7c5be1d6 100644 --- a/src/ansiblelint/schemas/__store__.json +++ b/src/ansiblelint/schemas/__store__.json @@ -11,6 +11,9 @@ "etag": "bd98c32fe4b9672bdadb85efd0dbfded7ef08b6cfda5c0ff91fb1cf45e274e0e", "url": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/arg_specs.json" }, + "changelog": { + "url": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/changelog.json" + }, "execution-environment": { "etag": "17ebd7426f2f31e362f7e0eae6683fbb17b83983bc0fdfc2cdf5c83e1ed38808", "url": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/execution-environment.json" diff --git a/src/ansiblelint/schemas/changelog.json b/src/ansiblelint/schemas/changelog.json new file mode 100644 index 0000000000..ff97535ea0 --- /dev/null +++ b/src/ansiblelint/schemas/changelog.json @@ -0,0 +1,98 @@ +{ + "$defs": { + "release": { + "additionalProperties": false, + "properties": { + "changes": { + "additionalProperties": false, + "properties": { + "bugfixes": { + "items": { + "type": "string" + }, + "type": "array" + }, + "deprecated_features": { + "items": { + "type": "string" + }, + "type": "array" + }, + "minor_changes": { + "items": { + "type": "string" + }, + "type": "array" + }, + "release_summary": { + "type": "string" + } + }, + "type": "object" + }, + "codename": { + "type": "string" + }, + "modules": { + "items": { + "properties": { + "description": { + "markdownDescription": "Value of `short_description from plugin `DOCUMENTATION`.", + "title": "Description", + "type": "string" + }, + "name": { + "markdownDescription": " It must not be the FQCN, but the name inside the collection.", + "pattern": "[a-zA-Z0-9_]+", + "title": "Short module name", + "type": "string" + }, + "namespace": { + "markdownDescription": "Must be `null` for plugin and objects. For modules it must be either empty string. The namespace is used to group new modules by their namespace inside the collection.", + "title": "Namespace", + "type": ["string", "null"] + } + }, + "type": "object" + }, + "type": "array" + }, + "release_date": { + "format": "date", + "markdownDescription": "Use ISO-8601 date format, like 2020-12-31", + "pattern": "\\d\\d\\d\\d-\\d\\d-\\d\\d", + "title": "Date of the release.", + "type": "string" + } + }, + "type": "object" + }, + "semver": { + "pattern": "\\d+.\\d+.\\d+.*", + "title": "Version string following SemVer specification.", + "type": "string" + } + }, + "$id": "https://raw.githubusercontent.com/ansible-lint/main/src/ansiblelint/schemas/changelog.json", + "$schema": "http://json-schema.org/draft-07/schema", + "additionalProperties": false, + "description": "Antsibull Changelog Schema", + "examples": ["changelog.yml"], + "markdownDescription": "See [Changelog YAML Format](https://github.com/ansible-community/antsibull-changelog/blob/main/docs/changelog.yaml-format.md)", + "properties": { + "ancestor": { + "$ref": "#/$defs/semver" + }, + "releases": { + "patternProperties": { + "\\d+.\\d+.\\d+.*": { + "$ref": "#/$defs/release", + "type": "object" + } + }, + "type": "object" + } + }, + "title": "Antsibull Changelog Schema", + "type": "object" +} diff --git a/test/schemas/negative_test/changelogs/invalid-date/changelog.yml b/test/schemas/negative_test/changelogs/invalid-date/changelog.yml new file mode 100644 index 0000000000..8948229162 --- /dev/null +++ b/test/schemas/negative_test/changelogs/invalid-date/changelog.yml @@ -0,0 +1,3 @@ +releases: + 1.0.0: + release_date: 01-01-2020 # invalid date format, must be ISO-8601 ! diff --git a/test/schemas/negative_test/changelogs/invalid-date/changelog.yml.md b/test/schemas/negative_test/changelogs/invalid-date/changelog.yml.md new file mode 100644 index 0000000000..2d6a69eebc --- /dev/null +++ b/test/schemas/negative_test/changelogs/invalid-date/changelog.yml.md @@ -0,0 +1,40 @@ +# ajv errors + +```json +[ + { + "instancePath": "/releases/1.0.0/release_date", + "keyword": "pattern", + "message": "must match pattern \"\\d\\d\\d\\d-\\d\\d-\\d\\d\"", + "params": { + "pattern": "\\d\\d\\d\\d-\\d\\d-\\d\\d" + }, + "schemaPath": "#/$defs/release/properties/release_date/pattern" + } +] +``` + +# check-jsonschema + +stdout: + +```json +{ + "status": "fail", + "errors": [ + { + "filename": "negative_test/changelogs/invalid-date/changelog.yml", + "path": "$.releases.1.0.0.release_date", + "message": "'01-01-2020' is not a 'date'", + "has_sub_errors": false + }, + { + "filename": "negative_test/changelogs/invalid-date/changelog.yml", + "path": "$.releases.1.0.0.release_date", + "message": "'01-01-2020' does not match '\\\\d\\\\d\\\\d\\\\d-\\\\d\\\\d-\\\\d\\\\d'", + "has_sub_errors": false + } + ], + "parse_errors": [] +} +``` diff --git a/test/schemas/negative_test/changelogs/list/changelog.yml b/test/schemas/negative_test/changelogs/list/changelog.yml new file mode 100644 index 0000000000..72def5bded --- /dev/null +++ b/test/schemas/negative_test/changelogs/list/changelog.yml @@ -0,0 +1,4 @@ +--- +- this is invalid +- as changelog must be object (mapping) +- not an array (sequence) diff --git a/test/schemas/negative_test/changelogs/list/changelog.yml.md b/test/schemas/negative_test/changelogs/list/changelog.yml.md new file mode 100644 index 0000000000..75f417ce49 --- /dev/null +++ b/test/schemas/negative_test/changelogs/list/changelog.yml.md @@ -0,0 +1,34 @@ +# ajv errors + +```json +[ + { + "instancePath": "", + "keyword": "type", + "message": "must be object", + "params": { + "type": "object" + }, + "schemaPath": "#/type" + } +] +``` + +# check-jsonschema + +stdout: + +```json +{ + "status": "fail", + "errors": [ + { + "filename": "negative_test/changelogs/list/changelog.yml", + "path": "$", + "message": "['this is invalid', 'as changelog must be object (mapping)', 'not an array (sequence)'] is not of type 'object'", + "has_sub_errors": false + } + ], + "parse_errors": [] +} +``` diff --git a/test/schemas/negative_test/changelogs/no-semver/changelog.yml b/test/schemas/negative_test/changelogs/no-semver/changelog.yml new file mode 100644 index 0000000000..7e445ae768 --- /dev/null +++ b/test/schemas/negative_test/changelogs/no-semver/changelog.yml @@ -0,0 +1 @@ +releases: foo # <-- not a semver diff --git a/test/schemas/negative_test/changelogs/no-semver/changelog.yml.md b/test/schemas/negative_test/changelogs/no-semver/changelog.yml.md new file mode 100644 index 0000000000..6ebcf952b4 --- /dev/null +++ b/test/schemas/negative_test/changelogs/no-semver/changelog.yml.md @@ -0,0 +1,34 @@ +# ajv errors + +```json +[ + { + "instancePath": "/releases", + "keyword": "type", + "message": "must be object", + "params": { + "type": "object" + }, + "schemaPath": "#/properties/releases/type" + } +] +``` + +# check-jsonschema + +stdout: + +```json +{ + "status": "fail", + "errors": [ + { + "filename": "negative_test/changelogs/no-semver/changelog.yml", + "path": "$.releases", + "message": "'foo' is not of type 'object'", + "has_sub_errors": false + } + ], + "parse_errors": [] +} +``` diff --git a/test/schemas/negative_test/changelogs/unknown-keys/changelog.yml b/test/schemas/negative_test/changelogs/unknown-keys/changelog.yml new file mode 100644 index 0000000000..121875bfd5 --- /dev/null +++ b/test/schemas/negative_test/changelogs/unknown-keys/changelog.yml @@ -0,0 +1 @@ +release: {} # <- unknown key, correct would be releases diff --git a/test/schemas/negative_test/changelogs/unknown-keys/changelog.yml.md b/test/schemas/negative_test/changelogs/unknown-keys/changelog.yml.md new file mode 100644 index 0000000000..c884c6b43d --- /dev/null +++ b/test/schemas/negative_test/changelogs/unknown-keys/changelog.yml.md @@ -0,0 +1,34 @@ +# ajv errors + +```json +[ + { + "instancePath": "", + "keyword": "additionalProperties", + "message": "must NOT have additional properties", + "params": { + "additionalProperty": "release" + }, + "schemaPath": "#/additionalProperties" + } +] +``` + +# check-jsonschema + +stdout: + +```json +{ + "status": "fail", + "errors": [ + { + "filename": "negative_test/changelogs/unknown-keys/changelog.yml", + "path": "$", + "message": "Additional properties are not allowed ('release' was unexpected)", + "has_sub_errors": false + } + ], + "parse_errors": [] +} +``` diff --git a/test/schemas/test/changelog.yml b/test/schemas/test/changelog.yml new file mode 100644 index 0000000000..8661bd7a5f --- /dev/null +++ b/test/schemas/test/changelog.yml @@ -0,0 +1,17 @@ +ancestor: 0.5.4 +releases: + 1.0.0-alpha: + release_date: "2020-01-01" + codename: "The first public one" + changes: + release_summary: A bit o markdown text + bugfixes: + - Fixed bug `#1 ` + deprecated_features: + - Free form text mentioning a deprecation + minor_changes: + - Free form text mentioning a minor change + modules: + - description: foo + name: short_module_name + namespace: foo diff --git a/test/schemas/test/changelogs/minimal/changelog.yml b/test/schemas/test/changelogs/minimal/changelog.yml new file mode 100644 index 0000000000..0c618323e9 --- /dev/null +++ b/test/schemas/test/changelogs/minimal/changelog.yml @@ -0,0 +1,3 @@ +--- +# Example of minimal changelog.yml that is considered valid +releases: {} diff --git a/test/test_schemas.py b/test/test_schemas.py index b436a73536..77634bbd95 100644 --- a/test/test_schemas.py +++ b/test/test_schemas.py @@ -1,6 +1,10 @@ """Test schemas modules.""" from time import sleep +import pytest +from ansiblelint.rules import RulesCollection +from ansiblelint.runner import Runner + from ansiblelint.schemas import refresh_schemas @@ -16,3 +20,21 @@ def test_refresh_schemas() -> None: sleep(1) # should be cached now assert refresh_schemas(min_age_seconds=10) == 0 + + +@pytest.mark.parametrize( + ("file", "expected_tags"), + (pytest.param("examples/changelog.yml", ["schema[changelog]"], id="changelog"),), +) +def test_schema( + default_rules_collection: RulesCollection, + file: str, + expected_tags: list[str], +) -> None: + """Test that runner can go through any corner cases.""" + runner = Runner(file, rules=default_rules_collection) + matches = runner.run() + + assert len(matches) == len(expected_tags) + for i, match in enumerate(matches): + assert match.tag == expected_tags[i]