Skip to content

Commit b7fd245

Browse files
authored
Merge branch 'v-next' into contributing-update-v3
2 parents f7b1f69 + 5f926b6 commit b7fd245

File tree

10 files changed

+141
-40
lines changed

10 files changed

+141
-40
lines changed

.changeset/forty-steaks-live.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"hardhat": patch
3+
---
4+
5+
Stop solidity tests being recompiled unnecessarily ([#7116](https://github.com/NomicFoundation/hardhat/issues/7116))

.changeset/strong-actors-count.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"hardhat": patch
3+
---
4+
5+
Send selected project type to GA

v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/build-system.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ export interface SolidityBuildSystemOptions {
8484
readonly soliditySourcesPaths: string[];
8585
readonly artifactsPath: string;
8686
readonly cachePath: string;
87+
readonly solidityTestsPath: string;
8788
}
8889

8990
export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
@@ -290,6 +291,8 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
290291
rootFilePaths: string[],
291292
options?: GetCompilationJobsOptions,
292293
): Promise<CompilationJobCreationError | GetCompilationJobsResult> {
294+
const isolated = options?.isolated ?? false;
295+
293296
await this.#downloadConfiguredCompilers(options?.quiet);
294297

295298
const dependencyGraph = await buildDependencyGraph(
@@ -397,7 +400,7 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
397400
options?.force === true ||
398401
cacheResult === undefined ||
399402
cacheResult.jobHash !== jobHash ||
400-
cacheResult.isolated !== options?.isolated
403+
cacheResult.isolated !== isolated
401404
) {
402405
rootFilesToCompile.add(rootFile);
403406
continue;
@@ -424,10 +427,7 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
424427
}
425428
}
426429

427-
if (
428-
options?.isolated !== true &&
429-
shouldMergeCompilationJobs(buildProfileName)
430-
) {
430+
if (!isolated && shouldMergeCompilationJobs(buildProfileName)) {
431431
// non-isolated mode
432432
log(`Merging compilation jobs`);
433433

@@ -702,6 +702,20 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
702702
)) {
703703
const relativePath = path.relative(this.#options.artifactsPath, file);
704704

705+
const testDirectorySubpath = path.relative(
706+
this.#options.projectRoot,
707+
this.#options.solidityTestsPath,
708+
);
709+
const hasTestFileExtension = file.endsWith(".t.sol");
710+
const isInsideTestFolder = relativePath.startsWith(
711+
testDirectorySubpath + path.sep,
712+
);
713+
714+
// Skip test artifacts, since our full compilation doesn't include them, they would incorrectly be marked for deletion
715+
if (hasTestFileExtension || isInsideTestFolder) {
716+
continue;
717+
}
718+
705719
if (!userSourceNamesSet.has(relativePath)) {
706720
await remove(file);
707721
}

v-next/hardhat/src/internal/builtin-plugins/solidity/hook-handlers/hre.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ export default async (): Promise<Partial<HardhatRuntimeEnvironmentHooks>> => {
120120
soliditySourcesPaths: hre.config.paths.sources.solidity,
121121
artifactsPath: hre.config.paths.artifacts,
122122
cachePath: hre.config.paths.cache,
123+
solidityTestsPath: hre.config.paths.tests.solidity,
123124
});
124125
},
125126
};

v-next/hardhat/src/internal/cli/init/init.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import * as semver from "semver";
2424
import { findClosestHardhatConfig } from "../../config-loading.js";
2525
import { HARDHAT_NAME } from "../../constants.js";
2626
import { getHardhatVersion } from "../../utils/package.js";
27+
import { sendProjectTypeAnalytics } from "../telemetry/analytics/analytics.js";
2728

2829
import {
2930
getDevDependenciesInstallationCommand,
@@ -96,7 +97,10 @@ export async function initHardhat(options?: InitHardhatOptions): Promise<void> {
9697

9798
// Ask the user for the template to use for the project initialization
9899
// if it was not provided, and validate that it exists
99-
const template = await getTemplate(hardhatVersion, options?.template);
100+
const [template, projectTypeAnalyticsPromise] = await getTemplate(
101+
hardhatVersion,
102+
options?.template,
103+
);
100104

101105
// Create the package.json file if it does not exist
102106
// and validate that it is an esm package
@@ -112,7 +116,11 @@ export async function initHardhat(options?: InitHardhatOptions): Promise<void> {
112116

113117
// Print the commands to install the project dependencies
114118
// Run them only if the user opts-in to it
115-
await installProjectDependencies(workspace, template, options?.install);
119+
// Concurrently, await the analytics hit
120+
await Promise.all([
121+
installProjectDependencies(workspace, template, options?.install),
122+
projectTypeAnalyticsPromise,
123+
]);
116124

117125
showStarOnGitHubMessage();
118126
} catch (e) {
@@ -241,26 +249,34 @@ export async function getWorkspace(workspace?: string): Promise<string> {
241249
* NOTE: This function is exported for testing purposes
242250
*
243251
* @param template The name of the template to use for the project initialization.
244-
* @returns
252+
* @returns A tuple with two elements: the template and a promise with the analytics hit.
245253
*/
246254
export async function getTemplate(
247255
hardhatVersion: "hardhat-2" | "hardhat-3",
248256
template?: string,
249-
): Promise<Template> {
257+
): Promise<[Template, Promise<boolean>]> {
250258
const templates = await getTemplates(hardhatVersion);
251259

252260
// Ask the user for the template to use for the project initialization if it was not provided
253261
if (template === undefined) {
254262
template = await promptForTemplate(templates);
255263
}
256264

265+
const projectTypeAnalyticsPromise = sendProjectTypeAnalytics(
266+
hardhatVersion,
267+
template,
268+
);
269+
257270
// Validate that the template exists
258271
for (const t of templates) {
259272
if (t.name === template) {
260-
return t;
273+
return [t, projectTypeAnalyticsPromise];
261274
}
262275
}
263276

277+
// we wait for the GA hit before throwing
278+
await projectTypeAnalyticsPromise;
279+
264280
throw new HardhatError(HardhatError.ERRORS.CORE.GENERAL.TEMPLATE_NOT_FOUND, {
265281
template,
266282
});

v-next/hardhat/src/internal/cli/telemetry/analytics/analytics.ts

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import type {
2-
EventNames,
2+
AnalyticsEvent,
33
Payload,
4-
TaskParams,
54
TelemetryConfigPayload,
65
} from "./types.js";
76

@@ -54,23 +53,38 @@ export async function sendTelemetryConfigAnalytics(
5453
}
5554

5655
export async function sendTaskAnalytics(taskId: string[]): Promise<boolean> {
57-
const eventParams: TaskParams = {
58-
task: taskId.join(", "),
56+
const taskAnalyticsEvent: AnalyticsEvent = {
57+
name: "task",
58+
params: {
59+
task: taskId.join(", "),
60+
},
5961
};
6062

61-
return sendAnalytics("task", eventParams);
63+
return sendAnalytics(taskAnalyticsEvent);
6264
}
6365

64-
// Return a boolean for testing purposes to confirm whether analytics were sent based on the consent value and not in CI environments
65-
async function sendAnalytics(
66-
eventName: EventNames,
67-
eventParams: TaskParams,
66+
export async function sendProjectTypeAnalytics(
67+
hardhatVersion: "hardhat-2" | "hardhat-3",
68+
template: string,
6869
): Promise<boolean> {
70+
const initAnalyticsEvent: AnalyticsEvent = {
71+
name: "init",
72+
params: {
73+
hardhatVersion,
74+
template,
75+
},
76+
};
77+
78+
return sendAnalytics(initAnalyticsEvent);
79+
}
80+
81+
// Return a boolean for testing purposes to confirm whether analytics were sent based on the consent value and not in CI environments
82+
async function sendAnalytics(analyticsEvent: AnalyticsEvent): Promise<boolean> {
6983
if (!(await isTelemetryAllowed())) {
7084
return false;
7185
}
7286

73-
const payload = await buildPayload(eventName, eventParams);
87+
const payload = await buildPayload(analyticsEvent);
7488

7589
await createSubprocessToSendAnalytics(payload);
7690

@@ -104,10 +118,7 @@ async function createSubprocessToSendAnalytics(
104118
log("Payload sent to detached subprocess");
105119
}
106120

107-
async function buildPayload(
108-
eventName: EventNames,
109-
eventParams: TaskParams,
110-
): Promise<Payload> {
121+
async function buildPayload(analyticsEvent: AnalyticsEvent): Promise<Payload> {
111122
const clientId = await getAnalyticsClientId();
112123

113124
return {
@@ -121,11 +132,11 @@ async function buildPayload(
121132
},
122133
events: [
123134
{
124-
name: eventName,
135+
name: analyticsEvent.name,
125136
params: {
126137
engagement_time_msec: ENGAGEMENT_TIME_MSEC,
127138
session_id: SESSION_ID,
128-
...eventParams,
139+
...analyticsEvent.params,
129140
},
130141
},
131142
],

v-next/hardhat/src/internal/cli/telemetry/analytics/types.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,20 @@ export interface TelemetryConfigPayload extends BasePayload {
3232
}>;
3333
}
3434

35-
export type EventNames = "task";
36-
37-
export interface TaskParams {
38-
task: string;
39-
}
35+
export type AnalyticsEvent =
36+
| {
37+
name: "task";
38+
params: {
39+
task: string;
40+
};
41+
}
42+
| {
43+
name: "init";
44+
params: {
45+
hardhatVersion: "hardhat-2" | "hardhat-3";
46+
template: string;
47+
};
48+
};
4049

4150
export interface Payload extends BasePayload {
4251
user_properties: {
@@ -54,10 +63,10 @@ export interface Payload extends BasePayload {
5463
};
5564
};
5665
events: Array<{
57-
name: EventNames;
66+
name: AnalyticsEvent["name"];
5867
params: {
5968
engagement_time_msec: string;
6069
session_id: string;
61-
} & TaskParams;
70+
} & AnalyticsEvent["params"];
6271
}>;
6372
}

v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/build-system.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ describe(
107107
soliditySourcesPaths: [path.join(process.cwd(), "contracts")],
108108
artifactsPath: expectedArtifactsPath,
109109
cachePath: expectedCachePath,
110+
solidityTestsPath: path.join(process.cwd(), "tests"),
110111
});
111112
const rootFilePaths = await solidity.getRootFilePaths();
112113
await solidity.build(rootFilePaths, {
@@ -129,6 +130,7 @@ describe(
129130
soliditySourcesPaths: [path.join(process.cwd(), "contracts")],
130131
artifactsPath: actualArtifactsPath,
131132
cachePath: actualCachePath,
133+
solidityTestsPath: path.join(process.cwd(), "tests"),
132134
});
133135
});
134136

v-next/hardhat/test/internal/cli/init/init.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ describe("getTemplate", () => {
9090
);
9191
});
9292
it("should return the provided template", async () => {
93-
const template = await getTemplate("hardhat-3", "mocha-ethers");
93+
const [template] = await getTemplate("hardhat-3", "mocha-ethers");
9494
assert.equal(template.name, "mocha-ethers");
9595
});
9696
});
@@ -284,7 +284,7 @@ describe("copyProjectFiles", () => {
284284

285285
describe("when force is true", () => {
286286
it("should copy the template files to the workspace and overwrite existing files", async () => {
287-
const template = await getTemplate("hardhat-3", "mocha-ethers");
287+
const [template] = await getTemplate("hardhat-3", "mocha-ethers");
288288
// Create template files with "some content" in the workspace
289289
const workspaceFiles = template.files.map(
290290
relativeTemplateToWorkspacePath,
@@ -303,7 +303,7 @@ describe("copyProjectFiles", () => {
303303
}
304304
});
305305
it("should copy the .gitignore file correctly", async () => {
306-
const template = await getTemplate("hardhat-3", "mocha-ethers");
306+
const [template] = await getTemplate("hardhat-3", "mocha-ethers");
307307
// Copy the template files to the workspace
308308
await copyProjectFiles(process.cwd(), template, true);
309309
// Check that the .gitignore exists but gitignore does not
@@ -319,7 +319,7 @@ describe("copyProjectFiles", () => {
319319
});
320320
describe("when force is false", () => {
321321
it("should copy the template files to the workspace and NOT overwrite existing files", async () => {
322-
const template = await getTemplate("hardhat-3", "mocha-ethers");
322+
const [template] = await getTemplate("hardhat-3", "mocha-ethers");
323323
// Create template files with "some content" in the workspace
324324
const workspaceFiles = template.files.map(
325325
relativeTemplateToWorkspacePath,
@@ -338,7 +338,7 @@ describe("copyProjectFiles", () => {
338338
}
339339
});
340340
it("should copy the .gitignore file correctly", async () => {
341-
const template = await getTemplate("hardhat-3", "mocha-ethers");
341+
const [template] = await getTemplate("hardhat-3", "mocha-ethers");
342342
// Copy the template files to the workspace
343343
await copyProjectFiles(process.cwd(), template, false);
344344
// Check that the .gitignore exists but gitignore does not
@@ -396,7 +396,7 @@ describe("installProjectDependencies", async () => {
396396
}
397397

398398
it("should not install any template dependencies if the user opts-out of the installation", async () => {
399-
const template = await getTemplate("hardhat-3", "mocha-ethers");
399+
const [template] = await getTemplate("hardhat-3", "mocha-ethers");
400400
await writeUtf8File("package.json", JSON.stringify({ type: "module" }));
401401
await installProjectDependencies(process.cwd(), template, false, false);
402402
assert.ok(!(await exists("node_modules")), "node_modules should not exist");
@@ -412,7 +412,7 @@ describe("installProjectDependencies", async () => {
412412
process.env.GITHUB_HEAD_REF?.startsWith("changeset-release/"),
413413
},
414414
async () => {
415-
const template = await getTemplate("hardhat-3", "mocha-ethers");
415+
const [template] = await getTemplate("hardhat-3", "mocha-ethers");
416416
await writeUtf8File(
417417
"package.json",
418418
JSON.stringify({

0 commit comments

Comments
 (0)