Skip to content

Commit c1c9718

Browse files
committed
Add dependency check for file action import failures
1 parent 511233b commit c1c9718

File tree

2 files changed

+58
-8
lines changed

2 files changed

+58
-8
lines changed

v-next/core/src/internal/tasks/resolved-task.ts

+22-5
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,14 @@ import type {
1111
TaskParameter,
1212
} from "../../types/tasks.js";
1313

14-
import { HardhatError } from "@nomicfoundation/hardhat-errors";
14+
import {
15+
HardhatError,
16+
assertHardhatInvariant,
17+
} from "@nomicfoundation/hardhat-errors";
1518
import { ensureError } from "@nomicfoundation/hardhat-utils/error";
1619

1720
import { isParameterValueValid } from "../parameters.js";
21+
import { detectPluginNpmDependencyProblems } from "../plugins/detect-plugin-npm-dependency-problems.js";
1822

1923
import { formatTaskId } from "./utils.js";
2024

@@ -130,7 +134,7 @@ export class ResolvedTask implements Task {
130134
const actionFn =
131135
typeof currentAction === "function"
132136
? currentAction
133-
: await this.#resolveFileAction(currentAction, this.id);
137+
: await this.#resolveFileAction(currentAction);
134138

135139
if (currentIndex === 0) {
136140
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions --
@@ -237,18 +241,31 @@ export class ResolvedTask implements Task {
237241
*/
238242
async #resolveFileAction(
239243
actionFileUrl: string,
240-
taskId: string[],
241244
): Promise<NewTaskActionFunction | TaskOverrideActionFunction> {
242245
let resolvedActionFn;
243246
try {
244247
resolvedActionFn = await import(actionFileUrl);
245248
} catch (error) {
246249
ensureError(error);
250+
251+
if (this.pluginId !== undefined) {
252+
const plugin = this.#hre.config.plugins.find(
253+
(p) => p.id === this.pluginId,
254+
);
255+
256+
assertHardhatInvariant(
257+
plugin !== undefined,
258+
`Plugin with id ${this.pluginId} not found.`,
259+
);
260+
261+
await detectPluginNpmDependencyProblems(plugin);
262+
}
263+
247264
throw new HardhatError(
248265
HardhatError.ERRORS.TASK_DEFINITIONS.INVALID_ACTION_URL,
249266
{
250267
action: actionFileUrl,
251-
task: formatTaskId(taskId),
268+
task: formatTaskId(this.id),
252269
},
253270
error,
254271
);
@@ -259,7 +276,7 @@ export class ResolvedTask implements Task {
259276
HardhatError.ERRORS.TASK_DEFINITIONS.INVALID_ACTION,
260277
{
261278
action: actionFileUrl,
262-
task: formatTaskId(taskId),
279+
task: formatTaskId(this.id),
263280
},
264281
);
265282
}

v-next/core/test/internal/tasks/task-manager.ts

+36-3
Original file line numberDiff line numberDiff line change
@@ -1493,7 +1493,7 @@ describe("TaskManagerImplementation", () => {
14931493
);
14941494
});
14951495

1496-
it("should throw if an action url is provided and the module can't be resolved", async () => {
1496+
it("should throw if an action url is provided but the corresponding module can't be resolved", async () => {
14971497
const hre = await createHardhatRuntimeEnvironment({
14981498
plugins: [
14991499
{
@@ -1520,7 +1520,40 @@ describe("TaskManagerImplementation", () => {
15201520
);
15211521
});
15221522

1523-
it("should throw if an action url is provided and the module doesn't have a default export", async () => {
1523+
/**
1524+
* There are multiple scenarios where detectPluginNpmDependencyProblems
1525+
* can throw an error. We're not trying to test all of them, just verify
1526+
* that the logic is being called and that the error is being thrown.
1527+
*/
1528+
it("should throw if an action url is provided but the corresponding module can't be resolved due to a missing package", async () => {
1529+
const nonInstalledPackageActionUrl = import.meta.resolve(
1530+
"./fixture-projects/not-installed-package/index.js",
1531+
);
1532+
1533+
const hre = await createHardhatRuntimeEnvironment({
1534+
plugins: [
1535+
{
1536+
id: "plugin1",
1537+
npmPackage: "non-installed-package",
1538+
tasks: [
1539+
new NewTaskDefinitionBuilderImplementation("task1")
1540+
.setAction(nonInstalledPackageActionUrl)
1541+
.build(),
1542+
],
1543+
},
1544+
],
1545+
});
1546+
1547+
const task1 = hre.tasks.getTask("task1");
1548+
await assert.rejects(
1549+
task1.run({}),
1550+
new HardhatError(HardhatError.ERRORS.PLUGINS.PLUGIN_NOT_INSTALLED, {
1551+
pluginId: "plugin1",
1552+
}),
1553+
);
1554+
});
1555+
1556+
it("should throw if an action url is provided and the corresponding module doesn't have a default export", async () => {
15241557
const actionUrl = import.meta.resolve(
15251558
"./fixture-projects/file-actions/no-default.js",
15261559
);
@@ -1551,7 +1584,7 @@ describe("TaskManagerImplementation", () => {
15511584
);
15521585
});
15531586

1554-
it("should throw if an action url is provided and the module default export is not a function", async () => {
1587+
it("should throw if an action url is provided and the corresponding module default export is not a function", async () => {
15551588
const actionUrl = import.meta.resolve(
15561589
"./fixture-projects/file-actions/no-default-fn.js",
15571590
);

0 commit comments

Comments
 (0)