From 91504546c48515a28a573f334ab90d873238150f Mon Sep 17 00:00:00 2001 From: angiejones Date: Mon, 20 Oct 2025 19:04:17 -0700 Subject: [PATCH] Add GitHub Health Dashboard workflow --- .github/workflows/update-health-dashboard.yml | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 .github/workflows/update-health-dashboard.yml diff --git a/.github/workflows/update-health-dashboard.yml b/.github/workflows/update-health-dashboard.yml new file mode 100644 index 00000000..26edf9fb --- /dev/null +++ b/.github/workflows/update-health-dashboard.yml @@ -0,0 +1,147 @@ +name: Update GitHub Health Dashboard + +# Trigger configuration +on: + # Run daily at midnight UTC + schedule: + - cron: '0 0 * * *' + + # Allow manual triggering from GitHub UI + workflow_dispatch: + +# Define permissions for the GITHUB_TOKEN +permissions: + # Required to read repository contents + contents: read + # Required to read issues and PRs + issues: read + pull-requests: read + # Required to update discussions + discussions: write + +jobs: + update-dashboard: + name: 'Update Health Dashboard' + runs-on: ubuntu-latest + + steps: + - name: 'Update Dashboard' + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const owner = context.repo.owner; + const repo = context.repo.repo; + const discussionNumber = 5285; + + console.log(`Fetching health metrics for ${owner}/${repo}`); + + // Fetch open issues + const { data: openIssues } = await github.rest.issues.listForRepo({ + owner, + repo, + state: 'open', + per_page: 100 + }); + + // Filter out PRs (issues API includes PRs) + const issues = openIssues.filter(issue => !issue.pull_request); + const totalOpenIssues = issues.length; + + // Count issues without labels (recent ones) + const issuesWithoutLabels = issues.filter(issue => issue.labels.length === 0); + + // Count issues by specific labels + const labelCounts = {}; + const targetLabels = ['P0', 'P1', 'Compaction', 'Windows', 'Provider', 'MCP/Extensions', 'Linux']; + + targetLabels.forEach(label => { + labelCounts[label] = issues.filter(issue => + issue.labels.some(l => l.name === label) + ).length; + }); + + // Fetch open PRs + const { data: openPRs } = await github.rest.pulls.list({ + owner, + repo, + state: 'open', + per_page: 100 + }); + + const totalOpenPRs = openPRs.length; + + // Format the dashboard markdown + const timestamp = new Date().toUTCString(); + + const dashboardBody = `# GitHub Health + +**Updated:** ${new Date().toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })} + +## Issues + +**Open:** ${totalOpenIssues} + +**No labels:** ${issuesWithoutLabels.length} (these are recent) + +### Label Breakdown + +| Label | Count | +|-------|-------| +| [P0](https://github.com/${owner}/${repo}/labels/P0) | ${labelCounts['P0'] || 0} | +| [P1](https://github.com/${owner}/${repo}/labels/P1) | ${labelCounts['P1'] || 0} | +| [Compaction](https://github.com/${owner}/${repo}/labels/Compaction) | ${labelCounts['Compaction'] || 0} | +| [Windows](https://github.com/${owner}/${repo}/labels/Windows) | ${labelCounts['Windows'] || 0} | +| [Provider](https://github.com/${owner}/${repo}/labels/Provider) | ${labelCounts['Provider'] || 0} | +| [MCP/Extensions](https://github.com/${owner}/${repo}/labels/MCP%2FExtensions) | ${labelCounts['MCP/Extensions'] || 0} | +| [Linux](https://github.com/${owner}/${repo}/labels/Linux) | ${labelCounts['Linux'] || 0} | + +## Open PRs + +**Total:** ${totalOpenPRs} + +--- + +*Last updated: ${timestamp}* +*This dashboard is automatically updated daily by [GitHub Actions](https://github.com/${owner}/${repo}/actions/workflows/update-health-dashboard.yml)*`; + + console.log('Dashboard generated, updating discussion...'); + + // Get the discussion node ID using GraphQL + const discussionQuery = ` + query GetDiscussion($owner: String!, $repo: String!, $number: Int!) { + repository(owner: $owner, name: $repo) { + discussion(number: $number) { + id + } + } + } + `; + + const discussionResult = await github.graphql(discussionQuery, { + owner, + repo, + number: discussionNumber + }); + + const discussionId = discussionResult.repository.discussion.id; + console.log(`Found discussion ID: ${discussionId}`); + + // Update the discussion using GraphQL mutation + const updateMutation = ` + mutation UpdateDiscussion($discussionId: ID!, $body: String!) { + updateDiscussion(input: {discussionId: $discussionId, body: $body}) { + discussion { + id + number + } + } + } + `; + + await github.graphql(updateMutation, { + discussionId, + body: dashboardBody + }); + + console.log(`Successfully updated discussion #${discussionNumber}`);