Skip to content

Commit 2d19c42

Browse files
authored
Add Discord announcement action (#1572)
1 parent 4e4df3d commit 2d19c42

File tree

2 files changed

+96
-0
lines changed

2 files changed

+96
-0
lines changed

.changeset/tidy-bobcats-wait.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@radui/ui": patch
3+
---
4+
5+
Testing Discord Release Workflow

.github/workflows/release.yml

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,94 @@ jobs:
7979
env:
8080
NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTOMATION_TOKEN_FROM_KOTAPI }}
8181
run: npm publish --access public --provenance
82+
83+
- name: Announce on Discord (with changelog + README summary)
84+
if: steps.exists.outputs.exists == 'false'
85+
env:
86+
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
87+
PKG_NAME: ${{ steps.pkg.outputs.name }}
88+
PKG_VERSION: ${{ steps.pkg.outputs.version }}
89+
REPO: ${{ github.repository }}
90+
run: |
91+
node - <<'NODE'
92+
const fs = require('fs');
93+
const https = require('https');
94+
95+
const webhook = process.env.DISCORD_WEBHOOK_URL;
96+
const name = process.env.PKG_NAME;
97+
const version = process.env.PKG_VERSION;
98+
const repo = process.env.REPO;
99+
100+
const npmUrl = `https://www.npmjs.com/package/${encodeURIComponent(name)}/v/${version}`;
101+
const ghUrl = `https://github.com/${repo}`;
102+
103+
const read = (p) => { try { return fs.readFileSync(p, 'utf8'); } catch { return ''; } };
104+
const squash = (s='') => s
105+
.replace(/<!--[\s\S]*?-->/g, '')
106+
.replace(/\r/g, '')
107+
.replace(/\n{3,}/g, '\n\n')
108+
.trim();
109+
const trunc = (s, n) => (s.length > n ? s.slice(0, n - 1) + '…' : s);
110+
111+
// README summary (first paragraph after title/badges)
112+
let readmeSummary = '';
113+
const readme = read('README.md');
114+
if (readme) {
115+
const lines = readme.split('\n');
116+
let i = 0;
117+
while (i < lines.length && (/^\s*#\s/.test(lines[i]) || /!\[.*\]\(.*\)|<img/i.test(lines[i]) || /^\s*$/.test(lines[i]))) i++;
118+
const para = [];
119+
for (; i < lines.length && !/^\s*$/.test(lines[i]); i++) para.push(lines[i]);
120+
readmeSummary = trunc(squash(para.join('\n')), 900); // field limit safe
121+
}
122+
123+
// Changelog section for this version
124+
let changelog = '';
125+
const raw = read('CHANGELOG.md');
126+
if (raw) {
127+
const esc = (v) => v.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
128+
const pats = [
129+
new RegExp(`^##\\s*\\[?v?${esc(version)}\\]?\\s*$`, 'mi'),
130+
new RegExp(`^##\\s*.*\\s+v?${esc(version)}\\s*$`, 'mi'),
131+
];
132+
let start = -1;
133+
for (const p of pats) { const m = raw.match(p); if (m) { start = m.index; break; } }
134+
if (start >= 0) {
135+
const tail = raw.slice(start);
136+
const next = tail.search(/^##\s+/m);
137+
const section = (next > 0 ? tail.slice(0, next) : tail).replace(/^##.*$/m, '');
138+
changelog = trunc(squash(section), 3600); // embed desc limit
139+
} else {
140+
// fallback: top-most section
141+
const parts = raw.split(/^##\s+/m);
142+
if (parts[1]) changelog = trunc(squash(parts[1]), 3600);
143+
}
144+
}
145+
146+
const body = {
147+
username: "Rad UI Release Bot",
148+
// avatar_url: "https://your.cdn/rad-ui-logo.png", // optional
149+
embeds: [{
150+
title: `Released ${name} ${version} 🎉`,
151+
url: npmUrl,
152+
description: changelog || "Changelog is available in the repo.",
153+
fields: [
154+
...(readmeSummary ? [{ name: "Summary", value: readmeSummary, inline: false }] : []),
155+
{ name: "npm", value: `[${name}@${version}](${npmUrl})`, inline: true },
156+
{ name: "GitHub", value: ghUrl, inline: true }
157+
],
158+
timestamp: new Date().toISOString()
159+
}]
160+
};
161+
162+
const data = JSON.stringify(body);
163+
const u = new URL(webhook);
164+
const req = https.request(
165+
{ hostname: u.hostname, path: u.pathname + u.search, method: 'POST',
166+
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) } },
167+
res => { res.resume(); res.on('end', () => process.exit(res.statusCode < 300 ? 0 : 1)); }
168+
);
169+
req.on('error', err => { console.error(err); process.exit(1); });
170+
req.write(data); req.end();
171+
NODE
172+

0 commit comments

Comments
 (0)