@@ -3,6 +3,16 @@ name: "[OpenAEV] Copilot On-Demand Review"
33on :
44 issue_comment :
55 types : [created]
6+ workflow_dispatch :
7+ inputs :
8+ command :
9+ description : " Review command to simulate (e.g. 'security', 'perf', 'all', or empty for general)"
10+ required : false
11+ default : " "
12+ dry_run :
13+ description : " Dry run — only parse and log, no PR comments"
14+ type : boolean
15+ default : true
616
717permissions :
818 contents : read
@@ -13,45 +23,88 @@ jobs:
1323 on-demand-review :
1424 name : " 🤖 On-demand agent review"
1525 if : >-
16- github.event.issue.pull_request &&
17- startsWith(github.event.comment.body, '/review')
26+ github.event_name == 'workflow_dispatch' ||
27+ (github.event.issue.pull_request &&
28+ startsWith(github.event.comment.body, '/review'))
1829 runs-on : ubuntu-latest
1930 steps :
2031 - name : Parse review command
2132 id : parse
2233 env :
23- COMMENT : ${{ github.event.comment.body }}
34+ COMMENT : ${{ github.event.comment.body || format('/review {0}', github.event.inputs.command) }}
35+ DRY_RUN : ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.dry_run == 'true' }}
2436 run : |
25- AGENT=" "
26-
27- case "$COMMENT" in
28- */review\ security*) AGENT="security-reviewer" ;;
29- */review\ perf*) AGENT="performance-reviewer" ;;
30- */review\ tenancy* ) AGENT="multi-tenancy -reviewer" ;;
31- */review\ test* ) AGENT="test-specialist " ;;
32- */review\ frontend* ) AGENT="frontend -reviewer" ;;
33- */review\ all*) AGENT="all " ;;
34- *)
35- echo "Unknown review command: $COMMENT"
36- AGENT="unknown"
37- ;;
37+ # Trim and extract the sub-command after "/review "
38+ SUB="${COMMENT#/review}"
39+ SUB="$(echo "$SUB" | xargs)" # trim whitespace
40+
41+ case "$SUB" in
42+ ""|code ) AGENT="code -reviewer" ;;
43+ security ) AGENT="security-reviewer " ;;
44+ perf|performance ) AGENT="performance -reviewer" ;;
45+ tenancy|multi-tenancy) AGENT="multi-tenancy-reviewer " ;;
46+ test|tests) AGENT="test-specialist" ;;
47+ frontend) AGENT="frontend-reviewer" ;;
48+ all) AGENT="all" ;;
49+ *) AGENT="unknown" ;;
3850 esac
3951
4052 echo "agent=$AGENT" >> "$GITHUB_OUTPUT"
53+ echo "dry_run=$DRY_RUN" >> "$GITHUB_OUTPUT"
54+
55+ echo "### 🔍 Parsed command" >> "$GITHUB_STEP_SUMMARY"
56+ echo "| Field | Value |" >> "$GITHUB_STEP_SUMMARY"
57+ echo "|---|---|" >> "$GITHUB_STEP_SUMMARY"
58+ echo "| Raw comment | \`$COMMENT\` |" >> "$GITHUB_STEP_SUMMARY"
59+ echo "| Sub-command | \`$SUB\` |" >> "$GITHUB_STEP_SUMMARY"
60+ echo "| Resolved agent | \`$AGENT\` |" >> "$GITHUB_STEP_SUMMARY"
61+ echo "| Dry run | \`$DRY_RUN\` |" >> "$GITHUB_STEP_SUMMARY"
62+
63+ - name : Reject unknown command
64+ if : steps.parse.outputs.agent == 'unknown' && steps.parse.outputs.dry_run != 'true'
65+ uses : actions/github-script@v7
66+ with :
67+ script : |
68+ await github.rest.reactions.createForIssueComment({
69+ owner: context.repo.owner,
70+ repo: context.repo.repo,
71+ comment_id: context.payload.comment.id,
72+ content: 'confused',
73+ });
74+
75+ await github.rest.issues.createComment({
76+ owner: context.repo.owner,
77+ repo: context.repo.repo,
78+ issue_number: context.issue.number,
79+ body: [
80+ '❓ Unknown review command. Available commands:',
81+ '',
82+ '| Command | Agent |',
83+ '|---|---|',
84+ '| `/review` | 🔍 General Code Reviewer |',
85+ '| `/review security` | 🔒 Security Reviewer |',
86+ '| `/review perf` | ⚡ Performance Reviewer |',
87+ '| `/review tenancy` | 🏠 Multi-Tenancy Reviewer |',
88+ '| `/review tests` | 🧪 Test Specialist |',
89+ '| `/review frontend` | 🎨 Frontend Reviewer |',
90+ '| `/review all` | All agents |',
91+ ].join('\n'),
92+ });
4193
4294 - name : Acknowledge command
43- if : steps.parse.outputs.agent != 'unknown'
95+ if : steps.parse.outputs.agent != 'unknown' && steps.parse.outputs.dry_run != 'true'
4496 uses : actions/github-script@v7
4597 with :
4698 script : |
4799 const agent = '${{ steps.parse.outputs.agent }}';
48100 const agentNames = {
49- 'security-reviewer': '🔒 Security Reviewer',
50- 'performance-reviewer': '⚡ Performance Reviewer',
51- 'multi-tenancy-reviewer': '🏠 Multi-Tenancy Reviewer',
52- 'test-specialist': '🧪 Test Specialist',
53- 'frontend-reviewer': '🎨 Frontend Reviewer',
54- 'all': '🔒⚡🏠🧪🎨 All Agents',
101+ 'code-reviewer': '🔍 General Code Reviewer',
102+ 'security-reviewer': '🔒 Security Reviewer',
103+ 'performance-reviewer': '⚡ Performance Reviewer',
104+ 'multi-tenancy-reviewer': '🏠 Multi-Tenancy Reviewer',
105+ 'test-specialist': '🧪 Test Specialist',
106+ 'frontend-reviewer': '🎨 Frontend Reviewer',
107+ 'all': '🔍🔒⚡🏠🧪🎨 All Agents',
55108 };
56109
57110 await github.rest.reactions.createForIssueComment({
@@ -65,29 +118,73 @@ jobs:
65118 owner: context.repo.owner,
66119 repo: context.repo.repo,
67120 issue_number: context.issue.number,
68- body: `🤖 **${agentNames[agent] || agent }** review requested by @${context.payload.comment.user.login}.\n\n> Agent will analyze the PR and post findings as a review comment.`,
121+ body: `🤖 **${agentNames[agent]}** review requested by @${context.payload.comment.user.login}.\n\n> Agent will analyze the PR and post findings as a review comment.`,
69122 });
70123
71- - name : Unknown command
72- if : steps.parse.outputs.agent == 'unknown'
124+ - name : Request Copilot review
125+ if : steps.parse.outputs.agent != 'unknown' && steps.parse.outputs.dry_run != 'true '
73126 uses : actions/github-script@v7
74127 with :
75128 script : |
129+ const prNumber = context.issue.number;
130+
131+ await github.rest.pulls.requestReviewers({
132+ owner: context.repo.owner,
133+ repo: context.repo.repo,
134+ pull_number: prNumber,
135+ reviewers: ['copilot'],
136+ });
137+
138+ - name : Run single-agent review
139+ if : steps.parse.outputs.agent != 'unknown' && steps.parse.outputs.agent != 'all' && steps.parse.outputs.dry_run != 'true'
140+ uses : actions/github-script@v7
141+ with :
142+ script : |
143+ const agent = '${{ steps.parse.outputs.agent }}';
76144 await github.rest.issues.createComment({
77145 owner: context.repo.owner,
78146 repo: context.repo.repo,
79147 issue_number: context.issue.number,
80- body: [
81- '❓ Unknown review command. Available commands:',
82- '',
83- '| Command | Agent |',
84- '|---|---|',
85- '| `/review security` | 🔒 Security Reviewer |',
86- '| `/review perf` | ⚡ Performance Reviewer |',
87- '| `/review tenancy` | 🏠 Multi-Tenancy Reviewer |',
88- '| `/review tests` | 🧪 Test Specialist |',
89- '| `/review frontend` | 🎨 Frontend Reviewer |',
90- '| `/review all` | All agents |',
91- ].join('\n'),
148+ body: `@copilot Please review this PR following the instructions in \`.github/agents/${agent}.agent.md\`.`,
92149 });
93150
151+ - name : Run all-agents review
152+ if : steps.parse.outputs.agent == 'all' && steps.parse.outputs.dry_run != 'true'
153+ uses : actions/github-script@v7
154+ with :
155+ script : |
156+ const agents = [
157+ 'code-reviewer',
158+ 'security-reviewer',
159+ 'performance-reviewer',
160+ 'multi-tenancy-reviewer',
161+ 'test-specialist',
162+ 'frontend-reviewer',
163+ ];
164+ const prNumber = context.issue.number;
165+
166+ for (const agent of agents) {
167+ await github.rest.issues.createComment({
168+ owner: context.repo.owner,
169+ repo: context.repo.repo,
170+ issue_number: prNumber,
171+ body: `@copilot Please review this PR following the instructions in \`.github/agents/${agent}.agent.md\`.`,
172+ });
173+ await new Promise(r => setTimeout(r, 2000));
174+ }
175+
176+ - name : Dry run summary
177+ if : steps.parse.outputs.dry_run == 'true'
178+ env :
179+ AGENT : ${{ steps.parse.outputs.agent }}
180+ run : |
181+ echo "### 🧪 Dry run complete" >> "$GITHUB_STEP_SUMMARY"
182+ echo "" >> "$GITHUB_STEP_SUMMARY"
183+ if [ "$AGENT" = "unknown" ]; then
184+ echo "❌ Command would be **rejected** (unknown agent)" >> "$GITHUB_STEP_SUMMARY"
185+ elif [ "$AGENT" = "all" ]; then
186+ echo "✅ Would trigger **all 6 agents**: code-reviewer, security-reviewer, performance-reviewer, multi-tenancy-reviewer, test-specialist, frontend-reviewer" >> "$GITHUB_STEP_SUMMARY"
187+ else
188+ echo "✅ Would trigger agent: **$AGENT**" >> "$GITHUB_STEP_SUMMARY"
189+ fi
190+
0 commit comments