diff --git a/packages/twenty-server/project.json b/packages/twenty-server/project.json index 54d809636e..3bb631d0e5 100644 --- a/packages/twenty-server/project.json +++ b/packages/twenty-server/project.json @@ -288,6 +288,13 @@ "cwd": "{projectRoot}", "command": "lingui compile --typescript" } + }, + "version:bump": { + "executor": "nx:run-commands", + "options": { + "cwd": "{projectRoot}", + "command": "npx tsx scripts/bump-version.ts" + } } } } diff --git a/packages/twenty-server/scripts/bump-version.ts b/packages/twenty-server/scripts/bump-version.ts new file mode 100644 index 0000000000..fca0bd2de6 --- /dev/null +++ b/packages/twenty-server/scripts/bump-version.ts @@ -0,0 +1,243 @@ +import { readFileSync, writeFileSync } from 'fs'; +import { resolve } from 'path'; + +import semver from 'semver'; + +const CONSTANTS_DIR = resolve( + __dirname, + '../src/engine/core-modules/upgrade/constants', +); + +const AUTO_GENERATED_HEADER = `/* + * _____ _ + *|_ _|_ _____ _ __ | |_ _ _ + * | | \\ \\ /\\ / / _ \\ '_ \\| __| | | | Auto-generated file + * | | \\ V V / __/ | | | |_| |_| | Any edits to this will be overridden + * |_| \\_/\\_/ \\___|_| |_|\\__|\\__, | Generated by: npx nx version:bump twenty-server + * |___/ + */ + +`; + +const incrementMinorVersion = (version: string): string => { + const incremented = semver.inc(version, 'minor'); + + if (!incremented) { + throw new Error(`Failed to increment version: ${version}`); + } + + return incremented; +}; + +const getCurrentVersion = (): string => { + const filePath = `${CONSTANTS_DIR}/twenty-current-version.constant.ts`; + const content = readFileSync(filePath, 'utf-8'); + const match = content.match(/'([0-9.]+)'/); + + if (!match) { + throw new Error('Could not extract current version'); + } + + return match[1]; +}; + +const getPreviousVersions = (): string[] => { + const filePath = `${CONSTANTS_DIR}/twenty-previous-versions.constant.ts`; + const content = readFileSync(filePath, 'utf-8'); + const matches = content.match(/'[0-9.]+'/g); + + if (!matches) { + return []; + } + + return matches.map((m) => m.replace(/'/g, '')); +}; + +const getNextVersions = (): string[] => { + const filePath = `${CONSTANTS_DIR}/twenty-next-versions.constant.ts`; + const content = readFileSync(filePath, 'utf-8'); + const matches = content.match(/'[0-9.]+'/g); + + if (!matches) { + return []; + } + + return matches.map((m) => m.replace(/'/g, '')); +}; + +const updateCurrentVersion = (newVersion: string): void => { + const filePath = `${CONSTANTS_DIR}/twenty-current-version.constant.ts`; + + writeFileSync( + filePath, + `${AUTO_GENERATED_HEADER}export const TWENTY_CURRENT_VERSION = '${newVersion}' as const;\n`, + ); + + console.log(`Updated TWENTY_CURRENT_VERSION to '${newVersion}'`); +}; + +const updatePreviousVersions = (versions: string[]): void => { + const filePath = `${CONSTANTS_DIR}/twenty-previous-versions.constant.ts`; + const formattedVersions = versions.map((v) => ` '${v}',`).join('\n'); + + writeFileSync( + filePath, + `${AUTO_GENERATED_HEADER}export const TWENTY_PREVIOUS_VERSIONS = [\n${formattedVersions}\n] as const;\n`, + ); + + console.log( + `Updated TWENTY_PREVIOUS_VERSIONS with ${versions.length} versions`, + ); +}; + +const updateNextVersions = (versions: string[]): void => { + const filePath = `${CONSTANTS_DIR}/twenty-next-versions.constant.ts`; + const formattedVersions = versions.map((v) => ` '${v}',`).join('\n'); + + writeFileSync( + filePath, + `${AUTO_GENERATED_HEADER}export const TWENTY_NEXT_VERSIONS = [\n${formattedVersions}\n] as const;\n`, + ); + + console.log(`Updated TWENTY_NEXT_VERSIONS with ${versions.length} versions`); +}; + +const resolveNewVersion = ({ + newVersionArg, + currentVersion, + nextVersions, +}: { + newVersionArg: string | undefined; + currentVersion: string; + nextVersions: string[]; +}): string => { + if (newVersionArg) { + if (!semver.valid(newVersionArg)) { + throw new Error(`Invalid version format: ${newVersionArg}`); + } + + if (!semver.gt(newVersionArg, currentVersion)) { + throw new Error( + `New version '${newVersionArg}' must be greater than current version '${currentVersion}'`, + ); + } + + if (nextVersions.length > 0) { + const highestNextVersion = nextVersions[nextVersions.length - 1]; + + if (semver.gt(newVersionArg, highestNextVersion)) { + throw new Error( + `New version '${newVersionArg}' cannot be greater than highest planned next version '${highestNextVersion}'`, + ); + } + } + + return newVersionArg; + } + + if (nextVersions.length === 0) { + const computed = incrementMinorVersion(currentVersion); + + console.log( + `\nNo version provided and TWENTY_NEXT_VERSIONS is empty, computed from current: '${computed}'`, + ); + + return computed; + } + + console.log( + `\nNo version provided, using TWENTY_NEXT_VERSIONS[0]: '${nextVersions[0]}'`, + ); + + return nextVersions[0]; +}; + +const partitionNextVersions = ({ + nextVersions, + newVersion, +}: { + nextVersions: string[]; + newVersion: string; +}): { + skippedNextVersions: string[]; + remainingNextVersions: string[]; +} => + nextVersions.reduce<{ + skippedNextVersions: string[]; + remainingNextVersions: string[]; + }>( + (acc, version) => { + if (semver.lt(version, newVersion)) { + return { + ...acc, + skippedNextVersions: [...acc.skippedNextVersions, version], + }; + } + + if (semver.gt(version, newVersion)) { + return { + ...acc, + remainingNextVersions: [...acc.remainingNextVersions, version], + }; + } + + return acc; + }, + { skippedNextVersions: [], remainingNextVersions: [] }, + ); + +const bumpVersion = (newVersionArg?: string): void => { + const currentVersion = getCurrentVersion(); + const previousVersions = getPreviousVersions(); + const nextVersions = getNextVersions(); + + console.log('\nCurrent state:'); + console.log(` TWENTY_CURRENT_VERSION: '${currentVersion}'`); + console.log( + ` TWENTY_PREVIOUS_VERSIONS: [${previousVersions.map((v) => `'${v}'`).join(', ')}]`, + ); + console.log( + ` TWENTY_NEXT_VERSIONS: [${nextVersions.map((v) => `'${v}'`).join(', ')}]`, + ); + + const newVersion = resolveNewVersion({ + newVersionArg, + currentVersion, + nextVersions, + }); + + const { skippedNextVersions, remainingNextVersions } = partitionNextVersions({ + nextVersions, + newVersion, + }); + + const updatedPreviousVersions = [ + ...previousVersions, + currentVersion, + ...skippedNextVersions, + ]; + const updatedNextVersions = + remainingNextVersions.length > 0 + ? remainingNextVersions + : [incrementMinorVersion(newVersion)]; + + console.log('\nApplying changes:'); + + updatePreviousVersions(updatedPreviousVersions); + updateCurrentVersion(newVersion); + updateNextVersions(updatedNextVersions); + + console.log('\nNew state:'); + console.log(` TWENTY_CURRENT_VERSION: '${newVersion}'`); + console.log( + ` TWENTY_PREVIOUS_VERSIONS: [${updatedPreviousVersions.map((v) => `'${v}'`).join(', ')}]`, + ); + console.log( + ` TWENTY_NEXT_VERSIONS: [${updatedNextVersions.map((v) => `'${v}'`).join(', ')}]`, + ); + console.log('\nVersion bump complete!'); +}; + +const newVersion = process.argv[2]; + +bumpVersion(newVersion); diff --git a/packages/twenty-server/src/engine/core-modules/upgrade/constants/twenty-current-version.constant.ts b/packages/twenty-server/src/engine/core-modules/upgrade/constants/twenty-current-version.constant.ts index 7fa11c5eb4..35410dd930 100644 --- a/packages/twenty-server/src/engine/core-modules/upgrade/constants/twenty-current-version.constant.ts +++ b/packages/twenty-server/src/engine/core-modules/upgrade/constants/twenty-current-version.constant.ts @@ -1 +1,10 @@ +/* + * _____ _ + *|_ _|_ _____ _ __ | |_ _ _ + * | | \ \ /\ / / _ \ '_ \| __| | | | Auto-generated file + * | | \ V V / __/ | | | |_| |_| | Any edits to this will be overridden + * |_| \_/\_/ \___|_| |_|\__|\__, | Generated by: npx nx version:bump twenty-server + * |___/ + */ + export const TWENTY_CURRENT_VERSION = '2.3.0' as const; diff --git a/packages/twenty-server/src/engine/core-modules/upgrade/constants/twenty-next-versions.constant.ts b/packages/twenty-server/src/engine/core-modules/upgrade/constants/twenty-next-versions.constant.ts index 2d65157060..d9aeba31c0 100644 --- a/packages/twenty-server/src/engine/core-modules/upgrade/constants/twenty-next-versions.constant.ts +++ b/packages/twenty-server/src/engine/core-modules/upgrade/constants/twenty-next-versions.constant.ts @@ -1 +1,10 @@ +/* + * _____ _ + *|_ _|_ _____ _ __ | |_ _ _ + * | | \ \ /\ / / _ \ '_ \| __| | | | Auto-generated file + * | | \ V V / __/ | | | |_| |_| | Any edits to this will be overridden + * |_| \_/\_/ \___|_| |_|\__|\__, | Generated by: npx nx version:bump twenty-server + * |___/ + */ + export const TWENTY_NEXT_VERSIONS = ['2.4.0'] as const; diff --git a/packages/twenty-server/src/engine/core-modules/upgrade/constants/twenty-previous-versions.constant.ts b/packages/twenty-server/src/engine/core-modules/upgrade/constants/twenty-previous-versions.constant.ts index 590b8428f9..a1705ea010 100644 --- a/packages/twenty-server/src/engine/core-modules/upgrade/constants/twenty-previous-versions.constant.ts +++ b/packages/twenty-server/src/engine/core-modules/upgrade/constants/twenty-previous-versions.constant.ts @@ -1,3 +1,12 @@ +/* + * _____ _ + *|_ _|_ _____ _ __ | |_ _ _ + * | | \ \ /\ / / _ \ '_ \| __| | | | Auto-generated file + * | | \ V V / __/ | | | |_| |_| | Any edits to this will be overridden + * |_| \_/\_/ \___|_| |_|\__|\__, | Generated by: npx nx version:bump twenty-server + * |___/ + */ + export const TWENTY_PREVIOUS_VERSIONS = [ '1.21.0', '1.22.0',