Skip to content

Commit 4251a56

Browse files
committed
feat: add support policy /info subjects
1 parent 876f188 commit 4251a56

File tree

7 files changed

+194
-5
lines changed

7 files changed

+194
-5
lines changed
Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,65 @@
1-
import { BaseMessageOptions, EmbedBuilder } from 'discord.js';
1+
import {
2+
ActionRowBuilder,
3+
BaseMessageOptions,
4+
ButtonBuilder,
5+
ButtonStyle,
6+
EmbedBuilder,
7+
} from 'discord.js';
8+
import { getSupportedFirebotVersions } from '../../../../services/github.service';
29

310
export function getBaseEmbed() {
411
return new EmbedBuilder().setColor('#FFBE00');
512
}
613

714
export type InfoTopic = {
815
name: string;
9-
message: BaseMessageOptions;
16+
message: BaseMessageOptions | (() => Promise<BaseMessageOptions>);
1017
};
18+
19+
export async function getSupportPolicyEmbed(): Promise<EmbedBuilder> {
20+
const supportedVersions = await getSupportedFirebotVersions();
21+
22+
// Build the list of currently supported versions
23+
const versionLines: string[] = [];
24+
if (supportedVersions.currentStable) {
25+
versionLines.push(`- **${supportedVersions.currentStable}** (Latest)`);
26+
}
27+
if (
28+
supportedVersions.previousStable &&
29+
supportedVersions.previousStableExpiresAt
30+
) {
31+
versionLines.push(
32+
`- **${supportedVersions.previousStable}** (Previous - support expires <t:${supportedVersions.previousStableExpiresAt}:R>)`
33+
);
34+
}
35+
if (supportedVersions.prerelease) {
36+
versionLines.push(
37+
`- **${supportedVersions.prerelease}** (Pre-release)`
38+
);
39+
}
40+
41+
const currentlySupportedSection =
42+
versionLines.length > 0
43+
? `**Currently Supported Versions:**\n${versionLines.join('\n')}\n\n`
44+
: '';
45+
return getBaseEmbed().setTitle('Support Policy').setDescription(`
46+
${currentlySupportedSection}**Policy Summary:**
47+
- Latest stable release is always supported
48+
- Previous stable releases are supported for up to **30 days** after a newer stable update
49+
- Betas are unsupported once a newer beta or corresponding stable release is available
50+
- Nightly builds receive limited support due to their unstable nature
51+
52+
To receive support, please update to a supported version of Firebot.
53+
`);
54+
}
55+
56+
export function getSupportPolicyLinkButton() {
57+
return new ActionRowBuilder<ButtonBuilder>().addComponents(
58+
new ButtonBuilder()
59+
.setLabel('View Full Support Policy')
60+
.setStyle(ButtonStyle.Link)
61+
.setURL(
62+
'https://github.com/crowbartools/Firebot/blob/master/.github/SUPPORT.md'
63+
)
64+
);
65+
}

src/interactions/commands/handlers/info/info-slash.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,17 @@ export const infoSlashCommand: ICommandHandler = {
3333

3434
const topicName = interaction.options.getString('topic');
3535

36-
const message = infoTopics.find((p) => p.name === topicName)?.message;
36+
const topic = infoTopics.find((p) => p.name === topicName);
3737

38-
if (!message) {
38+
if (!topic?.message) {
3939
await interaction.editReply('Invalid topic');
4040
return;
4141
}
4242

43+
const message = typeof topic.message === 'function'
44+
? await topic.message()
45+
: topic.message;
46+
4347
const targetUser = interaction.options.getUser('target');
4448

4549
const variableMap = {

src/interactions/commands/handlers/info/topics/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import { InfoTopic } from '../info-helpers';
1717
import { arm64InstallError } from './arm64';
1818
import { overlayIssues } from './overlay-issues';
1919
import { debugInfo } from './debug-info';
20+
import { unsupportedVersion } from './unsupported-version';
21+
import { supportPolicy } from './support-policy';
2022

2123
export const infoTopics: Array<InfoTopic> = [
2224
authIssues,
@@ -36,5 +38,7 @@ export const infoTopics: Array<InfoTopic> = [
3638
tuts,
3739
arm64InstallError,
3840
overlayIssues,
39-
debugInfo
41+
debugInfo,
42+
supportPolicy,
43+
unsupportedVersion,
4044
];
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import {
2+
getSupportPolicyEmbed,
3+
getSupportPolicyLinkButton,
4+
InfoTopic,
5+
} from '../info-helpers';
6+
7+
export const supportPolicy: InfoTopic = {
8+
name: 'Support Policy',
9+
message: async () => {
10+
return {
11+
embeds: [await getSupportPolicyEmbed()],
12+
components: [getSupportPolicyLinkButton()],
13+
};
14+
},
15+
};
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import {
2+
getSupportPolicyEmbed,
3+
getSupportPolicyLinkButton,
4+
InfoTopic,
5+
} from '../info-helpers';
6+
7+
export const unsupportedVersion: InfoTopic = {
8+
name: 'Unsupported Version',
9+
message: async () => {
10+
return {
11+
content:
12+
'It looks like you may be running an unsupported version of Firebot. To receive support, please update to a supported version of Firebot.',
13+
embeds: [await getSupportPolicyEmbed()],
14+
components: [getSupportPolicyLinkButton()],
15+
};
16+
},
17+
};

src/services/github.service.ts

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,3 +154,95 @@ export async function getLatestFirebotReleaseVersion(): Promise<string | null> {
154154

155155
return null;
156156
}
157+
158+
export async function getRecentFirebotReleases(): Promise<IRelease[] | null> {
159+
const getReleasesUrl =
160+
'https://api.github.com/repos/crowbartools/firebot/releases?per_page=50';
161+
162+
let response: AxiosResponse<IRelease[]>;
163+
try {
164+
response = await axios.get<IRelease[]>(
165+
getReleasesUrl,
166+
getDefaultAxiosConfig()
167+
);
168+
} catch (error) {
169+
console.log('Error getting firebot releases', error);
170+
}
171+
172+
if (response && response.status == 200) {
173+
return response.data;
174+
}
175+
176+
return null;
177+
}
178+
179+
export interface SupportedVersions {
180+
currentStable: string | null;
181+
previousStable: string | null;
182+
previousStableExpiresAt: number | null;
183+
prerelease: string | null;
184+
}
185+
186+
export async function getSupportedFirebotVersions(): Promise<SupportedVersions> {
187+
const releases = await getRecentFirebotReleases();
188+
189+
const result: SupportedVersions = {
190+
currentStable: null,
191+
previousStable: null,
192+
previousStableExpiresAt: null,
193+
prerelease: null,
194+
};
195+
196+
if (!releases || releases.length === 0) {
197+
return result;
198+
}
199+
200+
// Find stable releases
201+
const stableReleases = releases.filter(
202+
(r) => !r.prerelease
203+
);
204+
205+
// Find prerelease versions (betas, etc)
206+
const prereleases = releases.filter(
207+
(r) => r.prerelease
208+
);
209+
210+
// Current stable is the most recent stable release
211+
if (stableReleases.length > 0) {
212+
result.currentStable = stableReleases[0].tag_name;
213+
214+
// Check if previous stable should still be supported (within 30 days of current stable release)
215+
if (stableReleases.length > 1) {
216+
const currentStableDate = new Date(stableReleases[0].published_at);
217+
const now = new Date();
218+
const daysSinceCurrentStable = Math.floor(
219+
(now.getTime() - currentStableDate.getTime()) / (1000 * 60 * 60 * 24)
220+
);
221+
222+
if (daysSinceCurrentStable <= 30) {
223+
result.previousStable = stableReleases[1].tag_name;
224+
// Calculate expiration date (30 days from current stable release)
225+
const expirationDate = new Date(currentStableDate.getTime() + 30 * 24 * 60 * 60 * 1000);
226+
result.previousStableExpiresAt = Math.floor(expirationDate.getTime() / 1000);
227+
}
228+
}
229+
}
230+
231+
// Check if there's a prerelease that hasn't been superseded by a stable
232+
// A prerelease is still supported if it's newer than the current stable
233+
if (prereleases.length > 0 && stableReleases.length > 0) {
234+
const latestPrerelease = prereleases[0];
235+
const latestPrereleaseDate = new Date(latestPrerelease.published_at);
236+
const currentStableDate = new Date(stableReleases[0].published_at);
237+
238+
// Prerelease is supported if it was released after the current stable
239+
if (latestPrereleaseDate > currentStableDate) {
240+
result.prerelease = latestPrerelease.tag_name;
241+
}
242+
} else if (prereleases.length > 0 && stableReleases.length === 0) {
243+
// No stable releases, so the prerelease is supported
244+
result.prerelease = prereleases[0].tag_name;
245+
}
246+
247+
return result;
248+
}

src/types/github.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,6 @@ export interface ISearchResult {
5959

6060
export interface IRelease {
6161
tag_name: string;
62+
published_at: string;
63+
prerelease: boolean;
6264
}

0 commit comments

Comments
 (0)