Skip to content

Commit

Permalink
Add linter for values.schema.json (apache#20193)
Browse files Browse the repository at this point in the history
  • Loading branch information
mik-laj authored Dec 13, 2021
1 parent c7f36f2 commit aa70e2e
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 15 deletions.
7 changes: 7 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,13 @@ repos:
files: airflow/config_templates/config\.yml$
require_serial: true
additional_dependencies: ['jsonschema==3.2.0', 'PyYAML==5.3.1', 'requests==2.25.0']
- id: chart-schema-lint
name: Lint chart/values.schema.json file
entry: ./scripts/ci/pre_commit/pre_commit_chart_schema.py
language: python
pass_filenames: false
files: ^chart/values\.schema\.json$
require_serial: true
- id: ui-lint
name: ESLint against airflow/ui
language: node
Expand Down
31 changes: 16 additions & 15 deletions BREEZE.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2194,21 +2194,22 @@ This is the current syntax for `./breeze <./breeze>`_:
all airflow-config-yaml airflow-providers-available airflow-provider-yaml-files-ok
base-operator bats-tests bats-in-container-tests black blacken-docs boring-cyborg
build build-providers-dependencies capitalized-breeze changelog-duplicates
check-apache-license check-builtin-literals check-executables-have-shebangs
check-extras-order check-hooks-apply check-integrations check-merge-conflict
check-xml daysago-import-check debug-statements detect-private-key doctoc
dont-use-safe-filter end-of-file-fixer fix-encoding-pragma flake8 flynt codespell
forbid-tabs helm-lint identity incorrect-use-of-LoggingMixin insert-license isort
json-schema language-matters lint-dockerfile lint-openapi markdownlint mermaid
mixed-line-ending mypy mypy-helm no-providers-in-core-examples no-relative-imports
pre-commit-descriptions pre-commit-hook-names pretty-format-json
provide-create-sessions providers-changelogs providers-init-file
providers-subpackages-init-file provider-yamls pydevd pydocstyle python-no-log-warn
pyupgrade restrict-start_date rst-backticks setup-order setup-extra-packages
shellcheck sort-in-the-wild sort-spelling-wordlist stylelint trailing-whitespace
ui-lint update-breeze-file update-extras update-local-yml-file update-setup-cfg-file
update-versions verify-db-migrations-documented version-sync www-lint yamllint yesqa
build build-providers-dependencies chart-schema-lint capitalized-breeze
changelog-duplicates check-apache-license check-builtin-literals
check-executables-have-shebangs check-extras-order check-hooks-apply
check-integrations check-merge-conflict check-xml daysago-import-check
debug-statements detect-private-key doctoc dont-use-safe-filter end-of-file-fixer
fix-encoding-pragma flake8 flynt codespell forbid-tabs helm-lint identity
incorrect-use-of-LoggingMixin insert-license isort json-schema language-matters
lint-dockerfile lint-openapi markdownlint mermaid mixed-line-ending mypy mypy-helm
no-providers-in-core-examples no-relative-imports pre-commit-descriptions
pre-commit-hook-names pretty-format-json provide-create-sessions
providers-changelogs providers-init-file providers-subpackages-init-file
provider-yamls pydevd pydocstyle python-no-log-warn pyupgrade restrict-start_date
rst-backticks setup-order setup-extra-packages shellcheck sort-in-the-wild
sort-spelling-wordlist stylelint trailing-whitespace ui-lint update-breeze-file
update-extras update-local-yml-file update-setup-cfg-file update-versions
verify-db-migrations-documented version-sync www-lint yamllint yesqa
You can pass extra arguments including options to the pre-commit framework as
<EXTRA_ARGS> passed after --. For example:
Expand Down
2 changes: 2 additions & 0 deletions STATIC_CODE_CHECKS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ require Breeze Docker images to be installed locally.
------------------------------------ ---------------------------------------------------------------- ------------
``build-providers-dependencies`` Regenerates the JSON file with cross-provider dependencies
------------------------------------ ---------------------------------------------------------------- ------------
``chart-schema-lint`` Lint chart/values.schema.json file
------------------------------------ ---------------------------------------------------------------- ------------
``capitalized-breeze`` Breeze has to be Capitalized in Breeze2
------------------------------------ ---------------------------------------------------------------- ------------
``changelog-duplicates`` Checks for duplicate changelog entries
Expand Down
1 change: 1 addition & 0 deletions breeze-complete
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ blacken-docs
boring-cyborg
build
build-providers-dependencies
chart-schema-lint
capitalized-breeze
changelog-duplicates
check-apache-license
Expand Down
3 changes: 3 additions & 0 deletions chart/values.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2461,6 +2461,9 @@
"ports": {
"description": "Ports for flower NetworkPolicy ingress (if `from` is set).",
"type": "array",
"items": {
"$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.22.0-standalone-strict/networkpolicyport-networking-v1.json"
},
"default": [
{
"port": "flower-ui"
Expand Down
119 changes: 119 additions & 0 deletions scripts/ci/pre_commit/pre_commit_chart_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
#!/usr/bin/env python3
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

import json
import sys
from pathlib import Path

if __name__ not in ("__main__", "__mp_main__"):
raise SystemExit(
"This file is intended to be executed as an executable program. You cannot use it as a module."
f"To run this script, run the ./{__file__} command"
)

PROJECT_SOURCE_ROOT_DIR = Path(__file__).resolve().parent.parent.parent.parent
CHART_DIR = PROJECT_SOURCE_ROOT_DIR / "chart"
KNOWN_INVALID_TYPES = {
# I don't know the data structure for this type with 100 certainty. We have no tests.
"$['properties']['ingress']['properties']['web']['properties']['precedingPaths']",
# I don't know the data structure for this type with 100 certainty. We have no tests.
"$['properties']['ingress']['properties']['web']['properties']['succeedingPaths']",
# The value of this parameter is passed to statsd_exporter, which does not have a strict type definition.
"$['properties']['statsd']['properties']['extraMappings']",
}

SCHEMA = json.loads((CHART_DIR / "values.schema.json").read_text())


def display_definitions_list(definitions_list):
print("Invalid definitions: ")
for no_d, (schema_type, schema_path) in enumerate(definitions_list, start=1):
print(f"{no_d}: {schema_path}")
print(json.dumps(schema_type, indent=2))


def walk(value, path='$'):
yield value, path
if isinstance(value, dict):
for k, v in value.items():
yield from walk(v, path + f"[{k!r}]")
elif isinstance(value, (list, set, tuple)):
for no, v in enumerate(value):
yield from walk(v, path + f"[{no}]")


def validate_object_types():
all_object_types = ((d, p) for d, p in walk(SCHEMA) if type(d) == dict and d.get('type') == 'object')
all_object_types_with_a_loose_definition = [
(d, p)
for d, p in all_object_types
if 'properties' not in d
and "$ref" not in d
and type(d.get('additionalProperties')) != dict
and p not in KNOWN_INVALID_TYPES
]
to_display_invalid_types = [
(d, p) for d, p in all_object_types_with_a_loose_definition if p not in KNOWN_INVALID_TYPES
]
if to_display_invalid_types:
print(
"Found object type definitions with too loose a definition. "
"Make sure that the type meets one of the following conditions:"
)
print(" - has a `properties` key")
print(" - has a `$ref` key")
print(" - has a `additionalProperties` key, which content is an object")
display_definitions_list(to_display_invalid_types)
return all_object_types_with_a_loose_definition


def validate_array_types():
all_array_types = ((d, p) for d, p in walk(SCHEMA) if type(d) == dict and d.get('type') == 'array')
all_array_types_with_a_loose_definition = [
(d, p) for (d, p) in all_array_types if type(d.get('items')) != dict
]
to_display_invalid_types = [
(d, p) for d, p in all_array_types_with_a_loose_definition if p not in KNOWN_INVALID_TYPES
]

if to_display_invalid_types:
print(
"Found array type definitions with too loose a definition. "
"Make sure the object has the items key."
)
display_definitions_list(to_display_invalid_types)
return all_array_types_with_a_loose_definition


invalid_object_types_path = {p for _, p in validate_object_types()}
invalid_array_types_path = {p for _, p in validate_array_types()}
fixed_types = KNOWN_INVALID_TYPES - invalid_object_types_path - invalid_array_types_path
invalid_paths = (invalid_object_types_path.union(invalid_array_types_path)) - KNOWN_INVALID_TYPES

if fixed_types:
current_file = Path(__file__).resolve()
print(
f"Some types that were known to be invalid have been fixed. Can you update the variable "
f"`known_invalid_types` in file {current_file!r}? You just need to delete the following items:"
)
print("\n".join(fixed_types))

if fixed_types or invalid_paths:
sys.exit(1)
else:
print("No problems")

0 comments on commit aa70e2e

Please sign in to comment.