Repository: NomicFoundation/hardhat-ignition (ts)

Issue:
Display a warning when deploying against an ephemeral network
Proposed by Pato:

If we are running a deployment against an ephemeral network rather than an external node, we should display a warning:

chalk.bold(`You are running Hardhat Ignition against an in-process instance Hardhat Network. This will execute the deployment, but the results will be lost.
You can use --network <network-name> to deploy to a different network`);

Pull request:
feat:ephemeral warning (PR 2)
Display a warning message in the `deploy` task. It indicates that deployment is against an ephemeral network.

The implementation is to add extra information to the start run event, specifically the `deploymentDir`, which then allows the UI event handler to determine if the deployment is ephemeral.

This means injecting that information down throught the `deploy`/`deployer` barrier. This is not ideal, but I think it is legitimate to assume the UI should have access to all the passed in config. Put another way we should likely collapse the distinction between deploy and deployer in a future refactoring.

Resolves #553.

## Preview

![image](https://github.com/NomicFoundation/hardhat-ignition/assets/24030/d3ef0168-878c-43f7-b29d-167f72e9a7e8)


Patch:
diff --git a/packages/core/src/deploy.ts b/packages/core/src/deploy.ts
index d8aa3d73..90860a90 100644
--- a/packages/core/src/deploy.ts
+++ b/packages/core/src/deploy.ts
@@ -117,6 +117,7 @@ export async function deploy<
 
   const deployer = new Deployer(
     resolvedConfig,
+    deploymentDir,
     executionStrategy,
     jsonRpcClient,
     artifactResolver,
diff --git a/packages/core/src/internal/deployer.ts b/packages/core/src/internal/deployer.ts
index f44f00c1..5c128ffa 100644
--- a/packages/core/src/internal/deployer.ts
+++ b/packages/core/src/internal/deployer.ts
@@ -47,6 +47,7 @@ import { findStatus } from "./views/find-status";
 export class Deployer {
   constructor(
     private readonly _config: DeployConfig,
+    private readonly _deploymentDir: string | undefined,
     private readonly _executionStrategy: ExecutionStrategy,
     private readonly _jsonRpcClient: JsonRpcClient,
     private readonly _artifactResolver: ArtifactResolver,
@@ -74,7 +75,8 @@ export class Deployer {
     defaultSender: string
   ): Promise<DeploymentResult> {
     let deploymentState = await this._getOrInitializeDeploymentState(
-      ignitionModule.id
+      ignitionModule.id,
+      this._deploymentDir
     );
 
     const contracts =
@@ -217,13 +219,14 @@ export class Deployer {
   }
 
   private async _getOrInitializeDeploymentState(
-    moduleId: string
+    moduleId: string,
+    deploymentDir: string | undefined
   ): Promise<DeploymentState> {
     const chainId = await this._jsonRpcClient.getChainId();
     const deploymentState = await loadDeploymentState(this._deploymentLoader);
 
     if (deploymentState === undefined) {
-      this._emitDeploymentStartEvent(moduleId);
+      this._emitDeploymentStartEvent(moduleId, deploymentDir);
 
       return initializeDeploymentState(chainId, this._deploymentLoader);
     }
@@ -236,7 +239,10 @@ export class Deployer {
     return deploymentState;
   }
 
-  private _emitDeploymentStartEvent(moduleId: string): void {
+  private _emitDeploymentStartEvent(
+    moduleId: string,
+    deploymentDir: string | undefined
+  ): void {
     if (this._executionEventListener === undefined) {
       return;
     }
@@ -244,6 +250,7 @@ export class Deployer {
     this._executionEventListener.deploymentStart({
       type: ExecutionEventType.DEPLOYMENT_START,
       moduleName: moduleId,
+      deploymentDir: deploymentDir ?? undefined,
     });
   }
 
diff --git a/packages/core/src/types/execution-events.ts b/packages/core/src/types/execution-events.ts
index 91d478de..ecc19467 100644
--- a/packages/core/src/types/execution-events.ts
+++ b/packages/core/src/types/execution-events.ts
@@ -75,6 +75,7 @@ export enum ExecutionEventType {
 export interface DeploymentStartEvent {
   type: ExecutionEventType.DEPLOYMENT_START;
   moduleName: string;
+  deploymentDir: string | undefined;
 }
 
 /**
diff --git a/packages/hardhat-plugin/src/ui/helpers/calculate-starting-message.ts b/packages/hardhat-plugin/src/ui/helpers/calculate-starting-message.ts
new file mode 100644
index 00000000..a199fe6f
--- /dev/null
+++ b/packages/hardhat-plugin/src/ui/helpers/calculate-starting-message.ts
@@ -0,0 +1,30 @@
+import chalk from "chalk";
+
+/**
+ * Display the temporary starting message. Note this does not print a newline.
+ *
+ * @param state - the UI state
+ */
+export function calculateStartingMessage({
+  moduleName,
+  deploymentDir,
+}: {
+  moduleName: string | null;
+  deploymentDir: string | undefined | null;
+}): string {
+  const warningMessage = chalk.yellow(
+    chalk.bold(
+      `You are running Hardhat Ignition against an in-process instance of Hardhat Network.
+This will execute the deployment, but the results will be lost.
+You can use --network <network-name> to deploy to a different network.`
+    )
+  );
+
+  const startingMessage = `Hardhat Ignition starting for [ ${
+    moduleName ?? "unknown"
+  } ]...`;
+
+  return deploymentDir === undefined
+    ? `${warningMessage}\n\n${startingMessage}`
+    : startingMessage;
+}
diff --git a/packages/hardhat-plugin/src/ui/helpers/display-starting-message.ts b/packages/hardhat-plugin/src/ui/helpers/display-starting-message.ts
deleted file mode 100644
index 58e8b434..00000000
--- a/packages/hardhat-plugin/src/ui/helpers/display-starting-message.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { UiState } from "../types";
-
-/**
- * Display the temporary starting message. Note this does not print a newline.
- *
- * @param state - the UI state
- */
-export function displayStartingMessage(state: UiState) {
-  process.stdout.write(
-    `Hardhat Ignition starting for [ ${state.moduleName ?? "unknown"} ]...`
-  );
-}
diff --git a/packages/hardhat-plugin/src/ui/pretty-event-handler.ts b/packages/hardhat-plugin/src/ui/pretty-event-handler.ts
index 9c3f8c03..72e9c5c3 100644
--- a/packages/hardhat-plugin/src/ui/pretty-event-handler.ts
+++ b/packages/hardhat-plugin/src/ui/pretty-event-handler.ts
@@ -36,7 +36,7 @@ import {
 import { calculateBatchDisplay } from "./helpers/calculate-batch-display";
 import { calculateDeployingModulePanel } from "./helpers/calculate-deploying-module-panel";
 import { calculateDeploymentCompleteDisplay } from "./helpers/calculate-deployment-complete-display";
-import { displayStartingMessage } from "./helpers/display-starting-message";
+import { calculateStartingMessage } from "./helpers/calculate-starting-message";
 import {
   UiBatches,
   UiFuture,
@@ -54,6 +54,7 @@ export class PrettyEventHandler implements ExecutionEventListener {
     status: UiStateDeploymentStatus.UNSTARTED,
     chainId: null,
     moduleName: null,
+    deploymentDir: null,
     batches: [],
     currentBatch: 0,
     result: null,
@@ -75,9 +76,10 @@ export class PrettyEventHandler implements ExecutionEventListener {
       ...this.state,
       status: UiStateDeploymentStatus.DEPLOYING,
       moduleName: event.moduleName,
+      deploymentDir: event.deploymentDir,
     };
 
-    displayStartingMessage(this.state);
+    process.stdout.write(calculateStartingMessage(this.state));
   }
 
   public runStart(event: RunStartEvent): void {
diff --git a/packages/hardhat-plugin/src/ui/types.ts b/packages/hardhat-plugin/src/ui/types.ts
index d9e3d007..0c2e5066 100644
--- a/packages/hardhat-plugin/src/ui/types.ts
+++ b/packages/hardhat-plugin/src/ui/types.ts
@@ -56,6 +56,7 @@ export interface UiState {
   status: UiStateDeploymentStatus;
   chainId: number | null;
   moduleName: string | null;
+  deploymentDir: string | undefined | null;
   batches: UiBatches;
   currentBatch: number;
   result: DeploymentResult | null;


Test patch:
diff --git a/packages/hardhat-plugin/test/ui/helpers/calculate-batch-display.ts b/packages/hardhat-plugin/test/ui/helpers/calculate-batch-display.ts
index 55f8f1e7..289bc40d 100644
--- a/packages/hardhat-plugin/test/ui/helpers/calculate-batch-display.ts
+++ b/packages/hardhat-plugin/test/ui/helpers/calculate-batch-display.ts
@@ -12,6 +12,7 @@ const exampleState: UiState = {
   status: UiStateDeploymentStatus.DEPLOYING,
   chainId: 31337,
   moduleName: "ExampleModule",
+  deploymentDir: "/users/example",
   batches: [],
   currentBatch: 1,
   result: null,
diff --git a/packages/hardhat-plugin/test/ui/helpers/calculate-starting-message.ts b/packages/hardhat-plugin/test/ui/helpers/calculate-starting-message.ts
new file mode 100644
index 00000000..1eb12ba1
--- /dev/null
+++ b/packages/hardhat-plugin/test/ui/helpers/calculate-starting-message.ts
@@ -0,0 +1,34 @@
+import { assert } from "chai";
+import chalk from "chalk";
+
+import { calculateStartingMessage } from "../../../src/ui/helpers/calculate-starting-message";
+
+describe("ui - calculate starting message display", () => {
+  it("should display the starting message", () => {
+    const expectedText = `Hardhat Ignition starting for [ MyModule ]...`;
+
+    const actualText = calculateStartingMessage({
+      moduleName: "MyModule",
+      deploymentDir: "/users/example",
+    });
+
+    assert.equal(actualText, expectedText);
+  });
+
+  it("should display the warning for an ephemeral network", () => {
+    const warningMessage = `You are running Hardhat Ignition against an in-process instance of Hardhat Network.
+This will execute the deployment, but the results will be lost.
+You can use --network <network-name> to deploy to a different network.`;
+
+    const expectedText = `${chalk.yellow(
+      chalk.bold(warningMessage)
+    )}\n\nHardhat Ignition starting for [ MyModule ]...`;
+
+    const actualText = calculateStartingMessage({
+      moduleName: "MyModule",
+      deploymentDir: undefined,
+    });
+
+    assert.equal(actualText, expectedText);
+  });
+});