mirror of
https://github.com/huggingface/diffusers.git
synced 2026-10-24 20:59:27 +03:00
A tag is mutable: whoever controls the action's repository can move `v4` to different code, and the next run picks it up with no diff to review. Pinning to the commit SHA freezes the code that runs today. Co-authored-by: hf-security-analysis[bot] <265538906+hf-security-analysis[bot]@users.noreply.github.com>
151 lines
5.8 KiB
YAML
151 lines
5.8 KiB
YAML
name: "Bot: Pytest"
|
|
|
|
# Reusable workflow called by diffusers_bot.yml for `/diffusers-bot pytest <args>`.
|
|
# Runs pytest on a GPU runner and reports the result back on the PR.
|
|
|
|
on:
|
|
workflow_call:
|
|
inputs:
|
|
pytest_args:
|
|
required: true
|
|
type: string
|
|
|
|
jobs:
|
|
gate:
|
|
name: Acknowledge
|
|
runs-on: ubuntu-22.04
|
|
permissions:
|
|
pull-requests: write
|
|
outputs:
|
|
comment_id: ${{ steps.comment.outputs.comment_id }}
|
|
steps:
|
|
- name: Acknowledge with 👀
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
REPO: ${{ github.repository }}
|
|
COMMENT_ID: ${{ github.event.comment.id }}
|
|
run: |
|
|
gh api -X POST "repos/${REPO}/issues/comments/${COMMENT_ID}/reactions" -f content="eyes" >/dev/null
|
|
|
|
- name: Post "running" comment
|
|
id: comment
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
REPO: ${{ github.repository }}
|
|
PR: ${{ github.event.issue.number }}
|
|
COMMENTER: ${{ github.event.comment.user.login }}
|
|
PYTEST_ARGS: ${{ inputs.pytest_args }}
|
|
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
|
run: |
|
|
BODY="⏳ Running \`pytest ${PYTEST_ARGS}\` on a GPU runner — [view logs](${RUN_URL}).
|
|
|
|
Triggered by @${COMMENTER}."
|
|
CID=$(gh api -X POST "repos/${REPO}/issues/${PR}/comments" -f body="$BODY" --jq '.id')
|
|
echo "comment_id=${CID}" >> "$GITHUB_OUTPUT"
|
|
|
|
gpu:
|
|
name: Run pytest on GPU
|
|
needs: gate
|
|
# A newer command on the same PR supersedes an in-flight one. Scoped to this job
|
|
# only so the superseded run's `report` still updates its comment.
|
|
concurrency:
|
|
group: diffusers-bot-pytest-${{ github.event.issue.number }}
|
|
cancel-in-progress: true
|
|
runs-on:
|
|
group: aws-g4dn-2xlarge
|
|
container:
|
|
image: diffusers/diffusers-pytorch-cuda
|
|
options: --gpus all --shm-size "16gb" --ipc host
|
|
# Least privilege: this job checks out and runs untrusted fork code, so it gets no
|
|
# write token. Comment writes happen only in `gate`/`report`.
|
|
permissions:
|
|
contents: read
|
|
env:
|
|
DIFFUSERS_IS_CI: yes
|
|
OMP_NUM_THREADS: 8
|
|
MKL_NUM_THREADS: 8
|
|
HF_XET_HIGH_PERFORMANCE: 1
|
|
PYTEST_TIMEOUT: 600
|
|
# Force version overrides across every `uv pip install`: pin the
|
|
# torch/torchvision/torchaudio set baked into the image so `-U` installs can't bump
|
|
# torch and break torchvision's C++ ABI. Re-written into the file in the install step.
|
|
UV_OVERRIDE: /tmp/uv-overrides.txt
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
steps:
|
|
- name: Checkout PR head
|
|
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
|
|
with:
|
|
# Works for forks too — no fork credentials needed.
|
|
ref: refs/pull/${{ github.event.issue.number }}/head
|
|
fetch-depth: 2
|
|
|
|
- name: NVIDIA-SMI
|
|
run: nvidia-smi
|
|
|
|
- name: Install dependencies
|
|
run: |
|
|
printf 'torch==2.10.0\ntorchvision==0.25.0\ntorchaudio==2.10.0\n' > "$UV_OVERRIDE"
|
|
uv pip install -e ".[quality,training,test]"
|
|
uv pip install peft@git+https://github.com/huggingface/peft.git
|
|
uv pip uninstall accelerate && uv pip install -U accelerate@git+https://github.com/huggingface/accelerate.git
|
|
uv pip uninstall transformers huggingface_hub && UV_PRERELEASE=allow uv pip install -U transformers@git+https://github.com/huggingface/transformers.git
|
|
|
|
- name: Environment
|
|
run: diffusers-cli env
|
|
|
|
- name: Run pytest
|
|
env:
|
|
# No secrets here: this step runs untrusted fork code (pytest imports the PR's
|
|
# conftest.py/plugins), so exposing a token would let a malicious PR exfiltrate
|
|
# it. Public Hub models download without auth; gated-repo tests are unsupported.
|
|
# https://pytorch.org/docs/stable/notes/randomness.html#avoiding-nondeterministic-algorithms
|
|
CUBLAS_WORKSPACE_CONFIG: :16:8
|
|
# Forwarded via env (not interpolated into the script) to avoid breakage on
|
|
# quotes/special characters in a legitimate command.
|
|
PYTEST_ARGS: ${{ inputs.pytest_args }}
|
|
run: |
|
|
eval "pytest --make-reports=tests_bot_gpu $PYTEST_ARGS"
|
|
|
|
- name: Failure short reports
|
|
if: ${{ failure() }}
|
|
run: |
|
|
cat reports/tests_bot_gpu_stats.txt || true
|
|
cat reports/tests_bot_gpu_failures_short.txt || true
|
|
|
|
- name: Test suite reports artifacts
|
|
if: ${{ always() }}
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
|
with:
|
|
name: bot_gpu_test_reports
|
|
path: reports
|
|
|
|
report:
|
|
name: Report status
|
|
needs: [gate, gpu]
|
|
# Always run so the comment is updated on success, failure, or cancellation —
|
|
# but only if `gate` actually posted a comment to update.
|
|
if: ${{ always() && needs.gate.outputs.comment_id != '' }}
|
|
runs-on: ubuntu-22.04
|
|
permissions:
|
|
pull-requests: write
|
|
steps:
|
|
- name: Update comment with final status
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
REPO: ${{ github.repository }}
|
|
CID: ${{ needs.gate.outputs.comment_id }}
|
|
RESULT: ${{ needs.gpu.result }}
|
|
PYTEST_ARGS: ${{ inputs.pytest_args }}
|
|
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
|
run: |
|
|
case "$RESULT" in
|
|
success) EMOJI="✅"; MSG="passed";;
|
|
failure) EMOJI="❌"; MSG="failed";;
|
|
cancelled) EMOJI="⚠️"; MSG="was cancelled";;
|
|
*) EMOJI="⚠️"; MSG="did not run (${RESULT})";;
|
|
esac
|
|
BODY="${EMOJI} \`pytest ${PYTEST_ARGS}\` ${MSG} on GPU — [view logs](${RUN_URL})."
|
|
gh api -X PATCH "repos/${REPO}/issues/comments/${CID}" -f body="$BODY"
|