npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

package-version-upgrade-manager

v1.0.0

Published

Manage and report package version upgrades based on pre-defined version policies

Downloads

3

Readme

Package version upgrade manager

Replaces deprecated package version report generator.

This tool is now focused on managing and reporting package version upgrades based on policies.

It can be run on package.json file to:

  • generate package dependency reports.
  • determine packages that are invalid according to version policies and need to be updated

The goal of this tool is to help organizations detect packages that are in need of attention and could pose security risks, technical debt issues etc.

The package contains a binary pvum which can be run in the Terminal CLI as described under Usage

Alternatively you can integrate the core functionality in your own NodeJS tooling, such as described under Complete notification example (Slack API notifications)

import { getPackageInfo } from "package-version-upgrade-manager";

getPackageInfo is async and returns an object with packages and invalid status.

const { packages, invalid } = await getPackageInfo(pkgFile, opts);

1. Dependencies report

The default package dependencies report contains the following information for each package:

{
  "name": "got",
  "version": "11.8.2",
  "versionDate": "2021-2-26",
  "semVerDiff": "major",
  "versionDiff": "1.0.0",
  "majorDiff": 1,
  "minorDiff": 0,
  "patchDiff": 0,
  "latestVersion": "12.3.1",
  "latestVersionDate": "2022-8-6",
  "daysBehindLatestVersion": 526,
  "invalid": true
}

If run with --verbose setting you can additionally get the following information (versions are last 5 versions published)

{
  "description": "yargs the modern, pirate-themed, successor to optimist.",
  "license": "MIT",
  "homepage": "https://yargs.js.org/",
  "author": "bcoe, oss-bot",
  "versions": ["17.1.0", "17.1.1-candidate.0"]
}

You can use tools like jq to parse the JSON and handle it as needed, such as in the early stage of a CI pipeline to notify relevant parties, abort the pipeline etc.

2. Usage

The package installation makes the pvum executable available

$ pvum

Usage help

$ pvum --help

Commands:
  pvum info [pkgfile]         fetch package info from package.json file
  pvum xls-report [filepath]  generate xls file (Excel) from report json file

Options:
  --help     Show help                                                 [boolean]
  --version  Show version number                                       [boolean]
  -v, --verbose  Verbose package info                                  [boolean]

  -o, --output   Output file to store the report                       [string]
  -n, --names    Output only package names                             [boolean]
  -p, --pretty   Pretty output package names                             [boolean]

  -f, --filter   Apply rules filter to only output invalid packages    [boolean]
      --dev           Include devDependencies                          [boolean]
  -r, --rules    Path to rules file                                    [string]
  -s, --maxSVD   maximum semver diff such as: minor                    [string]
  -d, --maxDays  maximum number of days since last release             [string]
  --maxPatchDiff maximum patch versions behind                         [string]
  --maxMinorDiff maximum minor versions behind                         [string]
  --maxMajorDiff maximum major versions behind                         [string]

Print basic report

$ pvum info package.json

Processing: package.json
[
  {
    "name": "got",
    "version": "11.8.2",
    "versionDate": "2021-2-26",
    "semVerDiff": "major",
    "versionDiff": "1.0.0",
    "majorDiff": 1,
    "minorDiff": 0,
    "patchDiff": 0,
    "latestVersion": "12.4.1",
    "latestVersionDate": "2022-9-2",
    "daysBehindLatestVersion": 553,
    "invalid": false
  },
]

2.1. Exit codes

Use the ---exit option to force exit with a system exit code.

The exit code will be 0 (success) when there are no invalid packages and 1 (error) if there are 1 or more invalid packages.

Example usage:

$ pvum info package.json -r rules.json --dev --names --pretty --exit
Processing: package.json
diff-dates,got,json2xls,latest-semver,read-pkg,registry-url,semver-diff,yargs
 ✘  ~/repos/personal/package-version-upgrade-manager

Returns pretty printed list of invalid packages with exit code 1 (error)

2.2. Names

If run with --names you get the list of invalid package names

$ pvum info package.json -r warn-policies.json --names
got,yargs

If there are NO invalid packages it returns nothing

$ pvum info package.json -r critical-policies.json --names

This is useful combined with run against rules and --filter to output the list of packages that are invalid according to the version policies.

You can use different policy files for alerting on multiple policy levels such as warning and critical (see Complete notification example below)

3. Generate report

Generate and store basic report using the --output (-o) flag

$ pvum info package.json --output report.json

Processing: package.json
Writing to file: report.json
Done :)

Generate and store verbose report using the --verbose (-v) flag

$ pvum info package.json --verbose --output report.json

Processing: package.json
Writing to file: report.json
Done :)

4. Run against rules

Create a rules file such as:

{
  "maxSVD": "minor",
  "maxDays": 180,
  "maxMinorDiff": 2,
  "exclude": ["lodash", "moment"]
}

This rule file says that if a package version is either:

  • more than 2 minor versions behind (maxMinorDiff)
  • at least one minor version (maxSVD: "minor") and 180 days behind latest release (ie. maxDays)
  • and not in the list of packages to be excluded for consideration

Then the package will be marked as invalid in the output.

Then rule with the -r option pointing to the rule file

$ pvum info -r rules.json

Alternatively use the rule options directly

$ pvum info -r rules.json -d 160 -s minor

If you supply both types of rules, the options override any rule in the the rules file (overide maxDays in rules.json)

$ pvum info -r rules.json -d 160

With rules the invalid entry will be true or false depending on whether the package entry is within the constraints defined by the rules.

[
  {
    "name": "diff-dates",
    "version": "1.0.14",
    "versionDate": "2021-3-2",
    "versionDiff": "0.0.0",
    "majorDiff": 0,
    "minorDiff": 0,
    "patchDiff": 0,
    "latestVersion": "1.0.14",
    "latestVersionDate": "2021-3-2",
    "daysBehindLatestVersion": 0,
    "invalid": false
  },
  {
    "name": "got",
    "version": "11.8.2",
    "versionDate": "2021-2-26",
    "semVerDiff": "major",
    "versionDiff": "1.0.0",
    "majorDiff": 1,
    "minorDiff": 0,
    "patchDiff": 0,
    "latestVersion": "12.4.1",
    "latestVersionDate": "2022-9-2",
    "daysBehindLatestVersion": 553,
    "invalid": false
  },
 ]

In the above output, we can see that the package got has a semVerDiff of major which means it is a major sem version behind and more than 180 days (here 526) behind latest release. Therefore invalid for got is marked as false

4.1. Package category rules

You may also define package rule categories. Here we specify a set of core packages (react and redux) as entries in categories.list that all share the same package category rule as entries under categories.rules.

{
  "maxSVD": "minor",
  "maxDays": 180,
  "maxMinorDiff": 3,
  "categories": {
    "rules": {
      "core": {
        "maxDays": 90,
        "maxMinorDiff": 2
      }
    },
    "lists": {
      "core": ["react", "redux"]
    }
  }
}

4.2. Package specific rules

You can add a packages entry to the rules file to set package specific rules that override default and category rules.

{
  "maxSVD": "minor",
  "maxDays": 180,
  "maxMinorDiff": 3,
  "packages": {
    "react": {
      "maxDays": 90,
      "maxMinorDiff": 2
    }
  }
}

5. Generate XLS (Excel) report

The dependencies report .json file can be exported to an .xslx file (for Excel) using the xls-report command.

$ pvum xls-report report.json

Generating XLS report file for: report.json
Writing to file: report_2021-12-09.json
Done :)

6. Complete notification example

See this example in the examples folder of the repo. Ensure the following env variables are set:

  • SLACK_TOKEN
  • SLACK_CONVERSATION_ID

You can notify relevant parties using Slack or similar notification systems.

This could look something like the following:

import { WebClient } from "@slack/web-api";
import { getPackageInfo } from "package-version-upgrade-manager";

// Read a token from the environment variables
const token = process.env.SLACK_TOKEN;

// Initialize
const web = new WebClient(token);

// Given some known conversation ID (representing a public channel, private channel, DM or group DM)
const conversationId = process.env.SLACK_CONVERSATION_ID;

const policyLabelMap = {
  warn: "Warning ⚠️",
  critical: "CRITICAL 🔥🔥🔥",
};

const notifySlackChannel = async (packageNames, policy = "warn") => {
  // Post a message to the channel, and await the result.
  // Find more arguments and details of the response: https://api.slack.com/methods/chat.postMessage
  const namesToPrint = packageNames.join(", ");
  const policyLabel = policyLabelMap[policy];
  const text = `${policyLabel} : packages to be updated: ${namesToPrint}`;
  await web.chat.postMessage({
    text,
    channel: conversationId,
  });
};

const onInvalidPackages = async (packageNames, policy) => {
  await notifySlackChannel(packageNames, policy);
};

// default options
const opts = {
  names: true,
};

const rulesFileMap = {
  warn: "warning-policies.json",
  critical: "critical-policies.json",
};

const pkgFile = "./package.json";

const handlePolicies = async (msgFn, rulesFile, { policy }) => {
  const { packages, invalid } = await getPackageInfo(pkgFile, {
    ...opts,
    rules: rulesFile,
  });
  if (invalid) {
    await onInvalidPackages(packages, policy);
  }
  const msg = msgFn(opts);
  msg && console.log(msg);
};

const msgFn = ({ policy } = {}) => policy && `${policy} policies DONE`;

const policies = ["critical", "warn"];

const run = async () => {
  for (policy in policies) {
    await handlePolicies(msgFn, rulesFileMap[policy], { policy });
  }
};
run();