diff --git a/bun.lockb b/bun.lockb index 6d6c1326..f93f9821 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/packages/cli/README.md b/packages/cli/README.md index a3ecda7e..5c67bc10 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -55,6 +55,7 @@ Commands: pull|pl [options] Pull variables for specified environment to .env file push|ps [options] Push variables for specified environment to Shelve generate|g Generate resources for a project + upgrade|u Upgrade the Shelve CLI to the latest version config|cf Show the current configuration help [command] display help for command ``` diff --git a/packages/cli/package.json b/packages/cli/package.json index 0290aafa..992e6ab1 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@shelve/cli", - "version": "2.2.1", + "version": "2.3.0", "description": "The command-line interface for Shelve", "homepage": "https://shelve.hrcd.fr", "bugs": { @@ -43,13 +43,16 @@ "c12": "^1.11.2", "commander": "^12.1.0", "consola": "^3.2.3", + "npm-registry-fetch": "^17.1.0", "nypm": "^0.3.11", "ofetch": "^1.3.4", + "semver": "^7.6.3", "unbuild": "^2.0.0" }, "devDependencies": { "@shelve/types": "workspace:*", "@types/bun": "^1.1.9", + "@types/npm-registry-fetch": "^8.0.7", "@types/semver": "^7.5.8", "eslint": "^9.10.0", "release-it": "^17.6.0", diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index 437c968a..c0aef772 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -4,11 +4,13 @@ import { pullCommand } from './pull' import { pushCommand } from './push' import { generateCommand } from './generate' import { createCommand } from './create' +import { upgradeCommand } from './upgrade' export function registerCommands(program: Command): void { createCommand(program) pullCommand(program) pushCommand(program) generateCommand(program) + upgradeCommand(program) configCommand(program) } diff --git a/packages/cli/src/commands/upgrade.ts b/packages/cli/src/commands/upgrade.ts new file mode 100644 index 00000000..a97a687b --- /dev/null +++ b/packages/cli/src/commands/upgrade.ts @@ -0,0 +1,27 @@ +import { Command } from 'commander' +import { intro, outro } from '@clack/prompts' +import { isLatestVersion, installLatest, onCancel } from '../utils' + +export function upgradeCommand(program: Command): void { + program + .command('upgrade') + .alias('u') + .description('Upgrade the Shelve CLI to the latest version') + .action(async () => { + intro('Upgrading Shelve CLI to the latest version') + + try { + const isLatest = await isLatestVersion() + if (isLatest) { + outro('Shelve CLI is already up to date') + return + } + + await installLatest() + outro('Shelve CLI has been successfully updated') + } catch (error) { + console.error(error) + onCancel('Failed to check for updates') + } + }) +} diff --git a/packages/cli/src/utils/index.ts b/packages/cli/src/utils/index.ts index a816f370..75f9a6af 100644 --- a/packages/cli/src/utils/index.ts +++ b/packages/cli/src/utils/index.ts @@ -1,6 +1,41 @@ -import { cancel } from '@clack/prompts' +import { cancel, spinner, note } from '@clack/prompts' +import { addDependency } from 'nypm' +import semver from 'semver' +import npmFetch from 'npm-registry-fetch' +import { version } from '../../package.json' + +const s = spinner() export function onCancel(message: string, output: number = 0): never { cancel(message) process.exit(output) } + +export async function isLatestVersion(): Promise { + s.start('Checking for updates') + + const packageInfo = await npmFetch.json('/@shelve/cli') as { + 'dist-tags': { + latest: string + } + } + + s.stop('Checking for updates') + + const latestVersion = packageInfo['dist-tags'].latest + const isUpdated = semver.gte(version, latestVersion) + + if (!isUpdated) + note(`Shelve CLI ${version} is available (latest version is ${latestVersion})`, 'Update available') + + return isUpdated +} + +export async function installLatest(): Promise { + s.start('Updating Shelve CLI') + await addDependency('@shelve/cli', { + silent: true, + global: true + }) + s.stop('Updating Shelve CLI') +}