projenrc/support.ts (59 lines of code) (raw):

import { JsonFile, Project } from 'projen'; type ReleaseLine = `${number}.${number}`; type VersionNumber = `${number}.${number}.${number}`; interface ReleasesDocument { readonly current: ReleaseLine; readonly currentMinVersionNumber: VersionNumber; readonly maintenance: { readonly [release: ReleaseLine]: Date }; readonly endOfSupport?: readonly ReleaseLine[]; } export const SUPPORT_POLICY: ReleasesDocument = { current: '5.8', // Define a different patch version here if a specific feature or bug-fix currentMinVersionNumber: '5.8.0', maintenance: { // version: End-of-support date '5.0': new Date('2024-01-31'), '5.1': new Date('2024-04-30'), '5.2': new Date('2024-06-30'), '5.3': new Date('2024-10-15'), '5.4': new Date('2025-02-28'), '5.5': new Date('2025-05-15'), '5.6': new Date('2025-07-01'), '5.7': new Date('2025-09-15'), }, }; if (!SUPPORT_POLICY.currentMinVersionNumber.startsWith(SUPPORT_POLICY.current)) { throw new Error('currentMinVersionNumber must be part of the current version line'); } export class SupportPolicy { public get branches(): { [version: string]: string; } { const branches = { [SUPPORT_POLICY.current]: 'main', }; for (const version of Object.keys(SUPPORT_POLICY.maintenance)) { branches[version] = `maintenance/v${version}`; } return branches; } public constructor(project: Project) { new JsonFile(project, 'releases.json', { allowComments: false, editGitignore: false, obj: SUPPORT_POLICY, readonly: true, }); } /** * Get all actively maintained branches */ public activeBranches(includeCurrent = true): { [version: string]: string; } { return Object.fromEntries( Object.entries(this.branches).filter(([version]) => { if (includeCurrent && version === SUPPORT_POLICY.current) { return true; } // check if branch is still maintained return Date.now() <= SUPPORT_POLICY.maintenance[version as any]?.getTime(); }), ); } }