Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(arborist): add support for dependencies script #5094

Merged
merged 1 commit into from Jul 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 25 additions & 0 deletions workspaces/arborist/lib/arborist/reify.js
Expand Up @@ -22,6 +22,7 @@ const moveFile = require('@npmcli/move-file')
const rimraf = promisify(require('rimraf'))
const PackageJson = require('@npmcli/package-json')
const packageContents = require('@npmcli/installed-package-contents')
const runScript = require('@npmcli/run-script')
const { checkEngine, checkPlatform } = require('npm-install-checks')
const _force = Symbol.for('force')

Expand Down Expand Up @@ -1516,6 +1517,30 @@ module.exports = cls => class Reifier extends cls {

if (!this[_global]) {
await this.actualTree.meta.save()
const ignoreScripts = !!this.options.ignoreScripts
// if we aren't doing a dry run or ignoring scripts and we actually made changes to the dep
// tree, then run the dependencies scripts
if (!this[_dryRun] && !ignoreScripts && this.diff && this.diff.children.length) {
const { path, package: pkg } = this.actualTree.target
const stdio = this.options.foregroundScripts ? 'inherit' : 'pipe'
const { scripts = {} } = pkg
for (const event of ['predependencies', 'dependencies', 'postdependencies']) {
if (Object.prototype.hasOwnProperty.call(scripts, event)) {
const timer = `reify:run:${event}`
process.emit('time', timer)
log.info('run', pkg._id, event, scripts[event])
await runScript({
event,
path,
pkg,
stdioString: true,
stdio,
scriptShell: this.options.scriptShell,
})
process.emit('timeEnd', timer)
}
}
}
}
}
}
58 changes: 57 additions & 1 deletion workspaces/arborist/test/arborist/reify.js
@@ -1,4 +1,4 @@
const { resolve, basename } = require('path')
const { join, resolve, basename } = require('path')
const t = require('tap')
const runScript = require('@npmcli/run-script')
const localeCompare = require('@isaacs/string-locale-compare')('en')
Expand Down Expand Up @@ -2467,6 +2467,62 @@ t.test('add local dep with existing dev + peer/optional', async t => {
t.equal(tree.children.size, 1, 'children')
})

t.test('runs dependencies script if tree changes', async (t) => {
const path = t.testdir({
'package.json': JSON.stringify({
name: 'root',
version: '1.0.0',
dependencies: {
abbrev: '^1.1.1',
},
scripts: {
predependencies: `node -e "require('fs').writeFileSync('ran-predependencies', '')"`,
dependencies: `node -e "require('fs').writeFileSync('ran-dependencies', '')"`,
postdependencies: `node -e "require('fs').writeFileSync('ran-postdependencies', '')"`,
},
}),
})

await reify(path)

for (const script of ['predependencies', 'dependencies', 'postdependencies']) {
const expectedPath = join(path, `ran-${script}`)
t.ok(fs.existsSync(expectedPath), `ran ${script}`)
// delete the files after we assert they exist
fs.unlinkSync(expectedPath)
}

// reify again without changing dependencies
await reify(path)

for (const script of ['predependencies', 'dependencies', 'postdependencies']) {
const expectedPath = join(path, `ran-${script}`)
// and this time we assert that they do _not_ exist
t.not(fs.existsSync(expectedPath), `did not run ${script}`)
}

// take over console.log as run-script is going to print a banner for these because
// they're running in the foreground
const _log = console.log
t.teardown(() => {
console.log = _log
})
const logs = []
console.log = (msg) => logs.push(msg)
// reify again, this time adding a new dependency
await reify(path, { foregroundScripts: true, add: ['once@^1.4.0'] })
console.log = _log

t.match(logs, [/predependencies/, /dependencies/, /postdependencies/], 'logged banners')

// files should exist again
for (const script of ['predependencies', 'dependencies', 'postdependencies']) {
const expectedPath = join(path, `ran-${script}`)
t.ok(fs.existsSync(expectedPath), `ran ${script}`)
fs.unlinkSync(expectedPath)
}
})

t.test('save package.json on update', t => {
t.test('should save many deps in multiple package.json when using save=true', async t => {
const path = fixture(t, 'workspaces-need-update')
Expand Down