Merge pull request #118 from YellowSnnowmann/feat/github-release-discord-notify

feat: add Discord notification for new releases in GitHub Actions wor…
This commit is contained in:
Cyrus Gray
2026-03-31 17:52:54 +05:30
committed by GitHub
+141
View File
@@ -704,6 +704,147 @@ jobs:
});
core.info(`Published release ${releaseId}`);
notify-discord:
name: Notify Discord about release
runs-on: ubuntu-latest
environment: Production
needs: [prepare-release, create-release, build-artifacts, publish-release]
if: needs.publish-release.result == 'success' && needs.build-artifacts.result == 'success'
steps:
- name: Post release notification to Discord
continue-on-error: true
uses: actions/github-script@v7
env:
DISCORD_RELEASE_WEBHOOK_URL: ${{ secrets.DISCORD_RELEASE_WEBHOOK_URL }}
RELEASE_ID: ${{ needs.create-release.outputs.release_id }}
RELEASE_TAG: ${{ needs.prepare-release.outputs.tag }}
with:
script: |
const webhookUrl = process.env.DISCORD_RELEASE_WEBHOOK_URL;
const releaseId = Number(process.env.RELEASE_ID);
const releaseTag = process.env.RELEASE_TAG;
if (!webhookUrl) {
core.warning('DISCORD_RELEASE_WEBHOOK_URL is not configured; skipping Discord release notification.');
return;
}
if (!Number.isFinite(releaseId) || releaseId <= 0) {
core.warning(`Invalid release id "${process.env.RELEASE_ID}"; skipping Discord release notification.`);
return;
}
const { owner, repo } = context.repo;
const maxDescriptionLength = 3500;
const maxAssetLines = 8;
function truncate(text, maxLength) {
if (!text) return '';
if (text.length <= maxLength) return text;
return `${text.slice(0, maxLength - 3)}...`;
}
function stripMarkdownHeadings(text) {
return text
.replace(/^#{1,6}\s+/gm, '')
.replace(/\r/g, '')
.trim();
}
const { data: release } = await github.rest.repos.getRelease({
owner,
repo,
release_id: releaseId,
});
const releases = await github.paginate(github.rest.repos.listReleases, {
owner,
repo,
per_page: 100,
});
const sortedPublished = releases
.filter((item) => !item.draft)
.sort((a, b) => new Date(b.published_at || b.created_at || 0) - new Date(a.published_at || a.created_at || 0));
const currentIndex = sortedPublished.findIndex((item) => item.id === release.id);
const previousRelease = currentIndex >= 0 ? sortedPublished[currentIndex + 1] : null;
const compareUrl = previousRelease
? `https://github.com/${owner}/${repo}/compare/${previousRelease.tag_name}...${release.tag_name}`
: null;
const releaseTitle = release.name || release.tag_name || releaseTag;
const bodyText = stripMarkdownHeadings(release.body || '');
const summary = bodyText
? truncate(bodyText, maxDescriptionLength)
: 'GitHub release published. See the release page for full notes.';
const assetLines = (release.assets || [])
.slice(0, maxAssetLines)
.map((asset) => `- [${asset.name}](${asset.browser_download_url})`);
const extraAssetCount = Math.max((release.assets || []).length - maxAssetLines, 0);
if (extraAssetCount > 0) {
assetLines.push(`- ${extraAssetCount} more asset(s) available on the release page`);
}
const fields = [
{
name: 'Version',
value: `\`${release.tag_name || releaseTag}\``,
inline: true,
},
{
name: 'Release',
value: `[Open on GitHub](${release.html_url})`,
inline: true,
},
];
if (compareUrl) {
fields.push({
name: 'Compare',
value: `[${previousRelease.tag_name}...${release.tag_name}](${compareUrl})`,
inline: true,
});
}
if (assetLines.length > 0) {
fields.push({
name: 'Artifacts',
value: assetLines.join('\n'),
inline: false,
});
}
const payload = {
content: `New GitHub release published for \`${owner}/${repo}\`: **${releaseTitle}**`,
embeds: [
{
title: releaseTitle,
url: release.html_url,
description: summary,
color: release.prerelease ? 0xf0ad4e : 0x2ecc71,
fields,
footer: {
text: release.prerelease ? 'Pre-release' : 'Published release',
},
timestamp: release.published_at || new Date().toISOString(),
},
],
};
const response = await fetch(webhookUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
});
if (!response.ok) {
const body = await response.text();
core.warning(`Discord notification failed: HTTP ${response.status} ${body.slice(0, 300)}`);
return;
}
core.info(`Posted Discord release notification for ${release.tag_name || releaseTag}.`);
cleanup-failed-release:
name: Remove release and tag if build failed
runs-on: ubuntu-latest