Skip to content

Commit f2bc911

Browse files
authored
Prepend pacPath to the PATH environment variable (#869)
1 parent bcebb8d commit f2bc911

File tree

4 files changed

+75
-22
lines changed

4 files changed

+75
-22
lines changed

src/host/CliLocator.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ import path = require('path');
44
import { pathExists, chmod } from 'fs-extra';
55

66
export async function findPacCLI(): Promise<string> {
7+
// cli-wrapper expects the root folder, see: src\pac\createPacRunner.ts
8+
return (await findPacCLIPath()).pacRootPath;
9+
}
10+
11+
export async function findPacCLIPath(): Promise<{ pacRootPath: string, pacPath: string }> {
712
const pacRootPath = path.resolve(__dirname, 'bin');
813
let pacPath: string;
914
switch (process.platform) {
@@ -20,6 +25,9 @@ export async function findPacCLI(): Promise<string> {
2025
if (!await pathExists(pacPath)) {
2126
throw new Error(`Cannot find required pac CLI executable under: ${pacPath}`);
2227
}
23-
// cli-wrapper expects the root folder, see: src\pac\createPacRunner.ts
24-
return pacRootPath;
28+
29+
const lastSlashIndex = pacPath.lastIndexOf("/");
30+
pacPath = pacPath.substring(0, lastSlashIndex);
31+
32+
return { pacRootPath, pacPath};
2533
}

src/tasks/tool-installer/tool-installer-v2/index.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,26 @@
22
// Licensed under the MIT License.
33

44
import * as tl from 'azure-pipelines-task-lib/task';
5-
import { findPacCLI } from '../../../host/CliLocator';
5+
import { findPacCLIPath } from '../../../host/CliLocator';
66
import { PacPathEnvVarName } from '../../../host/BuildToolsRunnerParams';
77

88
(async () => {
99
if (process.env['AGENT_JOBNAME']) {
10-
await main();
10+
await main();
1111
}
1212
})().catch(error => {
1313
tl.setResult(tl.TaskResult.Failed, error);
1414
});
1515

1616
export async function main(): Promise<void> {
17-
const pacPath = await findPacCLI();
17+
const addToolsToPath = tl.getInputRequired('AddToolsToPath').toLowerCase() === 'true';
18+
const { pacRootPath, pacPath } = await findPacCLIPath();
1819

19-
tl.debug(`Found required pac CLI executable under: ${pacPath}`);
20-
tl.debug(`Setting ${PacPathEnvVarName} : ${pacPath}`);
21-
tl.setVariable(PacPathEnvVarName, pacPath);
20+
tl.debug(`Found required pac CLI executable under: ${pacRootPath}`);
21+
tl.debug(`Setting ${PacPathEnvVarName} : ${pacRootPath}`);
22+
if (addToolsToPath) {
23+
tl.prependPath(pacPath);
24+
}
25+
tl.setVariable(PacPathEnvVarName, pacRootPath);
2226
}
2327

src/tasks/tool-installer/tool-installer-v2/task.json

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,15 @@
2929
"type": "boolean",
3030
"required": true,
3131
"helpMarkDown": "OBSOLETE: Current task implementations are no longer based on Powershell modules. This ToolInstaller task always installs the latest pac CLI (Power Platform CLI) that is available for this task extension. The additional task parameters are kept to avoid breaking changes with existing Azure DevOps pipelines.",
32-
"defaultValue":true
32+
"defaultValue": true
33+
},
34+
{
35+
"name": "AddToolsToPath",
36+
"label": "Adds the pac cli to the PATH environment variable",
37+
"type": "boolean",
38+
"required": false,
39+
"helpMarkDown": "Enables you to use pac cli from script tasks without needing to set up the path manually.",
40+
"defaultValue": false
3341
},
3442
{
3543
"name": "PowerAppsAdminVersion",
@@ -38,7 +46,7 @@
3846
"required": false,
3947
"helpMarkDown": "IGNORED: This version of the BuildTools no longer depends on any PowerShell modules; specifying any version value will be ignored",
4048
"defaultValue": "(obsolete)",
41-
"groupname":"advanced"
49+
"groupname": "advanced"
4250
},
4351
{
4452
"name": "XrmToolingPackageDeploymentVersion",
@@ -47,7 +55,7 @@
4755
"required": false,
4856
"helpMarkDown": "IGNORED: This version of the BuildTools no longer depends on any PowerShell modules; specifying any version value will be ignored",
4957
"defaultValue": "(obsolete)",
50-
"groupname":"advanced"
58+
"groupname": "advanced"
5159
},
5260
{
5361
"name": "MicrosoftPowerAppsCheckerVersion",
@@ -56,7 +64,7 @@
5664
"required": true,
5765
"helpMarkDown": "IGNORED: This version of the BuildTools no longer depends on any PowerShell modules; specifying any version value will be ignored",
5866
"defaultValue": "(obsolete)",
59-
"groupname":"advanced"
67+
"groupname": "advanced"
6068
},
6169
{
6270
"name": "CrmSdkCoreToolsVersion",
@@ -65,7 +73,7 @@
6573
"required": false,
6674
"helpMarkDown": "IGNORED: This version of the BuildTools no longer depends on any PowerShell modules; specifying any version value will be ignored",
6775
"defaultValue": "(obsolete)",
68-
"groupname":"advanced"
76+
"groupname": "advanced"
6977
},
7078
{
7179
"name": "XrmOnlineManagementApiVersion",
@@ -74,15 +82,15 @@
7482
"required": false,
7583
"helpMarkDown": "IGNORED: This version of the BuildTools no longer depends on any PowerShell modules; specifying any version value will be ignored",
7684
"defaultValue": "(obsolete)",
77-
"groupname":"advanced"
85+
"groupname": "advanced"
7886
}
7987
],
8088
"groups": [
8189
{
82-
"name": "advanced",
83-
"displayName": "Advanced",
84-
"isExpanded": false,
85-
"visibleRule": "DefaultVersion = false"
90+
"name": "advanced",
91+
"displayName": "Advanced",
92+
"isExpanded": false,
93+
"visibleRule": "DefaultVersion = false"
8694
}
8795
],
8896
"execution": {

test/unit-test/tool-installer.test.ts

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,56 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

4-
import { should, use } from "chai";
4+
import { assert, should, use } from "chai";
55
import * as sinonChai from "sinon-chai";
66
import rewiremock from "../rewiremock";
7+
import { debug } from "console";
8+
import { restore } from "sinon";
79
should();
810
use(sinonChai);
911

1012
describe("tool-installer tests", () => {
13+
const cliLocatorPath = "path/from/mocked/cli/locator";
14+
const cliExecutablePath = `${cliLocatorPath}/pac/tools`;
15+
const addToolsToPath = 'AddToolsToPath';
16+
let prependPathValue: string;
17+
let inputs: { [key: string]: string };
18+
let variables: { [key: string]: string };
19+
20+
beforeEach(() => {
21+
prependPathValue = '';
22+
inputs = {};
23+
variables = {};
24+
});
25+
afterEach(() => restore());
26+
1127
async function callActionWithMocks(): Promise<void> {
1228
const toolInstaller = await rewiremock.around(
1329
() => import("../../src/tasks/tool-installer/tool-installer-v2/index"),
14-
(mock : any) => {
15-
mock(() => import("../../src/host/CliLocator")).with({ findPacCLI: () => Promise.resolve("path/from/mocked/cli/locator") });
30+
(mock: any) => {
31+
mock(() => import("azure-pipelines-task-lib")).with({
32+
getInputRequired: (name: string) => inputs[name],
33+
setVariable: (name: string, val: string, secret?: boolean | undefined, isOutput?: boolean | undefined): void => {
34+
variables[name] = val;
35+
},
36+
debug: (message: string) => debug(message),
37+
prependPath: (path: string) => prependPathValue = path
38+
});
39+
mock(() => import("../../src/host/CliLocator")).with({
40+
findPacCLIPath: () => Promise.resolve({ pacRootPath: cliLocatorPath, pacPath: cliExecutablePath })
41+
});
1642
});
1743
await toolInstaller.main();
1844
}
1945

20-
it("call task", async () => {
46+
it("calls tool-installer", async () => {
47+
inputs[addToolsToPath] = 'false';
48+
await callActionWithMocks();
49+
});
50+
51+
it("call tool-installer with AddToolsToPath=true and calls prependPath.", async () => {
52+
inputs[addToolsToPath] = 'true';
2153
await callActionWithMocks();
54+
assert.equal(prependPathValue, cliExecutablePath);
2255
});
2356
});

0 commit comments

Comments
 (0)