diff --git a/src/commands/status.ts b/src/commands/status.ts new file mode 100644 index 00000000..1c3598e7 --- /dev/null +++ b/src/commands/status.ts @@ -0,0 +1,169 @@ +import {isNullish, nonNullish, notEmptyString} from '@dfinity/utils'; +import { + getJunoPackageVersion, + missionControlVersion as missionControlVersionLib, + orbiterVersion as orbiterVersionLib +} from '@junobuild/admin'; +import {red, yellow} from 'kleur'; +import {actorParameters} from '../api/actor.api'; +import {getCliMissionControl, getCliOrbiters} from '../configs/cli.config'; +import { + MISSION_CONTROL_WASM_NAME, + ORBITER_WASM_NAME, + SATELLITE_WASM_NAME +} from '../constants/constants'; +import {checkVersion, getSatelliteVersion} from '../services/version.services'; +import type {AssetKey} from '../types/asset-key'; +import {toAssetKeys} from '../utils/asset-key.utils'; +import { + assertConfigAndLoadSatelliteContext, + orbiterKey, + satelliteKey +} from '../utils/satellite.utils'; +import {lastRelease} from '../utils/upgrade.utils'; + +export const status = async () => { + await missionControlVersion(); + await satelliteVersion(); + await orbitersVersion(); +}; + +const missionControlVersion = async () => { + const missionControl = await getCliMissionControl(); + + if (isNullish(missionControl)) { + console.log( + `${yellow( + 'No mission control found.' + )} This is expected if your access key doesn't manage it.` + ); + return; + } + + const actorParams = await actorParameters(); + + const getVersion = async (): Promise => { + const version = await getJunoPackageVersion({ + moduleId: missionControl, + ...actorParams + }); + + if (nonNullish(version) && notEmptyString(version)) { + return version; + } + + // Legacy + const missionControlParameters = { + missionControlId: missionControl, + ...actorParams + }; + + return await missionControlVersionLib({ + missionControl: missionControlParameters + }); + }; + + const currentVersion = await getVersion(); + + const displayHint = `mission control`; + + await checkSegmentVersion({ + currentVersion, + assetKey: MISSION_CONTROL_WASM_NAME, + displayHint + }); +}; + +const satelliteVersion = async () => { + const {satellite} = await assertConfigAndLoadSatelliteContext(); + const {satelliteId} = satellite; + + const displayHint = `satellite "${await satelliteKey(satelliteId)}"`; + + const result = await getSatelliteVersion(); + + if (result.result === 'error') { + return; + } + + const {version: currentVersion} = result; + + await checkSegmentVersion({ + currentVersion, + assetKey: SATELLITE_WASM_NAME, + displayHint + }); +}; + +const orbitersVersion = async () => { + const orbiters = await getCliOrbiters(); + + if (isNullish(orbiters) || orbiters.length === 0) { + return; + } + + const checkOrbiterVersion = async (orbiterId: string) => { + const actorParams = await actorParameters(); + + const orbiterParameters = { + orbiterId, + ...actorParams + }; + + const getVersion = async (): Promise => { + const version = await getJunoPackageVersion({ + moduleId: orbiterId, + ...actorParams + }); + + if (nonNullish(version) && notEmptyString(version)) { + return version; + } + + // Legacy + return await orbiterVersionLib({ + orbiter: orbiterParameters + }); + }; + + const currentVersion = await getVersion(); + + const displayHint = `orbiter "${await orbiterKey(orbiterId)}"`; + + await checkSegmentVersion({ + currentVersion, + assetKey: ORBITER_WASM_NAME, + displayHint + }); + }; + + await Promise.allSettled( + orbiters.map(async ({p: orbiterId}) => { + await checkOrbiterVersion(orbiterId); + }) + ); +}; + +const checkSegmentVersion = async ({ + currentVersion, + assetKey, + displayHint +}: { + currentVersion: string; + assetKey: AssetKey; + displayHint: string; +}): Promise => { + const latestVersion = await lastRelease(toAssetKeys(assetKey)); + + if (latestVersion === undefined) { + console.log(red(`Cannot fetch last release version of ${displayHint} on Juno's CDN 😢.`)); + return; + } + + checkVersion({ + currentVersion, + latestVersion, + displayHint, + commandLineHint: `juno upgrade${assetKey === 'mission_control' ? '-t m' : ''}` + }); +}; diff --git a/src/commands/version.ts b/src/commands/version.ts index 12838322..e14d02e1 100644 --- a/src/commands/version.ts +++ b/src/commands/version.ts @@ -1,41 +1,12 @@ -import {isNullish, nonNullish, notEmptyString} from '@dfinity/utils'; -import { - getJunoPackageVersion, - missionControlVersion as missionControlVersionLib, - orbiterVersion as orbiterVersionLib -} from '@junobuild/admin'; -import {hasArgs} from '@junobuild/cli-tools'; -import {cyan, green, red, yellow} from 'kleur'; -import {clean, compare} from 'semver'; +import {isNullish} from '@dfinity/utils'; +import {red} from 'kleur'; +import {clean} from 'semver'; import {version as cliCurrentVersion} from '../../package.json'; -import {actorParameters} from '../api/actor.api'; -import {getCliMissionControl, getCliOrbiters} from '../configs/cli.config'; -import { - MISSION_CONTROL_WASM_NAME, - ORBITER_WASM_NAME, - SATELLITE_WASM_NAME -} from '../constants/constants'; import {githubCliLastRelease} from '../rest/github.rest'; -import {getSatelliteVersion} from '../services/version.services'; -import type {AssetKey} from '../types/asset-key'; -import {toAssetKeys} from '../utils/asset-key.utils'; -import { - assertConfigAndLoadSatelliteContext, - orbiterKey, - satelliteKey -} from '../utils/satellite.utils'; -import {lastRelease} from '../utils/upgrade.utils'; +import {checkVersion} from '../services/version.services'; -export const version = async (args?: string[]) => { +export const version = async () => { await cliVersion(); - - if (hasArgs({args, options: ['-c', '--cli']})) { - return; - } - - await missionControlVersion(); - await satelliteVersion(); - await orbitersVersion(); }; const cliVersion = async () => { @@ -62,173 +33,3 @@ const cliVersion = async () => { commandLineHint: `npm i -g @junobuild/cli` }); }; - -const missionControlVersion = async () => { - const missionControl = await getCliMissionControl(); - - if (isNullish(missionControl)) { - console.log( - `${yellow( - 'No mission control found.' - )} This is expected if your access key doesn't manage it.` - ); - return; - } - - const actorParams = await actorParameters(); - - const getVersion = async (): Promise => { - const version = await getJunoPackageVersion({ - moduleId: missionControl, - ...actorParams - }); - - if (nonNullish(version) && notEmptyString(version)) { - return version; - } - - // Legacy - const missionControlParameters = { - missionControlId: missionControl, - ...actorParams - }; - - return await missionControlVersionLib({ - missionControl: missionControlParameters - }); - }; - - const currentVersion = await getVersion(); - - const displayHint = `mission control`; - - await checkSegmentVersion({ - currentVersion, - assetKey: MISSION_CONTROL_WASM_NAME, - displayHint - }); -}; - -const satelliteVersion = async () => { - const {satellite} = await assertConfigAndLoadSatelliteContext(); - const {satelliteId} = satellite; - - const displayHint = `satellite "${await satelliteKey(satelliteId)}"`; - - const result = await getSatelliteVersion(); - - if (result.result === 'error') { - return; - } - - const {version: currentVersion} = result; - - await checkSegmentVersion({ - currentVersion, - assetKey: SATELLITE_WASM_NAME, - displayHint - }); -}; - -const orbitersVersion = async () => { - const orbiters = await getCliOrbiters(); - - if (isNullish(orbiters) || orbiters.length === 0) { - return; - } - - const checkOrbiterVersion = async (orbiterId: string) => { - const actorParams = await actorParameters(); - - const orbiterParameters = { - orbiterId, - ...actorParams - }; - - const getVersion = async (): Promise => { - const version = await getJunoPackageVersion({ - moduleId: orbiterId, - ...actorParams - }); - - if (nonNullish(version) && notEmptyString(version)) { - return version; - } - - // Legacy - return await orbiterVersionLib({ - orbiter: orbiterParameters - }); - }; - - const currentVersion = await getVersion(); - - const displayHint = `orbiter "${await orbiterKey(orbiterId)}"`; - - await checkSegmentVersion({ - currentVersion, - assetKey: ORBITER_WASM_NAME, - displayHint - }); - }; - - await Promise.allSettled( - orbiters.map(async ({p: orbiterId}) => { - await checkOrbiterVersion(orbiterId); - }) - ); -}; - -const checkSegmentVersion = async ({ - currentVersion, - assetKey, - displayHint -}: { - currentVersion: string; - assetKey: AssetKey; - displayHint: string; -}): Promise => { - const latestVersion = await lastRelease(toAssetKeys(assetKey)); - - if (latestVersion === undefined) { - console.log(red(`Cannot fetch last release version of ${displayHint} on Juno's CDN 😢.`)); - return; - } - - checkVersion({ - currentVersion, - latestVersion, - displayHint, - commandLineHint: `juno upgrade${assetKey === 'mission_control' ? '-t m' : ''}` - }); -}; - -const checkVersion = ({ - currentVersion, - latestVersion, - displayHint, - commandLineHint -}: { - currentVersion: string; - latestVersion: string; - displayHint: string; - commandLineHint: string; -}) => { - const diff = compare(currentVersion, latestVersion); - - if (diff === 0) { - console.log(`Your ${displayHint} (${green(`v${currentVersion}`)}) is up-to-date.`); - return; - } - - if (diff === 1) { - console.log(yellow(`Your ${displayHint} version is more recent than the latest available 🤔.`)); - return; - } - - console.log( - `Your ${displayHint} (${yellow(`v${currentVersion}`)}) is behind the latest version (${green( - `v${latestVersion}` - )}) available. Run ${cyan(commandLineHint)} to update it.` - ); -}; diff --git a/src/constants/help.constants.ts b/src/constants/help.constants.ts index be70db58..a4bf51df 100644 --- a/src/constants/help.constants.ts +++ b/src/constants/help.constants.ts @@ -18,7 +18,8 @@ export const START_DESCRIPTION = 'Start a module.'; export const STOP_DESCRIPTION = 'Stop a module.'; export const UPGRADE_DESCRIPTION = 'Upgrade a module to a new version.'; export const USE_DESCRIPTION = 'Switch between multiple profiles.'; -export const VERSION_DESCRIPTION = 'Check the version of the modules and CLI.'; +export const VERSION_DESCRIPTION = 'Check the version of the CLI.'; +export const STATUS_DESCRIPTION = 'Check the status of the modules.'; export const WHOAMI_DESCRIPTION = 'Display your current profile, access key, and links to your satellite.'; diff --git a/src/help/status.help.ts b/src/help/status.help.ts new file mode 100644 index 00000000..95f9f7e4 --- /dev/null +++ b/src/help/status.help.ts @@ -0,0 +1,28 @@ +import {cyan, green, yellow} from 'kleur'; +import {OPTIONS_ENV, OPTION_HELP, STATUS_DESCRIPTION} from '../constants/help.constants'; +import {helpOutput} from './common.help'; +import {TITLE} from './help'; + +const usage = `Usage: ${green('juno')} ${cyan('status')} ${yellow('[options]')} + +Options: + ${OPTIONS_ENV} + ${OPTION_HELP}`; + +const doc = `${STATUS_DESCRIPTION} + +\`\`\` +${usage} +\`\`\` +`; + +const help = `${TITLE} + +${STATUS_DESCRIPTION} + +${usage} +`; + +export const logHelpStatus = (args?: string[]) => { + console.log(helpOutput(args) === 'doc' ? doc : help); +}; diff --git a/src/help/version.help.ts b/src/help/version.help.ts index ac5d2b10..bd7a9f09 100644 --- a/src/help/version.help.ts +++ b/src/help/version.help.ts @@ -1,13 +1,11 @@ import {cyan, green, yellow} from 'kleur'; -import {OPTIONS_ENV, OPTION_HELP, VERSION_DESCRIPTION} from '../constants/help.constants'; +import {OPTION_HELP, VERSION_DESCRIPTION} from '../constants/help.constants'; import {helpOutput} from './common.help'; import {TITLE} from './help'; -const usage = `Usage: ${green('juno')} ${cyan('init')} ${yellow('[options]')} +const usage = `Usage: ${green('juno')} ${cyan('version')} ${yellow('[options]')} Options: - ${yellow('-c, --cli')} Check only the version of the CLI. - ${OPTIONS_ENV} ${OPTION_HELP}`; const doc = `${VERSION_DESCRIPTION} diff --git a/src/index.ts b/src/index.ts index 7c9359ea..af37a585 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,6 +11,7 @@ import {init} from './commands/init'; import {open} from './commands/open'; import {snapshot} from './commands/snapshot'; import {startStop} from './commands/start-stop'; +import {status} from './commands/status'; import {upgrade} from './commands/upgrade'; import {version as versionCommand} from './commands/version'; import {whoami} from './commands/whoami'; @@ -24,6 +25,7 @@ import {logHelpLogout} from './help/logout.help'; import {logHelpOpen} from './help/open.help'; import {logHelpSnapshot} from './help/snapshot.help'; import {logHelpStart} from './help/start.help'; +import {logHelpStatus} from './help/status.help'; import {logHelpStop} from './help/stop.help'; import {logHelpUpgrade} from './help/upgrade.help'; import {logHelpVersion} from './help/version.help'; @@ -52,7 +54,7 @@ export const run = async () => { // Special use case if dev runs "juno --version" if (['-v', '--version'].includes(cmd)) { - await versionCommand(args); + await versionCommand(); return; } @@ -95,6 +97,9 @@ export const run = async () => { case 'version': logHelpVersion(args); break; + case 'status': + logHelpStatus(args); + break; case 'whoami': logHelpWhoAmI(args); break; @@ -134,7 +139,10 @@ export const run = async () => { await clear(); break; case 'version': - await versionCommand(args); + await versionCommand(); + break; + case 'status': + await status(); break; case 'open': await open(args); diff --git a/src/services/version.services.ts b/src/services/version.services.ts index 19c9f4ce..fc025377 100644 --- a/src/services/version.services.ts +++ b/src/services/version.services.ts @@ -5,8 +5,9 @@ import { satelliteVersion as satelliteVersionLib } from '@junobuild/admin'; import {JUNO_PACKAGE_SATELLITE_ID} from '@junobuild/config'; -import {red} from 'kleur'; +import {cyan, green, red, yellow} from 'kleur'; import ora from 'ora'; +import {compare} from 'semver'; import type {SatelliteParametersWithId} from '../types/satellite'; import {assertConfigAndLoadSatelliteContext} from '../utils/satellite.utils'; @@ -75,3 +76,33 @@ const loadSatelliteVersion = async ({ return {result: 'success', version: legacyVersion}; }; + +export const checkVersion = ({ + currentVersion, + latestVersion, + displayHint, + commandLineHint +}: { + currentVersion: string; + latestVersion: string; + displayHint: string; + commandLineHint: string; +}) => { + const diff = compare(currentVersion, latestVersion); + + if (diff === 0) { + console.log(`Your ${displayHint} (${green(`v${currentVersion}`)}) is up-to-date.`); + return; + } + + if (diff === 1) { + console.log(yellow(`Your ${displayHint} version is more recent than the latest available 🤔.`)); + return; + } + + console.log( + `Your ${displayHint} (${yellow(`v${currentVersion}`)}) is behind the latest version (${green( + `v${latestVersion}` + )}) available. Run ${cyan(commandLineHint)} to update it.` + ); +};