| name: PR comment GitHub CI |
|
|
| on: |
| issue_comment: |
| types: |
| - created |
| branches-ignore: |
| - main |
| concurrency: |
| group: ${{ github.workflow }}-${{ github.event.issue.number }}-${{ startsWith(github.event.comment.body, 'run-slow') || startsWith(github.event.comment.body, 'run slow') || startsWith(github.event.comment.body, 'run_slow') }} |
| cancel-in-progress: true |
| permissions: read-all |
|
|
| env: |
| HF_HOME: /mnt/cache |
| TRANSFORMERS_IS_CI: yes |
| OMP_NUM_THREADS: 8 |
| MKL_NUM_THREADS: 8 |
| RUN_SLOW: yes |
| |
| |
| HF_TOKEN: ${{ secrets.HF_HUB_READ_TOKEN }} |
| TF_FORCE_GPU_ALLOW_GROWTH: true |
| CUDA_VISIBLE_DEVICES: 0,1 |
|
|
|
|
| jobs: |
| get-pr-number: |
| name: Get PR number |
| if: ${{ github.event.issue.state == 'open' && contains(fromJSON('["ydshieh", "ArthurZucker", "zucchini-nlp", "molbap", "gante", "LysandreJik", "Cyrilvallez", "Rocketknight1", "SunMarc", "eustlb", "MekkCyber", "vasqu", "ivarflakstad", "stevhliu", "ebezzam", "remi-or", "itazap", "3outeille", "IlyasMoutawwakil"]'), github.actor) && (startsWith(github.event.comment.body, 'run-slow') || startsWith(github.event.comment.body, 'run slow') || startsWith(github.event.comment.body, 'run_slow')) }} |
| uses: ./.github/workflows/get-pr-number.yml |
|
|
| get-pr-info: |
| name: Get PR commit SHA |
| needs: get-pr-number |
| if: ${{ needs.get-pr-number.outputs.PR_NUMBER != ''}} |
| uses: ./.github/workflows/get-pr-info.yml |
| with: |
| pr_number: ${{ needs.get-pr-number.outputs.PR_NUMBER }} |
|
|
| check-timestamps: |
| name: Check timestamps (security check) |
| runs-on: ubuntu-22.04 |
| needs: get-pr-info |
| outputs: |
| PR_HEAD_SHA: ${{ needs.get-pr-info.outputs.PR_HEAD_SHA }} |
| PR_MERGE_SHA: ${{ needs.get-pr-info.outputs.PR_MERGE_COMMIT_SHA }} |
| steps: |
| - name: Verify `merge_commit` timestamp is older than the issue comment timestamp |
| env: |
| COMMENT_DATE: ${{ github.event.comment.created_at }} |
| PR_MERGE_COMMIT_TIMESTAMP: ${{ needs.get-pr-info.outputs.PR_MERGE_COMMIT_TIMESTAMP }} |
| run: | |
| COMMENT_TIMESTAMP=$(date -d "${COMMENT_DATE}" +"%s") |
| echo "COMMENT_DATE: $COMMENT_DATE" |
| echo "COMMENT_TIMESTAMP: $COMMENT_TIMESTAMP" |
| if [ $COMMENT_TIMESTAMP -le $PR_MERGE_COMMIT_TIMESTAMP ]; then |
| echo "Last commit on the pull request is newer than the issue comment triggering this run! Abort!"; |
| exit -1; |
| fi |
| |
| |
| get-tests: |
| runs-on: ubuntu-22.04 |
| needs: [get-pr-number, check-timestamps] |
| outputs: |
| models: ${{ steps.models_to_run.outputs.models }} |
| quantizations: ${{ steps.models_to_run.outputs.quantizations }} |
| steps: |
| - uses: actions/checkout@v4 |
| with: |
| fetch-depth: "0" |
| ref: "refs/pull/${{ needs.get-pr-number.outputs.PR_NUMBER }}/merge" |
|
|
| - name: Verify merge commit SHA |
| env: |
| VERIFIED_PR_MERGE_SHA: ${{ needs.check-timestamps.outputs.PR_MERGE_SHA }} |
| run: | |
| PR_MERGE_SHA=$(git log -1 --format=%H) |
| if [ $PR_MERGE_SHA != $VERIFIED_PR_MERGE_SHA ]; then |
| echo "The merged commit SHA is not the same as the verified one! Security issue detected, abort the workflow!"; |
| exit -1; |
| fi |
| |
| - name: Get models to test |
| env: |
| PR_COMMENT: ${{ github.event.comment.body }} |
| run: | |
| python -m pip install GitPython |
| python utils/pr_slow_ci_models.py --message "$PR_COMMENT" | tee output.txt |
| echo "models=$(tail -n 1 output.txt)" >> $GITHUB_ENV |
| python utils/pr_slow_ci_models.py --message "$PR_COMMENT" --quantization | tee output2.txt |
| echo "quantizations=$(tail -n 1 output2.txt)" >> $GITHUB_ENV |
| |
| - name: Show models to test |
| id: models_to_run |
| run: | |
| echo "$models" |
| echo "models=$models" >> $GITHUB_OUTPUT |
| echo "$quantizations" |
| echo "quantizations=$quantizations" >> $GITHUB_OUTPUT |
| |
| |
| report_error_earlier: |
| name: Report error earlier |
| if: ${{ always() && needs.get-pr-info.result == 'success' && needs.get-tests.result != 'success' }} |
| needs: [get-pr-number, get-pr-info, get-tests] |
| permissions: |
| pull-requests: write |
| runs-on: ubuntu-22.04 |
| steps: |
| - name: Reply to the comment |
| env: |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| GITHUB_RUN_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} |
| github_repository: ${{ github.repository }} |
| pr_number: ${{ needs.get-pr-number.outputs.PR_NUMBER }} |
| run: | |
| gh api \ |
| --method POST \ |
| -H "Accept: application/vnd.github+json" \ |
| -H "X-GitHub-Api-Version: 2022-11-28" \ |
| "repos/${github_repository}/issues/${pr_number}/comments" \ |
| -f body="💔 This comment contains \`run-slow\`, but unknown error occurred and [the workflow run]($GITHUB_RUN_URL) aborted!" |
| |
| reply_to_comment: |
| name: Reply to the comment |
| if: ${{ needs.get-tests.outputs.models != '[]' || needs.get-tests.outputs.quantizations != '[]' }} |
| needs: [get-pr-number, get-tests] |
| permissions: |
| pull-requests: write |
| runs-on: ubuntu-22.04 |
| steps: |
| - name: Reply to the comment |
| env: |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| BODY: '\n\nmodels: ${{ needs.get-tests.outputs.models }}\nquantizations: ${{ needs.get-tests.outputs.quantizations }}' |
| github_repository: ${{ github.repository }} |
| pr_number: ${{ needs.get-pr-number.outputs.PR_NUMBER }} |
| run: | |
| gh api \ |
| --method POST \ |
| -H "Accept: application/vnd.github+json" \ |
| -H "X-GitHub-Api-Version: 2022-11-28" \ |
| "repos/${github_repository}/issues/${pr_number}/comments" \ |
| -f body="This comment contains \`run-slow\`, running the specified jobs: $(echo -e "$BODY")" |
| |
| create_run: |
| name: Create run |
| needs: [check-timestamps, reply_to_comment] |
| permissions: |
| statuses: write |
| runs-on: ubuntu-22.04 |
| steps: |
| - name: Create Run |
| id: create_run |
| env: |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| |
| |
| GITHUB_RUN_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} |
| github_repository: ${{ github.repository }} |
| pr_head_sha: ${{ needs.check-timestamps.outputs.PR_HEAD_SHA }} |
| run: | |
| gh api \ |
| --method POST \ |
| -H "Accept: application/vnd.github+json" \ |
| -H "X-GitHub-Api-Version: 2022-11-28" \ |
| "repos/${github_repository}/statuses/${pr_head_sha}" \ |
| -f "target_url=$GITHUB_RUN_URL" -f "state=pending" -f "description=Slow CI job" -f "context=pytest/custom-tests" |
| |
| model-ci: |
| name: Model CI |
| if: ${{ needs.get-tests.outputs.models != '[]' }} |
| uses: ./.github/workflows/self-scheduled.yml |
| needs: [get-pr-number, check-timestamps, get-tests, create_run] |
| with: |
| job: run_models_gpu |
| slack_report_channel: "#transformers-ci-pr" |
| docker: huggingface/transformers-all-latest-gpu |
| ci_event: PR Comment CI |
| report_repo_id: hf-internal-testing/transformers_pr_ci |
| commit_sha: ${{ needs.check-timestamps.outputs.PR_MERGE_SHA }} |
| subdirs: ${{ needs.get-tests.outputs.models }} |
| pr_number: ${{ needs.get-pr-number.outputs.PR_NUMBER }} |
| secrets: inherit |
|
|
| quantization-ci: |
| name: Quantization CI |
| if: ${{ needs.get-tests.outputs.quantizations != '[]' }} |
| uses: ./.github/workflows/self-scheduled.yml |
| needs: [get-pr-number, check-timestamps, get-tests, create_run] |
| with: |
| job: run_quantization_torch_gpu |
| slack_report_channel: "#transformers-ci-pr" |
| docker: huggingface/transformers-quantization-latest-gpu |
| ci_event: PR Comment CI |
| report_repo_id: hf-internal-testing/transformers_pr_ci |
| commit_sha: ${{ needs.check-timestamps.outputs.PR_MERGE_SHA }} |
| subdirs: ${{ needs.get-tests.outputs.quantizations }} |
| pr_number: ${{ needs.get-pr-number.outputs.PR_NUMBER }} |
| secrets: inherit |
|
|
| report: |
| name: Check & Report |
| needs: [get-pr-number, check-timestamps, create_run, model-ci, quantization-ci] |
| permissions: |
| pull-requests: write |
| statuses: write |
| if: ${{ always() && needs.create_run.result == 'success' }} |
| runs-on: ubuntu-22.04 |
| steps: |
| - name: Show reports from jobs |
| env: |
| MODEL_REPORT: ${{ needs.model-ci.outputs.report }} |
| QUANT_REPORT: ${{ needs.quantization-ci.outputs.report }} |
| run: | |
| echo "$MODEL_REPORT" |
| echo "$QUANT_REPORT" |
| |
| - name: Process and filter reports |
| env: |
| MODEL_REPORT: ${{ needs.model-ci.outputs.report }} |
| QUANT_REPORT: ${{ needs.quantization-ci.outputs.report }} |
| run: | |
| # Preprocess with Python |
| python3 << 'PYTHON_SCRIPT' |
| import json |
| import os |
| |
| def filter_and_format_report(data): |
| """ |
| Filter out entries where commit is `None` (failing tests who status is not certain) and format as text |
| """ |
| lines = [] |
| |
| for model, model_result in data.items(): |
| model_lines = [] |
| for device, failures in model_result.items(): |
| |
| |
| test_names = [ |
| failure['test'] |
| for failure in failures |
| if isinstance(failure, dict) and failure.get('commit') is not None |
| ] |
|
|
| |
| for idx, test_name in enumerate(test_names): |
| if idx == 0: |
| job_link = failures[idx]['job_link'] |
| model_lines.append(f"- [{model}]({job_link}):") |
| |
| model_lines.append(f" {test_name}") |
| |
| # Only add model section if it has tests |
| if len(model_lines) > 0: |
| lines.extend(model_lines) |
| lines.append("") # Empty line between models |
| |
| return "\n".join(lines).strip() |
| |
| |
| model_report_str = os.environ.get('MODEL_REPORT', '{}') |
| quant_report_str = os.environ.get('QUANT_REPORT', '{}') |
| |
| model_report = json.loads(model_report_str) if model_report_str else {} |
| quant_report = json.loads(quant_report_str) if quant_report_str else {} |
| |
| formatted_model = filter_and_format_report(model_report) |
| formatted_quant = filter_and_format_report(quant_report) |
| |
| |
| with open('model_ci.txt', 'w') as f: |
| f.write(formatted_model) |
| if formatted_model: |
| f.write('\n') |
| |
| with open('quantization_ci.txt', 'w') as f: |
| f.write(formatted_quant) |
| if formatted_quant: |
| f.write('\n') |
| PYTHON_SCRIPT |
|
|
| - name: Post results as PR comment |
| env: |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| GITHUB_RUN_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} |
| github_repository: ${{ github.repository }} |
| pr_number: ${{ needs.get-pr-number.outputs.PR_NUMBER }} |
| model_ci_result: ${{ needs.model-ci.result }} |
| quantization_ci_result: ${{ needs.quantization-ci.result }} |
| run: | |
| { |
| echo '## CI Results' |
| echo "[Workflow Run ⚙️]($GITHUB_RUN_URL)" |
| echo '' |
| |
| |
| if [[ "$model_ci_result" == "skipped" || "$model_ci_result" == "cancelled" ]] && \ |
| [[ "$quantization_ci_result" == "skipped" || "$quantization_ci_result" == "cancelled" ]]; then |
| echo '⚠️ No test being reported (jobs are skipped or cancelled)!' |
| echo "STATUS=error" >> $GITHUB_ENV |
|
|
| |
| elif [ -s model_ci.txt ] || [ -s quantization_ci.txt ]; then |
| echo "STATUS=failure" >> $GITHUB_ENV |
|
|
| |
| if [ -s model_ci.txt ]; then |
| echo '### Model CI Report' |
| echo '' |
| echo '#### ❌ Failed tests' |
| echo '' |
| cat model_ci.txt |
| echo '' |
| fi |
| |
| |
| if [ -s quantization_ci.txt ]; then |
| echo '### Quantization CI Report' |
| echo '' |
| echo '#### ❌ Failed tests' |
| echo '' |
| cat quantization_ci.txt |
| echo '' |
| fi |
| else |
| echo "STATUS=success" >> $GITHUB_ENV |
| echo '✅ No failing test specific to this PR 🎉 !' |
| fi |
| } > comment_body.txt |
|
|
| gh api \ |
| --method POST \ |
| -H "Accept: application/vnd.github+json" \ |
| -H "X-GitHub-Api-Version: 2022-11-28" \ |
| "repos/${github_repository}/issues/${pr_number}/comments" \ |
| -F body=@comment_body.txt |
|
|
| - name: Update PR commit statuses |
| env: |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| GITHUB_RUN_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} |
| github_repository: ${{ github.repository }} |
| pr_head_sha: ${{ needs.check-timestamps.outputs.PR_HEAD_SHA }} |
| |
| run: | |
| gh api \ |
| --method POST \ |
| -H "Accept: application/vnd.github+json" \ |
| -H "X-GitHub-Api-Version: 2022-11-28" \ |
| "repos/${github_repository}/statuses/${pr_head_sha}" \ |
| -f "target_url=$GITHUB_RUN_URL" -f "state=$STATUS" -f "description=Slow CI job" -f "context=pytest/custom-tests" |
| |