From d018661a2f8c8c8265e4676e214e0982e6496968 Mon Sep 17 00:00:00 2001 From: Nautobot-Bot <79372327+nautobot-bot@users.noreply.github.com> Date: Sat, 9 Mar 2024 06:55:42 -0600 Subject: [PATCH] Cookie updated by NetworkToCode Cookie Drift Manager Tool (#730) * Cookie updated by NetworkToCode Cookie Drift Manager Tool Template: ``` { "template": "https://github.com/nautobot/cookiecutter-nautobot-app.git", "dir": "nautobot-app", "ref": "refs/tags/nautobot-app-v2.2.0", "path": null } ``` Cookie: ``` { "remote": "https://github.com/nautobot/nautobot-app-golden-config.git", "path": "/tmp/tmptjpgbanq/nautobot-app-golden-config", "repository_path": "/tmp/tmptjpgbanq/nautobot-app-golden-config", "dir": "", "branch_prefix": "drift-manager", "context": { "codeowner_github_usernames": "@itdependsnetworks @jeffkala @nkallergis", "full_name": "Network to Code, LLC", "email": "opensource@networktocode.com", "github_org": "nautobot", "app_name": "nautobot_golden_config", "verbose_name": "Golden Config", "app_slug": "nautobot-golden-config", "project_slug": "nautobot-app-golden-config", "repo_url": "https://github.com/nautobot/nautobot-app-golden-config", "base_url": "golden-config", "min_nautobot_version": "2.0.0", "max_nautobot_version": "2.9999", "camel_name": "NautobotGoldenConfig", "project_short_description": "An app for configuration on nautobot", "model_class_name": "None", "open_source_license": "Apache-2.0", "docs_base_url": "https://docs.nautobot.com", "docs_app_url": "https://docs.nautobot.com/projects/golden-config/en/latest", "_template": "https://github.com/nautobot/cookiecutter-nautobot-app.git", "_output_dir": "/tmp/tmptjpgbanq", "_repo_dir": "/github/home/.cookiecutters/cookiecutter-nautobot-app/nautobot-app", "_checkout": "refs/tags/nautobot-app-v2.2.0" }, "base_branch": "develop", "remote_name": "origin", "pull_request_strategy": "PullRequestStrategy.CREATE", "post_actions": [ "PostAction.BLACK" ], "baked_commit_ref": "c9dce46b70f0154a56974587202e71e82ef08bae", "draft": true } ``` CLI Arguments: ``` { "cookie_dir": "", "input": false, "json_filename": "", "output_dir": "", "push": true, "template": "", "template_dir": "", "template_ref": "refs/tags/nautobot-app-v2.2.0", "pull_request": null, "post_action": [], "disable_post_actions": false, "draft": null } ``` --------- Co-authored-by: bakebot Co-authored-by: Jan Snasel --- .cookiecutter.json | 4 +- .../pull_request_template.md | 1 - .github/workflows/ci.yml | 72 +++++-------------- changes/8.housekeeping | 1 + development/Dockerfile | 2 +- development/app_config_schema.py | 64 +++++++++++++++++ development/nautobot_config.py | 4 +- development/towncrier_template.j2 | 2 +- docs/admin/install.md | 2 +- docs/dev/contributing.md | 42 +++++------ docs/dev/dev_environment.md | 20 +++++- mkdocs.yml | 6 +- nautobot_golden_config/app-config-schema.json | 1 + poetry.lock | 18 ++++- pyproject.toml | 4 +- tasks.py | 54 ++++++++++++-- 16 files changed, 199 insertions(+), 98 deletions(-) create mode 100644 changes/8.housekeeping create mode 100644 development/app_config_schema.py create mode 100644 nautobot_golden_config/app-config-schema.json diff --git a/.cookiecutter.json b/.cookiecutter.json index b19002e0..5d01c752 100644 --- a/.cookiecutter.json +++ b/.cookiecutter.json @@ -21,7 +21,7 @@ "_drift_manager": { "template": "https://github.com/nautobot/cookiecutter-nautobot-app.git", "template_dir": "nautobot-app", - "template_ref": "refs/tags/nautobot-app-v2.1.0", + "template_ref": "refs/tags/nautobot-app-v2.2.0", "cookie_dir": "", "branch_prefix": "drift-manager", "pull_request_strategy": "create", @@ -29,7 +29,7 @@ "black" ], "draft": true, - "baked_commit_ref": "c9dce46b70f0154a56974587202e71e82ef08bae" + "baked_commit_ref": "1f3e36613d3c301a807cdbdc4a90e849fd88c554" } } } diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md index 8a9b4cf1..7cf1631e 100644 --- a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +++ b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md @@ -30,5 +30,4 @@ - [ ] Attached Screenshots, Payload Example - [ ] Unit, Integration Tests - [ ] Documentation Updates (when adding/changing features) -- [ ] Example App Updates (when adding/changing features) - [ ] Outline Remaining Work, Constraints from Design diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c128180..0f3c9bec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: - name: "Check out repository code" uses: "actions/checkout@v4" - name: "Setup environment" - uses: "networktocode/gh-action-setup-poetry-environment@v4" + uses: "networktocode/gh-action-setup-poetry-environment@v6" - name: "Linting: black" run: "poetry run invoke black" bandit: @@ -36,7 +36,7 @@ jobs: - name: "Check out repository code" uses: "actions/checkout@v4" - name: "Setup environment" - uses: "networktocode/gh-action-setup-poetry-environment@v4" + uses: "networktocode/gh-action-setup-poetry-environment@v6" - name: "Linting: bandit" run: "poetry run invoke bandit" ruff: @@ -47,7 +47,7 @@ jobs: - name: "Check out repository code" uses: "actions/checkout@v4" - name: "Setup environment" - uses: "networktocode/gh-action-setup-poetry-environment@v4" + uses: "networktocode/gh-action-setup-poetry-environment@v6" - name: "Linting: ruff" run: "poetry run invoke ruff" check-docs-build: @@ -58,7 +58,7 @@ jobs: - name: "Check out repository code" uses: "actions/checkout@v4" - name: "Setup environment" - uses: "networktocode/gh-action-setup-poetry-environment@v4" + uses: "networktocode/gh-action-setup-poetry-environment@v6" - name: "Check Docs Build" run: "poetry run invoke build-and-check-docs" flake8: @@ -69,7 +69,7 @@ jobs: - name: "Check out repository code" uses: "actions/checkout@v4" - name: "Setup environment" - uses: "networktocode/gh-action-setup-poetry-environment@v4" + uses: "networktocode/gh-action-setup-poetry-environment@v6" - name: "Linting: flake8" run: "poetry run invoke flake8" poetry: @@ -80,7 +80,7 @@ jobs: - name: "Check out repository code" uses: "actions/checkout@v4" - name: "Setup environment" - uses: "networktocode/gh-action-setup-poetry-environment@v4" + uses: "networktocode/gh-action-setup-poetry-environment@v6" - name: "Checking: poetry lock file" run: "poetry run invoke lock --check" yamllint: @@ -91,10 +91,10 @@ jobs: - name: "Check out repository code" uses: "actions/checkout@v4" - name: "Setup environment" - uses: "networktocode/gh-action-setup-poetry-environment@v4" + uses: "networktocode/gh-action-setup-poetry-environment@v6" - name: "Linting: yamllint" run: "poetry run invoke yamllint" - pylint: + check-in-docker: needs: - "bandit" - "ruff" @@ -115,7 +115,7 @@ jobs: - name: "Check out repository code" uses: "actions/checkout@v4" - name: "Setup environment" - uses: "networktocode/gh-action-setup-poetry-environment@v4" + uses: "networktocode/gh-action-setup-poetry-environment@v6" - name: "Set up Docker Buildx" id: "buildx" uses: "docker/setup-buildx-action@v3" @@ -137,53 +137,13 @@ jobs: run: "cp development/creds.example.env development/creds.env" - name: "Linting: pylint" run: "poetry run invoke pylint" - check-migrations: - needs: - - "bandit" - - "ruff" - - "flake8" - - "poetry" - - "yamllint" - - "black" - runs-on: "ubuntu-22.04" - strategy: - fail-fast: true - matrix: - python-version: ["3.11"] - nautobot-version: ["2.0.0"] - env: - INVOKE_NAUTOBOT_GOLDEN_CONFIG_PYTHON_VER: "${{ matrix.python-version }}" - INVOKE_NAUTOBOT_GOLDEN_CONFIG_NAUTOBOT_VER: "${{ matrix.nautobot-version }}" - steps: - - name: "Check out repository code" - uses: "actions/checkout@v4" - - name: "Setup environment" - uses: "networktocode/gh-action-setup-poetry-environment@v4" - - name: "Set up Docker Buildx" - id: "buildx" - uses: "docker/setup-buildx-action@v3" - - name: "Build" - uses: "docker/build-push-action@v5" - with: - builder: "${{ steps.buildx.outputs.name }}" - context: "./" - push: false - load: true - tags: "${{ env.APP_NAME }}/nautobot:${{ matrix.nautobot-version }}-py${{ matrix.python-version }}" - file: "./development/Dockerfile" - cache-from: "type=gha,scope=${{ matrix.nautobot-version }}-py${{ matrix.python-version }}" - cache-to: "type=gha,scope=${{ matrix.nautobot-version }}-py${{ matrix.python-version }}" - build-args: | - NAUTOBOT_VER=${{ matrix.nautobot-version }} - PYTHON_VER=${{ matrix.python-version }} - - name: "Copy credentials" - run: "cp development/creds.example.env development/creds.env" + - name: "Checking: App Config" + run: "poetry run invoke validate-app-config" - name: "Checking: migrations" run: "poetry run invoke check-migrations" unittest: needs: - - "pylint" - - "check-migrations" + - "check-in-docker" strategy: fail-fast: true matrix: @@ -205,7 +165,7 @@ jobs: - name: "Check out repository code" uses: "actions/checkout@v4" - name: "Setup environment" - uses: "networktocode/gh-action-setup-poetry-environment@v4" + uses: "networktocode/gh-action-setup-poetry-environment@v6" - name: "Set up Docker Buildx" id: "buildx" uses: "docker/setup-buildx-action@v3" @@ -241,7 +201,7 @@ jobs: with: fetch-depth: "0" - name: "Setup environment" - uses: "networktocode/gh-action-setup-poetry-environment@v4" + uses: "networktocode/gh-action-setup-poetry-environment@v6" - name: "Check for changelog entry" run: | git fetch --no-tags origin +refs/heads/${{ github.base_ref }}:refs/remotes/origin/${{ github.base_ref }} @@ -258,7 +218,7 @@ jobs: - name: "Check out repository code" uses: "actions/checkout@v4" - name: "Set up Python" - uses: "actions/setup-python@v4" + uses: "actions/setup-python@v5" with: python-version: "3.11" - name: "Install Python Packages" @@ -293,7 +253,7 @@ jobs: - name: "Check out repository code" uses: "actions/checkout@v4" - name: "Set up Python" - uses: "actions/setup-python@v4" + uses: "actions/setup-python@v5" with: python-version: "3.11" - name: "Install Python Packages" diff --git a/changes/8.housekeeping b/changes/8.housekeeping new file mode 100644 index 00000000..653c54ac --- /dev/null +++ b/changes/8.housekeeping @@ -0,0 +1 @@ +Re-baked from the latest template. diff --git a/development/Dockerfile b/development/Dockerfile index 243db304..dbc52741 100644 --- a/development/Dockerfile +++ b/development/Dockerfile @@ -28,7 +28,7 @@ ENV INVOKE_NAUTOBOT_GOLDEN_CONFIG_LOCAL=true # Since this is only used for development and we don't ship this container, pinning Poetry back is not expressly necessary # We also don't need virtual environments in container RUN which poetry || curl -sSL https://install.python-poetry.org | python3 - && \ - poetry config virtualenvs.create false + poetry config virtualenvs.create false # !!! USE CAUTION WHEN MODIFYING LINES ABOVE # ------------------------------------------------------------------------------------- diff --git a/development/app_config_schema.py b/development/app_config_schema.py new file mode 100644 index 00000000..47009954 --- /dev/null +++ b/development/app_config_schema.py @@ -0,0 +1,64 @@ +"""App Config Schema Generator and Validator.""" +import json +from importlib import import_module +from os import getenv +from pathlib import Path +from urllib.parse import urlparse + +import jsonschema +import toml +from django.conf import settings +from to_json_schema.to_json_schema import SchemaBuilder + + +def _enrich_object_schema(schema, defaults, required): + schema["additionalProperties"] = False + for key, value in schema["properties"].items(): + if required and key in required: + value["required"] = True + default_value = defaults and defaults.get(key, None) + if value["type"] == "object" and "properties" in value: + _enrich_object_schema(value, default_value, None) + elif default_value is not None: + value["default"] = default_value + + +def _main(): + pyproject = toml.loads(Path("pyproject.toml").read_text()) + url = urlparse(pyproject["tool"]["poetry"]["repository"]) + _, owner, repository = url.path.split("/") + package_name = pyproject["tool"]["poetry"]["packages"][0]["include"] + app_config = settings.PLUGINS_CONFIG[package_name] # type: ignore + schema_path = Path(package_name) / "app-config-schema.json" + command = getenv("APP_CONFIG_SCHEMA_COMMAND", "") + if command == "generate": + schema = { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": f"https://raw.githubusercontent.com/{owner}/{repository}/develop/{package_name}/app-config-schema.json", + "$comment": "TBD: Update $id, replace `develop` with the future release tag", + **SchemaBuilder().to_json_schema(app_config), # type: ignore + } + app_config = import_module(package_name).config + _enrich_object_schema(schema, app_config.default_settings, app_config.required_settings) + schema_path.write_text(json.dumps(schema, indent=4) + "\n") + print(f"\n==================\nGenerated schema:\n\n{schema_path}\n") + print( + "WARNING: Review and edit the generated file before committing.\n" + "\n" + "Its content is inferred from:\n" + "\n" + "- The current configuration in `PLUGINS_CONFIG`\n" + "- `NautobotAppConfig.default_settings`\n" + "- `NautobotAppConfig.required_settings`" + ) + elif command == "validate": + schema = json.loads(schema_path.read_text()) + jsonschema.validate(app_config, schema) + print( + f"\n==================\nValidated configuration using the schema:\n{schema_path}\nConfiguration is valid." + ) + else: + raise RuntimeError(f"Unknown command: {command}") + + +_main() diff --git a/development/nautobot_config.py b/development/nautobot_config.py index 29bafe35..776bcd4e 100644 --- a/development/nautobot_config.py +++ b/development/nautobot_config.py @@ -92,11 +92,11 @@ "disable_existing_loggers": False, "formatters": { "normal": { - "format": "%(asctime)s.%(msecs)03d %(levelname)-7s %(name)s :\n %(message)s", + "format": "%(asctime)s.%(msecs)03d %(levelname)-7s %(name)s : %(message)s", "datefmt": "%H:%M:%S", }, "verbose": { - "format": "%(asctime)s.%(msecs)03d %(levelname)-7s %(name)-20s %(filename)-15s %(funcName)30s() :\n %(message)s", + "format": "%(asctime)s.%(msecs)03d %(levelname)-7s %(name)-20s %(filename)-15s %(funcName)30s() : %(message)s", "datefmt": "%H:%M:%S", }, }, diff --git a/development/towncrier_template.j2 b/development/towncrier_template.j2 index d2ec61bd..b0f6e12f 100644 --- a/development/towncrier_template.j2 +++ b/development/towncrier_template.j2 @@ -1,6 +1,6 @@ {% if render_title %} -## v{{ versiondata.version }} ({{ versiondata.date }}) +## [v{{ versiondata.version }} ({{ versiondata.date }})]({{ cookiecutter.repo_url }}/releases/tag/v{{ versiondata.version}}) {% endif %} {% for section, _ in sections.items() %} diff --git a/docs/admin/install.md b/docs/admin/install.md index 9a818399..49e4fdee 100644 --- a/docs/admin/install.md +++ b/docs/admin/install.md @@ -15,7 +15,7 @@ There are no access requirements from external systems to this app. ## Install Guide !!! note - Apps can be installed manually or using Python's `pip`. See the [nautobot documentation](https://nautobot.readthedocs.io/en/latest/plugins/#install-the-package) for more details. The pip package name for this app is [`nautobot-golden-config`](https://pypi.org/project/nautobot-golden-config/). + Apps can be installed from the [Python Package Index](https://pypi.org/) or locally. See the [Nautobot documentation](https://docs.nautobot.com/projects/core/en/stable/user-guide/administration/installation/app-install/) for more details. The pip package name for this app is [`nautobot-golden-config`](https://pypi.org/project/nautobot-golden-config/). The app is available as a Python package via PyPI and can be installed with `pip`: diff --git a/docs/dev/contributing.md b/docs/dev/contributing.md index 4d074e31..81d39853 100644 --- a/docs/dev/contributing.md +++ b/docs/dev/contributing.md @@ -43,36 +43,30 @@ All pull requests to `next` or `develop` must include a changelog fragment file The branching policy includes the following tenets: -- The `develop` branch is the branch for bug fixes. -- The `next` branch is the branch for new features. -- The `stable-.` branch is the branch of the latest version within that major/minor version. -- The `stable-.` branch will have all of the latest bug fixes and security patches, and may or may not represent the released version. -- PRs intended to add new features should be branched from and merged to the `next` branch. -- PRs intended to add new features that break backward compatibility should be discussed before a PR is created. -- PRs intended to address bug fixes and security patches should be branched from and merged to the `develop` branch. +- The `develop` branch is the branch of the next major and minor paired version planned. +- PRs intended to add new features should be sourced from the `develop` branch. +- PRs intended to fix issues in the Nautobot LTM compatible release should be sourced from the latest `ltm-` branch instead of `develop`. -Nautobot Golden Config will observe semantic versioning, as of 1.0. This may result in an quick turn around in minor versions to keep pace with an ever growing feature set. +Golden Config will observe semantic versioning, as of 1.0. This may result in a quick turnaround in minor versions to keep pace with an ever growing feature set. ## Release Policy -Nautobot Golden Config has currently no intended scheduled release schedule, and will release new features in minor versions. +Golden Config has currently no intended scheduled release schedule, and will release new features in minor versions. -When a new release of any kind (e.g. from `develop` to `main`, or a release of a `stable-.`) is created the following should happen. +When a new release, from `develop` to `main`, is created the following should happen. -- A release PR is created: - - Add and/or update to the changelog in `docs/admin/release_notes/version_..md` file to reflect the changes. - - Update the mkdocs.yml file to include updates when adding a new release_notes version file. - - Change the version from `..-beta` to `..` in pyproject.toml. - - Set the PR to the proper branch, e.g. either `main` or `stable-.`. +- A release PR is created from `develop` with: + - Update the release notes in `docs/admin/release_notes/version_..md` file to reflect the changes. + - Change the version from `..-beta` to `..` in `pyproject.toml`. + - Set the PR to the `main` branch. - Ensure the tests for the PR pass. - Merge the PR. - Create a new tag: - - The tag should be in the form of `v..`. - - The title should be in the form of `v..`. - - The description should be the changes that were added to the `version_..md` document. -- If merged into `main`, then push from `main` to `develop`, in order to retain the merge commit created when the PR was merged. -- If the is a new `.`, create a `stable-.` for the **previous** version, so that security updates to old versions may be applied more easily. -- A post release PR is created: - - Change the version from `..` to `..-beta` in pyproject.toml. - - Set the PR to the proper branch, e.g. either `develop` or `stable-.`. - - Once tests pass, merge. + - The tag should be in the form of `v..`. + - The title should be in the form of `v..`. + - The description should be the changes that were added to the `version_..md` document. +- If merged into `main`, then push from `main` to `develop`, in order to retain the merge commit created when the PR was merged +- A post release PR is created with: + - Change the version from `..` to `..-beta` in both `pyproject.toml` and `nautobot.__init__.__version__`. + - Set the PR to the proper branch, `develop`. + - Once tests pass, merge. diff --git a/docs/dev/dev_environment.md b/docs/dev/dev_environment.md index 8ff0c27d..95837814 100644 --- a/docs/dev/dev_environment.md +++ b/docs/dev/dev_environment.md @@ -74,7 +74,7 @@ nautobot-server migrate !!! note If you want to develop on the latest develop branch of Nautobot, run the following command: `poetry add --optional git+https://github.com/nautobot/nautobot@develop`. After the `@` symbol must match either a branch or a tag. -You can now run `nautobot-server` commands as you would from the [Nautobot documentation](https://nautobot.readthedocs.io/en/latest/) for example to start the development server: +You can now run `nautobot-server` commands as you would from the [Nautobot documentation](https://docs.nautobot.com/projects/core/en/stable/user-guide/administration/tools/nautobot-server/) for example to start the development server: ```shell nautobot-server runserver 0.0.0.0:8080 --insecure @@ -470,3 +470,21 @@ To run an individual test, you can run any or all of the following: ➜ invoke ruff ➜ invoke pylint ``` + +### App Configuration Schema + +In the package source, there is the `nautobot_golden_config/app-config-schema.json` file, conforming to the [JSON Schema](https://json-schema.org/) format. This file is used to validate the configuration of the app in CI pipelines. + +If you make changes to `PLUGINS_CONFIG` or the configuration schema, you can run the following command to validate the schema: + +```bash +invoke validate-app-config +``` + +To generate the `app-config-schema.json` file based on the current `PLUGINS_CONFIG` configuration, run the following command: + +```bash +invoke generate-app-config-schema +``` + +This command can only guess the schema, so it's up to the developer to manually update the schema as needed. diff --git a/mkdocs.yml b/mkdocs.yml index f08d1492..6fa13912 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -81,7 +81,11 @@ markdown_extensions: anchor_linenums: true - "pymdownx.inlinehilite" - "pymdownx.snippets" - - "pymdownx.superfences" + - "pymdownx.superfences": + custom_fences: + - name: "mermaid" + class: "mermaid" + format: !!python/name:pymdownx.superfences.fence_code_format - "footnotes" plugins: - "search" diff --git a/nautobot_golden_config/app-config-schema.json b/nautobot_golden_config/app-config-schema.json new file mode 100644 index 00000000..27ba77dd --- /dev/null +++ b/nautobot_golden_config/app-config-schema.json @@ -0,0 +1 @@ +true diff --git a/poetry.lock b/poetry.lock index ed134e5b..63c09da1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.1 and should not be changed by hand. [[package]] name = "amqp" @@ -4418,6 +4418,20 @@ files = [ future = "*" six = "*" +[[package]] +name = "to-json-schema" +version = "1.0.1" +description = "" +optional = false +python-versions = "*" +files = [ + {file = "to_json_schema-1.0.1-py3-none-any.whl", hash = "sha256:5708663f1c81815e4ff01fce910ac32ee3964d0c6b3587fd4fff2e38d5c9aa7b"}, + {file = "to_json_schema-1.0.1.tar.gz", hash = "sha256:ec747bd5129256dd571105f66a7bc9a4546228cd5e5fbf5e06dc9776e255400e"}, +] + +[package.extras] +testing = ["pytest", "pytest-cov", "setuptools"] + [[package]] name = "toml" version = "0.10.2" @@ -4785,4 +4799,4 @@ all = [] [metadata] lock-version = "2.0" python-versions = ">=3.8,<3.12" -content-hash = "f1896597c9887054c25a28518d6a5dbb9201c6a4f97920a953964a5dc33b363e" +content-hash = "2501da506f0545bd3c3000d3004ca3b46720d3233fa59e3b7b0b80c902d24cc4" diff --git a/pyproject.toml b/pyproject.toml index 2c10704b..d9ee991e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,6 +66,8 @@ mkdocs-version-annotations = "1.0.0" mkdocstrings = "0.22.0" mkdocstrings-python = "1.5.2" towncrier = "~23.6.0" +to-json-schema = "*" +jsonschema = "*" [tool.poetry.extras] all = [ @@ -171,7 +173,7 @@ requires = ["poetry_core>=1.0.0"] build-backend = "poetry.core.masonry.api" [tool.towncrier] -package = "nautobot" +package = "nautobot_golden_config" directory = "changes" filename = "docs/admin/release_notes/version_X.Y.md" template = "development/towncrier_template.j2" diff --git a/tasks.py b/tasks.py index d620399a..09bc977f 100644 --- a/tasks.py +++ b/tasks.py @@ -149,15 +149,27 @@ def docker_compose(context, command, **kwargs): def run_command(context, command, **kwargs): """Wrapper to run a command locally or inside the nautobot container.""" if is_truthy(context.nautobot_golden_config.local): + if "command_env" in kwargs: + kwargs["env"] = { + **kwargs.get("env", {}), + **kwargs.pop("command_env"), + } context.run(command, **kwargs) else: # Check if nautobot is running, no need to start another nautobot container to run a command docker_compose_status = "ps --services --filter status=running" results = docker_compose(context, docker_compose_status, hide="out") if "nautobot" in results.stdout: - compose_command = f"exec nautobot {command}" + compose_command = "exec" else: - compose_command = f"run --rm --entrypoint '{command}' nautobot" + compose_command = "run --rm --entrypoint=''" + + if "command_env" in kwargs: + command_env = kwargs.pop("command_env") + for key, value in command_env.items(): + compose_command += f' --env="{key}={value}"' + + compose_command += f" -- nautobot {command}" pty = kwargs.pop("pty", True) @@ -327,15 +339,22 @@ def logs(context, service="", follow=False, tail=0): # ------------------------------------------------------------------------------ # ACTIONS # ------------------------------------------------------------------------------ -@task(help={"file": "Python file to execute"}) -def nbshell(context, file=""): +@task( + help={ + "file": "Python file to execute", + "env": "Environment variables to pass to the command", + "plain": "Flag to run nbshell in plain mode (default: False)", + }, +) +def nbshell(context, file="", env={}, plain=False): """Launch an interactive nbshell session.""" command = [ "nautobot-server", "nbshell", + "--plain" if plain else "", f"< '{file}'" if file else "", ] - run_command(context, " ".join(command), pty=not bool(file)) + run_command(context, " ".join(command), pty=not bool(file), command_env=env) @task @@ -798,8 +817,33 @@ def tests(context, failfast=False, keepdb=False, lint_only=False): pylint(context) print("Running mkdocs...") build_and_check_docs(context) + print("Checking app config schema...") + validate_app_config(context) if not lint_only: print("Running unit tests...") unittest(context, failfast=failfast, keepdb=keepdb) unittest_coverage(context) print("All tests have passed!") + + +@task +def generate_app_config_schema(context): + """Generate the app config schema from the current app config. + + WARNING: Review and edit the generated file before committing. + + Its content is inferred from: + + - The current configuration in `PLUGINS_CONFIG` + - `NautobotAppConfig.default_settings` + - `NautobotAppConfig.required_settings` + """ + start(context, service="nautobot") + nbshell(context, file="development/app_config_schema.py", env={"APP_CONFIG_SCHEMA_COMMAND": "generate"}) + + +@task +def validate_app_config(context): + """Validate the app config based on the app config schema.""" + start(context, service="nautobot") + nbshell(context, plain=True, file="development/app_config_schema.py", env={"APP_CONFIG_SCHEMA_COMMAND": "validate"})