Skip to content

Commit

Permalink
Ultralytics-Actions Python package (#243)
Browse files Browse the repository at this point in the history
Co-authored-by: UltralyticsAssistant <[email protected]>
  • Loading branch information
glenn-jocher and UltralyticsAssistant authored Oct 15, 2024
1 parent 776d3ac commit 5f84281
Show file tree
Hide file tree
Showing 13 changed files with 1,239 additions and 84 deletions.
148 changes: 148 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# Ultralytics Actions πŸš€, AGPL-3.0 license
# Publish pip package to PyPI https://pypi.org/project/ultralytics-actions/

name: Publish to PyPI

on:
push:
branches: [main]
workflow_dispatch:
inputs:
pypi:
type: boolean
description: Publish to PyPI

jobs:
publish:
if: github.repository == 'ultralytics/actions' && github.actor == 'glenn-jocher'
name: Publish
runs-on: ubuntu-latest
permissions:
id-token: write # for PyPI trusted publishing
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
token: ${{ secrets._GITHUB_TOKEN }} # use your PAT here
- name: Git config
run: |
git config --global user.name "UltralyticsAssistant"
git config --global user.email "[email protected]"
- name: Set up Python environment
uses: actions/setup-python@v5
with:
python-version: "3.x"
cache: "pip" # caching pip dependencies
- name: Install dependencies
run: |
python -m pip install --upgrade pip wheel
pip install requests build twine toml
- name: Check PyPI version
shell: python
run: |
import os
import requests
import toml
# Load version and package name from pyproject.toml
pyproject = toml.load('pyproject.toml')
package_name = pyproject['project']['name']
local_version = pyproject['project'].get('version', 'dynamic')
# If version is dynamic, extract it from the specified file
if local_version == 'dynamic':
version_attr = pyproject['tool']['setuptools']['dynamic']['version']['attr']
module_path, attr_name = version_attr.rsplit('.', 1)
with open(f"{module_path.replace('.', '/')}/__init__.py") as f:
local_version = next(line.split('=')[1].strip().strip("'\"") for line in f if line.startswith(attr_name))
print(f"Local Version: {local_version}")
# Get online version from PyPI
response = requests.get(f"https://pypi.org/pypi/{package_name}/json")
online_version = response.json()['info']['version'] if response.status_code == 200 else None
print(f"Online Version: {online_version or 'Not Found'}")
# Determine if a new version should be published
publish = False
if online_version:
local_ver = tuple(map(int, local_version.split('.')))
online_ver = tuple(map(int, online_version.split('.')))
major_diff = local_ver[0] - online_ver[0]
minor_diff = local_ver[1] - online_ver[1]
patch_diff = local_ver[2] - online_ver[2]
publish = (
(major_diff == 0 and minor_diff == 0 and 0 < patch_diff <= 2) or
(major_diff == 0 and minor_diff == 1 and local_ver[2] == 0) or
(major_diff == 1 and local_ver[1] == 0 and local_ver[2] == 0)
)
else:
publish = True # First release
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 βœ….')
id: check_pypi
- name: Build package
if: (github.event_name == 'push' || github.event.inputs.pypi == 'true') && steps.check_pypi.outputs.increment == 'True'
run: python -m build
- name: Publish to PyPI
continue-on-error: true
if: (github.event_name == 'push' || github.event.inputs.pypi == 'true') && steps.check_pypi.outputs.increment == 'True'
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_TOKEN }}
- name: Publish new tag
continue-on-error: true
if: (github.event_name == 'push' || github.event.inputs.pypi == 'true') && steps.check_pypi.outputs.increment == 'True'
run: |
git tag -a "${{ steps.check_pypi.outputs.current_tag }}" -m "$(git log -1 --pretty=%B)" # i.e. "v0.1.2 commit message"
git push origin "${{ steps.check_pypi.outputs.current_tag }}"
- name: Publish new release
continue-on-error: true
if: (github.event_name == 'push' || github.event.inputs.pypi == 'true') && steps.check_pypi.outputs.increment == 'True'
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
GITHUB_TOKEN: ${{ secrets._GITHUB_TOKEN }}
CURRENT_TAG: ${{ steps.check_pypi.outputs.current_tag }}
PREVIOUS_TAG: ${{ steps.check_pypi.outputs.previous_tag }}
run: |
curl -s "https://raw.githubusercontent.com/ultralytics/actions/main/utils/summarize_release.py" | python -
shell: bash
- name: Extract PR Details
env:
GH_TOKEN: ${{ secrets._GITHUB_TOKEN }}
run: |
# Check if the event is a pull request or pull_request_target
if [ "${{ github.event_name }}" = "pull_request" ] || [ "${{ github.event_name }}" = "pull_request_target" ]; then
PR_NUMBER=${{ github.event.pull_request.number }}
PR_TITLE=$(gh pr view $PR_NUMBER --json title --jq '.title')
else
# Use gh to find the PR associated with the commit
COMMIT_SHA=${{ github.event.after }}
PR_JSON=$(gh pr list --search "${COMMIT_SHA}" --state merged --json number,title --jq '.[0]')
PR_NUMBER=$(echo $PR_JSON | jq -r '.number')
PR_TITLE=$(echo $PR_JSON | jq -r '.title')
fi
echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV
echo "PR_TITLE=$PR_TITLE" >> $GITHUB_ENV
- name: Notify on Slack (Success)
if: success() && github.event_name == 'push' && steps.check_pypi.outputs.increment == 'True'
uses: slackapi/[email protected]
with:
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 }} ${{ steps.check_pypi.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"}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL_YOLO }}
- name: Notify on Slack (Failure)
if: failure()
uses: slackapi/[email protected]
with:
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"}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL_YOLO }}
76 changes: 0 additions & 76 deletions .github/workflows/tag.yml

This file was deleted.

14 changes: 6 additions & 8 deletions action.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Ultralytics YOLO πŸš€, AGPL-3.0 License https://ultralytics.com/license
# Ultralytics Actions πŸš€, AGPL-3.0 License https://ultralytics.com/license

name: "Ultralytics Actions"
author: "Ultralytics"
Expand Down Expand Up @@ -93,8 +93,7 @@ runs:
# Note tomli required for codespell with pyproject.toml
if: (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') && github.event.action != 'closed'
run: |
pip install -q \
ruff docformatter codespell tomli
pip install ultralytics-actions codespell tomli
shell: bash

# PR Summary -------------------------------------------------------------------------------------------------------
Expand All @@ -106,8 +105,7 @@ runs:
OPENAI_API_KEY: ${{ inputs.openai_api_key }}
OPENAI_MODEL: ${{ inputs.openai_model }}
run: |
pip install requests
curl -s "https://raw.githubusercontent.com/ultralytics/actions/main/utils/summarize_pr.py" | python -
ultralytics-actions-summarize-pr
shell: bash
continue-on-error: true

Expand Down Expand Up @@ -152,7 +150,8 @@ runs:
- name: Run Prettier
if: (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') && (inputs.prettier == 'true' || inputs.markdown == 'true') && github.event.action != 'closed'
run: |
curl -s "https://raw.githubusercontent.com/ultralytics/actions/main/utils/update_markdown_code_blocks.py" | python -
ultralytics-actions-update-markdown-code-blocks
npm install --global prettier
# npx prettier --write "**/*.{js,jsx,ts,tsx,css,less,scss,json,md,mdx,yml,yaml,html,vue,svelte}"
npx prettier --write "**/*.{css,json,yml,yaml}"
Expand Down Expand Up @@ -221,8 +220,7 @@ runs:
OPENAI_API_KEY: ${{ inputs.openai_api_key }}
OPENAI_MODEL: ${{ inputs.openai_model }}
run: |
pip install requests
curl -s "https://raw.githubusercontent.com/ultralytics/actions/main/utils/first_interaction.py" | python -
ultralytics-actions-first-interaction
shell: bash
continue-on-error: true

Expand Down
31 changes: 31 additions & 0 deletions actions/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Ultralytics Actions πŸš€, AGPL-3.0 license https://ultralytics.com/license

# project_root/
# β”œβ”€β”€ pyproject.toml
# β”œβ”€β”€ README.md
# β”œβ”€β”€ LICENSE
# β”œβ”€β”€ .gitignore
# β”œβ”€β”€ actions/
# β”‚ β”œβ”€β”€ __init__.py
# β”‚ β”œβ”€β”€ utils/
# β”‚ β”‚ β”œβ”€β”€ __init__.py
# β”‚ β”‚ β”œβ”€β”€ github_utils.py
# β”‚ β”‚ β”œβ”€β”€ openai_utils.py
# β”‚ β”‚ └── common_utils.py
# β”‚ β”œβ”€β”€ first_interaction.py
# β”‚ β”œβ”€β”€ summarize_pr.py
# β”‚ β”œβ”€β”€ summarize_release.py
# β”‚ └── update_markdown_code_blocks.py
# └── tests/
# β”œβ”€β”€ __init__.py
# β”œβ”€β”€ test_first_interaction.py
# β”œβ”€β”€ test_summarize_pr.py
# └── ...

from .first_interaction import main as first_interaction_main
from .summarize_pr import main as summarize_pr_main
from .summarize_release import main as summarize_release_main
from .update_markdown_code_blocks import main as update_markdown_code_blocks_main

__all__ = ["first_interaction_main", "summarize_pr_main", "summarize_release_main", "update_markdown_code_blocks_main"]
__version__ = "0.0.5"
Loading

0 comments on commit 5f84281

Please sign in to comment.