Skip to content

Commit 25dba34

Browse files
authored
Merge pull request #1152 from nautobot/release/4.2.0
Release v4.2.0
2 parents d489ee8 + 4f1bd75 commit 25dba34

File tree

111 files changed

+6881
-2531
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

111 files changed

+6881
-2531
lines changed

.cookiecutter.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@
1919
"_drift_manager": {
2020
"template": "https://github.com/nautobot/cookiecutter-nautobot-app.git",
2121
"template_dir": "nautobot-app",
22-
"template_ref": "nautobot-app-v3.0.0",
22+
"template_ref": "nautobot-app-v3.1.2",
2323
"cookie_dir": "",
2424
"pull_request_strategy": "create",
2525
"post_actions": [],
2626
"draft": false,
27-
"baked_commit_ref": "704ce3b7e8c6a47ff62771294c50a975ee377c37",
27+
"baked_commit_ref": "f567db50e4dc9c1dbd5896a543f78bc21d2b5f1a",
2828
"drift_managed_branch": "develop"
2929
}
3030
}

.github/workflows/ci.yml

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
name: "CI"
3-
concurrency: # Cancel any existing runs of this workflow for this same PR
3+
concurrency: # Cancel any existing runs of this workflow for this same PR
44
group: "${{ github.workflow }}-${{ github.ref }}"
55
cancel-in-progress: true
66
on: # yamllint disable-line rule:truthy rule:comments
@@ -20,7 +20,7 @@ jobs:
2020
- name: "Check out repository code"
2121
uses: "actions/checkout@v4"
2222
- name: "Setup environment"
23-
uses: "networktocode/gh-action-setup-poetry-environment@v6"
23+
uses: "networktocode/gh-action-setup-poetry-environment@v7"
2424
with:
2525
poetry-version: "2.1.3"
2626
poetry-install-options: "--only-root"
@@ -44,7 +44,7 @@ jobs:
4444
with:
4545
name: "poetry-lock"
4646
- name: "Setup environment"
47-
uses: "networktocode/gh-action-setup-poetry-environment@v6"
47+
uses: "networktocode/gh-action-setup-poetry-environment@v7"
4848
with:
4949
poetry-version: "2.1.3"
5050
- name: "Linting: ruff format"
@@ -62,7 +62,7 @@ jobs:
6262
with:
6363
name: "poetry-lock"
6464
- name: "Setup environment"
65-
uses: "networktocode/gh-action-setup-poetry-environment@v6"
65+
uses: "networktocode/gh-action-setup-poetry-environment@v7"
6666
with:
6767
poetry-version: "2.1.3"
6868
- name: "Linting: ruff"
@@ -80,7 +80,7 @@ jobs:
8080
with:
8181
name: "poetry-lock"
8282
- name: "Setup environment"
83-
uses: "networktocode/gh-action-setup-poetry-environment@v6"
83+
uses: "networktocode/gh-action-setup-poetry-environment@v7"
8484
with:
8585
poetry-version: "2.1.3"
8686
poetry-install-options: "--only dev,docs"
@@ -94,11 +94,29 @@ jobs:
9494
- name: "Check out repository code"
9595
uses: "actions/checkout@v4"
9696
- name: "Setup environment"
97-
uses: "networktocode/gh-action-setup-poetry-environment@v6"
97+
uses: "networktocode/gh-action-setup-poetry-environment@v7"
9898
with:
9999
poetry-version: "2.1.3"
100100
- name: "Checking: poetry lock file"
101101
run: "poetry run invoke lock --check"
102+
djlint:
103+
needs: "generate-lockfile"
104+
runs-on: "ubuntu-latest"
105+
env:
106+
INVOKE_NAUTOBOT_SSOT_LOCAL: "True"
107+
steps:
108+
- name: "Check out repository code"
109+
uses: "actions/checkout@v4"
110+
- name: "Download poetry.lock artifact"
111+
uses: "actions/download-artifact@v4"
112+
with:
113+
name: "poetry-lock"
114+
- name: "Setup environment"
115+
uses: "networktocode/gh-action-setup-poetry-environment@v7"
116+
with:
117+
poetry-version: "2.1.3"
118+
- name: "Linting: djlint"
119+
run: "poetry run invoke djlint"
102120
yamllint:
103121
needs: "generate-lockfile"
104122
runs-on: "ubuntu-latest"
@@ -112,7 +130,7 @@ jobs:
112130
with:
113131
name: "poetry-lock"
114132
- name: "Setup environment"
115-
uses: "networktocode/gh-action-setup-poetry-environment@v6"
133+
uses: "networktocode/gh-action-setup-poetry-environment@v7"
116134
with:
117135
poetry-version: "2.1.3"
118136
- name: "Linting: yamllint"
@@ -130,7 +148,7 @@ jobs:
130148
with:
131149
name: "poetry-lock"
132150
- name: "Setup environment"
133-
uses: "networktocode/gh-action-setup-poetry-environment@v6"
151+
uses: "networktocode/gh-action-setup-poetry-environment@v7"
134152
with:
135153
poetry-version: "2.1.3"
136154
- name: "Linting: markdownlint"
@@ -155,20 +173,18 @@ jobs:
155173
- name: "Check out repository code"
156174
uses: "actions/checkout@v4"
157175
- name: "Setup environment"
158-
uses: "networktocode/gh-action-setup-poetry-environment@v6"
176+
uses: "networktocode/gh-action-setup-poetry-environment@v7"
159177
with:
160178
poetry-version: "2.1.3"
161-
- name: "Pip install virtualenv to avoid issue with virtualenv --wheel"
162-
run: "~/.local/share/pypoetry/venv/bin/pip install virtualenv==20.30.0"
163179
- name: "Constrain Nautobot version and regenerate lock file"
164180
env:
165181
INVOKE_NAUTOBOT_SSOT_LOCAL: "true"
166182
run: "poetry run invoke lock --constrain-nautobot-ver --constrain-python-ver=${{ matrix.python-version }}"
167183
- name: "Set up Docker Buildx"
168184
id: "buildx"
169-
uses: "docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2" # v3.10.0
185+
uses: "docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2" # v3.10.0
170186
- name: "Build"
171-
uses: "docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25" # v5.4.0
187+
uses: "docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25" # v5.4.0
172188
with:
173189
builder: "${{ steps.buildx.outputs.name }}"
174190
context: "./"
@@ -194,7 +210,7 @@ jobs:
194210
strategy:
195211
fail-fast: true
196212
matrix:
197-
python-version: ["3.10"] # 3.13 stable is tested in unittest_report stage.
213+
python-version: ["3.10"] # 3.13 stable is tested in unittest_report stage.
198214
db-backend: ["postgresql"]
199215
nautobot-version: ["stable"]
200216
include:
@@ -212,20 +228,18 @@ jobs:
212228
- name: "Check out repository code"
213229
uses: "actions/checkout@v4"
214230
- name: "Setup environment"
215-
uses: "networktocode/gh-action-setup-poetry-environment@v6"
231+
uses: "networktocode/gh-action-setup-poetry-environment@v7"
216232
with:
217233
poetry-version: "2.1.3"
218-
- name: "Pip install virtualenv to avoid issue with virtualenv --wheel"
219-
run: "~/.local/share/pypoetry/venv/bin/pip install virtualenv==20.30.0"
220234
- name: "Constrain Nautobot version and regenerate lock file"
221235
env:
222236
INVOKE_NAUTOBOT_SSOT_LOCAL: "true"
223237
run: "poetry run invoke lock --constrain-nautobot-ver --constrain-python-ver=${{ matrix.python-version }}"
224238
- name: "Set up Docker Buildx"
225239
id: "buildx"
226-
uses: "docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2" # v3.10.0
240+
uses: "docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2" # v3.10.0
227241
- name: "Build"
228-
uses: "docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25" # v5.4.0
242+
uses: "docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25" # v5.4.0
229243
with:
230244
builder: "${{ steps.buildx.outputs.name }}"
231245
context: "./"
@@ -264,7 +278,7 @@ jobs:
264278
- name: "Check out repository code"
265279
uses: "actions/checkout@v4"
266280
- name: "Setup environment"
267-
uses: "networktocode/gh-action-setup-poetry-environment@v6"
281+
uses: "networktocode/gh-action-setup-poetry-environment@v7"
268282
with:
269283
poetry-version: "2.1.3"
270284
- name: "Constrain Nautobot version and regenerate lock file"
@@ -273,9 +287,9 @@ jobs:
273287
run: "poetry run invoke lock --constrain-nautobot-ver --constrain-python-ver=${{ matrix.python-version }}"
274288
- name: "Set up Docker Buildx"
275289
id: "buildx"
276-
uses: "docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2" # v3.10.0
290+
uses: "docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2" # v3.10.0
277291
- name: "Build"
278-
uses: "docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25" # v5.4.0
292+
uses: "docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25" # v5.4.0
279293
with:
280294
builder: "${{ steps.buildx.outputs.name }}"
281295
context: "./"
@@ -301,7 +315,7 @@ jobs:
301315
contains(fromJson('["develop","ltm-1.6"]'), github.base_ref) &&
302316
(github.head_ref != 'main') && (!startsWith(github.head_ref, 'release'))
303317
id: "coverage_comment"
304-
uses: "py-cov-action/python-coverage-comment-action@d1ff8fbb5ff80feedb3faa0f6d7b424f417ad0e1" # v3.30
318+
uses: "py-cov-action/python-coverage-comment-action@d1ff8fbb5ff80feedb3faa0f6d7b424f417ad0e1" # v3.30
305319
with:
306320
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
307321
MINIMUM_GREEN: 90
@@ -332,7 +346,7 @@ jobs:
332346
with:
333347
name: "poetry-lock"
334348
- name: "Setup environment"
335-
uses: "networktocode/gh-action-setup-poetry-environment@v6"
349+
uses: "networktocode/gh-action-setup-poetry-environment@v7"
336350
with:
337351
poetry-version: "2.1.3"
338352
- name: "Check for changelog entry"
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
---
2+
name: "Prepare Release"
3+
on: # yamllint disable-line rule:truthy rule:comments
4+
workflow_dispatch:
5+
inputs:
6+
bump_rule:
7+
description: "Select the version bump type"
8+
required: true
9+
default: "patch"
10+
type: "choice"
11+
options:
12+
- "prerelease"
13+
- "patch"
14+
- "minor"
15+
- "major"
16+
target_branch:
17+
description: "Create the release from this branch (default: main)."
18+
required: true
19+
default: "main"
20+
date:
21+
description: "Date of the release YYYY-MM-DD (defaults to today's date in the US Eastern TZ)."
22+
required: false
23+
default: ""
24+
25+
jobs:
26+
prepare-release:
27+
permissions:
28+
contents: "write"
29+
pull-requests: "write"
30+
name: "Prepare Release"
31+
runs-on: "ubuntu-latest"
32+
steps:
33+
- name: "Checkout code"
34+
uses: "actions/checkout@v4"
35+
with:
36+
# If target_branch is 'main', use 'develop' as the source branch. Otherwise, the source and target branch are the same.
37+
ref: "${{ github.event.inputs['target_branch'] == 'main' && 'develop' || github.event.inputs['target_branch'] }}"
38+
fetch-depth: 0 # Fetch all history for git tags
39+
40+
- name: "Setup environment"
41+
uses: "networktocode/gh-action-setup-poetry-environment@v6"
42+
with:
43+
poetry-version: "2.1.3"
44+
poetry-install-options: "--with dev"
45+
46+
- name: "Validate Branch and Tags"
47+
run: |
48+
# 1. Verify branch exists
49+
if ! git rev-parse --verify origin/${{ github.event.inputs.target_branch }} > /dev/null 2>&1; then
50+
echo "Error: Branch ${{ github.event.inputs.target_branch }} does not exist."
51+
exit 1
52+
fi
53+
54+
# 2. Try to get the previous version tag
55+
# If it fails (no tags), get the hash of the first commit
56+
if PREV_TAG=$(git describe --tags --abbrev=0 2>/dev/null); then
57+
echo "PREVIOUS_TAG=$PREV_TAG" >> $GITHUB_ENV
58+
echo "Found previous tag: $PREV_TAG"
59+
else
60+
# Fallback to the first commit in the repository
61+
FIRST_COMMIT=$(git rev-list --max-parents=0 HEAD)
62+
echo "PREVIOUS_TAG=$FIRST_COMMIT" >> $GITHUB_ENV
63+
echo "No tags found. Falling back to initial commit: $FIRST_COMMIT"
64+
fi
65+
66+
- name: "Determine New Version"
67+
id: "versioning"
68+
run: |
69+
# Perform the bump based on the user input
70+
poetry version ${{ github.event.inputs.bump_rule }}
71+
72+
# Capture the New version string for use in other steps
73+
NEW_VER=$(poetry version --short)
74+
echo "NEW_VERSION=$NEW_VER" >> $GITHUB_ENV
75+
echo "RELEASE_BRANCH=release/$NEW_VER" >> $GITHUB_ENV
76+
77+
- name: "Set Date Variable"
78+
run: |
79+
if [ -z "${{ github.event.inputs.date }}" ]; then
80+
RELEASE_DATE=$(TZ=America/New_York date +%Y-%m-%d)
81+
else
82+
RELEASE_DATE="${{ github.event.inputs.date }}"
83+
fi
84+
echo "RELEASE_DATE=$RELEASE_DATE" >> $GITHUB_ENV
85+
86+
- name: "Create Release Branch"
87+
env:
88+
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
89+
run: |
90+
git config user.name "${{ github.actor }}"
91+
git config user.email "${{ github.actor }}@users.noreply.github.com"
92+
93+
# Ensure release branch doesn't already exist
94+
if git rev-parse --verify origin/${{ env.RELEASE_BRANCH }} > /dev/null 2>&1; then
95+
echo "Error: Release branch ${{ env.RELEASE_BRANCH }} already exists."
96+
exit 1
97+
fi
98+
99+
# Create a new branch for the release
100+
git checkout -b "${{ env.RELEASE_BRANCH }}"
101+
102+
- name: "Regenerate poetry.lock"
103+
run: "poetry lock --regenerate"
104+
105+
- name: "Generate Github Release Notes"
106+
env:
107+
GH_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
108+
run: |
109+
# 1. Get Towncrier Draft
110+
TOWNCRIER_NOTES=$(poetry run towncrier build --version "${{ env.NEW_VERSION }}" --date "${{ env.RELEASE_DATE }}" --draft)
111+
112+
# 2. Call GitHub API to generate raw notes
113+
RAW_GH_NOTES=$(gh api /repos/${{ github.repository }}/releases/generate-notes \
114+
-f tag_name="v${{ env.NEW_VERSION }}" \
115+
-f target_commitish="${{ github.event.inputs['target_branch'] == 'main' && 'develop' || github.event.inputs['target_branch'] }}" \
116+
-f previous_tag_name="${{ env.PREVIOUS_TAG }}" --jq '.body')
117+
118+
# 3. Parse usernames (Regex match)
119+
# We use grep to find "@user" patterns, sort, and uniq them
120+
USERNAMES=$(echo "$RAW_GH_NOTES" | grep -oP 'by @\K[a-zA-Z0-9-]+' | sort -u | grep -vE 'dependabot|nautobot-bot|github-actions' || true)
121+
122+
# 4. Format the Contributors section
123+
CONTRIBUTORS_SECTION="## Contributors"
124+
for user in $USERNAMES; do
125+
CONTRIBUTORS_SECTION="$CONTRIBUTORS_SECTION"$'\n'"* @$user"
126+
done
127+
128+
# 5. Extract the "Full Changelog" or "New Contributors" part
129+
# Using awk to grab everything from '## New Contributors' or '**Full Changelog**' to the end
130+
GH_FOOTER=$(echo "$RAW_GH_NOTES" | awk '/## New Contributors/ || /\*\*Full Changelog\*\*/ {found=1} found {print}')
131+
if [ -z "$GH_FOOTER" ]; then
132+
GH_FOOTER=$(echo "$RAW_GH_NOTES" | sed -n '/**Full Changelog**/,$p')
133+
fi
134+
135+
# 6. Combine everything
136+
FINAL_NOTES="$TOWNCRIER_NOTES"$'\n\n'"$CONTRIBUTORS_SECTION"$'\n\n'"$GH_FOOTER"
137+
138+
# 7. Save to a temporary file to avoid shell argument length limits
139+
echo "$FINAL_NOTES" > ../consolidated_notes.md
140+
141+
- name: "Generate App Release Notes and update mkdocs.yml"
142+
run: "poetry run inv generate-release-notes --version '${{ env.NEW_VERSION }}' --date '${{ env.RELEASE_DATE }}'"
143+
144+
- name: "Commit Changes and Push"
145+
run: |
146+
# Add all changes (pyproject.toml, poetry.lock, etc.)
147+
git add .
148+
git commit -m "prepare release v${{ env.NEW_VERSION }}"
149+
git push origin "${{ env.RELEASE_BRANCH }}"
150+
151+
- name: "Create Pull Request"
152+
env:
153+
GH_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
154+
run: |
155+
gh pr create \
156+
--title "Release v${{ env.NEW_VERSION }}" \
157+
--body-file "../consolidated_notes.md" \
158+
--base "${{ github.event.inputs.target_branch }}" \
159+
--head "${{ env.RELEASE_BRANCH }}"
160+
161+
- name: "Create Draft Release"
162+
env:
163+
GH_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
164+
run: |
165+
if [[ "${{ github.event.inputs.bump_rule }}" == "prerelease" ]]; then
166+
RELEASE_FLAGS="--prerelease"
167+
elif [[ "${{ github.event.inputs.target_branch }}" == "main" ]]; then
168+
RELEASE_FLAGS="--latest"
169+
else
170+
RELEASE_FLAGS="--latest=false"
171+
fi
172+
173+
gh release create "v${{ env.NEW_VERSION }}" \
174+
--draft \
175+
$RELEASE_FLAGS \
176+
--title "v${{ env.NEW_VERSION }} - ${{ env.RELEASE_DATE }}" \
177+
--notes-file "../consolidated_notes.md" \
178+
--target "${{ github.event.inputs.target_branch }}"

0 commit comments

Comments
 (0)