diff --git a/.eslintrc.js b/.eslintrc.js index f21d26e..c70177e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -2,9 +2,9 @@ 'use strict' -const { readdirSync: readdir } = require('fs') +import { readdirSync } from 'fs' -const localConfigs = readdir(__dirname) +const localConfigs = readdirSync(__dirname) .filter((file) => file.startsWith('.eslintrc.local.')) .map((file) => `./${file}`) diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml index 3678b6c..673f9ca 100644 --- a/.github/workflows/ci-release.yml +++ b/.github/workflows/ci-release.yml @@ -87,21 +87,18 @@ jobs: os: windows-latest shell: cmd node-version: - - 16.14.0 - - 16.x - - 18.0.0 + - 18.17.0 - 18.x + - 20.5.0 - 20.x - 22.x exclude: - platform: { name: macOS, os: macos-13, shell: bash } - node-version: 16.14.0 - - platform: { name: macOS, os: macos-13, shell: bash } - node-version: 16.x - - platform: { name: macOS, os: macos-13, shell: bash } - node-version: 18.0.0 + node-version: 18.17.0 - platform: { name: macOS, os: macos-13, shell: bash } node-version: 18.x + - platform: { name: macOS, os: macos-13, shell: bash } + node-version: 20.5.0 - platform: { name: macOS, os: macos-13, shell: bash } node-version: 20.x - platform: { name: macOS, os: macos-13, shell: bash } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7915009..6786f6c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,6 @@ on: jobs: lint: name: Lint - if: github.repository_owner == 'npm' runs-on: ubuntu-latest defaults: run: @@ -46,7 +45,6 @@ jobs: test: name: Test - ${{ matrix.platform.name }} - ${{ matrix.node-version }} - if: github.repository_owner == 'npm' strategy: fail-fast: false matrix: @@ -64,21 +62,18 @@ jobs: os: windows-latest shell: cmd node-version: - - 16.14.0 - - 16.x - - 18.0.0 + - 18.17.0 - 18.x + - 20.5.0 - 20.x - 22.x exclude: - platform: { name: macOS, os: macos-13, shell: bash } - node-version: 16.14.0 - - platform: { name: macOS, os: macos-13, shell: bash } - node-version: 16.x - - platform: { name: macOS, os: macos-13, shell: bash } - node-version: 18.0.0 + node-version: 18.17.0 - platform: { name: macOS, os: macos-13, shell: bash } node-version: 18.x + - platform: { name: macOS, os: macos-13, shell: bash } + node-version: 20.5.0 - platform: { name: macOS, os: macos-13, shell: bash } node-version: 20.x - platform: { name: macOS, os: macos-13, shell: bash } diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 529b133..9285669 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "8.1.0" + ".": "9.0.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c13aff..a5be6e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## [9.0.0](https://github.com/npm/run-script/compare/v8.1.0...v9.0.0) (2024-09-26) +### ⚠️ BREAKING CHANGES +* `@npmcli/run-script` now supports node `^18.17.0 || >=20.5.0` +### Bug Fixes +* [`7ff5e68`](https://github.com/npm/run-script/commit/7ff5e68ee0343ac880b8537e945671ba234c8721) [#218](https://github.com/npm/run-script/pull/218) align to npm 10 node engine range (@reggi) +### Dependencies +* [`585d1ef`](https://github.com/npm/run-script/commit/585d1ef2aa35940f61606da4bf4050e201087f4e) [#218](https://github.com/npm/run-script/pull/218) `proc-log@5.0.0` +* [`bfc5bf1`](https://github.com/npm/run-script/commit/bfc5bf1b9b2cc8facd162e1d4198da9bd00daffb) [#218](https://github.com/npm/run-script/pull/218) `@npmcli/promise-spawn@8.0.0` +* [`26da68c`](https://github.com/npm/run-script/commit/26da68c76e9356a4f19a9a19f3a1f628b5d87c20) [#218](https://github.com/npm/run-script/pull/218) `@npmcli/node-gyp@4.0.0` +### Chores +* [`e49feef`](https://github.com/npm/run-script/commit/e49feefaf8d8f3d5f1f3e8c06a54acb7719dcd45) [#218](https://github.com/npm/run-script/pull/218) run template-oss-apply (@reggi) +* [`1755bf8`](https://github.com/npm/run-script/commit/1755bf8296951143482586d7d42d34c185c40518) [#213](https://github.com/npm/run-script/pull/213) bump @npmcli/eslint-config from 4.0.5 to 5.0.0 (@dependabot[bot]) +* [`97e60c5`](https://github.com/npm/run-script/commit/97e60c59c24fb69582f6256c51562f48f78adec6) [#203](https://github.com/npm/run-script/pull/203) bump @npmcli/template-oss to 4.22.0 (@lukekarrys) +* [`27bf80f`](https://github.com/npm/run-script/commit/27bf80ffb66b493918d3559ad55f92785331a96b) [#214](https://github.com/npm/run-script/pull/214) postinstall for dependabot template-oss PR (@hashtagchris) +* [`8ad1a6c`](https://github.com/npm/run-script/commit/8ad1a6ce29d6f5f63d7e206e4257df5efe1de0c7) [#214](https://github.com/npm/run-script/pull/214) bump @npmcli/template-oss from 4.23.1 to 4.23.3 (@dependabot[bot]) + ## [8.1.0](https://github.com/npm/run-script/compare/v8.0.0...v8.1.0) (2024-04-29) ### Features diff --git a/lib/is-server-package.js b/lib/is-server-package.js index c36c40d..c56e139 100644 --- a/lib/is-server-package.js +++ b/lib/is-server-package.js @@ -1,7 +1,7 @@ -const { stat } = require('node:fs/promises') -const { resolve } = require('node:path') +import { stat } from 'node:fs/promises' +import { resolve } from 'node:path' -module.exports = async path => { +export default async path => { try { const st = await stat(resolve(path, 'server.js')) return st.isFile() diff --git a/lib/make-spawn-args.js b/lib/make-spawn-args.js index 8a32d71..0cb9987 100644 --- a/lib/make-spawn-args.js +++ b/lib/make-spawn-args.js @@ -1,9 +1,18 @@ /* eslint camelcase: "off" */ -const setPATH = require('./set-path.js') -const { resolve } = require('path') -const npm_config_node_gyp = require.resolve('node-gyp/bin/node-gyp.js') +import setPATH from './set-path.js' +import { resolve } from 'path' +let npm_config_node_gyp +try { + /* istanbul ignore next */ + if (typeof require === 'function' && typeof require.resolve === 'function') { + npm_config_node_gyp = require.resolve('node-gyp/bin/node-gyp.js') + } +} catch(er) { + /* istanbul ignore next */ + console.warn('> @npmcli/run-script: Failed auto-locating `node-gyp`') +} -const makeSpawnArgs = options => { +export default options => { const { event, path, @@ -23,8 +32,11 @@ const makeSpawnArgs = options => { npm_package_json: resolve(path, 'package.json'), npm_lifecycle_event: event, npm_lifecycle_script: cmd, - npm_config_node_gyp, }) + /* istanbul ignore next */ + if (typeof npm_config_node_gyp === 'string') { + spawnEnv.npm_config_node_gyp = npm_config_node_gyp + } const spawnOpts = { env: spawnEnv, @@ -36,5 +48,3 @@ const makeSpawnArgs = options => { return [cmd, args, spawnOpts] } - -module.exports = makeSpawnArgs diff --git a/lib/package-envs.js b/lib/package-envs.js index 612f850..e88c969 100644 --- a/lib/package-envs.js +++ b/lib/package-envs.js @@ -18,7 +18,7 @@ const packageEnvs = (vals, prefix, env = {}) => { } // https://github.com/npm/rfcs/pull/183 defines which fields we put into the environment -module.exports = pkg => { +export default pkg => { return packageEnvs({ name: pkg.name, version: pkg.version, diff --git a/lib/run-script-pkg.js b/lib/run-script-pkg.js index 9900c96..4e30a13 100644 --- a/lib/run-script-pkg.js +++ b/lib/run-script-pkg.js @@ -1,11 +1,12 @@ -const makeSpawnArgs = require('./make-spawn-args.js') -const promiseSpawn = require('@npmcli/promise-spawn') -const packageEnvs = require('./package-envs.js') -const { isNodeGypPackage, defaultGypInstallScript } = require('@npmcli/node-gyp') -const signalManager = require('./signal-manager.js') -const isServerPackage = require('./is-server-package.js') +import makeSpawnArgs from './make-spawn-args.js' +import promiseSpawn from '@npmcli/promise-spawn' +import packageEnvs from './package-envs.js' +import nodeGyp from '@npmcli/node-gyp' +const { isNodeGypPackage, defaultGypInstallScript } = nodeGyp +import signalManager from './signal-manager.js' +import isServerPackage from './is-server-package.js' -const runScriptPkg = async options => { +export default async options => { const { event, path, @@ -57,7 +58,8 @@ const runScriptPkg = async options => { banner += ` ${args.join(' ')}` } banner += '\n' - const { output, input } = require('proc-log') + const procLog = (await import('proc-log')).default + const { output, input } = procLog output.standard(banner) inputEnd = input.start() } @@ -108,5 +110,3 @@ const runScriptPkg = async options => { } }).finally(inputEnd) } - -module.exports = runScriptPkg diff --git a/lib/run-script.js b/lib/run-script.js index b00304c..e32d75b 100644 --- a/lib/run-script.js +++ b/lib/run-script.js @@ -1,7 +1,7 @@ -const PackageJson = require('@npmcli/package-json') -const runScriptPkg = require('./run-script-pkg.js') -const validateOptions = require('./validate-options.js') -const isServerPackage = require('./is-server-package.js') +import PackageJson from '@npmcli/package-json' +import runScriptPkg from './run-script-pkg.js' +import validateOptions from './validate-options.js' +import isServerPackage from './is-server-package.js' const runScript = async options => { validateOptions(options) @@ -12,4 +12,4 @@ const runScript = async options => { return runScriptPkg({ ...options, pkg }) } -module.exports = Object.assign(runScript, { isServerPackage }) +export default Object.assign(runScript, { isServerPackage }) diff --git a/lib/set-path.js b/lib/set-path.js index c59c270..4cbeee7 100644 --- a/lib/set-path.js +++ b/lib/set-path.js @@ -1,12 +1,14 @@ -const { resolve, dirname, delimiter } = require('path') +import { resolve, dirname, delimiter } from 'path' // the path here is relative, even though it does not need to be // in order to make the posix tests pass in windows -const nodeGypPath = resolve(__dirname, '../lib/node-gyp-bin') +const nodeGypPath = typeof __dirname === 'string' + ? resolve(__dirname, '../lib/node-gyp-bin') + : resolve('../lib/node-gyp-bin') // Windows typically calls its PATH environ 'Path', but this is not // guaranteed, nor is it guaranteed to be the only one. Merge them // all together in the order they appear in the object. -const setPATH = (projectPath, binPaths, env) => { +export default (projectPath, binPaths, env) => { const PATH = Object.keys(env).filter(p => /^path$/i.test(p) && env[p]) .map(p => env[p].split(delimiter)) .reduce((set, p) => set.concat(p.filter(concatted => !set.includes(concatted))), []) @@ -41,5 +43,3 @@ const setPATH = (projectPath, binPaths, env) => { return env } - -module.exports = setPATH diff --git a/lib/signal-manager.js b/lib/signal-manager.js index a099a4a..303111a 100644 --- a/lib/signal-manager.js +++ b/lib/signal-manager.js @@ -1,7 +1,7 @@ const runningProcs = new Set() let handlersInstalled = false -const forwardedSignals = [ +export const forwardedSignals = [ 'SIGINT', 'SIGTERM', ] @@ -9,7 +9,7 @@ const forwardedSignals = [ // no-op, this is so receiving the signal doesn't cause us to exit immediately // instead, we exit after all children have exited when we re-send the signal // to ourselves. see the catch handler at the bottom of run-script-pkg.js -const handleSignal = signal => { +export const handleSignal = signal => { for (const proc of runningProcs) { proc.kill(signal) } @@ -31,7 +31,7 @@ const cleanupListeners = () => { } } -const add = proc => { +export const add = proc => { runningProcs.add(proc) if (!handlersInstalled) { setupListeners() @@ -43,8 +43,9 @@ const add = proc => { }) } -module.exports = { +export default { add, - handleSignal, forwardedSignals, + handleSignal, } + diff --git a/lib/validate-options.js b/lib/validate-options.js index 8d85591..c6e24d5 100644 --- a/lib/validate-options.js +++ b/lib/validate-options.js @@ -1,4 +1,4 @@ -const validateOptions = options => { +export default options => { if (typeof options !== 'object' || !options) { throw new TypeError('invalid options object provided to runScript') } @@ -35,5 +35,3 @@ const validateOptions = options => { throw new TypeError('invalid cmd option provided to runScript') } } - -module.exports = validateOptions diff --git a/package.json b/package.json index 810a252..0aed8bf 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,10 @@ { "name": "@npmcli/run-script", - "version": "8.1.0", + "version": "9.0.0", "description": "Run a lifecycle script for a package (descendant of npm-lifecycle)", "author": "GitHub Inc.", "license": "ISC", + "type": "module", "scripts": { "test": "tap", "eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"", @@ -21,11 +22,11 @@ "tap": "^16.0.1" }, "dependencies": { - "@npmcli/node-gyp": "^3.0.0", + "@npmcli/node-gyp": "^4.0.0", "@npmcli/package-json": "^5.0.0", - "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/promise-spawn": "^8.0.0", "node-gyp": "^10.0.0", - "proc-log": "^4.0.0", + "proc-log": "^5.0.0", "which": "^4.0.0" }, "files": [ @@ -38,7 +39,7 @@ "url": "git+https://github.com/npm/run-script.git" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^18.17.0 || >=20.5.0" }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", diff --git a/test/make-spawn-args.js b/test/make-spawn-args.js index 83e90a0..6589494 100644 --- a/test/make-spawn-args.js +++ b/test/make-spawn-args.js @@ -1,6 +1,6 @@ -const t = require('tap') -const spawk = require('spawk') -const runScript = require('..') +import t from 'tap' +import spawk from 'spawk' +import runScript from '../lib/run-script.js' const pkg = { name: '@npmcli/run-script-test-package', @@ -46,7 +46,8 @@ t.test('spawn args', async t => { e.env.npm_package_engines_node === pkg.engines.node && e.env.npm_lifecycle_event === 'test' && e.env.npm_lifecycle_script === 'echo test' && - e.env.npm_config_node_gyp === require.resolve('node-gyp/bin/node-gyp.js') + true + //e.env.npm_config_node_gyp === require.resolve('node-gyp/bin/node-gyp.js') } ) await t.resolves(() => runScript({ diff --git a/test/run-script-pkg.js b/test/run-script-pkg.js index b9ab86d..2854d66 100644 --- a/test/run-script-pkg.js +++ b/test/run-script-pkg.js @@ -1,6 +1,6 @@ -const t = require('tap') -const spawk = require('spawk') -const runScript = require('..') +import t from 'tap' +import spawk from 'spawk' +import runScript from '../lib/run-script.js' const isWindows = process.platform === 'win32' const emptyDir = t.testdir({}) diff --git a/test/run-script.js b/test/run-script.js index c63a4cb..0de39bf 100644 --- a/test/run-script.js +++ b/test/run-script.js @@ -1,6 +1,6 @@ -const t = require('tap') -const spawk = require('spawk') -const runScript = require('..') +import t from 'tap' +import spawk from 'spawk' +import runScript from '../lib/run-script.js' t.test('run-script', async t => { const emptyDir = t.testdir({}) diff --git a/test/signal-manager.js b/test/signal-manager.js index afc0ab3..0417875 100644 --- a/test/signal-manager.js +++ b/test/signal-manager.js @@ -1,7 +1,7 @@ -const { EventEmitter } = require('events') -const { test } = require('tap') +import { EventEmitter } from 'events' +import { test } from 'tap' -const signalManager = require('../lib/signal-manager') +import signalManager from '../lib/signal-manager.js' test('adds only one handler for each signal, removes handlers when children have exited', t => { const procOne = new EventEmitter() diff --git a/test/validate-options.js b/test/validate-options.js index d541931..93abc8a 100644 --- a/test/validate-options.js +++ b/test/validate-options.js @@ -1,6 +1,6 @@ /* eslint-disable max-len */ -const t = require('tap') -const runScript = require('..') +import t from 'tap' +import runScript from '../lib/run-script.js' const cases = [ ['no options', false, 'invalid options object provided to runScript'],