Show recent GitHub commits on competitor cards
Some checks failed
Deploy to Cloudflare / deploy (push) Has been cancelled
Some checks failed
Deploy to Cloudflare / deploy (push) Has been cancelled
Each competitor card now shows their last 3 commits from their repo. Commits are fetched from GitHub API and cached in KV for 5 minutes. - Omar: Bored-investments/chuckasickie - Rhys: Bored-investments/milly-countdown Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
a8bac830ea
commit
f72fbbf8e0
1 changed files with 47 additions and 7 deletions
54
worker.js
54
worker.js
|
|
@ -26,13 +26,14 @@ export default {
|
||||||
return new Response('Updated');
|
return new Response('Updated');
|
||||||
}
|
}
|
||||||
|
|
||||||
const [revenuesRaw, metricsRaw] = await Promise.all([
|
const competitors = defaultCompetitors();
|
||||||
|
|
||||||
|
const [revenuesRaw, metricsRaw, ...commitArrays] = await Promise.all([
|
||||||
env.MILLY_METRICS.get('revenues'),
|
env.MILLY_METRICS.get('revenues'),
|
||||||
env.MILLY_METRICS.get('metrics'),
|
env.MILLY_METRICS.get('metrics'),
|
||||||
|
...Object.values(competitors).map(c => fetchCommits(env, c.repo)),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Static config always comes from code — KV only stores revenue numbers
|
|
||||||
const competitors = defaultCompetitors();
|
|
||||||
const revenues = revenuesRaw ? JSON.parse(revenuesRaw) : {};
|
const revenues = revenuesRaw ? JSON.parse(revenuesRaw) : {};
|
||||||
const metrics = metricsRaw ? JSON.parse(metricsRaw) : {};
|
const metrics = metricsRaw ? JSON.parse(metricsRaw) : {};
|
||||||
|
|
||||||
|
|
@ -42,6 +43,10 @@ export default {
|
||||||
for (const id of ['rhys', 'pussy', 'patty']) {
|
for (const id of ['rhys', 'pussy', 'patty']) {
|
||||||
if (revenues[id] != null) competitors[id].revenue = revenues[id];
|
if (revenues[id] != null) competitors[id].revenue = revenues[id];
|
||||||
}
|
}
|
||||||
|
// Attach commits
|
||||||
|
Object.keys(competitors).forEach((id, i) => {
|
||||||
|
competitors[id].commits = commitArrays[i] || [];
|
||||||
|
});
|
||||||
|
|
||||||
return new Response(render(competitors), {
|
return new Response(render(competitors), {
|
||||||
headers: { 'Content-Type': 'text/html;charset=UTF-8', 'Cache-Control': 'no-store' }
|
headers: { 'Content-Type': 'text/html;charset=UTF-8', 'Cache-Control': 'no-store' }
|
||||||
|
|
@ -51,13 +56,34 @@ export default {
|
||||||
|
|
||||||
function defaultCompetitors() {
|
function defaultCompetitors() {
|
||||||
return {
|
return {
|
||||||
omar: { name:'King Omar', ai:'Claude Pro', revenue:0, color:'#6366f1', emoji:'👑', github:'kingomarwashere' },
|
omar: { name:'King Omar', ai:'Claude Pro', revenue:0, color:'#6366f1', emoji:'👑', github:'kingomarwashere', repo:'Bored-investments/chuckasickie' },
|
||||||
rhys: { name:'Basic Rhys', ai:'Codex', revenue:0, color:'#f59e0b', emoji:'🤓', github:'rhy-collab' },
|
rhys: { name:'Basic Rhys', ai:'Codex', revenue:0, color:'#f59e0b', emoji:'🤓', github:'rhy-collab', repo:'Bored-investments/milly-countdown' },
|
||||||
pussy: { name:'Pussy', ai:'Hermes Plus Ching Chong',revenue:0, color:'#ec4899', emoji:'🐱', github:'QuixThe2nd' },
|
pussy: { name:'Pussy', ai:'Hermes Plus Ching Chong',revenue:0, color:'#ec4899', emoji:'🐱', github:'QuixThe2nd', repo:null },
|
||||||
patty: { name:'Patty', ai:'Copilot & Clawpilot', revenue:0, color:'#10b981', emoji:'🤠', github:null },
|
patty: { name:'Patty', ai:'Copilot & Clawpilot', revenue:0, color:'#10b981', emoji:'🤠', github:null, repo:null },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function fetchCommits(env, repo) {
|
||||||
|
if (!repo) return [];
|
||||||
|
const cacheKey = `commits:${repo}`;
|
||||||
|
const cached = await env.MILLY_METRICS.get(cacheKey);
|
||||||
|
if (cached) return JSON.parse(cached);
|
||||||
|
try {
|
||||||
|
const res = await fetch(`https://api.github.com/repos/${repo}/commits?per_page=3`, {
|
||||||
|
headers: { 'User-Agent': 'milly-countdown' }
|
||||||
|
});
|
||||||
|
const data = await res.json();
|
||||||
|
if (!Array.isArray(data)) return [];
|
||||||
|
const commits = data.map(c => ({
|
||||||
|
sha: c.sha?.slice(0, 7),
|
||||||
|
message: c.commit?.message?.split('\n')[0]?.slice(0, 72),
|
||||||
|
date: c.commit?.author?.date,
|
||||||
|
}));
|
||||||
|
await env.MILLY_METRICS.put(cacheKey, JSON.stringify(commits), { expirationTtl: 300 });
|
||||||
|
return commits;
|
||||||
|
} catch { return []; }
|
||||||
|
}
|
||||||
|
|
||||||
const fmt = n => n >= 1e6 ? `$${(n/1e6).toFixed(3)}M` : n >= 1000 ? `$${(n/1000).toFixed(1)}K` : `$${n.toFixed(0)}`;
|
const fmt = n => n >= 1e6 ? `$${(n/1e6).toFixed(3)}M` : n >= 1000 ? `$${(n/1000).toFixed(1)}K` : `$${n.toFixed(0)}`;
|
||||||
const pct = r => Math.min((r / GOAL) * 100, 100);
|
const pct = r => Math.min((r / GOAL) * 100, 100);
|
||||||
|
|
||||||
|
|
@ -223,6 +249,14 @@ html,body{min-height:100vh;background:#080401;color:#fff;font-family:'Inter',san
|
||||||
.org-btn:hover{background:#1f1f1f;border-color:#6366f1;color:#fff}
|
.org-btn:hover{background:#1f1f1f;border-color:#6366f1;color:#fff}
|
||||||
.org-btn svg{width:16px;height:16px;fill:currentColor}
|
.org-btn svg{width:16px;height:16px;fill:currentColor}
|
||||||
|
|
||||||
|
/* === COMMITS === */
|
||||||
|
.card-commits{margin-top:10px;border-top:1px solid rgba(255,255,255,0.05);padding-top:8px;display:flex;flex-direction:column;gap:4px}
|
||||||
|
.card-commit{display:flex;align-items:baseline;gap:6px;font-size:11px;line-height:1.4}
|
||||||
|
.commit-sha{font-family:'Courier New',monospace;color:#4b5563;text-decoration:none;flex-shrink:0;
|
||||||
|
transition:color 0.2s}
|
||||||
|
.commit-sha:hover{color:#9ca3af}
|
||||||
|
.commit-msg{color:#6b7280;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||||||
|
|
||||||
/* === FOOTER === */
|
/* === FOOTER === */
|
||||||
footer{text-align:center;padding:24px 20px;border-top:1px solid #140900;color:#374151;font-size:12px}
|
footer{text-align:center;padding:24px 20px;border-top:1px solid #140900;color:#374151;font-size:12px}
|
||||||
footer a{color:#4b5563;text-decoration:none}
|
footer a{color:#4b5563;text-decoration:none}
|
||||||
|
|
@ -301,6 +335,12 @@ footer a:hover{color:#9ca3af}
|
||||||
<svg viewBox="0 0 16 16"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/></svg>
|
<svg viewBox="0 0 16 16"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/></svg>
|
||||||
github.com/${c.github}
|
github.com/${c.github}
|
||||||
</a>` : `<span class="card-github" style="opacity:0.3">no github connected</span>`}
|
</a>` : `<span class="card-github" style="opacity:0.3">no github connected</span>`}
|
||||||
|
${c.commits?.length ? `<div class="card-commits">
|
||||||
|
${c.commits.map(cm => `<div class="card-commit">
|
||||||
|
<a href="https://github.com/${c.repo}/commit/${cm.sha}" target="_blank" class="commit-sha">${cm.sha}</a>
|
||||||
|
<span class="commit-msg">${cm.message}</span>
|
||||||
|
</div>`).join('')}
|
||||||
|
</div>` : ''}
|
||||||
</div>`).join('')}
|
</div>`).join('')}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue