chore: import upstream snapshot with attribution
fuzz / fuzz (3.11) (push) Failing after 1s
fuzz / fuzz (3.12) (push) Failing after 1s
build and publish / sdist + pure wheel (push) Failing after 0s
diff-shades / analysis / base / ${{ matrix.mode }} (push) Has been skipped
docs / docs (ubuntu-latest) (push) Failing after 2s
fuzz / fuzz (3.10) (push) Failing after 1s
fuzz / fuzz (3.14) (push) Failing after 0s
lint and format / lint (push) Failing after 1s
diff-shades / configure (push) Failing after 1s
docker / build (linux/amd64) (push) Has been skipped
diff-shades / analysis / target / ${{ matrix.mode }} (push) Has been skipped
fuzz / fuzz (3.13) (push) Failing after 0s
build and publish / generate wheels matrix (push) Failing after 0s
test release tool / test-release-tool (ubuntu-latest, 3.13) (push) Failing after 1s
build and publish / mypyc wheels ${{ matrix.only }} (push) Has been skipped
test / test (ubuntu-latest, 3.10) (push) Failing after 0s
test / test (ubuntu-latest, 3.11) (push) Failing after 1s
test / test (ubuntu-latest, 3.13) (push) Failing after 0s
test / test (ubuntu-latest, pypy3.11-v7.3.22) (push) Failing after 1s
test / test (ubuntu-latest, 3.15) (push) Failing after 1s
test release tool / test-release-tool (ubuntu-latest, 3.15) (push) Failing after 0s
zizmor / zizmor (push) Failing after 0s
test release tool / test-release-tool (ubuntu-latest, 3.12) (push) Failing after 4s
test release tool / test-release-tool (ubuntu-latest, 3.14) (push) Failing after 3s
test / uvloop (ubuntu-latest) (push) Failing after 1s
test / test (ubuntu-latest, 3.14) (push) Failing after 1s
test / test (ubuntu-latest, 3.12.10) (push) Failing after 5s
docker / build (linux/arm64) (push) Has been cancelled
docker / push (push) Has been cancelled
docs / docs (windows-latest) (push) Has been cancelled
test release tool / test-release-tool (windows-latest, 3.14) (push) Has been cancelled
test release tool / test-release-tool (windows-latest, 3.15) (push) Has been cancelled
test release tool / test-release-tool (macOS-latest, 3.12) (push) Has been cancelled
test release tool / test-release-tool (macOS-latest, 3.13) (push) Has been cancelled
test release tool / test-release-tool (macOS-latest, 3.14) (push) Has been cancelled
test release tool / test-release-tool (macOS-latest, 3.15) (push) Has been cancelled
test release tool / test-release-tool (windows-latest, 3.12) (push) Has been cancelled
test release tool / test-release-tool (windows-latest, 3.13) (push) Has been cancelled
test / test (macOS-latest, 3.11) (push) Has been cancelled
test / test (macOS-latest, 3.12.10) (push) Has been cancelled
test / test (macOS-latest, 3.13) (push) Has been cancelled
test / test (macOS-latest, 3.14) (push) Has been cancelled
test / test (macOS-latest, 3.15) (push) Has been cancelled
test / test (macOS-latest, pypy3.11-v7.3.22) (push) Has been cancelled
test / test (windows-11-arm, 3.11) (push) Has been cancelled
test / test (windows-11-arm, 3.12.10) (push) Has been cancelled
test / test (windows-11-arm, 3.13) (push) Has been cancelled
test / test (macOS-latest, 3.10) (push) Has been cancelled
test / coveralls-finish (push) Has been cancelled
test / uvloop (macOS-latest) (push) Has been cancelled
test / uvloop (windows-11-arm) (push) Has been cancelled
test / uvloop (windows-latest) (push) Has been cancelled
test / test (windows-11-arm, 3.14) (push) Has been cancelled
test / test (windows-11-arm, 3.15) (push) Has been cancelled
test / test (windows-latest, 3.10) (push) Has been cancelled
test / test (windows-latest, 3.11) (push) Has been cancelled
test / test (windows-latest, 3.12.10) (push) Has been cancelled
test / test (windows-latest, 3.13) (push) Has been cancelled
test / test (windows-latest, 3.14) (push) Has been cancelled
test / test (windows-latest, 3.15) (push) Has been cancelled
test / test (windows-latest, pypy3.11-v7.3.22) (push) Has been cancelled
diff-shades / compare / ${{ matrix.mode }} (push) Has been cancelled
fuzz / create-issue (push) Has been cancelled
build and publish / publish-mypyc (push) Has been cancelled
build and publish / publish-hatch (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 12:07:39 +08:00
commit d0aab9212a
460 changed files with 145411 additions and 0 deletions
+25
View File
@@ -0,0 +1,25 @@
name: changelog
on:
pull_request:
types: [opened, synchronize, labeled, unlabeled, reopened]
permissions:
contents: read
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Grep CHANGES.md for PR number
if: >
contains(github.event.pull_request.labels.*.name, 'ci: skip news') != true
run: |
grep -Pz "\((\n\s*)?#${{ github.event.pull_request.number }}(\n\s*)?\)" CHANGES.md || \
(echo "Please add '(#${{ github.event.pull_request.number }})' change line to CHANGES.md (or if appropriate, ask a maintainer to add the 'ci: skip news' label)" && \
exit 1)
+240
View File
@@ -0,0 +1,240 @@
name: diff-shades
on:
push:
branches: [main]
paths:
- src/**
- pyproject.toml
- scripts/diff_shades_gha_helper.py
- .github/workflows/diff_shades.yml
- .github/workflows/diff_shades_comment.yml
pull_request:
paths:
- src/**
- pyproject.toml
- scripts/diff_shades_gha_helper.py
- .github/workflows/diff_shades.yml
- .github/workflows/diff_shades_comment.yml
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
env:
HATCH_BUILD_HOOKS_ENABLE: "1"
# Clang is less picky with the C code it's given than gcc (and may generate faster
# binaries too).
CC: clang-18
permissions: {}
jobs:
configure:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-config.outputs.matrix }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
pip-version: "25.3"
pip-install: --group diff-shades --group diff-shades-comment
- name: Calculate run configuration & metadata
id: set-config
env:
GITHUB_TOKEN: ${{ github.token }}
run: python scripts/diff_shades_gha_helper.py config
analysis-base:
name: analysis / base / ${{ matrix.mode }}
needs: configure
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include: ${{ fromJson(needs.configure.outputs.matrix) }}
steps:
- name: Checkout this repository (full clone)
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
# The baseline revision could be rather old so a full clone is ideal.
fetch-depth: 0
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
pip-version: "25.3"
pip-install: --group diff-shades
- name: Configure git
run: |
git config user.name "diff-shades-gha"
git config user.email "diff-shades-gha@example.com"
- name: Attempt to use cached baseline analysis
id: baseline-cache
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ${{ matrix.baseline-analysis }}
key: ${{ matrix.baseline-cache-key }}
- name: Build and install baseline revision
if: steps.baseline-cache.outputs.cache-hit != 'true'
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
${{ matrix.baseline-setup-cmd }}
python -m pip install .
- name: Analyze baseline revision
if: steps.baseline-cache.outputs.cache-hit != 'true'
run:
diff-shades analyze ${{ matrix.baseline-analysis }} --work-dir projects-cache/
--force-${{ matrix.style }}-style -v
- name: Upload baseline analysis
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ matrix.baseline-analysis }}
path: ${{ matrix.baseline-analysis }}
analysis-target:
name: analysis / target / ${{ matrix.mode }}
needs: configure
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include: ${{ fromJson(needs.configure.outputs.matrix) }}
steps:
- name: Checkout this repository (full clone)
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
# The baseline revision could be rather old so a full clone is ideal.
fetch-depth: 0
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
pip-version: "25.3"
pip-install: --group diff-shades
- name: Configure git
run: |
git config user.name "diff-shades-gha"
git config user.email "diff-shades-gha@example.com"
- name: Build and install target revision
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
${{ matrix.target-setup-cmd }}
python -m pip install .
# Pull it from previous runs - we're NOT trying to get it from this run
# (but it wouldn't cause problems if we theoretically did)
- name: Attempt to find baseline analysis
id: baseline-cache
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ${{ matrix.baseline-analysis }}
key: ${{ matrix.baseline-cache-key }}
- name: Analyze target revision (with repeated projects)
if: steps.baseline-cache.outputs.cache-hit == 'true'
run: |
diff-shades analyze ${{ matrix.target-analysis }} --work-dir projects-cache/ \
--force-${{ matrix.style }}-style -v \
--repeat-projects-from ${{ matrix.baseline-analysis }}
- name: Analyze target revision (without repeated projects)
if: steps.baseline-cache.outputs.cache-hit != 'true'
run:
diff-shades analyze ${{ matrix.target-analysis }} --work-dir projects-cache/
--force-${{ matrix.style }}-style -v
- name: Upload target analysis
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ matrix.target-analysis }}
path: ${{ matrix.target-analysis }}
- name: Check for failed files for target revision
run: diff-shades show-failed --check --show-log ${{ matrix.target-analysis }}
compare:
name: compare / ${{ matrix.mode }}
needs: ["configure", "analysis-base", "analysis-target"]
if: ${{ !cancelled() }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include: ${{ fromJson(needs.configure.outputs.matrix) }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
merge-multiple: true
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
pip-version: "25.3"
pip-install: --group diff-shades --group diff-shades-comment
- name: Generate HTML diff report
run: |
diff-shades --dump-html diff.html \
compare --diff ${{ matrix.baseline-analysis }} ${{ matrix.target-analysis }}
- name: Upload diff report
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ matrix.style }}-diff.html
path: diff.html
- name: Generate summary file (PR only)
if: github.event_name == 'pull_request'
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
python scripts/diff_shades_gha_helper.py comment-body \
${{ matrix.baseline-analysis }} ${{ matrix.target-analysis }} \
${{ matrix.style }} ${{ matrix.mode }}
- name: Upload summary file (PR only)
if: github.event_name == 'pull_request'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: .${{ matrix.style }}.pr-comment.md
path: .${{ matrix.style }}.pr-comment.md
include-hidden-files: true
- name: Verify zero changes (PR only)
if: matrix.mode == 'assert-no-changes'
run: |
diff-shades compare --check \
${{ matrix.baseline-analysis }} ${{ matrix.target-analysis }} || \
(echo "Please verify you didn't change the stable code style unintentionally!" \
&& exit 1)
+123
View File
@@ -0,0 +1,123 @@
name: diff-shades comment
on:
workflow_run:
workflows: [diff-shades]
types: [completed]
permissions: {}
jobs:
comment:
runs-on: ubuntu-latest
# We want to comment even if there were failed files or the stable style changed
# That would cause the main workflow to "fail"
if:
github.event.workflow_run.event == 'pull_request' &&
contains(fromJSON('["success", "failure"]'), github.event.workflow_run.conclusion)
permissions:
pull-requests: write # Needed to comment on PR
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
id: artifacts
with:
merge-multiple: true
pattern: ".*.pr-comment.md"
path: ${{ runner.temp }}/diff-shades-artifacts
github-token: ${{ github.token }}
run-id: ${{ github.event.workflow_run.id }}
- name: Validate downloaded comment artifacts
id: comment-artifacts
shell: bash
run: |
set -euo pipefail
artifact_dir="${RUNNER_TEMP}/diff-shades-artifacts"
preview_artifact="${artifact_dir}/.preview.pr-comment.md"
stable_artifact="${artifact_dir}/.stable.pr-comment.md"
if [ ! -d "$artifact_dir" ]; then
echo "::error::Artifact directory does not exist: ${artifact_dir}"
exit 1
fi
while IFS= read -r -d '' entry; do
if [ "$(dirname "$entry")" != "$artifact_dir" ]; then
echo "::error::Unexpected nested artifact path: ${entry}"
exit 1
fi
case "$(basename "$entry")" in
.preview.pr-comment.md|.stable.pr-comment.md) ;;
*)
echo "::error::Unexpected artifact path: ${entry}"
exit 1
;;
esac
if [ ! -f "$entry" ] || [ -L "$entry" ]; then
echo "::error::Artifact must be a regular file: ${entry}"
exit 1
fi
done < <(find "$artifact_dir" -mindepth 1 -print0)
for artifact in "$preview_artifact" "$stable_artifact"; do
if [ ! -f "$artifact" ] || [ -L "$artifact" ]; then
echo "::error::Missing expected artifact file: ${artifact}"
exit 1
fi
done
{
echo "preview=${preview_artifact}"
echo "stable=${stable_artifact}"
} >> "$GITHUB_OUTPUT"
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
pip-version: "25.3"
pip-install: --group diff-shades-comment
- name: Get PR number
id: pr
run:
echo pr=$(gh pr list --search $sha --json number --jq ".[0].number") >>
"$GITHUB_OUTPUT"
env:
GITHUB_TOKEN: ${{ github.token }}
sha: ${{ github.event.workflow_run.head_sha }}
- name: Get details from initial workflow run
id: metadata
run: |
python scripts/diff_shades_gha_helper.py comment-details \
"$pr" "$run_id" "$preview_artifact" "$stable_artifact"
env:
GITHUB_TOKEN: ${{ github.token }}
pr: ${{ steps.pr.outputs.pr }}
run_id: ${{ github.event.workflow_run.id }}
preview_artifact: ${{ steps.comment-artifacts.outputs.preview }}
stable_artifact: ${{ steps.comment-artifacts.outputs.stable }}
- name: Try to find pre-existing PR comment
id: find-comment
uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad # v4.0.0
with:
issue-number: ${{ steps.pr.outputs.pr }}
comment-author: "github-actions[bot]"
body-includes: "diff-shades"
- name: Create or update PR comment
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
with:
comment-id: ${{ steps.find-comment.outputs.comment-id }}
issue-number: ${{ steps.pr.outputs.pr }}
body: ${{ steps.metadata.outputs.comment-body }}
edit-mode: replace
+123
View File
@@ -0,0 +1,123 @@
name: docker
on:
push:
branches:
- "main"
release:
types: [published]
permissions:
contents: read
env:
REGISTRY: pyfound/black
jobs:
build:
if: github.repository == 'psf/black'
runs-on: ${{ matrix.runner }}
name: build (${{ matrix.platform }})
strategy:
matrix:
include:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
- name: Login to DockerHub
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Prepare
id: prepare
run: echo "platform=${platform//\//-}" >> $GITHUB_OUTPUT
env:
platform: ${{ matrix.platform }}
- name: Build and push
id: build
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
with:
context: .
platforms: ${{ matrix.platform }}
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
tags: ${{ env.REGISTRY }}
cache-from: type=gha,scope=${{ steps.prepare.outputs.platform }}
cache-to: type=gha,scope=${{ steps.prepare.outputs.platform }},mode=max
- name: Export digest
run: |
mkdir -p digests
touch "digests/${digest#sha256:}"
env:
digest: ${{ steps.build.outputs.digest }}
- name: Upload digest
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: digests-${{ steps.prepare.outputs.platform }}
path: digests/*
if-no-files-found: error
push:
runs-on: ubuntu-latest
needs: build
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Download digests
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: digests
pattern: digests-*
merge-multiple: true
- name: Login to DockerHub
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
- name: Create manifest list and push
run: |
TAGS="-t $REGISTRY:latest"
if [[ "$EVENT_NAME" == "release" ]]; then
TAGS="$TAGS -t $REGISTRY:$(git describe --candidates=0 --tags)"
if [[ "$PRERELEASE" == "true" ]]; then
TAGS="$TAGS -t $REGISTRY:latest_prerelease"
else
TAGS="$TAGS -t $REGISTRY:latest_release"
fi
else
TAGS="$TAGS -t $REGISTRY:latest_non_release"
fi
cd digests
docker buildx imagetools create $TAGS $(printf "$REGISTRY@sha256:%s " *)
env:
EVENT_NAME: ${{ github.event_name }}
PRERELEASE: ${{ github.event.release.prerelease }}
- name: Inspect image
run: docker buildx imagetools inspect $REGISTRY:latest
+41
View File
@@ -0,0 +1,41 @@
name: docs
on:
push:
paths: ["docs/**", "src/**", "pyproject.toml", ".github/workflows/docs.yml"]
pull_request:
paths: ["docs/**", "src/**", "pyproject.toml", ".github/workflows/docs.yml"]
permissions:
contents: read
jobs:
docs:
# We want to run on external PRs, but not on our own internal PRs as they'll be run
# by the push to the branch. Without this if check, checks are duplicated since
# internal PRs match both the push and pull_request events.
if:
github.event_name == 'push' || github.event.pull_request.head.repo.full_name !=
github.repository
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
pip-version: "25.3"
pip-install: -e .[d] --group docs
- name: Build documentation
run: sphinx-build -a -b html -W --keep-going docs/ docs/_build
+109
View File
@@ -0,0 +1,109 @@
name: fuzz
on:
push:
branches: main
pull_request:
paths:
- .github/workflows/fuzz.yml
- scripts/fuzz.py
schedule:
- cron: "0 0 * * *"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
permissions:
contents: read
jobs:
fuzz:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# TODO: add 3.15; relies on libcst which doesn't support 3.15 yet
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
pip-version: "25.3"
pip-install: --group tox
- name: Run fuzz tests
id: fuzz
run: tox -e fuzz --result-json $python_ver
env:
python_ver: ${{ matrix.python-version }}
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: failure() && steps.fuzz.outcome == 'failure'
with:
name: ${{ matrix.python-version }}
path: ${{ matrix.python-version }}
create-issue:
runs-on: ubuntu-latest
needs: fuzz
if:
github.repository == 'psf/black' && github.event_name != 'pull_request' &&
failure()
permissions:
issues: write # Needed to create issue
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
merge-multiple: true
path: ./output
- name: Generate issue data
run: |
output=issue-body.html
touch $output
for FILE in ./output/*; do
echo "**Python $(basename $FILE)**" >> $output
echo -e "\`\`\`py" >> $output
echo -e "# stdout:" >> $output
echo -e "$(jq .testenvs.fuzz.test[-1].output $FILE -r)\n" >> $output
echo -e "# stderr:" >> $output
echo -e "$(jq .testenvs.fuzz.test[-1].err $FILE -r)" >> $output
echo -e "\`\`\`\n" >> $output
done
- name: Get existing issue
id: issue
run: |
echo "ISSUE=$( gh issue list \
-A github-actions[bot] -l 'ci: fuzz error' \
--json number -q .[0].number \
-R $REPO )" >> $GITHUB_OUTPUT
env:
GITHUB_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
- name: Create new issue
if: steps.issue.outputs.ISSUE == ''
run: >
gh issue create -t "Fuzz test failure" -F issue-body.html -l "ci: fuzz error"
-R $REPO
env:
GITHUB_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
- name: Edit existing issue
if: steps.issue.outputs.ISSUE != ''
run: gh issue edit $ISSUE -F issue-body.html -R $REPO
env:
GITHUB_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
ISSUE: ${{ steps.issue.outputs.ISSUE }}
+46
View File
@@ -0,0 +1,46 @@
name: lint and format
on: [push, pull_request]
permissions: {}
jobs:
lint:
# We want to run on external PRs, but not on our own internal PRs as they'll be run
# by the push to the branch. Without this if check, checks are duplicated since
# internal PRs match both the push and pull_request events.
if:
github.event_name == 'push' || github.event.pull_request.head.repo.full_name !=
github.repository
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Assert PR target is main
if: github.event_name == 'pull_request' && github.repository == 'psf/black'
run: |
if [ "$GITHUB_BASE_REF" != "main" ]; then
echo "::error::PR targeting '$GITHUB_BASE_REF', please refile targeting 'main'." && exit 1
fi
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
pip-version: "25.3"
pip-install: -e . --group tox
- name: Run pre-commit hooks
uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1
- name: Format ourselves
run: tox -e run_self
- name: Regenerate schema
run: |
tox -e generate_schema
git diff --exit-code
+66
View File
@@ -0,0 +1,66 @@
name: post release
on:
release:
types: published
permissions: {}
jobs:
update-stable:
runs-on: ubuntu-latest
if: github.event.release.prerelease != 'true'
permissions:
contents: write # Needed to push to stable
steps:
- name: Checkout stable branch
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
ref: stable
fetch-depth: 0
persist-credentials: true # needed for `git push` below
- name: Update stable branch to release tag & push
run: |
git reset --hard "${TAG_NAME}"
git push
env:
TAG_NAME: ${{ github.event.release.tag_name }}
new-changelog:
runs-on: ubuntu-latest
if: github.event.release.prerelease != 'true'
permissions:
contents: write # Needed to push to new branch
pull-requests: write # Needed to create PR
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
ref: main
fetch-tags: true
persist-credentials: true # Needed for git-auto-commit-action
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
pip-version: "25.3"
- run: python scripts/release.py -a
- uses: stefanzweifel/git-auto-commit-action@4a55954c782fc1ea30b9056cd3e7a2b40ca8887d # v7.2.0
with:
commit_message: Add new changelog
branch: ci/new-changelog
create_branch: true
- name: Create PR
run: |
gh pr create \
-t "Add new changelog" -b "" \
-l "ci: skip news" -l "C: maintenance" \
-a $USER
env:
GITHUB_TOKEN: ${{ github.token }}
USER: ${{ github.event.release.author.login }}
+77
View File
@@ -0,0 +1,77 @@
name: publish binaries
on:
release:
types: [published]
workflow_dispatch:
inputs:
tag:
required: true
type: string
permissions: {}
jobs:
publish:
name: publish (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
pathsep: ";"
asset_name: black_windows.exe
executable_mime: "application/vnd.microsoft.portable-executable"
strip: false
- os: windows-11-arm
pathsep: ";"
asset_name: black_windows-arm.exe
executable_mime: "application/vnd.microsoft.portable-executable"
strip: false
- os: ubuntu-latest
pathsep: ":"
asset_name: black_linux
executable_mime: "application/x-executable"
strip: true
- os: ubuntu-24.04-arm
pathsep: ":"
asset_name: black_linux-arm
executable_mime: "application/x-executable"
strip: true
- os: macos-latest
pathsep: ":"
asset_name: black_macos
executable_mime: "application/x-mach-binary"
strip: false
permissions:
contents: write # Needed to upload to release
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
pip-version: "25.3"
pip-install: .[colorama] --group pyinstaller
- name: Build executable with PyInstaller
run:
python -m PyInstaller -F ${{ matrix.strip && '--strip' || '' }} --name ${{
matrix.asset_name }} --add-data 'src/blib2to3${{ matrix.pathsep }}blib2to3'
src/black/__main__.py
- name: Quickly test executable
run: |
./dist/${{ matrix.asset_name }} --version
./dist/${{ matrix.asset_name }} src --verbose
- run: gh release upload "$tag" dist/${{ matrix.asset_name }}
shell: bash
env:
GH_TOKEN: ${{ github.token }}
tag: ${{ inputs.tag || github.event.release.tag_name }}
+160
View File
@@ -0,0 +1,160 @@
name: build and publish
on:
release:
types: published
pull_request:
push:
branches: main
permissions: {}
env:
PROJECT: https://pypi.org/p/black
jobs:
configure:
name: generate wheels matrix
runs-on: ubuntu-latest
outputs:
include: ${{ steps.set-matrix.outputs.include }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
pip-version: "25.3"
pip-install: --group cibw
- name: generate matrix
if: |
github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'ci: build all wheels')
run: |
{
cibuildwheel --print-build-identifiers --platform linux \
| pyp 'json.dumps({"only": x, "os": "ubuntu-latest"})' \
&& cibuildwheel --print-build-identifiers --platform macos \
| pyp 'json.dumps({"only": x, "os": "macos-latest"})' \
&& cibuildwheel --print-build-identifiers --platform windows \
| pyp 'json.dumps({"only": x, "os": "windows-latest"})' \
&& cibuildwheel --print-build-identifiers --platform windows --archs ARM64 \
| pyp 'json.dumps({"only": x, "os": "windows-11-arm"})'
} | pyp 'json.dumps(list(map(json.loads, lines)))' > /tmp/matrix
env:
CIBW_ARCHS_LINUX: x86_64
CIBW_ARCHS_MACOS: x86_64 arm64
CIBW_ARCHS_WINDOWS: AMD64
- name: generate matrix (PR)
if: |
github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'ci: build all wheels')
run: |
{
CIBW_BUILD="cp310-*" cibuildwheel --print-build-identifiers --platform linux | pyp 'json.dumps({"only": x, "os": "ubuntu-latest"})'
CIBW_BUILD="cp314-*" cibuildwheel --print-build-identifiers --platform windows | pyp 'json.dumps({"only": x, "os": "windows-latest"})'
} | pyp 'json.dumps(list(map(json.loads, lines)))' > /tmp/matrix
env:
CIBW_ARCHS_LINUX: x86_64
- id: set-matrix
run: echo "include=$(cat /tmp/matrix)" | tee -a $GITHUB_OUTPUT
mypyc:
name: mypyc wheels ${{ matrix.only }}
needs: configure
runs-on: ${{ matrix.os }}
strategy:
matrix:
include: ${{ fromJson(needs.configure.outputs.include) }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
pip-version: "25.3"
pip-install: --group cibw
- name: Run cibuildwheel
run: cibuildwheel . --only ${{ matrix.only }}
- name: Upload wheels as workflow artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ matrix.only }}-mypyc-wheels
path: wheelhouse/
hatch:
name: sdist + pure wheel
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
pip-version: "25.3"
pip-install: --group hatch
- name: Build wheel and source distributions
run: python -m hatch build
- name: Store the distribution packages
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: sdist-and-pure-wheel
path: dist/
publish-mypyc:
if: github.event_name == 'release'
needs: mypyc
runs-on: ubuntu-latest
environment:
name: release
url: ${{ env.PROJECT }}
permissions:
id-token: write # Required for PyPI trusted publishing
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: "*-mypyc-wheels"
path: wheelhouse/
merge-multiple: true
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
with:
packages-dir: wheelhouse/
verbose: true
publish-hatch:
if: github.event_name == 'release'
needs: hatch
runs-on: ubuntu-latest
environment:
name: release
url: ${{ env.PROJECT }}
permissions:
id-token: write # Required for PyPI trusted publishing
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: sdist-and-pure-wheel
path: dist/
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
with:
verbose: true
+59
View File
@@ -0,0 +1,59 @@
name: test release tool
on:
push:
paths:
- .github/workflows/release_tests.yml
- scripts/release.py
- scripts/release_tests.py
pull_request:
paths:
- .github/workflows/release_tests.yml
- scripts/release.py
- scripts/release_tests.py
permissions: {}
jobs:
test-release-tool:
# We want to run on external PRs, but not on our own internal PRs as they'll be run
# by the push to the branch. Without this if check, checks are duplicated since
# internal PRs match both the push and pull_request events.
if:
github.event_name == 'push' || github.event.pull_request.head.repo.full_name !=
github.repository
runs-on: ${{ matrix.os }}
strategy:
matrix:
python-version: ["3.12", "3.13", "3.14", "3.15"]
os: [macOS-latest, ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
# Give us all history, branches and tags
fetch-depth: 0
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
pip-version: "25.3"
pip-install: --group coverage
- name: Print Python Version
run: python --version --version && which python
- name: Print Pip Version
run: pip --version && which pip
- name: Print Git Version
run: git --version && which git
- name: Run unit tests via coverage + print report
run: |
coverage run scripts/release_tests.py
coverage report --show-missing
+124
View File
@@ -0,0 +1,124 @@
name: test
on:
push:
paths:
- .github/workflows/test.yml
- src/**
- tests/**
- tox.ini
- pyproject.toml
pull_request:
paths:
- .github/workflows/test.yml
- src/**
- tests/**
- tox.ini
- pyproject.toml
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
jobs:
test:
# We want to run on external PRs, but not on our own internal PRs as they'll be run
# by the push to the branch. Without this if check, checks are duplicated since
# internal PRs match both the push and pull_request events.
if:
github.event_name == 'push' || github.event.pull_request.head.repo.full_name !=
github.repository
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
python-version:
["3.10", "3.11", "3.12.10", "3.13", "3.14", "3.15", "pypy3.11-v7.3.22"]
os: [ubuntu-latest, macOS-latest, windows-latest, windows-11-arm]
exclude:
# setup-python only supports CPython 3.11+ on arm64 windows
- os: windows-11-arm
python-version: "3.10"
- os: windows-11-arm
python-version: "pypy3.11-v7.3.22"
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
pip-version: "25.3"
pip-install: --group tox
- name: Unit tests
if: "!startsWith(matrix.python-version, 'pypy')"
run:
tox -e ci-py$(echo ${{ matrix.python-version }} | tr -d '.') -- -v --color=yes
- name: Unit tests (pypy)
if: "startsWith(matrix.python-version, 'pypy')"
run: tox -e ci-pypy3 -- -v --color=yes
- name: Upload coverage to Coveralls
# Upload coverage if we are on the main repository and
# we're running on Linux (this action only supports Linux)
if:
github.repository == 'psf/black' && matrix.os == 'ubuntu-latest' &&
!startsWith(matrix.python-version, 'pypy')
uses: AndreMiras/coveralls-python-action@ac868b9540fad490f7ca82b8ca00480fd751ed19
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
parallel: true
flag-name: py${{ matrix.python-version }}-${{ matrix.os }}
debug: true
coveralls-finish:
needs: test
if: github.repository == 'psf/black'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Send finished signal to Coveralls
uses: AndreMiras/coveralls-python-action@ac868b9540fad490f7ca82b8ca00480fd751ed19
with:
parallel-finished: true
debug: true
uvloop:
if:
github.event_name == 'push' || github.event.pull_request.head.repo.full_name !=
github.repository
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macOS-latest, windows-latest, windows-11-arm]
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
pip-version: "25.3"
pip-install: -e .[uvloop]
- name: Format ourselves
run: python -m black --check .
+25
View File
@@ -0,0 +1,25 @@
name: zizmor
on:
push:
branches: ["main"]
paths: ["**.yml"]
pull_request:
paths: ["**.yml"]
permissions: {}
jobs:
zizmor:
name: zizmor
runs-on: ubuntu-latest
permissions:
security-events: write # Required for upload-sarif (used by zizmor-action) to upload SARIF files.
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Run zizmor
uses: zizmorcore/zizmor-action@192e21d79ab29983730a13d1382995c2307fbcaa # v0.5.7