@@ -20,7 +20,7 @@ concurrency:
2020 cancel-in-progress : false
2121
2222jobs :
23- claude :
23+ setup :
2424 # Security-focused conditional execution (full support for Issues and PRs)
2525 if : |
2626 (
@@ -69,31 +69,39 @@ jobs:
6969
7070 runs-on : ubuntu-latest
7171 timeout-minutes : 15
72-
7372 permissions :
7473 # 📁 Content management (highest permissions)
7574 contents : write
7675 pull-requests : write
7776 issues : write
7877 discussions : write
79-
8078 # 🔧 Development & CI/CD management
8179 actions : write
8280 checks : write
8381 statuses : write
8482 pages : write
8583 deployments : write
86-
8784 # 📦 Package & security management
8885 packages : write
8986 security-events : write
90-
9187 # 🎯 Project management
9288 repository-projects : write
93-
9489 # 🆔 Authentication & token management
9590 id-token : write
96-
91+ # Outputs
92+ outputs :
93+ should-continue : ${{ steps.should-continue.outputs.should-continue }}
94+ issue-number : ${{ steps.context-info.outputs.issue-number }}
95+ pr-number : ${{ steps.context-info.outputs.pr-number }}
96+ head-ref : ${{ steps.context-info.outputs.head-ref }}
97+ base-ref : ${{ steps.context-info.outputs.base-ref }}
98+ head-sha : ${{ steps.context-info.outputs.head-sha }}
99+ is-pr : ${{ steps.context-info.outputs.is-pr }}
100+ trigger-text : ${{ steps.context-info.outputs.trigger-text }}
101+ has-linked-pr : ${{ steps.context-info.outputs.has-linked-pr }}
102+ # #####################
103+ # Setup steps
104+ # #####################
97105 steps :
98106 - name : Get Context Information
99107 id : context-info
@@ -255,33 +263,73 @@ jobs:
255263
256264 echo "✅ Environment validation complete"
257265
266+ - name : Exit early if Issue already has linked PR
267+ id : should-continue
268+ run : |
269+ IS_PR="${{ steps.context-info.outputs.is-pr }}"
270+ HAS_LINKED_PR="${{ steps.context-info.outputs.has-linked-pr }}"
271+
272+ if [[ "$IS_PR" == "false" && "$HAS_LINKED_PR" == "true" ]]; then
273+ echo "Issue already has linked PR. Will skip remaining steps."
274+ echo "should-continue=false" >> $GITHUB_OUTPUT
275+ else
276+ echo "No linked PRs found or this is a PR. Continuing."
277+ echo "should-continue=true" >> $GITHUB_OUTPUT
278+ fi
279+
280+ # ########################################################
281+ # Claude Code
282+ # ########################################################
283+ claude :
284+ needs : setup
285+ # Security-focused conditional execution (full support for Issues and PRs)
286+ if : needs.setup.outputs.should-continue == 'true'
287+ runs-on : ubuntu-latest
288+ timeout-minutes : 15
289+ permissions :
290+ # 📁 Content management (highest permissions)
291+ contents : write
292+ pull-requests : write
293+ issues : write
294+ discussions : write
295+
296+ # 🔧 Development & CI/CD management
297+ actions : write
298+ checks : write
299+ statuses : write
300+ pages : write
301+ deployments : write
302+
303+ # 📦 Package & security management
304+ packages : write
305+ security-events : write
306+
307+ # 🎯 Project management
308+ repository-projects : write
309+
310+ # 🆔 Authentication & token management
311+ id-token : write
312+
313+ steps :
258314 - name : Checkout Repository
259315 uses : actions/checkout@v4
260316 with :
261317 # Checkout the feature branch for PRs, or the default branch for Issues
262- ref : ${{ steps.context-info .outputs.head-sha || github.ref }}
263- fetch-depth : ${{ steps.context-info .outputs.is-pr == 'true' && 0 || 1 }}
318+ ref : ${{ needs.setup.outputs .outputs.head-sha || github.ref }}
319+ fetch-depth : ${{ needs.setup.outputs .outputs.is-pr == 'true' && 0 || 1 }}
264320 token : ${{ secrets.GITHUB_TOKEN }}
265321
266322 - name : Fetch Base Branch (PR only)
267- if : steps.context-info .outputs.is-pr == 'true' && steps.context-info .outputs.base-ref
323+ if : needs.setup .outputs.outputs. is-pr == 'true' && needs.setup.outputs .outputs.base-ref
268324 run : |
269- echo "📥 Fetching base branch: ${{ steps.context-info .outputs.base-ref }}"
270- git fetch origin ${{ steps.context-info .outputs.base-ref }}:${{ steps.context-info .outputs.base-ref }}
325+ echo "📥 Fetching base branch: ${{ needs.setup.outputs .outputs.base-ref }}"
326+ git fetch origin ${{ needs.setup .outputs.outputs. base-ref }}:${{ needs.setup.outputs .outputs.base-ref }}
271327
272328 echo "📋 Changed files:"
273- git diff --name-only origin/${{ steps.context-info .outputs.base-ref }}..HEAD || echo "Failed to get diff"
329+ git diff --name-only origin/${{ needs.setup.outputs .outputs.base-ref }}..HEAD || echo "Failed to get diff"
274330
275331 echo "📊 Change statistics:"
276- git diff --stat origin/${{ steps.context-info.outputs.base-ref }}..HEAD || echo "Failed to get stats"
277-
278- - name : Exit early if Issue already has linked PR
279- id : exit-early
280- if : |
281- steps.context-info.outputs.is-pr == 'false' && steps.context-info.outputs.has-linked-pr == 'true'
282- run : |
283- echo "Issue already has linked PR. Exiting early."
284- exit 0
332+ git diff --stat origin/${{ needs.setup.outputs.outputs.base-ref }}..HEAD || echo "Failed to get stats"
285333
286334 - name : Get Project Information
287335 id : project-info
@@ -380,14 +428,14 @@ jobs:
380428 Bash(rm -rf /)
381429 env :
382430 # Pass context information to Claude Code
383- GITHUB_CONTEXT_TYPE : ${{ steps.context-info .outputs.is-pr == 'true' && 'PR' || 'ISSUE' }}
384- ISSUE_NUMBER : ${{ steps.context-info .outputs.issue-number }}
385- PR_NUMBER : ${{ steps.context-info .outputs.pr-number }}
386- BASE_BRANCH : ${{ steps.context-info .outputs.base-ref }}
387- HEAD_BRANCH : ${{ steps.context-info .outputs.head-ref }}
388- HEAD_SHA : ${{ steps.context-info .outputs.head-sha }}
431+ GITHUB_CONTEXT_TYPE : ${{ needs.setup.outputs .outputs.is-pr == 'true' && 'PR' || 'ISSUE' }}
432+ ISSUE_NUMBER : ${{ needs.setup.outputs .outputs.issue-number }}
433+ PR_NUMBER : ${{ needs.setup.outputs .outputs.pr-number }}
434+ BASE_BRANCH : ${{ needs.setup.outputs .outputs.base-ref }}
435+ HEAD_BRANCH : ${{ needs.setup.outputs .outputs.head-ref }}
436+ HEAD_SHA : ${{ needs.setup.outputs .outputs.head-sha }}
389437 GITHUB_EVENT_NAME : ${{ github.event_name }}
390- TRIGGER_TEXT : ${{ steps.context-info .outputs.trigger-text }}
438+ TRIGGER_TEXT : ${{ needs.setup.outputs .outputs.trigger-text }}
391439 PROJECT_TYPE : ${{ steps.project-info.outputs.project-type }}
392440 PROJECT_FRAMEWORK : ${{ steps.project-info.outputs.framework }}
393441 TOTAL_FILES : ${{ steps.project-info.outputs.total-files }}
@@ -425,14 +473,14 @@ jobs:
425473
426474 - name : Run Advanced Repository Management
427475 id : advanced-management
428- if : steps.claude.outcome == 'success' && steps.context-info .outputs.issue-number
476+ if : steps.claude.outcome == 'success' && needs.setup.outputs .outputs.issue-number
429477 uses : actions/github-script@v7
430478 with :
431479 github-token : ${{ secrets.GITHUB_TOKEN }}
432480 script : |
433- const issueNumber = ${{ steps.context-info .outputs.issue-number }};
434- const isPR = '${{ steps.context-info .outputs.is-pr }}' === 'true';
435- const triggerText = (${{ toJSON(steps.context-info .outputs.trigger-text) }} || '').toLowerCase();
481+ const issueNumber = ${{ needs.setup.outputs .outputs.issue-number }};
482+ const isPR = '${{ needs.setup.outputs .outputs.is-pr }}' === 'true';
483+ const triggerText = (${{ toJSON(needs.setup.outputs .outputs.trigger-text) }} || '').toLowerCase();
436484 const framework = '${{ steps.project-info.outputs.framework }}';
437485 const hashSymbol = String.fromCharCode(35);
438486
@@ -705,7 +753,7 @@ jobs:
705753 }
706754 - name : Check for Changes and Prepare for PR
707755 id : check-changes
708- if : steps.claude.outcome == 'success' && steps.context-info .outputs.is-pr == 'false' && steps.claude.outputs.claude_branch_name
756+ if : steps.claude.outcome == 'success' && needs.setup.outputs .outputs.is-pr == 'false' && steps.claude.outputs.claude_branch_name
709757 run : |
710758 set -e # Exit immediately if a command exits with a non-zero status.
711759
@@ -770,14 +818,14 @@ jobs:
770818 # The 'if' condition is now correctly chained.
771819 if : |
772820 steps.claude.outcome == 'success'
773- && steps.context-info .outputs.is-pr == 'false'
821+ && needs.setup.outputs .outputs.is-pr == 'false'
774822 && steps.claude.outputs.claude_branch_name
775823 && steps.check-changes.outputs.has-changes == 'true'
776824 uses : actions/github-script@v7
777825 with :
778826 github-token : ${{ secrets.GITHUB_TOKEN }}
779827 script : |
780- const issueNumber = ${{ steps.context-info .outputs.issue-number }}
828+ const issueNumber = ${{ needs.setup.outputs .outputs.issue-number }}
781829 const branchName = '${{ steps.claude.outputs.claude_branch_name }}'
782830 const defaultBranch = '${{ github.event.repository.default_branch }}'
783831 const owner = context.repo.owner
@@ -879,11 +927,11 @@ jobs:
879927 }
880928
881929 - name : Notify on Success
882- if : steps.claude.outcome == 'success' && steps.context-info .outputs.issue-number
930+ if : steps.claude.outcome == 'success' && needs.setup.outputs .outputs.issue-number
883931 uses : actions/github-script@v7
884932 with :
885933 script : |
886- const isPR = '${{ steps.context-info .outputs.is-pr }}' === 'true';
934+ const isPR = '${{ needs.setup.outputs .outputs.is-pr }}' === 'true';
887935 const contextType = isPR ? 'Pull Request' : 'Issue';
888936 const eventName = '${{ github.event_name }}';
889937 const framework = '${{ steps.project-info.outputs.framework }}' || 'Unknown';
@@ -918,9 +966,9 @@ jobs:
918966 }
919967
920968 // Execution info (compact version)
921- message += `**📊 Execution Info:** ${contextType} ${hashSymbol}${${{ steps.context-info .outputs.issue-number }}} | ${framework} (${totalFiles} files) | @${{ github.actor }}\n`;
969+ message += `**📊 Execution Info:** ${contextType} ${hashSymbol}${${{ needs.setup.outputs .outputs.issue-number }}} | ${framework} (${totalFiles} files) | @${{ github.actor }}\n`;
922970 if (isPR) {
923- message += `**🌿 Branch:** \`${{ steps.context-info .outputs.head-ref }}\` → \`${{ steps.context-info .outputs.base-ref }}\`\n`;
971+ message += `**🌿 Branch:** \`${{ needs.setup .outputs.outputs. head-ref }}\` → \`${{ needs.setup.outputs .outputs.base-ref }}\`\n`;
924972 }
925973
926974 // Repository management results (summary)
@@ -989,24 +1037,24 @@ jobs:
9891037 message += `🔄 **Rerun**: You can run again anytime with \`claude [your instructions]\``;
9901038
9911039 await github.rest.issues.createComment({
992- issue_number: ${{ steps.context-info .outputs.issue-number }},
1040+ issue_number: ${{ needs.setup.outputs .outputs.issue-number }},
9931041 owner: context.repo.owner,
9941042 repo: context.repo.repo,
9951043 body: message
9961044 });
9971045
9981046 - name : Notify on Failure
999- if : steps.claude.outcome == 'failure' && steps.context-info .outputs.issue-number
1047+ if : steps.claude.outcome == 'failure' && needs.setup.outputs .outputs.issue-number
10001048 uses : actions/github-script@v7
10011049 with :
10021050 script : |
1003- const isPR = '${{ steps.context-info .outputs.is-pr }}' === 'true';
1051+ const isPR = '${{ needs.setup.outputs .outputs.is-pr }}' === 'true';
10041052 const contextType = isPR ? 'Pull Request' : 'Issue';
10051053 const managementError = '${{ steps.advanced-management.outputs.management-error }}';
10061054 const hashSymbol = '#';
10071055
10081056 let message = `❌ **Claude Code execution failed**\n\n`;
1009- message += `An error occurred while processing ${contextType} ${hashSymbol}${{ steps.context-info .outputs.issue-number }}.\n\n`;
1057+ message += `An error occurred while processing ${contextType} ${hashSymbol}${{ needs.setup.outputs .outputs.issue-number }}.\n\n`;
10101058
10111059 // Error info (compact version)
10121060 message += `**📊 Error Info:** ${contextType} | \`${{ github.event_name }}\` | @${{ github.actor }}\n`;
@@ -1045,7 +1093,7 @@ jobs:
10451093 message += `📞 **Support**: If the problem persists, please contact an administrator`;
10461094
10471095 await github.rest.issues.createComment({
1048- issue_number: ${{ steps.context-info .outputs.issue-number }},
1096+ issue_number: ${{ needs.setup.outputs .outputs.issue-number }},
10491097 owner: context.repo.owner,
10501098 repo: context.repo.repo,
10511099 body: message
@@ -1056,9 +1104,9 @@ jobs:
10561104 run : |
10571105 echo "📊 ===== Execution Summary ====="
10581106 echo "Status: ${{ steps.claude.outcome }}"
1059- echo "Context Type: ${{ steps.context-info .outputs.is-pr == 'true' && 'PR' || 'Issue' }}"
1060- echo "Issue/PR: '#${{ steps.context-info .outputs.issue-number }}'"
1061- echo "Branch: ${{ steps.context-info .outputs.head-ref || 'default' }}"
1107+ echo "Context Type: ${{ needs.setup.outputs .outputs.is-pr == 'true' && 'PR' || 'Issue' }}"
1108+ echo "Issue/PR: '#${{ needs.setup.outputs .outputs.issue-number }}'"
1109+ echo "Branch: ${{ needs.setup.outputs .outputs.head-ref || 'default' }}"
10621110 echo "Actor: ${{ github.actor }}"
10631111 echo "Event: ${{ github.event_name }}"
10641112 echo "Project: ${{ steps.project-info.outputs.framework || 'Unknown' }}"
0 commit comments