Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 138 additions & 0 deletions .github/workflows/update-health-dashboard.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
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 formattedDate = new Date().toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });

const dashboardBody = '# GitHub Health\n\n' +
'**Updated:** ' + formattedDate + '\n\n' +
'## Issues\n\n' +
'**Open:** ' + totalOpenIssues + '\n\n' +
'**No labels:** ' + issuesWithoutLabels.length + ' (these are recent)\n\n' +
'### Label Breakdown\n\n' +
'| Label | Count |\n' +
'|-------|-------|\n' +
'| [P0](https://github.com/' + owner + '/' + repo + '/labels/P0) | ' + (labelCounts['P0'] || 0) + ' |\n' +
'| [P1](https://github.com/' + owner + '/' + repo + '/labels/P1) | ' + (labelCounts['P1'] || 0) + ' |\n' +
'| [Compaction](https://github.com/' + owner + '/' + repo + '/labels/Compaction) | ' + (labelCounts['Compaction'] || 0) + ' |\n' +
'| [Windows](https://github.com/' + owner + '/' + repo + '/labels/Windows) | ' + (labelCounts['Windows'] || 0) + ' |\n' +
'| [Provider](https://github.com/' + owner + '/' + repo + '/labels/Provider) | ' + (labelCounts['Provider'] || 0) + ' |\n' +
'| [MCP/Extensions](https://github.com/' + owner + '/' + repo + '/labels/MCP%2FExtensions) | ' + (labelCounts['MCP/Extensions'] || 0) + ' |\n' +
'| [Linux](https://github.com/' + owner + '/' + repo + '/labels/Linux) | ' + (labelCounts['Linux'] || 0) + ' |\n\n' +
'## Open PRs\n\n' +
'**Total:** ' + totalOpenPRs + '\n\n' +
'---\n\n' +
'*Last updated: ' + timestamp + '*\n' +
'*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}`);
Loading