diff --git a/packages/core/src/cli/validate/build-info-file.test.ts b/packages/core/src/cli/validate/build-info-file.test.ts index 871784e3c..7edd637d1 100644 --- a/packages/core/src/cli/validate/build-info-file.test.ts +++ b/packages/core/src/cli/validate/build-info-file.test.ts @@ -4,7 +4,7 @@ import { promises as fs } from 'fs'; import { rimraf } from 'rimraf'; import path from 'path'; import os from 'os'; -import { BuildInfoFile, getBuildInfoDirWithFiles } from './build-info-file'; +import { BuildInfoFile, getBuildInfoFiles } from './build-info-file'; test.beforeEach(async t => { process.chdir(await fs.mkdtemp(path.join(os.tmpdir(), `upgrades-core-test-${t.title.replace(/\s/g, '-')}-`))); @@ -296,9 +296,9 @@ test.serial('get build info files - default hardhat', async t => { await fs.writeFile('artifacts/build-info/build-info.json', JSON.stringify(BUILD_INFO)); await fs.writeFile('artifacts/build-info/build-info-2.json', JSON.stringify(BUILD_INFO_2)); - const buildInfoFiles = await getBuildInfoDirWithFiles(); + const buildInfoFiles = await getBuildInfoFiles(); - assertBuildInfoFiles(t, buildInfoFiles.files); + assertBuildInfoFiles(t, buildInfoFiles); }); test.serial('get build info files - default foundry', async t => { @@ -308,9 +308,9 @@ test.serial('get build info files - default foundry', async t => { await fs.writeFile('out/build-info/build-info.json', JSON.stringify(BUILD_INFO)); await fs.writeFile('out/build-info/build-info-2.json', JSON.stringify(BUILD_INFO_2)); - const buildInfoFiles = await getBuildInfoDirWithFiles(); + const buildInfoFiles = await getBuildInfoFiles(); - assertBuildInfoFiles(t, buildInfoFiles.files); + assertBuildInfoFiles(t, buildInfoFiles); }); test.serial('get build info files - both hardhat and foundry dirs exist', async t => { @@ -320,12 +320,12 @@ test.serial('get build info files - both hardhat and foundry dirs exist', async await fs.mkdir('out/build-info', { recursive: true }); await fs.writeFile('out/build-info/build-info-2.json', JSON.stringify(BUILD_INFO_2)); - const error = await t.throwsAsync(getBuildInfoDirWithFiles()); + const error = await t.throwsAsync(getBuildInfoFiles()); t.true(error?.message.includes('Found both Hardhat and Foundry build info directories')); }); test.serial('get build info files - no default dirs exist', async t => { - const error = await t.throwsAsync(getBuildInfoDirWithFiles()); + const error = await t.throwsAsync(getBuildInfoFiles()); t.true(error?.message.includes('Could not find the default Hardhat or Foundry build info directory')); }); @@ -338,9 +338,9 @@ test.serial('get build info files - override with custom relative path', async t await fs.writeFile('custom/build-info/build-info.json', JSON.stringify(BUILD_INFO)); await fs.writeFile('custom/build-info/build-info-2.json', JSON.stringify(BUILD_INFO_2)); - const buildInfoFiles = await getBuildInfoDirWithFiles('custom/build-info'); + const buildInfoFiles = await getBuildInfoFiles('custom/build-info'); - assertBuildInfoFiles(t, buildInfoFiles.files); + assertBuildInfoFiles(t, buildInfoFiles); }); test.serial('get build info files - override with custom absolute path', async t => { @@ -352,21 +352,21 @@ test.serial('get build info files - override with custom absolute path', async t await fs.writeFile('custom/build-info/build-info.json', JSON.stringify(BUILD_INFO)); await fs.writeFile('custom/build-info/build-info-2.json', JSON.stringify(BUILD_INFO_2)); - const buildInfoFiles = await getBuildInfoDirWithFiles(path.join(process.cwd(), 'custom/build-info')); + const buildInfoFiles = await getBuildInfoFiles(path.join(process.cwd(), 'custom/build-info')); - assertBuildInfoFiles(t, buildInfoFiles.files); + assertBuildInfoFiles(t, buildInfoFiles); }); test.serial('invalid build info file', async t => { await fs.mkdir('invalid-build-info', { recursive: true }); await fs.writeFile('invalid-build-info/invalid.json', JSON.stringify({ output: {} })); - const error = await t.throwsAsync(getBuildInfoDirWithFiles('invalid-build-info')); + const error = await t.throwsAsync(getBuildInfoFiles('invalid-build-info')); t.true(error?.message.includes('must contain Solidity compiler input, output, and solcVersion')); }); test.serial('dir does not exist', async t => { - const error = await t.throwsAsync(getBuildInfoDirWithFiles('invalid-dir')); + const error = await t.throwsAsync(getBuildInfoFiles('invalid-dir')); t.true(error?.message.includes('does not exist')); }); @@ -376,7 +376,7 @@ test.serial('no build info files', async t => { await fs.mkdir(dir, { recursive: true }); await fs.writeFile(`${dir}/notjson.txt`, 'abc'); - const error = await t.throwsAsync(getBuildInfoDirWithFiles(dir)); + const error = await t.throwsAsync(getBuildInfoFiles(dir)); t.true(error?.message.includes('does not contain any build info files')); }); @@ -386,7 +386,7 @@ test.serial('no storage layout', async t => { await fs.mkdir(dir, { recursive: true }); await fs.writeFile(`${dir}/build-info.json`, JSON.stringify(BUILD_INFO_NO_LAYOUT)); - const error = await t.throwsAsync(getBuildInfoDirWithFiles(dir)); + const error = await t.throwsAsync(getBuildInfoFiles(dir)); t.true(error?.message.includes('does not contain storage layout')); }); @@ -396,7 +396,7 @@ test.serial('individual output selections - no layout', async t => { await fs.mkdir(dir, { recursive: true }); await fs.writeFile(`${dir}/build-info.json`, JSON.stringify(BUILD_INFO_INDIVIDUAL_NO_LAYOUT)); - const error = await t.throwsAsync(getBuildInfoDirWithFiles(dir)); + const error = await t.throwsAsync(getBuildInfoFiles(dir)); t.true(error?.message.includes('does not contain storage layout')); }); @@ -406,7 +406,7 @@ test.serial('individual output selections - has layout', async t => { await fs.mkdir(dir, { recursive: true }); await fs.writeFile(`${dir}/build-info.json`, JSON.stringify(BUILD_INFO_INDIVIDUAL_HAS_LAYOUT)); - t.assert((await getBuildInfoDirWithFiles(dir)).files.length === 1); + t.assert((await getBuildInfoFiles(dir)).length === 1); }); test.serial('individual output selections - partial layout', async t => { @@ -415,7 +415,7 @@ test.serial('individual output selections - partial layout', async t => { await fs.mkdir(dir, { recursive: true }); await fs.writeFile(`${dir}/build-info.json`, JSON.stringify(BUILD_INFO_PARTIAL_LAYOUT)); - const error = await t.throwsAsync(getBuildInfoDirWithFiles(dir)); + const error = await t.throwsAsync(getBuildInfoFiles(dir)); t.true(error?.message.includes('does not contain storage layout')); }); @@ -425,7 +425,7 @@ test.serial('individual output selections - partial compile', async t => { await fs.mkdir(dir, { recursive: true }); await fs.writeFile(`${dir}/build-info.json`, JSON.stringify(BUILD_INFO_PARTIAL_COMPILE)); - const error = await t.throwsAsync(getBuildInfoDirWithFiles(dir)); + const error = await t.throwsAsync(getBuildInfoFiles(dir)); t.true(error?.message.includes('is not from a full compilation')); }); @@ -435,7 +435,7 @@ test.serial('no output selection', async t => { await fs.mkdir(dir, { recursive: true }); await fs.writeFile(`${dir}/build-info.json`, JSON.stringify(BUILD_INFO_NO_OUTPUT_SELECTION)); - const error = await t.throwsAsync(getBuildInfoDirWithFiles(dir)); + const error = await t.throwsAsync(getBuildInfoFiles(dir)); t.true(error?.message.includes('is not from a full compilation')); }); diff --git a/packages/core/src/cli/validate/build-info-file.ts b/packages/core/src/cli/validate/build-info-file.ts index 492ea3f7d..5922397bd 100644 --- a/packages/core/src/cli/validate/build-info-file.ts +++ b/packages/core/src/cli/validate/build-info-file.ts @@ -56,25 +56,23 @@ export interface BuildInfoFile { dirShortName: string; } -export interface BuildInfoDirWithFiles { - dirShortName: string; - files: BuildInfoFile[]; -} - /** * Gets the build info files from the build info directory. * * @param buildInfoDir Build info directory, or undefined to use the default Hardhat or Foundry build-info dir. * @returns The build info files with Solidity compiler input and output. */ -export async function getBuildInfoDirWithFiles(buildInfoDir?: string): Promise { +export async function getBuildInfoFiles(buildInfoDir?: string): Promise { const dir = await findDir(buildInfoDir); const shortName = path.basename(dir); const jsonFiles = await getJsonFiles(dir); - return { dirShortName: shortName, files: await readBuildInfo(jsonFiles, shortName) }; // TODO remove redundant dirShortName + return await readBuildInfo(jsonFiles, shortName); } +/** + * Finds the build info dir if provided, otherwise finds the default Hardhat or Foundry build info dir. Throws an error if no build info files were found in the expected dir. + */ async function findDir(buildInfoDir?: string): Promise { if (buildInfoDir !== undefined && !(await hasJsonFiles(buildInfoDir))) { throw new ValidateCommandError( diff --git a/packages/core/src/cli/validate/validate-upgrade-safety.ts b/packages/core/src/cli/validate/validate-upgrade-safety.ts index f068ecc6c..a6042ee6b 100644 --- a/packages/core/src/cli/validate/validate-upgrade-safety.ts +++ b/packages/core/src/cli/validate/validate-upgrade-safety.ts @@ -1,7 +1,7 @@ import path from 'path'; import { ValidationOptions, withValidationDefaults } from '../..'; -import { getBuildInfoDirWithFiles } from './build-info-file'; +import { getBuildInfoFiles } from './build-info-file'; import { getContractReports } from './contract-report'; import { findContract } from './find-contract'; import { ProjectReport, getProjectReport } from './project-report'; @@ -39,12 +39,14 @@ export async function validateUpgradeSafety( ): Promise { const allOpts = withCliDefaults(opts); - const buildInfoDirWithFiles = await getBuildInfoDirWithFiles(buildInfoDir); - const sourceContracts = validateBuildInfoContracts(buildInfoDirWithFiles.files); + const buildInfoFiles = await getBuildInfoFiles(buildInfoDir); + const sourceContracts = validateBuildInfoContracts(buildInfoFiles); const buildInfoDictionary: BuildInfoDictionary = {}; buildInfoDictionary[''] = sourceContracts; - buildInfoDictionary[buildInfoDirWithFiles.dirShortName] = sourceContracts; + if (buildInfoFiles.length > 0) { + buildInfoDictionary[buildInfoFiles[0].dirShortName] = sourceContracts; + } if (referenceBuildInfoDirs !== undefined) { for (const referenceBuildInfoDir of referenceBuildInfoDirs) { @@ -54,8 +56,8 @@ export async function validateUpgradeSafety( throw new Error(`Reference build info directory short name '${key}' is not unique.`); } - const referenceBuildInfoFiles = await getBuildInfoDirWithFiles(referenceBuildInfoDir); - buildInfoDictionary[key] = validateBuildInfoContracts(referenceBuildInfoFiles.files); + const referenceBuildInfoFiles = await getBuildInfoFiles(referenceBuildInfoDir); + buildInfoDictionary[key] = validateBuildInfoContracts(referenceBuildInfoFiles); } }