feat: initial HSAP platform

Huaxu Sentinel Active Safety Platform with embedded algorithm code,
Docker Compose setup, and vendored dataset scaffolds for clone-and-run.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-25 16:59:59 +08:00
commit 7c43b44c57
1619 changed files with 373355 additions and 0 deletions

View File

@@ -0,0 +1,527 @@
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
# Ultralytics YOLO Continuous Integration (CI) GitHub Actions tests
name: CI
permissions:
contents: read
env:
PYTHONFAULTHANDLER: 1
on:
push:
branches: [main]
pull_request:
schedule:
- cron: "0 8 * * *" # runs at 08:00 UTC every day
workflow_dispatch:
inputs:
hub:
description: "Run HUB"
default: true
type: boolean
benchmarks:
description: "Run Benchmarks"
default: true
type: boolean
tests:
description: "Run Tests"
default: true
type: boolean
gpu:
description: "Run GPU"
default: true
type: boolean
raspberrypi:
description: "Run Raspberry Pi"
default: true
type: boolean
nvidia-jetson:
description: "Run NVIDIA Jetson"
default: true
type: boolean
conda:
description: "Run Conda"
default: true
type: boolean
jobs:
HUB:
if: github.repository == 'ultralytics/ultralytics' && (github.event_name == 'schedule' || github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.event.inputs.hub == 'true'))
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
python: ["3.12"]
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python }}
- uses: astral-sh/setup-uv@v7
- name: Install requirements
shell: bash # for Windows compatibility
run: |
uv pip install --system . --extra-index-url https://download.pytorch.org/whl/cpu
- name: Check environment
run: |
yolo checks
uv pip list
- name: Test HUB training
shell: python
env:
API_KEY: ${{ secrets.ULTRALYTICS_HUB_API_KEY }}
MODEL_ID: ${{ secrets.ULTRALYTICS_HUB_MODEL_ID }}
run: |
import os
from ultralytics import YOLO, hub
api_key, model_id = os.environ['API_KEY'], os.environ['MODEL_ID']
hub.login(api_key)
hub.reset_model(model_id)
model = YOLO('https://hub.ultralytics.com/models/' + model_id)
model.train()
- name: Test HUB inference API
shell: python
env:
API_KEY: ${{ secrets.ULTRALYTICS_HUB_API_KEY }}
MODEL_ID: ${{ secrets.ULTRALYTICS_HUB_MODEL_ID }}
run: |
import os
import requests
import json
api_key, model_id = os.environ['API_KEY'], os.environ['MODEL_ID']
url = f"https://api.ultralytics.com/v1/predict/{model_id}"
headers = {"x-api-key": api_key}
data = {"size": 320, "confidence": 0.25, "iou": 0.45}
with open("ultralytics/assets/zidane.jpg", "rb") as f:
response = requests.post(url, headers=headers, data=data, files={"image": f})
assert response.status_code == 200, f'Status code {response.status_code}, Reason {response.reason}'
print(json.dumps(response.json(), indent=2))
Benchmarks:
if: github.event_name != 'workflow_dispatch' || github.event.inputs.benchmarks == 'true'
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
# Temporarily disable windows-latest due to https://github.com/ultralytics/ultralytics/actions/runs/13020330819/job/36319338854?pr=18921
os: [ubuntu-latest, macos-26, ubuntu-24.04-arm]
python: ["3.12"]
model: [yolo26n]
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python }}
- uses: astral-sh/setup-uv@v7
- name: Install requirements
shell: bash # for Windows compatibility
run: |
uv pip install --system -e ".[export]" "coverage[toml]" --extra-index-url https://download.pytorch.org/whl/cpu --index-strategy unsafe-best-match
- name: Check environment
run: |
yolo checks
uv pip list
- name: Benchmark DetectionModel
shell: bash
run: coverage run -a --source=ultralytics -m ultralytics.cfg.__init__ benchmark model='path with spaces/${{ matrix.model }}.pt' imgsz=160 verbose=0.218
- name: Benchmark ClassificationModel
shell: bash
run: coverage run -a --source=ultralytics -m ultralytics.cfg.__init__ benchmark model='path with spaces/${{ matrix.model }}-cls.pt' imgsz=160 verbose=0.249
- name: Benchmark YOLOWorld DetectionModel
shell: bash
run: coverage run -a --source=ultralytics -m ultralytics.cfg.__init__ benchmark model='path with spaces/yolov8s-worldv2.pt' imgsz=160 verbose=0.337
- name: Benchmark SegmentationModel
shell: bash
run: coverage run -a --source=ultralytics -m ultralytics.cfg.__init__ benchmark model='path with spaces/${{ matrix.model }}-seg.pt' imgsz=160 verbose=0.230
- name: Benchmark PoseModel
shell: bash
run: coverage run -a --source=ultralytics -m ultralytics.cfg.__init__ benchmark model='path with spaces/${{ matrix.model }}-pose.pt' imgsz=160 verbose=0.194
- name: Benchmark OBBModel
shell: bash
run: coverage run -a --source=ultralytics -m ultralytics.cfg.__init__ benchmark model='path with spaces/${{ matrix.model }}-obb.pt' imgsz=160 verbose=0.374
- name: Merge Coverage Reports
run: |
coverage xml -o coverage-benchmarks.xml
- name: Upload Coverage Reports to CodeCov
if: github.repository == 'ultralytics/ultralytics'
uses: codecov/codecov-action@v5
with:
flags: Benchmarks
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
- name: Prune uv Cache
run: uv cache prune --ci
- name: Benchmark Summary
run: |
cat benchmarks.log
echo '```' >> $GITHUB_STEP_SUMMARY
cat benchmarks.log >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
Tests:
if: github.event_name == 'pull_request' || github.event_name == 'push'
timeout-minutes: 60
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-26, windows-latest, ubuntu-24.04-arm]
python: ["3.12"]
torch: [latest]
include:
- os: ubuntu-latest
python: "3.8" # torch 1.8.0 requires python >=3.6, <=3.9
torch: "1.8.0"
torchvision: "0.9.0"
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python }}
- uses: astral-sh/setup-uv@v7
- name: Install requirements
shell: bash # for Windows compatibility
run: |
slow=""
torch=""
if [ "${{ matrix.torch }}" != "latest" ]; then
torch="torch==${{ matrix.torch }} torchvision==${{ matrix.torchvision }}"
fi
uv pip install --system -e ".[export,solutions]" $torch pytest-cov --extra-index-url https://download.pytorch.org/whl/cpu --index-strategy unsafe-best-match
- name: Check environment
run: |
yolo checks
uv pip list
- name: Pytest tests
shell: bash # for Windows compatibility
run: pytest --cov=ultralytics/ --cov-report=xml tests/
- name: Upload Coverage Reports to CodeCov
if: github.repository == 'ultralytics/ultralytics' # && matrix.os == 'ubuntu-latest' && matrix.python == '3.12'
uses: codecov/codecov-action@v5
with:
flags: Tests
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
- name: Prune uv Cache
run: uv cache prune --ci
SlowTests:
if: (github.event_name == 'workflow_dispatch' && github.event.inputs.tests == 'true') || github.event_name == 'schedule'
timeout-minutes: 360
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-26, windows-latest, ubuntu-24.04-arm]
python: ["3.12"]
torch: [latest]
include:
- os: ubuntu-latest
python: "3.8" # torch 1.8.0 requires python >=3.6, <=3.9
torch: "1.8.0"
torchvision: "0.9.0"
- os: ubuntu-latest
python: "3.9"
torch: "1.9.0"
torchvision: "0.10.0"
- os: ubuntu-latest
python: "3.9"
torch: "1.10.0"
torchvision: "0.11.0"
- os: ubuntu-latest
python: "3.10"
torch: "1.11.0"
torchvision: "0.12.0"
- os: ubuntu-latest
python: "3.10"
torch: "1.12.0"
torchvision: "0.13.0"
- os: ubuntu-latest
python: "3.10"
torch: "1.13.0"
torchvision: "0.14.0"
- os: ubuntu-latest # Axelera exports
python: "3.10"
torch: "2.8.0"
torchvision: "0.23.0"
- os: ubuntu-latest
python: "3.11"
torch: "2.0.0"
torchvision: "0.15.0"
- os: ubuntu-latest
python: "3.11"
torch: "2.1.0"
torchvision: "0.16.0"
- os: ubuntu-latest
python: "3.12"
torch: "2.2.0"
torchvision: "0.17.0"
- os: ubuntu-latest
python: "3.12"
torch: "2.3.0"
torchvision: "0.18.0"
- os: ubuntu-latest
python: "3.12"
torch: "2.4.0"
torchvision: "0.19.0"
- os: ubuntu-latest
python: "3.12"
torch: "2.5.0"
torchvision: "0.20.0"
- os: ubuntu-latest
python: "3.12"
torch: "2.6.0"
torchvision: "0.21.0"
- os: ubuntu-latest
python: "3.12"
torch: "2.7.0"
torchvision: "0.22.0"
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python }}
- uses: astral-sh/setup-uv@v7
- name: Install requirements
shell: bash # for Windows compatibility
run: |
torch=""
if [ "${{ matrix.torch }}" != "latest" ]; then
torch="torch==${{ matrix.torch }} torchvision==${{ matrix.torchvision }}"
fi
uv pip install --system -e ".[export,solutions]" $torch faster-coco-eval mlflow pytest-cov --extra-index-url https://download.pytorch.org/whl/cpu --index-strategy unsafe-best-match
- name: Check environment
run: |
yolo checks
uv pip list
- name: Pytest tests
uses: ultralytics/actions/retry@main
with:
shell: bash # for Windows compatibility
run: pytest --slow --cov=ultralytics/ --cov-report=xml tests/
retries: 1 # Retry once after initial attempt (2 total runs)
retry_delay_seconds: 60
- name: Prune uv Cache
run: uv cache prune --ci
GPU:
if: github.repository == 'ultralytics/ultralytics' && (github.event_name != 'workflow_dispatch' || github.event.inputs.gpu == 'true')
timeout-minutes: 60
runs-on: gpu-latest
steps:
- uses: actions/checkout@v6
- uses: astral-sh/setup-uv@v7
with:
activate-environment: true
- name: Install requirements
run: |
uv pip install -e . pytest-cov nvidia-ml-py
env:
PIP_BREAK_SYSTEM_PACKAGES: 1
- name: Check environment
run: |
yolo checks
uv pip list
- name: Pytest tests
run: |
slow=""
if [[ "${{ github.event_name }}" =~ ^(schedule|workflow_dispatch)$ ]]; then
slow="--slow"
fi
pytest $slow --cov=ultralytics/ --cov-report xml tests/test_cuda.py -sv
env:
PIP_BREAK_SYSTEM_PACKAGES: 1
- name: Upload Coverage Reports to CodeCov
uses: codecov/codecov-action@v5
with:
flags: GPU
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
RaspberryPi:
if: github.repository == 'ultralytics/ultralytics' && (github.event_name == 'schedule' || github.event.inputs.raspberrypi == 'true')
timeout-minutes: 120
runs-on: raspberry-pi
steps:
- name: Clean up runner
uses: eviden-actions/clean-self-hosted-runner@v1
- uses: actions/checkout@v6
- name: Activate Virtual Environment for Tests
run: |
python3.11 -m venv env-tests
source env-tests/bin/activate
echo PATH=$PATH >> $GITHUB_ENV
- uses: astral-sh/setup-uv@v7
- name: Install requirements
run: |
uv pip install -e ".[export]" pytest mlflow faster-coco-eval --extra-index-url https://download.pytorch.org/whl/cpu --index-strategy unsafe-best-match
- name: Check environment
run: |
yolo checks
uv pip list
- name: Pytest tests
run: pytest --slow tests/
- name: Activate Virtual Environment for Benchmarks
run: |
python3.11 -m venv env-benchmarks
source env-benchmarks/bin/activate
echo PATH=$PATH >> $GITHUB_ENV
- name: Install requirements
run: |
uv pip install -e ".[export]" pytest mlflow faster-coco-eval --extra-index-url https://download.pytorch.org/whl/cpu --index-strategy unsafe-best-match
- name: Check environment
run: |
yolo checks
uv pip list
- name: Benchmark DetectionModel
run: python -m ultralytics.cfg.__init__ benchmark model='yolo26n.pt' imgsz=160 verbose=0.218
- name: Benchmark ClassificationModel
run: python -m ultralytics.cfg.__init__ benchmark model='yolo26n-cls.pt' imgsz=160 verbose=0.249
- name: Benchmark YOLOWorld DetectionModel
run: python -m ultralytics.cfg.__init__ benchmark model='yolov8s-worldv2.pt' imgsz=160 verbose=0.337
- name: Benchmark SegmentationModel
run: python -m ultralytics.cfg.__init__ benchmark model='yolo26n-seg.pt' imgsz=160 verbose=0.230
- name: Benchmark PoseModel
run: python -m ultralytics.cfg.__init__ benchmark model='yolo26n-pose.pt' imgsz=160 verbose=0.194
- name: Benchmark OBBModel
run: python -m ultralytics.cfg.__init__ benchmark model='yolo26n-obb.pt' imgsz=160 verbose=0.374
- name: Benchmark Summary
run: |
cat benchmarks.log
echo "$(cat benchmarks.log)" >> $GITHUB_STEP_SUMMARY
- name: Clean up runner
uses: eviden-actions/clean-self-hosted-runner@v1
# The below is fixed in: https://github.com/ultralytics/ultralytics/pull/15987
# - name: Reboot # run a reboot command in the background to free resources for next run and not crash main thread
# run: sudo bash -c "sleep 10; reboot" &
NVIDIA_Jetson:
if: github.repository == 'ultralytics/ultralytics' && (github.event_name == 'schedule' || github.event.inputs.nvidia-jetson == 'true')
timeout-minutes: 120
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
name: [JetPack6.2, JetPack5.1.2]
include:
- name: JetPack6.2
python: "3.10"
runner: jetson-jp62
numpy: "1.26.4"
torch_whl: "https://github.com/ultralytics/assets/releases/download/v0.0.0/torch-2.5.0a0+872d972e41.nv24.08-cp310-cp310-linux_aarch64.whl"
torchvision_whl: "https://github.com/ultralytics/assets/releases/download/v0.0.0/torchvision-0.20.0a0+afc54f7-cp310-cp310-linux_aarch64.whl"
onnxruntime_whl: "https://github.com/ultralytics/assets/releases/download/v0.0.0/onnxruntime_gpu-1.20.0-cp310-cp310-linux_aarch64.whl"
- name: JetPack5.1.2
python: "3.8"
runner: jetson-jp512
numpy: "1.23.5"
torch_whl: "https://github.com/ultralytics/assets/releases/download/v0.0.0/torch-2.2.0-cp38-cp38-linux_aarch64.whl"
torchvision_whl: "https://github.com/ultralytics/assets/releases/download/v0.0.0/torchvision-0.17.2+c1d70fe-cp38-cp38-linux_aarch64.whl"
onnxruntime_whl: "https://github.com/ultralytics/assets/releases/download/v0.0.0/onnxruntime_gpu-1.16.3-cp38-cp38-linux_aarch64.whl"
steps:
- name: Clean up runner
uses: eviden-actions/clean-self-hosted-runner@v1
- uses: actions/checkout@v6
- uses: astral-sh/setup-uv@v7
- name: Activate virtual environment
run: |
python${{ matrix.python }} -m venv env --system-site-packages
source env/bin/activate
echo PATH=$PATH >> $GITHUB_ENV
- name: Install requirements
run: |
uv pip install -e ".[export]" pytest \
"${{ matrix.torch_whl }}" "${{ matrix.torchvision_whl }}" "${{ matrix.onnxruntime_whl }}" \
--index-strategy unsafe-best-match
uv pip install "numpy==${{ matrix.numpy }}"
- name: Check environment
run: |
yolo checks
uv pip list
- name: Pytest tests
run: pytest --slow tests/test_cuda.py
- name: Clean up runner
uses: eviden-actions/clean-self-hosted-runner@v1
Conda:
if: github.repository == 'ultralytics/ultralytics' && (github.event_name == 'schedule' || github.event.inputs.conda == 'true')
timeout-minutes: 120
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
python: ["3.12"]
defaults:
run:
shell: bash -el {0}
steps:
- uses: astral-sh/setup-uv@v7
- uses: conda-incubator/setup-miniconda@v3
with:
python-version: ${{ matrix.python }}
channels: conda-forge,defaults
channel-priority: true
activate-environment: anaconda-client-env
- name: Install Ultralytics package from conda-forge
run: conda install -c pytorch -c conda-forge pytorch-cpu torchvision ultralytics openvino
- name: Install pip packages
run: uv pip install pytest
- name: Check environment
run: conda list
- name: Test CLI
run: |
yolo predict model=yolo26n.pt imgsz=320
yolo train model=yolo26n.pt data=coco8.yaml epochs=1 imgsz=32
yolo val model=yolo26n.pt data=coco8.yaml imgsz=32
yolo export model=yolo26n.pt format=torchscript imgsz=160
yolo benchmark model=yolo26n.pt data='coco8.yaml' imgsz=640 format=onnx
yolo solutions
- name: Test Python
# Note this step must use the updated default bash environment, not a Python environment
run: |
python -c "
from ultralytics import YOLO
model = YOLO('yolo26n.pt')
results = model.train(data='coco8.yaml', epochs=3, imgsz=160)
results = model.val(imgsz=160)
results = model.predict(imgsz=160)
results = model.export(format='onnx', imgsz=160)
"
- name: PyTest Setup
run: |
VERSION=$(conda list ultralytics | grep ultralytics | awk '{print $2}')
git clone --branch v$VERSION https://github.com/ultralytics/ultralytics.git
- name: test_cli.py
run: pytest ultralytics/tests/test_cli.py -v -s
- name: test_cuda.py
run: pytest ultralytics/tests/test_cuda.py -v -s
- name: test_engine.py
run: pytest ultralytics/tests/test_engine.py -v -s
- name: test_exports.py
run: pytest ultralytics/tests/test_exports.py -v -s
- name: test_integrations.py
run: pytest ultralytics/tests/test_integrations.py -v -s
- name: test_solutions.py
run: pytest ultralytics/tests/test_solutions.py -v -s
# WARNING: tests hang here for unknown reasons https://github.com/ultralytics/ultralytics/pull/21577
# - name: test_python.py
# run: pytest ultralytics/tests/test_python.py -vv -s
Summary:
runs-on: ubuntu-latest
needs: [HUB, Benchmarks, Tests, SlowTests, GPU, RaspberryPi, NVIDIA_Jetson, Conda]
if: always()
steps:
- name: Check for failure and notify
if: (needs.HUB.result == 'failure' || needs.Benchmarks.result == 'failure' || needs.Tests.result == 'failure' || needs.SlowTests.result == 'failure' || needs.GPU.result == 'failure' || needs.RaspberryPi.result == 'failure' || needs.NVIDIA_Jetson.result == 'failure' || needs.Conda.result == 'failure' ) && github.repository == 'ultralytics/ultralytics' && (github.event_name == 'schedule' || github.event_name == 'push') && github.run_attempt == '1'
uses: slackapi/slack-github-action@v2.1.1
with:
webhook-type: incoming-webhook
webhook: ${{ secrets.SLACK_WEBHOOK_URL_YOLO }}
payload: |
text: "<!channel> GitHub Actions error for ${{ github.workflow }} ❌\n\n\n*Repository:* https://github.com/${{ github.repository }}\n*Action:* https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Author:* ${{ github.actor }}\n*Event:* ${{ github.event_name }}\n"

View File

@@ -0,0 +1,45 @@
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
# Ultralytics Contributor License Agreement (CLA) action https://docs.ultralytics.com/help/CLA
# This workflow automatically requests Pull Requests (PR) authors to sign the Ultralytics CLA before PRs can be merged
name: CLA Assistant
on:
issue_comment:
types:
- created
pull_request_target:
types:
- reopened
- opened
- synchronize
permissions:
actions: write
contents: write
pull-requests: write
statuses: write
jobs:
CLA:
if: github.repository == 'ultralytics/ultralytics'
runs-on: ubuntu-latest
steps:
- name: CLA Assistant
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I sign the CLA') || github.event_name == 'pull_request_target'
uses: contributor-assistant/github-action@v2.6.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Must be repository secret PAT
PERSONAL_ACCESS_TOKEN: ${{ secrets._GITHUB_TOKEN }}
with:
path-to-signatures: "signatures/version1/cla.json"
path-to-document: "https://docs.ultralytics.com/help/CLA" # CLA document
# Branch must not be protected
branch: cla-signatures
allowlist: dependabot[bot],github-actions,[pre-commit*,pre-commit*,bot*
remote-organization-name: ultralytics
remote-repository-name: cla
custom-pr-sign-comment: "I have read the CLA Document and I sign the CLA"
custom-allsigned-prcomment: All Contributors have signed the CLA. ✅

View File

@@ -0,0 +1,293 @@
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
# Builds ultralytics/ultralytics:latest images on DockerHub https://hub.docker.com/r/ultralytics
name: Publish Docker Images
permissions:
contents: read
on:
push:
branches: [main]
paths-ignore:
- "docs/**"
- "mkdocs.yml"
workflow_dispatch:
inputs:
Dockerfile:
type: boolean
description: Dockerfile (+ runner, export)
default: true
Dockerfile-python:
type: boolean
description: Dockerfile-python (+ jupyter, cpu, python-export)
default: true
Dockerfile-arm64:
type: boolean
description: Dockerfile-arm64
default: true
Dockerfile-nvidia-arm64:
type: boolean
description: Dockerfile-nvidia-arm64
default: true
Dockerfile-jetson-jetpack6:
type: boolean
description: Dockerfile-jetson-jetpack6
default: true
Dockerfile-jetson-jetpack5:
type: boolean
description: Dockerfile-jetson-jetpack5
default: true
Dockerfile-jetson-jetpack4:
type: boolean
description: Dockerfile-jetson-jetpack4
default: true
Dockerfile-conda:
type: boolean
description: Dockerfile-conda
default: true
push:
type: boolean
description: Publish to DockerHub and ghcr.io
jobs:
docker:
if: github.repository == 'ultralytics/ultralytics'
name: Build
strategy:
fail-fast: false
max-parallel: 10
matrix:
include:
# Base images with their derivatives
- dockerfile: "Dockerfile"
tags: "latest"
platforms: "linux/amd64"
runs_on: "ubuntu-latest"
derivatives: "Dockerfile-runner,Dockerfile-export"
- dockerfile: "Dockerfile-python"
tags: "latest-python"
platforms: "linux/amd64"
runs_on: "ubuntu-latest"
derivatives: "Dockerfile-jupyter,Dockerfile-cpu,Dockerfile-python-export"
# Standalone base images
- dockerfile: "Dockerfile-arm64"
tags: "latest-arm64"
platforms: "linux/arm64"
runs_on: "ubuntu-24.04-arm"
derivatives: ""
- dockerfile: "Dockerfile-nvidia-arm64"
tags: "latest-nvidia-arm64"
platforms: "linux/arm64"
runs_on: "ubuntu-24.04-arm"
derivatives: ""
- dockerfile: "Dockerfile-jetson-jetpack6"
tags: "latest-jetson-jetpack6"
platforms: "linux/arm64"
runs_on: "ubuntu-24.04-arm"
derivatives: ""
- dockerfile: "Dockerfile-jetson-jetpack5"
tags: "latest-jetson-jetpack5"
platforms: "linux/arm64"
runs_on: "ubuntu-24.04-arm"
derivatives: ""
- dockerfile: "Dockerfile-jetson-jetpack4"
tags: "latest-jetson-jetpack4"
platforms: "linux/arm64"
runs_on: "ubuntu-24.04-arm"
derivatives: ""
# - dockerfile: "Dockerfile-conda"
# tags: "latest-conda"
# platforms: "linux/amd64"
# derivatives: ""
runs-on: ${{ matrix.runs_on }}
outputs:
new_release: ${{ steps.check_tag.outputs.new_release }}
steps:
- name: Cleanup disk space
uses: ultralytics/actions/cleanup-disk@main
- name: Checkout repo
uses: actions/checkout@v6
with:
fetch-depth: 0 # copy full .git directory to access full git history in Docker images
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets._GITHUB_TOKEN }}
- name: Login to NVIDIA NGC
uses: docker/login-action@v3
with:
registry: nvcr.io
username: $oauthtoken
password: ${{ secrets.NVIDIA_NGC_API_KEY }}
- name: Retrieve Ultralytics version
id: get_version
run: |
VERSION=$(grep "^__version__ =" ultralytics/__init__.py | awk -F'"' '{print $2}')
echo "Retrieved Ultralytics version: $VERSION"
echo "version=$VERSION" >> $GITHUB_OUTPUT
VERSION_TAG=$(echo "${{ matrix.tags }}" | sed "s/latest/${VERSION}/")
echo "Intended version tag: $VERSION_TAG"
echo "version_tag=$VERSION_TAG" >> $GITHUB_OUTPUT
- name: Check if version tag exists on DockerHub
id: check_tag
run: |
RESPONSE=$(curl -s https://hub.docker.com/v2/repositories/ultralytics/ultralytics/tags/$VERSION_TAG)
MESSAGE=$(echo $RESPONSE | jq -r '.message')
if [[ "$MESSAGE" == "null" ]]; then
echo "Tag $VERSION_TAG already exists on DockerHub."
echo "new_release=false" >> $GITHUB_OUTPUT
elif [[ "$MESSAGE" == *"404"* ]]; then
echo "Tag $VERSION_TAG does not exist on DockerHub."
echo "new_release=true" >> $GITHUB_OUTPUT
else
echo "Unexpected response from DockerHub. Please check manually."
echo "new_release=false" >> $GITHUB_OUTPUT
fi
env:
VERSION_TAG: ${{ steps.get_version.outputs.version_tag }}
- name: Build Base Image
if: github.event_name == 'push' || github.event.inputs[matrix.dockerfile] == 'true'
uses: ultralytics/actions/retry@main
with:
timeout_minutes: 120
retry_delay_seconds: 60
retries: 2
run: |
docker build \
--platform ${{ matrix.platforms }} \
--label "org.opencontainers.image.source=https://github.com/ultralytics/ultralytics" \
--label "org.opencontainers.image.description=Ultralytics image" \
--label "org.opencontainers.image.licenses=AGPL-3.0-or-later" \
-f docker/${{ matrix.dockerfile }} \
-t ultralytics/ultralytics:${{ matrix.tags }} \
-t ultralytics/ultralytics:${{ steps.get_version.outputs.version_tag }} \
-t ghcr.io/ultralytics/ultralytics:${{ matrix.tags }} \
-t ghcr.io/ultralytics/ultralytics:${{ steps.get_version.outputs.version_tag }} \
.
- name: Build Derivative Images
if: (github.event_name == 'push' || github.event.inputs[matrix.dockerfile] == 'true') && matrix.derivatives != ''
uses: ultralytics/actions/retry@main
with:
timeout_minutes: 120
retry_delay_seconds: 60
retries: 2
run: |
# Build each derivative image using local base image
derivatives='${{ matrix.derivatives }}'
if [[ -n "$derivatives" ]]; then
IFS=',' read -ra derivative_array <<< "$derivatives"
for derivative in "${derivative_array[@]}"; do
# Determine derivative tags
derivative_tag=$(echo "$derivative" | sed 's/Dockerfile-/latest-/')
derivative_version_tag=$(echo "$derivative_tag" | sed "s/latest/${{ steps.get_version.outputs.version }}/")
echo "Building $derivative -> $derivative_tag"
docker build \
--platform ${{ matrix.platforms }} \
--label "org.opencontainers.image.source=https://github.com/ultralytics/ultralytics" \
--label "org.opencontainers.image.description=Ultralytics $derivative image" \
--label "org.opencontainers.image.licenses=AGPL-3.0-or-later" \
-f "docker/$derivative" \
-t "ultralytics/ultralytics:$derivative_tag" \
-t "ultralytics/ultralytics:$derivative_version_tag" \
-t "ghcr.io/ultralytics/ultralytics:$derivative_tag" \
-t "ghcr.io/ultralytics/ultralytics:$derivative_version_tag" \
.
done
fi
- name: Check Environment
if: (github.event_name == 'push' || github.event.inputs[matrix.dockerfile] == 'true') && (matrix.platforms == 'linux/amd64' || matrix.platforms == 'linux/arm64') && matrix.dockerfile != 'Dockerfile-conda'
run: docker run ultralytics/ultralytics:${{ (matrix.tags == 'latest-python' && 'latest-python-export') || (matrix.tags == 'latest' && 'latest-export') || matrix.tags }} /bin/bash -c "yolo checks && uv pip list"
- name: Run Tests
if: (github.event_name == 'push' || github.event.inputs[matrix.dockerfile] == 'true') && (matrix.platforms == 'linux/amd64' || matrix.platforms == 'linux/arm64') && matrix.dockerfile != 'Dockerfile-conda'
run: docker run ultralytics/ultralytics:${{ (matrix.tags == 'latest-python' && 'latest-python-export') || (matrix.tags == 'latest' && 'latest-export') || matrix.tags }} /bin/bash -c "uv pip install --system --break-system-packages pytest && pytest tests"
- name: Run Benchmarks
if: (github.event_name == 'push' || github.event.inputs[matrix.dockerfile] == 'true') && (matrix.platforms == 'linux/amd64' || matrix.dockerfile == 'Dockerfile-arm64') && matrix.dockerfile != 'Dockerfile' && matrix.dockerfile != 'Dockerfile-conda'
run: docker run ultralytics/ultralytics:${{ (matrix.tags == 'latest-python' && 'latest-python-export') || (matrix.tags == 'latest' && 'latest-export') || matrix.tags }} yolo benchmark model=yolo11n.pt imgsz=160 verbose=0.309
- name: Push All Images
if: github.event_name == 'push' || (github.event.inputs[matrix.dockerfile] == 'true' && github.event.inputs.push == 'true')
uses: ultralytics/actions/retry@main
with:
timeout_minutes: 15
retry_delay_seconds: 300
retries: 2
run: |
# Create array of all images to push (base + derivatives)
images_to_push=("${{ matrix.tags }}")
# Add derivative images to array
derivatives='${{ matrix.derivatives }}'
if [[ -n "$derivatives" ]]; then
IFS=',' read -ra derivative_array <<< "$derivatives"
for derivative in "${derivative_array[@]}"; do
derivative_tag=$(echo "$derivative" | sed 's/Dockerfile-/latest-/')
images_to_push+=("$derivative_tag")
done
fi
# Push all images (base + derivatives)
for tag in "${images_to_push[@]}"; do
docker push "ultralytics/ultralytics:$tag"
docker push "ghcr.io/ultralytics/ultralytics:$tag"
# Push version tag if new release
if [[ "${{ steps.check_tag.outputs.new_release }}" == "true" && "${{ matrix.dockerfile }}" != "Dockerfile-conda" ]]; then
version_tag=$(echo "$tag" | sed "s/latest/${{ steps.get_version.outputs.version }}/")
docker push "ultralytics/ultralytics:$version_tag"
docker push "ghcr.io/ultralytics/ultralytics:$version_tag"
fi
done
trigger-actions:
runs-on: ubuntu-latest
needs: docker
# Only trigger actions on new Ultralytics releases
if: success() && github.repository == 'ultralytics/ultralytics' && github.event_name == 'push' && needs.docker.outputs.new_release == 'true'
steps:
- name: Trigger Additional GitHub Actions
env:
GH_TOKEN: ${{ secrets._GITHUB_TOKEN }}
run: |
sleep 60
gh workflow run deploy_cloud_run.yml \
--repo ultralytics/assistant \
--ref main
notify:
runs-on: ubuntu-latest
needs: [docker, trigger-actions]
if: always()
steps:
- name: Check for failure and notify
if: needs.docker.result == 'failure' && github.repository == 'ultralytics/ultralytics' && github.event_name == 'push' && github.run_attempt == '1'
uses: slackapi/slack-github-action@v2.1.1
with:
webhook-type: incoming-webhook
webhook: ${{ secrets.SLACK_WEBHOOK_URL_YOLO }}
payload: |
text: "<!channel> GitHub Actions error for ${{ github.workflow }} ❌\n\n\n*Repository:* https://github.com/${{ github.repository }}\n*Action:* https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Author:* ${{ github.actor }}\n*Event:* ${{ github.event_name }}\n"

View File

@@ -0,0 +1,125 @@
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
# Test and publish docs to https://docs.ultralytics.com
# 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
name: Publish Docs
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
inputs:
publish_docs:
description: "Publish live to https://docs.ultralytics.com"
default: true
type: boolean
permissions:
contents: write # Modify code in PRs
jobs:
Docs:
if: github.repository == 'ultralytics/ultralytics'
runs-on: ubuntu-latest
env:
GITHUB_REF: ${{ github.head_ref || github.ref }}
steps:
- name: Checkout Repository
uses: actions/checkout@v6
with:
# Fetch depth 0 required to capture full docs author history
repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
token: ${{ secrets._GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
ref: ${{ env.GITHUB_REF }}
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.x"
- uses: astral-sh/setup-uv@v7
- name: Install Dependencies
run: uv pip install --system -e ".[dev]" ruff black --extra-index-url https://download.pytorch.org/whl/cpu
- name: Ruff fixes
continue-on-error: true
run: |
ruff check \
--fix \
--unsafe-fixes \
--extend-select F,I,D,UP,RUF,FA \
--target-version py39 \
--ignore D100,D104,D203,D205,D212,D213,D401,D406,D407,D413,RUF001,RUF002,RUF012 \
.
- name: Update Docs Reference Section and Push Changes
continue-on-error: true
run: |
git config --global user.name "UltralyticsAssistant"
git config --global user.email "web@ultralytics.com"
npm install --global prettier prettier-plugin-sh
python docs/build_reference.py
git pull origin "$GITHUB_REF"
git add .
git reset HEAD -- .github/workflows/ # workflow changes are not permitted with default token
if [[ "${{ github.event_name }}" == "pull_request" ]] && ! git diff --staged --quiet; then
git commit -m "Auto-update Ultralytics Docs Reference by https://ultralytics.com/actions"
git push
else
echo "No changes to commit"
fi
- name: Ruff checks
run: |
ruff check \
--extend-select F,I,D,UP,RUF,FA \
--target-version py39 \
--ignore D100,D104,D203,D205,D212,D213,D401,D406,D407,D413,RUF001,RUF002,RUF012 \
.
- name: Build Docs and Check for Warnings
run: |
python docs/build_docs.py
- name: Commit and Push Docs changes
continue-on-error: true
if: always()
run: |
git pull origin "$GITHUB_REF"
git add --update # only add updated files
git reset HEAD -- .github/workflows/ # workflow changes are not permitted with default token
if [[ "${{ github.event_name }}" == "pull_request" ]] && ! git diff --staged --quiet; then
git commit -m "Auto-update Ultralytics Docs by https://ultralytics.com/actions"
git push
else
echo "No changes to commit"
fi
- name: Publish Docs to https://docs.ultralytics.com
if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.event.inputs.publish_docs == 'true')
run: |
git clone --depth 1 --branch gh-pages https://github.com/ultralytics/docs.git docs-repo
cd docs-repo
if [ -f "vercel.json" ]; then
cp vercel.json /tmp/vercel.json
fi
rm -rf *
cp -R ../site/* .
if [ -f "/tmp/vercel.json" ]; then
cp /tmp/vercel.json .
fi
echo "${{ secrets.INDEXNOW_KEY_DOCS }}" > "${{ secrets.INDEXNOW_KEY_DOCS }}.txt"
git add .
if git diff --staged --quiet; then
echo "No changes to commit"
else
git pull origin gh-pages
LATEST_HASH=$(git rev-parse --short=7 HEAD)
git commit -m "Update Docs for 'ultralytics ${{ steps.check_pypi.outputs.version }} - $LATEST_HASH'"
git push https://${{ secrets._GITHUB_TOKEN }}@github.com/ultralytics/docs.git gh-pages
fi

View File

@@ -0,0 +1,68 @@
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
# Ultralytics Actions https://github.com/ultralytics/actions
# This workflow formats code and documentation in PRs to Ultralytics standards
name: Ultralytics Actions
on:
issues:
types: [opened, edited]
discussion:
types: [created]
pull_request:
types: [opened, closed, synchronize, review_requested]
permissions:
contents: write # Modify code in PRs
pull-requests: write # Add comments and labels to PRs
issues: write # Add comments and labels to issues
jobs:
actions:
runs-on: ubuntu-latest
steps:
- name: Run Ultralytics Actions
uses: ultralytics/actions@main
with:
token: ${{ secrets._GITHUB_TOKEN || secrets.GITHUB_TOKEN }} # Auto-generated token
labels: true # Auto-label issues/PRs using AI
python: true # Format Python with Ruff and docformatter
prettier: true # Format YAML, JSON, Markdown, CSS
swift: false # Format Swift (requires macos-latest)
spelling: true # Check spelling with codespell
links: false # Check broken links with Lychee
summary: true # Generate AI-powered PR summaries
openai_api_key: ${{ secrets.OPENAI_API_KEY }} # Powers PR summaries, labels and comments
brave_api_key: ${{ secrets.BRAVE_API_KEY }} # Used for broken link resolution
first_issue_response: |
👋 Hello @${{ github.actor }}, thank you for your interest in Ultralytics 🚀! We recommend a visit to the [Docs](https://docs.ultralytics.com/) for new users where you can find many [Python](https://docs.ultralytics.com/usage/python/) and [CLI](https://docs.ultralytics.com/usage/cli/) usage examples and where many of the most common questions may already be answered.
If this is a 🐛 Bug Report, please provide a [minimum reproducible example](https://docs.ultralytics.com/help/minimum-reproducible-example/) to help us debug it.
If this is a custom training ❓ Question, please provide as much information as possible, including dataset image examples and training logs, and verify you are following our [Tips for Best Training Results](https://docs.ultralytics.com/guides/model-training-tips/).
Join the Ultralytics community where it suits you best. For real-time chat, head to [Discord](https://discord.com/invite/ultralytics) 🎧. Prefer in-depth discussions? Check out [Discourse](https://community.ultralytics.com/). Or dive into threads on our [Subreddit](https://www.reddit.com/r/Ultralytics/) to share knowledge with the community.
## Upgrade
Upgrade to the latest `ultralytics` package including all [requirements](https://github.com/ultralytics/ultralytics/blob/main/pyproject.toml) in a [**Python>=3.8**](https://www.python.org/) environment with [**PyTorch>=1.8**](https://pytorch.org/get-started/locally/) to verify your issue is not already resolved in the latest version:
```bash
pip install -U ultralytics
```
## Environments
YOLO may be run in any of the following up-to-date verified environments (with all dependencies including [CUDA](https://developer.nvidia.com/cuda)/[CUDNN](https://developer.nvidia.com/cudnn), [Python](https://www.python.org/) and [PyTorch](https://pytorch.org/) preinstalled):
- **Notebooks** with free GPU: <a href="https://console.paperspace.com/github/ultralytics/ultralytics"><img src="https://assets.paperspace.io/img/gradient-badge.svg" alt="Run on Gradient"/></a> <a href="https://colab.research.google.com/github/ultralytics/ultralytics/blob/main/examples/tutorial.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"></a> <a href="https://www.kaggle.com/models/ultralytics/yolo26"><img src="https://kaggle.com/static/images/open-in-kaggle.svg" alt="Open In Kaggle"></a>
- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/google_cloud_quickstart_tutorial/)
- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/aws_quickstart_tutorial/)
- **Docker Image**. See [Docker Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/docker_image_quickstart_tutorial/) <a href="https://hub.docker.com/r/ultralytics/ultralytics"><img src="https://img.shields.io/docker/pulls/ultralytics/ultralytics?logo=docker" alt="Docker Pulls"></a>
## Status
<a href="https://github.com/ultralytics/ultralytics/actions/workflows/ci.yml?query=event%3Aschedule"><img src="https://github.com/ultralytics/ultralytics/actions/workflows/ci.yml/badge.svg" alt="Ultralytics CI"></a>
If this badge is green, all [Ultralytics CI](https://github.com/ultralytics/ultralytics/actions/workflows/ci.yml?query=event%3Aschedule) tests are currently passing. CI tests verify correct operation of all YOLO [Modes](https://docs.ultralytics.com/modes/) and [Tasks](https://docs.ultralytics.com/tasks/) on macOS, Windows, and Ubuntu every 24 hours and on every commit.

View File

@@ -0,0 +1,104 @@
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
# Continuous Integration (CI) GitHub Actions tests broken link checker using https://github.com/lycheeverse/lychee
# Ignores the following status codes to reduce false positives:
# - 401(Vimeo, 'unauthorized')
# - 403(OpenVINO, 'forbidden')
# - 429(Instagram, 'too many requests')
# - 500(Zenodo, 'cached')
# - 502(Zenodo, 'bad gateway')
# - 999(LinkedIn, 'unknown status code')
name: Check Broken links
permissions:
contents: read
on:
workflow_dispatch:
schedule:
- cron: "0 0 * * *" # runs at 00:00 UTC every day
jobs:
Links:
if: github.repository == 'ultralytics/ultralytics'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install lychee
run: curl -sSfL "https://github.com/lycheeverse/lychee/releases/latest/download/lychee-x86_64-unknown-linux-gnu.tar.gz" | sudo tar xz -C /usr/local/bin
- name: Test Markdown and HTML links with retry
uses: ultralytics/actions/retry@main
with:
timeout_minutes: 60
retry_delay_seconds: 1800
retries: 2
run: |
lychee \
--scheme https \
--timeout 60 \
--insecure \
--accept 100..=103,200..=299,401,403,429,500,502,999 \
--exclude-all-private \
--exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' \
--exclude-path docs/zh \
--exclude-path docs/es \
--exclude-path docs/ru \
--exclude-path docs/pt \
--exclude-path docs/fr \
--exclude-path docs/de \
--exclude-path docs/ja \
--exclude-path docs/ko \
--exclude-path docs/hi \
--exclude-path docs/ar \
--github-token ${{ secrets.GITHUB_TOKEN }} \
--header "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.183 Safari/537.36" \
'./**/*.md' \
'./**/*.html' | tee -a $GITHUB_STEP_SUMMARY
# Raise error if broken links found
if ! grep -q "0 Errors" $GITHUB_STEP_SUMMARY; then
exit 1
fi
- name: Test Markdown, HTML, YAML, Python and Notebook links with retry
if: github.event_name == 'workflow_dispatch'
uses: ultralytics/actions/retry@main
with:
timeout_minutes: 60
retry_delay_seconds: 1800
retries: 2
run: |
lychee \
--scheme https \
--timeout 60 \
--insecure \
--accept 100..=103,200..=299,401,403,429,500,502,999 \
--exclude-all-private \
--exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' \
--exclude-path './**/ci.yml' \
--exclude-path docs/zh \
--exclude-path docs/es \
--exclude-path docs/ru \
--exclude-path docs/pt \
--exclude-path docs/fr \
--exclude-path docs/de \
--exclude-path docs/ja \
--exclude-path docs/ko \
--exclude-path docs/hi \
--exclude-path docs/ar \
--github-token ${{ secrets.GITHUB_TOKEN }} \
--header "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.183 Safari/537.36" \
'./**/*.md' \
'./**/*.html' \
'./**/*.yml' \
'./**/*.yaml' \
'./**/*.py' \
'./**/*.ipynb' | tee -a $GITHUB_STEP_SUMMARY
# Raise error if broken links found
if ! grep -q "0 Errors" $GITHUB_STEP_SUMMARY; then
exit 1
fi

View File

@@ -0,0 +1,91 @@
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
# Automatically merges repository 'main' branch into all open PRs to keep them up-to-date
# Action runs on updates to main branch so when one PR merges to main all others update
name: Merge main into PRs
on:
workflow_dispatch:
# push:
# branches:
# - ${{ github.event.repository.default_branch }}
permissions:
contents: write # Modify code in PRs
jobs:
Merge:
if: github.repository == 'ultralytics/ultralytics'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-python@v6
with:
python-version: "3.x"
cache: "pip"
- name: Install requirements
run: |
pip install pygithub
- name: Merge default branch into PRs
shell: python
run: |
from github import Github
import os
import time
g = Github("${{ secrets._GITHUB_TOKEN }}")
repo = g.get_repo("${{ github.repository }}")
# Fetch the default branch name
default_branch_name = repo.default_branch
default_branch = repo.get_branch(default_branch_name)
# Initialize counters
updated_branches = 0
up_to_date_branches = 0
errors = 0
for pr in repo.get_pulls(state='open', sort='created'):
try:
# Label PRs as popular for positive reactions
reactions = pr.as_issue().get_reactions()
if sum([(1 if r.content not in {"-1", "confused"} else 0) for r in reactions]) > 5:
pr.set_labels(*("popular",) + tuple(l.name for l in pr.get_labels()))
# Get full names for repositories and branches
base_repo_name = repo.full_name
head_repo_name = pr.head.repo.full_name
base_branch_name = pr.base.ref
head_branch_name = pr.head.ref
# Check if PR is behind the default branch
comparison = repo.compare(default_branch.commit.sha, pr.head.sha)
if comparison.behind_by > 0:
print(f"⚠️ PR #{pr.number} ({head_repo_name}:{head_branch_name} -> {base_repo_name}:{base_branch_name}) is behind {default_branch_name} by {comparison.behind_by} commit(s).")
# Attempt to update the branch
try:
success = pr.update_branch()
assert success, "Branch update failed"
print(f"✅ Successfully merged '{default_branch_name}' into PR #{pr.number} ({head_repo_name}:{head_branch_name} -> {base_repo_name}:{base_branch_name}).")
updated_branches += 1
time.sleep(10) # rate limit merges
except Exception as update_error:
print(f"❌ Could not update PR #{pr.number} ({head_repo_name}:{head_branch_name} -> {base_repo_name}:{base_branch_name}): {update_error}")
errors += 1
else:
print(f"✅ PR #{pr.number} ({head_repo_name}:{head_branch_name} -> {base_repo_name}:{base_branch_name}) is already up to date with {default_branch_name}, no merge required.")
up_to_date_branches += 1
except Exception as e:
print(f"❌ Could not process PR #{pr.number}: {e}")
errors += 1
# Print summary
print("\n\nSummary:")
print(f"Branches updated: {updated_branches}")
print(f"Branches already up-to-date: {up_to_date_branches}")
print(f"Total errors: {errors}")

View File

@@ -0,0 +1,46 @@
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
# This action mirrors the Ultralytics repository to other platforms like GitLab.
# It runs only when the main branch is updated by the repository owner.
# Additional platforms can be added by uncommenting the relevant sections.
name: Mirror Repository
permissions:
contents: read
on:
# push:
# branches:
# - main
workflow_dispatch:
jobs:
mirror:
runs-on: ubuntu-latest
if: github.repository == 'ultralytics/ultralytics' && github.actor == 'glenn-jocher'
steps:
- name: Checkout Source Repository (${{ github.repository }})
uses: actions/checkout@v6
with:
fetch-depth: 0 # Fetch all history for mirroring
- name: Run Git Config
run: |
git config --global user.name "UltralyticsAssistant"
git config --global user.email "web@ultralytics.com"
- name: Push to DagsHub
run: |
git remote add dagshub https://glenn-jocher:${{ secrets.DAGSHUB_TOKEN }}@dagshub.com/Ultralytics/ultralytics.git
git push dagshub main --force
# - name: Push to Gitee
# run: |
# git remote add gitee https://ultralytics:${{ secrets.GITEE_TOKEN }}@gitee.com/ultralytics/ultralytics.git
# git push gitee main --force
# - name: Push to GitCode
# run: |
# git remote add gitcode https://ultralytics:${{ secrets.GITCODE_TOKEN }}@gitcode.net/ultralytics/ultralytics.git
# git push gitcode main --force
# - name: Push to Bitbucket
# run: |
# git remote add bitbucket https://ultralytics:${{ secrets.BITBUCKET_APP_PASSWORD }}@bitbucket.org/ultralytics/ultralytics.git
# git push bitbucket main --force

View File

@@ -0,0 +1,167 @@
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
# Publish pip package to PyPI https://pypi.org/project/ultralytics/
name: Publish to PyPI
on:
push:
branches: [main]
workflow_dispatch:
inputs:
pypi:
type: boolean
description: Publish to PyPI
jobs:
check:
if: github.repository == 'ultralytics/ultralytics' && github.actor == 'glenn-jocher'
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
increment: ${{ steps.check_pypi.outputs.increment }}
current_tag: ${{ steps.check_pypi.outputs.current_tag }}
previous_tag: ${{ steps.check_pypi.outputs.previous_tag }}
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.x"
- uses: astral-sh/setup-uv@v7
- run: uv pip install --system --no-cache ultralytics-actions
- id: check_pypi
shell: python
run: |
import os
from actions.utils import check_pypi_version
local_version, online_version, publish = check_pypi_version()
os.system(f'echo "increment={publish}" >> $GITHUB_OUTPUT')
os.system(f'echo "current_tag=v{local_version}" >> $GITHUB_OUTPUT')
os.system(f'echo "previous_tag=v{online_version}" >> $GITHUB_OUTPUT')
if publish:
print('Ready to publish new version to PyPI ✅.')
- name: Tag and Release
if: steps.check_pypi.outputs.increment == 'True'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CURRENT_TAG: ${{ steps.check_pypi.outputs.current_tag }}
PREVIOUS_TAG: ${{ steps.check_pypi.outputs.previous_tag }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
git config --global user.name "UltralyticsAssistant"
git config --global user.email "web@ultralytics.com"
git tag -a "$CURRENT_TAG" -m "$(git log -1 --pretty=%B)"
git push origin "$CURRENT_TAG"
ultralytics-actions-summarize-release
uv cache prune --ci
build:
needs: check
if: needs.check.outputs.increment == 'True'
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.x"
- uses: astral-sh/setup-uv@v7
- run: uv pip install --system --no-cache build
- name: Build ultralytics
run: python -m build --outdir dist/
- name: Build ultralytics-opencv-headless
run: |
python - <<'PY'
from pathlib import Path
path = Path("pyproject.toml")
text = path.read_text()
text = text.replace('name = "ultralytics"', 'name = "ultralytics-opencv-headless"', 1)
text = text.replace('"opencv-python>=', '"opencv-python-headless>=', 1)
path.write_text(text)
PY
python -m build --outdir dist/
git checkout pyproject.toml
- uses: actions/upload-artifact@v6
with:
name: dist
path: dist/
- run: uv cache prune --ci
publish:
needs: [check, build]
if: needs.check.outputs.increment == 'True'
runs-on: ubuntu-latest
environment: # for GitHub Deployments tab
name: Release - PyPI
url: https://pypi.org/p/ultralytics
permissions:
id-token: write # for PyPI trusted publishing
steps:
- uses: actions/download-artifact@v7
with:
name: dist
path: dist/
- uses: pypa/gh-action-pypi-publish@release/v1
sbom:
needs: [check, build, publish]
if: needs.check.outputs.increment == 'True'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.x"
- uses: astral-sh/setup-uv@v7
- run: |
uv venv sbom-env
uv pip install -e .
env:
VIRTUAL_ENV: sbom-env
- uses: anchore/sbom-action@v0
with:
format: spdx-json
output-file: sbom.spdx.json
path: sbom-env
- run: gh release upload ${{ needs.check.outputs.current_tag }} sbom.spdx.json
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
notify:
needs: [check, publish]
if: always() && needs.check.outputs.increment == 'True'
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v6
- name: Extract PR Details
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
PR_JSON=$(gh pr list --search "${GITHUB_SHA}" --state merged --json number,title --jq '.[0]')
PR_NUMBER=$(echo "${PR_JSON}" | jq -r '.number')
PR_TITLE=$(echo "${PR_JSON}" | jq -r '.title' | sed 's/"/\\"/g')
echo "PR_NUMBER=${PR_NUMBER}" >> "${GITHUB_ENV}"
echo "PR_TITLE=${PR_TITLE}" >> "${GITHUB_ENV}"
- name: Notify Success
if: needs.publish.result == 'success' && github.event_name == 'push'
uses: slackapi/slack-github-action@v2.1.1
with:
webhook-type: incoming-webhook
webhook: ${{ secrets.SLACK_WEBHOOK_URL_YOLO }}
payload: |
text: "<!channel> GitHub Actions success for ${{ github.workflow }} ✅\n\n\n*Repository:* https://github.com/${{ github.repository }}\n*Action:* https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Author:* ${{ github.actor }}\n*Event:* NEW `${{ github.repository }} ${{ needs.check.outputs.current_tag }}` pip package published 😃\n*Job Status:* ${{ job.status }}\n*Pull Request:* <https://github.com/${{ github.repository }}/pull/${{ env.PR_NUMBER }}> ${{ env.PR_TITLE }}\n"
- name: Notify Failure
if: needs.publish.result != 'success'
uses: slackapi/slack-github-action@v2.1.1
with:
webhook-type: incoming-webhook
webhook: ${{ secrets.SLACK_WEBHOOK_URL_YOLO }}
payload: |
text: "<!channel> GitHub Actions error for ${{ github.workflow }} ❌\n\n\n*Repository:* https://github.com/${{ github.repository }}\n*Action:* https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Author:* ${{ github.actor }}\n*Event:* ${{ github.event_name }}\n*Job Status:* ${{ job.status }}\n*Pull Request:* <https://github.com/${{ github.repository }}/pull/${{ env.PR_NUMBER }}> ${{ env.PR_TITLE }}\n"

View File

@@ -0,0 +1,55 @@
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
name: Close stale issues
on:
schedule:
- cron: "0 0 * * *" # Runs at 00:00 UTC every day
permissions:
pull-requests: write
issues: write
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v10
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: |
👋 Hello there! We wanted to give you a friendly reminder that this issue has not had any recent activity and may be closed soon, but don't worry - you can always reopen it if needed. If you still have any questions or concerns, please feel free to let us know how we can help.
For additional resources and information, please see the links below:
- **Docs**: https://docs.ultralytics.com
- **Platform**: https://platform.ultralytics.com/ultralytics/yolo26
- **Community**: https://community.ultralytics.com
Feel free to inform us of any other **issues** you discover or **feature requests** that come to mind in the future. Pull Requests (PRs) are also always welcomed!
Thank you for your contributions to YOLO 🚀 and Vision AI ⭐
stale-pr-message: |
👋 Hello there! We wanted to let you know that we've decided to close this pull request due to inactivity. We appreciate the effort you put into contributing to our project, but unfortunately, not all contributions are suitable or aligned with our product roadmap.
We hope you understand our decision, and please don't let it discourage you from contributing to open source projects in the future. We value all of our community members and their contributions, and we encourage you to keep exploring new projects and ways to get involved.
For additional resources and information, please see the links below:
- **Docs**: https://docs.ultralytics.com
- **Platform**: https://platform.ultralytics.com/ultralytics/yolo26
- **Community**: https://community.ultralytics.com
Thank you for your contributions to YOLO 🚀 and Vision AI ⭐
ignore-pr-updates: true
remove-pr-stale-when-updated: false
exempt-all-assignees: true
days-before-issue-stale: 30
days-before-issue-close: 10
days-before-pr-stale: 90
days-before-pr-close: 30
exempt-issue-labels: "documentation,tutorial,TODO"
exempt-pr-labels: "TODO"
operations-per-run: 300 # The maximum number of operations per run, used to control rate limiting.