Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions .github/workflows/update-nautobot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
name: "Update Nautobot Version"

on:
schedule:
# Run every Tuesday at midnight UTC
- cron: "0 0 * * 2"
workflow_dispatch:

permissions:
contents: "write"
pull-requests: "write"

jobs:
update-nautobot:
runs-on: "ubuntu-latest"
steps:
- name: "Check out repository"
uses: "actions/checkout@v4"

- name: "Set up Python"
uses: "actions/setup-python@v5"
with:
python-version: "3.12"

- name: "Install Poetry"
uses: "snok/install-poetry@v1"
with:
version: "2.1.3"
virtualenvs-create: true
virtualenvs-in-project: true

- name: "Install dependencies"
run: "poetry install"

- name: "Update pyproject.toml with latest Nautobot from PyPI"
id: "update"
run: "poetry run invoke update-nautobot-deps --output='$GITHUB_OUTPUT'"

- name: "Update poetry.lock"
run: "poetry lock"

- name: "Create Pull Request"
uses: "peter-evans/create-pull-request@v6"
with:
token: "${{ secrets.GITHUB_TOKEN }}"
branch: "deps/nautobot-version-update"
delete-branch: true
title: "chore: update Nautobot to ${{ steps.update.outputs.version }}"
body: |
## Automated Nautobot Version Update

This PR updates the project to use the latest Nautobot version from PyPI.

**Changes:**
- **nautobot**: `${{ steps.update.outputs.version }}`
- **python**: `${{ steps.update.outputs.requires_python }}` (matches Nautobot's requires_python)

---
*This pull request was created automatically by the [Update Nautobot Version](.github/workflows/update-nautobot.yml) workflow.*
labels: |
dependencies
automated
commit-message: "chore: update Nautobot to ${{ steps.update.outputs.version }}"
96 changes: 95 additions & 1 deletion tasks.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
"""Development Tasks."""

from time import sleep
import json
import os
import re
from time import sleep
from urllib.request import urlopen

import toml
from invoke import Collection, task as invoke_task

Expand Down Expand Up @@ -290,3 +294,93 @@ def db_import(context):

print("Importing DB...\n")
docker_compose(context, import_cmd, pty=True)


# ------------------------------------------------------------------------------
# NAUTOBOT VERSION UPDATE (for CI / pyproject.toml sync with PyPI)
# ------------------------------------------------------------------------------
PYPI_NAUTOBOT_URL = "https://pypi.org/pypi/nautobot/json"


def _fetch_nautobot_metadata():
"""Fetch latest Nautobot version and requires_python from PyPI."""
with urlopen(PYPI_NAUTOBOT_URL) as response:
data = json.load(response)
info = data.get("info", {})
version = info.get("version", "")
requires_python = info.get("requires_python") or ""
if requires_python:
# Normalize: PyPI may use '<3.14,>=3.10' or '>=3.10,<3.14'
parts = sorted(
requires_python.split(","),
key=lambda x: (x.strip().startswith("<"), x),
)
requires_python = ",".join(p.strip() for p in parts)
return version, requires_python


def _update_pyproject_nautobot(version, requires_python, pyproject_path="pyproject.toml"):
"""Update nautobot and python version in pyproject.toml."""
with open(pyproject_path, "r", encoding="utf-8") as f:
content = f.read()

content = re.sub(
r'^(nautobot\s*=\s*)"[^"]*"',
rf'\1"{version}"',
content,
flags=re.MULTILINE,
)
if requires_python:
content = re.sub(
r'^(python\s*=\s*)"[^"]*"',
rf'\1"{requires_python}"',
content,
flags=re.MULTILINE,
)

with open(pyproject_path, "w", encoding="utf-8") as f:
f.write(content)


@task
def get_latest_nautobot(context):
"""Fetch and print the latest Nautobot version and requires_python from PyPI."""
version, requires_python = _fetch_nautobot_metadata()
print(f"Latest Nautobot: {version}, Requires-Python: {requires_python}")
return version, requires_python


@task(
help={
"version": "Nautobot version to set (default: fetch from PyPI)",
"requires_python": "Python version constraint (default: fetch from PyPI)",
"output": "If set (e.g. $GITHUB_OUTPUT), append version= and requires_python= for CI",
}
)
def update_nautobot_deps(
context,
version=None,
requires_python=None,
output=None,
):
"""
Update pyproject.toml with the latest Nautobot version and Python constraint from PyPI.

Fetches metadata from PyPI if version/requires_python not provided.
Use --output=$GITHUB_OUTPUT in CI to write values for workflow outputs.
"""
if version is None or requires_python is None:
fetched_version, fetched_rp = _fetch_nautobot_metadata()
version = version or fetched_version
requires_python = requires_python or fetched_rp

_update_pyproject_nautobot(version, requires_python)

print(f"Updated nautobot to {version}")
if requires_python:
print(f"Updated python to {requires_python}")

if output:
with open(output, "a", encoding="utf-8") as f:
f.write(f"version={version}\n")
f.write(f"requires_python={requires_python}\n")
Loading