Skip to content

Commit a6e5c7e

Browse files
committed
feat(plugins): import and remove hooks
added hooks for plugins after they have been imported and before they are removed. closes #6896 Signed-off-by: Hellgren Heikki <[email protected]>
1 parent e22562a commit a6e5c7e

File tree

8 files changed

+86
-19
lines changed

8 files changed

+86
-19
lines changed

.yarn/versions/71a206d9.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
releases:
2+
"@yarnpkg/core": patch
3+
"@yarnpkg/plugin-essentials": patch
4+
5+
declined:
6+
- "@yarnpkg/plugin-compat"
7+
- "@yarnpkg/plugin-constraints"
8+
- "@yarnpkg/plugin-dlx"
9+
- "@yarnpkg/plugin-exec"
10+
- "@yarnpkg/plugin-file"
11+
- "@yarnpkg/plugin-git"
12+
- "@yarnpkg/plugin-github"
13+
- "@yarnpkg/plugin-http"
14+
- "@yarnpkg/plugin-init"
15+
- "@yarnpkg/plugin-interactive-tools"
16+
- "@yarnpkg/plugin-jsr"
17+
- "@yarnpkg/plugin-link"
18+
- "@yarnpkg/plugin-nm"
19+
- "@yarnpkg/plugin-npm"
20+
- "@yarnpkg/plugin-npm-cli"
21+
- "@yarnpkg/plugin-pack"
22+
- "@yarnpkg/plugin-patch"
23+
- "@yarnpkg/plugin-pnp"
24+
- "@yarnpkg/plugin-pnpm"
25+
- "@yarnpkg/plugin-stage"
26+
- "@yarnpkg/plugin-typescript"
27+
- "@yarnpkg/plugin-version"
28+
- "@yarnpkg/plugin-workspace-tools"
29+
- "@yarnpkg/builder"
30+
- "@yarnpkg/cli"
31+
- "@yarnpkg/doctor"
32+
- "@yarnpkg/extensions"
33+
- "@yarnpkg/nm"
34+
- "@yarnpkg/pnpify"
35+
- "@yarnpkg/sdks"

packages/acceptance-tests/pkg-tests-specs/sources/commands/plugin/import.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ describe(`Commands`, () => {
4747

4848
await run(`plugin`, `import`, pluginUrl);
4949

50+
// Check for post import script output
51+
await expect(xfs.existsPromise(ppath.join(path, `post_import.txt`))).resolves.toEqual(true);
52+
5053
await expect(xfs.existsPromise(ppath.join(path, mockPluginPath))).resolves.toEqual(true);
5154
await expect(fs.readSyml(ppath.join(path, Filename.rc))).resolves.toEqual({
5255
httpsCaFilePath,

packages/acceptance-tests/pkg-tests-specs/sources/commands/plugin/remove.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ describe(`Commands`, () => {
3333
await run(`plugin`, `remove`, `@yarnpkg/plugin-hello-world`);
3434

3535
await expect(xfs.existsPromise(helloWorldPlugin)).resolves.toEqual(false);
36+
// Check for pre remove script output
37+
await expect(xfs.existsPromise(ppath.join(path, `pre_remove.txt`))).resolves.toEqual(true);
38+
3639
await expect(fs.readSyml(ppath.join(path, Filename.rc))).resolves.toEqual({
3740
plugins: [{
3841
path: ppath.relative(path, helloUniversePlugin),

packages/plugin-essentials/sources/commands/plugin/import.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import {BaseCommand} from '@yarnpkg/cli';
2-
import {PluginMeta} from '@yarnpkg/core/sources/Plugin';
2+
import {Hooks, PluginMeta} from '@yarnpkg/core/sources/Plugin';
33
import {Configuration, MessageName, Project, ReportError, StreamReport, Report} from '@yarnpkg/core';
44
import {YarnVersion, formatUtils, httpUtils, structUtils, hashUtils} from '@yarnpkg/core';
55
import {PortablePath, npath, ppath, xfs} from '@yarnpkg/fslib';
66
import {Command, Option, Usage} from 'clipanion';
7+
import * as console from 'node:console';
78
import semver from 'semver';
89
import {runInNewContext} from 'vm';
910

@@ -54,13 +55,12 @@ export default class PluginImportCommand extends BaseCommand {
5455

5556
async execute() {
5657
const configuration = await Configuration.find(this.context.cwd, this.context.plugins);
58+
const {project} = await Project.find(configuration, this.context.cwd);
5759

5860
const report = await StreamReport.start({
5961
configuration,
6062
stdout: this.context.stdout,
6163
}, async report => {
62-
const {project} = await Project.find(configuration, this.context.cwd);
63-
6464
let pluginSpec: string;
6565
let pluginBuffer: Buffer;
6666
if (this.name.match(/^\.{0,2}[\\/]/) || npath.isAbsolute(this.name)) {
@@ -116,6 +116,8 @@ export default class PluginImportCommand extends BaseCommand {
116116
await savePlugin(pluginSpec, pluginBuffer, {checksum: this.checksum, project, report});
117117
});
118118

119+
await configuration.triggerHook((hooks: Hooks) => hooks.pluginPostImport, project);
120+
119121
return report.exitCode();
120122
}
121123
}

packages/plugin-essentials/sources/commands/plugin/import/sources.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
import {BaseCommand} from '@yarnpkg/cli';
2-
import {structUtils, hashUtils, Report, CommandContext, YarnVersion} from '@yarnpkg/core';
3-
import {Configuration, MessageName, Project, ReportError, StreamReport} from '@yarnpkg/core';
4-
import {PortablePath, npath, ppath, xfs, Filename} from '@yarnpkg/fslib';
5-
import {Command, Option, Usage} from 'clipanion';
6-
import {tmpdir} from 'os';
1+
import {BaseCommand} from '@yarnpkg/cli';
2+
import {structUtils, hashUtils, Report, CommandContext, YarnVersion, Hooks} from '@yarnpkg/core';
3+
import {Configuration, MessageName, Project, ReportError, StreamReport} from '@yarnpkg/core';
4+
import {PortablePath, npath, ppath, xfs, Filename} from '@yarnpkg/fslib';
5+
import {Command, Option, Usage} from 'clipanion';
6+
import {tmpdir} from 'os';
77

8-
import {prepareRepo, runWorkflow} from '../../set/version/sources';
9-
import {savePlugin} from '../import';
10-
import {getAvailablePlugins} from '../list';
8+
import {prepareRepo, runWorkflow} from '../../set/version/sources';
9+
import {savePlugin} from '../import';
10+
import {getAvailablePlugins} from '../list';
1111

1212
const buildWorkflow = ({pluginName, noMinify}: {noMinify: boolean, pluginName: string}, target: PortablePath) => [
1313
[`yarn`, `build:${pluginName}`, ...noMinify ? [`--no-minify`] : [], `|`],
@@ -60,7 +60,7 @@ export default class PluginImportSourcesCommand extends BaseCommand {
6060

6161
async execute() {
6262
const configuration = await Configuration.find(this.context.cwd, this.context.plugins);
63-
63+
const {project} = await Project.find(configuration, this.context.cwd);
6464
const target = typeof this.installPath !== `undefined`
6565
? ppath.resolve(this.context.cwd, npath.toPortablePath(this.installPath))
6666
: ppath.resolve(npath.toPortablePath(tmpdir()), `yarnpkg-sources`, hashUtils.makeHash(this.repository).slice(0, 6) as Filename);
@@ -69,8 +69,6 @@ export default class PluginImportSourcesCommand extends BaseCommand {
6969
configuration,
7070
stdout: this.context.stdout,
7171
}, async report => {
72-
const {project} = await Project.find(configuration, this.context.cwd);
73-
7472
const ident = structUtils.parseIdent(this.name.replace(/^((@yarnpkg\/)?plugin-)?/, `@yarnpkg/plugin-`));
7573
const identStr = structUtils.stringifyIdent(ident);
7674
const data = await getAvailablePlugins(configuration, YarnVersion);
@@ -85,6 +83,8 @@ export default class PluginImportSourcesCommand extends BaseCommand {
8583
await buildAndSavePlugin(pluginSpec, this, {project, report, target});
8684
});
8785

86+
await configuration.triggerHook((hooks: Hooks) => hooks.pluginPostImport, project);
87+
8888
return report.exitCode();
8989
}
9090
}

packages/plugin-essentials/sources/commands/plugin/remove.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import {BaseCommand} from '@yarnpkg/cli';
2-
import {Configuration, MessageName, Project, StreamReport, formatUtils, structUtils} from '@yarnpkg/core';
3-
import {PortablePath, ppath, xfs} from '@yarnpkg/fslib';
4-
import {Command, Option, Usage, UsageError} from 'clipanion';
1+
import {BaseCommand} from '@yarnpkg/cli';
2+
import {Configuration, MessageName, Project, StreamReport, formatUtils, structUtils, Hooks} from '@yarnpkg/core';
3+
import {PortablePath, ppath, xfs} from '@yarnpkg/fslib';
4+
import {Command, Option, Usage, UsageError} from 'clipanion';
55

66
// eslint-disable-next-line arca/no-default-export
77
export default class PluginRemoveCommand extends BaseCommand {
@@ -32,6 +32,8 @@ export default class PluginRemoveCommand extends BaseCommand {
3232
const configuration = await Configuration.find(this.context.cwd, this.context.plugins);
3333
const {project} = await Project.find(configuration, this.context.cwd);
3434

35+
await configuration.triggerHook((hooks: Hooks) => hooks.pluginPreRemove, project);
36+
3537
const report = await StreamReport.start({
3638
configuration,
3739
stdout: this.context.stdout,

packages/yarnpkg-core/sources/Plugin.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,16 @@ export interface Hooks {
182182
cleanGlobalArtifacts?: (
183183
configuration: Configuration,
184184
) => Promise<void>;
185+
186+
/**
187+
* Called after the plugin has been imported.
188+
*/
189+
pluginPostImport?: (project: Project) => Promise<void>;
190+
191+
/**
192+
* Called before the plugin gets removed from the project.
193+
*/
194+
pluginPreRemove?: (project: Project) => Promise<void>;
185195
}
186196

187197
export type Plugin<PluginHooks = any> = {

scripts/plugin-hello-world.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,18 @@ module.exports = {
3535
commands: [
3636
HelloWorldCommand,
3737
],
38+
hooks: {
39+
pluginPostImport: project => {
40+
const {xfs, ppath} = require(`@yarnpkg/fslib`);
41+
const path = ppath.join(project.cwd, `post_import.txt`);
42+
xfs.writeFileSync(path, `Hello, World!`);
43+
},
44+
pluginPreRemove: project => {
45+
const {xfs, ppath} = require(`@yarnpkg/fslib`);
46+
const path = ppath.join(project.cwd, `pre_remove.txt`);
47+
xfs.writeFileSync(path, `Goodbye, World!`);
48+
},
49+
},
3850
};
3951
},
4052
};

0 commit comments

Comments
 (0)