diff --git a/.cookiecutter.json b/.cookiecutter.json index fd87fa73..97f0405b 100644 --- a/.cookiecutter.json +++ b/.cookiecutter.json @@ -23,7 +23,19 @@ "pull_request_strategy": "update-or-create", "post_actions": [], "draft": false, - "baked_commit_ref": "b23a9ed5a4714810d83670ad47cc182764c6d464", +<<<<<<< HEAD +<<<<<<< HEAD +<<<<<<< HEAD + "baked_commit_ref": "46f70d30baa1e0c5af3da3fdcf1c77b31157d3f9", +======= + "baked_commit_ref": "e188d3786e8b7973c1ef1f1ccf6d4f1a81ac27ea", +>>>>>>> 039361e (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) +======= + "baked_commit_ref": "d6e9480f9645bb5760fc1118c99a7f838cd85226", +>>>>>>> c6f4d54 (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) +======= + "baked_commit_ref": "2f5f33d567263f29941bfe3c3fe4db5e39cbbf50", +>>>>>>> fb127c6 (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 a6cd1872..20f5504a 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"] @@ -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" @@ -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" @@ -56,7 +56,9 @@ jobs: if: "startsWith(github.ref, 'refs/tags/v')" needs: "build" environment: "pypi" - # Steps to publish to PyPI. + # IMPORTANT: this permission is mandatory for trusted publishing. + permissions: + id-token: "write" steps: - name: "Retrieve built package from cache" uses: "actions/download-artifact@v4" @@ -65,11 +67,14 @@ jobs: path: "dist/" - name: "Publish package distributions to PyPI" uses: "pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e" # v1.13.0 +<<<<<<< HEAD ## Used for networktocode org since trusted publisher isn't supported for GitHub Plan. with: user: "__token__" password: "${{ secrets.PYPI_API_TOKEN }}" # End publish to PyPI job. +======= +>>>>>>> fb127c6 (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool) slack-notify: needs: @@ -104,3 +109,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/LICENSE b/LICENSE index 6ce362fa..9e40eee1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ Apache Software License 2.0 -Copyright (c) 2021-2025, Network to Code, LLC +Copyright (c) 2021-2026, Network to Code, LLC 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..62f826d6 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Netutils
-
+
@@ -18,9 +18,27 @@ 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
+<<<<<<< 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)
+=======
+- [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.
+>>>>>>> c6f4d54 (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.
+>>>>>>> fb127c6 (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/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..ed8eb129 100644
--- a/docs/admin/release_notes/version_1.0.md
+++ b/docs/admin/release_notes/version_1.0.md
@@ -6,7 +6,19 @@
- Commit to SemVer
- F5 fixes
+<<<<<<< HEAD
+<<<<<<< HEAD
+<<<<<<< HEAD
## v1.0.0 - 2021-11
+=======
+## [v1.0.0] - 2026-04-17
+>>>>>>> 039361e (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool)
+=======
+## [v1.0.0] - 2026-07-23
+>>>>>>> c6f4d54 (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool)
+=======
+## [v1.0.0] - 2026-08-12
+>>>>>>> fb127c6 (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool)
### Added
diff --git a/docs/generate_code_reference_pages.py b/docs/generate_code_reference_pages.py
new file mode 100644
index 00000000..59d81288
--- /dev/null
+++ b/docs/generate_code_reference_pages.py
@@ -0,0 +1,20 @@
+"""Generate code reference pages."""
+
+from pathlib import Path
+
+import mkdocs_gen_files
+
+for file_path in Path("netutils").rglob("*.py"):
+ module_path = file_path.with_suffix("")
+ doc_path = file_path.with_suffix(".md")
+ full_doc_path = Path("code-reference", doc_path)
+
+ parts = list(module_path.parts)
+ if parts[-1] == "__init__":
+ parts = parts[:-1]
+
+ with mkdocs_gen_files.open(full_doc_path, "w") as fd:
+ identifier = ".".join(parts)
+ print(f"::: {identifier}", file=fd)
+
+ mkdocs_gen_files.set_edit_path(full_doc_path, file_path)
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..a56f97d2 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -24,55 +24,92 @@ include = [
"netutils/protocols.json"
]
+packages = [
+ { include = "netutils" },
+]
+
[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"]
+=======
+=======
+>>>>>>> c6f4d54 (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool)
+=======
+>>>>>>> fb127c6 (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool)
+click = "*"
+>>>>>>> 039361e (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool)
[tool.poetry.group.dev.dependencies]
+<<<<<<< HEAD
coverage = "*"
invoke = "*"
+=======
+coverage = "~7.15.4"
+>>>>>>> fb127c6 (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool)
pytest = "*"
mock = "*"
mypy = "*"
pyyaml = "^6.0.1"
+<<<<<<< HEAD
pylint = "*"
yamllint = "*"
toml = "^0.10.2"
attrs = "^23.2.0"
towncrier = ">=23.6.0,<=24.8.0"
ruff = "0.5.5"
+=======
+pylint = "~4.0.6"
+yamllint = "~1.38.0"
+invoke = "~3.0.3"
+toml = "^0.10.2"
+attrs = "^23.2.0"
+towncrier = "~25.8.0"
+ruff = "~0.16.2"
+>>>>>>> fb127c6 (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool)
Markdown = "*"
[tool.poetry.group.docs.dependencies]
# Rendering docs to HTML
-mkdocs = "1.6.1"
+mkdocs = "~1.6.1"
# Embedding YAML files into Markdown documents as tables
-markdown-data-tables = "1.0.0"
+markdown-data-tables = "~1.0.0"
# Render custom markdown for version added/changed/remove notes
-markdown-version-annotations = "1.0.1"
+markdown-version-annotations = "~1.0.1"
# Automatically generate some files as part of mkdocs build
-mkdocs-gen-files = "0.5.0"
+mkdocs-gen-files = "~0.6.1"
# Image lightboxing in mkdocs
-mkdocs-glightbox = "0.4.0"
+mkdocs-glightbox = "~0.5.2"
# Use Jinja2 templating in docs - see settings.md
-mkdocs-macros-plugin = "1.3.7"
+mkdocs-macros-plugin = "~1.5.0"
# Material for mkdocs theme
-mkdocs-material = "9.6.15"
+mkdocs-material = "~9.7.7"
# Handle docs redirections
-mkdocs-redirects = "1.2.2"
+mkdocs-redirects = "~1.2.3"
# Automatically handle index pages for docs sections
-mkdocs-section-index = "0.3.10"
+mkdocs-section-index = "~0.3.12"
# Automatic documentation from sources, for MkDocs
-mkdocstrings = "0.27.0"
+mkdocstrings = "~1.0.6"
# Python-specific extension to mkdocstrings
+<<<<<<< HEAD
mkdocstrings-python = "1.13.0"
griffe = "1.1.1"
mkdocs-python-classy = "0.1.3"
+=======
+mkdocstrings-python = "~2.0.5"
+
+[tool.poetry.scripts]
+netutils = 'netutils.cli:main'
+
+
+>>>>>>> fb127c6 (Cookie updated targeting develop by NetworkToCode Cookie Drift Manager Tool)
[tool.ruff]
line-length = 120
diff --git a/tasks.py b/tasks.py
index 84805a24..a217ac84 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,
}
}
@@ -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,
)
@@ -188,6 +189,56 @@ 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)
+
+ 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)
+
+ 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)
+
+ 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)
+
+ 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):
@@ -340,14 +391,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
+
+