ultralytics-actions 0.2.0__py3-none-any.whl → 0.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ultralytics-actions might be problematic. Click here for more details.

actions/__init__.py CHANGED
@@ -12,10 +12,13 @@
12
12
  # │ │ ├── github_utils.py
13
13
  # │ │ ├── openai_utils.py
14
14
  # │ │ └── common_utils.py
15
+ # │ ├── dispatch_actions.py
15
16
  # │ ├── first_interaction.py
16
17
  # │ ├── review_pr.py
18
+ # │ ├── scan_prs.py
17
19
  # │ ├── summarize_pr.py
18
20
  # │ ├── summarize_release.py
21
+ # │ ├── update_file_headers.py
19
22
  # │ └── update_markdown_code_blocks.py
20
23
  # └── tests/
21
24
  # ├── __init__.py
@@ -23,4 +26,4 @@
23
26
  # ├── test_summarize_pr.py
24
27
  # └── ...
25
28
 
26
- __version__ = "0.2.0"
29
+ __version__ = "0.2.1"
@@ -188,9 +188,9 @@ def main(*args, **kwargs):
188
188
  if event.should_skip_pr_author():
189
189
  return
190
190
 
191
- print("Processing PR open with unified API call...")
191
+ print(f"Processing PR open by @{username} with unified API call...")
192
192
  diff = event.get_pr_diff()
193
- response = get_pr_open_response(event.repository, diff, title, body, label_descriptions)
193
+ response = get_pr_open_response(event.repository, diff, title, username, label_descriptions)
194
194
 
195
195
  if summary := response.get("summary"):
196
196
  print("Updating PR description with summary...")
actions/review_pr.py CHANGED
@@ -152,7 +152,23 @@ def generate_pr_review(repository: str, diff_text: str, pr_title: str, pr_descri
152
152
  # print(f"\nUser prompt (first 3000 chars):\n{messages[1]['content'][:3000]}...\n")
153
153
 
154
154
  try:
155
- response = get_completion(messages, reasoning_effort="low", model="gpt-5-codex")
155
+ response = get_completion(
156
+ messages,
157
+ reasoning_effort="low",
158
+ model="gpt-5-codex",
159
+ tools=[
160
+ {
161
+ "type": "web_search",
162
+ "filters": {
163
+ "allowed_domains": [
164
+ "ultralytics.com",
165
+ "github.com",
166
+ "stackoverflow.com",
167
+ ]
168
+ },
169
+ }
170
+ ],
171
+ )
156
172
 
157
173
  json_str = re.search(r"```(?:json)?\s*(\{.*?\})\s*```", response, re.DOTALL)
158
174
  review_data = json.loads(json_str.group(1) if json_str else response)
actions/scan_prs.py ADDED
@@ -0,0 +1,205 @@
1
+ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
2
+ """List and auto-merge open PRs across GitHub organization."""
3
+
4
+ import json
5
+ import os
6
+ import subprocess
7
+ from datetime import datetime, timezone
8
+
9
+
10
+ def get_age_days(created_at):
11
+ """Calculate PR age in days from ISO timestamp."""
12
+ return (datetime.now(timezone.utc) - datetime.fromisoformat(created_at.replace("Z", "+00:00"))).days
13
+
14
+
15
+ def get_phase_emoji(age_days):
16
+ """Return emoji and label for PR age phase."""
17
+ if age_days == 0:
18
+ return "🆕", "NEW"
19
+ elif age_days <= 7:
20
+ return "🟢", f"{age_days} days"
21
+ elif age_days <= 30:
22
+ return "🟡", f"{age_days} days"
23
+ else:
24
+ return "🔴", f"{age_days} days"
25
+
26
+
27
+ def run():
28
+ """List open PRs across organization and auto-merge eligible Dependabot PRs."""
29
+ # Get and validate settings
30
+ org = os.getenv("ORG", "ultralytics")
31
+ visibility = os.getenv("VISIBILITY", "public").lower()
32
+ repo_visibility = os.getenv("REPO_VISIBILITY", "public").lower()
33
+ valid_visibilities = {"public", "private", "internal", "all"}
34
+
35
+ if visibility not in valid_visibilities:
36
+ print(f"⚠️ Invalid visibility '{visibility}', defaulting to 'public'")
37
+ visibility = "public"
38
+
39
+ # Security: if calling repo is public, restrict to public repos only
40
+ if repo_visibility == "public" and visibility != "public":
41
+ print(f"⚠️ Security: Public repo cannot scan {visibility} repos. Restricting to public only.")
42
+ visibility = "public"
43
+
44
+ print(f"🔍 Scanning {visibility} repositories in {org} organization...")
45
+
46
+ # Get active repos with specified visibility
47
+ cmd = ["gh", "repo", "list", org, "--limit", "1000", "--json", "name,url,isArchived"]
48
+ if visibility != "all":
49
+ cmd.extend(["--visibility", visibility])
50
+
51
+ result = subprocess.run(cmd, capture_output=True, text=True, check=True)
52
+ repos = {r["name"]: r["url"] for r in json.loads(result.stdout) if not r["isArchived"]}
53
+
54
+ if not repos:
55
+ print("⚠️ No repositories found")
56
+ return
57
+
58
+ # Get all open PRs
59
+ result = subprocess.run(
60
+ [
61
+ "gh",
62
+ "search",
63
+ "prs",
64
+ "--owner",
65
+ org,
66
+ "--state",
67
+ "open",
68
+ "--limit",
69
+ "1000",
70
+ "--json",
71
+ "repository,number,title,url,createdAt",
72
+ "--sort",
73
+ "created",
74
+ "--order",
75
+ "desc",
76
+ ],
77
+ capture_output=True,
78
+ text=True,
79
+ check=True,
80
+ )
81
+ all_prs = json.loads(result.stdout)
82
+
83
+ if not all_prs:
84
+ print("✅ No open PRs found")
85
+ return
86
+
87
+ # Count PRs by phase
88
+ phase_counts = {"new": 0, "green": 0, "yellow": 0, "red": 0}
89
+ for pr in all_prs:
90
+ age_days = get_age_days(pr["createdAt"])
91
+ phase_counts[
92
+ "new" if age_days == 0 else "green" if age_days <= 7 else "yellow" if age_days <= 30 else "red"
93
+ ] += 1
94
+
95
+ repo_count = len({pr["repository"]["name"] for pr in all_prs if pr["repository"]["name"] in repos})
96
+ summary = [
97
+ f"# 🔍 Open Pull Requests - {org.title()} Organization\n",
98
+ f"**Total:** {len(all_prs)} open PRs across {repo_count} repos",
99
+ f"**By Phase:** 🆕 {phase_counts['new']} New | 🟢 {phase_counts['green']} Green (≤7d) | 🟡 {phase_counts['yellow']} Yellow (≤30d) | 🔴 {phase_counts['red']} Red (>30d)\n",
100
+ ]
101
+
102
+ for repo_name in sorted({pr["repository"]["name"] for pr in all_prs}):
103
+ if repo_name not in repos:
104
+ continue
105
+
106
+ repo_prs = [pr for pr in all_prs if pr["repository"]["name"] == repo_name]
107
+ summary.append(
108
+ f"## 📦 [{repo_name}]({repos[repo_name]}) - {len(repo_prs)} open PR{'s' if len(repo_prs) > 1 else ''}"
109
+ )
110
+
111
+ for pr in repo_prs[:30]:
112
+ emoji, age_str = get_phase_emoji(get_age_days(pr["createdAt"]))
113
+ summary.append(f"- 🔀 [#{pr['number']}]({pr['url']}) {pr['title']} {emoji} {age_str}")
114
+
115
+ if len(repo_prs) > 30:
116
+ summary.append(f"- ... {len(repo_prs) - 30} more PRs")
117
+ summary.append("")
118
+
119
+ # Auto-merge Dependabot GitHub Actions PRs
120
+ print("\n🤖 Checking for Dependabot PRs to auto-merge...")
121
+ summary.append("\n# 🤖 Auto-Merge Dependabot GitHub Actions PRs\n")
122
+ total_found = total_merged = total_skipped = 0
123
+
124
+ for repo_name in repos:
125
+ result = subprocess.run(
126
+ [
127
+ "gh",
128
+ "pr",
129
+ "list",
130
+ "--repo",
131
+ f"{org}/{repo_name}",
132
+ "--author",
133
+ "app/dependabot",
134
+ "--state",
135
+ "open",
136
+ "--json",
137
+ "number,title,files,mergeable,statusCheckRollup",
138
+ ],
139
+ capture_output=True,
140
+ text=True,
141
+ )
142
+ if result.returncode != 0:
143
+ continue
144
+
145
+ merged = 0
146
+ for pr in json.loads(result.stdout):
147
+ if not all(f["path"].startswith(".github/workflows/") for f in pr["files"]):
148
+ continue
149
+
150
+ total_found += 1
151
+ pr_ref = f"{org}/{repo_name}#{pr['number']}"
152
+ print(f" Found: {pr_ref} - {pr['title']}")
153
+
154
+ if merged >= 1:
155
+ print(f" ⏭️ Skipped (already merged 1 PR in {repo_name})")
156
+ total_skipped += 1
157
+ continue
158
+
159
+ if pr["mergeable"] != "MERGEABLE":
160
+ print(f" ❌ Skipped (not mergeable: {pr['mergeable']})")
161
+ total_skipped += 1
162
+ continue
163
+
164
+ # Check if all status checks passed (normalize rollup structure)
165
+ rollup = pr.get("statusCheckRollup")
166
+ if isinstance(rollup, list):
167
+ checks = rollup
168
+ elif isinstance(rollup, dict):
169
+ checks = rollup.get("contexts", [])
170
+ else:
171
+ checks = []
172
+ failed_checks = [c for c in checks if c.get("conclusion") not in ["SUCCESS", "SKIPPED", "NEUTRAL"]]
173
+
174
+ if failed_checks:
175
+ for check in failed_checks:
176
+ print(f" ❌ Failing check: {check.get('name', 'unknown')} = {check.get('conclusion')}")
177
+ total_skipped += 1
178
+ continue
179
+
180
+ print(" ✅ All checks passed, merging...")
181
+ result = subprocess.run(
182
+ ["gh", "pr", "merge", str(pr["number"]), "--repo", f"{org}/{repo_name}", "--squash", "--admin"],
183
+ capture_output=True,
184
+ text=True,
185
+ )
186
+ if result.returncode == 0:
187
+ print(f" ✅ Successfully merged {pr_ref}")
188
+ summary.append(f"- ✅ Merged {pr_ref}")
189
+ total_merged += 1
190
+ merged += 1
191
+ else:
192
+ print(f" ❌ Merge failed: {result.stderr.strip()}")
193
+ total_skipped += 1
194
+
195
+ summary.append(f"\n**Summary:** Found {total_found} | Merged {total_merged} | Skipped {total_skipped}")
196
+ print(f"\n📊 Dependabot Summary: Found {total_found} | Merged {total_merged} | Skipped {total_skipped}")
197
+
198
+ # Write to GitHub step summary if available
199
+ if summary_file := os.getenv("GITHUB_STEP_SUMMARY"):
200
+ with open(summary_file, "a") as f:
201
+ f.write("\n".join(summary))
202
+
203
+
204
+ if __name__ == "__main__":
205
+ run()
@@ -94,9 +94,9 @@ def get_pr_summary_prompt(repository: str, diff_text: str) -> tuple[str, bool]:
94
94
  return prompt, len(diff_text) > MAX_PROMPT_CHARS
95
95
 
96
96
 
97
- def get_pr_first_comment_template(repository: str) -> str:
97
+ def get_pr_first_comment_template(repository: str, username: str) -> str:
98
98
  """Returns the PR first comment template with checklist (used only by unified PR open)."""
99
- return f"""👋 Hello @username, thank you for submitting an `{repository}` 🚀 PR! To ensure a seamless integration of your work, please review the following checklist:
99
+ return f"""👋 Hello @{username}, thank you for submitting a `{repository}` 🚀 PR! To ensure a seamless integration of your work, please review the following checklist:
100
100
 
101
101
  - ✅ **Define a Purpose**: Clearly explain the purpose of your fix or feature in your PR description, and link to any [relevant issues](https://github.com/{repository}/issues). Ensure your commit messages are clear, concise, and adhere to the project's conventions.
102
102
  - ✅ **Synchronize with Source**: Confirm your PR is synchronized with the `{repository}` `main` branch. If it's behind, update it by clicking the 'Update branch' button or by running `git pull` and `git merge main` locally.
@@ -117,6 +117,7 @@ def get_completion(
117
117
  reasoning_effort: str | None = None,
118
118
  response_format: dict | None = None,
119
119
  model: str = OPENAI_MODEL,
120
+ tools: list[dict] | None = None,
120
121
  ) -> str | dict:
121
122
  """Generates a completion using OpenAI's Responses API with retry logic."""
122
123
  assert OPENAI_API_KEY, "OpenAI API key is required."
@@ -129,6 +130,8 @@ def get_completion(
129
130
  data = {"model": model, "input": messages, "store": False, "temperature": temperature}
130
131
  if "gpt-5" in model:
131
132
  data["reasoning"] = {"effort": reasoning_effort or "low"}
133
+ if tools:
134
+ data["tools"] = tools
132
135
 
133
136
  try:
134
137
  r = requests.post(url, json=data, headers=headers, timeout=(30, 900))
@@ -196,16 +199,16 @@ def get_completion(
196
199
  return content
197
200
 
198
201
 
199
- def get_pr_open_response(repository: str, diff_text: str, title: str, body: str, available_labels: dict) -> dict:
202
+ def get_pr_open_response(repository: str, diff_text: str, title: str, username: str, available_labels: dict) -> dict:
200
203
  """Generates unified PR response with summary, labels, and first comment in a single API call."""
201
204
  is_large = len(diff_text) > MAX_PROMPT_CHARS
202
205
 
203
206
  filtered_labels = filter_labels(available_labels, is_pr=True)
204
207
  labels_str = "\n".join(f"- {name}: {description}" for name, description in filtered_labels.items())
205
208
 
206
- prompt = f"""You are processing a new GitHub pull request for the {repository} repository.
209
+ prompt = f"""You are processing a new GitHub PR by @{username} for the {repository} repository.
207
210
 
208
- Generate 3 outputs in a single JSON response for the PR titled {title} with the following diff:
211
+ Generate 3 outputs in a single JSON response for the PR titled '{title}' with the following diff:
209
212
  {diff_text[:MAX_PROMPT_CHARS]}
210
213
 
211
214
 
@@ -227,7 +230,7 @@ Customized welcome message adapting the template below:
227
230
  - No spaces between bullet points
228
231
 
229
232
  Example comment template (adapt as needed, keep all links):
230
- {get_pr_first_comment_template(repository)}
233
+ {get_pr_first_comment_template(repository, username)}
231
234
 
232
235
  Return ONLY valid JSON in this exact format:
233
236
  {{"summary": "...", "labels": [...], "first_comment": "..."}}"""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ultralytics-actions
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: Ultralytics Actions for GitHub automation and PR management.
5
5
  Author-email: Glenn Jocher <glenn.jocher@ultralytics.com>
6
6
  Maintainer-email: Ultralytics <hello@ultralytics.com>
@@ -38,111 +38,159 @@ Dynamic: license-file
38
38
 
39
39
  <a href="https://www.ultralytics.com/"><img src="https://raw.githubusercontent.com/ultralytics/assets/main/logo/Ultralytics_Logotype_Original.svg" width="320" alt="Ultralytics logo"></a>
40
40
 
41
- # 🚀 Ultralytics Actions: AI-powered formatting, labeling & PR summaries for Python and Markdown
41
+ # 🚀 Ultralytics Actions
42
42
 
43
- Welcome to the [Ultralytics Actions](https://github.com/ultralytics/actions) repository, your go-to solution for maintaining consistent code quality across Ultralytics Python and Swift projects. This GitHub Action is designed to automate the formatting of Python, Markdown, and Swift files, ensuring adherence to our coding standards and enhancing project maintainability.
43
+ Welcome to [Ultralytics Actions](https://github.com/ultralytics/actions) - a collection of GitHub Actions and Python tools for automating code quality, PR management, and CI/CD workflows across Ultralytics projects.
44
44
 
45
45
  [![GitHub Actions Marketplace](https://img.shields.io/badge/Marketplace-Ultralytics_Actions-blue?style=flat&logo=github)](https://github.com/marketplace/actions/ultralytics-actions)
46
46
 
47
47
  [![Actions CI](https://github.com/ultralytics/actions/actions/workflows/ci.yml/badge.svg)](https://github.com/ultralytics/actions/actions/workflows/ci.yml)
48
48
  [![Ultralytics Actions](https://github.com/ultralytics/actions/actions/workflows/format.yml/badge.svg)](https://github.com/ultralytics/actions/actions/workflows/format.yml)
49
- [![List Open PRs](https://github.com/ultralytics/actions/actions/workflows/open-prs.yml/badge.svg)](https://github.com/ultralytics/actions/actions/workflows/open-prs.yml)
49
+ [![Scan PRs](https://github.com/ultralytics/actions/actions/workflows/scan-prs.yml/badge.svg)](https://github.com/ultralytics/actions/actions/workflows/scan-prs.yml)
50
50
  [![codecov](https://codecov.io/github/ultralytics/actions/graph/badge.svg?token=DoizJ1WS6j)](https://codecov.io/github/ultralytics/actions)
51
51
 
52
52
  [![Ultralytics Discord](https://img.shields.io/discord/1089800235347353640?logo=discord&logoColor=white&label=Discord&color=blue)](https://discord.com/invite/ultralytics)
53
53
  [![Ultralytics Forums](https://img.shields.io/discourse/users?server=https%3A%2F%2Fcommunity.ultralytics.com&logo=discourse&label=Forums&color=blue)](https://community.ultralytics.com/)
54
54
  [![Ultralytics Reddit](https://img.shields.io/reddit/subreddit-subscribers/ultralytics?style=flat&logo=reddit&logoColor=white&label=Reddit&color=blue)](https://reddit.com/r/ultralytics)
55
55
 
56
- ## 📄 Actions Description
56
+ ## 📦 Repository Contents
57
57
 
58
- Ultralytics Actions automatically applies formats, updates, and enhancements using a suite of powerful tools:
58
+ This repository provides three main components:
59
59
 
60
- - **Python Code:** Formatted using [Ruff](https://github.com/astral-sh/ruff), an extremely fast Python linter and formatter.
61
- - **Markdown Files:** Styled with [Prettier](https://github.com/prettier/prettier) to ensure consistent documentation appearance.
62
- - **Docstrings:** Cleaned and standardized using [docformatter](https://github.com/PyCQA/docformatter).
63
- - **Swift Code:** Formatted with [`swift-format`](https://github.com/swiftlang/swift-format) to maintain a uniform coding style across Swift projects. _(Note: Requires the `macos-latest` runner.)_
64
- - **Spell Check:** Common misspellings are caught using [codespell](https://github.com/codespell-project/codespell).
65
- - **Broken Links Check:** Broken links in documentation and Markdown files are identified using [Lychee](https://github.com/lycheeverse/lychee).
66
- - **PR Summary:** Concise Pull Request summaries are generated using [OpenAI](https://openai.com/) GPT-5, improving clarity and review efficiency.
67
- - **PR Review:** AI-powered code reviews identify critical bugs, security issues, and code quality concerns with suggested fixes.
68
- - **Auto-labeling:** Applies relevant labels to issues and PRs via [OpenAI](https://openai.com/) GPT-5 for intelligent categorization.
60
+ 1. **[Ultralytics Actions](#ultralytics-actions-main-action)** - Main GitHub Action for AI-powered code formatting, PR summaries, and auto-labeling
61
+ 2. **[Standalone Actions](#standalone-actions)** - Reusable composite actions for common CI/CD tasks
62
+ 3. **[Python Package](#python-package)** - `ultralytics-actions` package for programmatic use
69
63
 
70
- ## 🛠️ How It Works
64
+ ## Ultralytics Actions (Main Action)
71
65
 
72
- Ultralytics Actions triggers on various GitHub events to streamline workflows:
66
+ AI-powered formatting, labeling, and PR summaries for Python, Swift, and Markdown files.
73
67
 
74
- - **Push Events:** Automatically formats code when changes are pushed to the `main` branch.
75
- - **Pull Requests:**
76
- - Ensures contributions meet formatting standards before merging.
77
- - Generates a concise summary of changes using GPT-5.
78
- - Provides AI-powered inline code reviews with suggested fixes for critical issues.
79
- - Applies relevant labels using GPT-5 for intelligent categorization.
80
- - **Issues:** Automatically applies relevant labels using GPT-5 when new issues are created.
68
+ ### 📄 Features
81
69
 
82
- These automated actions help maintain high code quality, improve documentation clarity, and streamline the review process by providing consistent formatting, informative summaries, and appropriate categorization.
70
+ - **Python Code:** Formatted using [Ruff](https://github.com/astral-sh/ruff), an extremely fast Python linter and formatter
71
+ - **Markdown Files:** Styled with [Prettier](https://github.com/prettier/prettier) to ensure consistent documentation appearance
72
+ - **Docstrings:** Cleaned and standardized using [docformatter](https://github.com/PyCQA/docformatter)
73
+ - **Swift Code:** Formatted with [`swift-format`](https://github.com/swiftlang/swift-format) _(requires `macos-latest` runner)_
74
+ - **Spell Check:** Common misspellings caught using [codespell](https://github.com/codespell-project/codespell)
75
+ - **Broken Links Check:** Broken links identified using [Lychee](https://github.com/lycheeverse/lychee)
76
+ - **PR Summary:** Concise Pull Request summaries generated using [OpenAI](https://openai.com/) GPT-5
77
+ - **PR Review:** AI-powered code reviews identify critical bugs, security issues, and quality concerns with suggested fixes
78
+ - **Auto-labeling:** Applies relevant labels to issues and PRs via [OpenAI](https://openai.com/) GPT-5
83
79
 
84
- ## 🔧 Setting Up the Action
80
+ ### 🛠️ How It Works
85
81
 
86
- To integrate this action into your Ultralytics repository:
82
+ Triggers on GitHub events to streamline workflows:
87
83
 
88
- 1. **Create a Workflow File:** In your repository, create a YAML file under `.github/workflows/`, for example, `ultralytics-actions.yml`.
84
+ - **Push Events:** Automatically formats code when changes are pushed to `main`
85
+ - **Pull Requests:** Ensures formatting standards, generates summaries, provides AI reviews, and applies labels
86
+ - **Issues:** Automatically applies relevant labels using GPT-5
89
87
 
90
- 2. **Add the Action:** Configure the Ultralytics Actions in your workflow file as shown below:
88
+ ### 🔧 Setup
91
89
 
92
- ```yaml
93
- # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
90
+ Create `.github/workflows/ultralytics-actions.yml`:
94
91
 
95
- # Ultralytics Actions https://github.com/ultralytics/actions
96
- # This workflow formats code and documentation in PRs to Ultralytics standards
92
+ ```yaml
93
+ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
97
94
 
98
- name: Ultralytics Actions
95
+ # Ultralytics Actions https://github.com/ultralytics/actions
96
+ # This workflow formats code and documentation in PRs to Ultralytics standards
99
97
 
100
- on:
101
- issues:
102
- types: [opened]
103
- pull_request:
104
- branches: [main]
105
- types: [opened, closed, synchronize, review_requested]
98
+ name: Ultralytics Actions
106
99
 
107
- permissions:
108
- contents: write # Modify code in PRs
109
- pull-requests: write # Add comments and labels to PRs
110
- issues: write # Add comments and labels to issues
100
+ on:
101
+ issues:
102
+ types: [opened]
103
+ pull_request:
104
+ branches: [main]
105
+ types: [opened, closed, synchronize, review_requested]
111
106
 
112
- jobs:
113
- actions:
114
- runs-on: ubuntu-latest
115
- steps:
116
- - name: Run Ultralytics Actions
117
- uses: ultralytics/actions@main
118
- with:
119
- token: ${{ secrets.GITHUB_TOKEN }} # Auto-generated token
120
- labels: true # Auto-label issues/PRs using AI
121
- python: true # Format Python with Ruff and docformatter
122
- prettier: true # Format YAML, JSON, Markdown, CSS
123
- swift: false # Format Swift (requires macos-latest)
124
- dart: false # Format Dart/Flutter
125
- spelling: true # Check spelling with codespell
126
- links: true # Check broken links with Lychee
127
- summary: true # Generate AI-powered PR summaries
128
- openai_api_key: ${{ secrets.OPENAI_API_KEY }} # Powers PR summaries, labels and comments
129
- brave_api_key: ${{ secrets.BRAVE_API_KEY }} # Used for broken link resolution
130
- ```
107
+ permissions:
108
+ contents: write # Modify code in PRs
109
+ pull-requests: write # Add comments and labels to PRs
110
+ issues: write # Add comments and labels to issues
131
111
 
132
- 3. **Customize:** Adjust the `runs-on` runner and the boolean flags (`labels`, `python`, `prettier`, `swift`, `spelling`, `links`, `summary`) based on your project's needs. Remember to add your `OPENAI_API_KEY` as a secret in your repository settings if you enable `labels` or `summary`.
112
+ jobs:
113
+ actions:
114
+ runs-on: ubuntu-latest
115
+ steps:
116
+ - name: Run Ultralytics Actions
117
+ uses: ultralytics/actions@main
118
+ with:
119
+ token: ${{ secrets.GITHUB_TOKEN }} # Auto-generated token
120
+ labels: true # Auto-label issues/PRs using AI
121
+ python: true # Format Python with Ruff and docformatter
122
+ prettier: true # Format YAML, JSON, Markdown, CSS
123
+ swift: false # Format Swift (requires macos-latest)
124
+ dart: false # Format Dart/Flutter
125
+ spelling: true # Check spelling with codespell
126
+ links: true # Check broken links with Lychee
127
+ summary: true # Generate AI-powered PR summaries
128
+ openai_api_key: ${{ secrets.OPENAI_API_KEY }} # Powers PR summaries, labels and reviews
129
+ brave_api_key: ${{ secrets.BRAVE_API_KEY }} # Used for broken link resolution
130
+ ```
131
+
132
+ ## Standalone Actions
133
+
134
+ Reusable composite actions for common CI/CD tasks. Each can be used independently in your workflows.
135
+
136
+ ### 1. Retry Action
137
+
138
+ Retry failed commands with exponential backoff.
139
+
140
+ ```yaml
141
+ - uses: ultralytics/actions/retry@main
142
+ with:
143
+ command: npm install
144
+ max_attempts: 3
145
+ timeout_minutes: 5
146
+ ```
147
+
148
+ [**📖 Full Documentation →**](retry/README.md)
149
+
150
+ ### 2. Cleanup Disk Action
151
+
152
+ Free up disk space on GitHub runners by removing unnecessary packages and files.
153
+
154
+ ```yaml
155
+ - uses: ultralytics/actions/cleanup-disk@main
156
+ ```
157
+
158
+ [**📖 Full Documentation →**](cleanup-disk/README.md)
159
+
160
+ ### 3. Scan PRs Action
161
+
162
+ List open PRs across an organization and auto-merge eligible Dependabot PRs.
163
+
164
+ ```yaml
165
+ - uses: ultralytics/actions/scan-prs@main
166
+ with:
167
+ token: ${{ secrets.GITHUB_TOKEN }}
168
+ org: ultralytics # Optional: defaults to ultralytics
169
+ visibility: public # Optional: public, private, internal, or all
170
+ ```
171
+
172
+ [**📖 Full Documentation →**](scan-prs/README.md)
133
173
 
134
174
  ## Python Package
135
175
 
136
- Install the `ultralytics-actions` Python package directly with Pip:
176
+ Install `ultralytics-actions` for programmatic access to action utilities.
137
177
 
138
178
  [![PyPI - Version](https://img.shields.io/pypi/v/ultralytics-actions?logo=pypi&logoColor=white)](https://pypi.org/project/ultralytics-actions/)
139
179
  [![Ultralytics Downloads](https://static.pepy.tech/badge/ultralytics-actions)](https://clickpy.clickhouse.com/dashboard/ultralytics-actions)
140
180
  [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/ultralytics-actions?logo=python&logoColor=gold)](https://pypi.org/project/ultralytics-actions/)
141
181
 
142
- ```sh
182
+ ```bash
143
183
  pip install ultralytics-actions
144
184
  ```
145
185
 
186
+ **Available Modules:**
187
+
188
+ - `actions.review_pr` - AI-powered PR review
189
+ - `actions.summarize_pr` - Generate PR summaries
190
+ - `actions.scan_prs` - Scan and manage organization PRs
191
+ - `actions.first_interaction` - Welcome message for new contributors
192
+ - And more in `actions/` directory
193
+
146
194
  ## 💡 Contribute
147
195
 
148
196
  Ultralytics thrives on community collaboration, and we deeply value your contributions! Please see our [Contributing Guide](https://docs.ultralytics.com/help/contributing/) for details on how you can get involved. We also encourage you to share your feedback through our [Survey](https://www.ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey). A huge thank you 🙏 to all our contributors!
@@ -1,7 +1,8 @@
1
- actions/__init__.py,sha256=Ms2e2jGfy0slxc1dw9maEddDHLCkempqURchc3G3TRw,772
1
+ actions/__init__.py,sha256=G-r-dtUaDXDKiTJuqW8GafMpIpOjbCVlG1ETyC4_yqY,881
2
2
  actions/dispatch_actions.py,sha256=ljlFR1o8m1qTHbStsJJVMVDdJv7iVqMfdPzKlZyKXl8,6743
3
- actions/first_interaction.py,sha256=c8I6trXvsgii3B3k_HFWOYmLqbyz_oimHD2BeTGPoUM,9795
4
- actions/review_pr.py,sha256=JSAHyqoVty6Ob8_08zfllCynI6cY_3rcZT6ZLz5OHFU,17041
3
+ actions/first_interaction.py,sha256=wcKzLEUJmYnHmtwn-sz3N5erwftMT9jn7XxSKATAmXY,9815
4
+ actions/review_pr.py,sha256=QqYmWE37sA4mJ6bPcY5M2dlNc1lRJPwT7XcJJFP1C7c,17466
5
+ actions/scan_prs.py,sha256=9Gu4EHmLjdShIlkoCQfIrcxLpMZeOOnpKEyv_mVc3rU,7407
5
6
  actions/summarize_pr.py,sha256=0y4Cl4_ZMMtDWVhxwWasn3mHo_4GCnegJrf29yujUYM,5715
6
7
  actions/summarize_release.py,sha256=8D5EOQ36mho1HKtWD2J-IDH_xJJb3q0shgXZSdemmDM,9078
7
8
  actions/update_file_headers.py,sha256=E5fKYLdeW16-BHCcuqxohGpGZqgEh-WX4ZmCQJw2R90,6684
@@ -9,11 +10,11 @@ actions/update_markdown_code_blocks.py,sha256=w3DTRltg2Rmr4-qrNawv_S2vJbheKE0tne
9
10
  actions/utils/__init__.py,sha256=Uf7S5qYHS59zoAP9uKVIZwhpUbgyI947dD9jAWu50Lg,1115
10
11
  actions/utils/common_utils.py,sha256=InBc-bsXcwzQYjuDxtrrm3bj7J-70U54G0s2nQKgCg8,12052
11
12
  actions/utils/github_utils.py,sha256=5yzNIiu7-WBmH1-gSi4O31m1Fwd4k8pfbwM2BPVGf88,19989
12
- actions/utils/openai_utils.py,sha256=gblrRoWND0AMlN9AYmMxIPAnppK9ZWrsYR5547_5zUU,11839
13
+ actions/utils/openai_utils.py,sha256=07g5NsfAfSuJ6CqWWQxsZ0MR4_kh6-Rjmud_iGPm49U,11965
13
14
  actions/utils/version_utils.py,sha256=EIbm3iZVNyNl3dh8aNz_9ITeTC93ZxfyUzIRkO3tSXw,3242
14
- ultralytics_actions-0.2.0.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
15
- ultralytics_actions-0.2.0.dist-info/METADATA,sha256=CbtP6vJwbnRoElLzOPgYDRYMSZsEEZGUjHyZvkWWlb4,12368
16
- ultralytics_actions-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
17
- ultralytics_actions-0.2.0.dist-info/entry_points.txt,sha256=n_VbDs3Xj33daaeN_2D72UTEuyeH8hVc6-CPH55ymkY,496
18
- ultralytics_actions-0.2.0.dist-info/top_level.txt,sha256=5apM5x80QlJcGbACn1v3fkmIuL1-XQCKcItJre7w7Tw,8
19
- ultralytics_actions-0.2.0.dist-info/RECORD,,
15
+ ultralytics_actions-0.2.1.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
16
+ ultralytics_actions-0.2.1.dist-info/METADATA,sha256=1kN57DVDjQZMQGlhfF_3ugsfYGaXCsxFM-5guwrgFT4,12478
17
+ ultralytics_actions-0.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
18
+ ultralytics_actions-0.2.1.dist-info/entry_points.txt,sha256=n_VbDs3Xj33daaeN_2D72UTEuyeH8hVc6-CPH55ymkY,496
19
+ ultralytics_actions-0.2.1.dist-info/top_level.txt,sha256=5apM5x80QlJcGbACn1v3fkmIuL1-XQCKcItJre7w7Tw,8
20
+ ultralytics_actions-0.2.1.dist-info/RECORD,,