Open wighawag opened 4 years ago
Actually, ideally, if they could be any type, it would be even better.
Can you tell us more about what you are trying to do?
I basically want user to set multiple path for artifact and deployments, see : https://github.com/wighawag/buidler-deploy/issues/34
So instead of having the following in buidler.config.js
paths: {
imports: ["node_modules/@cartesi/arbitration/build/contracts"],
externalDeployments: {
rinkeby: ["node_modules/@cartesi/arbitration/build/contracts"],
}
}
I need to add the paths to a different field:
external: {
artifacts: ["node_modules/@cartesi/arbitration/build/contracts"],
deployments: {
rinkeby: ["node_modules/@cartesi/arbitration/build/contracts"],
},
},
Actually thinking about it the deployments object could be set on the network config, like that
networks: {
extraDeployments: ["node_modules/@cartesi/arbitration/build/contracts"]
},
But this is just an example. Basically there are use case where paths need to be arrays and potentially objects. buidler type system allows for it, but this fails at runtime.
Can you share the stack trace where it fails at runtime? If I'm understanding correctly, this shouldn't happen (I mean, fields other than the "predefined" ones shouldn't be used in any way.)
i forgot what was the exact error, I ll see if I can get it again, but looking at the code here : https://github.com/nomiclabs/buidler/blob/0183504555c2aed2e3ea7e63b6ddeb656ce7d4f7/packages/buidler-core/src/internal/core/config/config-resolution.ts#L95 it expected the paths to be string
Oh, I see. I'm not sure what the right solution is here. I guess we could stop resolving the other entries from paths
and just pass them down as they are in the buidler config, but this is a breaking change.
Another scenario for this is for monorepos where I have contracts spread out across individual packages. I want to leverage waffle test config setting "compilerAllowedPaths" but it doesn't look like it's supported. I basically want something like this:
paths: { compilerAllowedPaths: ['../common', '../token'] }
or paths: { sourcesPath: ['../common/contracts', '../token/contracts'], artifacts: ['../common/artifacts', '../token/artifacts'] }
Just to add my use case as well. I want to keep all test dependency contracts in a separate folder so this is required to be able to use deploy plugin with a custom folder only for given contracts.
More than one year later, is there any news about this? I have multiple contracts scattered into multiple solution folders, each contract is a proper hardhat project. In my "main project", I have multiple tests and some depends on other contracts that are not in my main solution contract folder. I want to deploy the other contracts by using the ethers.getContractFactory(), unfortunately it crashes. How to do that if we cannot specify multiple path sources? Error: Invalid value ["./contracts","../../anotherContractPath/contracts"] for HardhatConfig.paths.sources - Expected a value of type string | undefined. Thanks.
I'm in the same situation as @bricedenice59. Is there a workaround for this issue while it's not resolved? I would really appreciate some advice here. Thank you!!
Would also really appreciate this feature!
Any news on this issue?
Any news on this? I would really need this feature, as I have an hardhat repo with some contracts, but I also have another hardhat repo with other contracts that is a submodule of the 1st one. I would like to deploy the contracts all together but I cannot because I can only set 1 single path for each kind (1 artifacts, 1 sources etc)
Joining in. We're approaching 3 year anniversary for this issue (:
Also, I don't see how this is a breaking change: old behavior can easily be supported. Allow strings or arrays.
@lekevicius I know it's hard to see how this is a breaking change, but assume you are a plugin author that uses the paths.sources
somehow. The type of this is string
, so your code does something assuming it is a string.
Then Hardhat updates to a new patch/minor version and suddenly sources
is string | string[]
. Your code very likely won't work when you receive an array. So it's not a breaking change from a user perspective, but it can be from a plugin author perspective.
That being said:
Hopefully that makes sense, happy to answer any questions about this.
This is easy to do with a plugin or overriding a subtask. I know that that approach has way more friction than having this as a built-in feature, but the fact that there is a workaround also makes me err on the side of not introducing a breaking change.
Hello @fvictorio, do you have an example I can look at to do this? Is it TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS
that needs overriding?
Something like this should work:
const glob = require("glob");
const { TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS } = require("hardhat/builtin-tasks/task-names");
const path = require("path");
subtask(TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS).setAction(async (_, hre, runSuper) => {
const paths = await runSuper();
const otherDirectoryGlob = path.join(hre.config.paths.root, "more-contracts", "**", "*.sol");
const otherPaths = glob.sync(otherDirectoryGlob);
return [...paths, ...otherPaths];
});
Something like this should work:
const glob = require("glob"); const { TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS } = require("hardhat/builtin-tasks/task-names"); const path = require("path"); subtask(TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS).setAction(async (_, hre, runSuper) => { const paths = await runSuper(); const otherDirectoryGlob = path.join(hre.config.paths.root, "more-contracts", "**", "*.sol"); const otherPaths = glob.sync(otherDirectoryGlob); return [...paths, ...otherPaths]; });
thank you
Sadly this 4 year old bug means a lot of friction when trying to use hardhat to compile projects which don't conform to this single contract dir structure.
A not uncommon example is to use hardhat to compile a git submodule which uses foundry, which as you know uses solidity files for scripts and tests. Being able to specify individual paths would go a long way in terms of basic ergonomics.
If anyone is stuck on this, here is a possible working solution:
import { HardhatUserConfig, task } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox-viem";
import "@nomiclabs/hardhat-solhint";
import { glob } from "glob";
import path from "path";
// Define the base configuration
const config: HardhatUserConfig = {
solidity: "0.8.27",
paths: {
sources: "./contracts", // This will be overridden in the compile task
tests: "./test", // This will be overridden in the test task
},
};
// Helper function to find contract directories
const findContractDirs = (rootDir: string) => {
const contractPaths = glob.sync("module-*/deliverables/**/*.sol", {
cwd: rootDir,
ignore: ["**/node_modules/**"],
});
return [...new Set(contractPaths.map(path.dirname))];
};
// Override the default compile task
task(
"compile",
"Compiles the entire project, running all compilations",
).setAction(async (taskArgs, hre, runSuper) => {
const rootDir = hre.config.paths.root;
const contractDirs = findContractDirs(rootDir);
for (const contractDir of contractDirs) {
console.log(`Compiling contracts in ${contractDir}...`);
hre.config.paths.sources = path.join(rootDir, contractDir);
await runSuper(taskArgs);
}
});
// Custom test task
task("test", "Runs mocha tests in all module-x/test folders").setAction(
async (taskArgs, hre, runSuper) => {
const rootDir = hre.config.paths.root;
const testFolders = glob.sync("module-*/test", { cwd: rootDir });
// First, run the compile task
await hre.run("compile");
for (const testFolder of testFolders) {
console.log(`Running tests in ${testFolder}...`);
hre.config.paths.tests = path.join(rootDir, testFolder);
await runSuper(taskArgs);
}
},
);
export default config;
Just change the glob pattern for both source and test. This configuration simply loop through your contracts and tests.
For my plugin, I would like path config to be arrays.
Unfortunately, while buidler allow the types to be arrays, it fails at runtime because builder attempt to read them as string