Skip to content

Commit

Permalink
Remove support for deprecated include (#3722)
Browse files Browse the repository at this point in the history
  • Loading branch information
ssbarnea committed Nov 28, 2023
1 parent d7c9bff commit 868ebac
Show file tree
Hide file tree
Showing 10 changed files with 218 additions and 18 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Expand Up @@ -34,7 +34,7 @@ repos:
- id: check-useless-excludes
- repo: https://github.com/pre-commit/mirrors-prettier
# keep it before yamllint
rev: v3.0.3
rev: v3.1.0
hooks:
- id: prettier
# Temporary excludes so we can gradually normalize the formatting
Expand Down
2 changes: 1 addition & 1 deletion examples/playbooks/blockincludes.yml
Expand Up @@ -14,7 +14,7 @@
- name: Block level 3
block:
- name: Include under block level 3 # noqa: deprecated-module
ansible.builtin.include: "{{ varset }}.yml"
ansible.builtin.include_tasks: "{{ varset }}.yml"
- name: Block level 4
block:
- name: INCLUDE under block level 4
Expand Down
6 changes: 6 additions & 0 deletions examples/playbooks/removed-include.yml
@@ -0,0 +1,6 @@
---
- name: Invalid playbook
hosts: localhost
tasks:
- name: Foo
include: tasks/simple_task.yml # <-- include was removed in 2.16
14 changes: 14 additions & 0 deletions src/ansiblelint/schemas/ansible.json
@@ -1,5 +1,10 @@
{
"$defs": {
"removed-include-module": {
"markdownDescription": "See [include module](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/include_module.html)",
"not": {},
"title": "Replace 'include' with either 'ansible.builtin.include_tasks' or 'ansible.builtin.import_tasks'"
},
"ansible.builtin.import_playbook": {
"additionalProperties": false,
"oneOf": [
Expand Down Expand Up @@ -831,6 +836,15 @@
"title": "Action",
"type": "string"
},
"ansible.builtin.include": {
"$ref": "#/$defs/removed-include-module"
},
"include": {
"$ref": "#/$defs/removed-include-module"
},
"ansible.legacy.include": {
"$ref": "#/$defs/removed-include-module"
},
"any_errors_fatal": {
"$ref": "#/$defs/templated-boolean",
"title": "Any Errors Fatal"
Expand Down
34 changes: 22 additions & 12 deletions src/ansiblelint/schemas/main.py
Expand Up @@ -55,19 +55,29 @@ def validate_file_schema(file: Lintable) -> list[str]:
return []
if error.context:
error = find_best_deep_match(error)
message = f"{error.json_path} {error.message}"
# determine if we want to use our own messages embedded into schemas inside title/markdownDescription fields
if "not" in error.schema and len(error.schema["not"]) == 0:
message = error.schema["title"]
schema = error.schema
else:
message = f"{error.json_path} {error.message}"

documentation_url = ""
for k in ("description", "markdownDescription"):
if k in schema:
# Find standalone URLs and also markdown urls.
match = re.search(
r"\[.*?\]\((https?://[^\s]+)\)|https?://[^\s]+",
schema[k],
)
if match:
documentation_url = match[0] if match[0] else match[1]
break
for json_schema in (error.schema, schema):
for k in ("description", "markdownDescription"):
if k in json_schema:
# Find standalone URLs and also markdown urls.
match = re.search(
r"\[.*?\]\((?P<url>https?://[^\s]+)\)|(?P<url2>https?://[^\s]+)",
json_schema[k],
)
if match:
documentation_url = next(
x for x in match.groups() if x is not None
)
break
if documentation_url:
break
if documentation_url:
if not message.endswith("."):
message += "."
Expand All @@ -86,7 +96,7 @@ def validate_file_schema(file: Lintable) -> list[str]:
schema[k],
)
if match:
documentation_url = match[0] if match[0] else match[1]
documentation_url = match.groups()[0]
break
if documentation_url:
if not message.endswith("."):
Expand Down
14 changes: 14 additions & 0 deletions src/ansiblelint/schemas/playbook.json
Expand Up @@ -796,6 +796,11 @@
"title": "play-role",
"type": "object"
},
"removed-include-module": {
"markdownDescription": "See [include module](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/include_module.html)",
"not": {},
"title": "Replace 'include' with either 'ansible.builtin.include_tasks' or 'ansible.builtin.import_tasks'"
},
"tags": {
"anyOf": [
{
Expand Down Expand Up @@ -847,6 +852,12 @@
"title": "Action",
"type": "string"
},
"ansible.builtin.include": {
"$ref": "#/$defs/removed-include-module"
},
"ansible.legacy.include": {
"$ref": "#/$defs/removed-include-module"
},
"any_errors_fatal": {
"$ref": "#/$defs/templated-boolean",
"title": "Any Errors Fatal"
Expand Down Expand Up @@ -932,6 +943,9 @@
"title": "Ignore Unreachable",
"type": "boolean"
},
"include": {
"$ref": "#/$defs/removed-include-module"
},
"listen": {
"anyOf": [
{
Expand Down
14 changes: 14 additions & 0 deletions src/ansiblelint/schemas/tasks.json
Expand Up @@ -238,6 +238,11 @@
"markdownDescription": "Use for protecting sensitive data. See [no_log](https://docs.ansible.com/ansible/latest/reference_appendices/logging.html)",
"title": "no_log"
},
"removed-include-module": {
"markdownDescription": "See [include module](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/include_module.html)",
"not": {},
"title": "Replace 'include' with either 'ansible.builtin.include_tasks' or 'ansible.builtin.import_tasks'"
},
"tags": {
"anyOf": [
{
Expand Down Expand Up @@ -289,6 +294,12 @@
"title": "Action",
"type": "string"
},
"ansible.builtin.include": {
"$ref": "#/$defs/removed-include-module"
},
"ansible.legacy.include": {
"$ref": "#/$defs/removed-include-module"
},
"any_errors_fatal": {
"$ref": "#/$defs/templated-boolean",
"title": "Any Errors Fatal"
Expand Down Expand Up @@ -374,6 +385,9 @@
"title": "Ignore Unreachable",
"type": "boolean"
},
"include": {
"$ref": "#/$defs/removed-include-module"
},
"listen": {
"anyOf": [
{
Expand Down
3 changes: 3 additions & 0 deletions test/schemas/negative_test/playbooks/include.yml
@@ -0,0 +1,3 @@
- hosts: localhost
tasks:
- include: foo.yml # <-- removed in Ansible 2.16
142 changes: 142 additions & 0 deletions test/schemas/negative_test/playbooks/include.yml.md
@@ -0,0 +1,142 @@
# ajv errors

```json
[
{
"instancePath": "/0",
"keyword": "required",
"message": "must have required property 'ansible.builtin.import_playbook'",
"params": {
"missingProperty": "ansible.builtin.import_playbook"
},
"schemaPath": "#/oneOf/0/required"
},
{
"instancePath": "/0",
"keyword": "required",
"message": "must have required property 'import_playbook'",
"params": {
"missingProperty": "import_playbook"
},
"schemaPath": "#/oneOf/1/required"
},
{
"instancePath": "/0",
"keyword": "oneOf",
"message": "must match exactly one schema in oneOf",
"params": {
"passingSchemas": null
},
"schemaPath": "#/oneOf"
},
{
"instancePath": "/0",
"keyword": "additionalProperties",
"message": "must NOT have additional properties",
"params": {
"additionalProperty": "hosts"
},
"schemaPath": "#/additionalProperties"
},
{
"instancePath": "/0",
"keyword": "additionalProperties",
"message": "must NOT have additional properties",
"params": {
"additionalProperty": "tasks"
},
"schemaPath": "#/additionalProperties"
},
{
"instancePath": "/0/tasks/0",
"keyword": "required",
"message": "must have required property 'block'",
"params": {
"missingProperty": "block"
},
"schemaPath": "#/required"
},
{
"instancePath": "/0/tasks/0/include",
"keyword": "not",
"message": "must NOT be valid",
"params": {},
"schemaPath": "#/$defs/removed-include-module/not"
},
{
"instancePath": "/0/tasks/0",
"keyword": "anyOf",
"message": "must match a schema in anyOf",
"params": {},
"schemaPath": "#/items/anyOf"
},
{
"instancePath": "/0",
"keyword": "oneOf",
"message": "must match exactly one schema in oneOf",
"params": {
"passingSchemas": null
},
"schemaPath": "#/items/oneOf"
}
]
```

# check-jsonschema

stdout:

```json
{
"status": "fail",
"successes": [],
"errors": [
{
"filename": "negative_test/playbooks/include.yml",
"path": "$[0]",
"message": "{'hosts': 'localhost', 'tasks': [{'include': 'foo.yml'}]} is not valid under any of the given schemas",
"has_sub_errors": true,
"best_match": {
"path": "$[0]",
"message": "'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'"
},
"best_deep_match": {
"path": "$[0].tasks[0].include",
"message": "'foo.yml' should not be valid under {}"
},
"num_sub_errors": 6,
"sub_errors": [
{
"path": "$[0]",
"message": "'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'"
},
{
"path": "$[0]",
"message": "{'hosts': 'localhost', 'tasks': [{'include': 'foo.yml'}]} is not valid under any of the given schemas"
},
{
"path": "$[0]",
"message": "'ansible.builtin.import_playbook' is a required property"
},
{
"path": "$[0]",
"message": "'import_playbook' is a required property"
},
{
"path": "$[0].tasks[0]",
"message": "{'include': 'foo.yml'} is not valid under any of the given schemas"
},
{
"path": "$[0].tasks[0]",
"message": "'block' is a required property"
},
{
"path": "$[0].tasks[0].include",
"message": "'foo.yml' should not be valid under {}"
}
]
}
],
"parse_errors": []
}
```
5 changes: 1 addition & 4 deletions test/test_task_includes.py
@@ -1,5 +1,4 @@
"""Tests related to task inclusions."""
import sys

import pytest

Expand All @@ -14,9 +13,7 @@
pytest.param(
"examples/playbooks/blockincludes.yml",
4,
3
if sys.version_info >= (3, 10, 0)
else 4, # 3 with py310/ansible2.16, or 4 with py39/ansible2.15,
3,
id="blockincludes",
),
pytest.param(
Expand Down

0 comments on commit 868ebac

Please sign in to comment.