Monthly Metrics Snapshot workflow (affaan-m/ECC)
The Monthly Metrics Snapshot workflow from affaan-m/ECC, explained and optimized by Latchkey.
A
CI health: A - excellent
Point runs-on at Latchkey and get job timeouts, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the Monthly Metrics Snapshot workflow from the affaan-m/ECC repository, a real project running GitHub Actions. It is shown here with attribution under its MIT license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
workflow (.yml)
name: Monthly Metrics Snapshot
on:
schedule:
- cron: '0 14 1 * *' # Monthly on the 1st at 14:00 UTC
workflow_dispatch:
permissions:
contents: read
issues: write
jobs:
snapshot:
name: Update metrics issue
runs-on: ubuntu-latest
steps:
- name: Update monthly metrics issue
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
const title = "Monthly Metrics Snapshot";
const label = "metrics-snapshot";
const monthKey = new Date().toISOString().slice(0, 7);
function parseLastPage(linkHeader) {
if (!linkHeader) return null;
const match = linkHeader.match(/&page=(\d+)>; rel="last"/);
return match ? Number(match[1]) : null;
}
function escapeRegex(value) {
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
function fmt(value) {
if (value === null || value === undefined) return "n/a";
return Number(value).toLocaleString("en-US");
}
async function getNpmDownloads(range, pkg) {
try {
const res = await fetch(`https://api.npmjs.org/downloads/point/${range}/${pkg}`);
if (!res.ok) return null;
const data = await res.json();
return data.downloads ?? null;
} catch {
return null;
}
}
async function getContributorsCount() {
try {
const resp = await github.rest.repos.listContributors({
owner,
repo,
per_page: 1,
anon: "false"
});
return parseLastPage(resp.headers.link) ?? resp.data.length;
} catch {
return null;
}
}
async function getReleasesCount() {
try {
const resp = await github.rest.repos.listReleases({
owner,
repo,
per_page: 1
});
return parseLastPage(resp.headers.link) ?? resp.data.length;
} catch {
return null;
}
}
async function getTraffic(metric) {
try {
const route = metric === "clones"
? "GET /repos/{owner}/{repo}/traffic/clones"
: "GET /repos/{owner}/{repo}/traffic/views";
const resp = await github.request(route, { owner, repo });
return resp.data?.count ?? null;
} catch {
return null;
}
}
const [
mainWeek,
shieldWeek,
mainMonth,
shieldMonth,
repoData,
contributors,
releases,
views14d,
clones14d
] = await Promise.all([
getNpmDownloads("last-week", "ecc-universal"),
getNpmDownloads("last-week", "ecc-agentshield"),
getNpmDownloads("last-month", "ecc-universal"),
getNpmDownloads("last-month", "ecc-agentshield"),
github.rest.repos.get({ owner, repo }),
getContributorsCount(),
getReleasesCount(),
getTraffic("views"),
getTraffic("clones")
]);
const stars = repoData.data.stargazers_count;
const forks = repoData.data.forks_count;
const tableHeader = [
"| Month (UTC) | ecc-universal (week) | ecc-agentshield (week) | ecc-universal (30d) | ecc-agentshield (30d) | Stars | Forks | Contributors | GitHub App installs (manual) | Views (14d) | Clones (14d) | Releases |",
"|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|"
].join("\n");
const row = `| ${monthKey} | ${fmt(mainWeek)} | ${fmt(shieldWeek)} | ${fmt(mainMonth)} | ${fmt(shieldMonth)} | ${fmt(stars)} | ${fmt(forks)} | ${fmt(contributors)} | n/a | ${fmt(views14d)} | ${fmt(clones14d)} | ${fmt(releases)} |`;
const intro = [
"# Monthly Metrics Snapshot",
"",
"Automated monthly snapshot for sponsor/partner reporting.",
"",
"- `GitHub App installs (manual)` is intentionally manual until a stable public API path is available.",
"- Traffic metrics are 14-day rolling windows from the GitHub traffic API and can show `n/a` if unavailable.",
"",
tableHeader
].join("\n");
try {
await github.rest.issues.getLabel({ owner, repo, name: label });
} catch (error) {
if (error.status === 404) {
await github.rest.issues.createLabel({
owner,
repo,
name: label,
color: "0e8a16",
description: "Automated monthly project metrics snapshots"
});
} else {
throw error;
}
}
const issuesResp = await github.rest.issues.listForRepo({
owner,
repo,
state: "open",
labels: label,
per_page: 100
});
let issue = issuesResp.data.find((item) => item.title === title);
if (!issue) {
const created = await github.rest.issues.create({
owner,
repo,
title,
labels: [label],
body: `${intro}\n${row}\n`
});
console.log(`Created issue #${created.data.number}`);
return;
}
const currentBody = issue.body || "";
const rowPattern = new RegExp(`^\\| ${escapeRegex(monthKey)} \\|.*$`, "m");
let body;
if (rowPattern.test(currentBody)) {
body = currentBody.replace(rowPattern, row);
console.log(`Refreshed issue #${issue.number} snapshot row for ${monthKey}`);
} else {
body = currentBody.includes("| Month (UTC) |")
? `${currentBody.trimEnd()}\n${row}\n`
: `${intro}\n${row}\n`;
}
await github.rest.issues.update({
owner,
repo,
issue_number: issue.number,
body
});
console.log(`Updated issue #${issue.number}`);
The same workflow, on Latchkey
Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.
name: Monthly Metrics Snapshot on: schedule: - cron: '0 14 1 * *' # Monthly on the 1st at 14:00 UTC workflow_dispatch: permissions: contents: read issues: write jobs: snapshot: timeout-minutes: 30 name: Update metrics issue runs-on: latchkey-small steps: - name: Update monthly metrics issue uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | const owner = context.repo.owner; const repo = context.repo.repo; const title = "Monthly Metrics Snapshot"; const label = "metrics-snapshot"; const monthKey = new Date().toISOString().slice(0, 7); function parseLastPage(linkHeader) { if (!linkHeader) return null; const match = linkHeader.match(/&page=(\d+)>; rel="last"/); return match ? Number(match[1]) : null; } function escapeRegex(value) { return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } function fmt(value) { if (value === null || value === undefined) return "n/a"; return Number(value).toLocaleString("en-US"); } async function getNpmDownloads(range, pkg) { try { const res = await fetch(`https://api.npmjs.org/downloads/point/${range}/${pkg}`); if (!res.ok) return null; const data = await res.json(); return data.downloads ?? null; } catch { return null; } } async function getContributorsCount() { try { const resp = await github.rest.repos.listContributors({ owner, repo, per_page: 1, anon: "false" }); return parseLastPage(resp.headers.link) ?? resp.data.length; } catch { return null; } } async function getReleasesCount() { try { const resp = await github.rest.repos.listReleases({ owner, repo, per_page: 1 }); return parseLastPage(resp.headers.link) ?? resp.data.length; } catch { return null; } } async function getTraffic(metric) { try { const route = metric === "clones" ? "GET /repos/{owner}/{repo}/traffic/clones" : "GET /repos/{owner}/{repo}/traffic/views"; const resp = await github.request(route, { owner, repo }); return resp.data?.count ?? null; } catch { return null; } } const [ mainWeek, shieldWeek, mainMonth, shieldMonth, repoData, contributors, releases, views14d, clones14d ] = await Promise.all([ getNpmDownloads("last-week", "ecc-universal"), getNpmDownloads("last-week", "ecc-agentshield"), getNpmDownloads("last-month", "ecc-universal"), getNpmDownloads("last-month", "ecc-agentshield"), github.rest.repos.get({ owner, repo }), getContributorsCount(), getReleasesCount(), getTraffic("views"), getTraffic("clones") ]); const stars = repoData.data.stargazers_count; const forks = repoData.data.forks_count; const tableHeader = [ "| Month (UTC) | ecc-universal (week) | ecc-agentshield (week) | ecc-universal (30d) | ecc-agentshield (30d) | Stars | Forks | Contributors | GitHub App installs (manual) | Views (14d) | Clones (14d) | Releases |", "|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|" ].join("\n"); const row = `| ${monthKey} | ${fmt(mainWeek)} | ${fmt(shieldWeek)} | ${fmt(mainMonth)} | ${fmt(shieldMonth)} | ${fmt(stars)} | ${fmt(forks)} | ${fmt(contributors)} | n/a | ${fmt(views14d)} | ${fmt(clones14d)} | ${fmt(releases)} |`; const intro = [ "# Monthly Metrics Snapshot", "", "Automated monthly snapshot for sponsor/partner reporting.", "", "- `GitHub App installs (manual)` is intentionally manual until a stable public API path is available.", "- Traffic metrics are 14-day rolling windows from the GitHub traffic API and can show `n/a` if unavailable.", "", tableHeader ].join("\n"); try { await github.rest.issues.getLabel({ owner, repo, name: label }); } catch (error) { if (error.status === 404) { await github.rest.issues.createLabel({ owner, repo, name: label, color: "0e8a16", description: "Automated monthly project metrics snapshots" }); } else { throw error; } } const issuesResp = await github.rest.issues.listForRepo({ owner, repo, state: "open", labels: label, per_page: 100 }); let issue = issuesResp.data.find((item) => item.title === title); if (!issue) { const created = await github.rest.issues.create({ owner, repo, title, labels: [label], body: `${intro}\n${row}\n` }); console.log(`Created issue #${created.data.number}`); return; } const currentBody = issue.body || ""; const rowPattern = new RegExp(`^\\| ${escapeRegex(monthKey)} \\|.*$`, "m"); let body; if (rowPattern.test(currentBody)) { body = currentBody.replace(rowPattern, row); console.log(`Refreshed issue #${issue.number} snapshot row for ${monthKey}`); } else { body = currentBody.includes("| Month (UTC) |") ? `${currentBody.trimEnd()}\n${row}\n` : `${intro}\n${row}\n`; } await github.rest.issues.update({ owner, repo, issue_number: issue.number, body }); console.log(`Updated issue #${issue.number}`);
What changed
- Run on Latchkey managed runners with one line (
runs-on), which apply the fixes below automatically and self-heal transient failures. This example useslatchkey-small; pick the runner size that fits the job. - Add a job timeout so a hung step cannot burn hours of runner time.
This workflow runs 1 job per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.