Skip to content

Commit 27082ce

Browse files
Merge pull request #194 from aminya/arch
Arch option for setup-node
2 parents 4667755 + 05e7d6c commit 27082ce

File tree

9 files changed

+224
-48
lines changed

9 files changed

+224
-48
lines changed

.gitattributes

+4
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
1+
# Set default behavior to automatically normalize line endings, and force everything to be LF, except for Windows batch files that require CRLF, so that if a repo is accessed in Unix via a file share from Windows, the scripts will work.
2+
* text=auto eol=lf
3+
*.{cmd,[cC][mM][dD]} text eol=crlf
4+
*.{bat,[bB][aA][tT]} text eol=crlf
15
.licenses/** -diff linguist-generated=true

.github/workflows/versions.yml

+13
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,17 @@ jobs:
9696
node-version: 0.12.18
9797
- name: Verify node
9898
run: __tests__/verify-node.sh 0.12.18 SKIP_NPM
99+
shell: bash
100+
101+
arch:
102+
runs-on: windows-latest
103+
steps:
104+
- uses: actions/checkout@v2
105+
- name: Setup node 12 x86 from dist
106+
uses: ./
107+
with:
108+
node-version: '12'
109+
architecture: 'x86'
110+
- name: Verify node
111+
run: __tests__/verify-arch.sh "ia32"
99112
shell: bash

README.md

+55
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,61 @@ jobs:
7474
- run: npm test
7575
```
7676

77+
Architecture:
78+
79+
You can use any of the [supported operating systems](https://docs.github.com/en/actions/reference/virtual-environments-for-github-hosted-runners), and the compatible `architecture` can be selected using `architecture`. Values are `x86`, `x64`, `arm64`, `armv6l`, `armv7l`, `ppc64le`, `s390x` (not all of the architectures are available on all platforms).
80+
81+
When using `architecture`, `node-version` must be provided as well.
82+
```yaml
83+
jobs:
84+
build:
85+
runs-on: windows-latest
86+
name: Node sample
87+
steps:
88+
- uses: actions/checkout@v2
89+
- uses: actions/setup-node@v1
90+
with:
91+
node-version: '12'
92+
architecture: 'x64' # optional, x64 or x86. If not specified, x64 will be used by default
93+
- run: npm install
94+
- run: npm test
95+
```
96+
97+
Multiple Operating Systems and Architectures:
98+
99+
```yaml
100+
jobs:
101+
build:
102+
runs-on: ${{ matrix.os }}
103+
strategy:
104+
matrix:
105+
os:
106+
- ubuntu-latest
107+
- macos-latest
108+
- windows-latest
109+
node_version:
110+
- 10
111+
- 12
112+
- 14
113+
architecture:
114+
- x64
115+
# an extra windows-x86 run:
116+
include:
117+
- os: windows-2016
118+
node_version: 12
119+
architecture: x86
120+
name: Node ${{ matrix.node_version }} - ${{ matrix.architecture }} on ${{ matrix.os }}
121+
steps:
122+
- uses: actions/checkout@v2
123+
- name: Setup node
124+
uses: actions/setup-node@v1
125+
with:
126+
node-version: ${{ matrix.node_version }}
127+
architecture: ${{ matrix.architecture }}
128+
- run: npm install
129+
- run: npm test
130+
```
131+
77132
Publish to npmjs and GPR with npm:
78133
```yaml
79134
steps:

__tests__/installer.test.ts

+42-2
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ describe('setup-node', () => {
252252
expect(dlSpy).toHaveBeenCalled();
253253
expect(exSpy).toHaveBeenCalled();
254254
expect(logSpy).toHaveBeenCalledWith(
255-
`Acquiring ${resolvedVersion} from ${expectedUrl}`
255+
`Acquiring ${resolvedVersion} - ${os.arch} from ${expectedUrl}`
256256
);
257257
expect(logSpy).toHaveBeenCalledWith(
258258
`Attempting to download ${versionSpec}...`
@@ -341,6 +341,46 @@ describe('setup-node', () => {
341341
expect(cnSpy).toHaveBeenCalledWith(`::error::${errMsg}${osm.EOL}`);
342342
});
343343

344+
it('Acquires specified architecture of node', async () => {
345+
for (const {arch, version, osSpec} of [
346+
{arch: 'x86', version: '12.16.2', osSpec: 'win32'},
347+
{arch: 'x86', version: '14.0.0', osSpec: 'win32'}
348+
]) {
349+
os.platform = osSpec;
350+
os.arch = arch;
351+
const fileExtension = os.platform === 'win32' ? '7z' : 'tar.gz';
352+
const platform = {
353+
linux: 'linux',
354+
darwin: 'darwin',
355+
win32: 'win'
356+
}[os.platform];
357+
358+
inputs['node-version'] = version;
359+
inputs['architecture'] = arch;
360+
inputs['always-auth'] = false;
361+
inputs['token'] = 'faketoken';
362+
363+
let expectedUrl =
364+
arch === 'x64'
365+
? `https://github.com/actions/node-versions/releases/download/${version}/node-${version}-${platform}-${arch}.zip`
366+
: `https://nodejs.org/dist/v${version}/node-v${version}-${platform}-${arch}.${fileExtension}`;
367+
368+
// ... but not in the local cache
369+
findSpy.mockImplementation(() => '');
370+
371+
dlSpy.mockImplementation(async () => '/some/temp/path');
372+
let toolPath = path.normalize(`/cache/node/${version}/${arch}`);
373+
exSpy.mockImplementation(async () => '/some/other/temp/path');
374+
cacheSpy.mockImplementation(async () => toolPath);
375+
376+
await main.run();
377+
expect(dlSpy).toHaveBeenCalled();
378+
expect(logSpy).toHaveBeenCalledWith(
379+
`Acquiring ${version} - ${arch} from ${expectedUrl}`
380+
);
381+
}
382+
}, 100000);
383+
344384
describe('check-latest flag', () => {
345385
it('use local version and dont check manifest if check-latest is not specified', async () => {
346386
os.platform = 'linux';
@@ -403,7 +443,7 @@ describe('setup-node', () => {
403443
);
404444
expect(logSpy).toHaveBeenCalledWith("Resolved as '12.16.2'");
405445
expect(logSpy).toHaveBeenCalledWith(
406-
`Acquiring 12.16.2 from ${expectedUrl}`
446+
`Acquiring 12.16.2 - ${os.arch} from ${expectedUrl}`
407447
);
408448
expect(logSpy).toHaveBeenCalledWith('Extracting ...');
409449
});

__tests__/verify-arch.sh

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/bin/sh
2+
3+
if [ -n "$1" ]; then
4+
architecture="$(node -e 'console.log(process.arch)')"
5+
if [ -z "$(echo $architecture | grep --fixed-strings $1)" ]; then
6+
echo "Unexpected architecture"
7+
exit 1
8+
fi
9+
else
10+
echo "Skip testing architecture"
11+
fi

action.yml

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ inputs:
77
default: 'false'
88
node-version:
99
description: 'Version Spec of the version to use. Examples: 12.x, 10.15.1, >=10.15.0'
10+
architecture:
11+
description: 'Target architecture for Node to use. Examples: x86, x64. Will use system architecture by default.'
1012
check-latest:
1113
description: 'Set this option if you want the action to check for the latest available version that satisfies the version spec'
1214
default: false

dist/index.js

+35-23
Original file line numberDiff line numberDiff line change
@@ -4694,6 +4694,7 @@ const installer = __importStar(__webpack_require__(749));
46944694
const auth = __importStar(__webpack_require__(202));
46954695
const path = __importStar(__webpack_require__(622));
46964696
const url_1 = __webpack_require__(835);
4697+
const os = __webpack_require__(87);
46974698
function run() {
46984699
return __awaiter(this, void 0, void 0, function* () {
46994700
try {
@@ -4705,12 +4706,21 @@ function run() {
47054706
if (!version) {
47064707
version = core.getInput('version');
47074708
}
4709+
let arch = core.getInput('architecture');
4710+
// if architecture supplied but node-version is not
4711+
// if we don't throw a warning, the already installed x64 node will be used which is not probably what user meant.
4712+
if (arch && !version) {
4713+
core.warning('`architecture` is provided but `node-version` is missing. In this configuration, the version/architecture of Node will not be changed. To fix this, provide `architecture` in combination with `node-version`');
4714+
}
4715+
if (!arch) {
4716+
arch = os.arch();
4717+
}
47084718
if (version) {
47094719
let token = core.getInput('token');
47104720
let auth = !token || isGhes() ? undefined : `token ${token}`;
47114721
let stable = (core.getInput('stable') || 'true').toUpperCase() === 'TRUE';
47124722
const checkLatest = (core.getInput('check-latest') || 'false').toUpperCase() === 'TRUE';
4713-
yield installer.getNode(version, stable, checkLatest, auth);
4723+
yield installer.getNode(version, stable, checkLatest, auth, arch);
47144724
}
47154725
const registryUrl = core.getInput('registry-url');
47164726
const alwaysAuth = core.getInput('always-auth');
@@ -13093,13 +13103,13 @@ const tc = __importStar(__webpack_require__(533));
1309313103
const path = __importStar(__webpack_require__(622));
1309413104
const semver = __importStar(__webpack_require__(280));
1309513105
const fs = __webpack_require__(747);
13096-
function getNode(versionSpec, stable, checkLatest, auth) {
13106+
function getNode(versionSpec, stable, checkLatest, auth, arch = os.arch()) {
1309713107
return __awaiter(this, void 0, void 0, function* () {
1309813108
let osPlat = os.platform();
13099-
let osArch = translateArchToDistUrl(os.arch());
13109+
let osArch = translateArchToDistUrl(arch);
1310013110
if (checkLatest) {
1310113111
core.info('Attempt to resolve the latest version from manifest...');
13102-
const resolvedVersion = yield resolveVersionFromManifest(versionSpec, stable, auth);
13112+
const resolvedVersion = yield resolveVersionFromManifest(versionSpec, stable, auth, osArch);
1310313113
if (resolvedVersion) {
1310413114
versionSpec = resolvedVersion;
1310513115
core.info(`Resolved as '${versionSpec}'`);
@@ -13110,7 +13120,7 @@ function getNode(versionSpec, stable, checkLatest, auth) {
1311013120
}
1311113121
// check cache
1311213122
let toolPath;
13113-
toolPath = tc.find('node', versionSpec);
13123+
toolPath = tc.find('node', versionSpec, osArch);
1311413124
// If not found in cache, download
1311513125
if (toolPath) {
1311613126
core.info(`Found in cache @ ${toolPath}`);
@@ -13123,9 +13133,9 @@ function getNode(versionSpec, stable, checkLatest, auth) {
1312313133
// Try download from internal distribution (popular versions only)
1312413134
//
1312513135
try {
13126-
info = yield getInfoFromManifest(versionSpec, stable, auth);
13136+
info = yield getInfoFromManifest(versionSpec, stable, auth, osArch);
1312713137
if (info) {
13128-
core.info(`Acquiring ${info.resolvedVersion} from ${info.downloadUrl}`);
13138+
core.info(`Acquiring ${info.resolvedVersion} - ${info.arch} from ${info.downloadUrl}`);
1312913139
downloadPath = yield tc.downloadTool(info.downloadUrl, undefined, auth);
1313013140
}
1313113141
else {
@@ -13148,17 +13158,17 @@ function getNode(versionSpec, stable, checkLatest, auth) {
1314813158
// Download from nodejs.org
1314913159
//
1315013160
if (!downloadPath) {
13151-
info = yield getInfoFromDist(versionSpec);
13161+
info = yield getInfoFromDist(versionSpec, arch);
1315213162
if (!info) {
1315313163
throw new Error(`Unable to find Node version '${versionSpec}' for platform ${osPlat} and architecture ${osArch}.`);
1315413164
}
13155-
core.info(`Acquiring ${info.resolvedVersion} from ${info.downloadUrl}`);
13165+
core.info(`Acquiring ${info.resolvedVersion} - ${info.arch} from ${info.downloadUrl}`);
1315613166
try {
1315713167
downloadPath = yield tc.downloadTool(info.downloadUrl);
1315813168
}
1315913169
catch (err) {
1316013170
if (err instanceof tc.HTTPError && err.httpStatusCode == 404) {
13161-
return yield acquireNodeFromFallbackLocation(info.resolvedVersion);
13171+
return yield acquireNodeFromFallbackLocation(info.resolvedVersion, info.arch);
1316213172
}
1316313173
throw err;
1316413174
}
@@ -13189,7 +13199,7 @@ function getNode(versionSpec, stable, checkLatest, auth) {
1318913199
// Install into the local tool cache - node extracts with a root folder that matches the fileName downloaded
1319013200
//
1319113201
core.info('Adding to the cache ...');
13192-
toolPath = yield tc.cacheDir(extPath, 'node', info.resolvedVersion);
13202+
toolPath = yield tc.cacheDir(extPath, 'node', info.resolvedVersion, info.arch);
1319313203
core.info('Done');
1319413204
}
1319513205
//
@@ -13206,26 +13216,27 @@ function getNode(versionSpec, stable, checkLatest, auth) {
1320613216
});
1320713217
}
1320813218
exports.getNode = getNode;
13209-
function getInfoFromManifest(versionSpec, stable, auth) {
13219+
function getInfoFromManifest(versionSpec, stable, auth, osArch = translateArchToDistUrl(os.arch())) {
1321013220
return __awaiter(this, void 0, void 0, function* () {
1321113221
let info = null;
1321213222
const releases = yield tc.getManifestFromRepo('actions', 'node-versions', auth, 'main');
13213-
const rel = yield tc.findFromManifest(versionSpec, stable, releases);
13223+
const rel = yield tc.findFromManifest(versionSpec, stable, releases, osArch);
1321413224
if (rel && rel.files.length > 0) {
1321513225
info = {};
1321613226
info.resolvedVersion = rel.version;
13227+
info.arch = rel.files[0].arch;
1321713228
info.downloadUrl = rel.files[0].download_url;
1321813229
info.fileName = rel.files[0].filename;
1321913230
}
1322013231
return info;
1322113232
});
1322213233
}
13223-
function getInfoFromDist(versionSpec) {
13234+
function getInfoFromDist(versionSpec, arch = os.arch()) {
1322413235
return __awaiter(this, void 0, void 0, function* () {
1322513236
let osPlat = os.platform();
13226-
let osArch = translateArchToDistUrl(os.arch());
13237+
let osArch = translateArchToDistUrl(arch);
1322713238
let version;
13228-
version = yield queryDistForMatch(versionSpec);
13239+
version = yield queryDistForMatch(versionSpec, arch);
1322913240
if (!version) {
1323013241
return null;
1323113242
}
@@ -13241,14 +13252,15 @@ function getInfoFromDist(versionSpec) {
1324113252
return {
1324213253
downloadUrl: url,
1324313254
resolvedVersion: version,
13255+
arch: arch,
1324413256
fileName: fileName
1324513257
};
1324613258
});
1324713259
}
13248-
function resolveVersionFromManifest(versionSpec, stable, auth) {
13260+
function resolveVersionFromManifest(versionSpec, stable, auth, osArch = translateArchToDistUrl(os.arch())) {
1324913261
return __awaiter(this, void 0, void 0, function* () {
1325013262
try {
13251-
const info = yield getInfoFromManifest(versionSpec, stable, auth);
13263+
const info = yield getInfoFromManifest(versionSpec, stable, auth, osArch);
1325213264
return info === null || info === void 0 ? void 0 : info.resolvedVersion;
1325313265
}
1325413266
catch (err) {
@@ -13283,10 +13295,10 @@ function evaluateVersions(versions, versionSpec) {
1328313295
}
1328413296
return version;
1328513297
}
13286-
function queryDistForMatch(versionSpec) {
13298+
function queryDistForMatch(versionSpec, arch = os.arch()) {
1328713299
return __awaiter(this, void 0, void 0, function* () {
1328813300
let osPlat = os.platform();
13289-
let osArch = translateArchToDistUrl(os.arch());
13301+
let osArch = translateArchToDistUrl(arch);
1329013302
// node offers a json list of versions
1329113303
let dataFileName;
1329213304
switch (osPlat) {
@@ -13339,10 +13351,10 @@ exports.getVersionsFromDist = getVersionsFromDist;
1333913351
// This method attempts to download and cache the resources from these alternative locations.
1334013352
// Note also that the files are normally zipped but in this case they are just an exe
1334113353
// and lib file in a folder, not zipped.
13342-
function acquireNodeFromFallbackLocation(version) {
13354+
function acquireNodeFromFallbackLocation(version, arch = os.arch()) {
1334313355
return __awaiter(this, void 0, void 0, function* () {
1334413356
let osPlat = os.platform();
13345-
let osArch = translateArchToDistUrl(os.arch());
13357+
let osArch = translateArchToDistUrl(arch);
1334613358
// Create temporary folder to download in to
1334713359
const tempDownloadFolder = 'temp_' + Math.floor(Math.random() * 2000000000);
1334813360
const tempDirectory = process.env['RUNNER_TEMP'] || '';
@@ -13373,7 +13385,7 @@ function acquireNodeFromFallbackLocation(version) {
1337313385
throw err;
1337413386
}
1337513387
}
13376-
let toolPath = yield tc.cacheDir(tempDir, 'node', version);
13388+
let toolPath = yield tc.cacheDir(tempDir, 'node', version, arch);
1337713389
core.addPath(toolPath);
1337813390
return toolPath;
1337913391
});

0 commit comments

Comments
 (0)