Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@oclif/plugin-warn-if-update-available

Package Overview
Dependencies
Maintainers
2
Versions
134
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@oclif/plugin-warn-if-update-available - npm Package Compare versions

Comparing version 2.1.1 to 2.1.2-qa.0

oclif.lock

32

lib/get-version.js

@@ -1,8 +0,12 @@

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const promises_1 = require("fs/promises");
const http_call_1 = require("http-call");
const path_1 = require("path");
// eslint-disable-next-line max-params
async function run(name, file, version, registry, authorization) {
import makeDebug from 'debug';
import { HTTP } from 'http-call';
import { mkdir, writeFile } from 'node:fs/promises';
import { dirname } from 'node:path';
async function run([name, file, version, registry, authorization]) {
const debug = makeDebug('get-version');
debug('name:', name);
debug('file:', file);
debug('version:', version);
debug('registry:', registry);
debug('authorization:', authorization);
const url = [

@@ -13,9 +17,11 @@ registry.replace(/\/+$/, ''),

const headers = authorization ? { authorization } : {};
await (0, promises_1.mkdir)((0, path_1.dirname)(file), { recursive: true });
await (0, promises_1.writeFile)(file, JSON.stringify({ current: version, headers })); // touch file with current version to prevent multiple updates
const { body } = await http_call_1.default.get(url, { headers, timeout: 5000 });
await (0, promises_1.writeFile)(file, JSON.stringify(Object.assign(Object.assign({}, body['dist-tags']), { current: version, authorization })));
await mkdir(dirname(file), { recursive: true });
await writeFile(file, JSON.stringify({ current: version, headers })); // touch file with current version to prevent multiple updates
const { body } = await HTTP.get(url, { headers, timeout: 5000 });
await writeFile(file, JSON.stringify({ ...body['dist-tags'], authorization, current: version }));
process.exit(0); // eslint-disable-line unicorn/no-process-exit, no-process-exit
}
run(process.argv[2], process.argv[3], process.argv[4], process.argv[5], process.argv[6])
.catch(require('@oclif/core/handle'));
await run(process.argv.slice(2)).catch(async (error) => {
const { handle } = await import('@oclif/core');
await handle(error);
});

@@ -1,3 +0,23 @@

import { Hook } from '@oclif/core';
import { Hook, Interfaces } from '@oclif/core';
export declare function hasNotBeenMsSinceDate(ms: number, now: Date, date: Date): boolean;
export declare function convertToMs(frequency: number, unit: 'days' | 'hours' | 'milliseconds' | 'minutes' | 'seconds'): number;
export declare function getEnvVarNumber(envVar: string, defaultValue?: number): number | undefined;
export declare function getEnvVarEnum<T extends string>(envVar: string, allowed: T[], defaultValue: T): T;
export declare function getEnvVarEnum<T extends string>(envVar: string, allowed: T[], defaultValue?: T): T | undefined;
export declare function semverGreaterThan(a: string, b: string): boolean;
/**
* Returns the newest version of the CLI from the cache if it is newer than the current version.
*
* Returns undefined early if:
* - `update` command is being run
* - `<CLI>_SKIP_NEW_VERSION_CHECK` is set to true
* - the current version is a prerelease
* - the warning was last shown to the user within the frequency and frequencyUnit
*/
export declare function getNewerVersion({ argv, config, file, }: {
argv: string[];
config: Interfaces.Config;
file: string;
}): Promise<string | undefined>;
declare const hook: Hook<'init'>;
export default hook;

@@ -1,44 +0,103 @@

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const child_process_1 = require("child_process");
const promises_1 = require("fs/promises");
const path_1 = require("path");
import chalk from 'chalk';
import makeDebug from 'debug';
import { spawn } from 'node:child_process';
import { stat as fsStat, readFile, utimes } from 'node:fs/promises';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
async function readJSON(file) {
const [contents, stat] = await Promise.all([readFile(file, 'utf8'), fsStat(file)]);
return { contents: JSON.parse(contents), stat };
}
export function hasNotBeenMsSinceDate(ms, now, date) {
const diff = now.getTime() - date.getTime();
return diff < ms;
}
export function convertToMs(frequency, unit) {
switch (unit) {
case 'days': {
return frequency * 24 * 60 * 60 * 1000;
}
case 'hours': {
return frequency * 60 * 60 * 1000;
}
case 'milliseconds': {
return frequency;
}
case 'minutes': {
return frequency * 60 * 1000;
}
case 'seconds': {
return frequency * 1000;
}
default: {
// default to minutes
return frequency * 60 * 1000;
}
}
}
export function getEnvVarNumber(envVar, defaultValue) {
const envVarRaw = process.env[envVar];
if (!envVarRaw)
return defaultValue;
const parsed = Number.parseInt(envVarRaw, 10);
if (Number.isNaN(parsed))
return defaultValue;
return parsed;
}
export function getEnvVarEnum(envVar, allowed, defaultValue) {
const envVarRaw = process.env[envVar];
if (!envVarRaw)
return defaultValue;
if (!allowed.includes(envVarRaw))
return defaultValue;
return envVarRaw;
}
export function semverGreaterThan(a, b) {
return a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' }) > 0;
}
/**
* Returns the newest version of the CLI from the cache if it is newer than the current version.
*
* Returns undefined early if:
* - `update` command is being run
* - `<CLI>_SKIP_NEW_VERSION_CHECK` is set to true
* - the current version is a prerelease
* - the warning was last shown to the user within the frequency and frequencyUnit
*/
export async function getNewerVersion({ argv, config, file, }) {
// do not show warning if running `update` command of <CLI>_SKIP_NEW_VERSION_CHECK=true
if (argv[2] === 'update' || config.scopedEnvVarTrue('SKIP_NEW_VERSION_CHECK'))
return;
// TODO: handle prerelease channels
if (config.version.includes('-'))
return;
const { frequency, frequencyUnit } = config.pjson.oclif['warn-if-update-available'] ?? {};
const warningFrequency = getEnvVarNumber(config.scopedEnvVarKey('NEW_VERSION_CHECK_FREQ'), frequency);
const warningFrequencyUnit = getEnvVarEnum(config.scopedEnvVarKey('NEW_VERSION_CHECK_FREQ_UNIT'), ['days', 'hours', 'minutes', 'seconds', 'milliseconds'], frequencyUnit ?? 'minutes');
const tag = config.scopedEnvVar('NEW_VERSION_CHECK_TAG') ?? 'latest';
const { contents: distTags, stat } = await readJSON(file);
// If the file was modified before the timeout, don't show the warning
if (warningFrequency &&
warningFrequencyUnit &&
hasNotBeenMsSinceDate(convertToMs(warningFrequency, warningFrequencyUnit), new Date(), stat.mtime))
return;
if (distTags[tag] && semverGreaterThan(distTags[tag].split('-')[0], config.version.split('-')[0]))
return distTags[tag];
}
const hook = async function ({ config }) {
const file = (0, path_1.join)(config.cacheDir, 'version');
const debug = makeDebug('update-check');
const file = join(config.cacheDir, 'version');
// Destructure package.json configuration with defaults
const { timeoutInDays = 60, message = '<%= config.name %> update available from <%= chalk.greenBright(config.version) %> to <%= chalk.greenBright(latest) %>.', registry = 'https://registry.npmjs.org', authorization = '', } = config.pjson.oclif['warn-if-update-available'] || {};
const checkVersion = async () => {
try {
// do not show warning if updating
if (process.argv[2] === 'update')
return;
const distTags = JSON.parse(await (0, promises_1.readFile)(file, 'utf8'));
if (config.version.includes('-')) {
// to-do: handle channels
return;
}
const semverGt = await Promise.resolve().then(() => require('semver/functions/gt'));
if (distTags && distTags.latest && semverGt(distTags.latest.split('-')[0], config.version.split('-')[0])) {
const chalk = require('chalk');
// Default message if the user doesn't provide one
const template = require('lodash.template');
this.warn(template(message)(Object.assign({ chalk,
config }, distTags)));
}
}
catch (error) {
if (error.code !== 'ENOENT')
throw error;
}
};
const { authorization = '', message = '<%= config.name %> update available from <%= chalk.greenBright(config.version) %> to <%= chalk.greenBright(latest) %>.', registry = 'https://registry.npmjs.org', timeoutInDays = 60, } = config.pjson.oclif['warn-if-update-available'] ?? {};
const refreshNeeded = async () => {
if (this.config.scopedEnvVarTrue('FORCE_VERSION_CACHE_UPDATE'))
return true;
if (this.config.scopedEnvVarTrue('SKIP_NEW_VERSION_CHECK'))
return false;
try {
const { mtime } = await (0, promises_1.stat)(file);
const staleAt = new Date(mtime.valueOf() + (1000 * 60 * 60 * 24 * timeoutInDays));
const { mtime } = await fsStat(file);
const staleAt = new Date(mtime.valueOf() + 1000 * 60 * 60 * 24 * timeoutInDays);
return staleAt < new Date();
}
catch (error) {
const debug = require('debug')('update-check');
debug(error);

@@ -49,5 +108,6 @@ return true;

const spawnRefresh = async () => {
const debug = require('debug')('update-check');
const versionScript = resolve(dirname(fileURLToPath(import.meta.url)), '../../../lib/get-version');
debug('spawning version refresh');
(0, child_process_1.spawn)(process.execPath, [(0, path_1.join)(__dirname, '../../../lib/get-version'), config.name, file, config.version, registry, authorization], {
debug(process.execPath, versionScript, config.name, file, config.version, registry, authorization);
spawn(process.execPath, [versionScript, config.name, file, config.version, registry, authorization], {
detached: !config.windows,

@@ -57,6 +117,27 @@ stdio: 'ignore',

};
await checkVersion();
try {
const newerVersion = await getNewerVersion({ argv: process.argv, config, file });
if (newerVersion) {
// Default message if the user doesn't provide one
const [template] = await Promise.all([
import('lodash.template'),
// Update the modified time (mtime) of the version file so that we can track the last time we
// showed the warning. This makes it possible to respect the frequency and frequencyUnit options.
utimes(file, new Date(), new Date()),
]);
this.warn(template.default(message)({
chalk,
config,
latest: newerVersion,
}));
}
}
catch (error) {
const { code } = error;
if (code !== 'ENOENT')
throw error;
}
if (await refreshNeeded())
await spawnRefresh();
};
exports.default = hook;
export default hook;

@@ -1,3 +0,1 @@

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = {};
export default {};
{
"version": "2.1.1",
"commands": {}
"commands": {},
"version": "2.1.2-qa.0"
}
{
"name": "@oclif/plugin-warn-if-update-available",
"description": "warns if there is a newer version of CLI released",
"version": "2.1.1",
"version": "2.1.2-qa.0",
"author": "Salesforce",
"bugs": "https://github.com/oclif/plugin-warn-if-update-available/issues",
"dependencies": {
"@oclif/core": "^2.15.0",
"chalk": "^4.1.0",
"@oclif/core": "^3.3.1",
"chalk": "^5.3.0",
"debug": "^4.1.0",
"http-call": "^5.2.2",
"lodash.template": "^4.5.0",
"semver": "^7.5.4"
"lodash.template": "^4.5.0"
},
"devDependencies": {
"@oclif/test": "^1.2.8",
"@types/chai": "^4.3.6",
"@commitlint/config-conventional": "^17.7.0",
"@oclif/prettier-config": "^0.2.1",
"@oclif/test": "^3.0.2",
"@types/chai": "^4.3.8",
"@types/debug": "^4.1.9",
"@types/lodash.template": "^4.5.1",
"@types/mocha": "^8.0.0",
"@types/node": "^14.18.62",
"@types/semver": "^7.5.2",
"chai": "^4.3.8",
"eslint": "^7.3.1",
"eslint-config-oclif": "^3.1.0",
"eslint-config-oclif-typescript": "^0.2.0",
"@types/mocha": "^10.0.2",
"@types/node": "^18",
"@types/semver": "^7.5.3",
"chai": "^4.3.10",
"commitlint": "^17.7.2",
"eslint": "^8.51.0",
"eslint-config-oclif": "^5.0.0",
"eslint-config-oclif-typescript": "^3.0.5",
"eslint-config-prettier": "^9.0.0",
"globby": "^11.0.1",
"mocha": "^8.0.1",
"oclif": "^3.17.1",
"ts-node": "^9.1.1",
"tslib": "^2.6.2",
"typescript": "4.4.3"
"husky": "^8.0.3",
"lint-staged": "^14.0.1",
"mocha": "^10.2.0",
"oclif": "^4.0.2",
"prettier": "^3.0.3",
"sinon": "^16.1.0",
"ts-node": "^10.9.1",
"typescript": "^5.2.2"
},
"engines": {
"node": ">=12.0.0"
"node": ">=18.0.0"
},
"exports": "./lib/index.js",
"files": [
"oclif.manifest.json",
"/lib"
"/lib",
"/oclif.lock"
],

@@ -51,3 +60,4 @@ "homepage": "https://github.com/oclif/plugin-warn-if-update-available",

]
}
},
"topicSeparator": " "
},

@@ -57,13 +67,14 @@ "repository": "oclif/plugin-warn-if-update-available",

"build": "rm -rf lib && tsc",
"clean": "rm -f oclif.manifest.json",
"lint": "eslint . --ext .ts --config .eslintrc",
"clean": "rm -f oclif.manifest.json oclif.lock",
"lint": "eslint . --ext .ts",
"postpublish": "yarn run clean",
"posttest": "yarn lint",
"prepare": "husky install",
"prepublishOnly": "yarn run build && oclif lock && oclif manifest . && oclif readme",
"pretest": "yarn build --noEmit && tsc -p test --noEmit",
"preversion": "yarn run clean",
"test": "mocha --forbid-only \"test/**/*.test.ts\"",
"posttest": "yarn lint",
"prepublishOnly": "yarn run build && oclif manifest . && oclif readme",
"postpublish": "yarn run clean",
"preversion": "yarn run clean",
"version": "oclif readme && git add README.md"
},
"main": "lib/index.js"
}
"type": "module"
}

@@ -1,3 +0,2 @@

@oclif/plugin-warn-if-update-available
======================================
# @oclif/plugin-warn-if-update-available

@@ -7,4 +6,2 @@ warns if there is a newer version of CLI released

[![Version](https://img.shields.io/npm/v/@oclif/plugin-warn-if-update-available.svg)](https://npmjs.org/package/@oclif/plugin-warn-if-update-available)
[![CircleCI](https://circleci.com/gh/oclif/plugin-warn-if-update-available/tree/main.svg?style=shield)](https://circleci.com/gh/oclif/plugin-warn-if-update-available/tree/main)
[![Appveyor CI](https://ci.appveyor.com/api/projects/status/github/oclif/plugin-warn-if-update-available?branch=main&svg=true)](https://ci.appveyor.com/project/oclif/plugin-warn-if-update-available/branch/main)
[![Downloads/week](https://img.shields.io/npm/dw/@oclif/plugin-warn-if-update-available.svg)](https://npmjs.org/package/@oclif/plugin-warn-if-update-available)

@@ -14,2 +11,3 @@ [![License](https://img.shields.io/npm/l/@oclif/plugin-warn-if-update-available.svg)](https://github.com/oclif/plugin-warn-if-update-available/blob/main/package.json)

<!-- toc -->
* [@oclif/plugin-warn-if-update-available](#oclifplugin-warn-if-update-available)
* [What is this?](#what-is-this)

@@ -19,2 +17,3 @@ * [How it works](#how-it-works)

* [Configuration](#configuration)
* [Environment Variables](#environment-variables)
<!-- tocstop -->

@@ -30,3 +29,3 @@

This checks the version against the npm registry asynchronously in a forked process, at most once per 7 days. It then saves a version file to the cache directory that will enable the warning. The upside of this method is that it won't block a user while they're using your CLI—the downside is that it will only display _after_ running a command that fetches the new version.
This checks the version against the npm registry asynchronously in a forked process once every 60 days by default (see [Configuration](#configuration) for how to configure this). It then saves a version file to the cache directory that will enable the warning. The upside of this method is that it won't block a user while they're using your CLI—the downside is that it will only display _after_ running a command that fetches the new version.

@@ -57,2 +56,4 @@ # Installation

- `authorization` - Authorization header value for registries that require auth.
- `frequency` - The frequency that the new version warning should be shown.
- `frequencyUnit` - The unit of time that should be used to calculate the frequency (`days`, `hours`, `minutes`, `seconds`, `milliseconds`). Defaults to `minutes`.

@@ -64,5 +65,3 @@ ## Example configuration

"oclif": {
"plugins": [
"@oclif/plugin-warn-if-update-available"
],
"plugins": ["@oclif/plugin-warn-if-update-available"],
"warn-if-update-available": {

@@ -77,1 +76,65 @@ "timeoutInDays": 7,

```
## Notification Frequency
Once a new version has been found, the default behavior is to notify the user on every command execution. You can modify this by setting the `frequency` and `frequencyUnit` options.
**Examples**
Once every 10 minutes.
```json
{
"oclif": {
"warn-if-update-available": {
"frequency": 10
}
}
}
```
Once every 6 hours.
```json
{
"oclif": {
"warn-if-update-available": {
"frequency": 6,
"frequencyUnit": "hours"
}
}
}
```
Once a day.
```json
{
"oclif": {
"warn-if-update-available": {
"frequency": 1,
"frequencyUnit": "days"
}
}
}
```
Once every 30 seconds.
```json
{
"oclif": {
"warn-if-update-available": {
"frequency": 30,
"frequencyUnit": "seconds"
}
}
}
```
# Environment Variables
- `<CLI>_SKIP_NEW_VERSION_CHECK`: Skip this version check
- `<CLI>_FORCE_VERSION_CACHE_UPDATE`: Force the version cache to update
- `<CLI>_NEW_VERSION_CHECK_FREQ`: environment variable override for `frequency` setting
- `<CLI>_NEW_VERSION_CHECK_FREQ_UNIT`: environment variable override for `frequencyUnit` setting
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc