Skip to content

Commit 427cb54

Browse files
committed
Add tools deps install
1 parent 80cd371 commit 427cb54

21 files changed

+6214
-0
lines changed

.github/workflows/workflow.yml

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: Tests
2+
on: [push]
3+
jobs:
4+
run:
5+
name: Run
6+
runs-on: ${{ matrix.operating-system }}
7+
strategy:
8+
matrix:
9+
operating-system: [ubuntu-latest, windows-latest, macOS-latest]
10+
steps:
11+
- name: Checkout
12+
uses: actions/checkout@master
13+
14+
- name: Set Node.js 12.x
15+
uses: actions/setup-node@master
16+
with:
17+
version: 12.x
18+
19+
- name: npm install
20+
run: npm install
21+
22+
- name: Lint
23+
run: npm run format-check
24+
25+
- name: npm test
26+
run: npm test

.gitignore

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Explicitly not ignoring node_modules so that they are included in package downloaded by runner
2+
!node_modules/
3+
__tests__/runner/*
4+
5+
# Rest of the file pulled from https://github.com/github/gitignore/blob/master/Node.gitignore
6+
# Logs
7+
logs
8+
*.log
9+
npm-debug.log*
10+
yarn-debug.log*
11+
yarn-error.log*
12+
lerna-debug.log*
13+
14+
.DS_Store

.prettierrc.json

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"printWidth": 80,
3+
"tabWidth": 2,
4+
"useTabs": false,
5+
"semi": true,
6+
"singleQuote": true,
7+
"trailingComma": "none",
8+
"bracketSpacing": false,
9+
"arrowParens": "avoid",
10+
"parser": "typescript"
11+
}

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2018 GitHub, Inc. and contributors
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

__tests__/tdeps.test.ts

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import io = require('@actions/io');
2+
import os = require('os');
3+
import fs = require('fs');
4+
import path = require('path');
5+
6+
const toolDir = path.join(__dirname, 'runner', 'tools');
7+
const tempDir = path.join(__dirname, 'runner', 'temp');
8+
9+
process.env['RUNNER_TOOL_CACHE'] = toolDir;
10+
process.env['RUNNER_TEMP'] = tempDir;
11+
import * as tdeps from '../src/tdeps';
12+
13+
describe('tdeps tests', () => {
14+
beforeAll(async () => {
15+
await io.rmRF(toolDir);
16+
await io.rmRF(tempDir);
17+
}, 300000);
18+
19+
afterAll(async () => {
20+
try {
21+
await io.rmRF(toolDir);
22+
await io.rmRF(tempDir);
23+
} catch {
24+
console.log('Failed to remove test directories');
25+
}
26+
}, 100000);
27+
28+
it('Throws if invalid version', async () => {
29+
let thrown = false;
30+
try {
31+
await tdeps.setup('1000');
32+
} catch {
33+
thrown = true;
34+
}
35+
expect(thrown).toBe(true);
36+
});
37+
38+
it('Install clojure tools deps with normal version', async () => {
39+
await tdeps.setup('1.10.1.469');
40+
const clojureDir = path.join(
41+
toolDir,
42+
'ClojureToolsDeps',
43+
'1.10.1-469',
44+
os.arch()
45+
);
46+
47+
expect(fs.existsSync(`${clojureDir}.complete`)).toBe(true);
48+
expect(fs.existsSync(path.join(clojureDir, 'bin', 'clojure'))).toBe(true);
49+
}, 100000);
50+
51+
it('Uses version of clojure tools-deps installed in cache', async () => {
52+
const clojureDir: string = path.join(
53+
toolDir,
54+
'ClojureToolsDeps',
55+
'1.10.1-469',
56+
os.arch()
57+
);
58+
await io.mkdirP(clojureDir);
59+
fs.writeFileSync(`${clojureDir}.complete`, 'hello');
60+
await tdeps.setup('1.10.1.469');
61+
return;
62+
});
63+
64+
it('Doesnt use version of clojure that was only partially installed in cache', async () => {
65+
const clojureDir: string = path.join(
66+
toolDir,
67+
'ClojureToolsDeps',
68+
'1.10.1-469',
69+
os.arch()
70+
);
71+
await io.mkdirP(clojureDir);
72+
let thrown = false;
73+
try {
74+
await tdeps.setup('1000');
75+
} catch {
76+
thrown = true;
77+
}
78+
expect(thrown).toBe(true);
79+
return;
80+
});
81+
});

action.yml

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: 'Setup Clojure'
2+
description: 'Setup your runner with Clojure build tools'
3+
author: 'DeLaGuardo'
4+
branding:
5+
icon: 'gift'
6+
color: 'blue'
7+
inputs:
8+
liningen:
9+
description: 'The Leiningen version to make available on the path.'
10+
boot:
11+
description: 'The boot-clj version to make available on the path.'
12+
tools-deps:
13+
description: 'The tools deps version to make available on the path.'
14+
runs:
15+
using: 'node12'
16+
main: 'lib/setup-clojure.js'

jest.config.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module.exports = {
2+
clearMocks: true,
3+
moduleFileExtensions: ['js', 'ts'],
4+
testEnvironment: 'node',
5+
testMatch: ['**/*.test.ts'],
6+
testRunner: 'jest-circus/runner',
7+
transform: {
8+
'^.+\\.ts$': 'ts-jest'
9+
},
10+
verbose: true
11+
}

lib/boot.js

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
"use strict";
2+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4+
return new (P || (P = Promise))(function (resolve, reject) {
5+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8+
step((generator = generator.apply(thisArg, _arguments || [])).next());
9+
});
10+
};
11+
Object.defineProperty(exports, "__esModule", { value: true });
12+
function setup(version) {
13+
return __awaiter(this, void 0, void 0, function* () {
14+
throw new Error('Not yet available');
15+
});
16+
}
17+
exports.setup = setup;

lib/installer.js

+146
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
"use strict";
2+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4+
return new (P || (P = Promise))(function (resolve, reject) {
5+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8+
step((generator = generator.apply(thisArg, _arguments || [])).next());
9+
});
10+
};
11+
var __importStar = (this && this.__importStar) || function (mod) {
12+
if (mod && mod.__esModule) return mod;
13+
var result = {};
14+
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
15+
result["default"] = mod;
16+
return result;
17+
};
18+
Object.defineProperty(exports, "__esModule", { value: true });
19+
let tempDirectory = process.env['RUNNER_TEMP'] || '';
20+
const core = __importStar(require("@actions/core"));
21+
const io = __importStar(require("@actions/io"));
22+
const exec = __importStar(require("@actions/exec"));
23+
const tc = __importStar(require("@actions/tool-cache"));
24+
const fs = __importStar(require("fs"));
25+
const path = __importStar(require("path"));
26+
const os = __importStar(require("os"));
27+
const IS_WINDOWS = process.platform === 'win32';
28+
if (!tempDirectory) {
29+
let baseLocation;
30+
if (IS_WINDOWS) {
31+
baseLocation = process.env['USERPROFILE'] || 'C:\\';
32+
}
33+
else {
34+
if (process.platform === 'darwin') {
35+
baseLocation = '/Users';
36+
}
37+
else {
38+
baseLocation = '/home';
39+
}
40+
}
41+
tempDirectory = path.join(baseLocation, 'actions', 'temp');
42+
}
43+
let platform = '';
44+
if (IS_WINDOWS) {
45+
platform = 'windows';
46+
}
47+
else {
48+
if (process.platform === 'darwin') {
49+
platform = 'darwin';
50+
}
51+
else {
52+
platform = 'linux';
53+
}
54+
}
55+
function getGraalVM(version) {
56+
return __awaiter(this, void 0, void 0, function* () {
57+
let toolPath = tc.find('GraalVM', getCacheVersionString(version), os.arch());
58+
let compressedFileExtension = '';
59+
if (toolPath) {
60+
core.debug(`GraalVM found in cache ${toolPath}`);
61+
}
62+
else {
63+
core.debug('Downloading GraalVM from https://github.com/oracle/graal/releases');
64+
compressedFileExtension = IS_WINDOWS ? '.zip' : '.tar.gz';
65+
let graalvmFile = yield tc.downloadTool(`https://github.com/oracle/graal/releases/download/vm-${version}/graalvm-ce-${platform}-amd64-${version}${compressedFileExtension}`);
66+
let tempDir = path.join(tempDirectory, 'temp_' + Math.floor(Math.random() * 2000000000));
67+
const graalvmDir = yield unzipGraalVMDownload(graalvmFile, compressedFileExtension, tempDir);
68+
core.debug(`graalvm extracted to ${graalvmDir}`);
69+
toolPath = yield tc.cacheDir(graalvmDir, 'GraalVM', getCacheVersionString(version));
70+
}
71+
let extendedJavaHome = 'JAVA_HOME_' + version;
72+
core.exportVariable('JAVA_HOME', toolPath);
73+
core.exportVariable(extendedJavaHome, toolPath);
74+
core.addPath(path.join(toolPath, 'bin'));
75+
});
76+
}
77+
exports.getGraalVM = getGraalVM;
78+
function getCacheVersionString(version) {
79+
const versionArray = version.split('.');
80+
const major = versionArray[0];
81+
const minor = versionArray.length > 1 ? versionArray[1] : '0';
82+
const patch = versionArray.length > 2 ? versionArray.slice(2).join('-') : '0';
83+
return `${major}.${minor}.${patch}`;
84+
}
85+
function extractFiles(file, fileEnding, destinationFolder) {
86+
return __awaiter(this, void 0, void 0, function* () {
87+
const stats = fs.statSync(file);
88+
if (!stats) {
89+
throw new Error(`Failed to extract ${file} - it doesn't exist`);
90+
}
91+
else if (stats.isDirectory()) {
92+
throw new Error(`Failed to extract ${file} - it is a directory`);
93+
}
94+
if ('.tar.gz' === fileEnding) {
95+
yield tc.extractTar(file, destinationFolder);
96+
}
97+
else if ('.zip' === fileEnding) {
98+
yield tc.extractZip(file, destinationFolder);
99+
}
100+
});
101+
}
102+
function unpackJars(fsPath, javaBinPath) {
103+
return __awaiter(this, void 0, void 0, function* () {
104+
if (fs.existsSync(fsPath)) {
105+
if (fs.lstatSync(fsPath).isDirectory()) {
106+
for (const file in fs.readdirSync(fsPath)) {
107+
const curPath = path.join(fsPath, file);
108+
yield unpackJars(curPath, javaBinPath);
109+
}
110+
}
111+
else if (path.extname(fsPath).toLowerCase() === '.pack') {
112+
// Unpack the pack file synchonously
113+
const p = path.parse(fsPath);
114+
const toolName = IS_WINDOWS ? 'unpack200.exe' : 'unpack200';
115+
const args = IS_WINDOWS ? '-r -v -l ""' : '';
116+
const name = path.join(p.dir, p.name);
117+
yield exec.exec(`"${path.join(javaBinPath, toolName)}"`, [
118+
`${args} "${name}.pack" "${name}.jar"`
119+
]);
120+
}
121+
}
122+
});
123+
}
124+
function unzipGraalVMDownload(repoRoot, fileEnding, destinationFolder) {
125+
return __awaiter(this, void 0, void 0, function* () {
126+
yield io.mkdirP(destinationFolder);
127+
const graalvmFile = path.normalize(repoRoot);
128+
const stats = fs.statSync(graalvmFile);
129+
if (stats.isFile()) {
130+
yield extractFiles(graalvmFile, fileEnding, destinationFolder);
131+
const graalvmFolder = fs.readdirSync(destinationFolder)[0];
132+
if (process.platform === 'darwin') {
133+
for (const f of fs.readdirSync(path.join(destinationFolder, graalvmFolder, 'Contents', 'Home'))) {
134+
yield io.cp(path.join(destinationFolder, graalvmFolder, 'Contents', 'Home', f), path.join(destinationFolder, graalvmFolder, f), { recursive: true });
135+
}
136+
yield io.rmRF(path.join(destinationFolder, graalvmFolder, 'Contents'));
137+
}
138+
const graalvmDirectory = path.join(destinationFolder, graalvmFolder);
139+
yield unpackJars(graalvmDirectory, path.join(graalvmDirectory, 'bin'));
140+
return graalvmDirectory;
141+
}
142+
else {
143+
throw new Error(`Jdk argument ${graalvmFile} is not a file`);
144+
}
145+
});
146+
}

lib/leiningen.js

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
"use strict";
2+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4+
return new (P || (P = Promise))(function (resolve, reject) {
5+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8+
step((generator = generator.apply(thisArg, _arguments || [])).next());
9+
});
10+
};
11+
Object.defineProperty(exports, "__esModule", { value: true });
12+
function setup(version) {
13+
return __awaiter(this, void 0, void 0, function* () {
14+
throw new Error('Not yet available');
15+
});
16+
}
17+
exports.setup = setup;

0 commit comments

Comments
 (0)