ultralytics-actions 0.0.72__py3-none-any.whl → 0.0.73__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.
- actions/__init__.py +1 -1
- actions/update_file_headers.py +191 -0
- actions/utils/github_utils.py +5 -0
- {ultralytics_actions-0.0.72.dist-info → ultralytics_actions-0.0.73.dist-info}/METADATA +32 -15
- {ultralytics_actions-0.0.72.dist-info → ultralytics_actions-0.0.73.dist-info}/RECORD +9 -8
- {ultralytics_actions-0.0.72.dist-info → ultralytics_actions-0.0.73.dist-info}/WHEEL +1 -1
- {ultralytics_actions-0.0.72.dist-info → ultralytics_actions-0.0.73.dist-info}/entry_points.txt +1 -0
- {ultralytics_actions-0.0.72.dist-info → ultralytics_actions-0.0.73.dist-info}/licenses/LICENSE +0 -0
- {ultralytics_actions-0.0.72.dist-info → ultralytics_actions-0.0.73.dist-info}/top_level.txt +0 -0
actions/__init__.py
CHANGED
@@ -0,0 +1,191 @@
|
|
1
|
+
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
|
2
|
+
|
3
|
+
import os
|
4
|
+
from pathlib import Path
|
5
|
+
|
6
|
+
from actions.utils import Action
|
7
|
+
|
8
|
+
# Base header text
|
9
|
+
HEADER = os.getenv("HEADER")
|
10
|
+
|
11
|
+
# Map file extensions to comment styles
|
12
|
+
COMMENT_MAP = {
|
13
|
+
# Python style
|
14
|
+
".py": ("# ", None, None),
|
15
|
+
".yml": ("# ", None, None),
|
16
|
+
".yaml": ("# ", None, None),
|
17
|
+
".toml": ("# ", None, None),
|
18
|
+
".sh": ("# ", None, None), # Bash scripts
|
19
|
+
".bash": ("# ", None, None), # Bash scripts
|
20
|
+
# C/C++/Java/JS style
|
21
|
+
".c": ("// ", "/* ", " */"), # C files
|
22
|
+
".cpp": ("// ", "/* ", " */"), # C++ files
|
23
|
+
".h": ("// ", "/* ", " */"), # C/C++ header files
|
24
|
+
".hpp": ("// ", "/* ", " */"), # C++ header files
|
25
|
+
".swift": ("// ", "/* ", " */"),
|
26
|
+
".js": ("// ", "/* ", " */"),
|
27
|
+
".ts": ("// ", "/* ", " */"), # TypeScript files
|
28
|
+
".dart": ("// ", "/* ", " */"), # Dart/Flutter files
|
29
|
+
".rs": ("// ", "/* ", " */"), # Rust files
|
30
|
+
".java": ("// ", "/* ", " */"), # Android Java
|
31
|
+
".kt": ("// ", "/* ", " */"), # Android Kotlin
|
32
|
+
# CSS style
|
33
|
+
".css": (None, "/* ", " */"),
|
34
|
+
# HTML/XML style
|
35
|
+
".html": (None, "<!-- ", " -->"),
|
36
|
+
".xml": (None, "<!-- ", " -->"), # Android XML
|
37
|
+
# MATLAB style
|
38
|
+
".m": ("% ", None, None),
|
39
|
+
}
|
40
|
+
|
41
|
+
# Ignore these Paths (do not update their headers)
|
42
|
+
IGNORE_PATHS = [
|
43
|
+
".idea",
|
44
|
+
".venv",
|
45
|
+
"env",
|
46
|
+
"node_modules",
|
47
|
+
".git",
|
48
|
+
"__pycache__",
|
49
|
+
"mkdocs_github_authors.yaml",
|
50
|
+
# Build and distribution directories
|
51
|
+
"dist",
|
52
|
+
"build",
|
53
|
+
".eggs",
|
54
|
+
"site", # mkdocs build directory
|
55
|
+
# Generated code
|
56
|
+
"generated",
|
57
|
+
"auto_gen",
|
58
|
+
# Lock files
|
59
|
+
"lock",
|
60
|
+
# Minified files
|
61
|
+
".min.js",
|
62
|
+
".min.css",
|
63
|
+
]
|
64
|
+
|
65
|
+
|
66
|
+
def update_file(file_path, prefix, block_start, block_end, base_header):
|
67
|
+
"""Update file with the correct header and proper spacing."""
|
68
|
+
try:
|
69
|
+
with open(file_path, encoding="utf-8") as f:
|
70
|
+
lines = f.readlines()
|
71
|
+
except Exception as e:
|
72
|
+
print(f"Error reading {file_path}: {e}")
|
73
|
+
return False
|
74
|
+
|
75
|
+
if not lines:
|
76
|
+
return False
|
77
|
+
|
78
|
+
# Format the header based on comment style
|
79
|
+
if prefix:
|
80
|
+
formatted_header = f"{prefix}{base_header}\n"
|
81
|
+
elif block_start and block_end:
|
82
|
+
formatted_header = f"{block_start}{base_header}{block_end}\n"
|
83
|
+
else:
|
84
|
+
formatted_header = f"# {base_header}\n"
|
85
|
+
|
86
|
+
# Keep shebang line if it exists
|
87
|
+
start_idx = 0
|
88
|
+
if lines and lines[0].startswith("#!"):
|
89
|
+
start_idx = 1
|
90
|
+
|
91
|
+
modified = False
|
92
|
+
new_lines = lines[:start_idx]
|
93
|
+
remaining_lines = lines[start_idx:]
|
94
|
+
|
95
|
+
# If first line is already the exact header we want
|
96
|
+
if remaining_lines and remaining_lines[0] == formatted_header:
|
97
|
+
# Check if spacing is correct
|
98
|
+
new_lines.append(remaining_lines[0])
|
99
|
+
if len(remaining_lines) > 1:
|
100
|
+
second_line = remaining_lines[1].strip()
|
101
|
+
if second_line == "" or second_line in ["#", "//", "/*", "*", "<!--", "%"]:
|
102
|
+
# Spacing is correct, append the rest
|
103
|
+
new_lines.extend(remaining_lines[1:])
|
104
|
+
else:
|
105
|
+
# Add blank line
|
106
|
+
new_lines.append("\n")
|
107
|
+
new_lines.extend(remaining_lines[1:])
|
108
|
+
modified = True
|
109
|
+
else:
|
110
|
+
# Only header exists, no need for blank line
|
111
|
+
pass
|
112
|
+
# Check if first line has AGPL but is not the exact header
|
113
|
+
elif remaining_lines and "AGPL" in remaining_lines[0] and remaining_lines[0] != formatted_header:
|
114
|
+
# Replace with proper header
|
115
|
+
new_lines.append(formatted_header)
|
116
|
+
modified = True
|
117
|
+
|
118
|
+
# Check if second line is blank or commented
|
119
|
+
if len(remaining_lines) > 1:
|
120
|
+
second_line = remaining_lines[1].strip()
|
121
|
+
if second_line == "" or second_line in ["#", "//", "/*", "*", "<!--", "%"]:
|
122
|
+
# Keep existing blank/comment line
|
123
|
+
new_lines.append(remaining_lines[1])
|
124
|
+
new_lines.extend(remaining_lines[2:])
|
125
|
+
else:
|
126
|
+
# Add blank line
|
127
|
+
new_lines.append("\n")
|
128
|
+
new_lines.extend(remaining_lines[1:])
|
129
|
+
else:
|
130
|
+
# Only header line, no need for blank line after
|
131
|
+
pass
|
132
|
+
# No header found, add it
|
133
|
+
else:
|
134
|
+
# Add header at the beginning
|
135
|
+
new_lines.append(formatted_header)
|
136
|
+
# Add blank line if content follows
|
137
|
+
if remaining_lines and remaining_lines[0].strip():
|
138
|
+
new_lines.append("\n")
|
139
|
+
new_lines.extend(remaining_lines)
|
140
|
+
modified = True
|
141
|
+
|
142
|
+
if modified:
|
143
|
+
try:
|
144
|
+
with open(file_path, "w", encoding="utf-8") as f:
|
145
|
+
f.writelines(new_lines)
|
146
|
+
return True
|
147
|
+
except Exception as e:
|
148
|
+
print(f"Error writing {file_path}: {e}")
|
149
|
+
return False
|
150
|
+
|
151
|
+
return False
|
152
|
+
|
153
|
+
|
154
|
+
def main(*args, **kwargs):
|
155
|
+
"""Automates file header updates for all files in the specified directory."""
|
156
|
+
event = Action(*args, **kwargs)
|
157
|
+
|
158
|
+
if "ultralytics" in event.repository.lower():
|
159
|
+
if event.is_repo_private() and event.repository.startswith("ultralytics/"):
|
160
|
+
from datetime import datetime
|
161
|
+
|
162
|
+
notice = f"Copyright © 2014-{datetime.now().year}"
|
163
|
+
header = f"Ultralytics Inc. 🚀 {notice} - CONFIDENTIAL - https://ultralytics.com - All Rights Reserved"
|
164
|
+
else:
|
165
|
+
header = "Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license"
|
166
|
+
elif HEADER and HEADER.lower() not in {"true", "false", "none"}:
|
167
|
+
header = HEADER
|
168
|
+
else:
|
169
|
+
return
|
170
|
+
|
171
|
+
directory = Path.cwd()
|
172
|
+
total = changed = unchanged = 0
|
173
|
+
for ext, comment_style in COMMENT_MAP.items():
|
174
|
+
prefix, block_start, block_end = comment_style
|
175
|
+
|
176
|
+
for file_path in directory.rglob(f"*{ext}"):
|
177
|
+
if any(part in str(file_path) for part in IGNORE_PATHS):
|
178
|
+
continue
|
179
|
+
|
180
|
+
total += 1
|
181
|
+
if update_file(file_path, prefix, block_start, block_end, header):
|
182
|
+
print(f"Updated: {file_path.relative_to(directory)}")
|
183
|
+
changed += 1
|
184
|
+
else:
|
185
|
+
unchanged += 1
|
186
|
+
|
187
|
+
print(f"Headers: {total}, Updated: {changed}, Unchanged: {unchanged}")
|
188
|
+
|
189
|
+
|
190
|
+
if __name__ == "__main__":
|
191
|
+
main()
|
actions/utils/github_utils.py
CHANGED
@@ -91,6 +91,10 @@ class Action:
|
|
91
91
|
return json.loads(Path(event_path).read_text())
|
92
92
|
return {}
|
93
93
|
|
94
|
+
def is_repo_private(self) -> bool:
|
95
|
+
"""Checks if the repository is public using event data or GitHub API if needed."""
|
96
|
+
return self.event_data.get("repository", {}).get("private")
|
97
|
+
|
94
98
|
def get_username(self) -> str | None:
|
95
99
|
"""Gets username associated with the GitHub token."""
|
96
100
|
response = self.post(GITHUB_GRAPHQL_URL, json={"query": "query { viewer { login } }"})
|
@@ -152,6 +156,7 @@ class Action:
|
|
152
156
|
"github.event_name": self.event_name,
|
153
157
|
"github.event.action": self.event_data.get("action"),
|
154
158
|
"github.repository": self.repository,
|
159
|
+
"github.repository.private": self.is_repo_private(),
|
155
160
|
"github.event.pull_request.number": self.pr.get("number"),
|
156
161
|
"github.event.pull_request.head.repo.full_name": self.pr.get("head", {}).get("repo", {}).get("full_name"),
|
157
162
|
"github.actor": os.environ.get("GITHUB_ACTOR"),
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ultralytics-actions
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.73
|
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>
|
@@ -33,6 +33,7 @@ Requires-Dist: ruff>=0.9.1
|
|
33
33
|
Requires-Dist: docformatter>=1.7.5
|
34
34
|
Provides-Extra: dev
|
35
35
|
Requires-Dist: pytest; extra == "dev"
|
36
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
36
37
|
Dynamic: license-file
|
37
38
|
|
38
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>
|
@@ -42,12 +43,16 @@ Dynamic: license-file
|
|
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
44
|
|
44
45
|
[](https://github.com/marketplace/actions/ultralytics-actions)
|
46
|
+
|
47
|
+
[](https://github.com/ultralytics/actions/actions/workflows/ci.yml)
|
45
48
|
[](https://github.com/ultralytics/actions/actions/workflows/format.yml)
|
49
|
+
[](https://codecov.io/github/ultralytics/actions)
|
50
|
+
[](https://badge.fury.io/py/ultralytics-actions)
|
51
|
+
[](https://www.pepy.tech/projects/ultralytics-actions)
|
52
|
+
|
46
53
|
[](https://discord.com/invite/ultralytics)
|
47
54
|
[](https://community.ultralytics.com/)
|
48
55
|
[](https://reddit.com/r/ultralytics)
|
49
|
-
[](https://badge.fury.io/py/ultralytics-actions)
|
50
|
-
[](https://www.pepy.tech/projects/ultralytics-actions)
|
51
56
|
|
52
57
|
## 📄 Actions Description
|
53
58
|
|
@@ -84,6 +89,11 @@ To integrate this action into your Ultralytics repository:
|
|
84
89
|
2. **Add the Action:** Configure the Ultralytics Actions in your workflow file as shown below:
|
85
90
|
|
86
91
|
```yaml
|
92
|
+
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
|
93
|
+
|
94
|
+
# Ultralytics Actions https://github.com/ultralytics/actions
|
95
|
+
# This workflow formats code and documentation in PRs to Ultralytics standards
|
96
|
+
|
87
97
|
name: Ultralytics Actions
|
88
98
|
|
89
99
|
on:
|
@@ -91,24 +101,31 @@ To integrate this action into your Ultralytics repository:
|
|
91
101
|
types: [opened]
|
92
102
|
pull_request:
|
93
103
|
branches: [main]
|
94
|
-
types: [opened, closed]
|
104
|
+
types: [opened, closed, synchronize, review_requested]
|
105
|
+
|
106
|
+
permissions:
|
107
|
+
contents: write # Modify code in PRs
|
108
|
+
pull-requests: write # Add comments and labels to PRs
|
109
|
+
issues: write # Add comments and labels to issues
|
95
110
|
|
96
111
|
jobs:
|
97
|
-
|
98
|
-
runs-on: ubuntu-latest
|
112
|
+
actions:
|
113
|
+
runs-on: ubuntu-latest
|
99
114
|
steps:
|
100
|
-
- name: Run Ultralytics
|
115
|
+
- name: Run Ultralytics Actions
|
101
116
|
uses: ultralytics/actions@main
|
102
117
|
with:
|
103
|
-
token: ${{ secrets.GITHUB_TOKEN }} #
|
104
|
-
labels: true #
|
105
|
-
python: true # Format Python
|
106
|
-
prettier: true # Format YAML, JSON, Markdown,
|
107
|
-
swift: false # Format Swift
|
118
|
+
token: ${{ secrets.GITHUB_TOKEN }} # Auto-generated token
|
119
|
+
labels: true # Auto-label issues/PRs using AI
|
120
|
+
python: true # Format Python with Ruff and docformatter
|
121
|
+
prettier: true # Format YAML, JSON, Markdown, CSS
|
122
|
+
swift: false # Format Swift (requires macos-latest)
|
123
|
+
dart: false # Format Dart/Flutter
|
108
124
|
spelling: true # Check spelling with codespell
|
109
|
-
links: true # Check
|
110
|
-
summary: true # Generate
|
111
|
-
openai_api_key: ${{ secrets.OPENAI_API_KEY }} #
|
125
|
+
links: true # Check broken links with Lychee
|
126
|
+
summary: true # Generate AI-powered PR summaries
|
127
|
+
openai_api_key: ${{ secrets.OPENAI_API_KEY }} # Powers PR summaries, labels and comments
|
128
|
+
brave_api_key: ${{ secrets.BRAVE_API_KEY }} # Used for broken link resolution
|
112
129
|
```
|
113
130
|
|
114
131
|
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`.
|
@@ -1,16 +1,17 @@
|
|
1
|
-
actions/__init__.py,sha256=
|
1
|
+
actions/__init__.py,sha256=Uq5k3qN5QggBhuBJT9-zO0ROzbZ9h5OCR7MQ-Xl8L0I,742
|
2
2
|
actions/dispatch_actions.py,sha256=vbA4w_B8vMXMen__ck2WoDsUFCELjXOQbpLzZCmqTXg,4240
|
3
3
|
actions/first_interaction.py,sha256=whphdBrWkcWRt6RgOeK2dUoGq3aBTqttQdokxVjkye4,16309
|
4
4
|
actions/summarize_pr.py,sha256=NCaDSbw4PVoRbPJzji_Ua2HadI2pn7QOE_dy3VK9_cc,10463
|
5
5
|
actions/summarize_release.py,sha256=OncODHx7XsmB-nPf-B1tnxUTcaJx6hM4JAMa9frypzM,7922
|
6
|
+
actions/update_file_headers.py,sha256=EltkXfBiWV53NYtAHLtTFRZdO-tXkgx2FPQr8Dp0aOU,6259
|
6
7
|
actions/update_markdown_code_blocks.py,sha256=9PL7YIQfApRNAa0que2hYHv7umGZTZoHlblesB0xFj4,8587
|
7
8
|
actions/utils/__init__.py,sha256=TXYvhFgDeAnosePM4jfOrEd6PlC7tWC-WMOgCB_T6Tw,728
|
8
9
|
actions/utils/common_utils.py,sha256=2eNwGJFigl9bBXcyWzdr8mr97Lrx7zFKWIFYugZcUJw,11736
|
9
|
-
actions/utils/github_utils.py,sha256=
|
10
|
+
actions/utils/github_utils.py,sha256=gdObDzOGmoLl8LXJ-fza7Dr2qLKfDsX2HbpcyFBEMtE,10097
|
10
11
|
actions/utils/openai_utils.py,sha256=09kW4K2LOc6KsWz5tijf2Piinhu3PIKPDVkRC3KyIxU,2943
|
11
|
-
ultralytics_actions-0.0.
|
12
|
-
ultralytics_actions-0.0.
|
13
|
-
ultralytics_actions-0.0.
|
14
|
-
ultralytics_actions-0.0.
|
15
|
-
ultralytics_actions-0.0.
|
16
|
-
ultralytics_actions-0.0.
|
12
|
+
ultralytics_actions-0.0.73.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
|
13
|
+
ultralytics_actions-0.0.73.dist-info/METADATA,sha256=GM-a9l23v5JNXoF837vLh92ZfYbfzg-iz2o_4XC1Les,11638
|
14
|
+
ultralytics_actions-0.0.73.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
|
15
|
+
ultralytics_actions-0.0.73.dist-info/entry_points.txt,sha256=zNOtw1Dh8ItViVO6vKoaCQtWSjk7jw-_MaqGByju4I4,440
|
16
|
+
ultralytics_actions-0.0.73.dist-info/top_level.txt,sha256=5apM5x80QlJcGbACn1v3fkmIuL1-XQCKcItJre7w7Tw,8
|
17
|
+
ultralytics_actions-0.0.73.dist-info/RECORD,,
|
{ultralytics_actions-0.0.72.dist-info → ultralytics_actions-0.0.73.dist-info}/entry_points.txt
RENAMED
@@ -1,5 +1,6 @@
|
|
1
1
|
[console_scripts]
|
2
2
|
ultralytics-actions-first-interaction = actions.first_interaction:main
|
3
|
+
ultralytics-actions-header = actions.update_file_headers:main
|
3
4
|
ultralytics-actions-info = actions.utils:ultralytics_actions_info
|
4
5
|
ultralytics-actions-summarize-pr = actions.summarize_pr:main
|
5
6
|
ultralytics-actions-summarize-release = actions.summarize_release:main
|
{ultralytics_actions-0.0.72.dist-info → ultralytics_actions-0.0.73.dist-info}/licenses/LICENSE
RENAMED
File without changes
|
File without changes
|