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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Load hardhat.config.cjs to partially support ESM projects #3155

Merged
merged 7 commits into from
Sep 13, 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
7 changes: 7 additions & 0 deletions packages/hardhat-core/src/internal/core/project-structure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ import { getPackageRoot } from "../util/packageInfo";
import { HardhatError } from "./errors";
import { ERRORS } from "./errors-list";
const JS_CONFIG_FILENAME = "hardhat.config.js";
const CJS_CONFIG_FILENAME = "hardhat.config.cjs";
const TS_CONFIG_FILENAME = "hardhat.config.ts";
const CTS_CONFIG_FILENAME = "hardhat.config.cts";

export function isCwdInsideProject() {
return (
findUp.sync(TS_CONFIG_FILENAME) !== null ||
findUp.sync(CJS_CONFIG_FILENAME) !== null ||
findUp.sync(JS_CONFIG_FILENAME) !== null
);
}
Expand All @@ -28,6 +30,11 @@ export function getUserConfigPath() {
return tsConfigPath;
}

const cjsConfigPath = findUp.sync(CJS_CONFIG_FILENAME);
if (cjsConfigPath !== null) {
return cjsConfigPath;
}

const pathToConfigFile = findUp.sync(JS_CONFIG_FILENAME);
if (pathToConfigFile === null) {
throw new HardhatError(ERRORS.GENERAL.NOT_INSIDE_PROJECT);
Expand Down
88 changes: 87 additions & 1 deletion packages/hardhat-core/test/builtin-tasks/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { useEnvironment } from "../helpers/environment";
import { expectHardhatErrorAsync } from "../helpers/errors";
import { useFixtureProject } from "../helpers/project";

describe("run task", function () {
describe("run task (CJS)", function () {
useFixtureProject("project-with-scripts");
useEnvironment();

Expand Down Expand Up @@ -93,3 +93,89 @@ describe("run task", function () {
(process as any).exitCode = undefined;
});
});

describe("run task (ESM)", function () {
useFixtureProject("esm-project-with-scripts");
useEnvironment();

it("Should fail if a script doesn't exist", async function () {
await expectHardhatErrorAsync(
() =>
this.env.run("run", { script: "./does-not-exist", noCompile: true }),
ERRORS.BUILTIN_TASKS.RUN_FILE_NOT_FOUND
);
});

it("Should run the scripts to completion", async function () {
await this.env.run("run", {
script: "./async-script.js",
noCompile: true,
});

assert.equal(process.exitCode, 0);
(process as any).exitCode = undefined;
});

it("Should compile before running", async function () {
if (await fsExtra.pathExists("cache")) {
await fsExtra.remove("cache");
}

if (await fsExtra.pathExists("artifacts")) {
await fsExtra.remove("artifacts");
}

await this.env.run("run", {
script: "./successful-script.js",
});
assert.equal(process.exitCode, 0);
(process as any).exitCode = undefined;

const artifacts = new Artifacts(path.join(process.cwd(), "artifacts"));
const files = await artifacts.getArtifactPaths();
const expectedFile = path.join(
process.cwd(),
"artifacts/contracts/a.sol/A.json"
);
assert.sameMembers(files, [expectedFile]);

await fsExtra.remove("artifacts");
});

it("Shouldn't compile if asked not to", async function () {
if (await fsExtra.pathExists("cache")) {
await fsExtra.remove("cache");
}

if (await fsExtra.pathExists("artifacts")) {
await fsExtra.remove("artifacts");
}

await this.env.run("run", {
script: "./successful-script.js",
noCompile: true,
});
assert.equal(process.exitCode, 0);
(process as any).exitCode = undefined;

assert.isFalse(await fsExtra.pathExists("artifacts"));
});

it("Should return the script's status code on success", async function () {
await this.env.run("run", {
script: "./successful-script.js",
noCompile: true,
});
assert.equal(process.exitCode, 0);
(process as any).exitCode = undefined;
});

it("Should return the script's status code on failure", async function () {
await this.env.run("run", {
script: "./failing-script.js",
noCompile: true,
});
assert.notEqual(process.exitCode, 0);
(process as any).exitCode = undefined;
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/cache
/artifacts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import * as process from "process";

if (hardhatArguments.network !== "custom") {
process.exit(1);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as process from "process";

setTimeout(() => {
if (global.config === undefined || global.config.solidity === undefined) {
process.exit(123);
}
}, 100);
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
contract A {}

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import * as process from "process";

if (process.env.TEST_ENV_VAR !== "test") {
process.exit(123);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import * as process from "process";

process.exit(123);
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
solidity: "0.5.15",
networks: {
custom: {
url: "asd",
},
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"type": "module"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import * as process from "process";

if (
process.argv.length !== 5 ||
process.argv[2] !== "a" ||
process.argv[3] !== "b" ||
process.argv[4] !== "c"
) {
process.exit(12);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import * as process from "process";

if (global.config === undefined || global.config.solidity === undefined) {
process.exit(123123);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
task("example2", "example task", async (ret) => 28);

task("example", "example task", async (__, { run }) => run("example2"));

module.exports = {
defaultNetwork: "custom",
networks: {
custom: {
url: "http://127.0.0.1:8545",
},
localhost: {
accounts: [
"0xa95f9e3e7ae4e4865c5968828fe7c03fffa8a9f3bb52d36d26243f4c868ee166",
],
},
},
solidity: "0.5.15",
unknown: {
asd: 123,
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"type": "module"
}
12 changes: 12 additions & 0 deletions packages/hardhat-core/test/internal/core/config/config-loading.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ describe("config loading", function () {
});
});

describe("can load CJS config path inside an esm project", function () {
useFixtureProject("esm-project");
useEnvironment();

it("should load the default config if none is given", function () {
assert.isDefined(this.env.config.networks.localhost);
assert.deepEqual(this.env.config.networks.localhost.accounts, [
"0xa95f9e3e7ae4e4865c5968828fe7c03fffa8a9f3bb52d36d26243f4c868ee166",
]);
});
});

describe("Config validation", function () {
describe("When the config is invalid", function () {
useFixtureProject("invalid-config");
Expand Down
25 changes: 25 additions & 0 deletions packages/hardhat-core/test/internal/core/project-structure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,31 @@ describe("project structure", () => {
});
});
});

describe("Inside an ESM project", () => {
useFixtureProject("esm-project");
let configPath: string;

before("get root path", async () => {
// TODO: This is no longer needed once PR #71 gets merged
const pathToFixtureRoot = await getRealPath(
path.join(__dirname, "..", "..", "fixture-projects", "esm-project")
);

configPath = await getRealPath(
path.join(pathToFixtureRoot, "hardhat.config.cjs")
);
});

it("should work from the project root", () => {
assert.equal(getUserConfigPath(), configPath);
});

it("should work from deeper inside the project", () => {
process.chdir("contracts");
assert.equal(getUserConfigPath(), configPath);
});
});
});

describe("getRecommendedGitIgnore", () => {
Expand Down
87 changes: 86 additions & 1 deletion packages/hardhat-core/test/internal/util/scripts-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
import { useEnvironment } from "../../helpers/environment";
import { useFixtureProject } from "../../helpers/project";

describe("Scripts runner", function () {
describe("Scripts runner (CJS)", function () {
useFixtureProject("project-with-scripts");

it("Should pass params to the script", async function () {
Expand Down Expand Up @@ -91,3 +91,88 @@ describe("Scripts runner", function () {
});
});
});

describe("Scripts runner (ESM)", function () {
useFixtureProject("esm-project-with-scripts");

it("Should pass params to the script", async function () {
const [statusCodeWithScriptParams, statusCodeWithNoParams] =
await Promise.all([
runScript("./params-script.js", ["a", "b", "c"]),
runScript("./params-script.js"),
]);

assert.equal(statusCodeWithScriptParams, 0);

// We check here that the script is correctly testing this:
assert.notEqual(statusCodeWithNoParams, 0);
});

it("Should run the script to completion", async function () {
const before = new Date();
const status = await runScript("./async-script.js");
assert.equal(status, 123);
const after = new Date();

assert.isAtLeast(after.getTime() - before.getTime(), 100);
});

it("Should resolve to the status code of the script run", async function () {
assert.deepEqual(await runScript("./failing-script.js"), 123);
});

it("Should pass env variables to the script", async function () {
const [statusCodeWithEnvVars, statusCodeWithNoEnvArgs] = await Promise.all([
runScript("./env-var-script.js", [], [], {
TEST_ENV_VAR: "test",
}),
runScript("./env-var-script.js"),
]);

assert.equal(
statusCodeWithEnvVars,
0,
"Status code with env vars should be 0"
);

assert.notEqual(
statusCodeWithNoEnvArgs,
0,
"Status code with no env vars should not be 0"
);
});

describe("runWithHardhat", function () {
useEnvironment();

it("Should load hardhat/register successfully", async function () {
const [statusCodeWithHardhat, statusCodeWithoutHardhat] =
await Promise.all([
runScriptWithHardhat(
this.env.hardhatArguments,
"./successful-script.js"
),
runScript("./successful-script.js"),
]);

assert.equal(statusCodeWithHardhat, 0);

// We check here that the script is correctly testing this:
assert.notEqual(statusCodeWithoutHardhat, 0);
});

it("Should forward all the hardhat arguments", async function () {
// This is only for testing purposes, as we can't set a hardhat argument
// as the CLA does, and env variables always get forwarded to child
// processes
this.env.hardhatArguments.network = "custom";

const statusCode = await runScriptWithHardhat(
this.env.hardhatArguments,
"./assert-hardhat-arguments.js"
);

assert.equal(statusCode, 0);
});
});
});