summaryrefslogtreecommitdiffhomepage
path: root/.github/workflows/daily-issues-recap.yml
blob: 31cf08233b99002c209a966bf427beb460139e91 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
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"