From 2f2e2de0b7abce88635bd06997bdaa5bff5a1054 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Sun, 25 Oct 2026 15:20:39 -0700 Subject: [PATCH] =?UTF-8?q?=F0=9F=91=B7=20ci(release):=20adopt=20github-wo?= =?UTF-8?q?rkflows=206.0.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the shared release workflows from github-workflows 6.0.1 for news checks, release preparation and the weekly lock refresh. Prepare picks a v-prefixed version from the fragments and runs release-creator contributors to add a New Contributors section from the commit authors and co-authors before the release App pushes the annotated tag. CONTRIBUTING now says credits come from the commit, not from the fragment. Writers are trusted, so the release path no longer re-checks what they did. The check-tagged-source step, the tag format, main ancestry and release-creator tags checks in verify-tag, the re-check that the tag still names the release commit, and the floating-tag job's main ancestry, moved-tag and published-release checks are gone. So are the main-only condition on Prepare release, the redundant pull_request condition on the news job, and test_release_workflow.py with its CI job, which only covered those checks. verify-tag now just resolves the tag to its commit from a shallow checkout, without installing uv or the release tools, and is named for that. The notes job still skips prereleases, and the floating tags still move only when the release is the newest in its series. Nab writes pylock.toml from a [tool.nab] table, with a temporary upload cutoff exception for release-creator 4.1.0. A build group holds Cython and setuptools, since PyYAML has no CPython 3.15 wheel. The release, release-check and release-validate groups are gone. Every workflow, job and step gets an emoji name, including the steps of the action itself, whose two unnamed steps now have names. The required checks become "๐Ÿšฆ Required checks pass" and "๐Ÿ“ News fragment". The hook cooldown check and its scheduled rerun are gone. Dependabot's pre-commit ecosystem and pre-commit.ci's quarterly autoupdate update the hooks, so the release-creator managed hook pins are dropped. setup-uv is pinned to 10.3.2 in CI and in the action. CodeQL moves from default setup to a committed advanced workflow on ubuntu-26.04 with the same languages and query suite. --- .github/dependabot.yaml | 9 + .github/workflows/codeql.yaml | 38 ++ .github/workflows/main.yml | 101 ++-- .github/workflows/news.yaml | 34 ++ .github/workflows/prepare-release.yml | 94 +--- .github/workflows/release.yml | 234 ++++++--- .github/workflows/upgrade-release-tools.yml | 14 + .gitignore | 1 + .pre-commit-config.yaml | 32 +- CHANGELOG.md | 79 ++- CONTRIBUTING.md | 25 + README.md | 12 +- action.yml | 62 ++- pylock.toml | 502 ++++++++++++++++++++ pyproject.toml | 59 +++ 15 files changed, 1050 insertions(+), 246 deletions(-) create mode 100644 .github/workflows/codeql.yaml create mode 100644 .github/workflows/news.yaml create mode 100644 .github/workflows/upgrade-release-tools.yml create mode 100644 .gitignore create mode 100644 CONTRIBUTING.md create mode 100644 pylock.toml create mode 100644 pyproject.toml diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml index baad75f..473789a 100644 --- a/.github/dependabot.yaml +++ b/.github/dependabot.yaml @@ -15,3 +15,12 @@ updates: - "*" cooldown: default-days: 7 + - package-ecosystem: "pre-commit" + directory: "/" + labels: + - dependencies + - skip news + schedule: + interval: "weekly" + cooldown: + default-days: 7 diff --git a/.github/workflows/codeql.yaml b/.github/workflows/codeql.yaml new file mode 100644 index 0000000..f660be9 --- /dev/null +++ b/.github/workflows/codeql.yaml @@ -0,0 +1,38 @@ +name: ๐Ÿ›ก๏ธ CodeQL +on: + push: + branches: [main] + pull_request: + schedule: + - cron: "0 9 * * 2" + workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +permissions: {} +jobs: + analyze: + name: ๐Ÿ›ก๏ธ Analyze ${{ matrix.language }} + runs-on: ubuntu-26.04 + permissions: + contents: read + security-events: write + strategy: + fail-fast: false + matrix: + language: [actions] + steps: + - name: ๐Ÿ“ฅ Check out code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: ๐Ÿ›ก๏ธ Initialize CodeQL + uses: github/codeql-action/init@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4.39.0 + with: + languages: ${{ matrix.language }} + build-mode: none + queries: security-extended + - name: ๐Ÿ›ก๏ธ Analyze + uses: github/codeql-action/analyze@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4.39.0 + with: + category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0b68fd4..6a600e1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,75 +1,66 @@ -name: CI - +name: ๐Ÿงช CI on: pull_request: - types: [opened, synchronize, reopened, labeled, unlabeled] + types: [opened, synchronize, reopened] push: branches: [main, test-me-*] - permissions: contents: read - jobs: self-test-uvx: + name: ๐Ÿงช Self-test with uvx runs-on: ubuntu-26.04 steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - persist-credentials: false - - name: self test action (uvx path) - uses: $/ + - name: ๐Ÿ“ฅ Check out code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: ๐Ÿงช Self test action (uvx path) + uses: $/ self-test-uv-run: + name: ๐Ÿงช Self-test with uv run runs-on: ubuntu-26.04 steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - persist-credentials: false - - run: printf '[project]\nname = "test"\nversion = "0.0.0"\nrequires-python = ">=3.13"\n' > pyproject.toml - shell: bash - - name: self test action (uv run path) - uses: $/ + - name: ๐Ÿ“ฅ Check out code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: ๐Ÿ Install uv + uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 + with: + version: latest-known + python-version: "3.13" + enable-cache: false + - name: โš™๏ธ Write a test pyproject.toml + run: printf '[project]\nname = "test"\nversion = "0.0.0"\nrequires-python = ">=3.13,<3.14"\n' >pyproject.toml + shell: bash + - name: ๐Ÿงช Self test action (uv run path) + uses: $/ self-test-external-uv: + name: ๐Ÿงช Self-test with external uv runs-on: ubuntu-26.04 steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - persist-credentials: false - - uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0 - with: - python-version: "3.15" - enable-cache: false - - name: self test action (external uv) - uses: $/ - with: - uv-install: 'false' - news: - name: News fragment - if: github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'skip news') - runs-on: ubuntu-26.04 - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - fetch-depth: 0 - persist-credentials: false - - name: Require a user-facing change - run: | - found=0 - while IFS= read -r path; do - if [[ "$path" =~ ^changelog\.d/[0-9]+\.(feature|bugfix|doc)\.md$ && -s "$path" ]]; then - found=1 - fi - done < <(git diff --name-only --diff-filter=AM "origin/$GITHUB_BASE_REF"...HEAD) - if (( found == 0 )); then - echo "::error::add a nonempty changelog.d/..md fragment or apply skip news" - exit 1 - fi + - name: ๐Ÿ“ฅ Check out code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: ๐Ÿ Install uv + uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 + with: + version: latest-known + python-version: "3.15" + enable-cache: false + - name: ๐Ÿงช Self test action (external uv) + uses: $/ + with: + uv-install: 'false' gate: - name: Required checks pass + name: ๐Ÿšฆ ${{ github.event_name == 'pull_request' && 'Required checks pass' || 'Non-PR checks pass' }} if: always() - needs: [self-test-uvx, self-test-uv-run, self-test-external-uv, news] + needs: [self-test-uvx, self-test-uv-run, self-test-external-uv] runs-on: ubuntu-26.04 steps: - - env: - NEEDS_JSON: ${{ toJSON(needs) }} - run: | - jq -e 'all(to_entries[]; .value.result == "success" or (.key == "news" and .value.result == "skipped"))' <<< "$NEEDS_JSON" + - name: ๐Ÿšฆ Require all needed jobs to pass + env: + NEEDS_JSON: ${{ toJSON(needs) }} + run: jq -e 'all(to_entries[]; .value.result == "success")' <<<"$NEEDS_JSON" diff --git a/.github/workflows/news.yaml b/.github/workflows/news.yaml new file mode 100644 index 0000000..7672ff6 --- /dev/null +++ b/.github/workflows/news.yaml @@ -0,0 +1,34 @@ +name: ๐Ÿ“ Changelog +on: + pull_request: + types: [opened, reopened, synchronize, labeled, unlabeled] +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true +permissions: + contents: read +jobs: + news: + name: ๐Ÿ“ News fragment + runs-on: ubuntu-26.04 + permissions: + contents: read + steps: + - name: ๐Ÿ“ฅ Check out code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + persist-credentials: false + - name: ๐Ÿ Install uv + uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 + with: + version: latest-known + python-version: "3.15" + enable-cache: false + - name: ๐Ÿ“ฆ Install locked release tools + uses: tox-dev/github-workflows/install-locked-tools@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1 + with: + groups: release-news + venv: ${{ runner.temp }}/release-tools + - name: ๐Ÿ” Validate news fragments + uses: tox-dev/github-workflows/validate-news@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1 diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index 7cfa45a..3dad660 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -1,83 +1,29 @@ -name: Prepare release - +name: ๐Ÿท๏ธ Prepare release on: workflow_dispatch: inputs: - version: - description: Version to release, without a v prefix + bump: + description: Version bump type required: true - + type: choice + options: + - auto + - major + - minor + - patch + default: auto permissions: {} - -concurrency: - group: prepare-release - cancel-in-progress: false - jobs: prepare: - if: github.ref == 'refs/heads/main' - runs-on: ubuntu-26.04 - environment: release-auth + name: ๐Ÿท๏ธ Prepare Towncrier release + uses: tox-dev/github-workflows/.github/workflows/prepare-towncrier-release.yaml@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1 permissions: contents: read - steps: - - id: token - uses: actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510 # v3.3.0 - with: - client-id: ${{ vars.RELEASE_APP_CLIENT_ID }} - private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} - owner: ${{ github.repository_owner }} - repositories: ${{ github.event.repository.name }} - permission-contents: write - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - fetch-depth: 0 - token: ${{ steps.token.outputs.token }} - persist-credentials: true # zizmor: ignore[artipacked] the release job pushes main and its tag - - name: Build changelog and push release - env: - VERSION: ${{ inputs.version }} - GH_TOKEN: ${{ steps.token.outputs.token }} - APP_SLUG: ${{ steps.token.outputs.app-slug }} - run: | - set -euo pipefail - git fetch origin main - git reset --hard origin/main - if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - echo "::error::expected a major.minor.patch version" - exit 1 - fi - tag="v$VERSION" - latest=$(git tag --list 'v*' | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -n 1) - if [[ "$latest" == "$tag" || "$(printf '%s\n' "$latest" "$tag" | sort -V | tail -n 1)" != "$tag" ]]; then - echo "::error::$tag must be newer than $latest" - exit 1 - fi - mapfile -d '' fragments < <(find changelog.d -maxdepth 1 -type f -name '*.md' -print0 | sort -z) - if (( ${#fragments[@]} == 0 )); then - echo "::error::no news fragments to release" - exit 1 - fi - for fragment in "${fragments[@]}"; do - if [[ ! "$fragment" =~ ^changelog\.d/[0-9]+\.(feature|bugfix|doc)\.md$ || ! -s "$fragment" ]]; then - echo "::error::invalid or empty news fragment: $fragment" - exit 1 - fi - done - { - printf '# Changelog\n\n## %s (%s)\n\n' "$tag" "$(date -u +%F)" - for fragment in "${fragments[@]}"; do - cat "$fragment" - printf '\n\n' - done - tail -n +3 CHANGELOG.md - } > "$RUNNER_TEMP/changelog.md" - mv "$RUNNER_TEMP/changelog.md" CHANGELOG.md - git rm -- "${fragments[@]}" - app_user_id=$(gh api "/users/${APP_SLUG}[bot]" --jq .id) - git config user.name "${APP_SLUG}[bot]" - git config user.email "${app_user_id}+${APP_SLUG}[bot]@users.noreply.github.com" - git add CHANGELOG.md changelog.d - git commit -m "Prepare $tag" - git tag -a "$tag" -m "Release $tag" - git push --atomic origin HEAD:main "refs/tags/$tag" + pull-requests: read + with: + bump: ${{ inputs.bump }} + tag-prefix: v + changelog-prefix: v + annotated: true + secrets: + RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b1dea43..fc371f3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,5 +1,4 @@ -name: Update floating tags - +name: ๐Ÿš€ Update floating tags on: push: tags: ["v*.*.*"] @@ -10,85 +9,168 @@ on: tag: description: Full version tag to point the floating tags at (e.g. v1.0.4) required: true - permissions: contents: read - +concurrency: + group: release-${{ github.ref }} + cancel-in-progress: false jobs: - update-floating-tags: + verify-tag: + name: ๐Ÿท๏ธ Resolve release tag + runs-on: ubuntu-26.04 + permissions: + contents: read + outputs: + tag: ${{ steps.verify.outputs.tag }} + commit: ${{ steps.verify.outputs.commit }} + steps: + - name: ๐Ÿ“ฅ Check out code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: refs/tags/${{ github.event.release.tag_name || inputs.tag || github.ref_name }} + persist-credentials: false + - name: ๐Ÿท๏ธ Resolve tag to its commit + id: verify + env: + TAG: ${{ github.event.release.tag_name || inputs.tag || github.ref_name }} + run: | + set -euo pipefail + commit=$(git rev-parse --verify "refs/tags/$TAG^{commit}") + printf 'tag=%s\ncommit=%s\n' "$TAG" "$commit" >>"$GITHUB_OUTPUT" + notes: + name: ๐Ÿ“ Render GitHub Release notes + needs: verify-tag runs-on: ubuntu-26.04 if: github.event_name != 'release' || !github.event.release.prerelease - environment: release-auth + permissions: + contents: read + outputs: + artifact-id: ${{ steps.upload.outputs.artifact-id }} + steps: + - name: ๐Ÿ“ฅ Check out code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ needs.verify-tag.outputs.commit }} + fetch-depth: 0 + persist-credentials: false + - name: ๐Ÿ Install uv + uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 + with: + version: latest-known + python-version: "3.15" + enable-cache: false + - name: ๐Ÿ“ฆ Install locked release tools + uses: tox-dev/github-workflows/install-locked-tools@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1 + with: + groups: release-notes + venv: ${{ runner.temp }}/release-tools + - name: ๐Ÿ“ Render release notes + uses: tox-dev/github-workflows/render-release-notes@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1 + with: + tag: ${{ needs.verify-tag.outputs.tag }} + changelog: CHANGELOG.md + - name: ๐Ÿ“ค Upload release notes + id: upload + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: release-notes + path: ${{ runner.temp }}/release-notes.md + if-no-files-found: error + github-release: + name: ๐Ÿš€ Publish GitHub Release + needs: [verify-tag, notes] + if: github.event_name == 'push' + runs-on: ubuntu-26.04 + environment: release permissions: contents: write steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.event.release.tag_name || inputs.tag || github.ref_name }} - fetch-depth: 0 - persist-credentials: false - - name: Require release notes in the changelog - env: - TAG: ${{ github.event.release.tag_name || inputs.tag || github.ref_name }} - run: | - if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - echo "::error::unexpected release tag $TAG" - exit 1 - fi - awk -v heading="## $TAG " ' - /^## / { if (found) exit; found = index($0, heading) == 1; next } - found { print } - ' CHANGELOG.md > "$RUNNER_TEMP/release-notes.md" - if [[ ! -s "$RUNNER_TEMP/release-notes.md" ]]; then - echo "::error::CHANGELOG.md has no section for $TAG" - exit 1 - fi - - name: Publish GitHub release - if: github.event_name == 'push' - env: - GH_TOKEN: ${{ github.token }} - TAG: ${{ github.ref_name }} - run: | - set -euo pipefail - previous=$(git tag --list | grep -E '^v?[0-9]+\.[0-9]+\.[0-9]+$' | awk '{ version = $0; sub(/^v/, "", version); print version, $0 }' | sort -V -k1,1 | awk -v tag="$TAG" '$2 == tag { print previous; exit } { previous = $2 }') - if [[ -n "$previous" ]]; then - printf '\n**Full Changelog**: https://github.com/%s/compare/%s...%s\n' "$GITHUB_REPOSITORY" "$previous" "$TAG" >> "$RUNNER_TEMP/release-notes.md" - else - printf '\n**Full Changelog**: https://github.com/%s/commits/%s\n' "$GITHUB_REPOSITORY" "$TAG" >> "$RUNNER_TEMP/release-notes.md" - fi - gh release create "$TAG" --verify-tag --title "$TAG" --notes-file "$RUNNER_TEMP/release-notes.md" - - id: token - uses: actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510 # v3.3.0 - with: - client-id: ${{ vars.RELEASE_APP_CLIENT_ID }} - private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} - owner: ${{ github.repository_owner }} - repositories: ${{ github.event.repository.name }} - permission-contents: write - - name: Move major and minor tags to the released version - env: - GH_TOKEN: ${{ steps.token.outputs.token }} - REPO: ${{ github.repository }} - TAG: ${{ github.event.release.tag_name || inputs.tag || github.ref_name }} - run: | - set -euo pipefail - if [[ ! "${TAG}" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then - echo "::error::Unexpected tag format: ${TAG} (expected vMAJOR.MINOR.PATCH)" >&2 - exit 1 - fi - major="v${BASH_REMATCH[1]}" - minor="v${BASH_REMATCH[1]}.${BASH_REMATCH[2]}" - sha="$(gh api "repos/${REPO}/commits/${TAG}" --jq '.sha')" - for ref in "${major}" "${minor}"; do - latest=$(git tag --list "${ref}.*" | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -n 1) - if [[ "$TAG" != "$latest" ]]; then - echo "Keeping ${ref} at its newer release ${latest}" - continue - fi - if gh api "repos/${REPO}/git/ref/tags/${ref}" >/dev/null 2>&1; then - gh api -X PATCH "repos/${REPO}/git/refs/tags/${ref}" -f "sha=${sha}" -F force=true >/dev/null - else - gh api -X POST "repos/${REPO}/git/refs" -f "ref=refs/tags/${ref}" -f "sha=${sha}" >/dev/null - fi - echo "Pointed ${ref} -> ${TAG} (${sha})" - done + - name: ๐Ÿ“ฉ Download release notes + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + with: + artifact-ids: ${{ needs.notes.outputs.artifact-id }} + path: ${{ runner.temp }} + - name: ๐Ÿš€ Publish GitHub release + uses: tox-dev/github-workflows/publish-github-release@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1 + env: + GH_TOKEN: ${{ github.token }} + with: + tag: ${{ needs.verify-tag.outputs.tag }} + commit: ${{ needs.verify-tag.outputs.commit }} + title: ${{ needs.verify-tag.outputs.tag }} + notes-file: ${{ runner.temp }}/release-notes.md + update-floating-tags: + name: ๐Ÿท๏ธ Move floating major and minor tags + needs: [verify-tag, notes, github-release] + runs-on: ubuntu-26.04 + if: |- + always() && needs.verify-tag.result == 'success' && + needs.notes.result == 'success' && + (needs.github-release.result == 'success' || needs.github-release.result == 'skipped') + environment: release-auth + permissions: + contents: read + steps: + - name: ๐Ÿ“ฅ Check out code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ needs.verify-tag.outputs.commit }} + fetch-depth: 0 + persist-credentials: false + - name: ๐Ÿ”‘ Create release App token + id: token + uses: actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510 # v3.3.0 + with: + client-id: ${{ vars.RELEASE_APP_CLIENT_ID }} + private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} + owner: ${{ github.repository_owner }} + repositories: ${{ github.event.repository.name }} + permission-contents: write + - name: ๐Ÿท๏ธ Move major and minor tags to the released version + env: + GH_TOKEN: ${{ steps.token.outputs.token }} + REPO: ${{ github.repository }} + TAG: ${{ needs.verify-tag.outputs.tag }} + COMMIT: ${{ needs.verify-tag.outputs.commit }} + run: | + set -euo pipefail + is_versioned_tag() { + case "$1" in + v*.*.*) ;; + *) return 1 ;; + esac + case "$1" in + *.) return 1 ;; + esac + local -a components + IFS=. read -r -a components <<<"${1#v}" + [[ ${#components[@]} -eq 3 ]] || return 1 + local component + for component in "${components[@]}"; do + case "$component" in + '' | *[!0-9]*) return 1 ;; + esac + done + } + IFS=. read -r -a components <<<"${TAG#v}" + major="v${components[0]}" + minor="${major}.${components[1]}" + for ref in "${major}" "${minor}"; do + versions=() + while IFS= read -r candidate; do + if is_versioned_tag "$candidate"; then + versions+=("$candidate") + fi + done < <(git tag --list "${ref}.*") + latest=$(printf '%s\n' "${versions[@]}" | sort -V | tail -n 1) + if [[ "$TAG" != "$latest" ]]; then + echo "Keeping ${ref} at its newer release ${latest}" + continue + fi + if gh api "repos/${REPO}/git/ref/tags/${ref}" >/dev/null 2>&1; then + gh api -X PATCH "repos/${REPO}/git/refs/tags/${ref}" -f "sha=${COMMIT}" -F force=true >/dev/null + else + gh api -X POST "repos/${REPO}/git/refs" -f "ref=refs/tags/${ref}" -f "sha=${COMMIT}" >/dev/null + fi + echo "Pointed ${ref} -> ${TAG} (${COMMIT})" + done diff --git a/.github/workflows/upgrade-release-tools.yml b/.github/workflows/upgrade-release-tools.yml new file mode 100644 index 0000000..e27f172 --- /dev/null +++ b/.github/workflows/upgrade-release-tools.yml @@ -0,0 +1,14 @@ +name: ๐Ÿ”’ Upgrade release tools +on: + workflow_dispatch: + schedule: + - cron: 0 8 * * 2 +permissions: {} +jobs: + upgrade: + name: ๐Ÿ”€ Upgrade release tools + uses: tox-dev/github-workflows/.github/workflows/upgrade-release-tools.yaml@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1 + permissions: + contents: read + secrets: + RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..65c9c56 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/uv.lock diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4cc50cd..89bb1dc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,14 +2,42 @@ default_language_version: python: python3.15 repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v6.0.0 + rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # frozen: v6.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: check-yaml - repo: https://github.com/zizmorcore/zizmor-pre-commit - rev: v1.30.1 + rev: c92afdf2c6ca336aaa8f39e2bd8d48f62dbd8e1f # frozen: v1.31.1 hooks: - id: zizmor + - repo: https://github.com/hukkin/mdformat + rev: "82912cdaea4fb830f751504486a7879c70526547" # frozen: 1.0.0 + hooks: + - id: mdformat + args: ["--wrap", "120"] + files: |- + (?x) + ^(?P + CHANGELOG[.]md # Published history + | README[.]md # Project guide + | CONTRIBUTING[.]md # Contribution guide + | changelog[.]d/.*[.]md # Unreleased fragments + )$ + additional_dependencies: + - "mdformat-gfm==1.0.0" + - repo: https://github.com/scop/pre-commit-shfmt + rev: 479be5958357ba5ab65ce47172117348516860e9 # frozen: v3.14.1-1 + hooks: + - id: shfmt + args: ["-i", "2"] + - repo: https://github.com/shellcheck-py/shellcheck-py + rev: a6564f5d57444e123433a5c9af733e3975c77229 # frozen: v0.11.0.1-1 + hooks: + - id: shellcheck + - repo: https://github.com/google/yamlfmt + rev: 21ca5323a9c87ee37a434e0ca908efc0a89daa07 # frozen: v0.21.0 + hooks: + - id: yamlfmt ci: autoupdate_schedule: quarterly diff --git a/CHANGELOG.md b/CHANGELOG.md index 332b39a..8eb03f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,31 +1,94 @@ # Changelog + + + + ## v1.1.0 (2026-10-10) -- Run pre-commit with Python 3.15 in project and isolated tool environments. -- Update the pinned uv and cache actions. + + +### Added + +- Run pre-commit with Python 3.15 in project and isolated tool environments + ([#38](https://github.com/tox-dev/action-pre-commit-uv/pull/38)) by [@gaborbernat](https://github.com/gaborbernat). + + ## v1.0.5 (2026-07-21) -- Update the pinned uv and cache actions. + + +### Added + +- Keep the `v1` and `v1.0` tags pointed at the latest stable release + ([#29](https://github.com/tox-dev/action-pre-commit-uv/pull/29), + [#30](https://github.com/tox-dev/action-pre-commit-uv/pull/30)) by [@gaborbernat](https://github.com/gaborbernat). + + ## v1.0.4 (2026-05-27) -- Use action dependencies compatible with Node 24. + + +### Added + +- Add the `uv-install` input and select `uvx` when the checkout has no project + ([#24](https://github.com/tox-dev/action-pre-commit-uv/pull/24)) by [@gaborbernat](https://github.com/gaborbernat). + + + +### Fixed + +- Skip installing uv when it is already available ([#23](https://github.com/tox-dev/action-pre-commit-uv/pull/23)) by + [@gaborbernat](https://github.com/gaborbernat). + + ## 1.0.3 (2025-08-25) -- Publish the action under a unique GitHub Marketplace name. -- Enable Dependabot for Actions and quarterly pre-commit updates. + + +### Changes + +- Publish the action under a unique GitHub Marketplace name + ([#8](https://github.com/tox-dev/action-pre-commit-uv/pull/8)) by [@hugovk](https://github.com/hugovk). + + ## v1.0.2 (2025-01-26) -- Pass `--no-sync` to `uv run`. + + +### Changes + +- Pass `--no-sync` to `uv run` ([#4](https://github.com/tox-dev/action-pre-commit-uv/pull/4)) by + [@zeevro](https://github.com/zeevro). + + ## v1.0.1 (2024-10-23) -- Replace `hynek/setup-cached-uv` with `astral-sh/setup-uv` and cache pre-commit environments. + + +### Changes + +- Set up uv with `astral-sh/setup-uv` ([#2](https://github.com/tox-dev/action-pre-commit-uv/pull/2)) by + [@hugovk](https://github.com/hugovk). + + + +### Added + +- Cache pre-commit environments ([#3](https://github.com/tox-dev/action-pre-commit-uv/pull/3)) by + [@gaborbernat](https://github.com/gaborbernat). + + ## v1.0.0 (2024-10-23) + + +### Added + - Run pre-commit through pre-commit-uv. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..02670b3 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,25 @@ +# Contributing + +Open a pull request for changes to the Action. The CI workflow runs the Action in a checkout with a Python project, a +checkout without one, and a checkout where uv is already installed. + +## Release notes + +Add a Markdown file under `changelog.d` for a change Action users should know about. Name it `+topic.feature.md`, +`+topic.change.md`, `+topic.bugfix.md`, or `+topic.doc.md`. Other supported categories are `breaking`, `security`, +`performance`, `deprecation`, `removal`, and `packaging`. One pull request can have several fragments. Describe the +change from the user's point of view; do not add a fragment for CI or dependency maintenance alone. + +Do not write credits into a fragment. The release tooling links a named fragment to its squash-merged pull request and +credits the authors and `Co-authored-by` co-authors of that commit. You do not need a pull request number when creating +the file. If the pull request has no user-facing change, apply the `skip news` label; the required news check reruns +when the label changes. Automation pull requests without a fragment get that label automatically. A bot pull request +that supplies a fragment still has it validated. + +## Releases + +Maintainers dispatch **Prepare release** on `main` and choose `auto`, `major`, `minor`, or `patch`. `auto` uses the +pending fragment categories. The workflow calculates a `v`-prefixed tag, builds the changelog, runs +`release-creator contributors` to list first-time contributors from the commit authors and co-authors, runs `prek`, and +validates the patch before a repository-scoped GitHub App pushes the release commit and tag. The tag workflow creates a +GitHub Release from the tagged changelog and advances the floating `v1` and `v1.0` tags when appropriate. diff --git a/README.md b/README.md index 21b6751..5511e7c 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,8 @@ A GitHub action to run [pre-commit](https://pre-commit.com) using [pre-commit-uv](https://github.com/tox-dev/pre-commit-uv). -See the [changelog](CHANGELOG.md) for released changes. +See the [changelog](CHANGELOG.md) for released changes. See [Contributing](CONTRIBUTING.md) for release-note and +pull-request rules. ### using this action @@ -22,9 +23,9 @@ on: jobs: pre-commit: - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - uses: tox-dev/action-pre-commit-uv@v1 ``` @@ -43,9 +44,10 @@ By default (`uv-install: 'auto'`), the action detects whether uv is already avai You can override this with `'true'` (always install) or `'false'` (never install): ```yaml - - uses: astral-sh/setup-uv@v7 + - uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 with: - version: 0.6.0 + version: latest-known + python-version: '3.15' - uses: tox-dev/action-pre-commit-uv@v1 with: uv-install: 'false' diff --git a/action.yml b/action.yml index 160ec54..15a935f 100644 --- a/action.yml +++ b/action.yml @@ -12,29 +12,39 @@ inputs: runs: using: composite steps: - - name: Check if uv is already installed - if: inputs.uv-install == 'auto' - id: check-uv - run: command -v uv && echo "installed=true" >> "$GITHUB_OUTPUT" || echo "installed=false" >> "$GITHUB_OUTPUT" - shell: bash - - name: Install the latest version of uv - if: inputs.uv-install == 'true' || (inputs.uv-install == 'auto' && steps.check-uv.outputs.installed != 'true') - uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0 - with: - enable-cache: true - cache-dependency-glob: '.pre-commit-config.yaml' - - run: uv run --python 3.15 --isolated --no-sync true && echo "pythonLocation=$(uv python find 3.15)" >>$GITHUB_ENV - shell: bash - - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - with: - path: ~/.cache/pre-commit - key: pre-commit-3|${{ env.pythonLocation }}|${{ hashFiles('.pre-commit-config.yaml') }} - - run: | - if [ -f pyproject.toml ]; then - uv run --python 3.15 --no-sync --with pre-commit-uv pre-commit run --show-diff-on-failure --color=always ${INPUTS_EXTRA_ARGS} - else - uvx --python 3.15 --with pre-commit-uv pre-commit run --show-diff-on-failure --color=always ${INPUTS_EXTRA_ARGS} - fi - shell: bash - env: - INPUTS_EXTRA_ARGS: ${{ inputs.extra_args }} + - name: ๐Ÿ” Check if uv is already installed + if: inputs.uv-install == 'auto' + id: check-uv + run: command -v uv && echo "installed=true" >> "$GITHUB_OUTPUT" || echo "installed=false" >> "$GITHUB_OUTPUT" + shell: bash + - name: ๐Ÿ Install the latest version of uv + if: inputs.uv-install == 'true' || (inputs.uv-install == 'auto' && steps.check-uv.outputs.installed != 'true') + uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 + with: + version: latest-known + enable-cache: true + cache-dependency-glob: '.pre-commit-config.yaml' + - name: โš™๏ธ Record the Python location + run: uv run --isolated --no-sync true && echo "pythonLocation=$(uv python find)" >>$GITHUB_ENV + shell: bash + - name: ๐Ÿ’พ Cache pre-commit environments + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ~/.cache/pre-commit + key: pre-commit-3|${{ env.pythonLocation }}|${{ hashFiles('.pre-commit-config.yaml') }} + - name: ๐Ÿงน Run hooks with project dependencies + if: hashFiles('pyproject.toml') != '' + run: | + uv run --no-sync --with pre-commit-uv env -u UV_PYTHON pre-commit run \ + --show-diff-on-failure --color=always ${INPUTS_EXTRA_ARGS} + shell: bash + env: + INPUTS_EXTRA_ARGS: ${{ inputs.extra_args }} + - name: ๐Ÿงน Run hooks without a project + if: hashFiles('pyproject.toml') == '' + run: | + uvx --from pre-commit --with pre-commit-uv env -u UV_PYTHON pre-commit run \ + --show-diff-on-failure --color=always ${INPUTS_EXTRA_ARGS} + shell: bash + env: + INPUTS_EXTRA_ARGS: ${{ inputs.extra_args }} diff --git a/pylock.toml b/pylock.toml new file mode 100644 index 0000000..f45dc29 --- /dev/null +++ b/pylock.toml @@ -0,0 +1,502 @@ +lock-version = "1.0" +environments = [ + "python_version == \"3.15\" and sys_platform == \"linux\" and platform_machine == \"x86_64\" and platform_python_implementation == \"CPython\"", +] +requires-python = ">=3.15" +dependency-groups = [ + "build", + "project-runtime", + "release-news", + "release-notes", + "release-prepare", +] +default-groups = [ + "project-runtime", +] +created-by = "nab" + +[[packages]] +name = "click" +version = "8.5.0" +marker = "\"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups" +requires-python = ">=3.10" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "click-8.5.0.tar.gz" +upload-time = 2026-08-26 13:33:14.560531+00:00 +url = "https://files.pythonhosted.org/packages/c7/0e/7fa0ef50764b67090eca4114772a2abf8b6148198475e54c660b97caeee6/click-8.5.0.tar.gz" +size = 382235 + +[packages.sdist.hashes] +sha256 = "ba0d2089de75ea0310e2dde03160e6ca10009947fb95a182f9b54021bb272e34" + +[[packages.wheels]] +name = "click-8.5.0-py3-none-any.whl" +upload-time = 2026-08-26 13:33:12.928043+00:00 +url = "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl" +size = 125251 + +[packages.wheels.hashes] +sha256 = "255bc9599cf7748b4b1a446ccc735421bd08a2ae529a8b88597d3de5664ee360" + +[[packages]] +name = "cython" +version = "3.3.0" +marker = "\"build\" in dependency_groups" +requires-python = ">=3.9" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "cython-3.3.0.tar.gz" +upload-time = 2026-08-22 05:16:39.493040+00:00 +url = "https://files.pythonhosted.org/packages/a9/d8/4981ef716ad0e3ff0d3ef383aefc6b03c4a88dee33b272bf8e0d833001ca/cython-3.3.0.tar.gz" +size = 3727515 + +[packages.sdist.hashes] +sha256 = "eed0d93fbca7087f143b42c34b05a825849bdf17f101572c2105acfa49aa88b8" + +[[packages.wheels]] +name = "cython-3.3.0-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" +upload-time = 2026-08-22 05:17:36.538454+00:00 +url = "https://files.pythonhosted.org/packages/c9/aa/4c0b6773ecf6bc1ec6cda7db8312a566611b330fb6dae87d740e44a47822/cython-3.3.0-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" +size = 3454285 + +[packages.wheels.hashes] +sha256 = "b447f6906e0555f05dc4742ef1f99091b1e5d9aa9f16616e772fbf9ff6271616" + +[[packages.wheels]] +name = "cython-3.3.0-py3-none-any.whl" +upload-time = 2026-08-22 05:16:36.741632+00:00 +url = "https://files.pythonhosted.org/packages/bf/77/67b0b24e45073a699610e50f00c18474ff9b09ea29ecc95083bdf5e60acd/cython-3.3.0-py3-none-any.whl" +size = 1349151 + +[packages.wheels.hashes] +sha256 = "9b24b5c8cd536946b62086fcafee6d5509d3f549f72d553d2336af87ffbe0da1" + +[[packages]] +name = "docutils" +version = "0.23" +marker = "\"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups" +requires-python = ">=3.9" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "docutils-0.23.tar.gz" +upload-time = 2026-05-27 17:41:06.934109+00:00 +url = "https://files.pythonhosted.org/packages/39/a4/5180d9afc57e8fca05601dd652bdff19604c218814037fe90ffc7625a50a/docutils-0.23.tar.gz" +size = 2303823 + +[packages.sdist.hashes] +sha256 = "746f5060322511280a1e50eb76846ed6bf2342984b2ac04dc42caa1a8d78799e" + +[[packages.wheels]] +name = "docutils-0.23-py3-none-any.whl" +upload-time = 2026-05-27 17:40:58.442528+00:00 +url = "https://files.pythonhosted.org/packages/32/91/30151a39f7570f448ed84529390628a651d7f27c87d73c9b887f8189695e/docutils-0.23-py3-none-any.whl" +size = 634701 + +[packages.wheels.hashes] +sha256 = "25d013af9bf23bc1c7b2b093dff4208166c53a94786c9e447808335ef1185fea" + +[[packages]] +name = "jinja2" +version = "3.1.6" +marker = "\"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups" +requires-python = ">=3.7" +dependencies = [ + { name = "markupsafe" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "jinja2-3.1.6.tar.gz" +upload-time = 2025-03-05 20:05:02.478302+00:00 +url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz" +size = 245115 + +[packages.sdist.hashes] +sha256 = "0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d" + +[[packages.wheels]] +name = "jinja2-3.1.6-py3-none-any.whl" +upload-time = 2025-03-05 20:05:00.369721+00:00 +url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl" +size = 134899 + +[packages.wheels.hashes] +sha256 = "85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67" + +[[packages]] +name = "markdown-it-py" +version = "4.2.0" +marker = "\"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups" +requires-python = ">=3.10" +dependencies = [ + { name = "mdurl" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "markdown_it_py-4.2.0.tar.gz" +upload-time = 2026-05-07 12:08:28.360612+00:00 +url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz" +size = 82454 + +[packages.sdist.hashes] +sha256 = "04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49" + +[[packages.wheels]] +name = "markdown_it_py-4.2.0-py3-none-any.whl" +upload-time = 2026-05-07 12:08:27.182789+00:00 +url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl" +size = 91687 + +[packages.wheels.hashes] +sha256 = "9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a" + +[[packages]] +name = "markupsafe" +version = "3.0.4" +marker = "\"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups" +requires-python = ">=3.9" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "markupsafe-3.0.4.tar.gz" +upload-time = 2026-10-02 23:07:22.290270+00:00 +url = "https://files.pythonhosted.org/packages/38/9b/e422a865e1d5d57d0e509b4e0bf1c1a70a7f6382c29a5aa428df994c8bc8/markupsafe-3.0.4.tar.gz" +size = 153777 + +[packages.sdist.hashes] +sha256 = "2e9ad7dd851bf45fab9f75cbff4cb493fee9979e8d8c7c9c3ee119022518edd6" + +[[packages.wheels]] +name = "markupsafe-3.0.4-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" +upload-time = 2026-10-02 23:06:22.524416+00:00 +url = "https://files.pythonhosted.org/packages/82/96/ef49135ce260db4ca4a12b119ed468449cd248db6b1468e2112b546d7a2e/markupsafe-3.0.4-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" +size = 23111 + +[packages.wheels.hashes] +sha256 = "925f929d6b59a8b3f8b8c6ac363cd0af7eecc81efb3071770b3c6717c450a369" + +[[packages]] +name = "mdformat" +version = "1.0.0" +marker = "\"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups" +requires-python = ">=3.10" +dependencies = [ + { name = "markdown-it-py" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "mdformat-1.0.0.tar.gz" +upload-time = 2025-10-16 12:05:03.695033+00:00 +url = "https://files.pythonhosted.org/packages/3f/05/32b5e14b192b0a8a309f32232c580aefedd9d06017cb8fe8fce34bec654c/mdformat-1.0.0.tar.gz" +size = 56953 + +[packages.sdist.hashes] +sha256 = "4954045fcae797c29f86d4ad879e43bb151fa55dbaf74ac6eaeacf1d45bb3928" + +[[packages.wheels]] +name = "mdformat-1.0.0-py3-none-any.whl" +upload-time = 2025-10-16 12:05:02.607432+00:00 +url = "https://files.pythonhosted.org/packages/54/9a/8fe71b95985ca7a4001effbcc58e5a07a1f2a2884203f74dcf48a3b08315/mdformat-1.0.0-py3-none-any.whl" +size = 53288 + +[packages.wheels.hashes] +sha256 = "bca015d65a1d063a02e885a91daee303057bc7829c2cd37b2075a50dbb65944b" + +[[packages]] +name = "mdformat-gfm" +version = "1.0.0" +marker = "\"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups" +requires-python = ">=3.10" +dependencies = [ + { name = "markdown-it-py" }, + { name = "mdformat" }, + { name = "mdit-py-plugins" }, + { name = "wcwidth" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "mdformat_gfm-1.0.0.tar.gz" +upload-time = 2025-10-16 09:12:22.402429+00:00 +url = "https://files.pythonhosted.org/packages/56/6f/a626ebb142a290474401b67e2d61e73ce096bf7798ee22dfe6270f924b3f/mdformat_gfm-1.0.0.tar.gz" +size = 10112 + +[packages.sdist.hashes] +sha256 = "d1d49a409a6acb774ce7635c72d69178df7dce1dc8cdd10e19f78e8e57b72623" + +[[packages.wheels]] +name = "mdformat_gfm-1.0.0-py3-none-any.whl" +upload-time = 2025-10-16 09:12:21.276157+00:00 +url = "https://files.pythonhosted.org/packages/e6/18/6bc2189b744dd383cad03764f41f30352b1278d2205096f77a29c0b327ad/mdformat_gfm-1.0.0-py3-none-any.whl" +size = 10970 + +[packages.wheels.hashes] +sha256 = "7305a50efd2a140d7c83505b58e3ac5df2b09e293f9bbe72f6c7bee8c678b005" + +[[packages]] +name = "mdit-py-plugins" +version = "0.6.1" +marker = "\"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups" +requires-python = ">=3.10" +dependencies = [ + { name = "markdown-it-py" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "mdit_py_plugins-0.6.1.tar.gz" +upload-time = 2026-05-13 09:03:38.910230+00:00 +url = "https://files.pythonhosted.org/packages/59/fc/f8d0863f8862f25602c0404d75568e89fb6b4109804645e5cdfb1be5cf56/mdit_py_plugins-0.6.1.tar.gz" +size = 56114 + +[packages.sdist.hashes] +sha256 = "a2bca0f039f39dbd35fb74ae1b5f998608c437463371f0ff7f49a19a17a114d0" + +[[packages.wheels]] +name = "mdit_py_plugins-0.6.1-py3-none-any.whl" +upload-time = 2026-05-13 09:03:37.760000+00:00 +url = "https://files.pythonhosted.org/packages/a5/69/6da5581c6a7fede7dc261bf4e67d6adca4196f176b43288b55b3db395b6e/mdit_py_plugins-0.6.1-py3-none-any.whl" +size = 66663 + +[packages.wheels.hashes] +sha256 = "214c82fb2ac524472ab6a5bcab1de80f73b50443e187f401bfd77efbc7c6481d" + +[[packages]] +name = "mdurl" +version = "0.1.2" +marker = "\"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups" +requires-python = ">=3.7" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "mdurl-0.1.2.tar.gz" +upload-time = 2022-08-14 12:40:10.846281+00:00 +url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz" +size = 8729 + +[packages.sdist.hashes] +sha256 = "bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba" + +[[packages.wheels]] +name = "mdurl-0.1.2-py3-none-any.whl" +upload-time = 2022-08-14 12:40:09.779676+00:00 +url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl" +size = 9979 + +[packages.wheels.hashes] +sha256 = "84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8" + +[[packages]] +name = "packaging" +version = "26.3" +marker = "\"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups" +requires-python = ">=3.9" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "packaging-26.3.tar.gz" +upload-time = 2026-08-04 18:15:28.737071+00:00 +url = "https://files.pythonhosted.org/packages/7d/fa/3944b40b07da9ce895c0e6303a5ab7d53da063554f534556b134a54d6093/packaging-26.3.tar.gz" +size = 313412 + +[packages.sdist.hashes] +sha256 = "94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79" + +[[packages.wheels]] +name = "packaging-26.3-py3-none-any.whl" +upload-time = 2026-08-04 18:15:27.159957+00:00 +url = "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl" +size = 129956 + +[packages.wheels.hashes] +sha256 = "d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c" + +[[packages]] +name = "prek" +version = "0.5.6" +marker = "\"release-prepare\" in dependency_groups" +requires-python = ">=3.8" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "prek-0.5.6.tar.gz" +upload-time = 2026-10-19 05:46:52.314250+00:00 +url = "https://files.pythonhosted.org/packages/4f/96/c4062bcaebdabfa945d07c424fb8c05d53a72d4f3fdcf255b1188abbb150/prek-0.5.6.tar.gz" +size = 579962 + +[packages.sdist.hashes] +sha256 = "87a8c19f873b96be809b4368959ed908cfa06255dba15082d0fb91173e9293bc" + +[[packages.wheels]] +name = "prek-0.5.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" +upload-time = 2026-10-19 05:46:42.326947+00:00 +url = "https://files.pythonhosted.org/packages/e1/f7/04e08d2343ce1d54c5da879e2dfea7df20f3140b1b2023a937fac87fa545/prek-0.5.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" +size = 6165929 + +[packages.wheels.hashes] +sha256 = "aabec01beeb372bcdc48f6b339021bc33c07edf477b337fc92dc5d3b01f99150" + +[[packages]] +name = "pyyaml" +version = "6.0.3" +marker = "\"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups" +requires-python = ">=3.8" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "pyyaml-6.0.3.tar.gz" +upload-time = 2025-09-25 21:33:16.546886+00:00 +url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz" +size = 130960 + +[packages.sdist.hashes] +sha256 = "d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f" + +[[packages]] +name = "release-creator" +version = "4.1.0" +marker = "\"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups" +requires-python = ">=3.15" +dependencies = [ + { name = "docutils" }, + { name = "markdown-it-py" }, + { name = "mdformat" }, + { name = "mdformat-gfm" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "towncrier" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "release_creator-4.1.0.tar.gz" +upload-time = 2026-10-26 18:24:45.805437+00:00 +url = "https://files.pythonhosted.org/packages/7f/fd/05d7f3c604476a238d67d5aaa2a4085312e7078c193dbd7ad99ad48d560d/release_creator-4.1.0.tar.gz" +size = 186016 + +[packages.sdist.hashes] +sha256 = "c783037f5ca2efc16fa7cccfb1c2abf0a442f116a63ca82bd7bfb7e2a8343a15" + +[[packages.wheels]] +name = "release_creator-4.1.0-py3-none-any.whl" +upload-time = 2026-10-26 18:24:44.353933+00:00 +url = "https://files.pythonhosted.org/packages/30/d0/38480e99025c021d07e0710af02547562dfadbd798bef26dc01869a3f81e/release_creator-4.1.0-py3-none-any.whl" +size = 52922 + +[packages.wheels.hashes] +sha256 = "67deae16d11ac261a1512f18a22c0cf13418f43afc3e56cb74e58ad4422062e3" + +[[packages]] +name = "setuptools" +version = "84.0.0" +marker = "\"build\" in dependency_groups" +requires-python = ">=3.10" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "setuptools-84.0.0.tar.gz" +upload-time = 2026-08-08 18:27:58.365696+00:00 +url = "https://files.pythonhosted.org/packages/6d/44/f5da03a8ef95d369145c5bb53050e7877c9f3d312e128605fd9504829143/setuptools-84.0.0.tar.gz" +size = 1168449 + +[packages.sdist.hashes] +sha256 = "f4695c21257f0d9b537ec2692c941d02ee143b7cc1276941349a546573b2ef73" + +[[packages.wheels]] +name = "setuptools-84.0.0-py3-none-any.whl" +upload-time = 2026-08-08 18:27:56.719708+00:00 +url = "https://files.pythonhosted.org/packages/95/9c/c510029fc6ef33a6275cd2c5d3cecd6613dfd6aa401d57c54f1c18852ccf/setuptools-84.0.0-py3-none-any.whl" +size = 818216 + +[packages.wheels.hashes] +sha256 = "51a52592b3b99e102b609654876bd65f19f999935166d1352678931132b0c670" + +[[packages]] +name = "towncrier" +version = "26.9.0" +marker = "\"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups" +requires-python = ">=3.9" +dependencies = [ + { name = "click" }, + { name = "jinja2" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "towncrier-26.9.0.tar.gz" +upload-time = 2026-09-04 12:57:25.341701+00:00 +url = "https://files.pythonhosted.org/packages/92/d4/e85ce614bf45b1a7fe13b82cc687819c2eaac5a1dd94b84834322095fd98/towncrier-26.9.0.tar.gz" +size = 79338 + +[packages.sdist.hashes] +sha256 = "ace9031631c718cc0709107b8755e6e31350eb8acdc877af43df3177addb9a55" + +[[packages.wheels]] +name = "towncrier-26.9.0-py3-none-any.whl" +upload-time = 2026-09-04 12:57:23.986160+00:00 +url = "https://files.pythonhosted.org/packages/82/88/f9340b545dafa64de053798e760515a2736fbb60092cf9aa6b146ccf3ede/towncrier-26.9.0-py3-none-any.whl" +size = 67030 + +[packages.wheels.hashes] +sha256 = "ae4d223e6aadaff98d29b7f09e58d9c9ccf4cd3b455a2d2e0486d432cd8bf660" + +[[packages]] +name = "wcwidth" +version = "0.9.2" +marker = "\"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups" +requires-python = ">=3.9" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "wcwidth-0.9.2.tar.gz" +upload-time = 2026-10-05 00:24:05.521972+00:00 +url = "https://files.pythonhosted.org/packages/f0/b4/7830542634bb2d3e62aa3b586a72d5b3b6c91c3168929e7000ef3fed041d/wcwidth-0.9.2.tar.gz" +size = 955039 + +[packages.sdist.hashes] +sha256 = "ae0ef90b90f6af38b54f1fe6d58662ec33b3cb4b8391958a62416d654231727b" + +[[packages.wheels]] +name = "wcwidth-0.9.2-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" +upload-time = 2026-10-05 00:23:40.175985+00:00 +url = "https://files.pythonhosted.org/packages/db/6c/f940133c71427c208575910e981942bd78c98b1f7cd0d1425ca4b7457c04/wcwidth-0.9.2-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" +size = 769763 + +[packages.wheels.hashes] +sha256 = "751bef0ab404b6a1dc028b56b4b85d46486be1c55833f80da533e42dc691f389" + +[[packages.wheels]] +name = "wcwidth-0.9.2-py3-none-any.whl" +upload-time = 2026-10-05 00:23:21.097514+00:00 +url = "https://files.pythonhosted.org/packages/9c/b4/0bfa065af506540d9d558e3e5548cff00bc1f9b24e6e2a8512498e8628de/wcwidth-0.9.2-py3-none-any.whl" +size = 301667 + +[packages.wheels.hashes] +sha256 = "89ca642c5bf0101157a09366be69fad0379db1f700ae39a920e103234573670e" + +[tool.nab] +nab-version = "0.0.22" +created-at = 2026-10-26 20:06:24.472187+00:00 +command-line = [ + "nab", + "lock", + "--all-groups", + "--all-extras", + "--no-cache", + "--upgrade", + "pyproject.toml", + "--output", + "pylock.toml", +] +input-path = "pyproject.toml" +mode = "universal" +python-specifier = ">=3.15,<3.16" +platforms = [ + "linux_x86_64", +] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..1d954d2 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,59 @@ +[project] +name = "action-pre-commit-uv-release-tools" +version = "0" +requires-python = ">=3.15" +dependencies = [] + +[dependency-groups] +build = [ + "cython>=3", + "setuptools>=80", +] +release-notes = [ + "release-creator>=4.1", +] + +release-news = [ + "release-creator>=4.1", + "towncrier>=26.9", +] + +release-prepare = [ + "prek>=0.5", + "release-creator>=4.1", + "towncrier>=26.9", +] + + +[tool.uv] +package = false + +[tool.nab] +mode = "universal" +default-groups = [] +base-group = "project-runtime" +uploaded-prior-to = "P7D" +decision-order = "stable" +matrix.python = ">=3.15,<3.16" +matrix.platforms = [ "linux_x86_64" ] +# temporary, delete after 2026-11-02 +packages.release-creator.uploaded-prior-to = 2026-10-26T18:24:46Z + +[tool.towncrier] +name = "action-pre-commit-uv" +directory = "changelog.d" +filename = "CHANGELOG.md" +template = "release_creator.fragments:template.jinja2" +title_format = false +type = [ + { directory = "feature", name = "Added", showcontent = true }, + { directory = "change", name = "Changes", showcontent = true }, + { directory = "bugfix", name = "Fixed", showcontent = true }, + { directory = "doc", name = "Documentation", showcontent = true }, + { directory = "breaking", name = "Breaking changes", showcontent = true }, + { directory = "security", name = "Security", showcontent = true }, + { directory = "performance", name = "Performance", showcontent = true }, + { directory = "deprecation", name = "Deprecated", showcontent = true }, + { directory = "removal", name = "Removed", showcontent = true }, + { directory = "packaging", name = "Packaging", showcontent = true }, +]