Files
actions/action.yml
T
Glenn JocherandUltralyticsAssistant 59069122fd Automatic PR reviews (#562)
Signed-off-by: Glenn Jocher <[email protected]>
Co-authored-by: UltralyticsAssistant <[email protected]>
2025-10-21 01:51:02 +02:00

310 lines
13 KiB
YAML

# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
name: "Ultralytics Actions"
author: "Ultralytics"
description: "Optimize code and docs with official Ultralytics Actions for syntax, spelling, and link checks."
branding:
icon: "code"
color: "blue"
inputs:
token:
description: "GitHub token"
required: true
labels:
description: "Run issue and PR auto-labeling"
required: false
default: "false"
python:
description: "Run Python formatting"
required: false
default: "false"
markdown:
description: "Run Markdown formatting (deprecated in favor of prettier)"
required: false
default: "false"
prettier:
description: "Run Prettier formatting for JavaScript, JSX, Angular, Vue, Flow, TypeScript, CSS, HTML, JSON, GraphQL, Markdown, YAML"
required: false
default: "false"
swift:
description: "Run Swift formatting"
required: false
default: "false"
dart:
description: "Run Dart formatting"
required: false
default: "false"
spelling:
description: "Run Spelling checks"
required: false
default: "false"
links:
description: "Run Broken Links checks"
required: false
default: "false"
summary:
description: "Run PR Summary"
required: false
default: "false"
review:
description: "Run PR Review"
required: false
default: "true"
header:
description: "File header"
required: false
default: ""
brave_api_key:
description: "Brave API Key"
required: false
openai_api_key:
description: "OpenAI API Key"
required: false
openai_model:
description: "OpenAI Model"
required: false
default: "gpt-5-2025-08-07"
first_issue_response:
description: "Example response to a new issue"
required: false
first_pr_response:
description: "Example response to a new PR"
required: false
github_username:
description: "GitHub username for commits"
required: false
default: "UltralyticsAssistant"
# default: "github-actions[bot]"
github_email:
description: "GitHub email for commits"
required: false
default: "[email protected]"
# default: "41898282+github-actions[bot]@users.noreply.github.com"
runs:
using: "composite"
steps:
- uses: astral-sh/setup-uv@v7
with:
ignore-empty-workdir: true
enable-cache: false
version: "0.9.4"
- name: Install Dependencies
# Note tomli required for codespell with pyproject.toml
env:
INPUTS_SPELLING: ${{ inputs.spelling }}
run: |
# For debug
# sudo env "PATH=$PATH" uv pip install --system --break-system-packages git+https://github.com/ultralytics/actions@main codespell tomli
packages="ultralytics-actions"
if [ "$INPUTS_SPELLING" = "true" ]; then
packages="$packages codespell tomli"
fi
# On macOS, don't use sudo as it can cause environment issues
if [ "$(uname)" = "Darwin" ]; then
uv pip install --system --break-system-packages $packages
else
sudo env "PATH=$PATH" uv pip install --system --break-system-packages $packages
fi
ultralytics-actions-info
shell: bash
# Checkout Repository ----------------------------------------------------------------------------------------------
- name: Checkout Repository
if: github.event.action == 'opened' || github.event.action == 'synchronize'
uses: actions/checkout@v5
with:
repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
token: ${{ inputs.token }}
ref: ${{ github.head_ref || github.ref }}
fetch-depth: 1
# PR Summary -------------------------------------------------------------------------------------------------------
- name: PR Summary
if: (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') && inputs.summary == 'true' && github.event.action != 'synchronize' && github.event.action != 'review_requested'
env:
GITHUB_TOKEN: ${{ inputs.token }}
BRAVE_API_KEY: ${{ inputs.brave_api_key }}
OPENAI_API_KEY: ${{ inputs.openai_api_key }}
OPENAI_MODEL: ${{ inputs.openai_model }}
run: |
ultralytics-actions-summarize-pr
shell: bash
continue-on-error: true
# File header ------------------------------------------------------------------------------------------------------
- name: File Header
if: (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') && (github.event.action == 'opened' || github.event.action == 'synchronize')
env:
HEADER: ${{ inputs.header }}
run: |
ultralytics-actions-headers
shell: bash
continue-on-error: false
# Python formatting ------------------------------------------------------------------------------------------------
# Ignores the following Docs rules to match Google-style docstrings:
# D100: Missing docstring in public module
# D104: Missing docstring in public package
# D203: 1 blank line required before class docstring
# D205: 1 blank line required between summary line and description
# D212: Multi-line docstring summary should start at the first line
# D213: Multi-line docstring summary should start at the second line
# D401: First line of docstring should be in imperative mood
# D406: Section name should end with a newline
# D407: Missing dashed underline after section
# D413: Missing blank line after last section
# --target-version is Python 3.9 for --extend-select UP (pyupgrade)
- name: Run Python
if: (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') && inputs.python == 'true' && (github.event.action == 'opened' || github.event.action == 'synchronize')
run: |
ruff check \
--fix \
--unsafe-fixes \
--extend-select I,D,UP \
--target-version py39 \
--ignore D100,D104,D203,D205,D212,D213,D401,D406,D407,D413 \
. || true
ruff format \
--line-length 120 \
. || true
docformatter \
--wrap-summaries 120 \
--wrap-descriptions 120 \
--pre-summary-newline \
--close-quotes-on-newline \
--in-place \
--recursive \
.
shell: bash
continue-on-error: true
# Prettier (JavaScript, JSX, Angular, Vue, Flow, TypeScript, CSS, HTML, JSON, GraphQL, Markdown, YAML) -------------
- name: Run Prettier
if: (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') && (inputs.prettier == 'true' || inputs.markdown == 'true') && (github.event.action == 'opened' || github.event.action == 'synchronize')
run: |
npm install --global [email protected] prettier-plugin-sh
ultralytics-actions-update-markdown-code-blocks
npx prettier --write --list-different "**/*.{js,jsx,ts,tsx,css,less,scss,json,yml,yaml,html,vue,svelte}" '!**/*lock.{json,yaml,yml}' '!**/*.lock' '!**/model.json'
# Bash file format
if find . -name "*.sh" -type f | grep -q .; then
npx prettier --write --list-different --plugin=$(npm root -g)/prettier-plugin-sh/lib/index.cjs "**/*.sh"
fi
# Handle Markdown separately
find . -name "*.md" ! -path "*/docs/*" -exec npx prettier --write --list-different {} +
if [ -d "./docs" ]; then
find ./docs -name "*.md" ! -path "*/reference/*" -exec npx prettier --tab-width 4 --write --list-different {} +
fi
shell: bash
continue-on-error: true
# Swift formatting -------------------------------------------------------------------------------------------------
- name: Run Swift Formatter
if: (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') && inputs.swift == 'true' && (github.event.action == 'opened' || github.event.action == 'synchronize')
run: |
brew install swift-format
swift-format --in-place --recursive .
shell: bash
continue-on-error: true
# Dart formatting --------------------------------------------------------------------------------------------------
- name: Setup Dart SDK
if: (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') && inputs.dart == 'true' && (github.event.action == 'opened' || github.event.action == 'synchronize')
uses: dart-lang/setup-dart@v1
with:
sdk: stable
- name: Run Dart Formatter
if: (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') && inputs.dart == 'true' && (github.event.action == 'opened' || github.event.action == 'synchronize')
run: |
dart format .
shell: bash
continue-on-error: true # Important so that commit step can pick up changes
# Spelling ---------------------------------------------------------------------------------------------------------
- name: Run Codespell
if: (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') && inputs.spelling == 'true' && (github.event.action == 'opened' || github.event.action == 'synchronize')
run: |
codespell \
--write-changes \
--uri-ignore-words-list * \
--ignore-words-list "finalY,RepResNet,Idenfy,WIT,Smoot,EHR,ROUGE,ALS,iTerm,Carmel,FPR,Hach,Calle,ore,COO,MOT,crate,nd,ned,strack,dota,ane,segway,fo,gool,winn,commend,bloc,nam,afterall,skelton,goin" \
--skip "*.pt,*.pth,*.torchscript,*.onnx,*.tflite,*.pb,*.bin,*.param,*.mlmodel,*.engine,*.npy,*.data*,*.csv,*pnnx*,*venv*,*translat*,*lock*,__pycache__*,*.ico,*.jpg,*.png,*.mp4,*.mov,/runs,/.git,./docs/??/*.md,./docs/mkdocs_??.yml"
shell: bash
continue-on-error: true
# Autolabel Issues and PRs (labels and first interaction) ---------------------------------------------------------
- name: Autolabel Issues and PRs
if: inputs.labels == 'true' && (github.event.action == 'opened' || github.event.action == 'created')
env:
GITHUB_TOKEN: ${{ inputs.token }}
FIRST_ISSUE_RESPONSE: ${{ inputs.first_issue_response }}
FIRST_PR_RESPONSE: ${{ inputs.first_pr_response }}
BRAVE_API_KEY: ${{ inputs.brave_api_key }}
OPENAI_API_KEY: ${{ inputs.openai_api_key }}
OPENAI_MODEL: ${{ inputs.openai_model }}
REVIEW: ${{ inputs.review }}
run: |
ultralytics-actions-first-interaction
shell: bash
continue-on-error: true
# PR Review --------------------------------------------------------------------------------------------------------
- name: PR Review
if: |
(github.event_name == 'pull_request' || github.event_name == 'pull_request_target') &&
github.event.action == 'review_requested' &&
github.event.requested_reviewer.login == inputs.github_username
env:
GITHUB_TOKEN: ${{ inputs.token }}
OPENAI_API_KEY: ${{ inputs.openai_api_key }}
OPENAI_MODEL: ${{ inputs.openai_model }}
run: |
ultralytics-actions-review-pr
shell: bash
continue-on-error: true
# Commit Changes ---------------------------------------------------------------------------------------------------
- name: Commit and Push Changes
if: (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') && (github.event.action == 'opened' || github.event.action == 'synchronize')
env:
GITHUB_USERNAME: ${{ inputs.github_username }}
GITHUB_EMAIL: ${{ inputs.github_email }}
run: |
git config --global user.name "$GITHUB_USERNAME"
git config --global user.email "$GITHUB_EMAIL"
git add .
git reset HEAD -- .github/workflows/ # workflow changes are not permitted with default token
if ! git diff --staged --quiet; then
git commit -m "Auto-format by https://ultralytics.com/actions"
git push
else
echo "No changes to commit"
fi
shell: bash
continue-on-error: true
# Broken links -----------------------------------------------------------------------------------------------------
- name: Broken Link Checker
if: inputs.links == 'true' && github.event.action != 'closed'
uses: lycheeverse/[email protected]
with:
# Check all markdown and html files in repo. Ignores the following status codes to reduce false positives:
# - 403(OpenVINO, "forbidden")
# - 429(Instagram, "too many requests")
# - 500(Zenodo, "cached")
# - 502(Zenodo, "bad gateway")
# - 999(LinkedIn, "unknown status code")
args: |
--scheme https
--timeout 60
--insecure
--accept 100..=103,200..=299,401,403,429,500,502,999
--exclude-all-private
--exclude "https?://(www\.)?(github\.com|linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)"
"./**/*.md"
"./**/*.html"
token: ${{ inputs.token }}
output: ../lychee/results.md
fail: true
continue-on-error: false