Skip to content

Commit b8e23c1

Browse files
author
Alvaro Muñoz
authored
Merge pull request #110 from github/ext_prefix
Expect external workflows and actions in .github/workflow/external and .github/actions/external
2 parents d0c761b + 455afc2 commit b8e23c1

File tree

12 files changed

+383
-72
lines changed

12 files changed

+383
-72
lines changed

ql/lib/codeql/actions/Helper.qll

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,12 @@ string getRepoRoot() {
5050
.getRelativePath()
5151
.prefix(w.getLocation().getFile().getRelativePath().indexOf("/.github/workflows") + 1) and
5252
// exclude workflow_enum reusable workflows directory root
53-
not result.indexOf(".github/reusable_workflows/") > -1
53+
not result.indexOf(".github/workflows/external/") > -1 and
54+
not result.indexOf(".github/actions/external/") > -1
5455
or
5556
not w.getLocation().getFile().getRelativePath().indexOf("/.github/workflows") > 0 and
56-
not w.getLocation().getFile().getRelativePath().indexOf(".github/reusable_workflows") > -1 and
57+
not w.getLocation().getFile().getRelativePath().indexOf(".github/workflows/external/") > -1 and
58+
not w.getLocation().getFile().getRelativePath().indexOf(".github/actions/external/") > -1 and
5759
result = ""
5860
)
5961
}

ql/lib/codeql/actions/ast/internal/Ast.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ class CompositeActionImpl extends AstNodeImpl, TCompositeAction {
425425
.replaceAll(getRepoRoot(), "")
426426
.replaceAll("/action.yml", "")
427427
.replaceAll("/action.yaml", "")
428-
.replaceAll(".github/reusable_workflows/", "")
428+
.replaceAll(".github/actions/external/", "")
429429
}
430430

431431
private predicate hasExplicitSecretAccess() {
@@ -550,7 +550,7 @@ class ReusableWorkflowImpl extends AstNodeImpl, WorkflowImpl {
550550
.getFile()
551551
.getRelativePath()
552552
.replaceAll(getRepoRoot(), "")
553-
.replaceAll(".github/reusable_workflows/", "")
553+
.replaceAll(".github/workflows/external/", "")
554554
}
555555
}
556556

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,4 @@ runs:
4444
ref: refs/pull/${{ github.event.number }}/merge
4545
fetch-depth: ${{ inputs.fetch-depth }}
4646

47+
Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
# Ultralytics Actions 🚀, AGPL-3.0 License https://ultralytics.com/license
2+
3+
name: "Ultralytics Actions"
4+
author: "Ultralytics"
5+
description: "Optimize code and docs with official Ultralytics Actions for syntax, spelling, and link checks."
6+
branding:
7+
icon: "code"
8+
color: "blue"
9+
inputs:
10+
token:
11+
description: "GitHub token"
12+
required: true
13+
labels:
14+
description: "Run issue and PR auto-labeling"
15+
required: false
16+
default: "false"
17+
python:
18+
description: "Run Python formatting"
19+
required: false
20+
default: "false"
21+
markdown:
22+
description: "Run Markdown formatting (deprecated in favor of prettier)"
23+
required: false
24+
default: "false"
25+
prettier:
26+
description: "Run Prettier formatting for JavaScript, JSX, Angular, Vue, Flow, TypeScript, CSS, HTML, JSON, GraphQL, Markdown, YAML"
27+
required: false
28+
default: "false"
29+
swift:
30+
description: "Run Swift formatting"
31+
required: false
32+
default: "false"
33+
spelling:
34+
description: "Run Spelling checks"
35+
required: false
36+
default: "false"
37+
links:
38+
description: "Run Broken Links checks"
39+
required: false
40+
default: "false"
41+
summary:
42+
description: "Run PR Summary"
43+
required: false
44+
default: "false"
45+
openai_api_key:
46+
description: "OpenAI API Key"
47+
required: false
48+
openai_model:
49+
description: "OpenAI Model"
50+
required: false
51+
default: "gpt-4o"
52+
first_issue_response:
53+
description: "Example response to a new issue"
54+
required: false
55+
first_pr_response:
56+
description: "Example response to a new PR"
57+
required: false
58+
github_username:
59+
description: "GitHub username for commits"
60+
required: false
61+
default: "UltralyticsAssistant"
62+
github_email:
63+
description: "GitHub email for commits"
64+
required: false
65+
default: "[email protected]"
66+
body:
67+
description: "PR body"
68+
required: false
69+
default: ""
70+
runs:
71+
using: "composite"
72+
steps:
73+
- uses: astral-sh/setup-uv@v3
74+
- name: Install Dependencies
75+
# Note tomli required for codespell with pyproject.toml
76+
# For debug:
77+
# python -m pip install --upgrade pip wheel
78+
# pip install -q git+https://github.com/ultralytics/actions@main codespell tomli
79+
run: |
80+
packages="ultralytics-actions"
81+
if [ "${{ inputs.spelling }}" = "true" ]; then
82+
packages="$packages codespell tomli"
83+
fi
84+
85+
# On macOS, don't use sudo as it can cause environment issues
86+
if [ "$(uname)" = "Darwin" ]; then
87+
pip install -q $packages
88+
else
89+
sudo env "PATH=$PATH" uv pip install --system $packages
90+
fi
91+
92+
ultralytics-actions-info
93+
shell: bash
94+
- shell: bash
95+
run: |
96+
echo "${{ inputs.body }}"
97+
98+
# Checkout Repository ----------------------------------------------------------------------------------------------
99+
- name: Checkout Repository
100+
if: github.event.action != 'closed'
101+
uses: actions/checkout@v4
102+
with:
103+
repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
104+
token: ${{ inputs.token }}
105+
ref: ${{ github.head_ref || github.ref }}
106+
fetch-depth: 0
107+
108+
# PR Summary -------------------------------------------------------------------------------------------------------
109+
- name: PR Summary
110+
if: (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') && inputs.summary == 'true' && github.event.action != 'synchronize'
111+
env:
112+
GITHUB_TOKEN: ${{ inputs.token }}
113+
OPENAI_API_KEY: ${{ inputs.openai_api_key }}
114+
OPENAI_MODEL: ${{ inputs.openai_model }}
115+
run: |
116+
ultralytics-actions-summarize-pr
117+
shell: bash
118+
continue-on-error: true
119+
120+
# Python formatting ------------------------------------------------------------------------------------------------
121+
# Ignores the following Docs rules to match Google-style docstrings:
122+
# D100: Missing docstring in public module
123+
# D104: Missing docstring in public package
124+
# D203: 1 blank line required before class docstring
125+
# D205: 1 blank line required between summary line and description
126+
# D212: Multi-line docstring summary should start at the first line
127+
# D213: Multi-line docstring summary should start at the second line
128+
# D401: First line of docstring should be in imperative mood
129+
# D406: Section name should end with a newline
130+
# D407: Missing dashed underline after section
131+
# D413: Missing blank line after last section
132+
# --target-version is Python 3.8 for --extend-select UP (pyupgrade)
133+
- name: Run Python
134+
if: (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') && inputs.python == 'true' && github.event.action != 'closed'
135+
run: |
136+
ruff format \
137+
--line-length 120 \
138+
. || true
139+
ruff check \
140+
--fix \
141+
--unsafe-fixes \
142+
--extend-select I,D,UP \
143+
--target-version py38 \
144+
--ignore D100,D104,D203,D205,D212,D213,D401,D406,D407,D413 \
145+
. || true
146+
docformatter \
147+
--wrap-summaries 120 \
148+
--wrap-descriptions 120 \
149+
--pre-summary-newline \
150+
--close-quotes-on-newline \
151+
--in-place \
152+
--recursive \
153+
.
154+
shell: bash
155+
continue-on-error: true
156+
157+
# Prettier (JavaScript, JSX, Angular, Vue, Flow, TypeScript, CSS, HTML, JSON, GraphQL, Markdown, YAML) -------------
158+
- name: Run Prettier
159+
if: (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') && (inputs.prettier == 'true' || inputs.markdown == 'true') && github.event.action != 'closed'
160+
run: |
161+
ultralytics-actions-update-markdown-code-blocks
162+
npm install --global prettier
163+
npx prettier --write "**/*.{js,jsx,ts,tsx,css,less,scss,json,yml,yaml,html,vue,svelte}" '!**/*lock.{json,yaml,yml}' '!**/*.lock' '!**/model.json'
164+
# Handle Markdown separately
165+
find . -name "*.md" ! -path "*/docs/*" -exec npx prettier --write {} +
166+
if [ -d "./docs" ]; then
167+
find ./docs -name "*.md" ! -path "*/reference/*" -exec npx prettier --tab-width 4 --write {} +
168+
fi
169+
shell: bash
170+
continue-on-error: true
171+
172+
# - name: Fix MkDocs reference section changes
173+
# if: (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') && (inputs.prettier == 'true' || inputs.markdown == 'true') && github.event.action != 'closed'
174+
# run: |
175+
# from pathlib import Path
176+
# for file in Path("./docs").rglob('*.md'):
177+
# content = file.read_text()
178+
# updated_content = content.replace(".\_","._")
179+
# file.write_text(updated_content)
180+
# shell: python
181+
# continue-on-error: true
182+
183+
# Swift formatting -------------------------------------------------------------------------------------------------
184+
- name: Run Swift Formatter
185+
if: (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') && inputs.swift == 'true' && github.event.action != 'closed'
186+
run: |
187+
brew install swift-format
188+
swift-format --in-place --recursive .
189+
shell: bash
190+
continue-on-error: true
191+
192+
# Spelling ---------------------------------------------------------------------------------------------------------
193+
- name: Run Codespell
194+
if: (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') && inputs.spelling == 'true' && github.event.action != 'closed'
195+
run: |
196+
codespell \
197+
--write-changes \
198+
--ignore-words-list "crate,nd,ned,strack,dota,ane,segway,fo,gool,winn,commend,bloc,nam,afterall,skelton,goin" \
199+
--skip "*.pt,*.pth,*.torchscript,*.onnx,*.tflite,*.pb,*.bin,*.param,*.mlmodel,*.engine,*.npy,*.data*,*.csv,*pnnx*,*venv*,*translat*,*lock*,__pycache__*,*.ico,*.jpg,*.png,*.mp4,*.mov,/runs,/.git,./docs/??/*.md,./docs/mkdocs_??.yml"
200+
shell: bash
201+
continue-on-error: true
202+
203+
# Autolabel Issues and PRs (run before commit changes in case commit fails) ----------------------------------------
204+
- name: Autolabel Issues and PRs
205+
if: inputs.labels == 'true' && (github.event.action == 'opened' || github.event.action == 'created')
206+
env:
207+
GITHUB_TOKEN: ${{ inputs.token }}
208+
FIRST_ISSUE_RESPONSE: ${{ inputs.first_issue_response }}
209+
FIRST_PR_RESPONSE: ${{ inputs.first_pr_response }}
210+
OPENAI_API_KEY: ${{ inputs.openai_api_key }}
211+
OPENAI_MODEL: ${{ inputs.openai_model }}
212+
run: |
213+
ultralytics-actions-first-interaction
214+
shell: bash
215+
continue-on-error: true
216+
217+
# Commit Changes ---------------------------------------------------------------------------------------------------
218+
- name: Commit and Push Changes
219+
if: (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') && github.event.action != 'closed'
220+
run: |
221+
git config --global user.name "${{ inputs.github_username }}"
222+
git config --global user.email "${{ inputs.github_email }}"
223+
git pull origin ${{ github.head_ref || github.ref }}
224+
git add .
225+
git reset HEAD -- .github/workflows/ # workflow changes are not permitted with default token
226+
if ! git diff --staged --quiet; then
227+
git commit -m "Auto-format by https://ultralytics.com/actions"
228+
git push
229+
else
230+
echo "No changes to commit"
231+
fi
232+
shell: bash
233+
continue-on-error: false
234+
235+
# Broken links -----------------------------------------------------------------------------------------------------
236+
- name: Broken Link Checker
237+
if: inputs.links == 'true' && github.event.action != 'closed'
238+
uses: lycheeverse/[email protected]
239+
with:
240+
# Check all markdown and html files in repo. Ignores the following status codes to reduce false positives:
241+
# - 403(OpenVINO, "forbidden")
242+
# - 429(Instagram, "too many requests")
243+
# - 500(Zenodo, "cached")
244+
# - 502(Zenodo, "bad gateway")
245+
# - 999(LinkedIn, "unknown status code")
246+
args: |
247+
--scheme https
248+
--timeout 60
249+
--insecure
250+
--accept 403,429,500,502,999
251+
--exclude-all-private
252+
--exclude "https?://(www\.)?(github\.com|linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)"
253+
"./**/*.md"
254+
"./**/*.html"
255+
token: ${{ inputs.token }}
256+
output: ../lychee/results.md
257+
fail: true
258+
continue-on-error: false
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Ultralytics 🚀 - AGPL-3.0 License https://ultralytics.com/license
2+
# Ultralytics Actions https://github.com/ultralytics/actions
3+
# This workflow automatically formats code and documentation in PRs to official Ultralytics standards
4+
5+
name: Ultralytics Actions
6+
7+
on:
8+
issues:
9+
types: [opened, edited]
10+
discussion:
11+
types: [created]
12+
pull_request_target:
13+
branches: [main]
14+
types: [opened, closed, synchronize, review_requested]
15+
16+
permissions:
17+
contents: write
18+
19+
jobs:
20+
format:
21+
runs-on: ubuntu-latest
22+
steps:
23+
- name: Run Ultralytics Formatting
24+
uses: ultralytics/actions@main
25+
with:
26+
token: ${{ secrets._GITHUB_TOKEN }} # note GITHUB_TOKEN automatically generated
27+
labels: true # autolabel issues and PRs
28+
python: true # format Python code and docstrings
29+
prettier: true # format YAML, JSON, Markdown and CSS
30+
spelling: true # check spelling
31+
links: false # check broken links
32+
summary: true # print PR summary with GPT4o (requires 'openai_api_key')
33+
openai_api_key: ${{ secrets.OPENAI_API_KEY }}
34+
first_issue_response: "foo"
35+
body: ${{ github.event.pull_request.body }}
36+

0 commit comments

Comments
 (0)