11name : Format Files
22
3- # cpp
4- # csharp - https://github.com/dotnet/format ?
5- # java - prettier-plugin-java
6- # javascript - prettier
7- # python - black
8- # ruby - rufo
9- # swift - https://github.com/apple/swift-format ?
10- # typescript - prettier
11-
123on :
134 workflow_dispatch :
14- pull_request_target :
5+ pull_request :
156 types : [opened, synchronize, reopened]
167
8+ permissions :
9+ contents : write # write needed only for same-repo pushes; forks get read-only token automatically
10+
1711jobs :
18- Format :
12+ format :
1913 runs-on : ubuntu-latest
2014
21- strategy :
22- matrix :
23- node-version : [20.x]
24-
2515 steps :
26- - name : Checkout Repository
16+ - name : Checkout PR HEAD
2717 uses : actions/checkout@v4
2818 with :
29- ref : ${{ github.head_ref }}
30- fetch-depth : 1
19+ repository : ${{ github.event.pull_request.head.repo.full_name }}
20+ ref : ${{ github.event.pull_request.head.sha }}
21+ fetch-depth : 0
22+
23+ - name : Detect fork vs same-repo
24+ id : ctx
25+ run : |
26+ if [ "${{ github.event.pull_request.head.repo.full_name }}" = "${{ github.repository }}" ]; then
27+ echo "same_repo=true" >> $GITHUB_OUTPUT
28+ else
29+ echo "same_repo=false" >> $GITHUB_OUTPUT
30+ fi
3131
32- - name : Use Node.js (dependency)
32+ - name : Use Node.js
3333 uses : actions/setup-node@v4
3434 with :
35- node-version : ${{ matrix.node-version }}
35+ node-version : 20
3636
37- - name : Install Rufo (dependency)
37+ - name : Install formatters
3838 run : |
39- sudo apt update
39+ sudo apt-get update
4040 sudo gem install rufo
41-
42- - name : Install Prettier
43- run : |
44- npm install -g prettier
45- npm install -g prettier-plugin-java
46-
41+ npm i -g prettier prettier-plugin-java
4742 - name : Install Black
4843 uses : BSFishy/pip-action@v1
4944 with :
5045 packages : black
5146
52- - name : Format
47+ - name : Run formatters
48+ run : |
49+ set -e
50+ # Use globs; .prettierrc discovered from repo root
51+ prettier --write "javascript/*.js" || true
52+ prettier --write "typescript/*.ts" || true
53+ prettier --write "java/*.java" || true
54+ rufo ruby || true
55+ python -m black . || true
56+
57+ - name : Check for changes
58+ id : diff
59+ run : |
60+ git status --porcelain
61+ if [ -n "$(git status --porcelain)" ]; then
62+ echo "changed=true" >> $GITHUB_OUTPUT
63+ else
64+ echo "changed=false" >> $GITHUB_OUTPUT
65+ fi
66+
67+ # Auto-push only for same-repo PRs
68+ - name : Push formatting changes (same-repo only)
69+ if : steps.ctx.outputs.same_repo == 'true' && steps.diff.outputs.changed == 'true'
70+ run : |
71+ git config user.email "[email protected] " 72+ git config user.name "Bot-A0"
73+ git add -A
74+ git commit -m "🎨 Format files (🛠️ from GitHub Actions)"
75+ git push "https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.event.pull_request.head.repo.full_name }}.git" \
76+ HEAD:refs/heads/${{ github.event.pull_request.head.ref }}
77+ env :
78+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
79+
80+ # For forks, upload a patch artifact the author can apply locally: `git apply formatting.patch`
81+ - name : Create patch (forks only)
82+ if : steps.ctx.outputs.same_repo == 'false' && steps.diff.outputs.changed == 'true'
5383 run : |
54- prettier --config "$GITHUB_WORKSPACE/.prettierrc" --write "$GITHUB_WORKSPACE/javascript/*.js" 2>&1 || true
55- prettier --config "$GITHUB_WORKSPACE/.prettierrc" --write "$GITHUB_WORKSPACE/typescript/*.ts" 2>&1 || true
56- prettier --config "$GITHUB_WORKSPACE/.prettierrc" --write "$GITHUB_WORKSPACE/java/*.java" 2>&1 || true
57- rufo "$GITHUB_WORKSPACE/ruby" 2>&1 || true
58- python -m black "$GITHUB_WORKSPACE/" 2>&1 || true
84+ git diff > formatting.patch
85+ ls -l formatting.patch
86+
87+ - name : Upload patch artifact (forks only)
88+ if : steps.ctx.outputs.same_repo == 'false' && steps.diff.outputs.changed == 'true'
89+ uses : actions/upload-artifact@v4
90+ with :
91+ name : formatting.patch
92+ path : formatting.patch
93+ if-no-files-found : error
94+ retention-days : 7
95+
96+ # Leave a comment with instructions on fork PRs
97+ - name : Comment instructions (forks only)
98+ if : steps.ctx.outputs.same_repo == 'false' && steps.diff.outputs.changed == 'true'
99+ uses : actions/github-script@v7
100+ with :
101+ script : |
102+ const body = [
103+ "I ran the formatters and found changes. Since this is a forked PR, I can't push to your branch.",
104+ "",
105+ "**How to apply the patch:**",
106+ "```bash",
107+ "curl -L -o formatting.patch \"$ACTIONS_ARTIFACT_URL\" # Download from the job's Artifacts section",
108+ "git apply formatting.patch",
109+ "git commit -am \"Apply formatting patch\"",
110+ "git push",
111+ "```",
112+ "",
113+ "Alternatively, run the same formatters locally: `prettier`, `rufo`, and `black`."
114+ ].join("\n");
115+ github.rest.issues.createComment({
116+ owner: context.repo.owner,
117+ repo: context.repo.repo,
118+ issue_number: context.payload.pull_request.number,
119+ body
120+ });
59121
60- - name : Push
122+ # Optional: make CI fail if formatting changes were needed (forces author to accept fixes or patch)
123+ - name : Fail if formatting changes are needed
124+ if : steps.diff.outputs.changed == 'true' && steps.ctx.outputs.same_repo == 'false'
61125 run : |
62- git config --global user.email "[email protected] " 63- git config --global user.name "Bot-A0"
64- git add .
65- git commit -m "🎨 Format files (🛠️ from Github Actions)" || true
66- git push || true
126+ echo "Formatting changes required. Patch uploaded as an artifact."
127+ exit 1
0 commit comments