From 8d51840518fc0a4910206d6a10a3c6b1b2ef3cfa Mon Sep 17 00:00:00 2001 From: bakebot Date: Thu, 12 Feb 2026 17:03:49 +0000 Subject: [PATCH 1/7] Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool Template: ``` { "template": "https://github.com/networktocode-llc/cookiecutter-ntc.git", "dir": "python", "ref": "main", "path": "/__w/cookiecutter-nautobot-app-drift-manager/cookiecutter-nautobot-app-drift-manager/cookiecutter-ntc/python" } ``` Cookie: ``` { "remote": "https://github.com/networktocode/netutils.git", "path": "/tmp/tmp8yy2e_dd/netutils", "repository_path": "/tmp/tmp8yy2e_dd/netutils", "dir": "", "branch_prefix": "drift-manager/develop", "context": { "codeowner_github_usernames": "@itdependsnetworks @jeffkala @qduk", "full_name": "Network to Code, LLC", "email": "info@networktocode.com", "github_org": "networktocode", "description": "Common helper functions useful in network automation.", "project_name": "netutils", "project_slug": "netutils", "repo_url": "https://github.com/networktocode/netutils", "base_url": "netutils", "project_python_name": "netutils", "project_python_base_version": "3.10", "project_with_config_settings": "no", "generate_docs": "yes", "version": "1.15.1", "original_publish_year": "2021", "_template": "/__w/cookiecutter-nautobot-app-drift-manager/cookiecutter-nautobot-app-drift-manager/cookiecutter-ntc/python", "_output_dir": "/tmp/tmp8yy2e_dd", "_repo_dir": "/__w/cookiecutter-nautobot-app-drift-manager/cookiecutter-nautobot-app-drift-manager/cookiecutter-ntc/python", "_checkout": null }, "drift_managed_branch": "develop", "remote_name": "origin", "pull_request_strategy": "PullRequestStrategy.UPDATE_OR_CREATE", "post_actions": [], "baked_commit_ref": "b23a9ed5a4714810d83670ad47cc182764c6d464", "draft": false } ``` CLI Arguments: ``` { "cookie_dir": "", "input": false, "json_filename": "", "output_dir": "", "push": true, "template": "./cookiecutter-ntc", "template_dir": "python", "template_ref": "main", "pull_request": "update-or-create", "post_action": [], "disable_post_actions": true, "draft": null, "drift_managed_branch": "develop" } ``` --- .cookiecutter.json | 4 ++++ LICENSE | 4 ++++ changes/+main.housekeeping | 1 + docs/admin/release_notes/version_1.0.md | 4 ++++ example.invoke.yml | 2 +- pyproject.toml | 4 ++++ tasks.py | 7 ++++--- 7 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 changes/+main.housekeeping diff --git a/.cookiecutter.json b/.cookiecutter.json index fd87fa73..c184d8bb 100644 --- a/.cookiecutter.json +++ b/.cookiecutter.json @@ -23,7 +23,11 @@ "pull_request_strategy": "update-or-create", "post_actions": [], "draft": false, +<<<<<<< HEAD "baked_commit_ref": "b23a9ed5a4714810d83670ad47cc182764c6d464", +======= + "baked_commit_ref": "a996428068385caa4a089ec4abfd1ac731fca674", +>>>>>>> 016b1ed (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) "drift_managed_branch": "develop" } } diff --git a/LICENSE b/LICENSE index 6ce362fa..dd536f54 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,10 @@ Apache Software License 2.0 +<<<<<<< HEAD Copyright (c) 2021-2025, Network to Code, LLC +======= +Copyright (c) 2021-2026, Network to Code, LLC +>>>>>>> 016b1ed (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/changes/+main.housekeeping b/changes/+main.housekeeping new file mode 100644 index 00000000..3433adf6 --- /dev/null +++ b/changes/+main.housekeeping @@ -0,0 +1 @@ +Rebaked from the cookie `main`. diff --git a/docs/admin/release_notes/version_1.0.md b/docs/admin/release_notes/version_1.0.md index 63ef2244..9710b545 100644 --- a/docs/admin/release_notes/version_1.0.md +++ b/docs/admin/release_notes/version_1.0.md @@ -6,7 +6,11 @@ - Commit to SemVer - F5 fixes +<<<<<<< HEAD ## v1.0.0 - 2021-11 +======= +## [v1.0.0] - 2026-02-12 +>>>>>>> 016b1ed (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) ### Added diff --git a/example.invoke.yml b/example.invoke.yml index 199f8277..6206b5f9 100644 --- a/example.invoke.yml +++ b/example.invoke.yml @@ -1,6 +1,6 @@ --- "netutils": - python_ver: "3.9" + python_ver: "3.10" local: false # image_name: "netutils" # image_ver: "latest" diff --git a/pyproject.toml b/pyproject.toml index d8384cfa..af49011b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,12 +26,16 @@ include = [ [tool.poetry.dependencies] python = ">=3.10,<3.14" +<<<<<<< HEAD napalm = {version = "^4.0.0", optional = true} jsonschema = {version = "^4.17.3", optional = true} legacycrypt = {version = "0.3", optional = true} [tool.poetry.extras] optionals = ["jsonschema", "napalm", "legacycrypt"] +======= +click = "*" +>>>>>>> 016b1ed (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) [tool.poetry.group.dev.dependencies] coverage = "*" diff --git a/tasks.py b/tasks.py index 84805a24..86acbe74 100644 --- a/tasks.py +++ b/tasks.py @@ -66,13 +66,14 @@ def task_wrapper(function=None): return task_wrapper -def run_command(context, exec_cmd, port=None): +def run_command(context, exec_cmd, port=None, rm=True): """Wrapper to run the invoke task commands. Args: context ([invoke.task]): Invoke task object. exec_cmd ([str]): Command to run. port (int): Used to serve local docs. + rm (bool): Whether to remove the container after running the command. Returns: result (obj): Contains Invoke result from running task. @@ -86,12 +87,12 @@ def run_command(context, exec_cmd, port=None): ) if port: result = context.run( - f"docker run -it -p {port} -v {context.netutils.pwd}:/local {context.netutils.image_name}:{context.netutils.image_ver} sh -c '{exec_cmd}'", + f"docker run -it {'--rm' if rm else ''} -p {port} -v {context.netutils.pwd}:/local {context.netutils.image_name}:{context.netutils.image_ver} sh -c '{exec_cmd}'", pty=True, ) else: result = context.run( - f"docker run -it -v {context.netutils.pwd}:/local {context.netutils.image_name}:{context.netutils.image_ver} sh -c '{exec_cmd}'", + f"docker run -it {'--rm' if rm else ''} -v {context.netutils.pwd}:/local {context.netutils.image_name}:{context.netutils.image_ver} sh -c '{exec_cmd}'", pty=True, ) From 7560b3a7ffdee2672804d2da0917ff9c03bd2fa7 Mon Sep 17 00:00:00 2001 From: bakebot Date: Tue, 3 Mar 2026 18:07:17 +0000 Subject: [PATCH 2/7] Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool Template: ``` { "template": "https://github.com/networktocode-llc/cookiecutter-ntc.git", "dir": "python", "ref": "main", "path": "/__w/cookiecutter-nautobot-app-drift-manager/cookiecutter-nautobot-app-drift-manager/cookiecutter-ntc/python" } ``` Cookie: ``` { "remote": "https://github.com/networktocode/netutils.git", "path": "/tmp/tmp422crx0_/netutils", "repository_path": "/tmp/tmp422crx0_/netutils", "dir": "", "branch_prefix": "drift-manager/develop", "context": { "codeowner_github_usernames": "@itdependsnetworks @jeffkala @qduk", "full_name": "Network to Code, LLC", "email": "info@networktocode.com", "github_org": "networktocode", "description": "Common helper functions useful in network automation.", "project_name": "netutils", "project_slug": "netutils", "repo_url": "https://github.com/networktocode/netutils", "base_url": "netutils", "project_python_name": "netutils", "project_python_base_version": "3.10", "project_with_config_settings": "no", "generate_docs": "yes", "version": "1.15.1", "original_publish_year": "2021", "_template": "/__w/cookiecutter-nautobot-app-drift-manager/cookiecutter-nautobot-app-drift-manager/cookiecutter-ntc/python", "_output_dir": "/tmp/tmp422crx0_", "_repo_dir": "/__w/cookiecutter-nautobot-app-drift-manager/cookiecutter-nautobot-app-drift-manager/cookiecutter-ntc/python", "_checkout": null }, "drift_managed_branch": "develop", "remote_name": "origin", "pull_request_strategy": "PullRequestStrategy.UPDATE_OR_CREATE", "post_actions": [], "baked_commit_ref": "b23a9ed5a4714810d83670ad47cc182764c6d464", "draft": false } ``` CLI Arguments: ``` { "cookie_dir": "", "input": false, "json_filename": "", "output_dir": "", "push": true, "template": "./cookiecutter-ntc", "template_dir": "python", "template_ref": "main", "pull_request": "update-or-create", "post_action": [], "disable_post_actions": true, "draft": null, "drift_managed_branch": "develop" } ``` --- .cookiecutter.json | 4 ++++ .github/workflows/ci.yml | 8 ++++++++ LICENSE | 4 ++++ README.md | 8 +++++++- docs/admin/release_notes/version_1.0.md | 4 ++++ pyproject.toml | 3 +++ tasks.py | 12 +++++++++++- 7 files changed, 41 insertions(+), 2 deletions(-) diff --git a/.cookiecutter.json b/.cookiecutter.json index c184d8bb..1ee02293 100644 --- a/.cookiecutter.json +++ b/.cookiecutter.json @@ -23,11 +23,15 @@ "pull_request_strategy": "update-or-create", "post_actions": [], "draft": false, +<<<<<<< HEAD <<<<<<< HEAD "baked_commit_ref": "b23a9ed5a4714810d83670ad47cc182764c6d464", ======= "baked_commit_ref": "a996428068385caa4a089ec4abfd1ac731fca674", >>>>>>> 016b1ed (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) +======= + "baked_commit_ref": "7af44cb7e9a8e4894c9edfd2ee6ad8dc7b109de2", +>>>>>>> 3ab07dc (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) "drift_managed_branch": "develop" } } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 412c9963..1f0f0dd7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -134,7 +134,11 @@ jobs: cache-from: "type=gha,scope=${{ env.INVOKE_NETUTILS_IMAGE_NAME }}-${{ env.INVOKE_NETUTILS_IMAGE_VER }}-py${{ matrix.python-version }}" cache-to: "type=gha,scope=${{ env.INVOKE_NETUTILS_IMAGE_NAME }}-${{ env.INVOKE_NETUTILS_IMAGE_VER }}-py${{ matrix.python-version }}" build-args: | +<<<<<<< HEAD PYTHON_VER=${{ matrix.python-version }} +======= + PYTHON_VER=${{ env.INVOKE_{{cookiecutter.project_slug | upper}}_PYTHON_VER }} +>>>>>>> 3ab07dc (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) - name: "Linting: Pylint" run: "poetry run invoke pylint" pytest: @@ -171,7 +175,11 @@ jobs: cache-from: "type=gha,scope=${{ env.INVOKE_NETUTILS_IMAGE_NAME }}-${{ env.INVOKE_NETUTILS_IMAGE_VER }}-py${{ matrix.python-version }}" cache-to: "type=gha,scope=${{ env.INVOKE_NETUTILS_IMAGE_NAME }}-${{ env.INVOKE_NETUTILS_IMAGE_VER }}-py${{ matrix.python-version }}" build-args: | +<<<<<<< HEAD PYTHON_VER=${{ matrix.python-version }} +======= + PYTHON_VER=${{ env.INVOKE_{{cookiecutter.project_slug | upper}}_PYTHON_VER }} +>>>>>>> 3ab07dc (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) - name: "Run Tests" run: "poetry run invoke pytest" changelog: diff --git a/LICENSE b/LICENSE index dd536f54..c4b4459f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,10 +1,14 @@ Apache Software License 2.0 +<<<<<<< HEAD <<<<<<< HEAD Copyright (c) 2021-2025, Network to Code, LLC ======= Copyright (c) 2021-2026, Network to Code, LLC >>>>>>> 016b1ed (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) +======= +Copyright (c) 2021-2026, Network to Code, LLC +>>>>>>> 3ab07dc (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 969516fe..f8ccdef5 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Netutils

- +
@@ -18,9 +18,15 @@ A Python library that is a collection of functions that are used in the common n Full web-based HTML documentation for this library can be found over on the [Netutils Docs](https://netutils.readthedocs.io) website: +<<<<<<< HEAD - [User Guide](https://netutils.readthedocs.io/en/latest/user/lib_overview/) - Overview, Using the library, Getting Started. - [Administrator Guide](https://netutils.readthedocs.io/en/latest/admin/install/) - How to Install, Configure, Upgrade, or Uninstall the library. - [Developer Guide](https://netutils.readthedocs.io/en/latest/dev/contributing/) - Extending the library, Code Reference, Contribution Guide. +======= +- [User Guide](https://netutils.readthedocs.io/en/latest/user/app_overview/) - Overview, Using the Library, Getting Started. +- [Administrator Guide](https://netutils.readthedocs.io/en/latest/admin/install/) - How to Install, Configure, Upgrade, or Uninstall the Library. +- [Developer Guide](https://netutils.readthedocs.io/en/latest/dev/contributing/) - Extending the Library, Code Reference, Contribution Guide. +>>>>>>> 3ab07dc (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) - [Release Notes / Changelog](https://netutils.readthedocs.io/en/latest/admin/release_notes/). - [Frequently Asked Questions](https://netutils.readthedocs.io/en/latest/user/faq/). diff --git a/docs/admin/release_notes/version_1.0.md b/docs/admin/release_notes/version_1.0.md index 9710b545..fd85f48b 100644 --- a/docs/admin/release_notes/version_1.0.md +++ b/docs/admin/release_notes/version_1.0.md @@ -6,11 +6,15 @@ - Commit to SemVer - F5 fixes +<<<<<<< HEAD <<<<<<< HEAD ## v1.0.0 - 2021-11 ======= ## [v1.0.0] - 2026-02-12 >>>>>>> 016b1ed (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) +======= +## [v1.0.0] - 2026-03-03 +>>>>>>> 3ab07dc (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) ### Added diff --git a/pyproject.toml b/pyproject.toml index af49011b..d25c0ef3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,6 +27,7 @@ include = [ [tool.poetry.dependencies] python = ">=3.10,<3.14" <<<<<<< HEAD +<<<<<<< HEAD napalm = {version = "^4.0.0", optional = true} jsonschema = {version = "^4.17.3", optional = true} legacycrypt = {version = "0.3", optional = true} @@ -34,6 +35,8 @@ legacycrypt = {version = "0.3", optional = true} [tool.poetry.extras] optionals = ["jsonschema", "napalm", "legacycrypt"] ======= +======= +>>>>>>> 3ab07dc (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) click = "*" >>>>>>> 016b1ed (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) diff --git a/tasks.py b/tasks.py index 86acbe74..e42bd62e 100644 --- a/tasks.py +++ b/tasks.py @@ -39,7 +39,7 @@ def is_truthy(arg): "python_ver": "3.10", "local": is_truthy(os.getenv("INVOKE_NETUTILS_LOCAL", "false")), "image_name": "netutils", - "image_ver": os.getenv("INVOKE_PARSER_IMAGE_VER", "latest"), + "image_ver": os.getenv("INVOKE_NETUTILS_IMAGE_VER", "latest"), "pwd": Path(__file__).parent, } } @@ -189,6 +189,16 @@ def pytest(context, pattern=None, label=None): exec_cmd = " && ".join([doc_test_cmd, pytest_cmd, coverage_cmd]) run_command(context, exec_cmd) + doc_test_cmd = "pytest -vv --doctest-modules netutils/" + pytest_cmd = "coverage run --source=netutils -m pytest" + if pattern: + pytest_cmd += "".join([f" -k {_pattern}" for _pattern in pattern]) + if label: + pytest_cmd += "".join([f" {_label}" for _label in label]) + coverage_cmd = "coverage report" + exec_cmd = " && ".join([doc_test_cmd, pytest_cmd, coverage_cmd]) + run_command(context, exec_cmd) + @task(aliases=("a",)) def autoformat(context): From 5d6929f230878996263126a0c305dd51a151e375 Mon Sep 17 00:00:00 2001 From: bakebot Date: Tue, 3 Mar 2026 22:16:46 +0000 Subject: [PATCH 3/7] Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool Template: ``` { "template": "https://github.com/networktocode-llc/cookiecutter-ntc.git", "dir": "python", "ref": "main", "path": "/__w/cookiecutter-nautobot-app-drift-manager/cookiecutter-nautobot-app-drift-manager/cookiecutter-ntc/python" } ``` Cookie: ``` { "remote": "https://github.com/networktocode/netutils.git", "path": "/tmp/tmp8oss3l1r/netutils", "repository_path": "/tmp/tmp8oss3l1r/netutils", "dir": "", "branch_prefix": "drift-manager/develop", "context": { "codeowner_github_usernames": "@itdependsnetworks @jeffkala @qduk", "full_name": "Network to Code, LLC", "email": "info@networktocode.com", "github_org": "networktocode", "description": "Common helper functions useful in network automation.", "project_name": "netutils", "project_slug": "netutils", "repo_url": "https://github.com/networktocode/netutils", "base_url": "netutils", "project_python_name": "netutils", "project_python_base_version": "3.10", "project_with_config_settings": "no", "generate_docs": "yes", "version": "1.15.1", "original_publish_year": "2021", "_template": "/__w/cookiecutter-nautobot-app-drift-manager/cookiecutter-nautobot-app-drift-manager/cookiecutter-ntc/python", "_output_dir": "/tmp/tmp8oss3l1r", "_repo_dir": "/__w/cookiecutter-nautobot-app-drift-manager/cookiecutter-nautobot-app-drift-manager/cookiecutter-ntc/python", "_checkout": null }, "drift_managed_branch": "develop", "remote_name": "origin", "pull_request_strategy": "PullRequestStrategy.UPDATE_OR_CREATE", "post_actions": [], "baked_commit_ref": "b23a9ed5a4714810d83670ad47cc182764c6d464", "draft": false } ``` CLI Arguments: ``` { "cookie_dir": "", "input": false, "json_filename": "", "output_dir": "", "push": true, "template": "./cookiecutter-ntc", "template_dir": "python", "template_ref": "main", "pull_request": "update-or-create", "post_action": [], "disable_post_actions": true, "draft": null, "drift_managed_branch": "develop" } ``` --- .cookiecutter.json | 4 ++++ .github/workflows/ci.yml | 8 ++++++++ .github/workflows/release.yml | 4 ++-- LICENSE | 4 ++++ README.md | 6 ++++++ docs/admin/release_notes/version_1.0.md | 4 ++++ pyproject.toml | 3 +++ tasks.py | 10 ++++++++++ 8 files changed, 41 insertions(+), 2 deletions(-) diff --git a/.cookiecutter.json b/.cookiecutter.json index 1ee02293..47fcf67a 100644 --- a/.cookiecutter.json +++ b/.cookiecutter.json @@ -24,6 +24,7 @@ "post_actions": [], "draft": false, <<<<<<< HEAD +<<<<<<< HEAD <<<<<<< HEAD "baked_commit_ref": "b23a9ed5a4714810d83670ad47cc182764c6d464", ======= @@ -32,6 +33,9 @@ ======= "baked_commit_ref": "7af44cb7e9a8e4894c9edfd2ee6ad8dc7b109de2", >>>>>>> 3ab07dc (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) +======= + "baked_commit_ref": "46f70d30baa1e0c5af3da3fdcf1c77b31157d3f9", +>>>>>>> 67a15b6 (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) "drift_managed_branch": "develop" } } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f0f0dd7..771d5182 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -134,11 +134,15 @@ jobs: cache-from: "type=gha,scope=${{ env.INVOKE_NETUTILS_IMAGE_NAME }}-${{ env.INVOKE_NETUTILS_IMAGE_VER }}-py${{ matrix.python-version }}" cache-to: "type=gha,scope=${{ env.INVOKE_NETUTILS_IMAGE_NAME }}-${{ env.INVOKE_NETUTILS_IMAGE_VER }}-py${{ matrix.python-version }}" build-args: | +<<<<<<< HEAD <<<<<<< HEAD PYTHON_VER=${{ matrix.python-version }} ======= PYTHON_VER=${{ env.INVOKE_{{cookiecutter.project_slug | upper}}_PYTHON_VER }} >>>>>>> 3ab07dc (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) +======= + PYTHON_VER=${{ matrix.python-version }} +>>>>>>> 67a15b6 (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) - name: "Linting: Pylint" run: "poetry run invoke pylint" pytest: @@ -175,11 +179,15 @@ jobs: cache-from: "type=gha,scope=${{ env.INVOKE_NETUTILS_IMAGE_NAME }}-${{ env.INVOKE_NETUTILS_IMAGE_VER }}-py${{ matrix.python-version }}" cache-to: "type=gha,scope=${{ env.INVOKE_NETUTILS_IMAGE_NAME }}-${{ env.INVOKE_NETUTILS_IMAGE_VER }}-py${{ matrix.python-version }}" build-args: | +<<<<<<< HEAD <<<<<<< HEAD PYTHON_VER=${{ matrix.python-version }} ======= PYTHON_VER=${{ env.INVOKE_{{cookiecutter.project_slug | upper}}_PYTHON_VER }} >>>>>>> 3ab07dc (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) +======= + PYTHON_VER=${{ matrix.python-version }} +>>>>>>> 67a15b6 (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) - name: "Run Tests" run: "poetry run invoke pytest" changelog: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a6cd1872..b8d962ee 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,6 +1,6 @@ --- name: "Release" -on: # yamllint disable-line rule:truthy rule:comments +on: # yamllint disable-line rule:truthy rule:comments release: types: ["published"] @@ -48,7 +48,7 @@ jobs: - name: "Upload binaries to release" run: "gh release upload ${{ github.ref_name }} dist/*.{tar.gz,whl}" env: - GH_TOKEN: "${{ secrets.NTC_GITHUB_TOKEN }}" + GH_TOKEN: "${{ secrets.GITHUB_TOKEN }}" publish-pypi: name: "Push Package to PyPI" diff --git a/LICENSE b/LICENSE index c4b4459f..ca1fe257 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,6 @@ Apache Software License 2.0 +<<<<<<< HEAD <<<<<<< HEAD <<<<<<< HEAD Copyright (c) 2021-2025, Network to Code, LLC @@ -9,6 +10,9 @@ Copyright (c) 2021-2026, Network to Code, LLC ======= Copyright (c) 2021-2026, Network to Code, LLC >>>>>>> 3ab07dc (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) +======= +Copyright (c) 2021-2026, Network to Code, LLC +>>>>>>> 67a15b6 (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index f8ccdef5..4621061f 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ A Python library that is a collection of functions that are used in the common n Full web-based HTML documentation for this library can be found over on the [Netutils Docs](https://netutils.readthedocs.io) website: +<<<<<<< HEAD <<<<<<< HEAD - [User Guide](https://netutils.readthedocs.io/en/latest/user/lib_overview/) - Overview, Using the library, Getting Started. - [Administrator Guide](https://netutils.readthedocs.io/en/latest/admin/install/) - How to Install, Configure, Upgrade, or Uninstall the library. @@ -27,6 +28,11 @@ Full web-based HTML documentation for this library can be found over on the [Net - [Administrator Guide](https://netutils.readthedocs.io/en/latest/admin/install/) - How to Install, Configure, Upgrade, or Uninstall the Library. - [Developer Guide](https://netutils.readthedocs.io/en/latest/dev/contributing/) - Extending the Library, Code Reference, Contribution Guide. >>>>>>> 3ab07dc (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) +======= +- [User Guide](https://netutils.readthedocs.io/en/latest/user/app_overview/) - Overview, Using the Library, Getting Started. +- [Administrator Guide](https://netutils.readthedocs.io/en/latest/admin/install/) - How to Install, Configure, Upgrade, or Uninstall the Library. +- [Developer Guide](https://netutils.readthedocs.io/en/latest/dev/contributing/) - Extending the Library, Code Reference, Contribution Guide. +>>>>>>> 67a15b6 (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) - [Release Notes / Changelog](https://netutils.readthedocs.io/en/latest/admin/release_notes/). - [Frequently Asked Questions](https://netutils.readthedocs.io/en/latest/user/faq/). diff --git a/docs/admin/release_notes/version_1.0.md b/docs/admin/release_notes/version_1.0.md index fd85f48b..0d5f8ee3 100644 --- a/docs/admin/release_notes/version_1.0.md +++ b/docs/admin/release_notes/version_1.0.md @@ -6,6 +6,7 @@ - Commit to SemVer - F5 fixes +<<<<<<< HEAD <<<<<<< HEAD <<<<<<< HEAD ## v1.0.0 - 2021-11 @@ -15,6 +16,9 @@ ======= ## [v1.0.0] - 2026-03-03 >>>>>>> 3ab07dc (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) +======= +## [v1.0.0] - 2026-03-03 +>>>>>>> 67a15b6 (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) ### Added diff --git a/pyproject.toml b/pyproject.toml index d25c0ef3..b91436e5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,6 +28,7 @@ include = [ python = ">=3.10,<3.14" <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD napalm = {version = "^4.0.0", optional = true} jsonschema = {version = "^4.17.3", optional = true} legacycrypt = {version = "0.3", optional = true} @@ -37,6 +38,8 @@ optionals = ["jsonschema", "napalm", "legacycrypt"] ======= ======= >>>>>>> 3ab07dc (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) +======= +>>>>>>> 67a15b6 (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) click = "*" >>>>>>> 016b1ed (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) diff --git a/tasks.py b/tasks.py index e42bd62e..91599e9f 100644 --- a/tasks.py +++ b/tasks.py @@ -199,6 +199,16 @@ def pytest(context, pattern=None, label=None): exec_cmd = " && ".join([doc_test_cmd, pytest_cmd, coverage_cmd]) run_command(context, exec_cmd) + doc_test_cmd = "pytest -vv --doctest-modules netutils/" + pytest_cmd = "coverage run --source=netutils -m pytest" + if pattern: + pytest_cmd += "".join([f" -k {_pattern}" for _pattern in pattern]) + if label: + pytest_cmd += "".join([f" {_label}" for _label in label]) + coverage_cmd = "coverage report" + exec_cmd = " && ".join([doc_test_cmd, pytest_cmd, coverage_cmd]) + run_command(context, exec_cmd) + @task(aliases=("a",)) def autoformat(context): From 8a42e9749916a6c594d92ce31f0bd06cfc80edb6 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Tue, 3 Mar 2026 15:36:46 -0700 Subject: [PATCH 4/7] fix drift manager conflicts --- .cookiecutter.json | 12 ------------ .github/workflows/ci.yml | 16 ---------------- LICENSE | 12 ------------ README.md | 11 +---------- docs/admin/release_notes/version_1.0.md | 12 ------------ pyproject.toml | 10 ---------- 6 files changed, 1 insertion(+), 72 deletions(-) diff --git a/.cookiecutter.json b/.cookiecutter.json index 47fcf67a..e12990f5 100644 --- a/.cookiecutter.json +++ b/.cookiecutter.json @@ -23,19 +23,7 @@ "pull_request_strategy": "update-or-create", "post_actions": [], "draft": false, -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD - "baked_commit_ref": "b23a9ed5a4714810d83670ad47cc182764c6d464", -======= - "baked_commit_ref": "a996428068385caa4a089ec4abfd1ac731fca674", ->>>>>>> 016b1ed (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) -======= - "baked_commit_ref": "7af44cb7e9a8e4894c9edfd2ee6ad8dc7b109de2", ->>>>>>> 3ab07dc (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) -======= "baked_commit_ref": "46f70d30baa1e0c5af3da3fdcf1c77b31157d3f9", ->>>>>>> 67a15b6 (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) "drift_managed_branch": "develop" } } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 771d5182..412c9963 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -134,15 +134,7 @@ jobs: cache-from: "type=gha,scope=${{ env.INVOKE_NETUTILS_IMAGE_NAME }}-${{ env.INVOKE_NETUTILS_IMAGE_VER }}-py${{ matrix.python-version }}" cache-to: "type=gha,scope=${{ env.INVOKE_NETUTILS_IMAGE_NAME }}-${{ env.INVOKE_NETUTILS_IMAGE_VER }}-py${{ matrix.python-version }}" build-args: | -<<<<<<< HEAD -<<<<<<< HEAD PYTHON_VER=${{ matrix.python-version }} -======= - PYTHON_VER=${{ env.INVOKE_{{cookiecutter.project_slug | upper}}_PYTHON_VER }} ->>>>>>> 3ab07dc (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) -======= - PYTHON_VER=${{ matrix.python-version }} ->>>>>>> 67a15b6 (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) - name: "Linting: Pylint" run: "poetry run invoke pylint" pytest: @@ -179,15 +171,7 @@ jobs: cache-from: "type=gha,scope=${{ env.INVOKE_NETUTILS_IMAGE_NAME }}-${{ env.INVOKE_NETUTILS_IMAGE_VER }}-py${{ matrix.python-version }}" cache-to: "type=gha,scope=${{ env.INVOKE_NETUTILS_IMAGE_NAME }}-${{ env.INVOKE_NETUTILS_IMAGE_VER }}-py${{ matrix.python-version }}" build-args: | -<<<<<<< HEAD -<<<<<<< HEAD - PYTHON_VER=${{ matrix.python-version }} -======= - PYTHON_VER=${{ env.INVOKE_{{cookiecutter.project_slug | upper}}_PYTHON_VER }} ->>>>>>> 3ab07dc (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) -======= PYTHON_VER=${{ matrix.python-version }} ->>>>>>> 67a15b6 (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) - name: "Run Tests" run: "poetry run invoke pytest" changelog: diff --git a/LICENSE b/LICENSE index ca1fe257..9e40eee1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,18 +1,6 @@ Apache Software License 2.0 -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD -Copyright (c) 2021-2025, Network to Code, LLC -======= Copyright (c) 2021-2026, Network to Code, LLC ->>>>>>> 016b1ed (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) -======= -Copyright (c) 2021-2026, Network to Code, LLC ->>>>>>> 3ab07dc (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) -======= -Copyright (c) 2021-2026, Network to Code, LLC ->>>>>>> 67a15b6 (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 4621061f..5d57aab5 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Netutils

- +
@@ -18,21 +18,12 @@ A Python library that is a collection of functions that are used in the common n Full web-based HTML documentation for this library can be found over on the [Netutils Docs](https://netutils.readthedocs.io) website: -<<<<<<< HEAD -<<<<<<< HEAD - [User Guide](https://netutils.readthedocs.io/en/latest/user/lib_overview/) - Overview, Using the library, Getting Started. - [Administrator Guide](https://netutils.readthedocs.io/en/latest/admin/install/) - How to Install, Configure, Upgrade, or Uninstall the library. - [Developer Guide](https://netutils.readthedocs.io/en/latest/dev/contributing/) - Extending the library, Code Reference, Contribution Guide. -======= - [User Guide](https://netutils.readthedocs.io/en/latest/user/app_overview/) - Overview, Using the Library, Getting Started. - [Administrator Guide](https://netutils.readthedocs.io/en/latest/admin/install/) - How to Install, Configure, Upgrade, or Uninstall the Library. - [Developer Guide](https://netutils.readthedocs.io/en/latest/dev/contributing/) - Extending the Library, Code Reference, Contribution Guide. ->>>>>>> 3ab07dc (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) -======= -- [User Guide](https://netutils.readthedocs.io/en/latest/user/app_overview/) - Overview, Using the Library, Getting Started. -- [Administrator Guide](https://netutils.readthedocs.io/en/latest/admin/install/) - How to Install, Configure, Upgrade, or Uninstall the Library. -- [Developer Guide](https://netutils.readthedocs.io/en/latest/dev/contributing/) - Extending the Library, Code Reference, Contribution Guide. ->>>>>>> 67a15b6 (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) - [Release Notes / Changelog](https://netutils.readthedocs.io/en/latest/admin/release_notes/). - [Frequently Asked Questions](https://netutils.readthedocs.io/en/latest/user/faq/). diff --git a/docs/admin/release_notes/version_1.0.md b/docs/admin/release_notes/version_1.0.md index 0d5f8ee3..63ef2244 100644 --- a/docs/admin/release_notes/version_1.0.md +++ b/docs/admin/release_notes/version_1.0.md @@ -6,19 +6,7 @@ - Commit to SemVer - F5 fixes -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD ## v1.0.0 - 2021-11 -======= -## [v1.0.0] - 2026-02-12 ->>>>>>> 016b1ed (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) -======= -## [v1.0.0] - 2026-03-03 ->>>>>>> 3ab07dc (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) -======= -## [v1.0.0] - 2026-03-03 ->>>>>>> 67a15b6 (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) ### Added diff --git a/pyproject.toml b/pyproject.toml index b91436e5..d8384cfa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,22 +26,12 @@ include = [ [tool.poetry.dependencies] python = ">=3.10,<3.14" -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD napalm = {version = "^4.0.0", optional = true} jsonschema = {version = "^4.17.3", optional = true} legacycrypt = {version = "0.3", optional = true} [tool.poetry.extras] optionals = ["jsonschema", "napalm", "legacycrypt"] -======= -======= ->>>>>>> 3ab07dc (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) -======= ->>>>>>> 67a15b6 (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) -click = "*" ->>>>>>> 016b1ed (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) [tool.poetry.group.dev.dependencies] coverage = "*" From 1486aadad075e9b34c28df9c7b523be79d951bf6 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Tue, 3 Mar 2026 15:39:22 -0700 Subject: [PATCH 5/7] fix drift manager conflicts --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 5d57aab5..93f99757 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,6 @@ A Python library that is a collection of functions that are used in the common n Full web-based HTML documentation for this library can be found over on the [Netutils Docs](https://netutils.readthedocs.io) website: -- [User Guide](https://netutils.readthedocs.io/en/latest/user/lib_overview/) - Overview, Using the library, Getting Started. -- [Administrator Guide](https://netutils.readthedocs.io/en/latest/admin/install/) - How to Install, Configure, Upgrade, or Uninstall the library. -- [Developer Guide](https://netutils.readthedocs.io/en/latest/dev/contributing/) - Extending the library, Code Reference, Contribution Guide. - [User Guide](https://netutils.readthedocs.io/en/latest/user/app_overview/) - Overview, Using the Library, Getting Started. - [Administrator Guide](https://netutils.readthedocs.io/en/latest/admin/install/) - How to Install, Configure, Upgrade, or Uninstall the Library. - [Developer Guide](https://netutils.readthedocs.io/en/latest/dev/contributing/) - Extending the Library, Code Reference, Contribution Guide. From 17d9a2abef84cd76f9fe707f78d12c27a715e8d7 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Tue, 3 Mar 2026 15:40:39 -0700 Subject: [PATCH 6/7] fix drift manager conflicts --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 93f99757..969516fe 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,9 @@ A Python library that is a collection of functions that are used in the common n Full web-based HTML documentation for this library can be found over on the [Netutils Docs](https://netutils.readthedocs.io) website: -- [User Guide](https://netutils.readthedocs.io/en/latest/user/app_overview/) - Overview, Using the Library, Getting Started. -- [Administrator Guide](https://netutils.readthedocs.io/en/latest/admin/install/) - How to Install, Configure, Upgrade, or Uninstall the Library. -- [Developer Guide](https://netutils.readthedocs.io/en/latest/dev/contributing/) - Extending the Library, Code Reference, Contribution Guide. +- [User Guide](https://netutils.readthedocs.io/en/latest/user/lib_overview/) - Overview, Using the library, Getting Started. +- [Administrator Guide](https://netutils.readthedocs.io/en/latest/admin/install/) - How to Install, Configure, Upgrade, or Uninstall the library. +- [Developer Guide](https://netutils.readthedocs.io/en/latest/dev/contributing/) - Extending the library, Code Reference, Contribution Guide. - [Release Notes / Changelog](https://netutils.readthedocs.io/en/latest/admin/release_notes/). - [Frequently Asked Questions](https://netutils.readthedocs.io/en/latest/user/faq/). From 17c494a504300edbe40d9a913d31ada03cf2b08b Mon Sep 17 00:00:00 2001 From: bakebot Date: Fri, 17 Apr 2026 20:34:04 +0000 Subject: [PATCH 7/7] Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool Template: ``` { "template": "https://github.com/networktocode-llc/cookiecutter-ntc.git", "dir": "python", "ref": "main", "path": "/__w/cookiecutter-nautobot-app-drift-manager/cookiecutter-nautobot-app-drift-manager/cookiecutter-ntc/python" } ``` Cookie: ``` { "remote": "https://github.com/networktocode/netutils.git", "path": "/tmp/tmpiz94bhko/netutils", "repository_path": "/tmp/tmpiz94bhko/netutils", "dir": "", "branch_prefix": "drift-manager/develop", "context": { "codeowner_github_usernames": "@itdependsnetworks @jeffkala @qduk", "full_name": "Network to Code, LLC", "email": "info@networktocode.com", "github_org": "networktocode", "description": "Common helper functions useful in network automation.", "project_name": "netutils", "project_slug": "netutils", "repo_url": "https://github.com/networktocode/netutils", "base_url": "netutils", "project_python_name": "netutils", "project_python_base_version": "3.10", "project_with_config_settings": "no", "generate_docs": "yes", "version": "1.15.1", "original_publish_year": "2021", "_template": "/__w/cookiecutter-nautobot-app-drift-manager/cookiecutter-nautobot-app-drift-manager/cookiecutter-ntc/python", "_output_dir": "/tmp/tmpiz94bhko", "_repo_dir": "/__w/cookiecutter-nautobot-app-drift-manager/cookiecutter-nautobot-app-drift-manager/cookiecutter-ntc/python", "_checkout": null }, "drift_managed_branch": "develop", "remote_name": "origin", "pull_request_strategy": "PullRequestStrategy.UPDATE_OR_CREATE", "post_actions": [], "baked_commit_ref": "b23a9ed5a4714810d83670ad47cc182764c6d464", "draft": false } ``` CLI Arguments: ``` { "cookie_dir": "", "input": false, "json_filename": "", "output_dir": "", "push": true, "template": "./cookiecutter-ntc", "template_dir": "python", "template_ref": "main", "pull_request": "update-or-create", "post_action": [], "disable_post_actions": true, "draft": null, "drift_managed_branch": "develop" } ``` --- .cookiecutter.json | 4 + .github/workflows/prepare_release.yml | 178 ++++++++++++++++++++++++ .github/workflows/release.yml | 63 ++++++++- README.md | 6 + bin/ensure_release_notes.py | 97 +++++++++++++ docs/admin/release_notes/version_1.0.md | 4 + pyproject.toml | 4 + tasks.py | 27 +++- towncrier_header.txt | 9 ++ 9 files changed, 384 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/prepare_release.yml create mode 100644 bin/ensure_release_notes.py create mode 100644 towncrier_header.txt diff --git a/.cookiecutter.json b/.cookiecutter.json index e12990f5..2d8536eb 100644 --- a/.cookiecutter.json +++ b/.cookiecutter.json @@ -23,7 +23,11 @@ "pull_request_strategy": "update-or-create", "post_actions": [], "draft": false, +<<<<<<< HEAD "baked_commit_ref": "46f70d30baa1e0c5af3da3fdcf1c77b31157d3f9", +======= + "baked_commit_ref": "e188d3786e8b7973c1ef1f1ccf6d4f1a81ac27ea", +>>>>>>> 039361e (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) "drift_managed_branch": "develop" } } diff --git a/.github/workflows/prepare_release.yml b/.github/workflows/prepare_release.yml new file mode 100644 index 00000000..727c32df --- /dev/null +++ b/.github/workflows/prepare_release.yml @@ -0,0 +1,178 @@ +--- +name: "Prepare Release" +on: # yamllint disable-line rule:truthy rule:comments + workflow_dispatch: + inputs: + bump_rule: + description: "Select the version bump type" + required: true + default: "patch" + type: "choice" + options: + - "prerelease" + - "patch" + - "minor" + - "major" + target_branch: + description: "Create the release from this branch (default: main)." + required: true + default: "main" + date: + description: "Date of the release YYYY-MM-DD (defaults to today's date in the US Eastern TZ)." + required: false + default: "" + +jobs: + prepare-release: + permissions: + contents: "write" + pull-requests: "write" + name: "Prepare Release" + runs-on: "ubuntu-latest" + steps: + - name: "Checkout code" + uses: "actions/checkout@v4" + with: + # If target_branch is 'main', use 'develop' as the source branch. Otherwise, the source and target branch are the same. + ref: "${{ github.event.inputs['target_branch'] == 'main' && 'develop' || github.event.inputs['target_branch'] }}" + fetch-depth: 0 # Fetch all history for git tags + + - name: "Setup environment" + uses: "networktocode/gh-action-setup-poetry-environment@v6" + with: + poetry-version: "2.1.3" + poetry-install-options: "--with dev" + + - name: "Validate Branch and Tags" + run: | + # 1. Verify branch exists + if ! git rev-parse --verify origin/${{ github.event.inputs.target_branch }} > /dev/null 2>&1; then + echo "Error: Branch ${{ github.event.inputs.target_branch }} does not exist." + exit 1 + fi + + # 2. Try to get the previous version tag + # If it fails (no tags), get the hash of the first commit + if PREV_TAG=$(git describe --tags --abbrev=0 2>/dev/null); then + echo "PREVIOUS_TAG=$PREV_TAG" >> $GITHUB_ENV + echo "Found previous tag: $PREV_TAG" + else + # Fallback to the first commit in the repository + FIRST_COMMIT=$(git rev-list --max-parents=0 HEAD) + echo "PREVIOUS_TAG=$FIRST_COMMIT" >> $GITHUB_ENV + echo "No tags found. Falling back to initial commit: $FIRST_COMMIT" + fi + + - name: "Determine New Version" + id: "versioning" + run: | + # Perform the bump based on the user input + poetry version ${{ github.event.inputs.bump_rule }} + + # Capture the New version string for use in other steps + NEW_VER=$(poetry version --short) + echo "NEW_VERSION=$NEW_VER" >> $GITHUB_ENV + echo "RELEASE_BRANCH=release/$NEW_VER" >> $GITHUB_ENV + + - name: "Set Date Variable" + run: | + if [ -z "${{ github.event.inputs.date }}" ]; then + RELEASE_DATE=$(TZ=America/New_York date +%Y-%m-%d) + else + RELEASE_DATE="${{ github.event.inputs.date }}" + fi + echo "RELEASE_DATE=$RELEASE_DATE" >> $GITHUB_ENV + + - name: "Create Release Branch" + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + run: | + git config user.name "${{ github.actor }}" + git config user.email "${{ github.actor }}@users.noreply.github.com" + + # Ensure release branch doesn't already exist + if git rev-parse --verify origin/${{ env.RELEASE_BRANCH }} > /dev/null 2>&1; then + echo "Error: Release branch ${{ env.RELEASE_BRANCH }} already exists." + exit 1 + fi + + # Create a new branch for the release + git checkout -b "${{ env.RELEASE_BRANCH }}" + + - name: "Regenerate poetry.lock" + run: "poetry lock --regenerate" + + - name: "Generate Github Release Notes" + env: + GH_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + run: | + # 1. Get Towncrier Draft + TOWNCRIER_NOTES=$(poetry run towncrier build --version "${{ env.NEW_VERSION }}" --date "${{ env.RELEASE_DATE }}" --draft) + + # 2. Call GitHub API to generate raw notes + RAW_GH_NOTES=$(gh api /repos/${{ github.repository }}/releases/generate-notes \ + -f tag_name="v${{ env.NEW_VERSION }}" \ + -f target_commitish="${{ github.event.inputs['target_branch'] == 'main' && 'develop' || github.event.inputs['target_branch'] }}" \ + -f previous_tag_name="${{ env.PREVIOUS_TAG }}" --jq '.body') + + # 3. Parse usernames (Regex match) + # We use grep to find "@user" patterns, sort, and uniq them + USERNAMES=$(echo "$RAW_GH_NOTES" | grep -oP 'by @\K[a-zA-Z0-9-]+' | sort -u | grep -vE 'dependabot|nautobot-bot|github-actions' || true) + + # 4. Format the Contributors section + CONTRIBUTORS_SECTION="## Contributors" + for user in $USERNAMES; do + CONTRIBUTORS_SECTION="$CONTRIBUTORS_SECTION"$'\n'"* @$user" + done + + # 5. Extract the "Full Changelog" or "New Contributors" part + # Using awk to grab everything from '## New Contributors' or '**Full Changelog**' to the end + GH_FOOTER=$(echo "$RAW_GH_NOTES" | awk '/## New Contributors/ || /\*\*Full Changelog\*\*/ {found=1} found {print}') + if [ -z "$GH_FOOTER" ]; then + GH_FOOTER=$(echo "$RAW_GH_NOTES" | sed -n '/**Full Changelog**/,$p') + fi + + # 6. Combine everything + FINAL_NOTES="$TOWNCRIER_NOTES"$'\n\n'"$CONTRIBUTORS_SECTION"$'\n\n'"$GH_FOOTER" + + # 7. Save to a temporary file to avoid shell argument length limits + echo "$FINAL_NOTES" > ../consolidated_notes.md + + - name: "Generate Release Notes" + run: "poetry run inv generate-release-notes --version '${{ env.NEW_VERSION }}' --date '${{ env.RELEASE_DATE }}'" + + - name: "Commit Changes and Push" + run: | + # Add all changes (pyproject.toml, poetry.lock, etc.) + git add . + git commit -m "prepare release v${{ env.NEW_VERSION }}" + git push origin "${{ env.RELEASE_BRANCH }}" + + - name: "Create Pull Request" + env: + GH_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + run: | + gh pr create \ + --title "Release v${{ env.NEW_VERSION }}" \ + --body-file "../consolidated_notes.md" \ + --base "${{ github.event.inputs.target_branch }}" \ + --head "${{ env.RELEASE_BRANCH }}" + + - name: "Create Draft Release" + env: + GH_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + run: | + if [[ "${{ github.event.inputs.bump_rule }}" == "prerelease" ]]; then + RELEASE_FLAGS="--prerelease" + elif [[ "${{ github.event.inputs.target_branch }}" == "main" ]]; then + RELEASE_FLAGS="--latest" + else + RELEASE_FLAGS="--latest=false" + fi + + gh release create "v${{ env.NEW_VERSION }}" \ + --draft \ + $RELEASE_FLAGS \ + --title "v${{ env.NEW_VERSION }} - ${{ env.RELEASE_DATE }}" \ + --notes-file "../consolidated_notes.md" \ + --target "${{ github.event.inputs.target_branch }}" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b8d962ee..c9351591 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,10 +12,10 @@ jobs: steps: - uses: "actions/checkout@v4" - name: "Setup environment" - uses: "networktocode/gh-action-setup-poetry-environment@v6" + uses: "networktocode/gh-action-setup-poetry-environment@v7" with: poetry-version: "2.1.3" - python-version: "3.13" + python-version: "3.12" poetry-install-options: "--no-root" - name: "Run Poetry Build" run: "poetry build" @@ -104,3 +104,62 @@ jobs: } ] } + + create-pr-to-develop: + if: "github.event.release.target_commitish == 'main'" + permissions: + contents: "write" + pull-requests: "write" + name: "Create a PR from main into develop" + needs: + - "publish-github" + - "publish-pypi" + runs-on: "ubuntu-latest" + steps: + - name: "Checkout main" + uses: "actions/checkout@v4" + with: + ref: "main" + fetch-depth: 0 + + - name: "Setup environment" + uses: "networktocode/gh-action-setup-poetry-environment@v6" + with: + poetry-version: "2.1.3" + poetry-install-options: "--no-root" + + - name: "Create release branch from main" + id: "branch" + run: | + + git config user.name "${{ github.actor }}" + git config user.email "${{ github.actor }}@users.noreply.github.com" + + TAG_NAME="${{ github.event.release.tag_name }}" + VERSION="${TAG_NAME#v}" + + BRANCH_NAME="release-${VERSION}-to-develop" + + # Ensure release branch doesn't already exist + if git rev-parse --verify origin/$BRANCH_NAME > /dev/null 2>&1; then + echo "Error: Release branch $BRANCH_NAME already exists." + exit 1 + fi + + git checkout -b "$BRANCH_NAME" + + poetry version prepatch + git add pyproject.toml && git commit -m "Bump version" + git push origin "$BRANCH_NAME" + + echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT + + - name: "Create Pull Request to develop" + env: + GH_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + run: | + gh pr create \ + --title "Post release ${{ github.event.release.tag_name }} to develop" \ + --body "Please do a merge commit." \ + --base "develop" \ + --head "${{ steps.branch.outputs.branch_name }}" diff --git a/README.md b/README.md index 969516fe..8790da7d 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,15 @@ A Python library that is a collection of functions that are used in the common n Full web-based HTML documentation for this library can be found over on the [Netutils Docs](https://netutils.readthedocs.io) website: +<<<<<<< HEAD - [User Guide](https://netutils.readthedocs.io/en/latest/user/lib_overview/) - Overview, Using the library, Getting Started. - [Administrator Guide](https://netutils.readthedocs.io/en/latest/admin/install/) - How to Install, Configure, Upgrade, or Uninstall the library. - [Developer Guide](https://netutils.readthedocs.io/en/latest/dev/contributing/) - Extending the library, Code Reference, Contribution Guide. +======= +- [User Guide](https://netutils.readthedocs.io/en/latest/user/app_overview/) - Overview, Using the Library, Getting Started. +- [Administrator Guide](https://netutils.readthedocs.io/en/latest/admin/install/) - How to Install, Configure, Upgrade, or Uninstall the Library. +- [Developer Guide](https://netutils.readthedocs.io/en/latest/dev/contributing/) - Extending the Library, Code Reference, Contribution Guide. +>>>>>>> 039361e (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) - [Release Notes / Changelog](https://netutils.readthedocs.io/en/latest/admin/release_notes/). - [Frequently Asked Questions](https://netutils.readthedocs.io/en/latest/user/faq/). diff --git a/bin/ensure_release_notes.py b/bin/ensure_release_notes.py new file mode 100644 index 00000000..74794337 --- /dev/null +++ b/bin/ensure_release_notes.py @@ -0,0 +1,97 @@ +"""Ensure that release notes exist for a given version. + +This script will do the following: + Ensure a release notes file exists at `docs/admin/release_notes/version_{version}.md`. + Ensure the `mkdocs.yml` file is updated to add the release notes file to the navigation. + Ensure the `pyproject.toml` `tool.towncrier.filename` is updated to reference the release notes file. + +It shouldn't be necessary to run this file manually. It is automatically called by `invoke generate-release-notes`. + +Example: + $ python bin/ensure_release_notes.py --version '1.0' +""" + +import argparse + +try: + import tomllib +except ImportError: + import tomli as tomllib + +from pathlib import Path + + +def release_notes_pyproject_toml(version): + """Update the pyproject.toml file to set the towncrier filename for the given version.""" + pyproject_file = Path(__file__).parent.parent / "pyproject.toml" + pyproject_content = pyproject_file.read_text() + pyproject_data = tomllib.loads(pyproject_content) + release_notes_file = f"docs/admin/release_notes/version_{version}.md" + + # Update the towncrier filename + if pyproject_data["tool"]["towncrier"].get("filename", "") != release_notes_file: + pyproject_data["tool"]["towncrier"]["filename"] = release_notes_file + + # Write back the updated content to pyproject.toml + # tomllib is not used to write the file because it is not roundtrippable + new_pyproject_content = [] + in_towncrier_section = False + for line in pyproject_content.splitlines(): + if line.strip() == "[tool.towncrier]": + in_towncrier_section = True + new_pyproject_content.append(line) + continue + if in_towncrier_section: + if line.strip().startswith("filename"): + new_pyproject_content.append(f'filename = "docs/admin/release_notes/version_{version}.md"') + in_towncrier_section = False # Only replace the first occurrence + else: + new_pyproject_content.append(line) + else: + new_pyproject_content.append(line) + + pyproject_file.write_text("\n".join(new_pyproject_content)) + # Add a newline at the end of the file if it doesn't exist + if not pyproject_file.read_text().endswith("\n"): + pyproject_file.write_text(pyproject_file.read_text() + "\n") + # Remind the user to update the release notes file. + print( + f"\033[33mRemember to update the Release Overview section in the release notes file: {release_notes_file}\033[0m" + ) + + +def ensure_release_notes_file(version): + """Ensure that the release notes file for the given version exists and is referenced in mkdocs.yml.""" + release_notes_file = Path(__file__).parent.parent / "docs" / "admin" / "release_notes" / f"version_{version}.md" + if not release_notes_file.exists(): + # Create a new release notes file with a basic template from towncrier_header.txt + towncrier_header = Path(__file__).parent.parent / "towncrier_header.txt" + content = towncrier_header.read_text().format(version=version) + release_notes_file.write_text(content) + + +def ensure_mkdocs_version(version): + """Ensure that mkdocs.yml includes the new release notes file in the navigation.""" + mkdocs_yml_file = Path(__file__).parent.parent / "mkdocs.yml" + mkdocs_yml_content = mkdocs_yml_file.read_text() + release_notes_nav_entry = f' - v{version}: "admin/release_notes/version_{version}.md"\n' + if release_notes_nav_entry in mkdocs_yml_content: + return + + # Add the new release notes entry to the mkdocs.yml content + if "Release Notes:" in mkdocs_yml_content: + mkdocs_yml_content = mkdocs_yml_content.replace( + ' - "admin/release_notes/index.md"\n', + f' - "admin/release_notes/index.md"\n{release_notes_nav_entry}', + ) + + mkdocs_yml_file.write_text(mkdocs_yml_content) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Ensure release notes exist for a given version.") + parser.add_argument("--version", help="The version number (e.g. 2.2)") + args = parser.parse_args() + ensure_release_notes_file(args.version) + ensure_mkdocs_version(args.version) + release_notes_pyproject_toml(args.version) diff --git a/docs/admin/release_notes/version_1.0.md b/docs/admin/release_notes/version_1.0.md index 63ef2244..770cb152 100644 --- a/docs/admin/release_notes/version_1.0.md +++ b/docs/admin/release_notes/version_1.0.md @@ -6,7 +6,11 @@ - Commit to SemVer - F5 fixes +<<<<<<< HEAD ## v1.0.0 - 2021-11 +======= +## [v1.0.0] - 2026-04-17 +>>>>>>> 039361e (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) ### Added diff --git a/pyproject.toml b/pyproject.toml index d8384cfa..ca442a74 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,12 +26,16 @@ include = [ [tool.poetry.dependencies] python = ">=3.10,<3.14" +<<<<<<< HEAD napalm = {version = "^4.0.0", optional = true} jsonschema = {version = "^4.17.3", optional = true} legacycrypt = {version = "0.3", optional = true} [tool.poetry.extras] optionals = ["jsonschema", "napalm", "legacycrypt"] +======= +click = "*" +>>>>>>> 039361e (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) [tool.poetry.group.dev.dependencies] coverage = "*" diff --git a/tasks.py b/tasks.py index 91599e9f..aa41edb2 100644 --- a/tasks.py +++ b/tasks.py @@ -209,6 +209,16 @@ def pytest(context, pattern=None, label=None): exec_cmd = " && ".join([doc_test_cmd, pytest_cmd, coverage_cmd]) run_command(context, exec_cmd) + doc_test_cmd = "pytest -vv --doctest-modules netutils/" + pytest_cmd = "coverage run --source=netutils -m pytest" + if pattern: + pytest_cmd += "".join([f" -k {_pattern}" for _pattern in pattern]) + if label: + pytest_cmd += "".join([f" {_label}" for _label in label]) + coverage_cmd = "coverage report" + exec_cmd = " && ".join([doc_test_cmd, pytest_cmd, coverage_cmd]) + run_command(context, exec_cmd) + @task(aliases=("a",)) def autoformat(context): @@ -361,14 +371,19 @@ def docs(context): @task( help={ "version": "Version of netutils to generate the release notes for.", + "date": "Date of the release (default: today).", } ) -def generate_release_notes(context, version=""): +def generate_release_notes(context, version="", date=""): """Generate Release Notes using Towncrier.""" - command = "poetry run towncrier build" - if version: - command += f" --version {version}" - else: - command += " --version `poetry version -s`" + if not version: + version = context.run("poetry version --short", hide=True).stdout.strip() + + version_major_minor = ".".join(version.split(".")[:2]) + context.run(f"poetry run python bin/ensure_release_notes.py --version {version_major_minor}") + + command = f"poetry run towncrier build --version {version} --yes" + if date: + command += f" --date {date}" # Due to issues with git repo ownership in the containers, this must always run locally. context.run(command) diff --git a/towncrier_header.txt b/towncrier_header.txt new file mode 100644 index 00000000..a350a182 --- /dev/null +++ b/towncrier_header.txt @@ -0,0 +1,9 @@ +# v{version} Release Notes + +This document describes all new features and changes in the release. 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 + +