Skip to content

Commit c7e7147

Browse files
authored
Add ability to write resolved version of SDK into the output variable (#324)
1 parent 0705ef0 commit c7e7147

File tree

9 files changed

+254
-15
lines changed

9 files changed

+254
-15
lines changed

.github/workflows/workflow.yml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,60 @@ jobs:
237237
$version = & dotnet --version
238238
Write-Host "Installed version: $version"
239239
if (-not ($version.Contains("preview") -or $version.Contains("rc"))) { throw "Unexpected version" }
240+
241+
test-dotnet-version-output-during-single-version-installation:
242+
runs-on: ${{ matrix.operating-system }}
243+
strategy:
244+
fail-fast: false
245+
matrix:
246+
operating-system: [ubuntu-latest, windows-latest, macOS-latest]
247+
steps:
248+
- name: Checkout
249+
uses: actions/checkout@v3
250+
- name: Clear toolcache
251+
shell: pwsh
252+
run: __tests__/clear-toolcache.ps1 ${{ runner.os }}
253+
254+
- name: Setup dotnet 6.0.401
255+
uses: ./
256+
id: step1
257+
with:
258+
dotnet-version: "6.0.401"
259+
260+
- name: Verify value of the dotnet-version output
261+
shell: pwsh
262+
run: |
263+
$version = & dotnet --version
264+
Write-Host "Installed version: $version"
265+
if (-not ($version -eq '${{steps.step1.outputs.dotnet-version}}')) { throw "Unexpected output value" }
266+
267+
test-dotnet-version-output-during-multiple-version-installation:
268+
runs-on: ${{ matrix.operating-system }}
269+
strategy:
270+
fail-fast: false
271+
matrix:
272+
operating-system: [ubuntu-latest, windows-latest, macOS-latest]
273+
steps:
274+
- name: Checkout
275+
uses: actions/checkout@v3
276+
- name: Clear toolcache
277+
shell: pwsh
278+
run: __tests__/clear-toolcache.ps1 ${{ runner.os }}
279+
280+
- name: Setup dotnet 6.0.401, 5.0.408, 7.0.100-rc.1.22431.12
281+
uses: ./
282+
id: step2
283+
with:
284+
dotnet-version: |
285+
7.0.100-rc.1.22431.12
286+
6.0.401
287+
5.0.408
288+
289+
- name: Verify value of the dotnet-version output
290+
shell: pwsh
291+
run: |
292+
$version = "7.0.100-rc.1.22431.12"
293+
if (-not ($version -eq '${{steps.step2.outputs.dotnet-version}}')) { throw "Unexpected output value" }
240294
241295
test-proxy:
242296
runs-on: ubuntu-latest

README.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,54 @@ steps:
141141
```
142142
> **Note**: It's the only way to push a package to nuget.org feed for macOS/Linux machines due to API key config store limitations.
143143

144+
# Outputs and environment variables
145+
146+
## Outputs
147+
148+
### `dotnet-version`
149+
150+
Using the **dotnet-version** output it's possible to get the installed by the action .NET SDK version.
151+
152+
**Single version installation**
153+
154+
In case of a single version installation, the `dotnet-version` output contains the version that is installed by the action.
155+
156+
```yaml
157+
- uses: actions/setup-dotnet@v3
158+
id: cp310
159+
with:
160+
dotnet-version: 3.1.422
161+
- run: echo '${{ steps.cp310.outputs.dotnet-version }}' # outputs 3.1.422
162+
```
163+
164+
**Multiple version installation**
165+
166+
In case of a multiple version installation, the `dotnet-version` output contains the latest version that is installed by the action.
167+
168+
```yaml
169+
- uses: actions/setup-dotnet@v3
170+
id: cp310
171+
with:
172+
dotnet-version: |
173+
3.1.422
174+
5.0.408
175+
- run: echo '${{ steps.cp310.outputs.dotnet-version }}' # outputs 5.0.408
176+
```
177+
**Installation from global.json**
178+
179+
When the `dotnet-version` input is used along with the `global-json-file` input, the `dotnet-version` output contains the version resolved from the `global.json`.
180+
181+
```yaml
182+
- uses: actions/setup-dotnet@v3
183+
id: cp310
184+
with:
185+
dotnet-version: |
186+
3.1.422
187+
5.0.408
188+
global-json-file: "./global.json" # contains version 2.2.207
189+
- run: echo '${{ steps.cp310.outputs.dotnet-version }}' # outputs 2.2.207
190+
```
191+
144192
## Environment variables
145193

146194
Some environment variables may be necessary for your particular case or to improve logging. Some examples are listed below, but the full list with complete details can be found here: https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-environment-variables

__tests__/installer.test.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,15 @@ describe('DotnetCoreInstaller tests', () => {
107107
expect(process.env.PATH?.startsWith(toolDir)).toBe(true);
108108
}, 600000); //This needs some time to download on "slower" internet connections
109109

110+
it('Returns string with installed SDK version', async () => {
111+
const version = '3.1.120';
112+
let installedVersion: string;
113+
114+
installedVersion = await getDotnet(version);
115+
116+
expect(installedVersion).toBe('3.1.120');
117+
}, 600000);
118+
110119
it('Throws if no location contains correct dotnet version', async () => {
111120
await expect(async () => {
112121
await getDotnet('1000.0.0');
@@ -267,11 +276,15 @@ function normalizeFileContents(contents: string): string {
267276
.replace(new RegExp('\r', 'g'), '\n');
268277
}
269278

270-
async function getDotnet(version: string, quality: string = ''): Promise<void> {
279+
async function getDotnet(
280+
version: string,
281+
quality: string = ''
282+
): Promise<string> {
271283
const dotnetInstaller = new installer.DotnetCoreInstaller(
272284
version,
273285
quality as QualityOptions
274286
);
275-
await dotnetInstaller.installDotnet();
287+
const installedVersion = await dotnetInstaller.installDotnet();
276288
installer.DotnetCoreInstaller.addToPath();
289+
return installedVersion;
277290
}

__tests__/setup-dotnet.test.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as io from '@actions/io';
2+
import * as core from '@actions/core';
23
import fs from 'fs';
34
import os from 'os';
45
import path from 'path';
@@ -20,6 +21,12 @@ if (IS_WINDOWS) {
2021
const tempDir = path.join(__dirname, 'runner', 'temp2');
2122

2223
describe('setup-dotnet tests', () => {
24+
let getInputSpy = jest.spyOn(core, 'getInput');
25+
let getMultilineInputSpy = jest.spyOn(core, 'getMultilineInput');
26+
let setOutputSpy = jest.spyOn(core, 'setOutput');
27+
28+
let inputs = {} as any;
29+
2330
beforeAll(async () => {
2431
process.env.RUNNER_TOOL_CACHE = toolDir;
2532
process.env.DOTNET_INSTALL_DIR = toolDir;
@@ -59,4 +66,33 @@ describe('setup-dotnet tests', () => {
5966
expect(fs.existsSync(path.join(toolDir, 'dotnet'))).toBe(true);
6067
}
6168
}, 400000);
69+
70+
it("Sets output with the latest installed by action version if global.json file isn't specified", async () => {
71+
inputs['dotnet-version'] = ['3.1.201', '6.0.401'];
72+
73+
getMultilineInputSpy.mockImplementation(input => inputs[input]);
74+
75+
await setup.run();
76+
77+
expect(setOutputSpy).toBeCalledWith('dotnet-version', '6.0.401');
78+
}, 400000);
79+
80+
it("Sets output with the version specified in global.json, if it's present", async () => {
81+
const globalJsonPath = path.join(process.cwd(), 'global.json');
82+
const jsonContents = `{${os.EOL}"sdk": {${os.EOL}"version": "3.0.103"${os.EOL}}${os.EOL}}`;
83+
if (!fs.existsSync(globalJsonPath)) {
84+
fs.writeFileSync(globalJsonPath, jsonContents);
85+
}
86+
87+
inputs['dotnet-version'] = ['3.1.201', '6.0.401'];
88+
inputs['global-json-file'] = './global.json';
89+
90+
getMultilineInputSpy.mockImplementation(input => inputs[input]);
91+
92+
getInputSpy.mockImplementation(input => inputs[input]);
93+
94+
await setup.run();
95+
96+
expect(setOutputSpy).toBeCalledWith('dotnet-version', '3.0.103');
97+
}, 400000);
6298
});

action.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ inputs:
1717
description: 'Optional OWNER for using packages from GitHub Package Registry organizations/users other than the current repository''s owner. Only used if a GPR URL is also provided in source-url'
1818
config-file:
1919
description: 'Optional NuGet.config location, if your NuGet.config isn''t located in the root of the repo.'
20+
outputs:
21+
dotnet-version:
22+
description: 'Contains the installed by action .NET SDK version for reuse.'
2023
runs:
2124
using: 'node16'
2225
main: 'dist/index.js'

dist/index.js

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ const exec = __importStar(__nccwpck_require__(1514));
189189
const io = __importStar(__nccwpck_require__(7436));
190190
const hc = __importStar(__nccwpck_require__(6255));
191191
const fs_1 = __nccwpck_require__(7147);
192+
const promises_1 = __nccwpck_require__(3292);
192193
const path_1 = __importDefault(__nccwpck_require__(1017));
193194
const semver_1 = __importDefault(__nccwpck_require__(5911));
194195
const utils_1 = __nccwpck_require__(918);
@@ -284,8 +285,8 @@ class DotnetCoreInstaller {
284285
}
285286
else {
286287
// This is the default set in install-dotnet.sh
287-
core.addPath(path_1.default.join(process.env['HOME'] + '', '.dotnet'));
288-
core.exportVariable('DOTNET_ROOT', path_1.default.join(process.env['HOME'] + '', '.dotnet'));
288+
core.addPath(DotnetCoreInstaller.installationDirectoryMac);
289+
core.exportVariable('DOTNET_ROOT', DotnetCoreInstaller.installationDirectoryMac);
289290
}
290291
}
291292
}
@@ -332,11 +333,11 @@ class DotnetCoreInstaller {
332333
if (process.env['no_proxy'] != null) {
333334
scriptArguments.push(`-ProxyBypassList ${process.env['no_proxy']}`);
334335
}
335-
scriptArguments.push(`-InstallDir '${DotnetCoreInstaller.installationDirectoryWindows}'`);
336+
scriptArguments.push('-InstallDir', `'${DotnetCoreInstaller.installationDirectoryWindows}'`);
336337
// process.env must be explicitly passed in for DOTNET_INSTALL_DIR to be used
337338
scriptPath =
338339
(yield io.which('pwsh', false)) || (yield io.which('powershell', true));
339-
scriptArguments = [...windowsDefaultOptions, scriptArguments.join(' ')];
340+
scriptArguments = windowsDefaultOptions.concat(scriptArguments);
340341
}
341342
else {
342343
fs_1.chmodSync(escapedScript, '777');
@@ -351,17 +352,31 @@ class DotnetCoreInstaller {
351352
if (utils_1.IS_LINUX) {
352353
scriptArguments.push('--install-dir', DotnetCoreInstaller.installationDirectoryLinux);
353354
}
355+
if (utils_1.IS_MAC) {
356+
scriptArguments.push('--install-dir', DotnetCoreInstaller.installationDirectoryMac);
357+
}
354358
}
355359
const { exitCode, stdout } = yield exec.getExecOutput(`"${scriptPath}"`, scriptArguments, { ignoreReturnCode: true });
356360
if (exitCode) {
357361
throw new Error(`Failed to install dotnet ${exitCode}. ${stdout}`);
358362
}
363+
return this.outputDotnetVersion(dotnetVersion.value, scriptArguments[scriptArguments.length - 1]);
364+
});
365+
}
366+
outputDotnetVersion(version, installationPath) {
367+
return __awaiter(this, void 0, void 0, function* () {
368+
let versionsOnRunner = yield promises_1.readdir(path_1.default.join(installationPath.replace(/'/g, ''), 'sdk'));
369+
let installedVersion = semver_1.default.maxSatisfying(versionsOnRunner, version, {
370+
includePrerelease: true
371+
});
372+
return installedVersion;
359373
});
360374
}
361375
}
362376
exports.DotnetCoreInstaller = DotnetCoreInstaller;
363377
DotnetCoreInstaller.installationDirectoryWindows = path_1.default.join(process.env['PROGRAMFILES'] + '', 'dotnet');
364378
DotnetCoreInstaller.installationDirectoryLinux = '/usr/share/dotnet';
379+
DotnetCoreInstaller.installationDirectoryMac = path_1.default.join(process.env['HOME'] + '', '.dotnet');
365380

366381

367382
/***/ }),
@@ -408,6 +423,7 @@ const core = __importStar(__nccwpck_require__(2186));
408423
const installer_1 = __nccwpck_require__(1480);
409424
const fs = __importStar(__nccwpck_require__(7147));
410425
const path_1 = __importDefault(__nccwpck_require__(1017));
426+
const semver_1 = __importDefault(__nccwpck_require__(5911));
411427
const auth = __importStar(__nccwpck_require__(8527));
412428
const qualityOptions = [
413429
'daily',
@@ -429,6 +445,7 @@ function run() {
429445
// Proxy, auth, (etc) are still set up, even if no version is identified
430446
//
431447
const versions = core.getMultilineInput('dotnet-version');
448+
const installedDotnetVersions = [];
432449
const globalJsonFileInput = core.getInput('global-json-file');
433450
if (globalJsonFileInput) {
434451
const globalJsonPath = path_1.default.join(process.cwd(), globalJsonFileInput);
@@ -454,7 +471,8 @@ function run() {
454471
const uniqueVersions = new Set(versions);
455472
for (const version of uniqueVersions) {
456473
dotnetInstaller = new installer_1.DotnetCoreInstaller(version, quality);
457-
yield dotnetInstaller.installDotnet();
474+
const installedVersion = yield dotnetInstaller.installDotnet();
475+
installedDotnetVersions.push(installedVersion);
458476
}
459477
installer_1.DotnetCoreInstaller.addToPath();
460478
}
@@ -463,6 +481,13 @@ function run() {
463481
if (sourceUrl) {
464482
auth.configAuthentication(sourceUrl, configFile);
465483
}
484+
const comparisonRange = globalJsonFileInput
485+
? versions[versions.length - 1]
486+
: '*';
487+
const versionToOutput = semver_1.default.maxSatisfying(installedDotnetVersions, comparisonRange, {
488+
includePrerelease: true
489+
});
490+
core.setOutput('dotnet-version', versionToOutput);
466491
const matchersPath = path_1.default.join(__dirname, '..', '.github');
467492
core.info(`##[add-matcher]${path_1.default.join(matchersPath, 'csc.json')}`);
468493
}
@@ -498,9 +523,10 @@ run();
498523
"use strict";
499524

500525
Object.defineProperty(exports, "__esModule", ({ value: true }));
501-
exports.IS_LINUX = exports.IS_WINDOWS = void 0;
526+
exports.IS_MAC = exports.IS_LINUX = exports.IS_WINDOWS = void 0;
502527
exports.IS_WINDOWS = process.platform === 'win32';
503528
exports.IS_LINUX = process.platform === 'linux';
529+
exports.IS_MAC = process.platform === 'darwin';
504530

505531

506532
/***/ }),
@@ -25688,6 +25714,14 @@ module.exports = require("fs");
2568825714

2568925715
/***/ }),
2569025716

25717+
/***/ 3292:
25718+
/***/ ((module) => {
25719+
25720+
"use strict";
25721+
module.exports = require("fs/promises");
25722+
25723+
/***/ }),
25724+
2569125725
/***/ 3685:
2569225726
/***/ ((module) => {
2569325727

0 commit comments

Comments
 (0)