|
| 1 | +name: Daily Project Digest |
| 2 | + |
| 3 | +on: |
| 4 | + schedule: |
| 5 | + - cron: '0 7 * * *' # 07:00 UTC daily |
| 6 | + workflow_dispatch: {} # Allow manual trigger |
| 7 | + |
| 8 | +permissions: |
| 9 | + issues: write |
| 10 | + |
| 11 | +jobs: |
| 12 | + digest: |
| 13 | + runs-on: ubuntu-latest |
| 14 | + steps: |
| 15 | + - uses: actions/checkout@v5 |
| 16 | + with: |
| 17 | + fetch-depth: 0 # Full history for git log |
| 18 | + |
| 19 | + - name: Gather repository data |
| 20 | + env: |
| 21 | + GH_TOKEN: ${{ github.token }} |
| 22 | + run: | |
| 23 | + REPO="${{ github.repository }}" |
| 24 | + YESTERDAY=$(date -u -d '1 day ago' +%Y-%m-%dT00:00:00Z) |
| 25 | + TODAY=$(date -u +%Y-%m-%d) |
| 26 | + YESTERDAY_DATE=$(date -u -d '1 day ago' +%Y-%m-%d) |
| 27 | +
|
| 28 | + echo "=== Gathering data for $YESTERDAY_DATE ===" >&2 |
| 29 | +
|
| 30 | + # --- Stars and Forks --- |
| 31 | + gh api "repos/$REPO" --jq '{ |
| 32 | + stars: .stargazers_count, |
| 33 | + forks: .forks_count, |
| 34 | + open_issues: .open_issues_count, |
| 35 | + watchers: .subscribers_count |
| 36 | + }' > /tmp/repo-stats.json |
| 37 | +
|
| 38 | + # --- Commits in last 24h --- |
| 39 | + git log --since="$YESTERDAY" --format='- [`%h`](https://github.com/'"$REPO"'/commit/%H) %s (%an)' > /tmp/commits.txt || true |
| 40 | +
|
| 41 | + # --- Pull requests merged in last 24h --- |
| 42 | + gh pr list --repo "$REPO" --state merged --search "merged:>=$YESTERDAY_DATE" \ |
| 43 | + --json number,title,author,mergedAt,url --limit 50 \ |
| 44 | + --jq '.[] | "- [#\(.number)](\(.url)) \(.title) (@\(.author.login))"' \ |
| 45 | + > /tmp/merged-prs.txt || true |
| 46 | +
|
| 47 | + # --- Pull requests opened in last 24h --- |
| 48 | + gh pr list --repo "$REPO" --state open --search "created:>=$YESTERDAY_DATE" \ |
| 49 | + --json number,title,author,url --limit 50 \ |
| 50 | + --jq '.[] | "- [#\(.number)](\(.url)) \(.title) (@\(.author.login))"' \ |
| 51 | + > /tmp/opened-prs.txt || true |
| 52 | +
|
| 53 | + # --- Currently open PRs --- |
| 54 | + gh pr list --repo "$REPO" --state open \ |
| 55 | + --json number,title,author,url --limit 50 \ |
| 56 | + --jq '.[] | "- [#\(.number)](\(.url)) \(.title) (@\(.author.login))"' \ |
| 57 | + > /tmp/open-prs.txt || true |
| 58 | +
|
| 59 | + # --- Issues opened in last 24h --- |
| 60 | + gh issue list --repo "$REPO" --state open --search "created:>=$YESTERDAY_DATE" \ |
| 61 | + --json number,title,author,url,labels --limit 50 \ |
| 62 | + --jq '.[] | "- [#\(.number)](\(.url)) \(.title) (@\(.author.login))"' \ |
| 63 | + > /tmp/opened-issues.txt || true |
| 64 | +
|
| 65 | + # --- Issues closed in last 24h --- |
| 66 | + gh issue list --repo "$REPO" --state closed --search "closed:>=$YESTERDAY_DATE" \ |
| 67 | + --json number,title,url --limit 50 \ |
| 68 | + --jq '.[] | "- [#\(.number)](\(.url)) \(.title)"' \ |
| 69 | + > /tmp/closed-issues.txt || true |
| 70 | +
|
| 71 | + # --- Currently open issues --- |
| 72 | + OPEN_ISSUE_COUNT=$(gh issue list --repo "$REPO" --state open --limit 1 --json number --jq 'length') |
| 73 | + echo "$OPEN_ISSUE_COUNT" > /tmp/open-issue-count.txt |
| 74 | +
|
| 75 | + # --- Dependency updates (go.sum changes) --- |
| 76 | + git diff --name-only HEAD~5..HEAD 2>/dev/null | grep -E "go\.(mod|sum)" > /tmp/dep-changes.txt || true |
| 77 | +
|
| 78 | + # --- CI status of latest run --- |
| 79 | + gh run list --repo "$REPO" --branch main --limit 3 \ |
| 80 | + --json conclusion,name,updatedAt,url \ |
| 81 | + --jq '.[] | "- \(.conclusion // "in_progress") — \(.name) [\(.updatedAt)](\(.url))"' \ |
| 82 | + > /tmp/ci-status.txt || true |
| 83 | +
|
| 84 | + - name: Build digest |
| 85 | + run: | |
| 86 | + YESTERDAY_DATE=$(date -u -d '1 day ago' +%Y-%m-%d) |
| 87 | + TODAY=$(date -u +%Y-%m-%d) |
| 88 | +
|
| 89 | + STARS=$(jq -r '.stars' /tmp/repo-stats.json) |
| 90 | + FORKS=$(jq -r '.forks' /tmp/repo-stats.json) |
| 91 | + WATCHERS=$(jq -r '.watchers' /tmp/repo-stats.json) |
| 92 | + OPEN_ISSUES=$(cat /tmp/open-issue-count.txt) |
| 93 | +
|
| 94 | + cat > /tmp/digest-data.txt <<DATAEOF |
| 95 | + # Daily Project Digest: $TODAY |
| 96 | +
|
| 97 | + ## Repository Stats |
| 98 | + | Metric | Count | |
| 99 | + |--------|-------| |
| 100 | + | Stars | $STARS | |
| 101 | + | Forks | $FORKS | |
| 102 | + | Watchers | $WATCHERS | |
| 103 | + | Open issues | $OPEN_ISSUES | |
| 104 | +
|
| 105 | + ## Commits (last 24h) |
| 106 | + $(cat /tmp/commits.txt 2>/dev/null | head -30) |
| 107 | + $([ ! -s /tmp/commits.txt ] && echo "_No commits in the last 24 hours._") |
| 108 | +
|
| 109 | + ## Pull Requests Merged (last 24h) |
| 110 | + $(cat /tmp/merged-prs.txt 2>/dev/null) |
| 111 | + $([ ! -s /tmp/merged-prs.txt ] && echo "_No PRs merged._") |
| 112 | +
|
| 113 | + ## Pull Requests Opened (last 24h) |
| 114 | + $(cat /tmp/opened-prs.txt 2>/dev/null) |
| 115 | + $([ ! -s /tmp/opened-prs.txt ] && echo "_No new PRs._") |
| 116 | +
|
| 117 | + ## Currently Open PRs |
| 118 | + $(cat /tmp/open-prs.txt 2>/dev/null) |
| 119 | + $([ ! -s /tmp/open-prs.txt ] && echo "_No open PRs._") |
| 120 | +
|
| 121 | + ## Issues Opened (last 24h) |
| 122 | + $(cat /tmp/opened-issues.txt 2>/dev/null) |
| 123 | + $([ ! -s /tmp/opened-issues.txt ] && echo "_No new issues._") |
| 124 | +
|
| 125 | + ## Issues Closed (last 24h) |
| 126 | + $(cat /tmp/closed-issues.txt 2>/dev/null) |
| 127 | + $([ ! -s /tmp/closed-issues.txt ] && echo "_No issues closed._") |
| 128 | +
|
| 129 | + ## CI Status (latest runs on main) |
| 130 | + $(cat /tmp/ci-status.txt 2>/dev/null) |
| 131 | +
|
| 132 | + ## Dependency Changes (last 5 commits) |
| 133 | + $(cat /tmp/dep-changes.txt 2>/dev/null) |
| 134 | + $([ ! -s /tmp/dep-changes.txt ] && echo "_No dependency changes._") |
| 135 | + DATAEOF |
| 136 | +
|
| 137 | + - name: Generate AI summary |
| 138 | + env: |
| 139 | + OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }} |
| 140 | + run: | |
| 141 | + if [ -z "$OPENROUTER_API_KEY" ]; then |
| 142 | + echo "::warning::OPENROUTER_API_KEY not set, posting raw digest" |
| 143 | + cp /tmp/digest-data.txt /tmp/digest-final.md |
| 144 | + exit 0 |
| 145 | + fi |
| 146 | +
|
| 147 | + jq -n --rawfile data /tmp/digest-data.txt '{ |
| 148 | + model: "nvidia/nemotron-3-super-120b-a12b:free", |
| 149 | + messages: [ |
| 150 | + { |
| 151 | + role: "system", |
| 152 | + content: "You are a project digest assistant for mxcli, a Go CLI tool for reading and modifying Mendix application projects (.mpr files). Generate a concise daily digest from the raw data provided. Structure your response as:\n\n1. **Highlights** (1-3 bullet points of the most important changes)\n2. **Code Changes** (summarize commits by theme, not individually)\n3. **Pull Requests** (merged, opened, pending review)\n4. **Issues** (new, closed, total open)\n5. **Repository Health** (stars, forks, CI status)\n6. **Action Items** (anything that needs attention: failing CI, stale PRs, unanswered issues)\n\nKeep it concise — this is a daily scan, not a detailed report. Use markdown formatting." |
| 153 | + }, |
| 154 | + { |
| 155 | + role: "user", |
| 156 | + content: $data |
| 157 | + } |
| 158 | + ], |
| 159 | + max_tokens: 3000, |
| 160 | + temperature: 0.3 |
| 161 | + }' > /tmp/ai-request.json |
| 162 | +
|
| 163 | + HTTP_CODE=$(curl -s -w "%{http_code}" -o /tmp/ai-response.json -X POST \ |
| 164 | + -H "Authorization: Bearer $OPENROUTER_API_KEY" \ |
| 165 | + -H "Content-Type: application/json" \ |
| 166 | + -d @/tmp/ai-request.json \ |
| 167 | + https://openrouter.ai/api/v1/chat/completions) |
| 168 | +
|
| 169 | + if [ "$HTTP_CODE" = "200" ]; then |
| 170 | + SUMMARY=$(jq -r '.choices[0].message.content // empty' /tmp/ai-response.json) |
| 171 | + if [ -n "$SUMMARY" ]; then |
| 172 | + echo "$SUMMARY" > /tmp/digest-final.md |
| 173 | + else |
| 174 | + cp /tmp/digest-data.txt /tmp/digest-final.md |
| 175 | + fi |
| 176 | + else |
| 177 | + echo "::warning::OpenRouter returned HTTP $HTTP_CODE, using raw digest" |
| 178 | + cp /tmp/digest-data.txt /tmp/digest-final.md |
| 179 | + fi |
| 180 | +
|
| 181 | + - name: Post digest as issue |
| 182 | + env: |
| 183 | + GH_TOKEN: ${{ github.token }} |
| 184 | + run: | |
| 185 | + TODAY=$(date -u +%Y-%m-%d) |
| 186 | +
|
| 187 | + { |
| 188 | + cat /tmp/digest-final.md |
| 189 | + echo "" |
| 190 | + echo "---" |
| 191 | + echo "*Daily digest generated automatically — [workflow source](${{ github.server_url }}/${{ github.repository }}/blob/main/.github/workflows/daily-digest.yml)*" |
| 192 | + } > /tmp/issue-body.md |
| 193 | +
|
| 194 | + gh issue create \ |
| 195 | + --repo "${{ github.repository }}" \ |
| 196 | + --title "Daily Digest: $TODAY" \ |
| 197 | + --body-file /tmp/issue-body.md \ |
| 198 | + --label "digest" |
0 commit comments