packages/aws-cdk/lib/cli/version.ts (104 lines of code) (raw):

/* c8 ignore start */ import * as path from 'path'; import * as chalk from 'chalk'; import * as fs from 'fs-extra'; import * as semver from 'semver'; import { ToolkitError } from '../../../@aws-cdk/toolkit-lib/lib/api'; import { debug, info } from '../logging'; import { cdkCacheDir } from '../util'; import { cliRootDir } from './root-dir'; import { formatAsBanner } from './util/console-formatters'; import { execNpmView } from './util/npm'; const ONE_DAY_IN_SECONDS = 1 * 24 * 60 * 60; const UPGRADE_DOCUMENTATION_LINKS: Record<number, string> = { 1: 'https://docs.aws.amazon.com/cdk/v2/guide/migrating-v2.html', }; export function displayVersion() { return `${versionNumber()} (build ${commit()})`; } export function isDeveloperBuild(): boolean { return versionNumber() === '0.0.0'; } export function versionNumber(): string { // eslint-disable-next-line @typescript-eslint/no-require-imports return require(path.join(cliRootDir(), 'package.json')).version.replace(/\+[0-9a-f]+$/, ''); } function commit(): string { // eslint-disable-next-line @typescript-eslint/no-require-imports return require(path.join(cliRootDir(), 'build-info.json')).commit; } export class VersionCheckTTL { public static timestampFilePath(): string { // Using the same path from account-cache.ts return path.join(cdkCacheDir(), 'repo-version-ttl'); } private readonly file: string; // File modify times are accurate only to the second private readonly ttlSecs: number; constructor(file?: string, ttlSecs?: number) { this.file = file || VersionCheckTTL.timestampFilePath(); try { fs.mkdirsSync(path.dirname(this.file)); fs.accessSync(path.dirname(this.file), fs.constants.W_OK); } catch { throw new ToolkitError(`Directory (${path.dirname(this.file)}) is not writable.`); } this.ttlSecs = ttlSecs || ONE_DAY_IN_SECONDS; } public async hasExpired(): Promise<boolean> { try { const lastCheckTime = (await fs.stat(this.file)).mtimeMs; const today = new Date().getTime(); if ((today - lastCheckTime) / 1000 > this.ttlSecs) { // convert ms to sec return true; } return false; } catch (err: any) { if (err.code === 'ENOENT') { return true; } else { throw err; } } } public async update(latestVersion?: string): Promise<void> { if (!latestVersion) { latestVersion = ''; } await fs.writeFile(this.file, latestVersion); } } // Export for unit testing only. // Don't use directly, use displayVersionMessage() instead. export async function getVersionMessages(currentVersion: string, cacheFile: VersionCheckTTL): Promise<string[]> { if (!(await cacheFile.hasExpired())) { return []; } const packageInfo = await execNpmView(currentVersion); const latestVersion = packageInfo.latestVersion; await cacheFile.update(JSON.stringify(packageInfo)); // If the latest version is the same as the current version, there is no need to display a message if (semver.eq(latestVersion, currentVersion)) { return []; } const versionMessage = [ packageInfo.deprecated ? `${chalk.red(packageInfo.deprecated as string)}` : undefined, `Newer version of CDK is available [${chalk.green(latestVersion as string)}]`, getMajorVersionUpgradeMessage(currentVersion), 'Upgrade recommended (npm install -g aws-cdk)', ].filter(Boolean) as string[]; return versionMessage; } function getMajorVersionUpgradeMessage(currentVersion: string): string | void { const currentMajorVersion = semver.major(currentVersion); if (UPGRADE_DOCUMENTATION_LINKS[currentMajorVersion]) { return `Information about upgrading from version ${currentMajorVersion}.x to version ${currentMajorVersion + 1}.x is available here: ${UPGRADE_DOCUMENTATION_LINKS[currentMajorVersion]}`; } } export async function displayVersionMessage(currentVersion = versionNumber(), versionCheckCache?: VersionCheckTTL): Promise<void> { if (!process.stdout.isTTY || process.env.CDK_DISABLE_VERSION_CHECK) { return; } try { const versionMessages = await getVersionMessages(currentVersion, versionCheckCache ?? new VersionCheckTTL()); formatAsBanner(versionMessages).forEach(e => info(e)); } catch (err: any) { debug(`Could not run version check - ${err.message}`); } } /* c8 ignore stop */