daily-issues-recap #4
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: daily-issues-recap | |
| on: | |
| schedule: | |
| # Run at 6 PM EST (23:00 UTC, or 22:00 UTC during daylight saving) | |
| - cron: "0 23 * * *" | |
| workflow_dispatch: # Allow manual trigger for testing | |
| jobs: | |
| daily-recap: | |
| runs-on: blacksmith-4vcpu-ubuntu-2404 | |
| permissions: | |
| contents: read | |
| issues: read | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 1 | |
| - uses: ./.github/actions/setup-bun | |
| - name: Install opencode | |
| run: curl -fsSL https://opencode.ai/install | bash | |
| - name: Generate daily issues recap | |
| id: recap | |
| env: | |
| OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| OPENCODE_PERMISSION: | | |
| { | |
| "bash": { | |
| "*": "deny", | |
| "gh issue*": "allow", | |
| "gh search*": "allow" | |
| }, | |
| "webfetch": "deny", | |
| "edit": "deny", | |
| "write": "deny" | |
| } | |
| run: | | |
| # Get today's date range | |
| TODAY=$(date -u +%Y-%m-%d) | |
| opencode run -m opencode/claude-sonnet-4-5 "Generate a daily issues recap for the OpenCode repository. | |
| TODAY'S DATE: ${TODAY} | |
| STEP 1: Gather today's issues | |
| Search for all OPEN issues created today (${TODAY}) using: | |
| gh issue list --repo ${{ github.repository }} --state open --search \"created:${TODAY}\" --json number,title,body,labels,state,comments,createdAt,author --limit 500 | |
| IMPORTANT: EXCLUDE all issues authored by Anomaly team members. Filter out issues where the author login matches ANY of these: | |
| adamdotdevin, Brendonovich, fwang, Hona, iamdavidhill, jayair, kitlangton, kommander, MrMushrooooom, R44VC0RP, rekram1-node, thdxr | |
| This recap is specifically for COMMUNITY (external) issues only. | |
| STEP 2: Analyze and categorize | |
| For each issue created today, categorize it: | |
| **Severity Assessment:** | |
| - CRITICAL: Crashes, data loss, security issues, blocks major functionality | |
| - HIGH: Significant bugs affecting many users, important features broken | |
| - MEDIUM: Bugs with workarounds, minor features broken | |
| - LOW: Minor issues, cosmetic, nice-to-haves | |
| **Activity Assessment:** | |
| - Note issues with high comment counts or engagement | |
| - Note issues from repeat reporters (check if author has filed before) | |
| STEP 3: Cross-reference with existing issues | |
| For issues that seem like feature requests or recurring bugs: | |
| - Search for similar older issues to identify patterns | |
| - Note if this is a frequently requested feature | |
| - Identify any issues that are duplicates of long-standing requests | |
| STEP 4: Generate the recap | |
| Create a structured recap with these sections: | |
| ===DISCORD_START=== | |
| **Daily Issues Recap - ${TODAY}** | |
| **Summary Stats** | |
| - Total issues opened today: [count] | |
| - By category: [bugs/features/questions] | |
| **Critical/High Priority Issues** | |
| [List any CRITICAL or HIGH severity issues with brief descriptions and issue numbers] | |
| **Most Active/Discussed** | |
| [Issues with significant engagement or from active community members] | |
| **Trending Topics** | |
| [Patterns noticed - e.g., 'Multiple reports about X', 'Continued interest in Y feature'] | |
| **Duplicates & Related** | |
| [Issues that relate to existing open issues] | |
| ===DISCORD_END=== | |
| STEP 5: Format for Discord | |
| Format the recap as a Discord-compatible message: | |
| - Use Discord markdown (**, __, etc.) | |
| - BE EXTREMELY CONCISE - this is an EOD summary, not a detailed report | |
| - Use hyperlinked issue numbers with suppressed embeds: [#1234](<https://github.com/${{ github.repository }}/issues/1234>) | |
| - Group related issues on single lines where possible | |
| - Add emoji sparingly for critical items only | |
| - HARD LIMIT: Keep under 1800 characters total | |
| - Skip sections that have nothing notable (e.g., if no critical issues, omit that section) | |
| - Prioritize signal over completeness - only surface what matters | |
| OUTPUT: Output ONLY the content between ===DISCORD_START=== and ===DISCORD_END=== markers. Include the markers so I can extract it." > /tmp/recap_raw.txt | |
| # Extract only the Discord message between markers | |
| sed -n '/===DISCORD_START===/,/===DISCORD_END===/p' /tmp/recap_raw.txt | grep -v '===DISCORD' > /tmp/recap.txt | |
| echo "recap_file=/tmp/recap.txt" >> $GITHUB_OUTPUT | |
| - name: Post to Discord | |
| env: | |
| DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_ISSUES_WEBHOOK_URL }} | |
| run: | | |
| if [ -z "$DISCORD_WEBHOOK_URL" ]; then | |
| echo "Warning: DISCORD_ISSUES_WEBHOOK_URL secret not set, skipping Discord post" | |
| cat /tmp/recap.txt | |
| exit 0 | |
| fi | |
| # Read the recap | |
| RECAP_RAW=$(cat /tmp/recap.txt) | |
| RECAP_LENGTH=${#RECAP_RAW} | |
| echo "Recap length: ${RECAP_LENGTH} chars" | |
| # Function to post a message to Discord | |
| post_to_discord() { | |
| local msg="$1" | |
| local content=$(echo "$msg" | jq -Rs '.') | |
| curl -s -H "Content-Type: application/json" \ | |
| -X POST \ | |
| -d "{\"content\": ${content}}" \ | |
| "$DISCORD_WEBHOOK_URL" | |
| sleep 1 | |
| } | |
| # If under limit, send as single message | |
| if [ "$RECAP_LENGTH" -le 1950 ]; then | |
| post_to_discord "$RECAP_RAW" | |
| else | |
| echo "Splitting into multiple messages..." | |
| remaining="$RECAP_RAW" | |
| while [ ${#remaining} -gt 0 ]; do | |
| if [ ${#remaining} -le 1950 ]; then | |
| post_to_discord "$remaining" | |
| break | |
| else | |
| chunk="${remaining:0:1900}" | |
| last_newline=$(echo "$chunk" | grep -bo $'\n' | tail -1 | cut -d: -f1) | |
| if [ -n "$last_newline" ] && [ "$last_newline" -gt 500 ]; then | |
| chunk="${remaining:0:$last_newline}" | |
| remaining="${remaining:$((last_newline+1))}" | |
| else | |
| chunk="${remaining:0:1900}" | |
| remaining="${remaining:1900}" | |
| fi | |
| post_to_discord "$chunk" | |
| fi | |
| done | |
| fi | |
| echo "Posted daily recap to Discord" |