Fix: Make generate-implementation independent of preprocess to avoid … #29
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Enhance Feature Requests | ||
| on: | ||
| issues: | ||
| types: [opened, labeled] | ||
| workflow_dispatch: | ||
| # Prevent parallel runs for the same issue | ||
| concurrency: | ||
| group: enhance-feature-request-${{ github.event.issue.number || inputs.issue_number }} | ||
| cancel-in-progress: false | ||
| inputs: | ||
| issue_number: | ||
| description: 'Issue number to process' | ||
| required: true | ||
| type: string | ||
| permissions: | ||
| issues: write | ||
| contents: write | ||
| pull-requests: write | ||
| jobs: | ||
| check-label: | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| has_enhancement: ${{ steps.check.outputs.has_enhancement }} | ||
| already_enhanced: ${{ steps.check.outputs.already_enhanced }} | ||
| issue_number: ${{ steps.set_issue.outputs.issue_number }} | ||
| steps: | ||
| - name: Set issue number | ||
| id: set_issue | ||
| run: | | ||
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | ||
| echo "issue_number=${{ inputs.issue_number }}" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "issue_number=${{ github.event.issue.number }}" >> "$GITHUB_OUTPUT" | ||
| fi | ||
| - name: Fetch and check issue | ||
| id: check | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| ISSUE_NUMBER: ${{ steps.set_issue.outputs.issue_number }} | ||
| run: | | ||
| set -e | ||
| # Fetch issue data | ||
| ISSUE_JSON=$(curl -s \ | ||
| -H "Authorization: token $GITHUB_TOKEN" \ | ||
| -H "Accept: application/vnd.github+json" \ | ||
| "https://api.github.com/repos/${{ github.repository }}/issues/$ISSUE_NUMBER") | ||
| # Write to temp file for safe parsing | ||
| echo "$ISSUE_JSON" > /tmp/issue.json | ||
| # Extract labels | ||
| LABELS=$(jq -r '.labels[].name' /tmp/issue.json) | ||
| # Check for enhancement label (word boundary, not exact line) | ||
| if echo "$LABELS" | grep -qw "enhancement"; then | ||
| echo "✅ Issue has enhancement label" | ||
| echo "has_enhancement=true" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "❌ No enhancement label found" | ||
| echo "has_enhancement=false" >> "$GITHUB_OUTPUT" | ||
| fi | ||
| # Check if already enhanced | ||
| BODY=$(jq -r '.body // ""' /tmp/issue.json) | ||
| if echo "$BODY" | grep -qF "## 📝 Enhanced Feature Request"; then | ||
| echo "⚠️ Issue already enhanced - skipping" | ||
| echo "already_enhanced=true" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "✅ Issue not yet enhanced" | ||
| echo "already_enhanced=false" >> "$GITHUB_OUTPUT" | ||
| fi | ||
| preprocess: | ||
| runs-on: ubuntu-latest | ||
| needs: check-label | ||
| if: needs.check-label.outputs.has_enhancement == 'true' && needs.check-label.outputs.already_enhanced == 'false' | ||
| outputs: | ||
| enhanced_task: ${{ steps.preprocess.outputs.enhanced_task }} | ||
| issue_title: ${{ steps.fetch.outputs.issue_title }} | ||
| issue_user: ${{ steps.fetch.outputs.issue_user }} | ||
| issue_body: ${{ steps.fetch.outputs.issue_body }} | ||
| issue_created: ${{ steps.fetch.outputs.issue_created }} | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| ref: develop | ||
| - uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: '20.20.0' | ||
| cache: npm | ||
| - name: Install dependencies | ||
| working-directory: .github/agent | ||
| run: npm install | ||
| - name: Fetch full issue data | ||
| id: fetch | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| ISSUE_NUMBER: ${{ needs.check-label.outputs.issue_number }} | ||
| run: | | ||
| ISSUE_JSON=$(curl -s \ | ||
| -H "Authorization: token $GITHUB_TOKEN" \ | ||
| -H "Accept: application/vnd.github+json" \ | ||
| "https://api.github.com/repos/${{ github.repository }}/issues/$ISSUE_NUMBER") | ||
| TITLE=$(echo "$ISSUE_JSON" | jq -r '.title') | ||
| USER=$(echo "$ISSUE_JSON" | jq -r '.user.login') | ||
| BODY=$(echo "$ISSUE_JSON" | jq -r '.body // ""') | ||
| CREATED=$(echo "$ISSUE_JSON" | jq -r '.created_at') | ||
| echo "issue_title=$TITLE" >> "$GITHUB_OUTPUT" | ||
| echo "issue_user=$USER" >> "$GITHUB_OUTPUT" | ||
| echo "issue_created=$CREATED" >> "$GITHUB_OUTPUT" | ||
| { | ||
| echo "issue_body<<EOF" | ||
| echo "$BODY" | ||
| echo "EOF" | ||
| } >> "$GITHUB_OUTPUT" | ||
| - name: Preprocess issue | ||
| id: preprocess | ||
| env: | ||
| OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} | ||
| PREPROCESSING_MODEL: ${{ secrets.PREPROCESSING_MODEL }} | ||
| TASK: ${{ steps.fetch.outputs.issue_title }} | ||
| REQUESTER: ${{ steps.fetch.outputs.issue_user }} | ||
| GITHUB_RUN_ID: ${{ github.run_id }} | ||
| run: | | ||
| set -e | ||
| OUTPUT=$(node .github/agent/preprocess-task.mjs 2>&1) | ||
| echo "$OUTPUT" | ||
| if echo "$OUTPUT" | grep -q "ENHANCED_TASK_START"; then | ||
| ENHANCED=$(echo "$OUTPUT" | sed -n '/ENHANCED_TASK_START/,/ENHANCED_TASK_END/p' | sed '1d;$d') | ||
| else | ||
| ENHANCED="$TASK" | ||
| fi | ||
| { | ||
| echo "enhanced_task<<EOF" | ||
| echo "$ENHANCED" | ||
| echo "EOF" | ||
| } >> "$GITHUB_OUTPUT" | ||
| create-confluence: | ||
| runs-on: ubuntu-latest | ||
| needs: [check-label, preprocess] | ||
| outputs: | ||
| confluence_url: ${{ steps.confluence.outputs.confluence_url }} | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| ref: develop | ||
| - uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: '20.20.0' | ||
| cache: npm | ||
| - name: Install dependencies | ||
| working-directory: .github/agent | ||
| run: npm install | ||
| - name: Create Confluence page | ||
| id: confluence | ||
| env: | ||
| TASK: ${{ needs.preprocess.outputs.issue_title }} | ||
| REQUESTER: ${{ needs.preprocess.outputs.issue_user }} | ||
| ISSUE_NUMBER: ${{ needs.check-label.outputs.issue_number }} | ||
| CONFLUENCE_URL: ${{ secrets.CONFLUENCE_URL }} | ||
| CONFLUENCE_EMAIL: ${{ secrets.CONFLUENCE_EMAIL }} | ||
| CONFLUENCE_API_TOKEN: ${{ secrets.CONFLUENCE_API_TOKEN }} | ||
| CONFLUENCE_SPACE_KEY: ${{ secrets.CONFLUENCE_SPACE_KEY }} | ||
| CONFLUENCE_PARENT_PAGE_ID: ${{ secrets.CONFLUENCE_PARENT_PAGE_ID }} | ||
| ENHANCED_TASK: ${{ needs.preprocess.outputs.enhanced_task }} | ||
| run: | | ||
| set -e | ||
| OUTPUT=$(node .github/agent/create-confluence.mjs 2>&1) | ||
| echo "$OUTPUT" | ||
| URL=$(echo "$OUTPUT" | grep "CONFLUENCE_URL:" | sed 's/CONFLUENCE_URL://' | tr -d '[:space:]') | ||
| echo "confluence_url=$URL" >> "$GITHUB_OUTPUT" | ||
| update-issue: | ||
| runs-on: ubuntu-latest | ||
| needs: [check-label, preprocess, create-confluence] | ||
| steps: | ||
| - name: Update issue body | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| ISSUE_NUMBER: ${{ needs.check-label.outputs.issue_number }} | ||
| run: | | ||
| set -euo pipefail | ||
| # Use jq to safely build JSON with proper escaping | ||
| jq -n \ | ||
| --arg enhanced "${{ needs.preprocess.outputs.enhanced_task }}" \ | ||
| --arg confluence "${{ needs.create-confluence.outputs.confluence_url }}" \ | ||
| --arg original "${{ needs.preprocess.outputs.issue_body }}" \ | ||
| --arg requester "${{ needs.preprocess.outputs.issue_user }}" \ | ||
| --arg created "${{ needs.preprocess.outputs.issue_created }}" \ | ||
| '{ | ||
| body: ( | ||
| "## 📝 Enhanced Feature Request\n\n" + | ||
| $enhanced + | ||
| "\n\n---\n\n" + | ||
| "📄 **Requirements documented:** " + | ||
| (if $confluence != "" then $confluence else "_Not available_" end) + | ||
| "\n\n---\n\n" + | ||
| "## 📋 Original Request\n\n" + | ||
| $original + | ||
| "\n\n---\n\n" + | ||
| "**Requested by:** " + $requester + "\n" + | ||
| "**Created:** " + $created | ||
| ) | ||
| }' \ | ||
| | curl -X PATCH \ | ||
| -H "Authorization: token $GITHUB_TOKEN" \ | ||
| -H "Accept: application/vnd.github+json" \ | ||
| -H "Content-Type: application/json" \ | ||
| -d @- \ | ||
| "https://api.github.com/repos/${{ github.repository }}/issues/$ISSUE_NUMBER" | ||
| echo "✅ Issue updated with enhanced + original content" | ||
| add-comment: | ||
| runs-on: ubuntu-latest | ||
| needs: [check-label, update-issue] | ||
| steps: | ||
| - name: Comment | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| ISSUE_NUMBER: ${{ needs.check-label.outputs.issue_number }} | ||
| run: | | ||
| COMMENT="🤖 **Feature request enhanced!** | ||
| Issue description and requirements are now structured and documented." | ||
| jq -n --arg body "$COMMENT" '{body:$body}' \ | ||
| | curl -X POST \ | ||
| -H "Authorization: token $GITHUB_TOKEN" \ | ||
| -H "Accept: application/vnd.github+json" \ | ||
| -H "Content-Type: application/json" \ | ||
| -d @- \ | ||
| "https://api.github.com/repos/${{ github.repository }}/issues/$ISSUE_NUMBER/comments" | ||
| generate-implementation: | ||
| runs-on: ubuntu-latest | ||
| needs: [check-label] | ||
| # Run if issue has enhancement label and isn't already enhanced | ||
| # Don't depend on preprocess to avoid skipping if preprocess fails/is skipped | ||
| if: | | ||
| needs.check-label.outputs.has_enhancement == 'true' && | ||
| needs.check-label.outputs.already_enhanced == 'false' | ||
| permissions: | ||
| contents: write | ||
| pull-requests: write | ||
| issues: write | ||
| steps: | ||
| - name: Checkout develop | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| ref: develop | ||
| fetch-depth: 0 | ||
| - name: Setup Node.js | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: '20.20.0' | ||
| cache: npm | ||
| - name: Install agent dependencies | ||
| working-directory: .github/agent | ||
| run: npm install | ||
| - name: Fetch issue data | ||
| id: fetch-issue | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| ISSUE_NUMBER: ${{ needs.check-label.outputs.issue_number }} | ||
| run: | | ||
| ISSUE_JSON=$(curl -s \ | ||
| -H "Authorization: token $GITHUB_TOKEN" \ | ||
| -H "Accept: application/vnd.github+json" \ | ||
| "https://api.github.com/repos/${{ github.repository }}/issues/$ISSUE_NUMBER") | ||
| TITLE=$(echo "$ISSUE_JSON" | jq -r '.title') | ||
| BODY=$(echo "$ISSUE_JSON" | jq -r '.body // ""') | ||
| { | ||
| echo "issue_title<<EOF" | ||
| echo "$TITLE" | ||
| echo "EOF" | ||
| } >> "$GITHUB_OUTPUT" | ||
| - name: Generate implementation with Claude | ||
| id: generate | ||
| env: | ||
| ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} | ||
| CLAUDE_MODEL: ${{ secrets.CLAUDE_MODEL }} | ||
| ENHANCED_TASK: ${{ steps.fetch-issue.outputs.issue_title }} | ||
| TASK: ${{ steps.fetch-issue.outputs.issue_title }} | ||
| ISSUE_NUMBER: ${{ needs.check-label.outputs.issue_number }} | ||
| run: | | ||
| set -e | ||
| OUTPUT=$(node .github/agent/generate-implementation.mjs 2>&1) | ||
| echo "$OUTPUT" | ||
| # Extract implementation file path | ||
| IMPL_FILE=$(echo "$OUTPUT" | grep "IMPLEMENTATION_FILE:" | sed 's/IMPLEMENTATION_FILE://' | tr -d '[:space:]') | ||
| echo "implementation_file=$IMPL_FILE" >> $GITHUB_OUTPUT | ||
| - name: Create implementation branch and PR | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| ISSUE_NUMBER: ${{ needs.check-label.outputs.issue_number }} | ||
| IMPL_FILE: ${{ steps.generate.outputs.implementation_file }} | ||
| run: | | ||
| set -e | ||
| # Configure git | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "github-actions[bot]@users.noreply.github.com" | ||
| # Create feature branch | ||
| BRANCH_NAME="feature/issue-$ISSUE_NUMBER-implementation" | ||
| git checkout -b "$BRANCH_NAME" | ||
| # Add the implementation file | ||
| if [ -f "$IMPL_FILE" ]; then | ||
| git add "$IMPL_FILE" | ||
| # Create commit with heredoc to handle multiline | ||
| git commit -m "$(cat <<EOF | ||
| Add implementation plan for issue #$ISSUE_NUMBER | ||
| This is an AI-generated implementation plan created by Claude. | ||
| Please review and adapt as needed. | ||
| Related issue: #$ISSUE_NUMBER | ||
| EOF | ||
| )" | ||
| # Push branch | ||
| git push -u origin "$BRANCH_NAME" | ||
| # Create PR body using heredoc | ||
| PR_BODY=$(cat <<'EOF' | ||
| ## 🤖 AI-Generated Implementation Plan | ||
| This PR contains an implementation plan generated by Claude AI for issue #$ISSUE_NUMBER. | ||
| ### 📋 Implementation Plan | ||
| See [implementation-$ISSUE_NUMBER.md](./implementation-$ISSUE_NUMBER.md) for details. | ||
| ### ⚠️ Important | ||
| This is an **AI-generated proposal**. Please: | ||
| - Review the implementation plan carefully | ||
| - Adapt and modify as needed | ||
| - Add actual code changes based on the plan | ||
| - Test thoroughly before merging | ||
| Closes #$ISSUE_NUMBER | ||
| EOF | ||
| ) | ||
| # Substitute environment variables in PR body | ||
| PR_BODY=$(echo "$PR_BODY" | sed "s/\$ISSUE_NUMBER/$ISSUE_NUMBER/g") | ||
| # Create PR | ||
| gh pr create \ | ||
| --title "feat: Implementation plan for issue #$ISSUE_NUMBER" \ | ||
| --body "$PR_BODY" \ | ||
| --base develop \ | ||
| --head "$BRANCH_NAME" \ | ||
| --label "ai-generated,enhancement" | ||
| echo "✅ Created PR for branch $BRANCH_NAME" | ||
| else | ||
| echo "❌ Implementation file not found: $IMPL_FILE" | ||
| exit 1 | ||
| fi | ||
| - name: Comment on issue with PR link | ||
| if: success() | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| ISSUE_NUMBER: ${{ needs.check-label.outputs.issue_number }} | ||
| run: | | ||
| COMMENT="🚀 **Implementation PR Created!** | ||
| An AI-generated implementation plan has been created. Check the pull request for details. | ||
| Note: This is a starting point - please review and adapt the implementation as needed." | ||
| jq -n --arg body "$COMMENT" '{body:$body}' \ | ||
| | curl -X POST \ | ||
| -H "Authorization: token $GITHUB_TOKEN" \ | ||
| -H "Accept: application/vnd.github+json" \ | ||
| -H "Content-Type: application/json" \ | ||
| -d @- \ | ||
| "https://api.github.com/repos/${{ github.repository }}/issues/$ISSUE_NUMBER/comments" | ||