diff --git a/.github/workflows/d2gen.yml b/.github/workflows/d2gen.yml new file mode 100644 index 000000000..67452ff6a --- /dev/null +++ b/.github/workflows/d2gen.yml @@ -0,0 +1,223 @@ +name: D2 Gen + +on: + pull_request: + branches: [ main ] + +concurrency: + group: d2gen-${{ github.ref }}-${{ github.event_name }} + cancel-in-progress: true + +permissions: + contents: write + pull-requests: write + +jobs: + d2gen: + runs-on: ubuntu-latest + # container: terrastruct/d2:latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + fetch-depth: 0 + ref: ${{ github.head_ref }} + + - name: Install D2 + run: | + curl -fsSL https://d2lang.com/install.sh | sh -s -- --tala + echo "$HOME/.local/bin" >> $GITHUB_PATH + + - name: Generate SVG images from D2 + env: + TSTRUCT_TOKEN: ${{ secrets.TSTRUCT_TOKEN }} + run: make d2gen-all + + - name: Check for changes in SVG files + id: check_changes + run: | + if git diff --quiet '*.svg'; then + echo "changed=false" >> $GITHUB_OUTPUT + else + echo "changed=true" >> $GITHUB_OUTPUT + echo "The following SVG files have changed:" + git diff --name-only '*.svg' + fi + + - name: Get changed SVG files + if: steps.check_changes.outputs.changed == 'true' + id: get_changed_files + run: | + echo "files<> $GITHUB_OUTPUT + git diff --name-only '*.svg' + echo "EOF" >> $GITHUB_OUTPUT + + - name: Create PR comment for approval + if: steps.check_changes.outputs.changed == 'true' + id: pr_comment + uses: actions/github-script@v7 + with: + script: | + const changedFiles = `${{ steps.get_changed_files.outputs.files }}`; + + const body = [ + "## SVG Files Updated 📊", + "", + "The `make d2gen-all` command has generated updated SVG files from D2 diagrams.", + "", + "**Changed files:**", + "```", + changedFiles, + "```", + "", + "Would you like me to commit these changes to this PR?", + "", + "- 👍 **Yes** - Automatically commit the updated SVG files", + "- 👎 **No** - Skip committing, CI will pass without the changes", + "", + "Please react to this comment with your choice." + ].join("\\n"); + + const { data: comment } = await github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: body + }); + + return comment.id; + + - name: Wait for user reaction + if: steps.check_changes.outputs.changed == 'true' + id: wait_reaction + uses: actions/github-script@v7 + with: + script: | + const commentId = parseInt('${{ steps.pr_comment.outputs.result }}'); + console.log('Starting wait for user reaction, commentId:', commentId); + const maxWaitTime = 60000; // 1 minute for testing + const pollInterval = 5000; // 5 seconds + let elapsedTime = 0; + + while (elapsedTime < maxWaitTime) { + console.log(`Polling for reactions (${elapsedTime/1000}s elapsed)...`); + const { data: reactions } = await github.rest.reactions.listForIssueComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: commentId + }); + + const thumbsUp = reactions.find(r => r.content === '+1'); + const thumbsDown = reactions.find(r => r.content === '-1'); + + if (thumbsUp) { + console.log('User approved changes with 👍'); + require('fs').appendFileSync(process.env.GITHUB_OUTPUT, 'result=approve\n'); + return 'approve'; + } else if (thumbsDown) { + console.log('User declined changes with 👎'); + require('fs').appendFileSync(process.env.GITHUB_OUTPUT, 'result=decline\n'); + return 'decline'; + } + + await new Promise(resolve => setTimeout(resolve, pollInterval)); + elapsedTime += pollInterval; + } + + console.log('Timeout reached, defaulting to decline'); + require('fs').appendFileSync(process.env.GITHUB_OUTPUT, 'result=decline\n'); + return 'decline'; + + - name: Debug wait reaction step + if: always() + run: | + echo "🔍 Checking if wait_reaction step ran..." + echo "Wait reaction step conclusion: ${{ steps.wait_reaction.conclusion }}" + echo "Wait reaction step outcome: ${{ steps.wait_reaction.outcome }}" + echo "Wait reaction step outputs.result: '${{ steps.wait_reaction.outputs.result }}'" + + - name: Always debug outputs + run: | + echo "🐛 Always running debug - checking all outputs..." + echo "Changed files detected: '${{ steps.check_changes.outputs.changed }}'" + echo "User reaction result: '${{ steps.wait_reaction.outputs.result }}'" + echo "PR comment ID: '${{ steps.pr_comment.outputs.result }}'" + echo "Condition 1 (changes): ${{ steps.check_changes.outputs.changed == 'true' }}" + echo "Condition 2 (approve): ${{ steps.wait_reaction.outputs.result == 'approve' }}" + echo "Combined condition: ${{ steps.check_changes.outputs.changed == 'true' && steps.wait_reaction.outputs.result == 'approve' }}" + + - name: Debug step conditions + if: steps.check_changes.outputs.changed == 'true' + run: | + echo "🐛 Conditional debug (changes detected)..." + echo "Changed files detected: ${{ steps.check_changes.outputs.changed }}" + echo "User reaction result: ${{ steps.wait_reaction.outputs.result }}" + echo "Will commit changes: ${{ steps.check_changes.outputs.changed == 'true' && steps.wait_reaction.outputs.result == 'approve' }}" + + - name: Commit and push changes + if: steps.check_changes.outputs.changed == 'true' # && steps.wait_reaction.outputs.result == 'approve' + run: | + echo "🔧 Setting up git configuration..." + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + + echo "📁 Current working directory:" + pwd + + echo "📊 Git status before adding files:" + git status + + echo "🔍 Finding SVG files to add..." + find . -name "*.svg" -type f -exec echo "Found: {}" \; + + echo "➕ Adding all SVG files..." + git add . --all + + echo "📊 Git status after adding files:" + git status + + echo "💾 Committing changes..." + git commit -m "chore: update generated SVG files from D2 diagrams" -m "🤖 Generated with GitHub Actions" + + echo "🚀 Pushing to remote..." + git push + + - name: Update PR comment with result + if: steps.check_changes.outputs.changed == 'true' + uses: actions/github-script@v7 + with: + script: | + const commentId = parseInt('${{ steps.pr_comment.outputs.result }}'); + const action = '${{ steps.wait_reaction.outputs.result }}'; + + let updateBody; + if (action === 'approve') { + updateBody = [ + "## SVG Files Updated ✅", + "", + "The updated SVG files have been successfully committed to this PR.", + "", + "**Status:** Changes committed automatically based on user approval." + ].join("\\n"); + } else { + updateBody = [ + "## SVG Files Updated ⏭️", + "", + "The SVG files have changes but were not committed based on user choice or timeout.", + "", + "**Status:** CI will pass without committing the changes." + ].join("\\n"); + } + + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: commentId, + body: updateBody + }); + + - name: Always pass CI + run: | + echo "SVG generation workflow completed successfully" + exit 0 diff --git a/mempool/img/mempool_architecture.svg b/mempool/img/mempool_architecture.svg index 5a98f5c7d..d64ddb140 100644 --- a/mempool/img/mempool_architecture.svg +++ b/mempool/img/mempool_architecture.svg @@ -1,4 +1,4 @@ -