Skip to content

Commit

Permalink
feat: add update-notifier
Browse files Browse the repository at this point in the history
  • Loading branch information
chengcyber committed Feb 26, 2024
1 parent 82c90cf commit 81e8f4c
Show file tree
Hide file tree
Showing 11 changed files with 461 additions and 33 deletions.
2 changes: 2 additions & 0 deletions apps/sparo-lib/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"inversify": "~6.0.2",
"reflect-metadata": "~0.2.1",
"semver": "~7.6.0",
"update-notifier": "~5.1.0",
"yargs": "~17.7.2"
},
"devDependencies": {
Expand All @@ -26,6 +27,7 @@
"@types/heft-jest": "1.0.6",
"@types/node": "20.11.16",
"@types/semver": "7.5.7",
"@types/update-notifier": "6.0.8",
"@types/yargs": "17.0.32",
"eslint": "8.56.0",
"typescript": "~5.3.3"
Expand Down
10 changes: 10 additions & 0 deletions apps/sparo-lib/src/api/Sparo.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { SparoCommandLine } from '../cli/SparoCommandLine';
import { SparoCICommandLine } from '../cli/SparoCICommandLine';
import type { ICollectTelemetryFunction } from '../services/TelemetryService';
import type { ICallerPackageJson } from '../cli/SparoStartupBanner';

/**
* Options to pass to the sparo "launch" functions.
Expand All @@ -17,6 +18,15 @@ export interface ILaunchOptions {
* Later, the API will be redesigned to meet more generic requirements.
*/
collectTelemetryAsync?: ICollectTelemetryFunction;

/**
* Provide the caller package JSON info.
* @internal
*
* @remarks
* It is used to update notification.
*/
callerPackageJson?: ICallerPackageJson;
}

/**
Expand Down
4 changes: 3 additions & 1 deletion apps/sparo-lib/src/cli/SparoCICommandLine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ export class SparoCICommandLine {
}

GitVersionCompatibility.ensureGitVersion();
SparoStartupBanner.logBanner();
SparoStartupBanner.logBanner({
callerPackageJson: launchOptions.callerPackageJson
});

const sparoCI: SparoCICommandLine = new SparoCICommandLine();
await sparoCI.prepareCommandAsync();
Expand Down
4 changes: 3 additions & 1 deletion apps/sparo-lib/src/cli/SparoCommandLine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ export class SparoCommandLine {
}

GitVersionCompatibility.ensureGitVersion();
SparoStartupBanner.logBanner();
SparoStartupBanner.logBanner({
callerPackageJson: launchOptions.callerPackageJson
});

const sparo: SparoCommandLine = new SparoCommandLine();
await sparo.prepareCommandAsync();
Expand Down
46 changes: 43 additions & 3 deletions apps/sparo-lib/src/cli/SparoStartupBanner.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,33 @@
import * as semver from 'semver';
import updateNotifier, { type UpdateNotifier } from 'update-notifier';
import { Colorize } from '@rushstack/terminal';
import { getFromContainer } from '../di/container';
import { TerminalService } from '../services/TerminalService';
import { SparoVersion } from '../logic/SparoVersion';
import { SparoLibPackage } from '../logic/SparoLibPackage';
import { GitVersionCompatibility } from '../logic/GitVersionCompatibility';

/**
* The package json information of the package who calls "sparo-lib".
* @alpha
*/
export interface ICallerPackageJson {
/**
* Package name
*/
name: string;
/**
* Package version
*/
version: string;
}

export interface ILogBannerOptions {
callerPackageJson?: ICallerPackageJson;
}

export class SparoStartupBanner {
public static logBanner(): void {
const sparoVersion: string = SparoVersion.version;
public static logBanner(options: ILogBannerOptions = {}): void {
const sparoVersion: string = SparoLibPackage.version;
const gitVersion: string = GitVersionCompatibility.getGitVersion().join('.');
const nodeVersion: string = this._formatNodeVersion();
const { terminal } = getFromContainer(TerminalService);
Expand All @@ -17,6 +37,26 @@ export class SparoStartupBanner {
terminal.writeLine(`Node.js version is ${nodeVersion}`);
terminal.writeLine(`Git version is ${gitVersion}`);
terminal.writeLine();

if (options.callerPackageJson && options.callerPackageJson.name && options.callerPackageJson.version) {
// CLI parameter has not been processed yet, so directly go through parameters here.
const isDebug: boolean = process.argv.includes('--debug');
const notifier: UpdateNotifier = updateNotifier({
pkg: options.callerPackageJson,
// Normally update-notifier waits a day or so before it starts displaying upgrade notices.
// In debug mode, show the notice right away.
updateCheckInterval: isDebug ? 0 : undefined
});
notifier.notify({
// Make sure it says "-g" in the "npm install" example command line
isGlobal: true,
// Show the notice immediately, rather than waiting for process.onExit()
defer: false
});
if (isDebug) {
terminal.writeLine(Colorize.gray(`Notifier update: ${JSON.stringify(notifier.update)}`));
}
}
}

private static _formatNodeVersion(): string {
Expand Down
1 change: 1 addition & 0 deletions apps/sparo-lib/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export { GitService, type IExecuteGitCommandParams } from './services/GitService
export { TerminalService, type ITerminal } from './services/TerminalService';

export type { ICollectTelemetryFunction, ITelemetryData } from './services/TelemetryService';
export type { ICallerPackageJson } from './cli/SparoStartupBanner';
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as path from 'path';
import { type IPackageJson, PackageJsonLookup } from '@rushstack/node-core-library';

export class SparoVersion {
export class SparoLibPackage {
private static __sparoLibPackageJson: IPackageJson | undefined = undefined;
private static __sparoLibPackageFolder: string | undefined = undefined;

Expand All @@ -19,24 +19,24 @@ export class SparoVersion {
* @internal
*/
public static get _sparoLibPackageJson(): IPackageJson {
SparoVersion._ensureOwnPackageJsonIsLoaded();
return SparoVersion.__sparoLibPackageJson!;
SparoLibPackage._ensureOwnPackageJsonIsLoaded();
return SparoLibPackage.__sparoLibPackageJson!;
}

public static get _sparoLibPackageFolder(): string {
SparoVersion._ensureOwnPackageJsonIsLoaded();
return SparoVersion.__sparoLibPackageFolder!;
SparoLibPackage._ensureOwnPackageJsonIsLoaded();
return SparoLibPackage.__sparoLibPackageFolder!;
}

private static _ensureOwnPackageJsonIsLoaded(): void {
if (!SparoVersion.__sparoLibPackageJson) {
if (!SparoLibPackage.__sparoLibPackageJson) {
const packageJsonFilePath: string | undefined =
PackageJsonLookup.instance.tryGetPackageJsonFilePathFor(__dirname);
if (!packageJsonFilePath) {
throw new Error('Unable to locate the package.json file for this module');
}
SparoVersion.__sparoLibPackageFolder = path.dirname(packageJsonFilePath);
SparoVersion.__sparoLibPackageJson = PackageJsonLookup.instance.loadPackageJson(packageJsonFilePath);
SparoLibPackage.__sparoLibPackageFolder = path.dirname(packageJsonFilePath);
SparoLibPackage.__sparoLibPackageJson = PackageJsonLookup.instance.loadPackageJson(packageJsonFilePath);
}
}
}
6 changes: 4 additions & 2 deletions apps/sparo/src/SparoCommandSelector.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import * as path from 'path';

import { Sparo, type ILaunchOptions } from 'sparo-lib';
import { SparoPackage } from './SparoPackage';

type CommandName = 'sparo' | 'sparo-ci' | undefined;

export class SparoCommandSelector {
public static async executeAsync(): Promise<void> {
const commandName: CommandName = SparoCommandSelector._getCommandName();
const launchOptions: ILaunchOptions = {};
const launchOptions: ILaunchOptions = {
callerPackageJson: SparoPackage._sparoPackageJson
};
switch (commandName) {
case 'sparo-ci': {
await Sparo.launchSparoCIAsync(launchOptions);
Expand Down
42 changes: 42 additions & 0 deletions apps/sparo/src/SparoPackage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import * as path from 'path';
import { type IPackageJson, PackageJsonLookup } from '@rushstack/node-core-library';

export class SparoPackage {
private static __sparoPackageJson: IPackageJson | undefined = undefined;
private static __sparoPackageFolder: string | undefined = undefined;

private constructor() {}

/**
* The currently executing version of the "sparo" library.
* This is the same as the Sparo tool version for that release.
*/
public static get version(): string {
return this._sparoPackageJson.version;
}

/**
* @internal
*/
public static get _sparoPackageJson(): IPackageJson {
SparoPackage._ensureOwnPackageJsonIsLoaded();
return SparoPackage.__sparoPackageJson!;
}

public static get _sparoPackageFolder(): string {
SparoPackage._ensureOwnPackageJsonIsLoaded();
return SparoPackage.__sparoPackageFolder!;
}

private static _ensureOwnPackageJsonIsLoaded(): void {
if (!SparoPackage.__sparoPackageJson) {
const packageJsonFilePath: string | undefined =
PackageJsonLookup.instance.tryGetPackageJsonFilePathFor(__dirname);
if (!packageJsonFilePath) {
throw new Error('Unable to locate the package.json file for this module');
}
SparoPackage.__sparoPackageFolder = path.dirname(packageJsonFilePath);
SparoPackage.__sparoPackageJson = PackageJsonLookup.instance.loadPackageJson(packageJsonFilePath);
}
}
}
Loading

0 comments on commit 81e8f4c

Please sign in to comment.