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 }, +]