Skip to content
This repository was archived by the owner on Mar 11, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"onCommand:truffle-vscode.newSolidityProject",
"onCommand:truffle-vscode.buildContracts",
"onCommand:truffle-vscode.deployContracts",
"onCommand:truffle-vscode.execScript",
"onCommand:truffle-vscode.connectProject",
"onCommand:truffle-vscode.copyRPCEndpointAddress",
"onCommand:truffle-vscode.createProject",
Expand Down Expand Up @@ -230,6 +231,11 @@
"title": "Deploy Contracts",
"category": "Truffle"
},
{
"command": "truffle-vscode.execScript",
"title": "Truffle: Execute Script",
"category": "Truffle"
},
{
"command": "truffle-vscode.connectProject",
"title": "Connect to network",
Expand Down Expand Up @@ -439,6 +445,11 @@
"when": "resourceLangId == json",
"command": "truffle-contract.copyABI",
"group": "9_copyFromContractGroup"
},
{
"when": "resourceLangId == javascript",
"command": "truffle-vscode.execScript",
"group": "10_execScriptGroup"
}
]
},
Expand Down
1 change: 1 addition & 0 deletions src/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,7 @@ export class Constants {

public static statusBarMessages = {
buildingContracts: "Building contracts",
executingScript: "Executing script",
checkingRequirementDependencies: "Checking requirement dependencies version",
createBDMApplication: "Creating BDM app",
createBlobs: "Creating blobs",
Expand Down
6 changes: 5 additions & 1 deletion src/commands/SdkCoreCommands.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Consensys Software Inc. All rights reserved.
// Licensed under the MIT license.

import {Memento, window} from "vscode";
import {Memento, window, Uri} from "vscode";
import {Constants} from "../Constants";
import {
// getWorkspaceRoot,
Expand Down Expand Up @@ -38,6 +38,10 @@ class SdkCoreCommands {
return this.extensionAdapter.deploy();
}

public async execScript(uri: Uri): Promise<void> {
return this.extensionAdapter.execScript(uri);
}

private async getCoreSdk() {
return userSettings.getConfigurationAsync(Constants.userSettings.coreSdkSettingsKey);
}
Expand Down
14 changes: 14 additions & 0 deletions src/commands/TruffleCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,20 @@ export namespace TruffleCommands {
Telemetry.sendEvent("TruffleCommands.deployContracts.commandFinished");
}

export async function execScript(uri: Uri): Promise<void> {
Telemetry.sendEvent("TruffleCommands.execScript.commandStarted");

await showIgnorableNotification(Constants.statusBarMessages.executingScript, async () => {
if (!(await required.checkAppsSilent(RequiredApps.truffle))) {
Telemetry.sendEvent("TruffleCommands.execScript.truffleInstallation");
await required.installTruffle(required.Scope.locally);
}
await outputCommandHelper.executeCommand(getWorkspaceRoot(), "npx", RequiredApps.truffle, "exec", uri.fsPath);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you not want to do something with the output of this call?

Does this output to the outputChannel or similar? Debugging any issues will be problematic otherwise. Especially any exceptions (non 0 return codes).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey @michaeljohnbennett (apols for the delay), yup it does currently output to Truffle for VSCode channel...does that make sense from your perspective?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kevinbluer, just a heads up: if we have more than one Truffle Project opened, or even a root directory without any truffle-config.js file, the function getWorkspaceRoot() might not work (e.g.: deploy function). The fix for that is on: fix/compile-from-working-dir

});

Telemetry.sendEvent("TruffleCommands.execScript.commandFinished");
}

export async function writeAbiToBuffer(uri: Uri): Promise<void> {
Telemetry.sendEvent("TruffleCommands.writeAbiToBuffer.commandStarted");
const contract = await readCompiledContract(uri);
Expand Down
4 changes: 4 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ export async function activate(context: ExtensionContext) {
const deployContracts = commands.registerCommand("truffle-vscode.deployContracts", async () => {
await tryExecute(() => sdkCoreCommands.deploy());
});
const execScript = commands.registerCommand("truffle-vscode.execScript", async (uri: Uri) => {
await tryExecute(() => sdkCoreCommands.execScript(uri));
});
const copyByteCode = commands.registerCommand("truffle-contract.copyByteCode", async (uri: Uri) => {
await tryExecute(() => TruffleCommands.writeBytecodeToBuffer(uri));
});
Expand Down Expand Up @@ -215,6 +218,7 @@ export async function activate(context: ExtensionContext) {
newSolidityProject,
buildContracts,
deployContracts,
execScript,
// createNewBDMApplication,
createProject,
connectProject,
Expand Down
3 changes: 3 additions & 0 deletions src/services/extensionAdapter/IExtensionAdapter.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
// Copyright (c) Consensys Software Inc. All rights reserved.
// Licensed under the MIT license.
import {Uri} from "vscode";

export interface IExtensionAdapter {
validateExtension: () => Promise<void>;
build: (...args: Array<string>) => Promise<void>;
deploy: () => Promise<void>;

execScript: (uri: Uri) => Promise<void>;
}
5 changes: 5 additions & 0 deletions src/services/extensionAdapter/TruffleExtensionAdapter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Consensys Software Inc. All rights reserved.
// Licensed under the MIT license.

import {Uri} from "vscode";
import {TruffleCommands} from "../../commands/TruffleCommands";
import {IExtensionAdapter} from "./IExtensionAdapter";

Expand All @@ -15,4 +16,8 @@ export class TruffleExtensionAdapter implements IExtensionAdapter {
public async deploy() {
return TruffleCommands.deployContracts();
}

public async execScript(uri: Uri) {
return TruffleCommands.execScript(uri);
}
}
2 changes: 2 additions & 0 deletions test/TestConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,6 @@ export class TestConstants {
};

public static truffleCommandTestDataFolder: string = "testData";

public static truffleExecScriptExample: string = "script.js";
}
66 changes: 66 additions & 0 deletions test/TruffleCommandsTests/execScript.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright (c) Consensys Software Inc. All rights reserved.
// Licensed under the MIT license.

import assert from "assert";
import {SinonMock, SinonExpectation, SinonStub, mock, stub, restore} from "sinon";
import uuid from "uuid";
import {CancellationToken, Progress, ProgressOptions, window, Uri} from "vscode";
import {TruffleCommands} from "../../src/commands/TruffleCommands";
import * as helpers from "../../src/helpers";
import * as commands from "../../src/helpers/command";
import {TestConstants} from "../TestConstants";
import {join} from "path";

describe("ExecScript Command", () => {
describe("Integration test", async () => {
let requiredMock: SinonMock;
let getWorkspaceRootMock: any;
let checkAppsSilent: SinonExpectation;
let installTruffle: SinonExpectation;
let commandContextMock: SinonMock;
let executeCommandMock: SinonExpectation;
let withProgressStub: SinonStub<[ProgressOptions, (progress: Progress<any>, token: CancellationToken) => any], any>;

beforeEach(() => {
requiredMock = mock(helpers.required);

getWorkspaceRootMock = stub(helpers, "getWorkspaceRoot");
getWorkspaceRootMock.returns(uuid.v4());

checkAppsSilent = requiredMock.expects("checkAppsSilent");
installTruffle = requiredMock.expects("installTruffle");

commandContextMock = mock(commands);
executeCommandMock = commandContextMock.expects("executeCommand");

withProgressStub = stub(window, "withProgress");
withProgressStub.callsFake(async (...args: any[]) => {
return args[1]();
});
});

afterEach(() => {
restore();
});

it("should not throw exception when script executes successfully", async () => {
// Arrange
checkAppsSilent.returns(true);
executeCommandMock.returns(uuid.v4());

// Act
const scriptPath = join(
__dirname,
TestConstants.truffleCommandTestDataFolder,
TestConstants.truffleExecScriptExample
);
await TruffleCommands.execScript(Uri.file(scriptPath));

// Assert
assert.strictEqual(checkAppsSilent.calledOnce, true, "checkAppsSilent should be called once");
assert.strictEqual(getWorkspaceRootMock.calledOnce, true, "getWorkspaceRoot should be called once");
assert.strictEqual(installTruffle.called, false, "installTruffle should not be called");
assert.strictEqual(executeCommandMock.called, true, "executeCommand should be called");
});
});
});
12 changes: 12 additions & 0 deletions test/TruffleCommandsTests/testData/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const TestContract = artifacts.require("./TestContract");

const main = async (cb) => {
try {
const accounts = await web3.eth.getAccounts();
} catch(err) {
console.log('Doh! ', err.message);
}
cb();
}

module.exports = main;
11 changes: 11 additions & 0 deletions test/TruffleExtensionAdapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,18 @@ import assert from "assert";
import sinon from "sinon";
import {TruffleCommands} from "../src/commands/TruffleCommands";
import {TruffleExtensionAdapter} from "../src/services/extensionAdapter";
import {Uri} from "vscode";

describe("TruffleExtensionAdapter", () => {
let buildContractsMock: sinon.SinonStub<any>;
let deployContractsMock: sinon.SinonStub<any>;
let execScriptMock: sinon.SinonStub<any>;
let truffleExtensionAdapter: TruffleExtensionAdapter;

beforeEach(() => {
buildContractsMock = sinon.stub(TruffleCommands, "buildContracts");
deployContractsMock = sinon.stub(TruffleCommands, "deployContracts");
execScriptMock = sinon.stub(TruffleCommands, "execScript");

truffleExtensionAdapter = new TruffleExtensionAdapter();
});
Expand All @@ -37,4 +40,12 @@ describe("TruffleExtensionAdapter", () => {
// Assert
assert.strictEqual(deployContractsMock.calledOnce, true, "TruffleCommands.deployContracts should be called once");
});

it("exec method should call truffleCommands.execScript", async () => {
// Act
await truffleExtensionAdapter.execScript(Uri.file("./test.js"));

// Assert
assert.strictEqual(execScriptMock.calledOnce, true, "TruffleCommands.execScript should be called once");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similarly should this test mock something lower down and return a true/false on the success/failure of the exec call?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

possibly 🙃 do you mean whether the script actually executes (irrespective of its success / failure)? i feel this is more of a QOL of update and whether the script actually succeeds / fails doesn't matter too much as long as the output is accessible (as per the above)...it would be awesome if it auto-open to the output channel though

});
});