Skip to content

Commit c8ea4be

Browse files
committed
Enforce discord embed size limits
Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>
1 parent 3f67ffd commit c8ea4be

File tree

2 files changed

+69
-15
lines changed

2 files changed

+69
-15
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "base-release-action",
3-
"version": "1.5.2",
3+
"version": "1.5.3",
44
"description": "An action to create incremented releases in a similar style to Jenkins",
55
"repository": "https://github.com/Kas-tle/base-release-action.git",
66
"author": "Joshua Castle <packages@kastle.dev>",

src/action/hook.ts

Lines changed: 68 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,37 +24,91 @@ export async function sendWebhook(inp: {inputs: Inputs, api: OctokitApi, repoDat
2424

2525
const thumbnail= `https://opengraph.githubassets.com/1/${owner}/${repo}/releases/tag/${tag}`;
2626

27-
let assets = '';
27+
// Prepare Asset Fields (Split if > 1024)
28+
let assetLines: string[] = [];
2829
for (const asset of updatedRelease.data.assets) {
29-
assets += `- :page_facing_up: [${asset.name}](${asset.browser_download_url})\n`;
30+
assetLines.push(`- :page_facing_up: [${asset.name}](${asset.browser_download_url})`);
3031
}
31-
assets += `- :package: [Source code (zip)](${updatedRelease.data.zipball_url})\n`;
32-
assets += `- :package: [Source code (tar.gz)](${updatedRelease.data.tarball_url})\n`;
32+
assetLines.push(`- :package: [Source code (zip)](${updatedRelease.data.zipball_url})`);
33+
assetLines.push(`- :package: [Source code (tar.gz)](${updatedRelease.data.tarball_url})`);
3334

35+
const assetFields: { name: string; value: string; inline: boolean }[] = [];
36+
let currentAssetChunk = '';
37+
38+
for (const line of assetLines) {
39+
if (currentAssetChunk.length + line.length + 1 > 1024) {
40+
assetFields.push({ name: 'Assets', value: currentAssetChunk, inline: false });
41+
currentAssetChunk = '';
42+
}
43+
currentAssetChunk += line + '\n';
44+
}
45+
if (currentAssetChunk) {
46+
assetFields.push({ name: 'Assets', value: currentAssetChunk, inline: false });
47+
}
48+
49+
// Prepare Static Fields
3450
const time = Math.floor(new Date(updatedRelease.data.created_at).getTime() / 1000);
35-
const author = updatedRelease.data.author.type === 'User' ? updatedRelease.data.author.login : updatedRelease.data.author.login.replace('[bot]', '');
3651
const sha = inputs.changes[inputs.changes.length - 1].commit.slice(0, 7);
3752
const statusEmoji = failed ? ':red_circle:' : ':green_circle:';
3853
const status = failed ? 'Failed' : 'Success';
3954
const runID = process.env.GITHUB_RUN_ID!;
4055

56+
const staticFields = [
57+
{ name: '', value: `:watch: <t:${time}:R>`, inline: true },
58+
{ name: '', value: `:label: [${tag}](${url}/${owner}/${repo}/tree/${tag})`, inline: true },
59+
{ name: '', value: `:lock_with_ink_pen: [${sha}](${url}/${owner}/${repo}/commit/${sha})`, inline: true },
60+
{ name: '', value: `${statusEmoji} [${status}](${url}/${owner}/${repo}/actions/runs/${runID})`, inline: true }
61+
];
62+
63+
// Enforce Field Count Limit (Max 25)
64+
// We have 4 static fields, leaving 21 slots for assets
65+
if (assetFields.length > 21) {
66+
assetFields.length = 21;
67+
}
68+
const allFields = [...assetFields, ...staticFields];
69+
70+
// Truncate & Calculate Sizes
71+
// Author Name: Max 256
72+
const embedAuthorName = `${owner}/${repo}`.substring(0, 256);
73+
74+
// Title: Max 256
75+
const embedTitle = inputs.release.name.substring(0, 256);
76+
77+
// Footer: Max 2048
78+
let author = updatedRelease.data.author.type === 'User' ? updatedRelease.data.author.login : updatedRelease.data.author.login.replace('[bot]', '');
79+
const embedFooterText = `Released by ${author}`.substring(0, 2048);
80+
81+
// Calculate current used size (excluding description)
82+
let currentTotalSize = 0;
83+
currentTotalSize += embedAuthorName.length;
84+
currentTotalSize += embedTitle.length;
85+
currentTotalSize += embedFooterText.length;
86+
87+
for (const f of allFields) {
88+
currentTotalSize += (f.name.length || 0) + (f.value.length || 0);
89+
}
90+
91+
// Description: Max 4096, but Total Embed must be <= 6000
92+
const availableForDesc = 6000 - currentTotalSize;
93+
const maxDesc = Math.min(4096, availableForDesc);
94+
const description = (inputs.release.body || '').substring(0, Math.max(0, maxDesc));
95+
4196
const embed = new Embed()
4297
.setTimestamp()
4398
.setAuthor({
44-
name: `${owner}/${repo}`,
99+
name: embedAuthorName,
45100
url: `${url}/${owner}/${repo}`,
46101
icon_url: `${url}/${owner}.png`
47102
})
48103
.setColor(color)
49-
.setTitle(inputs.release.name)
104+
.setTitle(embedTitle)
50105
.setUrl(updatedRelease.data.html_url)
51-
.setDescription(inputs.release.body.substring(0, 4000))
52-
.addField({ name: 'Assets', value: assets, inline: false })
53-
.addField({ name: '', value: `:watch: <t:${time}:R>`, inline: true })
54-
.addField({ name: '', value: `:label: [${tag}](${url}/${owner}/${repo}/tree/${tag})`, inline: true })
55-
.addField({ name: '', value: `:lock_with_ink_pen: [${sha}](${url}/${owner}/${repo}/commit/${sha})`, inline: true })
56-
.addField({ name: '', value: `${statusEmoji} [${status}](${url}/${owner}/${repo}/actions/runs/${runID})`, inline: true })
57-
.setFooter({ text: `Released by ${author}`, icon_url: updatedRelease.data.author.avatar_url })
106+
.setDescription(description)
107+
.setFooter({ text: embedFooterText, icon_url: updatedRelease.data.author.avatar_url })
108+
109+
for (const field of allFields) {
110+
embed.addField(field);
111+
}
58112

59113
if (thumbnail) {
60114
embed.setImage({ url: thumbnail });

0 commit comments

Comments
 (0)