[stable-2.20] Update the stable-2.20 branch (#3072)

* update core branch for stable-2.20

* remove devel only tooling
This commit is contained in:
Don Naro
2025-09-25 08:18:10 +01:00
committed by GitHub
parent df040ef284
commit 837169206d
17 changed files with 2 additions and 1245 deletions

View File

@@ -1,22 +0,0 @@
---
name: Scheduled build for devel docs
"on":
schedule:
# Run at 05:22 daily
- cron: '22 5 * * *'
jobs:
build-package-docs:
name: 📝 Build
uses: ./.github/workflows/reusable-build-docs.yaml
secrets:
DOCS_BOT_TOKEN: ${{ secrets.DOCS_BOT_TOKEN }}
deploy-package-docs:
name: 🚀 Deploy
needs: build-package-docs
uses: ./.github/workflows/reusable-deploy-docs.yaml
with:
deployment-environment: 'production'
secrets:
DEPLOY_DOC_BUILD: ${{ secrets.DEPLOY_DOC_BUILD }}

View File

@@ -1,27 +0,0 @@
---
name: Scheduled build for latest docs
"on":
schedule:
# Run at 05:41 on Monday
- cron: '41 5 * * 1'
jobs:
build-package-docs:
name: 📝 Build
uses: ./.github/workflows/reusable-build-docs.yaml
with:
repository-branch: 'stable-2.19'
ansible-package-version: '12'
secrets:
DOCS_BOT_TOKEN: ${{ secrets.DOCS_BOT_TOKEN }}
deploy-package-docs:
name: 🚀 Deploy
needs: build-package-docs
uses: ./.github/workflows/reusable-deploy-docs.yaml
with:
ansible-package-version: '12'
deployment-environment: 'production'
repository-branch: 'stable-2.19'
secrets:
DEPLOY_DOC_BUILD: ${{ secrets.DEPLOY_DOC_BUILD }}

View File

@@ -1,79 +0,0 @@
---
name: Build and deploy docs
"on":
schedule:
# Run at 05:17 on Tuesday and Thursday
- cron: '17 5 * * 2,4'
workflow_dispatch:
inputs:
repository-owner:
description: GitHub account or org that owns the repository
type: string
required: true
default: ansible
repository-name:
description: Name of the GitHub repository
type: string
required: true
default: ansible-documentation
repository-branch:
description: Branch, tag, or commit SHA
type: string
required: true
default: devel
ansible-package-version:
description: Ansible community package version
type: choice
required: true
default: devel
options:
- devel
- '12'
- '11'
- '10'
- '9'
generate-redirects:
description: Generate page redirects
type: boolean
default: true
deploy:
description: Deploy the build
type: boolean
required: true
default: false
deployment-environment:
description: Deployment environment
type: choice
required: true
default: test
options:
- production
- test
jobs:
build-package-docs:
name: 📝 Build
uses: ./.github/workflows/reusable-build-docs.yaml
with:
repository-owner: ${{ github.event.inputs.repository-owner || 'ansible' }}
repository-name: ${{ github.event.inputs.repository-name || 'ansible-documentation' }}
repository-branch: ${{ github.event.inputs.repository-branch || 'devel' }}
ansible-package-version: ${{ github.event.inputs.ansible-package-version || 'devel' }}
generate-redirects: >-
${{ github.event_name == 'workflow_dispatch'
&& github.event.inputs.generate-redirects == 'true' }}
secrets:
DOCS_BOT_TOKEN: ${{ secrets.DOCS_BOT_TOKEN }}
deploy-package-docs:
name: 🚀 Deploy
if: github.event_name == 'workflow_dispatch' && github.event.inputs.deploy == 'true'
needs: build-package-docs
uses: ./.github/workflows/reusable-deploy-docs.yaml
with:
ansible-package-version: ${{ github.event.inputs.ansible-package-version }}
deployment-environment: ${{ github.event.inputs.deployment-environment }}
repository-owner: ${{ github.event.inputs.repository-owner }}
repository-branch: ${{ github.event.inputs.repository-branch }}
secrets:
DEPLOY_DOC_BUILD: ${{ secrets.DEPLOY_DOC_BUILD }}

View File

@@ -1,66 +0,0 @@
---
name: "Refresh dev dependencies"
"on":
schedule:
# Weekly
- cron: "0 0 * * 0"
workflow_dispatch:
inputs:
reset-branch:
type: boolean
default: false
labels:
required: false
type: string
jobs:
refresh:
strategy:
fail-fast: false
matrix:
include:
- base-branch: devel
pr-branch: pip-compile/devel/dev
nox-args: >-
-e 'pip-compile(formatters)'
'pip-compile(typing)'
'pip-compile(static)'
'pip-compile(spelling)'
'pip-compile(tag)'
'pip-compile(pip-compile)'
python-versions: "3.12"
- base-branch: stable-2.19
pr-branch: pip-compile/stable-2.19/dev
nox-args: >-
-e 'pip-compile(formatters)'
'pip-compile(typing)'
'pip-compile(static)'
'pip-compile(spelling)'
python-versions: "3.11"
- base-branch: stable-2.18
pr-branch: pip-compile/stable-2.18/dev
nox-args: >-
-e 'pip-compile(formatters)'
'pip-compile(typing)'
'pip-compile(static)'
'pip-compile(spelling)'
python-versions: "3.11"
- base-branch: stable-2.17
pr-branch: pip-compile/stable-2.17/dev
nox-args: >-
-e 'pip-compile(formatters)'
'pip-compile(typing)'
'pip-compile(static)'
'pip-compile(spelling)'
python-versions: "3.10"
name: "Refresh dev dependencies"
uses: ./.github/workflows/reusable-pip-compile.yml
with:
message: "ci: refresh dev dependencies"
base-branch: "${{ matrix.base-branch }}"
pr-branch: "${{ matrix.pr-branch }}"
nox-args: "${{ matrix.nox-args }}"
python-versions: "${{ matrix.python-versions }}"
reset-branch: "${{ inputs.reset-branch || false }}"
labels: "${{ inputs.labels || 'no_backport,tooling' }}"
secrets: inherit

View File

@@ -1,36 +0,0 @@
---
name: "Refresh docs build dependencies"
"on":
schedule:
# Weekly
- cron: "0 0 * * 0"
workflow_dispatch:
inputs:
base-branch:
required: false
type: string
pr-branch:
required: false
type: string
reset-branch:
type: boolean
default: false
labels:
required: false
type: string
jobs:
refresh:
name: "Refresh docs build dependencies"
uses: ./.github/workflows/reusable-pip-compile.yml
with:
message: "ci: refresh docs build dependencies"
base-branch: "${{ inputs.base-branch || 'devel' }}"
pr-branch: "${{ inputs.pr-branch || 'pip-compile/devel/docs' }}"
nox-args: >-
-e
'pip-compile(requirements)'
reset-branch: "${{ inputs.reset-branch || false }}"
labels: "${{ inputs.labels || 'doc builds,no_backport' }}"
python-versions: "3.12"
secrets: inherit

View File

@@ -1,98 +0,0 @@
---
name: Ansible porting guide creation
on:
workflow_dispatch:
inputs:
ansible-build-data-branch:
description: >-
Release Branch name from the Ansible Build data PR.
(e.g. `refs/pull/1/merge`)
required: true
ansible-version:
description: >-
Exact release version. For example, 12.1.0
required: true
jobs:
upload-porting-guide:
name: Extract the porting guide
runs-on: ubuntu-latest
environment: github-bot
env:
GIT_BRANCH: "release/porting-guide-${{ inputs.ansible-version }}"
ANSIBLE_VERSION_FULL: ${{ inputs.ansible-version }}
CI_COMMIT_MESSAGE: >-
Add the Ansible community ${{ inputs.ansible-version }} porting guide
steps:
- name: Extract the major version
run: echo "ANSIBLE_VERSION_MAJOR=${ANSIBLE_VERSION_FULL%%.*}" >> "${GITHUB_ENV}"
shell: bash --noprofile --norc -O extglob -eEuo pipefail {0}
- name: Generate temp GITHUB_TOKEN
id: create_token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.BOT_APP_ID }} # From github-bot environment
private-key: ${{ secrets.BOT_APP_KEY }} # From github-bot environment
- name: Check out this repo src
uses: actions/checkout@v5
with:
token: ${{ steps.create_token.outputs.token }}
- name: Check out ansible-build-data
uses: actions/checkout@v5
with:
repository: ansible-community/ansible-build-data
ref: ${{ inputs.ansible-build-data-branch }}
path: ansible-build-data
- name: Copy the RST file to the correct path
run: >-
cp -v
"ansible-build-data/${ANSIBLE_VERSION_MAJOR}/porting_guide_${ANSIBLE_VERSION_MAJOR}.rst"
docs/docsite/rst/porting_guides/
- name: Set up git
run: |
git switch --create "${GIT_BRANCH}"
ACTOR_NAME="$(curl -s https://api.github.com/users/"${GITHUB_ACTOR}" | jq --raw-output '.name // .login')"
git config --global user.name "${ACTOR_NAME}"
git config --global user.email "${GITHUB_ACTOR_ID}+${GITHUB_ACTOR}@users.noreply.github.com"
- name: Add the porting guide
run: git add docs/docsite/rst/porting_guides/"porting_guide_${ANSIBLE_VERSION_MAJOR}.rst"
- name: Commit the porting guide
run: >-
git diff-index --quiet HEAD ||
git commit -m "${CI_COMMIT_MESSAGE}"
- name: Push to the repo
env:
GITHUB_TOKEN: ${{ steps.create_token.outputs.token }}
run: git push origin "${GIT_BRANCH}"
- name: Create the porting guide PR as draft
env:
GITHUB_TOKEN: ${{ steps.create_token.outputs.token }}
PR_BODY_MESSAGE: |-
##### SUMMARY
This is a draft PR. Please mark the PR as ready for review to trigger PR checks.
##### ISSUE TYPE
- Docs Pull Request
##### COMPONENT NAME
docs/docsite/rst/porting_guides/porting_guide_${{ env.ANSIBLE_VERSION_MAJOR }}.rst
run: >-
gh pr create
--draft
--base devel
--head "${GIT_BRANCH}"
--title "${CI_COMMIT_MESSAGE}"
--body "${PR_BODY_MESSAGE}"

View File

@@ -1,123 +0,0 @@
---
name: Build docs
"on":
workflow_call:
inputs:
repository-owner:
description: GitHub account or org that owns the repository
type: string
required: false
default: ansible
repository-name:
description: Name of the GitHub repository
type: string
required: false
default: ansible-documentation
repository-branch:
description: Branch, tag, or commit SHA
type: string
required: false
default: devel
ansible-package-version:
type: string
description: Ansible community package version
required: false
default: devel
generate-redirects:
description: Generate page redirects
type: boolean
default: true
secrets:
DOCS_BOT_TOKEN:
required: true
env:
PACKAGE_VERSION: ${{ inputs.ansible-package-version }}
jobs:
build-package-docs:
runs-on: ubuntu-latest
steps:
- name: Checkout Ansible documentation
uses: actions/checkout@v5
with:
repository: >-
${{
inputs.repository-owner
}}/${{
inputs.repository-name
}}
ref: ${{ inputs.repository-branch }}
path: build-directory
- name: Setup nox
uses: wntrblm/nox@2025.05.01
- name: Output Python info
run: python --version --version && which python
- name: Graft ansible-core
run: nox -s clone-core
working-directory: build-directory
- name: Install project requirements
run: >-
python -m pip install
-r tests/requirements.in
-c tests/requirements.txt
working-directory: build-directory
- name: Set the VERSION variable
run: echo VERSION="${PACKAGE_VERSION}" >> "${GITHUB_ENV}"
- name: Build the Ansible community package docs
run: >-
make webdocs ${{
inputs.generate-redirects && 'EXTRA_TAGS="-t redirects"' || ''
}} ANSIBLE_VERSION="${{
env.PACKAGE_VERSION != 'devel' && env.PACKAGE_VERSION || ''
}}"
working-directory: build-directory/docs/docsite
- name: Create a tarball with the build contents
run: >-
tar -czvf
ansible-package-docs-html-"${PACKAGE_VERSION}"-"$(date '+%Y-%m-%d')"-${{
github.run_id
}}-${{
github.run_number
}}-${{
github.run_attempt
}}.tar.gz
--directory=_build/html/ .
working-directory: build-directory/docs/docsite
- name: Create a downloadable archive that contains the tarball
uses: actions/upload-artifact@v4
with:
name: package-docs-build
path: build-directory/docs/docsite/ansible-package-docs-html-*.tar.gz
retention-days: 7
notify-build-failures:
if: failure()
needs: build-package-docs
runs-on: ubuntu-latest
env:
ROOM_URL: https://ansible-accounts.ems.host/_matrix/client/v3/rooms/!HJtetIFWYEIDBOXxFE:libera.chat/send/m.room.message
FAIL_MESSAGE: >-
Oh no! A community package docs build has failed.
Check this workflow run to see what went wrong:
https://github.com/ansible/ansible-documentation/actions/runs/${{ github.run_id }}
@orandon @samccann
steps:
- name: Set a transaction ID
run: echo "TX_ID=$(date +%s)" >> "${GITHUB_ENV}"
- name: Notify the DaWGs in Matrix
run: |
curl -X PUT "${{ env.ROOM_URL }}/${TX_ID}" \
-H "Authorization: Bearer ${{ secrets.DOCS_BOT_TOKEN }}" \
-H "Content-Type: application/json" \
-d '{"msgtype": "m.text", "body": "${{ env.FAIL_MESSAGE }}"}'

View File

@@ -1,129 +0,0 @@
---
name: Deploy docs
"on":
workflow_call:
inputs:
repository-owner:
description: GitHub account or org that owns the repository
type: string
required: false
default: ansible
repository-branch:
description: Branch, tag, or commit SHA
type: string
required: false
default: devel
ansible-package-version:
type: string
description: Ansible community package version
required: false
default: devel
deployment-environment:
description: Deployment environment
type: string
required: false
default: test
secrets:
DEPLOY_DOC_BUILD:
required: true
jobs:
log-inputs:
runs-on: ubuntu-latest
steps:
- name: Log the workflow inputs if deployed
run: |
{
echo "## Deployment details :shipit:";
echo "Publish to: ${{ inputs.deployment-environment }}";
echo "Package version: ${{ inputs.ansible-package-version }}";
echo "Owner: ${{ inputs.repository-owner }}";
echo "Branch: ${{ inputs.repository-branch }}";
} >> "${GITHUB_STEP_SUMMARY}"
deploy-package-docs:
runs-on: ubuntu-latest
environment:
name: deploy-package-docs
url: ${{ env.ENV_URL }}
env:
DEST_REPO: ansible-community/package-doc-builds
USER_EMAIL: "41898282+github-actions[bot]@users.noreply.github.com"
USER_NAME: "github-actions[bot]"
steps:
- name: Download the build archive
uses: actions/download-artifact@v5
with:
name: package-docs-build
- name: Extract the tarball
run: >-
tar -xvzf
ansible-package-docs-html-*.tar.gz
--one-top-level
- name: Set the production branch and url
if: inputs.deployment-environment == 'production'
env:
BRANCH_NAME: ${{ inputs.ansible-package-version }}
PROD_URL: https://ansible.readthedocs.io/projects/ansible
run: |
echo "BRANCH=${BRANCH_NAME}" >> "${GITHUB_ENV}"
echo "ENV_URL=${PROD_URL}/${BRANCH_NAME}" >> "${GITHUB_ENV}"
- name: Set the test branch and url
if: inputs.deployment-environment == 'test'
env:
TEST_URL: https://ansible-community.github.io/package-doc-builds
run: |
echo "BRANCH=gh-pages" >> "${GITHUB_ENV}"
echo "ENV_URL=${TEST_URL}" >> "${GITHUB_ENV}"
- name: Checkout the deploy directory
uses: actions/checkout@v5
with:
repository: ${{ env.DEST_REPO }}
ref: ${{ env.BRANCH }}
path: deploy-directory
fetch-depth: 0
ssh-key: ${{ secrets.DEPLOY_DOC_BUILD }}
persist-credentials: true
- name: Copy the generated HTML and assets for production
run: >-
rsync -av --delete --mkpath
ansible-package-docs-html-*/
deploy-directory/docs
- name: Create a norobots.txt file for the test site
if: inputs.deployment-environment == 'test'
run: |
echo "User-agent: *" > deploy-directory/docs/norobots.txt
echo "Disallow: /" >> deploy-directory/docs/norobots.txt
- name: Configure the git user
run: |
git config --local user.email "${USER_EMAIL}"
git config --local user.name "${USER_NAME}"
working-directory: deploy-directory
- name: Git add the generated HTML and assets
run: git add ./docs --all --force
working-directory: deploy-directory
- name: Commit generated HTML and assets
run: >-
git diff-index --quiet HEAD ||
git commit -m "Push docs build $(date '+%Y-%m-%d')-${{
github.run_id
}}-${{
github.run_number
}}-${{
github.run_attempt
}}"
working-directory: deploy-directory
- name: Push build to deploy repository
run: git push origin
working-directory: deploy-directory

View File

@@ -1,138 +0,0 @@
---
name: "Refresh pinned dependencies"
"on":
workflow_call:
inputs:
# Commit messae and PR title
message:
type: string
required: true
# Branch to create PR from
pr-branch:
type: string
required: true
# Branch to base PR on
base-branch:
type: string
required: true
# Nox session to call
nox-args:
type: string
required: true
# Files to commit
changed-files:
default: "tests/*.txt"
type: string
required: false
# Reset branch
reset-branch:
type: boolean
default: false
labels:
type: string
default: ""
python-versions:
type: string
required: true
jobs:
refresh:
runs-on: ubuntu-latest
environment: github-bot
steps:
- name: Generate temp GITHUB_TOKEN
id: create_token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.BOT_APP_ID }}
private-key: ${{ secrets.BOT_APP_KEY }}
- name: Check out repo
uses: actions/checkout@v5
with:
fetch-depth: 0
ref: "${{ inputs.base-branch }}"
token: "${{ steps.create_token.outputs.token }}"
- name: Fetch required contents of ansible-core
run: |
python docs/bin/clone-core.py
- name: Set up nox
uses: wntrblm/nox@2025.05.01
with:
python-versions: "${{ inputs.python-versions }}"
- name: Set up git committer
run: |
hacking/get_bot_user.sh "ansible-documentation-bot" "Ansible Documentation Bot"
- name: "Use a branch named ${{ inputs.pr-branch }}"
env:
base_branch: "${{ inputs.base-branch }}"
pr_branch: "${{ inputs.pr-branch }}"
id: branch
run: |
set -x
if git branch -r | grep "origin/${pr_branch}"; then
echo "branch-exists=true" >> "${GITHUB_OUTPUT}"
git switch "${pr_branch}"
${{ inputs.reset-branch && 'git reset --hard' || 'git rebase' }} \
"${base_branch}"
else
echo "branch-exists=false" >> "${GITHUB_OUTPUT}"
git switch -c "${pr_branch}"
fi
- name: "Run nox ${{ inputs.nox-args }}"
env:
# Ensure the latest pip version is used
VIRTUALENV_DOWNLOAD: '1'
#
run: |
nox ${{ inputs.nox-args }}
- name: Push new dependency versions and create a PR
env:
GITHUB_TOKEN: ${{ steps.create_token.outputs.token }}
base_branch: "${{ inputs.base-branch }}"
pr_branch: "${{ inputs.pr-branch }}"
message: "${{ inputs.message }}"
pr_title: "[${{ inputs.base-branch }}] ${{ inputs.message }}"
changed_files: "${{ inputs.changed-files }}"
labels: "${{ inputs.labels }}"
branch_exists: "${{ steps.branch.outputs.branch-exists }}"
run: |
set -x
git diff || :
# shellcheck disable=SC2086
git add ${changed_files}
# shellcheck disable=SC2086
if git diff-index --quiet HEAD ${changed_files}; then
echo "Nothing to do!"
exit
fi
git commit -m "${message}"
git push --force origin "${pr_branch}"
if [ "${branch_exists}" = "true" ]; then
# https://github.com/cli/cli/discussions/5792#discussioncomment-10410197
current_pr="$(gh pr list \
--head "${pr_branch}"\
--app ansible-documentation-bot \
--state open \
--json url --jq .[].url \
)"
if [ -n "${current_pr}" ]; then
echo "PR already exists: ${current_pr}"
exit
fi
fi
command=(gh pr create
--base "${base_branch}"
--title "${pr_title}"
--body ""
--label dependency_update
)
# Add custom labels to the command.
old_ifs="$IFS"
IFS=","
for label in ${labels}; do
command+=("--label" "${label}")
done
IFS="${old_ifs}"
"${command[@]}"

View File

@@ -1,49 +0,0 @@
---
name: Sync tags with ansible-core releases
"on":
workflow_dispatch:
inputs:
dry-run:
type: boolean
default: false
description: "Select to run the tag script in dry-run mode"
schedule:
- cron: "0 * * * *" # Hourly
jobs:
tag:
runs-on: "ubuntu-latest"
environment: github-bot
permissions:
contents: write
steps:
- name: Generate temp GITHUB_TOKEN
id: create_token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.BOT_APP_ID }}
private-key: ${{ secrets.BOT_APP_KEY }}
- name: Check out us
uses: actions/checkout@v5
with:
path: ansible-documentation
fetch-depth: 0
token: "${{ steps.create_token.outputs.token }}"
- name: Check out core
uses: actions/checkout@v5
with:
repository: ansible/ansible
path: ansible
fetch-depth: 0
- name: Setup nox
uses: wntrblm/nox@2025.05.01
with:
python-versions: "3.12"
- name: Set up git committer
run: |
./hacking/get_bot_user.sh "ansible-documentation-bot" "Ansible Documentation Bot"
working-directory: ansible-documentation
- name: Run tag script
run: nox -s tag -- tag ${{ inputs.dry-run && '--no-push' || '' }}
working-directory: ansible-documentation

View File

@@ -1 +1 @@
devel
stable-2.20

View File

@@ -1,421 +0,0 @@
#!/usr/bin/env python3
# Copyright (C) 2024 Maxwell G <maxwell@gtmx.me>
# SPDX-License-Identifier: GPL-3.0-or-later
# GNU General Public License v3.0+
# (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
Script to handle tagging versions in the ansible-documentation repo in sync
with ansible-core.
"""
from __future__ import annotations
import datetime
from collections.abc import Iterable
from dataclasses import dataclass
from pathlib import Path
from string import Template
from types import SimpleNamespace
from typing import Any, List, NamedTuple, NoReturn, Optional
import click
import git
import git.objects.util
import typer
from packaging.version import Version
MESSAGE = Template(
"""\
${version_str}
This tag contains a snapshot of the ansible-documentation ${branch} branch
at the time of the ansible-core ${version_str} release.
"""
)
# hacking/tagger
HERE = Path(__file__).resolve().parent
ROOT = HERE.parent.parent
DEFAULT_ANSIBLE_CORE_CHECKOUT = ROOT.parent.joinpath("ansible")
DEFAULT_REMOTE = "origin"
DEFAULT_ACTIVE_BRANCHES: tuple[str, ...] = (
"stable-2.16",
"stable-2.17",
"stable-2.18",
"stable-2.19",
)
def get_tags(repo: git.Repo) -> list[str]:
"""
Args:
repo:
A repo object
Returns:
A list of tag names as strings
"""
return [tag.name.removeprefix("refs/tags/") for tag in repo.tags]
def filter_tags(tags: Iterable[str], major_minor: str) -> dict[str, Version]:
"""
Args:
tags:
Iterable of tag names as strings
major_minor:
`{version.major}.{version.minor}` of an ansible-core branch
Returns:
Sorted (newest->oldest) dict of tag names that are part of
`major_minor` mapped to parsed `packaging.version.Version`s
"""
tags = {
tag: Version(stripped)
for tag in tags
if (stripped := tag.lstrip("v")).startswith(major_minor)
}
return dict(sorted(tags.items(), reverse=True, key=lambda x: x[1]))
def get_tag_datetime(tag: git.TagReference) -> datetime.datetime:
"""
Args:
tag:
Lightweight tag reference
Returns:
A `datetime.datetime` of the tagged date or the committed date for a
non-annotated tag
"""
if tag.tag:
return git.objects.util.from_timestamp(
tag.tag.tagged_date, tag.tag.tagger_tz_offset
)
return tag.commit.committed_datetime
def _get_last_commit_before(
commits: Iterable[git.objects.Commit], before: datetime.datetime
) -> git.objects.Commit:
for commit in commits:
if commit.committed_datetime <= before:
return commit
raise ValueError("No commit found!")
def get_last_hash(
docs_repo: git.Repo, core_tag: git.TagReference, branch: str, remote: str
) -> str:
"""
Get the last commit before the datetime of ansible-core's release of TAG.
Args:
docs_repo:
ansible-documentation `git.Repo` object
core_tag:
`git.TagReference` for the corresponding tag in ansible-core
branch:
Branch name in which to search for the properly timed commit
Returns:
Commit hash
Raises:
ValueError:
No commit was found before the datetime of ansible-core's release of TAG
"""
return _get_last_commit_before(
commits=docs_repo.iter_commits(f"{remote}/{branch}", first_parent=True),
before=get_tag_datetime(core_tag),
)
def get_branch(tag_name: str, /) -> str:
"""
Determine a `stable-XX.XX` branch name based on `tag_name`
"""
version = Version(tag_name.lstrip("v"))
major_minor = f"{version.major}.{version.minor}"
return "stable-" + major_minor
def v_prefix_tag(name: str, /) -> str:
"""
Ensure a tag/version has a `v` prefix
"""
return "v" + name.lstrip("v")
# START: typer CLI code
app = typer.Typer()
def fatal(__msg: object, /, *, returncode: int = 1) -> NoReturn:
typer.secho(f"! {__msg}", err=True, fg="red")
raise typer.Exit(returncode)
def msg(__msg: object, not_on_quiet: bool = True, /, **kwargs: Any) -> None:
if not_on_quiet:
try:
quiet = click.get_current_context().ensure_object(Args).quiet
except Exception:
quiet = False
if quiet:
return
kwarg: dict[str, Any] = {"err": True, "fg": "blue"} | kwargs
typer.secho(f"* {__msg}", **kwarg)
@dataclass(kw_only=True)
class Args:
"""
Context for global arguments
"""
docs_repo_path: Path
docs_repo: git.Repo
docs_remote: str
core_repo_path: Path
core_repo: git.Repo
core_remote: str
quiet: bool
def ensure_tag(tag: git.TagReference) -> None:
"""
Ensure a `git.TagReference` actually object
"""
try:
_ = tag.object
except ValueError:
name = tag.name.removeprefix("refs/tags/")
fatal(f"Tag {name} does not exist in core!")
def get_new_tags(args: Args, branch: str) -> dict[str, Version]:
"""
Returns:
Sorted (newest->oldest) dict of new tag names mapped to parsed
`packaging.version.Version`s
"""
core_tags, our_tags = get_tags(args.core_repo), get_tags(args.docs_repo)
core_filtered_tags = filter_tags(core_tags, branch.removeprefix("stable-"))
our_filtered_tags = filter_tags(our_tags, branch.removeprefix("stable-"))
missing_tags: dict[str, Version] = {}
for tag, version in core_filtered_tags.items():
if tag in our_filtered_tags:
break
missing_tags[tag] = version
return missing_tags
class BranchTagRef(NamedTuple):
branch: str
tag: str
ref: str
def branch_tag_ref(
args: Args, branch: str | None, tag: str, ref: str | None
) -> BranchTagRef:
tag = v_prefix_tag(tag)
branch = branch or get_branch(tag)
core_tag = args.core_repo.tag(tag)
ensure_tag(core_tag)
if not ref:
ref = get_last_hash(args.docs_repo, core_tag, branch, args.docs_remote)
return BranchTagRef(branch, tag, ref)
def create_tag(
args: Args, branch: str, tag: str, ref: str, *, push: bool
) -> git.TagReference:
"""
Create and push a tag with the proper message
Args:
args:
CLI context `Args` object
branch:
Branch name
tag:
Tag name
ref:
Reference to tag
"""
message = MESSAGE.substitute(version_str=tag.lstrip("v"), branch=branch)
msg(f"Tagging {ref} as {tag}")
tag_ref = git.TagReference.create(args.docs_repo, tag, ref, message)
if push:
print(f"Pushing {tag} to {args.docs_remote}")
args.docs_repo.remote(args.docs_remote).push(tag)
return tag_ref
PARAMS = SimpleNamespace(
branches=typer.Option(
None,
"-b",
"--branch",
help="Branches in which to search for tags."
" Can be specified multiple times."
f" Defaults to {DEFAULT_ACTIVE_BRANCHES}",
),
branch=typer.Option(
None,
"-b",
"--branch",
help="Branch name. Autodetect based on --tag by deafult.",
),
tag_required=typer.Option(
...,
"-t",
"--tag",
help="Tag name",
),
ref=typer.Option(
...,
"-r",
"--ref",
help="Tag reference",
),
)
@app.callback(help=__doc__)
def callback(
ctx: typer.Context,
docs_repo_path: Path = typer.Option(
ROOT,
"--docs",
help="Path to ansible-documentation checkout",
dir_okay=True,
file_okay=False,
exists=True,
),
core_repo_path: Path = typer.Option(
DEFAULT_ANSIBLE_CORE_CHECKOUT,
"--core",
help="Path to core checkout",
dir_okay=True,
file_okay=False,
exists=True,
),
remote: Optional[str] = typer.Option(
None,
help="Git Remote name for ansible-core and ansible-documentation checkouts."
f" Default: {DEFAULT_REMOTE}",
),
core_remote: Optional[str] = typer.Option(
None, help="Override remote name for core checkout"
),
docs_remote: Optional[str] = typer.Option(
None, help="Override remote name for docs checkout"
),
fetch: bool = typer.Option(True, help="Whether to fetch repos"),
quiet: bool = typer.Option(False, help="Silence logging"),
):
"""
Process global CLI arguments and create a context object to store them
"""
core_remote = core_remote or remote or DEFAULT_REMOTE
docs_remote = docs_remote or remote or DEFAULT_REMOTE
docs_repo = git.Repo(docs_repo_path)
core_repo = git.Repo(core_repo_path)
args = Args(
docs_repo_path=docs_repo_path,
docs_repo=docs_repo,
docs_remote=docs_remote,
core_repo_path=core_repo_path,
core_repo=core_repo,
core_remote=core_remote,
quiet=quiet,
)
ctx.obj = args
if fetch:
fetch_all(args)
def fetch_all(args: Args) -> None:
remotes = {
"docs": (args.docs_repo, args.docs_remote),
"core": (args.core_repo, args.core_remote),
}
for name, (repo, cur_remote) in remotes.items():
msg(f"Fetching {cur_remote} from {name} repo...")
repo.remote(cur_remote).fetch()
@app.command(name="new-tags")
def new_tags_command(
ctx: typer.Context, branches: Optional[List[str]] = PARAMS.branches
) -> None:
"""
List new tags in ansible-core that are not tagged here
"""
args = ctx.ensure_object(Args)
branches = branches or list(DEFAULT_ACTIVE_BRANCHES)
missing_tags = [tag for branch in branches for tag in get_new_tags(args, branch)]
if missing_tags:
print("\n".join(missing_tags))
ctx.exit(0 if missing_tags else 1)
@app.command(name="hash")
def hash_command(
ctx: typer.Context,
tag: str = PARAMS.tag_required,
branch: Optional[str] = PARAMS.branch,
) -> None:
"""
Get the last commit hash before the datetime of ansible-core's release of TAG.
"""
args = ctx.ensure_object(Args)
_, _, ref = branch_tag_ref(args, branch, tag, None)
print(ref)
@app.command(name="mantag")
def mantag_command(
ctx: typer.Context,
tag: str = PARAMS.tag_required,
ref: str = PARAMS.ref,
branch: Optional[str] = PARAMS.branch,
push: bool = True,
) -> None:
"""
Manually tag a release
"""
args = ctx.ensure_object(Args)
triplet = branch_tag_ref(args, branch, tag, ref)
create_tag(args, *triplet, push=push)
@app.command(name="tag")
def tag_command(
ctx: typer.Context,
branches: Optional[List[str]] = PARAMS.branches,
push: bool = True,
):
"""
Determine the missing ansible-core releases from `--branch`, create
corresponding tags for each release in the ansible-documentation repo, and
push them.
"""
args = ctx.ensure_object(Args)
branches = branches or list(DEFAULT_ACTIVE_BRANCHES)
triplets: list[BranchTagRef] = [
branch_tag_ref(args, branch, tag, None)
for branch in branches
for tag in get_new_tags(args, branch)
]
for triplet in triplets:
create_tag(args, *triplet, push=push)
if __name__ == "__main__":
app()

View File

@@ -12,7 +12,6 @@ import nox
LINT_FILES: tuple[str, ...] = (
"hacking/pr_labeler/pr_labeler",
"hacking/tagger/tag.py",
"noxfile.py",
*iglob("docs/bin/*.py"),
*iglob("tests/checkers/rst-yamllint*.py"), # TODO: also lint others

View File

@@ -1,3 +0,0 @@
gitpython
packaging
typer

View File

@@ -1,28 +0,0 @@
# This file was autogenerated by uv via the following command:
# uv pip compile --universal --output-file tests/tag.txt tests/tag.in
click==8.3.0
# via typer
colorama==0.4.6 ; sys_platform == 'win32'
# via click
gitdb==4.0.12
# via gitpython
gitpython==3.1.45
# via -r tests/tag.in
markdown-it-py==4.0.0
# via rich
mdurl==0.1.2
# via markdown-it-py
packaging==25.0
# via -r tests/tag.in
pygments==2.19.2
# via rich
rich==14.1.0
# via typer
shellingham==1.5.4
# via typer
smmap==5.0.2
# via gitdb
typer==0.19.1
# via -r tests/tag.in
typing-extensions==4.15.0
# via typer

View File

@@ -1,5 +1,4 @@
-r ../hacking/pr_labeler/requirements.txt
-r tag.in
mypy
nox
types-docutils

View File

@@ -15,9 +15,7 @@ cffi==2.0.0 ; platform_python_implementation != 'PyPy'
charset-normalizer==3.4.3
# via requests
click==8.3.0
# via
# typer
# typer-slim
# via typer-slim
codeowners==0.8.0
# via -r tests/../hacking/pr_labeler/requirements.txt
colorama==0.4.6 ; sys_platform == 'win32'
@@ -36,20 +34,12 @@ docutils==0.22.2
# via antsibull-docutils
filelock==3.19.1
# via virtualenv
gitdb==4.0.12
# via gitpython
gitpython==3.1.45
# via -r tests/tag.in
idna==3.10
# via requests
jinja2==3.1.6
# via -r tests/../hacking/pr_labeler/requirements.txt
markdown-it-py==4.0.0
# via rich
markupsafe==3.0.2
# via jinja2
mdurl==0.1.2
# via markdown-it-py
mypy==1.18.2
# via -r tests/typing.in
mypy-extensions==1.1.0
@@ -58,7 +48,6 @@ nox==2025.5.1
# via -r tests/typing.in
packaging==25.0
# via
# -r tests/tag.in
# dependency-groups
# nox
pathspec==0.12.1
@@ -69,22 +58,12 @@ pycparser==2.23 ; implementation_name != 'PyPy' and platform_python_implementati
# via cffi
pygithub==2.8.1
# via -r tests/../hacking/pr_labeler/requirements.txt
pygments==2.19.2
# via rich
pyjwt==2.10.1
# via pygithub
pynacl==1.6.0
# via pygithub
requests==2.32.5
# via pygithub
rich==14.1.0
# via typer
shellingham==1.5.4
# via typer
smmap==5.0.2
# via gitdb
typer==0.19.1
# via -r tests/tag.in
typer-slim==0.19.1
# via -r tests/../hacking/pr_labeler/requirements.txt
types-docutils==0.22.0.20250919
@@ -94,7 +73,6 @@ typing-extensions==4.15.0
# codeowners
# mypy
# pygithub
# typer
# typer-slim
urllib3==2.5.0
# via