From 3b450c4fb752a4affa889532bf26d52fa6d451ae Mon Sep 17 00:00:00 2001 From: bakebot Date: Thu, 1 Feb 2024 14:57:46 +0000 Subject: [PATCH 1/4] 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.1.0", "path": null } ``` Cookie: ``` { "remote": "https://github.com/nautobot/nautobot-app-chatops.git", "path": "/tmp/tmp3t7nocrc/nautobot-app-chatops", "repository_path": "/tmp/tmp3t7nocrc/nautobot-app-chatops", "dir": "", "branch_prefix": "drift-manager", "context": { "codeowner_github_usernames": "@glennmatthews @jvanderaa @smk4664 @whitej6", "full_name": "Network to Code, LLC", "email": "opensource@networktocode.com", "github_org": "nautobot", "app_name": "nautobot_chatops", "verbose_name": "Nautobot ChatOps App", "app_slug": "nautobot-chatops", "project_slug": "nautobot-app-chatops", "repo_url": "https://github.com/nautobot/nautobot-app-chatops/", "base_url": "chatops", "min_nautobot_version": "2.0.0", "max_nautobot_version": "2.9999", "camel_name": "NautobotChatOpsApp", "project_short_description": "Nautobot ChatOps App", "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/chatops/en/latest", "_template": "https://github.com/nautobot/cookiecutter-nautobot-app.git", "_output_dir": "/tmp/tmp3t7nocrc", "_repo_dir": "/github/home/.cookiecutters/cookiecutter-nautobot-app/nautobot-app", "_checkout": "refs/tags/nautobot-app-v2.1.0" }, "base_branch": "develop", "remote_name": "origin", "pull_request_strategy": "PullRequestStrategy.CREATE", "post_actions": [ "PostAction.BLACK" ], "baked_commit_ref": "f7199da166a77ef00af4347535a1e09f939a711a", "draft": true } ``` CLI Arguments: ``` { "cookie_dir": "", "input": false, "json_filename": "", "output_dir": "", "push": true, "template": "", "template_dir": "", "template_ref": "refs/tags/nautobot-app-v2.1.0", "pull_request": null, "post_action": [], "disable_post_actions": false, "draft": null } ``` --- .cookiecutter.json | 4 +- .github/CODEOWNERS | 11 +- .../pull_request_template.md | 2 +- .github/workflows/ci.yml | 53 +++-- .github/workflows/rebake.yml | 118 ----------- LICENSE | 2 +- README.md | 46 +++-- development/Dockerfile | 4 +- development/docker-compose.base.yml | 6 +- development/docker-compose.dev.yml | 12 ++ development/nautobot_config.py | 3 - development/towncrier_template.j2 | 4 +- docs/admin/compatibility_matrix.md | 26 +-- docs/admin/install.md | 81 ++++++++ docs/admin/release_notes/version_1.0.md | 48 +++++ docs/admin/uninstall.md | 14 +- docs/admin/upgrade.md | 4 +- docs/assets/extra.css | 5 + docs/dev/arch_decision.md | 7 + docs/dev/contributing.md | 140 +------------ docs/dev/dev_environment.md | 11 +- docs/user/app_overview.md | 17 +- nautobot_chatops/__init__.py | 35 +--- nautobot_chatops/migrations/__init__.py | 0 nautobot_chatops/tests/test_api.py | 3 +- nautobot_chatops/tests/test_basic.py | 12 -- pyproject.toml | 184 ++++++++++-------- tasks.py | 158 ++++++++++++--- 28 files changed, 507 insertions(+), 503 deletions(-) delete mode 100644 .github/workflows/rebake.yml create mode 100644 docs/admin/install.md create mode 100644 docs/admin/release_notes/version_1.0.md create mode 100644 docs/dev/arch_decision.md delete mode 100644 nautobot_chatops/migrations/__init__.py diff --git a/.cookiecutter.json b/.cookiecutter.json index 1cd564a0..6e537e17 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": "develop", + "template_ref": "refs/tags/nautobot-app-v2.1.0", "cookie_dir": "", "branch_prefix": "drift-manager", "pull_request_strategy": "create", @@ -29,7 +29,7 @@ "black" ], "draft": true, - "baked_commit_ref": "f7199da166a77ef00af4347535a1e09f939a711a" + "baked_commit_ref": "4b6c888ec08af5233332d01d66b9f71c2f9368a8" } } } diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 9d83a2e6..e5d2e518 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,9 +1,2 @@ -# Default owners for all files in this repository -* @glennmatthews @jvanderaa @smk4664 @whitej6 @romanukes -/nautobot_chatops/integrations/aci/ @pato23arg -/nautobot_chatops/integrations/ansible/ @smk4664 -/nautobot_chatops/integrations/aristacv/ @qduk -/nautobot_chatops/integrations/grafana/ @davidban77 -/nautobot_chatops/integrations/meraki/ @jeffkala -/nautobot_chatops/integrations/ipfabric/ @alhogan @pke11y -/nautobot_chatops/integrations/panorama/ @jdrew82 +# Default owner(s) of all files in this repository +* @glennmatthews @jvanderaa @smk4664 @whitej6 diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md index b1eba070..31b4e282 100644 --- a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +++ b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md @@ -1,5 +1,5 @@ " +issue_format = "[#{issue}](https://github.com/nautobot/nautobot-app-chatops//issues/{issue})" + +[[tool.towncrier.type]] +directory = "security" +name = "Security" +showcontent = true + +[[tool.towncrier.type]] +directory = "added" +name = "Added" +showcontent = true + +[[tool.towncrier.type]] +directory = "changed" +name = "Changed" +showcontent = true + +[[tool.towncrier.type]] +directory = "deprecated" +name = "Deprecated" +showcontent = true + +[[tool.towncrier.type]] +directory = "removed" +name = "Removed" +showcontent = true + +[[tool.towncrier.type]] +directory = "fixed" +name = "Fixed" +showcontent = true + +[[tool.towncrier.type]] +directory = "dependencies" +name = "Dependencies" +showcontent = true + +[[tool.towncrier.type]] +directory = "documentation" +name = "Documentation" +showcontent = true + +[[tool.towncrier.type]] +directory = "housekeeping" +name = "Housekeeping" +showcontent = true diff --git a/tasks.py b/tasks.py index b2960e11..282a62a7 100644 --- a/tasks.py +++ b/tasks.py @@ -13,6 +13,8 @@ """ import os +from pathlib import Path +from time import sleep from invoke.collection import Collection from invoke.tasks import task as invoke_task @@ -21,7 +23,8 @@ def is_truthy(arg): """Convert "truthy" strings into Booleans. - Examples: + Examples + -------- >>> is_truthy('yes') True Args: @@ -69,6 +72,25 @@ def _is_compose_included(context, name): return f"docker-compose.{name}.yml" in context.nautobot_chatops.compose_files +def _await_healthy_service(context, service): + container_id = docker_compose(context, f"ps -q -- {service}", pty=False, echo=False, hide=True).stdout.strip() + _await_healthy_container(context, container_id) + + +def _await_healthy_container(context, container_id): + while True: + result = context.run( + "docker inspect --format='{{.State.Health.Status}}' " + container_id, + pty=False, + echo=False, + hide=True, + ) + if result.stdout.strip() == "healthy": + break + print(f"Waiting for `{container_id}` container to become healthy ...") + sleep(1) + + def task(function=None, *args, **kwargs): """Task decorator to override the default Invoke task decorator and add each task to the invoke namespace.""" @@ -92,6 +114,7 @@ def docker_compose(context, command, **kwargs): """Helper function for running a specific docker compose command with all appropriate parameters and environment. Args: + ---- context (obj): Used to run specific commands command (str): Command string to append to the "docker compose ..." command, such as "build", "up", etc. **kwargs: Passed through to the context.run() call. @@ -218,11 +241,46 @@ def stop(context, service=""): docker_compose(context, "stop" if service else "down --remove-orphans", service=service) -@task -def destroy(context): +@task( + aliases=("down",), + help={ + "volumes": "Remove Docker compose volumes (default: True)", + "import-db-file": "Import database from `import-db-file` file into the fresh environment (default: empty)", + }, +) +def destroy(context, volumes=True, import_db_file=""): """Destroy all containers and volumes.""" print("Destroying Nautobot...") - docker_compose(context, "down --remove-orphans --volumes") + docker_compose(context, f"down --remove-orphans {'--volumes' if volumes else ''}") + + if not import_db_file: + return + + if not volumes: + raise ValueError("Cannot specify `--no-volumes` and `--import-db-file` arguments at the same time.") + + print(f"Importing database file: {import_db_file}...") + + input_path = Path(import_db_file).absolute() + if not input_path.is_file(): + raise ValueError(f"File not found: {input_path}") + + command = [ + "run", + "--rm", + "--detach", + f"--volume='{input_path}:/docker-entrypoint-initdb.d/dump.sql'", + "--", + "db", + ] + + container_id = docker_compose(context, " ".join(command), pty=False, echo=False, hide=True).stdout.strip() + _await_healthy_container(context, container_id) + print("Stopping database container...") + context.run(f"docker stop {container_id}", pty=False, echo=False, hide=True) + + print("Database import complete, you can start Nautobot with the following command:") + print("invoke start") @task @@ -426,27 +484,43 @@ def dbshell(context, db_name="", input_file="", output_file="", query=""): @task( help={ + "db-name": "Database name to create (default: Nautobot database)", "input-file": "SQL dump file to replace the existing database with. This can be generated using `invoke backup-db` (default: `dump.sql`).", } ) -def import_db(context, input_file="dump.sql"): - """Stop Nautobot containers and replace the current database with the dump into the running `db` container.""" - docker_compose(context, "stop -- nautobot worker") +def import_db(context, db_name="", input_file="dump.sql"): + """Stop Nautobot containers and replace the current database with the dump into `db` container.""" + docker_compose(context, "stop -- nautobot worker beat") + start(context, "db") + _await_healthy_service(context, "db") command = ["exec -- db sh -c '"] if _is_compose_included(context, "mysql"): + if not db_name: + db_name = "$MYSQL_DATABASE" command += [ + "mysql --user root --password=$MYSQL_ROOT_PASSWORD", + '--execute="', + f"DROP DATABASE IF EXISTS {db_name};", + f"CREATE DATABASE {db_name};", + "" + if db_name == "$MYSQL_DATABASE" + else f"GRANT ALL PRIVILEGES ON {db_name}.* TO $MYSQL_USER; FLUSH PRIVILEGES;", + '"', + "&&", "mysql", - "--database=$MYSQL_DATABASE", + f"--database={db_name}", "--user=$MYSQL_USER", "--password=$MYSQL_PASSWORD", ] elif _is_compose_included(context, "postgres"): + if not db_name: + db_name = "$POSTGRES_DB" command += [ - "psql", - "--username=$POSTGRES_USER", - "postgres", + f"dropdb --if-exists --user=$POSTGRES_USER {db_name} &&", + f"createdb --user=$POSTGRES_USER {db_name} &&", + f"psql --user=$POSTGRES_USER --dbname={db_name}", ] else: raise ValueError("Unsupported database backend.") @@ -469,7 +543,10 @@ def import_db(context, input_file="dump.sql"): } ) def backup_db(context, db_name="", output_file="dump.sql", readable=True): - """Dump database into `output_file` file from running `db` container.""" + """Dump database into `output_file` file from `db` container.""" + start(context, "db") + _await_healthy_service(context, "db") + command = ["exec -- db sh -c '"] if _is_compose_included(context, "mysql"): @@ -477,17 +554,12 @@ def backup_db(context, db_name="", output_file="dump.sql", readable=True): "mysqldump", "--user=root", "--password=$MYSQL_ROOT_PASSWORD", - "--add-drop-database", "--skip-extended-insert" if readable else "", - "--databases", db_name if db_name else "$MYSQL_DATABASE", ] elif _is_compose_included(context, "postgres"): command += [ "pg_dump", - "--clean", - "--create", - "--if-exists", "--username=$POSTGRES_USER", f"--dbname={db_name or '$POSTGRES_DB'}", "--inserts" if readable else "", @@ -544,6 +616,19 @@ def help_task(context): context.run(f"invoke {task_name} --help") +@task( + help={ + "version": "Version of Nautobot ChatOps App to generate the release notes for.", + } +) +def generate_release_notes(context, version=""): + """Generate Release Notes using Towncrier.""" + command = "env DJANGO_SETTINGS_MODULE=nautobot.core.settings towncrier build" + if version: + command += f" --version {version}" + run_command(context, command) + + # ------------------------------------------------------------------------------ # TESTS # ------------------------------------------------------------------------------ @@ -585,12 +670,34 @@ def pylint(context): run_command(context, command) -@task -def pydocstyle(context): - """Run pydocstyle to validate docstring formatting adheres to NTC defined standards.""" - # We exclude the /migrations/ directory since it is autogenerated code - command = "pydocstyle ." - run_command(context, command) +@task(aliases=("a",)) +def autoformat(context): + """Run code autoformatting.""" + black(context, autoformat=True) + ruff(context, action="both", fix=True) + + +@task( + help={ + "action": "One of 'lint', 'format', or 'both'", + "fix": "Automatically fix selected action. May not be able to fix all.", + "output_format": "see https://docs.astral.sh/ruff/settings/#output-format", + }, +) +def ruff(context, action="lint", fix=False, output_format="text"): + """Run ruff to perform code formatting and/or linting.""" + if action != "lint": + command = "ruff format" + if not fix: + command += " --check" + command += " ." + run_command(context, command) + if action != "format": + command = "ruff check" + if fix: + command += " --fix" + command += f" --output-format {output_format} ." + run_command(context, command) @task @@ -605,6 +712,7 @@ def yamllint(context): """Run yamllint to validate formatting adheres to NTC defined YAML standards. Args: + ---- context (obj): Used to run specific commands """ command = "yamllint . --format standard" @@ -679,12 +787,12 @@ def tests(context, failfast=False, keepdb=False, lint_only=False): # Sorted loosely from fastest to slowest print("Running black...") black(context) + print("Running ruff...") + ruff(context) print("Running flake8...") flake8(context) print("Running bandit...") bandit(context) - print("Running pydocstyle...") - pydocstyle(context) print("Running yamllint...") yamllint(context) print("Running poetry check...") From a186fae1afd514e7d9c7d01e8c0fe38c7d7a8c41 Mon Sep 17 00:00:00 2001 From: Jan Snasel Date: Thu, 1 Feb 2024 15:34:45 +0000 Subject: [PATCH 2/4] chore: Manual fixes --- .github/CODEOWNERS | 9 +- README.md | 46 +++--- development/towncrier_template.j2 | 2 +- docs/admin/compatibility_matrix.md | 26 +++- docs/admin/install.md | 81 ---------- docs/admin/release_notes/version_1.0.md | 48 ------ docs/admin/upgrade.md | 4 +- docs/dev/arch_decision.md | 7 - docs/dev/contributing.md | 138 ++++++++++++++++++ docs/dev/dev_environment.md | 2 +- docs/user/app_overview.md | 17 +-- nautobot_chatops/__init__.py | 33 ++++- nautobot_chatops/integrations/__init__.py | 1 + .../integrations/grafana/__init__.py | 1 + nautobot_chatops/migrations/__init__.py | 0 nautobot_chatops/sockets/__init__.py | 1 + nautobot_chatops/tests/test_api.py | 3 +- pyproject.toml | 78 ++++++++-- tasks.py | 18 +-- 19 files changed, 299 insertions(+), 216 deletions(-) delete mode 100644 docs/admin/install.md delete mode 100644 docs/admin/release_notes/version_1.0.md delete mode 100644 docs/dev/arch_decision.md create mode 100644 nautobot_chatops/migrations/__init__.py diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index e5d2e518..33f44a03 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,2 +1,9 @@ # Default owner(s) of all files in this repository -* @glennmatthews @jvanderaa @smk4664 @whitej6 +* @glennmatthews @jvanderaa @smk4664 @whitej6 @romanukes +/nautobot_chatops/integrations/aci/ @pato23arg +/nautobot_chatops/integrations/ansible/ @smk4664 +/nautobot_chatops/integrations/aristacv/ @qduk +/nautobot_chatops/integrations/grafana/ @davidban77 +/nautobot_chatops/integrations/meraki/ @jeffkala +/nautobot_chatops/integrations/ipfabric/ @alhogan @pke11y +/nautobot_chatops/integrations/panorama/ @jdrew82 diff --git a/README.md b/README.md index df4f4503..5af700d6 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,33 @@ # Nautobot ChatOps

- +
- - + +
A multi-platform ChatOps bot App for Nautobot.

-## Overview - -> Developer Note: Add a long (2-3 paragraphs) description of what the App does, what problems it solves, what functionality it adds to Nautobot, what external systems it works with etc. - -### Screenshots - -> Developer Note: Add any representative screenshots of the App in action. These images should also be added to the `docs/user/app_use_cases.md` section. - -> Developer Note: Place the files in the `docs/images/` folder and link them using only full URLs from GitHub, for example: `![Overview](https://raw.githubusercontent.com/nautobot/nautobot-app-chatops/develop/docs/images/app-overview.png)`. This absolute static linking is required to ensure the README renders properly in GitHub, the docs site, and any other external sites like PyPI. - -More screenshots can be found in the [Using the App](https://docs.nautobot.com/projects/chatops/en/latest/user/app_use_cases/) page in the documentation. Here's a quick overview of some of the app's added functionality: - -![](https://raw.githubusercontent.com/nautobot/nautobot-app-chatops/develop/docs/images/placeholder.png) - -## Try it out! - -> Developer Note: Only keep this section if appropriate. Update link to correct sandbox. - -This App is installed in the Nautobot Community Sandbox found over at [demo.nautobot.com](https://demo.nautobot.com/)! - -> For a full list of all the available always-on sandbox environments, head over to the main page on [networktocode.com](https://www.networktocode.com/nautobot/sandbox-environments/). +- Support for multiple chat platforms: + - Mattermost + - Microsoft Teams + - Slack + - Cisco Webex +- Support for multiple integrations: + - Cisco ACI + - AWX / Ansible Tower + - Arista CloudVision + - Grafana + - IPFabric + - Cisco Meraki + - Palo Alto Panorama +- Write a command once and run it on every supported platform, including rich content formatting. +- Extensible - other Nautobot apps can provide additional commands which will be dynamically discovered. +- Automatic generation of basic help menus (accessed via `help`, `/command help`, or `/command sub-command help`). +- Metrics of command usage via the `nautobot_capacity_metrics` app. ## Documentation @@ -46,7 +42,7 @@ Full web-based HTML documentation for this app can be found over on the [Nautobo ## Try it Out -You can find all the Markdown source for the App documentation under the [`docs`](https://github.com/nautobot/nautobot-app-chatops//tree/develop/docs) folder in this repository. For simple edits, a Markdown capable editor is sufficient: clone the repository and edit away. +Interested to see Nautobot ChatOps in action? It's currently setup on the [Demo Instance](https://demo.nautobot.com/) and integrated into [NTC Slack](https://slack.networktocode.com). You can sign up for that Slack workspace and join the `#nautobot-chat` channel to understand what this bot can do and try it for yourself. You can try these exact chat commands and many more: ### Command: `/nautobot` diff --git a/development/towncrier_template.j2 b/development/towncrier_template.j2 index d2ec61bd..7010b057 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 }})](https://github.com/nautobot/nautobot-app-chatops/releases/tag/v{{ versiondata.version}}) {% endif %} {% for section, _ in sections.items() %} diff --git a/docs/admin/compatibility_matrix.md b/docs/admin/compatibility_matrix.md index 7494f0a4..c799cf60 100644 --- a/docs/admin/compatibility_matrix.md +++ b/docs/admin/compatibility_matrix.md @@ -1,8 +1,24 @@ # Compatibility Matrix -!!! warning "Developer Note - Remove Me!" - Explain how the release models of the app and of Nautobot work together, how releases are supported, how features and older releases are deprecated etc. +Changes to the support of upstream Nautobot releases will be announced 1 minor or major version ahead. -| Nautobot ChatOps App Version | Nautobot First Support Version | Nautobot Last Support Version | -| ------------- | -------------------- | ------------- | -| 1.0.X | 2.0.0 | 2.99.99 | +The **deprecation policy** will be announced within the [release notes](release_notes/index.md), and updated in the table below. There will be a `stable-.` branch that will be minimally maintained. Any security enhancements or major bugs in that branch will be supported for a limited time. + +While that last supported version will not be strictly enforced via the `max_version` setting, any issues with an updated Nautobot supported version in a minor release will require raising a bug and fixing it in Nautobot core, with no fixes expected in this app. This allows the Chatops app the ability to quickly take advantage of the latest features in Nautobot. + +| Chatops Version | Nautobot First Support Version | Nautobot Last Support Version | +| --------------- | ------------------------------ | ----------------------------- | +| 1.0.X | 1.0.0 | 1.2.99 [Official] | +| 1.1.X | 1.0.0 | 1.2.99 [Official] | +| 1.2.X | 1.0.0 | 1.2.99 [Official] | +| 1.3.X | 1.0.0 | 1.2.99 [Official] | +| 1.4.X | 1.0.0 | 1.2.99 [Official] | +| 1.5.X | 1.0.0 | 1.2.99 [Official] | +| 1.6.X | 1.0.0 | 1.2.99 [Official] | +| 1.7.X | 1.0.0 | 1.2.99 [Official] | +| 1.8.X | 1.1.0 | 1.4.99 [Official] | +| 1.9.X | 1.2.0 | 1.5.99 [Official] | +| 1.10.X | 1.3.0 | 1.5.99 [Official] | +| 2.0.X | 1.5.4 | 1.6.99 [Official] | +| 2.1.X | 1.6.2 | 1.6.99 [Official] | +| 3.0.X | 2.0.0 | 2.2.99 [Official] | diff --git a/docs/admin/install.md b/docs/admin/install.md deleted file mode 100644 index 5fa696c0..00000000 --- a/docs/admin/install.md +++ /dev/null @@ -1,81 +0,0 @@ -# Installing the App in Nautobot - -Here you will find detailed instructions on how to **install** and **configure** the App within your Nautobot environment. - -!!! warning "Developer Note - Remove Me!" - Detailed instructions on installing the App. You will need to update this section based on any additional dependencies or prerequisites. - -## Prerequisites - -- The app is compatible with Nautobot 2.0.0 and higher. -- Databases supported: PostgreSQL, MySQL - -!!! note - Please check the [dedicated page](compatibility_matrix.md) for a full compatibility matrix and the deprecation policy. - -### Access Requirements - -!!! warning "Developer Note - Remove Me!" - What external systems (if any) it needs access to in order to work. - -## 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-chatops`](https://pypi.org/project/nautobot-chatops/). - -The app is available as a Python package via PyPI and can be installed with `pip`: - -```shell -pip install nautobot-chatops -``` - -To ensure Nautobot ChatOps App is automatically re-installed during future upgrades, create a file named `local_requirements.txt` (if not already existing) in the Nautobot root directory (alongside `requirements.txt`) and list the `nautobot-chatops` package: - -```shell -echo nautobot-chatops >> local_requirements.txt -``` - -Once installed, the app needs to be enabled in your Nautobot configuration. The following block of code below shows the additional configuration required to be added to your `nautobot_config.py` file: - -- Append `"nautobot_chatops"` to the `PLUGINS` list. -- Append the `"nautobot_chatops"` dictionary to the `PLUGINS_CONFIG` dictionary and override any defaults. - -```python -# In your nautobot_config.py -PLUGINS = ["nautobot_chatops"] - -# PLUGINS_CONFIG = { -# "nautobot_chatops": { -# ADD YOUR SETTINGS HERE -# } -# } -``` - -Once the Nautobot configuration is updated, run the Post Upgrade command (`nautobot-server post_upgrade`) to run migrations and clear any cache: - -```shell -nautobot-server post_upgrade -``` - -Then restart (if necessary) the Nautobot services which may include: - -- Nautobot -- Nautobot Workers -- Nautobot Scheduler - -```shell -sudo systemctl restart nautobot nautobot-worker nautobot-scheduler -``` - -## App Configuration - -!!! warning "Developer Note - Remove Me!" - Any configuration required to get the App set up. Edit the table below as per the examples provided. - -The app behavior can be controlled with the following list of settings: - -| Key | Example | Default | Description | -| ------- | ------ | -------- | ------------------------------------- | -| `enable_backup` | `True` | `True` | A boolean to represent whether or not to run backup configurations within the app. | -| `platform_slug_map` | `{"cisco_wlc": "cisco_aireos"}` | `None` | A dictionary in which the key is the platform slug and the value is what netutils uses in any "network_os" parameter. | -| `per_feature_bar_width` | `0.15` | `0.15` | The width of the table bar within the overview report | diff --git a/docs/admin/release_notes/version_1.0.md b/docs/admin/release_notes/version_1.0.md deleted file mode 100644 index f1f4f4c2..00000000 --- a/docs/admin/release_notes/version_1.0.md +++ /dev/null @@ -1,48 +0,0 @@ -# v1.0 Release Notes - -!!! warning "Developer Note - Remove Me!" - Guiding Principles: - - - Changelogs are for humans, not machines. - - There should be an entry for every single version. - - The same types of changes should be grouped. - - Versions and sections should be linkable. - - The latest version comes first. - - The release date of each version is displayed. - - Mention whether you follow Semantic Versioning. - - Types of changes: - - - `Added` for new features. - - `Changed` for changes in existing functionality. - - `Deprecated` for soon-to-be removed features. - - `Removed` for now removed features. - - `Fixed` for any bug fixes. - - `Security` in case of vulnerabilities. - - -This document describes all new features and changes in the release `1.0`. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## Release Overview - -- Major features or milestones -- Achieved in this `x.y` release -- Changes to compatibility with Nautobot and/or other apps, libraries etc. - -## [v1.0.1] - 2021-09-08 - -### Added - -### Changed - -### Fixed - -- [#123](https://github.com/nautobot/nautobot-app-chatops//issues/123) Fixed Tag filtering not working in job launch form - -## [v1.0.0] - 2021-08-03 - -### Added - -### Changed - -### Fixed diff --git a/docs/admin/upgrade.md b/docs/admin/upgrade.md index eba97c56..6c8becb4 100644 --- a/docs/admin/upgrade.md +++ b/docs/admin/upgrade.md @@ -6,4 +6,6 @@ Here you will find any steps necessary to upgrade the App in your Nautobot envir When a new release comes out it may be necessary to run a migration of the database to account for any changes in the data models used by this app. Execute the command `nautobot-server post_upgrade` within the runtime environment of your Nautobot installation after updating the `nautobot-chatops` package via `pip`. -When a new release comes out it may be necessary to run a migration of the database to account for any changes in the data models used by this app. Execute the command `nautobot-server post-upgrade` within the runtime environment of your Nautobot installation after updating the `nautobot-chatops` package via `pip`. +### Upgrading to ChatOps 3.0 + +Introduced in 3.0.0 is [Account Linking](../models/chatopsaccountlink.md), users will now need to link their Chat Platform User with their Nautobot User. Until this is done, the `fallback_chatops_user` setting controls the default Nautobot User and should have proper Nautobot Permissions applied. diff --git a/docs/dev/arch_decision.md b/docs/dev/arch_decision.md deleted file mode 100644 index 6a68035d..00000000 --- a/docs/dev/arch_decision.md +++ /dev/null @@ -1,7 +0,0 @@ -# Architecture Decision Records - -The intention is to document deviations from a standard Model View Controller (MVC) design. - -!!! warning "Developer Note - Remove Me!" - Optional page, remove if not applicable. - For examples see [Golden Config](https://github.com/nautobot/nautobot-plugin-golden-config/tree/develop/docs/dev/dev_adr.md). diff --git a/docs/dev/contributing.md b/docs/dev/contributing.md index b6277a4d..1d03330e 100644 --- a/docs/dev/contributing.md +++ b/docs/dev/contributing.md @@ -39,6 +39,144 @@ All pull requests to `next` or `develop` must include a changelog fragment file Changed release notes generation. ``` +## Adding a new top-level command + +First, you should be familiar with the design goals and constraints involved in Nautobot (`design.md`). +Be sure that this is really what you want to do, versus adding a sub-command instead. + +We recommend that each command exist as its own submodule under `nautobot_chatops/workers/` (or, as a separate package +entirely, such as `nautobot_chatops_mycommand/worker.py`, using the `entrypoint/plugin` capability described in `design.md`) +to keep code files to a reasonable size and complexity. This submodule or package should implement a +`celery` worker function(s). In general this worker function shouldn't need to do much more than call +the `handle_subcommands` helper function provided: + +```python +# nautobot_chatops/workers/mycommand.py + +from nautobot_chatops.workers import handle_subcommands, subcommand_of + + +def mycommand(subcommand, **kwargs) + """Perform mycommand and its subcommands.""" + return handle_subcommands("mycommand", subcommand, **kwargs) +``` + +By using `handle_subcommands`, the top-level command worker will automatically recognize the sub-command "help", +as well as any sub-commands registered using the `@subcommand_of` decorator. + +You shouldn't need to make any changes to the `views` or `dispatchers` modules in this scenario. + +For usability, you should use the App Studio app in the Microsoft Teams client to update the bot settings +(`Nautobot_ms_teams.zip`) to include this new top-level command as a documented command supported by the bot. +You will probably then need to delete the bot deployment from your team and re-deploy it for the new command to appear. + +You will also need to log in to api.slack.com and add the new slash-command to your bot's configuration. + +## Adding a new sub-command + +First, you should be familiar with the design goals and constraints involved in Nautobot (`design.md`). + +To register a sub-command, write a function whose name matches the sub-command's name (any `_` in the function name +will be automatically converted to `-` for the sub-command name), and decorate it with the `@subcommand_of` decorator. +This function must take `dispatcher` (an instance of any `Dispatcher` subclass) as its first argument; any additional +positional arguments become arguments in the chat app UI. The docstring of this function will become the help text +displayed for this sub-command when a user invokes ` help`, so it should be concise and to the point. + +```python +from nautobot_chatops.workers import subcommand_of + +# ... + +@subcommand_of("mycommand") +def do_something(dispatcher, first_arg, second_arg): + """Do something with two arguments.""" + # ... +``` + +With the above code, the command `mycommand do_something [first_arg] [second_arg]` will now be available. + +You shouldn't need to make any changes to the `views` or `dispatchers` modules in this scenario. + +A sub-command worker function should always return one of the following: + +### `return False` + +This indicates that the function did not do anything meaningful, and it so should not be logged in Nautobot's +command log. Typically, this is only returned when not all required parameters have been provided by the user +and so the function needs to prompt the user for additional inputs, for example: + +```python +@subcommand_of("nautobot") +def get_rack(dispatcher, site_key, rack_id): + """Get information about a specific rack from Nautobot.""" + site_lt = LocationType.objects.get(name="Site") + if not site_key: + site_options = [(site.name, site.composite_key) for site in Location.objects.filter(location_type=site_lt)] + dispatcher.prompt_from_menu("nautobot get-rack", "Select a site (location)", site_options) + return False # command did not run to completion and therefore should not be logged + ... +``` + +### `return CommandStatusChoices.STATUS_SUCCEEDED` + +This indicates that the command was successful, and no further details are necessary in the logging. +You *could* return another status code besides `STATUS_SUCCEEDED` in this pattern, but in general any other status +code should be accompanied by an explanatory message: + +### `return (CommandStatusChoices.STATUS_FAILED, details_str)` + +This indicates that the command failed for some reason, which is provided for logging purposes. +You could also use other status codes (including `STATUS_SUCCEEDED`) for any other outcome that also requires +explanation. + +The provided `details_str` will be stored in the Nautobot command log history. + +## Adding support for a new chat platform (Webhooks) + +First, you should be familiar with the design goals and constraints involved in Nautobot (`design.md`). + +You'll need to add a new `nautobot_chatops.views.` submodule that provides any necessary API endpoints. + +You'll also need to add a new `nautobot_chatops.dispatchers.` submodule that implements an appropriate +subclass of `Dispatcher`. This new dispatcher class will need to implement any abstract methods of the base class +and override any other methods where platform-specific behavior is required (which will probably be most of them). + +You shouldn't need to make any changes to the `workers` module in this scenario. + +## Adding support for a new chat platform (WebSockets) + +First, you should be familiar with the design goals and constraints involved in Nautobot (`design.md`). + +You'll need to add a new `nautobot_chatops.sockets.` submodule that provides the necessary WebSockets connection to the Platform. + +You'll also need to add a new `nautobot_chatops.dispatchers.` submodule that implements an appropriate +subclass of `Dispatcher`. This new dispatcher class will need to implement any abstract methods of the base class +and override any other methods where platform-specific behavior is required (which will probably be most of them). + +Finally, you will need to add a new `nautobot_chatops.management.start__socket` management command that will start the WebSockets asynchronous loop. +In 2.0 these will likely be condensed to use a single base command with arguments to select the platform. + +You shouldn't need to make any changes to the `workers` module in this scenario. + +## Submitting Pull Requests + +- It is recommended to open an issue **before** starting work on a pull request, and discuss your idea with the Nautobot maintainers before beginning work. This will help prevent wasting time on something that we might not be able to implement. When suggesting a new feature, also make sure it won't conflict with any work that's already in progress. + +- Once you've opened or identified an issue you'd like to work on, ask that it + be assigned to you so that others are aware it's being worked on. A maintainer + will then mark the issue as "accepted." + +- If you followed the project guidelines, have ample tests, code quality, you will first be acknowledged for your work. So, thank you in advance! After that, the PR will be quickly reviewed to ensure that it makes sense as a contribution to the project, and to gauge the work effort or issues with merging into *current*. If the effort required by the core team isn’t trivial, it’ll likely still be a few weeks before it gets thoroughly reviewed and merged, thus it won't be uncommon to move it to *near term* with a `near-term` label. It will just depend on the current backlog. + +- All code submissions should meet the following criteria (CI will enforce +these checks): + - Python syntax is valid + - All unit tests pass successfully + - PEP 8 compliance is enforced, with the exception that lines may be + greater than 80 characters in length + - At least one [changelog fragment](#creating-changelog-fragments) has + been included in the feature branch + ## Branching Policy The branching policy includes the following tenets: diff --git a/docs/dev/dev_environment.md b/docs/dev/dev_environment.md index 80b02327..9a9a458e 100644 --- a/docs/dev/dev_environment.md +++ b/docs/dev/dev_environment.md @@ -368,7 +368,7 @@ Once the dependencies are resolved, stop the existing containers, rebuild the Do ### Installing Additional Nautobot Apps -Let's say for example you want the new app you're creating to integrate into Slack. To do this, you will want to integrate into the existing Nautobot ChatOps App. +Let's say for example you want the new app you're creating to integrate into Nautobot ChatOps. To do this, you will want to integrate into the existing Nautobot ChatOps App. ```bash ➜ poetry shell diff --git a/docs/user/app_overview.md b/docs/user/app_overview.md index 29247449..0e8a188f 100644 --- a/docs/user/app_overview.md +++ b/docs/user/app_overview.md @@ -23,16 +23,7 @@ The ChatOps framework provides Network Engineers power to query Nautobot or thei ## Authors and Maintainers -!!! warning "Developer Note - Remove Me!" - Add the team and/or the main individuals maintaining this project. Include historical maintainers as well. - -## Nautobot Features Used - -!!! warning "Developer Note - Remove Me!" - What is shown today in the Installed Apps page in Nautobot. What parts of Nautobot does it interact with, what does it add etc. ? - -### Extras - -!!! warning "Developer Note - Remove Me!" - Custom Fields - things like which CFs are created by this app? - Jobs - are jobs, if so, which ones, installed by this app? +- Glenn Matthews (@glennmatthews) +- Josh VanDeraa (@jvanderaa) +- Jeremy White (@whitej6) +- Stephen Kiely (@smk4664) diff --git a/nautobot_chatops/__init__.py b/nautobot_chatops/__init__.py index a3c495a0..b191b59e 100644 --- a/nautobot_chatops/__init__.py +++ b/nautobot_chatops/__init__.py @@ -2,12 +2,36 @@ # Metadata is inherited from Nautobot. If not including Nautobot in the environment, this should be added from importlib import metadata -from nautobot.apps import NautobotAppConfig +from django.conf import settings +from nautobot.apps import ConstanceConfigItem, NautobotAppConfig __version__ = metadata.version(__name__) -class NautobotChatOpsAppConfig(NautobotAppConfig): +_CONFLICTING_APP_NAMES = [ + # App names that conflict with nautobot_chatops + "nautobot_plugin_chatops_aci", + "nautobot_plugin_chatops_ansible", + "nautobot_plugin_chatops_aristacv", + "nautobot_plugin_chatops_grafana", + "nautobot_plugin_chatops_ipfabric", + "nautobot_plugin_chatops_meraki", + "nautobot_plugin_chatops_panorama", +] + + +def _check_for_conflicting_apps(): + intersection = set(_CONFLICTING_APP_NAMES).intersection(set(settings.PLUGINS)) + if intersection: + raise RuntimeError( + f"The following apps are installed and conflict with `nautobot-chatops`: {', '.join(intersection)}." + ) + + +_check_for_conflicting_apps() + + +class NautobotChatOpsConfig(NautobotAppConfig): """App configuration for the nautobot_chatops app.""" name = "nautobot_chatops" @@ -129,4 +153,7 @@ def ready(self): from nautobot_capacity_metrics import register_metric_func from .metrics_app import metric_commands -config = NautobotChatOpsAppConfig # pylint:disable=invalid-name + register_metric_func(metric_commands) + + +config = NautobotChatOpsConfig # pylint:disable=invalid-name diff --git a/nautobot_chatops/integrations/__init__.py b/nautobot_chatops/integrations/__init__.py index e69de29b..9c158ba0 100644 --- a/nautobot_chatops/integrations/__init__.py +++ b/nautobot_chatops/integrations/__init__.py @@ -0,0 +1 @@ +"""Nautobot ChatOps Integrations.""" diff --git a/nautobot_chatops/integrations/grafana/__init__.py b/nautobot_chatops/integrations/grafana/__init__.py index e69de29b..10a07da3 100644 --- a/nautobot_chatops/integrations/grafana/__init__.py +++ b/nautobot_chatops/integrations/grafana/__init__.py @@ -0,0 +1 @@ +"""Nautobot ChatOps Graphana Integration.""" diff --git a/nautobot_chatops/migrations/__init__.py b/nautobot_chatops/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/nautobot_chatops/sockets/__init__.py b/nautobot_chatops/sockets/__init__.py index e69de29b..c63edf0d 100644 --- a/nautobot_chatops/sockets/__init__.py +++ b/nautobot_chatops/sockets/__init__.py @@ -0,0 +1 @@ +"""Nautobot ChatOps Sockets.""" diff --git a/nautobot_chatops/tests/test_api.py b/nautobot_chatops/tests/test_api.py index 4508c7c5..3113ce4e 100644 --- a/nautobot_chatops/tests/test_api.py +++ b/nautobot_chatops/tests/test_api.py @@ -7,8 +7,7 @@ from nautobot_chatops.models import AccessGrant, CommandToken -class PlaceholderAPITest(TestCase): - """Test the NautobotChatOpsApp API.""" +nautobot_version = metadata.version("nautobot") class AppTest(APITestCase): # pylint: disable=too-many-ancestors diff --git a/pyproject.toml b/pyproject.toml index 4dfc1eeb..77230393 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -70,6 +70,7 @@ texttable = "^1.6.2" webexteamssdk = "^1.3" [tool.poetry.group.dev.dependencies] +Markdown = "*" bandit = "*" black = "*" coverage = "~5.4" @@ -77,27 +78,79 @@ django-debug-toolbar = "*" flake8 = "*" invoke = "*" ipython = "*" -pylint = "*" -pylint-django = "*" -pylint-nautobot = "*" -ruff = "*" -yamllint = "*" -toml = "*" -Markdown = "*" -# Rendering docs to HTML mkdocs = "1.5.2" -# Material for MkDocs theme +mkdocs-include-markdown-plugin = "6.0.3" mkdocs-material = "9.1.15" -# Render custom markdown for version added/changed/remove notes mkdocs-version-annotations = "1.0.0" -# Automatic documentation from sources, for MkDocs mkdocstrings = "0.22.0" mkdocstrings-python = "1.5.2" +prybar = "*" +pylint = "*" +pylint-django = "*" +pylint-nautobot = "*" +requests-mock = "^1.9.3" +ruff = "*" +toml = "*" towncrier = "~23.6.0" +yamllint = "*" [tool.poetry.extras] all = [ + "PyYAML", + "certifi", + "cloudvision", + "cvprac", + "defusedxml", + "diffsync", + "ipaddr", + "ipfabric", + "ipfabric-diagrams", + "isodate", + "meraki", + "netmiko", + "netutils", + "pan-os-python", + "prettytable", + "protobuf", + "pydantic", + "schema-enforcer", + "termcolor", +] +aci = [ + "prettytable", +] +aristacv = [ + "certifi", + "cloudvision", + "cvprac", + "protobuf" +] +ansible = [ + "PyYAML", ] +grafana = [ + "diffsync", + "isodate", + "pydantic", + "schema-enforcer", + "termcolor", +] +ipfabric = [ + "ipfabric", + "ipfabric-diagrams", + "netutils", +] +meraki = [ + "meraki", +] +panorama = [ + "defusedxml", + "ipaddr", + "netmiko", + "netutils", + "pan-os-python", +] +nautobot = ["nautobot"] [tool.black] line-length = 120 @@ -183,6 +236,9 @@ ignore = [ "D401", # First line of docstring should be in imperative mood "D407", # Missing dashed underline after section "D416", # Section name ends in colon + + # Package specific + "D417", # Missing argument descriptions in Docstrings ] [tool.ruff.lint.pydocstyle] diff --git a/tasks.py b/tasks.py index 282a62a7..8891db05 100644 --- a/tasks.py +++ b/tasks.py @@ -23,8 +23,7 @@ def is_truthy(arg): """Convert "truthy" strings into Booleans. - Examples - -------- + Examples: >>> is_truthy('yes') True Args: @@ -114,7 +113,6 @@ def docker_compose(context, command, **kwargs): """Helper function for running a specific docker compose command with all appropriate parameters and environment. Args: - ---- context (obj): Used to run specific commands command (str): Command string to append to the "docker compose ..." command, such as "build", "up", etc. **kwargs: Passed through to the context.run() call. @@ -712,7 +710,6 @@ def yamllint(context): """Run yamllint to validate formatting adheres to NTC defined YAML standards. Args: - ---- context (obj): Used to run specific commands """ command = "yamllint . --format standard" @@ -859,16 +856,3 @@ def connect_awx_container(context, container_name="tools_awx_1"): bridge_network = f"{context.nautobot_chatops.project_name}_awx" context.run(f"docker network connect --alias awx {bridge_network} {container_name}") print(f"Container {container_name} connected to {bridge_network} network") - - -@task( - help={ - "version": "Version of Nautobot ChatOps to generate the release notes for.", - } -) -def generate_release_notes(context, version=""): - """Generate Release Notes using Towncrier.""" - command = "env DJANGO_SETTINGS_MODULE=nautobot.core.settings towncrier build" - if version: - command += f" --version {version}" - run_command(context, command) From a98b2e5c18dea08ecc86e76f186d0b9741714cbf Mon Sep 17 00:00:00 2001 From: Jan Snasel Date: Thu, 1 Feb 2024 15:37:28 +0000 Subject: [PATCH 3/4] chore: Poetry lock --- poetry.lock | 89 ++++++++++++++++++++++------------------------------- 1 file changed, 36 insertions(+), 53 deletions(-) diff --git a/poetry.lock b/poetry.lock index cec3f276..88348e98 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "aiodns" @@ -3409,23 +3409,6 @@ typing-extensions = ">=4.2.0" dotenv = ["python-dotenv (>=0.10.4)"] email = ["email-validator (>=1.0.3)"] -[[package]] -name = "pydocstyle" -version = "6.3.0" -description = "Python docstring style checker" -optional = false -python-versions = ">=3.6" -files = [ - {file = "pydocstyle-6.3.0-py3-none-any.whl", hash = "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019"}, - {file = "pydocstyle-6.3.0.tar.gz", hash = "sha256:7ce43f0c0ac87b07494eb9c0b462c0b73e6ff276807f204d6b53edc72b7e44e1"}, -] - -[package.dependencies] -snowballstemmer = ">=2.2.0" - -[package.extras] -toml = ["tomli (>=1.2.3)"] - [[package]] name = "pyflakes" version = "2.3.1" @@ -4141,7 +4124,8 @@ files = [ {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-win32.whl", hash = "sha256:763d65baa3b952479c4e972669f679fe490eee058d5aa85da483ebae2009d231"}, {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:d000f258cf42fec2b1bbf2863c61d7b8918d31ffee905da62dede869254d3b8a"}, {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:045e0626baf1c52e5527bd5db361bc83180faaba2ff586e763d3d5982a876a9e"}, - {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-macosx_12_6_arm64.whl", hash = "sha256:721bc4ba4525f53f6a611ec0967bdcee61b31df5a56801281027a3a6d1c2daf5"}, + {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:1a6391a7cabb7641c32517539ca42cf84b87b667bad38b78d4d42dd23e957c81"}, + {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:9c7617df90c1365638916b98cdd9be833d31d337dbcd722485597b43c4a215bf"}, {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:41d0f1fa4c6830176eef5b276af04c89320ea616655d01327d5ce65e50575c94"}, {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-win32.whl", hash = "sha256:f6d3d39611ac2e4f62c3128a9eed45f19a6608670c5a2f4f07f24e8de3441d38"}, {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:da538167284de58a52109a9b89b8f6a53ff8437dd6dc26d33b57bf6699153122"}, @@ -4172,6 +4156,32 @@ files = [ {file = "ruamel.yaml.clib-0.2.7.tar.gz", hash = "sha256:1f08fd5a2bea9c4180db71678e850b995d2a5f4537be0e94557668cf0f5f9497"}, ] +[[package]] +name = "ruff" +version = "0.1.15" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.1.15-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:5fe8d54df166ecc24106db7dd6a68d44852d14eb0729ea4672bb4d96c320b7df"}, + {file = "ruff-0.1.15-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6f0bfbb53c4b4de117ac4d6ddfd33aa5fc31beeaa21d23c45c6dd249faf9126f"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0d432aec35bfc0d800d4f70eba26e23a352386be3a6cf157083d18f6f5881c8"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9405fa9ac0e97f35aaddf185a1be194a589424b8713e3b97b762336ec79ff807"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c66ec24fe36841636e814b8f90f572a8c0cb0e54d8b5c2d0e300d28a0d7bffec"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:6f8ad828f01e8dd32cc58bc28375150171d198491fc901f6f98d2a39ba8e3ff5"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86811954eec63e9ea162af0ffa9f8d09088bab51b7438e8b6488b9401863c25e"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fd4025ac5e87d9b80e1f300207eb2fd099ff8200fa2320d7dc066a3f4622dc6b"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b17b93c02cdb6aeb696effecea1095ac93f3884a49a554a9afa76bb125c114c1"}, + {file = "ruff-0.1.15-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ddb87643be40f034e97e97f5bc2ef7ce39de20e34608f3f829db727a93fb82c5"}, + {file = "ruff-0.1.15-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:abf4822129ed3a5ce54383d5f0e964e7fef74a41e48eb1dfad404151efc130a2"}, + {file = "ruff-0.1.15-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6c629cf64bacfd136c07c78ac10a54578ec9d1bd2a9d395efbee0935868bf852"}, + {file = "ruff-0.1.15-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1bab866aafb53da39c2cadfb8e1c4550ac5340bb40300083eb8967ba25481447"}, + {file = "ruff-0.1.15-py3-none-win32.whl", hash = "sha256:2417e1cb6e2068389b07e6fa74c306b2810fe3ee3476d5b8a96616633f40d14f"}, + {file = "ruff-0.1.15-py3-none-win_amd64.whl", hash = "sha256:3837ac73d869efc4182d9036b1405ef4c73d9b1f88da2413875e34e0d6919587"}, + {file = "ruff-0.1.15-py3-none-win_arm64.whl", hash = "sha256:9a933dfb1c14ec7a33cceb1e49ec4a16b51ce3c20fd42663198746efc0427360"}, + {file = "ruff-0.1.15.tar.gz", hash = "sha256:f6dfa8c1b21c913c326919056c390966648b680966febcb796cc9d1aaab8564e"}, +] + [[package]] name = "rx" version = "1.6.3" @@ -4224,22 +4234,6 @@ files = [ [package.dependencies] paramiko = "*" -[[package]] -name = "setuptools" -version = "68.2.2" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -optional = false -python-versions = ">=3.8" -files = [ - {file = "setuptools-68.2.2-py3-none-any.whl", hash = "sha256:b454a35605876da60632df1a60f736524eb73cc47bbc9f3f1ef1b644de74fd2a"}, - {file = "setuptools-68.2.2.tar.gz", hash = "sha256:4ac1475276d2f1c48684874089fefcd83bd7162ddaafb81fac866ba0db282a87"}, -] - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] - [[package]] name = "singledispatch" version = "4.1.0" @@ -4303,17 +4297,6 @@ files = [ {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, ] -[[package]] -name = "snowballstemmer" -version = "2.2.0" -description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." -optional = false -python-versions = "*" -files = [ - {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, - {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, -] - [[package]] name = "social-auth-app-django" version = "5.2.0" @@ -4515,25 +4498,25 @@ files = [ [[package]] name = "towncrier" -version = "22.8.0" +version = "23.6.0" description = "Building newsfiles for your project." optional = false python-versions = ">=3.7" files = [ - {file = "towncrier-22.8.0-py2.py3-none-any.whl", hash = "sha256:3b780c3d966e1b26414830aec3d15000654b31e64e024f3e5fd128b4c6eb8f47"}, - {file = "towncrier-22.8.0.tar.gz", hash = "sha256:7d3839b033859b45fb55df82b74cfd702431933c0cc9f287a5a7ea3e05d042cb"}, + {file = "towncrier-23.6.0-py3-none-any.whl", hash = "sha256:da552f29192b3c2b04d630133f194c98e9f14f0558669d427708e203fea4d0a5"}, + {file = "towncrier-23.6.0.tar.gz", hash = "sha256:fc29bd5ab4727c8dacfbe636f7fb5dc53b99805b62da1c96b214836159ff70c1"}, ] [package.dependencies] click = "*" click-default-group = "*" +importlib-resources = {version = ">=5", markers = "python_version < \"3.10\""} incremental = "*" jinja2 = "*" -setuptools = "*" -tomli = "*" +tomli = {version = "*", markers = "python_version < \"3.11\""} [package.extras] -dev = ["packaging"] +dev = ["furo", "packaging", "sphinx (>=5)", "twisted"] [[package]] name = "traitlets" @@ -4997,4 +4980,4 @@ panorama = ["defusedxml", "ipaddr", "netmiko", "netutils", "pan-os-python"] [metadata] lock-version = "2.0" python-versions = ">=3.8,<3.12" -content-hash = "ab7d4f0eab523ac12ffe5ed51c5764fc1fb4e477c8ff161753a984db7d495722" +content-hash = "9edc678921261739f715585db93b205eb9d4e92b525c11a27d87dbe7625d1196" From c5bc13b8fc813a500f0d361878be896bb58b4f24 Mon Sep 17 00:00:00 2001 From: Jan Snasel Date: Thu, 1 Feb 2024 15:37:35 +0000 Subject: [PATCH 4/4] chore: Changelog fragment --- changes/297.changed | 1 + 1 file changed, 1 insertion(+) create mode 100644 changes/297.changed diff --git a/changes/297.changed b/changes/297.changed new file mode 100644 index 00000000..7a7cdde0 --- /dev/null +++ b/changes/297.changed @@ -0,0 +1 @@ +Replaced pydocstyle with ruff.