Skip to content

Commit a335a70

Browse files
Zachary-wWclaude
andcommitted
ci: trigger internal CI from PR comments
Add the internal CI workflow behind an explicit PR comment command and allow PR authors to trigger both internal CI and Claude review. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 9aa7abc commit a335a70

2 files changed

Lines changed: 249 additions & 1 deletion

File tree

.github/workflows/claude-review.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ jobs:
2222
github.event_name == 'issue_comment' &&
2323
github.event.issue.pull_request &&
2424
github.event.comment.body == '/claude-review' &&
25-
contains(fromJSON('["OWNER","MEMBER","COLLABORATOR","CONTRIBUTOR"]'), github.event.comment.author_association)
25+
(
26+
contains(fromJSON('["OWNER","MEMBER","COLLABORATOR","CONTRIBUTOR"]'), github.event.comment.author_association) ||
27+
github.event.comment.user.login == github.event.issue.user.login
28+
)
2629
)
2730
runs-on: [self-hosted, macOS, ARM64]
2831
timeout-minutes: 15

.github/workflows/internal-ci.yml

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
name: LoongForge Internal CI
2+
3+
on:
4+
issue_comment:
5+
types: [created]
6+
workflow_dispatch:
7+
inputs:
8+
pr_number:
9+
description: 'PR number (for manual trigger)'
10+
required: false
11+
12+
permissions:
13+
contents: read
14+
pull-requests: read
15+
16+
concurrency:
17+
group: internal-ci-pr-${{ github.event.issue.number || inputs.pr_number || github.run_id }}
18+
cancel-in-progress: true
19+
20+
jobs:
21+
build-and-notify:
22+
if: >-
23+
github.event_name == 'workflow_dispatch' ||
24+
(
25+
github.event_name == 'issue_comment' &&
26+
github.event.issue.pull_request &&
27+
github.event.comment.body == '/loongforge-ci' &&
28+
(
29+
contains(fromJSON('["OWNER","MEMBER","COLLABORATOR","CONTRIBUTOR"]'), github.event.comment.author_association) ||
30+
github.event.comment.user.login == github.event.issue.user.login
31+
)
32+
)
33+
runs-on: [self-hosted, Linux, X64]
34+
steps:
35+
- name: Load config
36+
run: |
37+
set -euo pipefail
38+
39+
CONFIG_FILE=/home/users/weizhihao/loongforge-ci/.env
40+
if [ ! -f "$CONFIG_FILE" ]; then
41+
echo "配置文件不存在: $CONFIG_FILE"
42+
echo "请先在 017 上创建该文件"
43+
exit 1
44+
fi
45+
46+
while IFS= read -r line || [ -n "$line" ]; do
47+
case "$line" in
48+
''|'#'*) continue ;;
49+
esac
50+
51+
key="${line%%=*}"
52+
value="${line#*=}"
53+
if ! printf '%s' "$key" | grep -Eq '^[A-Za-z_][A-Za-z0-9_]*$'; then
54+
echo "配置项名称非法: $key"
55+
exit 1
56+
fi
57+
58+
echo "::add-mask::$value"
59+
printf '%s=%s\n' "$key" "$value" >> "$GITHUB_ENV"
60+
done < "$CONFIG_FILE"
61+
62+
echo "配置已加载"
63+
64+
- name: Get PR info
65+
id: pr-info
66+
env:
67+
GH_TOKEN: ${{ github.token }}
68+
run: |
69+
set -euo pipefail
70+
71+
if [ "${{ github.event_name }}" = "issue_comment" ]; then
72+
PR_NUM="${{ github.event.issue.number }}"
73+
elif [ -n "${{ inputs.pr_number }}" ]; then
74+
PR_NUM="${{ inputs.pr_number }}"
75+
else
76+
echo "No PR number found"
77+
exit 1
78+
fi
79+
80+
PR_DATA=$(gh pr view "$PR_NUM" --json headRefOid,headRefName --repo "$GITHUB_REPOSITORY")
81+
BRANCH=$(printf '%s' "$PR_DATA" | jq -r '.headRefName')
82+
HEAD_SHA=$(printf '%s' "$PR_DATA" | jq -r '.headRefOid')
83+
84+
if ! printf '%s' "$PR_NUM" | grep -Eq '^[0-9]+$'; then
85+
echo "Invalid PR number: $PR_NUM"
86+
exit 1
87+
fi
88+
89+
SHA7=$(printf '%s' "$HEAD_SHA" | cut -c1-7)
90+
TIMESTAMP=$(date +%s)
91+
SAFE_BRANCH=$(printf '%s' "$BRANCH" | sed 's#[^A-Za-z0-9._-]#_#g' | cut -c1-120)
92+
93+
echo "pr_num=$PR_NUM" >> "$GITHUB_OUTPUT"
94+
echo "branch=$BRANCH" >> "$GITHUB_OUTPUT"
95+
echo "safe_branch=$SAFE_BRANCH" >> "$GITHUB_OUTPUT"
96+
echo "head_sha=$HEAD_SHA" >> "$GITHUB_OUTPUT"
97+
echo "sha7=$SHA7" >> "$GITHUB_OUTPUT"
98+
echo "timestamp=$TIMESTAMP" >> "$GITHUB_OUTPUT"
99+
echo "PR #$PR_NUM, branch=$BRANCH, sha7=$SHA7"
100+
101+
- name: Checkout PR code
102+
env:
103+
GH_TOKEN: ${{ github.token }}
104+
PR_NUM: ${{ steps.pr-info.outputs.pr_num }}
105+
run: |
106+
set -euo pipefail
107+
108+
mkdir -p "$GITHUB_WORKSPACE"
109+
find "$GITHUB_WORKSPACE" -mindepth 1 -maxdepth 1 -exec rm -rf {} +
110+
111+
git init "$GITHUB_WORKSPACE"
112+
git -C "$GITHUB_WORKSPACE" remote add origin "https://github.com/$GITHUB_REPOSITORY.git"
113+
git -C "$GITHUB_WORKSPACE" config --local gc.auto 0
114+
115+
AUTH_HEADER=$(printf 'x-access-token:%s' "$GH_TOKEN" | base64 | tr -d '\n')
116+
git -C "$GITHUB_WORKSPACE" \
117+
-c "http.https://github.com/.extraheader=AUTHORIZATION: basic $AUTH_HEADER" \
118+
fetch --no-tags origin "+refs/pull/${PR_NUM}/head:refs/remotes/origin/pr/${PR_NUM}"
119+
git -C "$GITHUB_WORKSPACE" checkout --force "refs/remotes/origin/pr/${PR_NUM}"
120+
git -C "$GITHUB_WORKSPACE" remote set-url origin "https://github.com/$GITHUB_REPOSITORY.git"
121+
git -C "$GITHUB_WORKSPACE" \
122+
-c "http.https://github.com/.extraheader=AUTHORIZATION: basic $AUTH_HEADER" \
123+
submodule update --init --recursive third_party/Loong-Megatron
124+
125+
- name: Repack code
126+
id: repack
127+
run: |
128+
set -euo pipefail
129+
130+
PR_NUM="${{ steps.pr-info.outputs.pr_num }}"
131+
STAGING_DIR="/tmp/loongforge_ci_${PR_NUM}"
132+
OUTPUT_FILE="/tmp/LoongForge_pr${PR_NUM}.tar.gz"
133+
MEGATRON_SHA=$(git ls-tree HEAD third_party/Loong-Megatron 2>/dev/null | awk '{print $3}')
134+
echo "Loong-Megatron SHA: ${MEGATRON_SHA:-not found}"
135+
136+
rm -rf "$STAGING_DIR"
137+
mkdir -p "$STAGING_DIR/LoongForge"
138+
139+
rsync -a --exclude='.git' --exclude='third_party/Loong-Megatron' ./ "$STAGING_DIR/LoongForge/"
140+
141+
TAR_INPUTS="LoongForge/"
142+
if [ -d "third_party/Loong-Megatron" ]; then
143+
rsync -a --exclude='.git' ./third_party/Loong-Megatron/ "$STAGING_DIR/Loong-Megatron/"
144+
TAR_INPUTS="$TAR_INPUTS Loong-Megatron/"
145+
else
146+
echo "警告:third_party/Loong-Megatron 不存在,跳过"
147+
fi
148+
149+
tar -czf "$OUTPUT_FILE" -C "$STAGING_DIR" $TAR_INPUTS
150+
151+
SIZE=$(du -h "$OUTPUT_FILE" | cut -f1)
152+
echo "Package size: $SIZE"
153+
echo "output_file=$OUTPUT_FILE" >> "$GITHUB_OUTPUT"
154+
155+
- name: Upload to BOS
156+
id: upload
157+
run: |
158+
set -euo pipefail
159+
160+
: "${BOS_BUCKET:?BOS_BUCKET is required}"
161+
: "${BOS_PATH_PREFIX:?BOS_PATH_PREFIX is required}"
162+
163+
BOS_PREFIX="${BOS_PATH_PREFIX%/}"
164+
BOS_PATH="$BOS_PREFIX/${{ steps.pr-info.outputs.safe_branch }}-${{ steps.pr-info.outputs.sha7 }}-${{ steps.pr-info.outputs.timestamp }}/LoongForge.tar.gz"
165+
OUTPUT_FILE="${{ steps.repack.outputs.output_file }}"
166+
167+
bcecmd bos put "$OUTPUT_FILE" "bos:/$BOS_BUCKET/$BOS_PATH"
168+
169+
BOS_URL="https://$BOS_BUCKET.bj.bcebos.com/$BOS_PATH"
170+
echo "bos_url=$BOS_URL" >> "$GITHUB_OUTPUT"
171+
echo "Uploaded to: $BOS_URL"
172+
173+
- name: Write CI trigger signal
174+
run: |
175+
set -euo pipefail
176+
177+
: "${BOS_BUCKET:?BOS_BUCKET is required}"
178+
: "${BOS_PATH_PREFIX:?BOS_PATH_PREFIX is required}"
179+
180+
PR_NUM="${{ steps.pr-info.outputs.pr_num }}"
181+
BRANCH="${{ steps.pr-info.outputs.branch }}"
182+
SHA7="${{ steps.pr-info.outputs.sha7 }}"
183+
TIMESTAMP="${{ steps.pr-info.outputs.timestamp }}"
184+
BOS_URL="${{ steps.upload.outputs.bos_url }}"
185+
BOS_PREFIX="${BOS_PATH_PREFIX%/}"
186+
187+
jq -n \
188+
--argjson pr_number "$PR_NUM" \
189+
--arg branch "$BRANCH" \
190+
--arg sha7 "$SHA7" \
191+
--arg timestamp "$TIMESTAMP" \
192+
--arg bos_url "$BOS_URL" \
193+
--arg updated_at "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
194+
'{pr_number:$pr_number,branch:$branch,sha7:$sha7,timestamp:$timestamp,bos_url:$bos_url,status:"pending",updated_at:$updated_at}' \
195+
> /tmp/ci_trigger.json
196+
197+
bcecmd bos put /tmp/ci_trigger.json "bos:/$BOS_BUCKET/$BOS_PREFIX/ci_trigger_pr${PR_NUM}.json"
198+
199+
echo "CI trigger signal uploaded"
200+
201+
- name: Notify via Ruliu group
202+
if: always()
203+
run: |
204+
PR_NUM="${{ steps.pr-info.outputs.pr_num }}"
205+
BRANCH="${{ steps.pr-info.outputs.branch }}"
206+
SHA7="${{ steps.pr-info.outputs.sha7 }}"
207+
BOS_URL="${{ steps.upload.outputs.bos_url }}"
208+
STATUS="打包上传成功"
209+
210+
if [ -z "$BOS_URL" ]; then
211+
STATUS="打包上传失败"
212+
BOS_URL="N/A"
213+
fi
214+
215+
if [ -z "${RULIU_WEBHOOK:-}" ]; then
216+
echo "RULIU_WEBHOOK 未配置,跳过通知"
217+
exit 0
218+
fi
219+
220+
CONTENT=$(cat <<EOF
221+
##### LoongForge CI 通知
222+
**PR**: #${PR_NUM:-N/A}
223+
**Branch**: ${BRANCH:-N/A}
224+
**Commit**: ${SHA7:-N/A}
225+
**状态**: ${STATUS}
226+
**BOS_URL**: ${BOS_URL}
227+
228+
dodo 将自动触发内部流水线,请稍候...
229+
EOF
230+
)
231+
PAYLOAD=$(jq -n --arg content "$CONTENT" '{message:{body:[{type:"MD",content:$content}]}}')
232+
233+
curl -sS -X POST "$RULIU_WEBHOOK" \
234+
-H 'Content-Type: application/json' \
235+
-d "$PAYLOAD" || echo "如流通知发送失败(不影响主流程)"
236+
237+
- name: Cleanup
238+
if: always()
239+
run: |
240+
PR_NUM="${{ steps.pr-info.outputs.pr_num }}"
241+
if [ -n "$PR_NUM" ]; then
242+
rm -rf "/tmp/loongforge_ci_${PR_NUM}"
243+
rm -f "/tmp/LoongForge_pr${PR_NUM}.tar.gz"
244+
fi
245+
rm -f /tmp/ci_trigger.json

0 commit comments

Comments
 (0)