Skip to content

Commit 61c4345

Browse files
authored
cherry pick 6fae1bd (#8416)
1 parent b8a7d30 commit 61c4345

File tree

13 files changed

+262
-169
lines changed

13 files changed

+262
-169
lines changed

Tasks/CondaEnvironmentV1/Strings/resources.resjson/en-US/resources.resjson

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@
2323
"loc.messages.InstallFailed": "Failed to install packages. %s",
2424
"loc.messages.ReactivateExistingEnvironment": "Found existing environment %s and the task's \"Clean environment\" parameter is not set. Reactivating ...",
2525
"loc.messages.ParameterRequired": "The `%s` parameter is required",
26-
"loc.messages.PlatformNotRecognized": "Platform not recognized"
26+
"loc.messages.PlatformNotRecognized": "Platform not recognized",
27+
"loc.messages.PrependPath": "Prepending PATH environment variable with directory: %s"
2728
}

Tasks/CondaEnvironmentV1/Tests/L0.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import * as path from 'path';
44

55
import { MockTestRunner } from 'vsts-task-lib/mock-test';
66

7+
import { getPlatform, Platform } from '../taskutil';
8+
79
describe('CondaEnvironment L0 Suite', function () {
810
describe('conda.ts', function () {
911
require('./L0_conda');
@@ -19,7 +21,12 @@ describe('CondaEnvironment L0 Suite', function () {
1921

2022
testRunner.run();
2123

22-
assert(testRunner.ran(`conda create --quiet --prefix ${path.join('/', 'miniconda', 'envs', 'test')} --mkdir --yes`));
24+
if (getPlatform() === Platform.Windows) {
25+
assert(testRunner.ran('conda create --quiet --prefix \\miniconda\\envs\\test --mkdir --yes'));
26+
} else {
27+
assert(testRunner.ran('sudo conda create --quiet --prefix /miniconda/envs/test --mkdir --yes'));
28+
}
29+
2330
assert.strictEqual(testRunner.stderr.length, 0, 'should not have written to stderr');
2431
assert(testRunner.succeeded, 'task should have succeeded');
2532
});
@@ -30,7 +37,12 @@ describe('CondaEnvironment L0 Suite', function () {
3037

3138
testRunner.run();
3239

33-
assert(testRunner.ran('conda install python=3 --quiet --yes --json'));
40+
if (getPlatform() === Platform.Windows) {
41+
assert(testRunner.ran('conda install python=3 --quiet --yes --json'));
42+
} else {
43+
assert(testRunner.ran('sudo conda install python=3 --quiet --yes --json'));
44+
}
45+
3446
assert.strictEqual(testRunner.stderr.length, 0, 'should not have written to stderr');
3547
assert(testRunner.succeeded, 'task should have succeeded');
3648
});

Tasks/CondaEnvironmentV1/Tests/L0BaseEnvironment.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,19 @@ taskRunner.setAnswers({
1616
'conda': '/miniconda/bin/conda'
1717
},
1818
exec: {
19+
'sudo conda install python=3 --quiet --yes --json': {
20+
code: 0
21+
},
1922
'conda install python=3 --quiet --yes --json': {
20-
'code': 0
21-
}
23+
code: 0
24+
},
25+
'/miniconda/bin/conda info --base': {
26+
code: 0,
27+
stdout: '/base/environment'
28+
},
29+
},
30+
checkPath: {
31+
'/miniconda/bin/conda': true
2232
}
2333
});
2434

Tasks/CondaEnvironmentV1/Tests/L0CreateEnvironment.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ taskRunner.setAnswers({
1616
'conda': '/miniconda/bin/conda'
1717
},
1818
exec: {
19-
'conda create --quiet --prefix /miniconda/envs/test --mkdir --yes': {
20-
'code': 0
19+
'sudo conda create --quiet --prefix /miniconda/envs/test --mkdir --yes': {
20+
code: 0
2121
},
2222
'conda create --quiet --prefix \\miniconda\\envs\\test --mkdir --yes': {
23-
'code': 0
23+
code: 0
2424
},
2525
}
2626
});

Tasks/CondaEnvironmentV1/Tests/L0_conda.ts

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ it('creates and activates environment', async function () {
5959
await uut.condaEnvironment(parameters, Platform.Linux);
6060
assert(findConda.calledOnceWithExactly(Platform.Linux));
6161
assert(prependCondaToPath.calledOnceWithExactly('path-to-conda', Platform.Linux));
62-
assert(createEnvironment.calledOnceWithExactly(path.join('path-to-conda', 'envs', 'env'), undefined, undefined));
62+
assert(createEnvironment.calledOnceWithExactly(path.join('path-to-conda', 'envs', 'env'), Platform.Linux, undefined, undefined));
6363
assert(activateEnvironment.calledOnceWithExactly(path.join('path-to-conda', 'envs'), 'env', Platform.Linux));
6464
});
6565

@@ -124,7 +124,7 @@ it('updates Conda if the user requests it', async function () {
124124
assert(updateConda.calledOnceWithExactly('path-to-conda', Platform.Linux));
125125
});
126126

127-
it('fails if `conda` is not found', async function (done: MochaDone) {
127+
it('fails if `conda` is not found', async function () {
128128
mockery.registerMock('fs', {
129129
existsSync: () => false
130130
});
@@ -147,15 +147,57 @@ it('fails if `conda` is not found', async function (done: MochaDone) {
147147
updateConda: false
148148
};
149149

150+
// Can't use `assert.throws` with an async function
151+
// Node 10: use `assert.rejects`
152+
let error: any | undefined;
150153
try {
151154
await uut.condaEnvironment(parameters, Platform.Windows);
152-
done(new Error('should not have succeeded'));
153155
} catch (e) {
154-
assert.strictEqual(e.message, 'loc_mock_CondaNotFound');
155-
assert(findConda.calledOnceWithExactly(Platform.Windows));
156-
assert(prependCondaToPath.notCalled);
157-
assert(createEnvironment.notCalled);
158-
assert(activateEnvironment.notCalled);
159-
done();
156+
error = e;
160157
}
161-
});
158+
159+
assert(error instanceof Error);
160+
assert.strictEqual(error.message, 'loc_mock_CondaNotFound');
161+
162+
assert(findConda.calledOnceWithExactly(Platform.Windows));
163+
assert(prependCondaToPath.notCalled);
164+
assert(createEnvironment.notCalled);
165+
assert(activateEnvironment.notCalled);
166+
});
167+
168+
it('fails if installing packages to the base environment fails', async function () {
169+
mockery.registerMock('vsts-task-lib/task', mockTask);
170+
171+
const findConda = sinon.stub().returns('path-to-conda');
172+
const prependCondaToPath = sinon.spy();
173+
const installPackagesGlobally = sinon.stub().rejects(new Error('installPackagesGlobally'));
174+
175+
mockery.registerMock('./conda_internal', {
176+
findConda: findConda,
177+
prependCondaToPath: prependCondaToPath,
178+
installPackagesGlobally: installPackagesGlobally
179+
});
180+
181+
const uut = reload('../conda');
182+
const parameters = {
183+
createCustomEnvironment: false,
184+
packageSpecs: 'pytest',
185+
updateConda: false
186+
};
187+
188+
// Can't use `assert.throws` with an async function
189+
// Node 10: use `assert.rejects`
190+
let error: any | undefined;
191+
try {
192+
await uut.condaEnvironment(parameters, Platform.Linux);
193+
} catch (e) {
194+
error = e;
195+
}
196+
197+
assert(error instanceof Error);
198+
assert.strictEqual(error.message, 'installPackagesGlobally');
199+
200+
assert(findConda.calledOnceWithExactly(Platform.Linux));
201+
assert(prependCondaToPath.calledOnceWithExactly('path-to-conda', Platform.Linux));
202+
assert(installPackagesGlobally.calledOnceWithExactly('pytest', Platform.Linux, undefined));
203+
});

Tasks/CondaEnvironmentV1/Tests/L0_conda_internal.ts

Lines changed: 88 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,6 @@ it('finds the Conda installation with the CONDA variable', async function () {
5353
getVariable: getVariable
5454
}));
5555

56-
mockery.registerMock('vsts-task-tool-lib/tool', {});
57-
5856
{ // executable exists and is a file
5957
existsSync.returns(true);
6058
statSync.returns({
@@ -114,55 +112,71 @@ it('finds the Conda installation with PATH', async function () {
114112
getVariable: getVariable
115113
}));
116114

117-
mockery.registerMock('vsts-task-tool-lib/tool', {});
118-
119115
const uut = reload('../conda_internal');
120116

121117
assert.strictEqual(uut.findConda(Platform.Linux), 'path-to-conda');
122118
assert.strictEqual(uut.findConda(Platform.MacOS), 'path-to-conda');
123119
assert.strictEqual(uut.findConda(Platform.Windows), 'path-to-conda');
124120
});
125121

126-
it('creates Conda environment', async function (done: MochaDone) {
122+
it('creates Conda environment', async function () {
127123
mockery.registerMock('vsts-task-lib/task', mockTask);
128124
mockery.registerMock('vsts-task-lib/toolrunner', mockToolRunner);
129-
mockery.registerMock('vsts-task-tool-lib/tool', {});
130125
const uut = reload('../conda_internal');
131126

132-
{ // success
133-
mockToolRunner.setAnswers({
134-
exec: {
135-
'conda create --quiet --prefix envsDir/env --mkdir --yes': {
136-
code: 0
137-
},
138-
// workaround for running tests cross-platform
139-
'conda create --quiet --prefix envsDir\\env --mkdir --yes': {
140-
code: 0
141-
}
127+
for (const platform of [Platform.Windows, Platform.Linux, Platform.MacOS])
128+
{
129+
{ // success
130+
if (platform === Platform.Windows) {
131+
mockToolRunner.setAnswers({
132+
exec: {
133+
[`conda create --quiet --prefix ${path.join('envsDir', 'env')} --mkdir --yes`]: {
134+
code: 0
135+
}
136+
}
137+
});
138+
} else {
139+
mockToolRunner.setAnswers({
140+
exec: {
141+
[`sudo conda create --quiet --prefix ${path.join('envsDir', 'env')} --mkdir --yes`]: {
142+
code: 0
143+
}
144+
}
145+
});
142146
}
143-
});
144147

145-
await uut.createEnvironment(path.join('envsDir', 'env'));
146-
}
147-
{ // failure
148-
mockToolRunner.setAnswers({
149-
exec: {
150-
'conda create --quiet --prefix envsDir/env --mkdir --yes': {
151-
code: 1
152-
},
153-
// workaround for running tests cross-platform
154-
'conda create --quiet --prefix envsDir\\env --mkdir --yes': {
155-
code: 1
156-
}
148+
await uut.createEnvironment(path.join('envsDir', 'env'), platform);
149+
}
150+
{ // failure
151+
if (platform === Platform.Windows) {
152+
mockToolRunner.setAnswers({
153+
exec: {
154+
[`conda create --quiet --prefix ${path.join('envsDir', 'env')} --mkdir --yes`]: {
155+
code: 1
156+
}
157+
}
158+
});
159+
} else {
160+
mockToolRunner.setAnswers({
161+
exec: {
162+
[`sudo conda create --quiet --prefix ${path.join('envsDir', 'env')} --mkdir --yes`]: {
163+
code: 1
164+
}
165+
}
166+
});
157167
}
158-
});
159168

160-
try {
161-
await uut.createEnvironment(path.join('envsDir', 'env'));
162-
done(new Error('should not have succeeded'));
163-
} catch (e) {
164-
assert.strictEqual(e.message, `loc_mock_CreateFailed ${path.join('envsDir', 'env')} Error: conda failed with return code: 1`);
165-
done();
169+
// Can't use `assert.throws` with an async function
170+
// Node 10: use `assert.rejects`
171+
let error: any | undefined;
172+
try {
173+
await uut.createEnvironment(path.join('envsDir', 'env'), platform);
174+
} catch (e) {
175+
error = e;
176+
}
177+
178+
assert(error instanceof Error);
179+
assert.strictEqual(error.message, `loc_mock_CreateFailed ${path.join('envsDir', 'env')} Error: ${platform === Platform.Windows ? 'conda' : 'sudo'} failed with return code: 1`);
166180
}
167181
}
168182
});
@@ -173,37 +187,66 @@ it('activates Conda environment', async function () {
173187
setVariable: setVariable
174188
}));
175189

176-
const prependPath = sinon.spy();
177-
mockery.registerMock('vsts-task-tool-lib/tool', {
178-
prependPath: prependPath
190+
const prependPathSafe = sinon.spy();
191+
mockery.registerMock('./toolutil', {
192+
prependPathSafe: prependPathSafe
179193
});
180194

181195
const uut = reload('../conda_internal');
182196

183197
{ // Linux
184198
uut.activateEnvironment('envs', 'env', Platform.Linux);
185-
assert(prependPath.calledOnceWithExactly(path.join('envs', 'env', 'bin')));
199+
assert(prependPathSafe.calledOnceWithExactly(path.join('envs', 'env', 'bin')));
186200
assert(setVariable.calledTwice);
187201
assert(setVariable.calledWithExactly('CONDA_DEFAULT_ENV', 'env'));
188202
assert(setVariable.calledWithExactly('CONDA_PREFIX', path.join('envs', 'env')));
189203
}
190204
{ // macOS
191205
setVariable.resetHistory();
192-
prependPath.resetHistory();
206+
prependPathSafe.resetHistory();
193207
uut.activateEnvironment('envs', 'env', Platform.MacOS);
194-
assert(prependPath.calledOnceWithExactly(path.join('envs', 'env', 'bin')));
208+
assert(prependPathSafe.calledOnceWithExactly(path.join('envs', 'env', 'bin')));
195209
assert(setVariable.calledTwice);
196210
assert(setVariable.calledWithExactly('CONDA_DEFAULT_ENV', 'env'));
197211
assert(setVariable.calledWithExactly('CONDA_PREFIX', path.join('envs', 'env')));
198212
}
199213
{ // Windows
200214
setVariable.resetHistory();
201-
prependPath.resetHistory();
215+
prependPathSafe.resetHistory();
202216
uut.activateEnvironment('envs', 'env', Platform.Windows);
203-
assert(prependPath.calledWithExactly(path.join('envs', 'env')));
204-
assert(prependPath.calledWithExactly(path.join('envs', 'env', 'Scripts')));
217+
assert(prependPathSafe.calledWithExactly(path.join('envs', 'env')));
218+
assert(prependPathSafe.calledWithExactly(path.join('envs', 'env', 'Scripts')));
205219
assert(setVariable.calledTwice);
206220
assert(setVariable.calledWithExactly('CONDA_DEFAULT_ENV', 'env'));
207221
assert(setVariable.calledWithExactly('CONDA_PREFIX', path.join('envs', 'env')));
208222
}
223+
});
224+
225+
it('adds base environment to path successfully', function () {
226+
mockTask.setAnswers({
227+
which: {
228+
'conda': '/miniconda/bin/conda'
229+
},
230+
exec: {
231+
'/miniconda/bin/conda info --base': {
232+
code: 0,
233+
stdout: '/base/environment'
234+
}
235+
},
236+
checkPath: {
237+
'/miniconda/bin/conda': true
238+
}
239+
});
240+
241+
mockery.registerMock('vsts-task-lib/task', mockTask);
242+
243+
const prependPathSafe = sinon.spy();
244+
mockery.registerMock('./toolutil', {
245+
prependPathSafe: prependPathSafe
246+
});
247+
248+
const uut = reload('../conda_internal');
249+
uut.addBaseEnvironmentToPath(Platform.Linux);
250+
251+
assert(prependPathSafe.calledOnceWithExactly(path.join('/base/environment', 'bin')));
209252
});

0 commit comments

Comments
 (0)