Make next Discord changelog release-only
This commit is contained in:
296
.github/workflows/discord-changelog.yml
vendored
296
.github/workflows/discord-changelog.yml
vendored
@@ -1,21 +1,9 @@
|
||||
name: Discord changelog
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
- synchronize
|
||||
- closed
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
create:
|
||||
delete:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_tag:
|
||||
@@ -25,14 +13,13 @@ on:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
discord-changelog:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
||||
if: github.event_name == 'release' || github.event_name == 'workflow_dispatch'
|
||||
steps:
|
||||
- name: Post changelog to Discord
|
||||
- name: Post release changelog to Discord
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_CHANGELOG_WEBHOOK }}
|
||||
@@ -46,12 +33,40 @@ jobs:
|
||||
return;
|
||||
}
|
||||
|
||||
let eventName = context.eventName;
|
||||
let event = context.payload;
|
||||
const repoFullName = `${context.repo.owner}/${context.repo.repo}`;
|
||||
const repoUrl = `https://github.com/${repoFullName}`;
|
||||
if (context.eventName !== "release" && context.eventName !== "workflow_dispatch") {
|
||||
core.info(`Skipping ${context.eventName}; this workflow only posts releases.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const release = await getRelease();
|
||||
const messages = buildReleaseMessages(release);
|
||||
|
||||
for (const content of messages) {
|
||||
const response = await fetch(webhookUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username: "Repo Changelog",
|
||||
content,
|
||||
allowed_mentions: {
|
||||
parse: [],
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
core.setFailed(`Discord webhook failed with ${response.status}: ${await response.text()}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
async function getRelease() {
|
||||
if (context.eventName === "release") {
|
||||
return context.payload.release;
|
||||
}
|
||||
|
||||
if (eventName === "workflow_dispatch") {
|
||||
const releaseTag = process.env.RELEASE_TAG;
|
||||
const response = releaseTag
|
||||
? await github.rest.repos.getReleaseByTag({
|
||||
@@ -64,201 +79,26 @@ jobs:
|
||||
repo: context.repo.repo,
|
||||
});
|
||||
|
||||
eventName = "release";
|
||||
event = {
|
||||
action: "published",
|
||||
repository: {
|
||||
full_name: repoFullName,
|
||||
html_url: repoUrl,
|
||||
},
|
||||
sender: {
|
||||
login: context.actor,
|
||||
},
|
||||
release: response.data,
|
||||
};
|
||||
return response.data;
|
||||
}
|
||||
|
||||
const discordPayload = buildDiscordPayload(eventName, event);
|
||||
const discordResponse = await fetch(webhookUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(discordPayload),
|
||||
});
|
||||
function buildReleaseMessages(release) {
|
||||
const tag = release.tag_name || release.name || "release";
|
||||
const title = release.name || tag;
|
||||
const notes = formatReleaseNotes(release.body || "") || "No release notes provided.";
|
||||
const fullMessage = `**${title} Released**\n\n${notes}`;
|
||||
|
||||
if (!discordResponse.ok) {
|
||||
core.setFailed(
|
||||
`Discord webhook failed with ${discordResponse.status}: ${await discordResponse.text()}`,
|
||||
);
|
||||
}
|
||||
|
||||
function buildDiscordPayload(eventName, event) {
|
||||
return {
|
||||
username: "Repo Changelog",
|
||||
content: buildContent(eventName, event),
|
||||
embeds: [
|
||||
{
|
||||
...buildEmbed(eventName, event),
|
||||
footer: {
|
||||
text: `GitHub ${eventName} event`,
|
||||
},
|
||||
timestamp: new Date().toISOString(),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function buildContent(eventName, event) {
|
||||
const repo = getRepoName(event);
|
||||
|
||||
if (eventName === "release") {
|
||||
const tag = event.release?.tag_name || event.release?.name || "release";
|
||||
const action = event.action === "published" ? "published" : event.action || "updated";
|
||||
|
||||
return `**${repo}** ${action} **${tag}**`;
|
||||
}
|
||||
|
||||
return `**${repo}** update from ${getActor(event)}`;
|
||||
}
|
||||
|
||||
function buildEmbed(eventName, event) {
|
||||
if (eventName === "release") {
|
||||
return buildReleaseEmbed(event);
|
||||
}
|
||||
|
||||
if (eventName === "push") {
|
||||
return buildPushEmbed(event);
|
||||
}
|
||||
|
||||
if (eventName === "pull_request") {
|
||||
return buildPullRequestEmbed(event);
|
||||
}
|
||||
|
||||
if (eventName === "create" || eventName === "delete") {
|
||||
return buildRefEmbed(eventName, event);
|
||||
}
|
||||
|
||||
return {
|
||||
title: `GitHub ${eventName} event`,
|
||||
description: `Received a ${eventName} event for ${getRepoName(event)}.`,
|
||||
url: event.repository?.html_url,
|
||||
color: 0x99aab5,
|
||||
};
|
||||
}
|
||||
|
||||
function buildReleaseEmbed(event) {
|
||||
const release = event.release || {};
|
||||
const tag = release.tag_name || "release";
|
||||
const titleTag = release.name || tag;
|
||||
const author = release.author?.login || event.sender?.login || "unknown";
|
||||
|
||||
return {
|
||||
title: `${titleTag} Released`,
|
||||
description: formatReleaseNotes(release.body || "") || "No release notes provided.",
|
||||
url: release.html_url || event.repository?.html_url,
|
||||
color: 0x57f287,
|
||||
fields: [
|
||||
{
|
||||
name: "Repository",
|
||||
value: link(getRepoName(event), event.repository?.html_url),
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: "Tag",
|
||||
value: tag,
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: "Published by",
|
||||
value: author,
|
||||
inline: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function buildPushEmbed(event) {
|
||||
const repo = getRepoName(event);
|
||||
const branch = trimRef(event.ref);
|
||||
const commits = Array.isArray(event.commits) ? event.commits : [];
|
||||
const commitLines = commits.slice(0, 8).map(formatCommit).join("\n");
|
||||
const overflow = commits.length > 8 ? `\n...and ${commits.length - 8} more.` : "";
|
||||
const commitWord = commits.length === 1 ? "commit" : "commits";
|
||||
|
||||
return {
|
||||
title: `${commits.length} ${commitWord} pushed to ${branch}`,
|
||||
description: commitLines
|
||||
? `${commitLines}${overflow}`
|
||||
: "No commit list was included in this event.",
|
||||
url: event.compare || event.repository?.html_url,
|
||||
color: 0x5865f2,
|
||||
fields: [
|
||||
{
|
||||
name: "Repository",
|
||||
value: link(repo, event.repository?.html_url),
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: "Branch",
|
||||
value: branch,
|
||||
inline: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function buildPullRequestEmbed(event) {
|
||||
const pr = event.pull_request || {};
|
||||
const action =
|
||||
event.action === "closed" && pr.merged ? "merged" : event.action || "updated";
|
||||
const number = pr.number ? `#${pr.number}` : "";
|
||||
|
||||
return {
|
||||
title: `Pull request ${number} ${action}`,
|
||||
description: link(pr.title || "Pull request", pr.html_url),
|
||||
url: pr.html_url || event.repository?.html_url,
|
||||
color: pr.merged ? 0x57f287 : 0xfee75c,
|
||||
fields: [
|
||||
{
|
||||
name: "Author",
|
||||
value: pr.user?.login || event.sender?.login || "unknown",
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: "Branch",
|
||||
value: `${pr.head?.ref || "head"} -> ${pr.base?.ref || "base"}`,
|
||||
inline: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function buildRefEmbed(eventName, event) {
|
||||
const action = eventName === "create" ? "created" : "deleted";
|
||||
const type = event.ref_type || "ref";
|
||||
const ref = event.ref || "unknown";
|
||||
|
||||
return {
|
||||
title: `${capitalize(type)} ${action}: ${ref}`,
|
||||
description: `${getActor(event)} ${action} ${type} \`${ref}\`.`,
|
||||
url: event.repository?.html_url,
|
||||
color: eventName === "create" ? 0x57f287 : 0xed4245,
|
||||
};
|
||||
}
|
||||
|
||||
function formatCommit(commit) {
|
||||
const shortSha = commit.id ? commit.id.slice(0, 7) : "commit";
|
||||
const message = truncate(oneLine(commit.message || "No commit message"), 140);
|
||||
const author = commit.author?.name ? ` - ${commit.author.name}` : "";
|
||||
|
||||
return `- ${link(shortSha, commit.url)} ${message}${author}`;
|
||||
return splitDiscordMessage(fullMessage, 1900);
|
||||
}
|
||||
|
||||
function formatReleaseNotes(value) {
|
||||
return truncate(
|
||||
value
|
||||
.replace(/\r\n/g, "\n")
|
||||
.replace(/https:\/\/github\.com\/[^/\s]+\/[^/\s]+\/pull\/(\d+)/g, "#$1")
|
||||
.replace(/https:\/\/github\.com\/[^/\s]+\/[^/\s]+\/issues\/(\d+)/g, "#$1")
|
||||
.replace(/https:\/\/github\.com\/[^/\s]+\/[^/\s]+\/commit\/([0-9a-f]{7})[0-9a-f]*/gi, "$1")
|
||||
.replace(/https:\/\/github\.com\/\S+/g, "")
|
||||
.trim()
|
||||
.split("\n")
|
||||
.map((line) => {
|
||||
@@ -272,30 +112,38 @@ jobs:
|
||||
);
|
||||
}
|
||||
|
||||
function getRepoName(event) {
|
||||
return event.repository?.full_name || repoFullName;
|
||||
}
|
||||
function splitDiscordMessage(value, maxLength) {
|
||||
if (value.length <= maxLength) {
|
||||
return [value];
|
||||
}
|
||||
|
||||
function getActor(event) {
|
||||
return event.sender?.login || event.pusher?.name || context.actor || "GitHub";
|
||||
}
|
||||
const chunks = [];
|
||||
let remaining = value;
|
||||
|
||||
function link(label, url) {
|
||||
return url ? `[${label}](${url})` : label;
|
||||
}
|
||||
while (remaining.length > maxLength) {
|
||||
let splitAt = remaining.lastIndexOf("\n", maxLength);
|
||||
|
||||
function trimRef(ref) {
|
||||
return (ref || "unknown").replace(/^refs\/heads\//, "").replace(/^refs\/tags\//, "");
|
||||
}
|
||||
if (splitAt < 500) {
|
||||
splitAt = remaining.lastIndexOf(" ", maxLength);
|
||||
}
|
||||
|
||||
function oneLine(value) {
|
||||
return value.replace(/\s+/g, " ").trim();
|
||||
if (splitAt < 500) {
|
||||
splitAt = maxLength;
|
||||
}
|
||||
|
||||
chunks.push(remaining.slice(0, splitAt).trim());
|
||||
remaining = remaining.slice(splitAt).trim();
|
||||
}
|
||||
|
||||
if (remaining) {
|
||||
chunks.push(remaining);
|
||||
}
|
||||
|
||||
return chunks.map((chunk, index) =>
|
||||
index === 0 ? chunk : `**Changelog continued**\n\n${chunk}`,
|
||||
);
|
||||
}
|
||||
|
||||
function truncate(value, maxLength) {
|
||||
return value.length <= maxLength ? value : `${value.slice(0, maxLength - 3)}...`;
|
||||
}
|
||||
|
||||
function capitalize(value) {
|
||||
return `${value.slice(0, 1).toUpperCase()}${value.slice(1)}`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user