mirror of
https://github.com/multipleof4/gitea-github-cron.git
synced 2026-10-13 23:55:20 +00:00
Tidy ntfy notifications with markdown and a run button
Hide zero counts on one compact line, list changes as bullets, add a pass/fail emoji tag, and replace the tap-to-open run link with an "Open run" action button. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,51 +1,56 @@
|
|||||||
const { readFileSync } = require('node:fs');
|
const { readFileSync } = require('node:fs');
|
||||||
const { NTFY_TOPIC_URL, RUN_URL, STEP_OUTCOME, TEST_NOTIFICATION, WORKFLOW_KIND } = process.env;
|
const { NTFY_TOPIC_URL, RUN_URL, STEP_OUTCOME, TEST_NOTIFICATION, WORKFLOW_KIND } = process.env;
|
||||||
|
|
||||||
|
// [noun, key]: shown as "**n** noun(s)" and hidden when zero
|
||||||
const labels = {
|
const labels = {
|
||||||
mirror: ['Mirror sync', 'mirror-facts.json', [
|
mirror: ['Mirror sync', 'mirror-facts.json', [
|
||||||
['Organizations checked', 'orgsChecked'],
|
['org', 'orgsChecked'],
|
||||||
['GitHub repositories found', 'reposFound'],
|
['repo', 'reposFound'],
|
||||||
['Organizations created', 'orgsCreated'],
|
['created org', 'orgsCreated'],
|
||||||
['Org visibility changes', 'orgVisibilityChanged'],
|
['org visibility change', 'orgVisibilityChanged'],
|
||||||
['Org avatars updated', 'avatarsUpdated'],
|
['new mirror', 'mirrorsCreated'],
|
||||||
['New mirrors', 'mirrorsCreated'],
|
['repo visibility change', 'repoVisibilityChanged'],
|
||||||
['Repo visibility changes', 'repoVisibilityChanged'],
|
['failure', 'failures']
|
||||||
['Failures', 'failures']
|
|
||||||
]],
|
]],
|
||||||
rename: ['Missing-mirror check', 'rename-facts.json', [
|
rename: ['Missing-mirror check', 'rename-facts.json', [
|
||||||
['Gitea organizations checked', 'orgsChecked'],
|
['org', 'orgsChecked'],
|
||||||
['GitHub mirrors found', 'mirrorsFound'],
|
['mirror', 'mirrorsFound'],
|
||||||
['Renamed mirrors', 'renamed'],
|
['renamed mirror', 'renamed'],
|
||||||
['Organizations skipped', 'skippedOrgs'],
|
['skipped org', 'skippedOrgs'],
|
||||||
['Failures', 'failures']
|
['failure', 'failures']
|
||||||
]]
|
]]
|
||||||
};
|
};
|
||||||
|
const md = text => String(text).replace(/[\\`*_[\]#]/g, '\\$&');
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
if (!NTFY_TOPIC_URL || !labels[WORKFLOW_KIND]) throw new Error('Notification URL or workflow kind missing');
|
if (!NTFY_TOPIC_URL || !labels[WORKFLOW_KIND]) throw new Error('Notification URL or workflow kind missing');
|
||||||
const test = TEST_NOTIFICATION === 'true';
|
const test = TEST_NOTIFICATION === 'true', ok = STEP_OUTCOME === 'success';
|
||||||
const [label, file, fields] = labels[WORKFLOW_KIND];
|
const [label, file, fields] = labels[WORKFLOW_KIND];
|
||||||
const title = test ? 'Gitea backup notification test' : `${label}: ${STEP_OUTCOME === 'success' ? 'succeeded' : 'failed'}`;
|
const title = test ? 'Gitea backup notification test' : `${label}: ${ok ? 'succeeded' : 'failed'}`;
|
||||||
const lines = test ? ['Notification-only test. No mirror or rename ran.'] : [];
|
const lines = test ? ['Notification-only test. No mirror or rename ran.'] : [];
|
||||||
|
|
||||||
if (!test) {
|
if (!test) {
|
||||||
try {
|
try {
|
||||||
const facts = JSON.parse(readFileSync(file, 'utf8'));
|
const facts = JSON.parse(readFileSync(file, 'utf8'));
|
||||||
lines.push(...fields.map(([name, key]) => `${name}: ${facts[key] ?? 0}`));
|
const counts = fields.filter(([, k]) => facts[k]).map(([noun, k]) => `**${facts[k]}** ${noun}${facts[k] === 1 ? '' : 's'}`);
|
||||||
|
if (counts.length) lines.push(counts.join(' · '));
|
||||||
const changes = facts.changes || [];
|
const changes = facts.changes || [];
|
||||||
if (changes.length) lines.push('Changes:', ...changes.slice(0, 10));
|
if (changes.length) lines.push('', ...changes.slice(0, 10).map(c => `- ${md(c)}`));
|
||||||
if (changes.length > 10) lines.push(`...and ${changes.length - 10} more; see run logs.`);
|
if (changes.length > 10) lines.push(`- *…and ${changes.length - 10} more; see run logs.*`);
|
||||||
if (facts.fatal) lines.push('Fatal error; see run logs.');
|
if (facts.fatal) lines.push('', '**Fatal error**; see run logs.');
|
||||||
} catch {
|
} catch {
|
||||||
lines.push('No run summary available; see run logs.');
|
lines.push('No run summary available; see run logs.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RUN_URL) lines.push(`Run: ${RUN_URL}`);
|
|
||||||
const res = await fetch(NTFY_TOPIC_URL, {
|
const res = await fetch(NTFY_TOPIC_URL, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { Priority: '2', Title: title, ...(RUN_URL && { Click: RUN_URL }) },
|
headers: {
|
||||||
body: lines.join('\n'),
|
Priority: '2', Title: title, Markdown: 'yes',
|
||||||
|
Tags: test ? 'test_tube' : ok ? 'white_check_mark' : 'x',
|
||||||
|
...(RUN_URL && { Actions: `view, Open run, ${RUN_URL}` })
|
||||||
|
},
|
||||||
|
body: lines.join('\n') || 'Nothing to report.',
|
||||||
signal: AbortSignal.timeout(30_000)
|
signal: AbortSignal.timeout(30_000)
|
||||||
});
|
});
|
||||||
if (!res.ok) throw new Error(`ntfy returned HTTP ${res.status}`);
|
if (!res.ok) throw new Error(`ntfy returned HTTP ${res.status}`);
|
||||||
|
|||||||
Reference in New Issue
Block a user