@versatiles/release-tool 2.4.4 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,6 @@
1
- import { readFileSync, writeFileSync } from 'fs';
2
- import { inspect } from 'util';
3
- import { check, info, warn } from '../lib/log.js';
4
- import { getShell } from '../lib/shell.js';
1
+ import ncu from 'npm-check-updates';
2
+ import { check, info } from '../lib/log.js';
3
+ import { Shell } from '../lib/shell.js';
5
4
  /**
6
5
  * Upgrades the dependencies in a package.json file to their latest versions, removes existing
7
6
  * installed modules, and reinstalls them in the specified directory.
@@ -17,88 +16,17 @@ import { getShell } from '../lib/shell.js';
17
16
  * @returns A promise that resolves when the process is complete.
18
17
  */
19
18
  export async function upgradeDependencies(directory) {
20
- const shell = getShell(directory);
21
- // Step 1: Check and upgrade all versions
22
- await check('Upgrade all versions', async () => {
23
- const { stdout } = await shell.run('npm outdated --all --json', false);
24
- const outdated = JSON.parse(stdout);
25
- const latestVersions = new Map();
26
- // Collect the latest version for each dependency
27
- for (const [name, entry] of Object.entries(outdated)) {
28
- let version = '0.0.0';
29
- if (Array.isArray(entry)) {
30
- for (const item of entry) {
31
- if (isGreaterSemver(item.latest, version))
32
- version = item.latest;
33
- }
34
- }
35
- else {
36
- version = entry.latest;
37
- }
38
- latestVersions.set(name, version);
39
- }
40
- // Load package.json
41
- const pack = JSON.parse(readFileSync('package.json', 'utf8'));
42
- // Update dependencies to their latest versions
43
- patch(pack.dependencies);
44
- patch(pack.devDependencies);
45
- patch(pack.optionalDependencies);
46
- patch(pack.peerDependencies);
47
- // Write the updated package.json
48
- writeFileSync('package.json', JSON.stringify(pack, null, 2) + '\n');
49
- /**
50
- * Mutates the provided dependency object by updating
51
- * each dependency to the latest known version (if available).
52
- *
53
- * @param dependencies - A mapping of dependency names to their currently specified versions.
54
- */
55
- function patch(dependencies) {
56
- if (!dependencies)
57
- return;
58
- for (const name of Object.keys(dependencies)) {
59
- const version = latestVersions.get(name);
60
- if (version)
61
- dependencies[name] = '^' + version;
62
- }
63
- }
19
+ await check('Upgrade all dependencies', async () => {
20
+ await ncu.run({
21
+ cwd: directory,
22
+ packageFile: 'package.json',
23
+ upgrade: true,
24
+ });
64
25
  });
65
- // Step 2: Remove existing dependencies and lock file
66
- await check('Remove all dependencies', async () => {
67
- try {
68
- await shell.run('rm -f package-lock.json');
69
- }
70
- catch (e) {
71
- warn(inspect(e));
72
- }
73
- });
74
- // Step 3: Reinstall/upgrade all dependencies
75
- await check('Upgrade all dependencies', shell.stdout('npm update --save'));
26
+ const shell = new Shell(directory);
27
+ await check('Remove lock file and node_modules', shell.stdout('rm -f package-lock.json && rm -rf node_modules'));
28
+ await check('Reinstall all dependencies', shell.stdout('npm i'));
76
29
  // Final log message
77
30
  info('All dependencies are up to date');
78
31
  }
79
- /**
80
- * Compares two semantic version strings (major.minor.patch) and checks if `a` is greater than `b`.
81
- *
82
- * @param a - A semantic version string (e.g., "1.2.3").
83
- * @param b - Another semantic version string (e.g., "1.2.4").
84
- * @returns `true` if `a` is greater than `b`, otherwise `false`.
85
- * @throws If either version string is invalid (i.e., not in "x.x.x" format).
86
- */
87
- function isGreaterSemver(a, b) {
88
- const pa = a.split('.');
89
- const pb = b.split('.');
90
- for (let i = 0; i < 3; i++) {
91
- const na = Number(pa[i]);
92
- const nb = Number(pb[i]);
93
- if (isNaN(na))
94
- throw new Error('Invalid version number: ' + a);
95
- if (isNaN(nb))
96
- throw new Error('Invalid version number: ' + b);
97
- if (na > nb)
98
- return true;
99
- if (na < nb)
100
- return false;
101
- }
102
- return false;
103
- }
104
32
  //# sourceMappingURL=deps-upgrade.js.map
@@ -39,7 +39,7 @@ async function getCommandResults(command) {
39
39
  FORCE_COLOR: '0'
40
40
  };
41
41
  // Spawn a child process to run the command with the '--help' flag.
42
- const childProcess = cp.spawn('npx', [...command.split(' '), '--help'], { env });
42
+ const childProcess = cp.spawn('npm', ['--offline', 'exec', '--', ...command.split(' '), '--help'], { env });
43
43
  let output = '';
44
44
  // Collect output data from the process.
45
45
  childProcess.stdout.on('data', data => output += String(data));
@@ -2,11 +2,11 @@
2
2
  import { readFileSync, writeFileSync } from 'fs';
3
3
  import select from '@inquirer/select';
4
4
  import { check, info, panic, warn } from '../lib/log.js';
5
- import { getShell } from '../lib/shell.js';
5
+ import { Shell } from '../lib/shell.js';
6
6
  import { getGit } from '../lib/git.js';
7
7
  import { resolve } from 'path';
8
8
  export async function release(directory, branch = 'main') {
9
- const shell = getShell(directory);
9
+ const shell = new Shell(directory);
10
10
  const { getCommitsBetween, getCurrentGitHubCommit, getLastGitHubTag } = getGit(directory);
11
11
  info('starting release process');
12
12
  // git: check if in the correct branch
@@ -48,7 +48,7 @@ export async function release(directory, branch = 'main') {
48
48
  const releaseNotes = await check('prepare release notes', getReleaseNotes(nextVersion, shaLast, shaCurrent));
49
49
  if (!('private' in pkg) || !pkg.private) {
50
50
  // npm publish
51
- await check('npm publish', shell.run('npm publish --access public'));
51
+ await check('npm publish', shell.runInteractive('npm publish --access public'));
52
52
  }
53
53
  // git push
54
54
  await check('git add', shell.run('git add .'));
package/dist/lib/git.js CHANGED
@@ -1,6 +1,6 @@
1
- import { getShell } from './shell.js';
1
+ import { Shell } from './shell.js';
2
2
  export function getGit(cwd) {
3
- const shell = getShell(cwd);
3
+ const shell = new Shell(cwd);
4
4
  return {
5
5
  getLastGitHubTag,
6
6
  getCurrentGitHubCommit,
@@ -1,12 +1,17 @@
1
- export interface Shell {
2
- run: (command: string, errorOnCodeNonZero?: boolean) => Promise<{
1
+ export declare class Shell {
2
+ private cwd;
3
+ constructor(cwd: string);
4
+ run(command: string, errorOnCodeNonZero?: boolean): Promise<{
3
5
  code: number | null;
4
6
  signal: string | null;
5
7
  stdout: string;
6
8
  stderr: string;
7
9
  }>;
8
- stderr: (command: string, errorOnCodeZero?: boolean) => Promise<string>;
9
- stdout: (command: string, errorOnCodeZero?: boolean) => Promise<string>;
10
- ok: (command: string) => Promise<boolean>;
10
+ runInteractive(command: string, errorOnCodeNonZero?: boolean): Promise<{
11
+ code: number | null;
12
+ signal: string | null;
13
+ }>;
14
+ stderr(command: string, errorOnCodeZero?: boolean): Promise<string>;
15
+ stdout(command: string, errorOnCodeZero?: boolean): Promise<string>;
16
+ ok(command: string): Promise<boolean>;
11
17
  }
12
- export declare function getShell(cwd: string): Shell;
package/dist/lib/shell.js CHANGED
@@ -1,14 +1,16 @@
1
1
  import { spawn } from 'child_process';
2
- export function getShell(cwd) {
3
- async function run(command, errorOnCodeNonZero) {
2
+ export class Shell {
3
+ cwd;
4
+ constructor(cwd) {
5
+ this.cwd = cwd;
6
+ }
7
+ async run(command, errorOnCodeNonZero = true) {
4
8
  try {
5
9
  return await new Promise((resolve, reject) => {
6
10
  const stdout = [];
7
11
  const stderr = [];
8
- const cp = spawn('bash', ['-c', command], { cwd })
9
- .on('error', error => {
10
- reject(error);
11
- })
12
+ const cp = spawn('bash', ['-c', command], { cwd: this.cwd })
13
+ .on('error', error => reject(error))
12
14
  .on('close', (code, signal) => {
13
15
  const result = {
14
16
  code,
@@ -16,15 +18,15 @@ export function getShell(cwd) {
16
18
  stdout: Buffer.concat(stdout).toString(),
17
19
  stderr: Buffer.concat(stderr).toString(),
18
20
  };
19
- if ((errorOnCodeNonZero ?? true) && (code !== 0)) {
21
+ if (errorOnCodeNonZero && code !== 0) {
20
22
  reject(result);
21
23
  }
22
24
  else {
23
25
  resolve(result);
24
26
  }
25
27
  });
26
- cp.stdout.on('data', (chunk) => stdout.push(chunk));
27
- cp.stderr.on('data', (chunk) => stderr.push(chunk));
28
+ cp.stdout.on('data', chunk => stdout.push(chunk));
29
+ cp.stderr.on('data', chunk => stderr.push(chunk));
28
30
  });
29
31
  }
30
32
  catch (error) {
@@ -32,11 +34,36 @@ export function getShell(cwd) {
32
34
  throw error;
33
35
  }
34
36
  }
35
- return {
36
- run,
37
- stderr: async (command, errorOnCodeZero) => (await run(command, errorOnCodeZero)).stderr.trim(),
38
- stdout: async (command, errorOnCodeZero) => (await run(command, errorOnCodeZero)).stdout.trim(),
39
- ok: async (command) => (await run(command, false)).code === 0,
40
- };
37
+ // Runs a command interactively, so the user can interact with stdin/stdout/stderr directly.
38
+ async runInteractive(command, errorOnCodeNonZero = true) {
39
+ return await new Promise((resolve, reject) => {
40
+ const cp = spawn('bash', ['-c', command], {
41
+ cwd: this.cwd,
42
+ stdio: 'inherit', // give full TTY passthrough
43
+ });
44
+ cp.on('error', reject);
45
+ cp.on('close', (code, signal) => {
46
+ const result = { code, signal };
47
+ if (errorOnCodeNonZero && code !== 0) {
48
+ reject(result);
49
+ }
50
+ else {
51
+ resolve(result);
52
+ }
53
+ });
54
+ });
55
+ }
56
+ async stderr(command, errorOnCodeZero) {
57
+ const result = await this.run(command, errorOnCodeZero);
58
+ return result.stderr.trim();
59
+ }
60
+ async stdout(command, errorOnCodeZero) {
61
+ const result = await this.run(command, errorOnCodeZero);
62
+ return result.stdout.trim();
63
+ }
64
+ async ok(command) {
65
+ const result = await this.run(command, false);
66
+ return result.code === 0;
67
+ }
41
68
  }
42
69
  //# sourceMappingURL=shell.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@versatiles/release-tool",
3
- "version": "2.4.4",
3
+ "version": "2.5.0",
4
4
  "description": "VersaTiles release and documentation tools",
5
5
  "bin": {
6
6
  "vrt": "./dist/index.js"
@@ -20,8 +20,8 @@
20
20
  "lint": "eslint . --color",
21
21
  "prepack": "npm run build",
22
22
  "release": "tsx src/index.ts release-npm",
23
- "test-coverage": "NODE_OPTIONS=--experimental-vm-modules jest --coverage",
24
- "test": "NODE_OPTIONS=--experimental-vm-modules jest",
23
+ "test-coverage": "vitest --run --coverage",
24
+ "test": "vitest --run",
25
25
  "upgrade": "tsx src/index.ts deps-upgrade"
26
26
  },
27
27
  "author": "Michael Kreil <versatiles@michael-kreil.de>",
@@ -34,24 +34,24 @@
34
34
  "homepage": "https://github.com/versatiles-org/node-release-tool",
35
35
  "devDependencies": {
36
36
  "@schemastore/package": "^0.0.10",
37
- "@types/jest": "^30.0.0",
38
- "@types/node": "^24.7.2",
39
- "@typescript-eslint/eslint-plugin": "^8.46.0",
40
- "@typescript-eslint/parser": "^8.46.0",
41
- "eslint": "^9.37.0",
42
- "jest": "^30.2.0",
43
- "ts-jest": "^29.4.5",
44
- "tsx": "^4.20.6",
37
+ "@types/node": "^24.10.1",
38
+ "@typescript-eslint/eslint-plugin": "^8.48.1",
39
+ "@typescript-eslint/parser": "^8.48.1",
40
+ "@vitest/coverage-v8": "^4.0.15",
41
+ "eslint": "^9.39.1",
42
+ "tsx": "^4.21.0",
45
43
  "typescript": "^5.9.3",
46
- "typescript-eslint": "^8.46.0"
44
+ "typescript-eslint": "^8.48.1",
45
+ "vitest": "^4.0.15"
47
46
  },
48
47
  "dependencies": {
49
- "@inquirer/select": "^4.3.4",
50
- "commander": "^14.0.1",
51
- "dependency-cruiser": "^17.0.2",
48
+ "@inquirer/select": "^5.0.2",
49
+ "commander": "^14.0.2",
50
+ "dependency-cruiser": "^17.3.2",
51
+ "npm-check-updates": "^19.1.2",
52
52
  "remark": "^15.0.1",
53
53
  "remark-gfm": "^4.0.1",
54
- "typedoc": "^0.28.14",
54
+ "typedoc": "^0.28.15",
55
55
  "typedoc-github-theme": "^0.3.1",
56
56
  "typedoc-github-wiki-theme": "^2.1.0",
57
57
  "typedoc-plugin-markdown": "^4.9.0"