renamed GitVersion.js -> GitVersion.ts, added ToolInstaller and ToolLib

This commit is contained in:
Artur Stolear
2019-11-10 10:59:04 +02:00
parent 02c0ebd58a
commit a1dd63474d
10 changed files with 7694 additions and 3023 deletions

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
node_modules/
/*.js

10252
dist/index.js vendored

File diff suppressed because it is too large Load Diff

98
package-lock.json generated
View File

@@ -9,6 +9,11 @@
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.0.tgz",
"integrity": "sha512-ZKdyhlSlyz38S6YFfPnyNgCDZuAF2T0Qv5eHflNWytPS8Qjvz39bZFMry9Bb/dpSnqWcNeav5yM2CTYpJeY+Dw=="
},
"@actions/exec": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.0.1.tgz",
"integrity": "sha512-nvFkxwiicvpzNiCBF4wFBDfnBvi7xp/as7LE1hBxBxKG2L29+gkIPBiLKMVORL+Hg3JNf07AKRfl0V5djoypjQ=="
},
"@actions/github": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@actions/github/-/github-1.1.0.tgz",
@@ -18,6 +23,24 @@
"@octokit/rest": "^16.15.0"
}
},
"@actions/io": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.0.1.tgz",
"integrity": "sha512-rhq+tfZukbtaus7xyUtwKfuiCRXd1hWSfmJNEpFgBQJ4woqPEpsBw04awicjwz9tyG2/MVhAEMfVn664Cri5zA=="
},
"@actions/tool-cache": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-1.1.2.tgz",
"integrity": "sha512-IJczPaZr02ECa3Lgws/TJEVco9tjOujiQSZbO3dHuXXjhd5vrUtfOgGwhmz3/f97L910OraPZ8SknofUk6RvOQ==",
"requires": {
"@actions/core": "^1.1.0",
"@actions/exec": "^1.0.1",
"@actions/io": "^1.0.1",
"semver": "^6.1.0",
"typed-rest-client": "^1.4.0",
"uuid": "^3.3.2"
}
},
"@octokit/endpoint": {
"version": "5.5.1",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-5.5.1.tgz",
@@ -120,9 +143,30 @@
}
},
"@types/node": {
"version": "12.12.6",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.6.tgz",
"integrity": "sha512-FjsYUPzEJdGXjwKqSpE0/9QEh6kzhTAeObA54rn6j3rR4C/mzpI9L0KNfoeASSPMMdxIsoJuCLDWcM/rVjIsSA=="
"version": "12.12.7",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.7.tgz",
"integrity": "sha512-E6Zn0rffhgd130zbCbAr/JdXfXkoOUFAKNs/rF8qnafSJ8KYaA/j3oz7dcwal+lYjLA7xvdd5J4wdYpCTlP8+w=="
},
"@types/q": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz",
"integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==",
"dev": true
},
"@types/semver": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-6.2.0.tgz",
"integrity": "sha512-1OzrNb4RuAzIT7wHSsgZRlMBlNsJl+do6UblR7JMW4oB7bbR+uBEYtUh7gEc/jM84GGilh68lSOokyM/zNUlBA==",
"dev": true
},
"@types/uuid": {
"version": "3.4.6",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.6.tgz",
"integrity": "sha512-cCdlC/1kGEZdEglzOieLDYBxHsvEOIg7kp/2FYyVR9Pxakq+Qf/inL3RKQ+PA8gOlI/NnL+fXmQH12nwcGzsHw==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"atob-lite": {
"version": "2.0.0",
@@ -149,6 +193,13 @@
"semver": "^5.5.0",
"shebang-command": "^1.2.0",
"which": "^1.2.9"
},
"dependencies": {
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
}
}
},
"deprecation": {
@@ -289,9 +340,14 @@
}
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
},
"semver-compare": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
"integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w="
},
"shebang-command": {
"version": "1.2.0",
@@ -316,6 +372,31 @@
"resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="
},
"tunnel": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.4.tgz",
"integrity": "sha1-LTeFoVjBdMmhbcLARuxfxfF0IhM="
},
"typed-rest-client": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.5.0.tgz",
"integrity": "sha512-DVZRlmsfnTjp6ZJaatcdyvvwYwbWvR4YDNFDqb+qdTxpvaVP99YCpBkA8rxsLtAPjBVoDe4fNsnMIdZTiPuKWg==",
"requires": {
"tunnel": "0.0.4",
"underscore": "1.8.3"
}
},
"typescript": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.2.tgz",
"integrity": "sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ==",
"dev": true
},
"underscore": {
"version": "1.8.3",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
"integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI="
},
"universal-user-agent": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-2.1.0.tgz",
@@ -324,6 +405,11 @@
"os-name": "^3.0.0"
}
},
"uuid": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz",
"integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ=="
},
"which": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",

View File

@@ -1,24 +1,38 @@
{
"name": "use-gitversion",
"version": "1.0.0",
"description": "Github Action that installs and uses the GitVersion tool",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/GitTools/use-gitversion.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/GitTools/use-gitversion/issues"
},
"homepage": "https://github.com/GitTools/use-gitversion#readme",
"dependencies": {
"@actions/core": "^1.2.0",
"@actions/github": "^1.1.0"
}
"name": "use-gitversion",
"version": "1.0.0",
"description": "Github Action that installs and uses the GitVersion tool",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/GitTools/use-gitversion.git"
},
"keywords": [],
"author": "",
"license": "MIT",
"bugs": {
"url": "https://github.com/GitTools/use-gitversion/issues"
},
"homepage": "https://github.com/GitTools/use-gitversion#readme",
"dependencies": {
"@actions/core": "^1.2.0",
"@actions/exec": "^1.0.1",
"@actions/github": "^1.1.0",
"@actions/io": "^1.0.1",
"@actions/tool-cache": "^1.1.2",
"semver": "^6.3.0",
"semver-compare": "^1.0.0",
"typed-rest-client": "1.5.0",
"uuid": "^3.3.3"
},
"devDependencies": {
"@types/node": "^12.12.7",
"@types/q": "1.5.2",
"@types/semver": "^6.2.0",
"@types/uuid": "^3.4.6",
"typescript": "^3.6.3"
}
}

24
src/Interfaces.ts Normal file
View File

@@ -0,0 +1,24 @@
export interface IProxy {
find: (toolName: string, versionSpec: string, arch?: string) => string;
debug: (message: string) => void;
exportVariable: (name: string, val: string) => void;
addPath: (inputPath: string) => void;
which: (tool: string, check?: boolean) => Promise<string>;
cacheDir: (sourceDir: string, tool: string, version: string, arch?: string) => Promise<string>;
isExplicitVersion: (versionSpec: string) => boolean;
evaluateVersions: (versions: string[], versionSpec: string) => string;
cleanVersion: (version: string) => string;
createTempDir: () => Promise<string>;
executeDotNet: (args: string[]) => Promise<IExecSyncResult>;
};
export interface IExecSyncResult {
/** standard output */
stdout: string;
/** error output */
stderr: string;
/** return code */
code: number;
/** Error on failure */
error: Error;
}

128
src/ToolInstaller.ts Normal file
View File

@@ -0,0 +1,128 @@
import * as path from 'path';
import * as fs from 'fs';
import * as os from 'os';
import * as httpm from 'typed-rest-client/HttpClient';
import { IProxy } from './Interfaces';
export class ToolInstaller {
constructor(public utils: IProxy) {
this.httpClient = new httpm.HttpClient("ToolInstaller");
}
public async downloadAndInstall(toolName: string, versionSpec: string, checkLatest: boolean, includePrerelease: boolean): Promise<string> {
console.log('');
console.log('--------------------------');
console.log(`Installing ${toolName} version ` + versionSpec);
console.log('--------------------------');
if (this.utils.isExplicitVersion(versionSpec)) {
checkLatest = false; // check latest doesn't make sense when explicit version
}
let toolPath: string;
if (!checkLatest) {
//
// Let's try and resolve the version spec locally first
//
toolPath = this.utils.find(toolName, versionSpec);
}
if (!toolPath) {
let version: string;
if (this.utils.isExplicitVersion(versionSpec)) {
//
// Explicit version was specified. No need to query for list of versions.
//
version = versionSpec;
}
else {
//
// Let's query and resolve the latest version for the versionSpec.
// If the version is an explicit version (1.1.1 or v1.1.1) then no need to query.
// If your tool doesn't offer a mechanism to query,
// then it can only support exact version inputs.
//
version = await this.queryLatestMatch(toolName, versionSpec, includePrerelease);
if (!version) {
throw new Error(`Unable to find ${toolName} version '${versionSpec}'.`);
}
//
// Check the cache for the resolved version.
//
toolPath = this.utils.find(toolName, version)
}
if (!toolPath) {
//
// Download, extract, cache
//
toolPath = await this.acquireTool(toolName, version);
}
}
//
// Prepend the tools path. This prepends the PATH for the current process and
// instructs the agent to prepend for each task that follows.
//
this.utils.debug(`toolPath: ${toolPath}`);
if (os.platform() != 'win32') {
let dotnetRoot = path.dirname(fs.readlinkSync(await this.utils.which("dotnet")));
this.utils.exportVariable('DOTNET_ROOT', dotnetRoot);
}
this.utils.addPath(toolPath);
return toolPath;
}
private async queryLatestMatch(toolName: string, versionSpec: string, includePrerelease: boolean): Promise<string> {
this.utils.debug(`querying tool versions for ${toolName}${versionSpec ? `@${versionSpec}` : ""} ${includePrerelease ? "including pre-releases" : ""}`);
var downloadPath = `https://api-v2v3search-0.nuget.org/query?q=${encodeURIComponent(toolName.toLowerCase())}&prerelease=${includePrerelease ? "true" : "false"}&semVerLevel=2.0.0`;
var res = await this.httpClient.get(downloadPath);
if (!res || res.message.statusCode != 200)
{
return null;
}
let body: string = await res.readBody();
var data = JSON.parse(body).data;
const versions = (<Array<{ version: string }>>data[0].versions).map(x => x.version);
if (!versions || !versions.length)
{
return null;
}
this.utils.debug(`got versions: ${versions.join(", ")}`);
return this.utils.evaluateVersions(versions, versionSpec);
}
private async acquireTool(toolName: string, version: string): Promise<string> {
let tempDirectory = await this.utils.createTempDir();
let args = ["tool", "install", toolName, "--tool-path", tempDirectory];
if (version) {
version = this.utils.cleanVersion(version);
args = args.concat(["--version", version]);
}
let result = await this.utils.executeDotNet(args);
let status = result.code === 0 ? "success" : "failure";
let message = result.code === 0 ? result.stdout : result.stderr;
this.utils.debug(`tool install result: ${status} ${message}`);
if (result.code) {
throw new Error("Error installing tool");
}
return await this.utils.cacheDir(tempDirectory, toolName, version);
}
private httpClient: httpm.HttpClient;
}

View File

@@ -1,7 +1,10 @@
const core = require('@actions/core');
const github = require('@actions/github');
import * as core from '@actions/core';
import * as github from '@actions/github';
import { ToolInstaller } from '../ToolInstaller';
import { Proxy as utils } from './Proxy';
try {
let toolInstaller = new ToolInstaller(utils);
toolInstaller.downloadAndInstall('GitVersion.Tool', '5.1.2', false, false);
// `who-to-greet` input defined in action metadata file
const nameToGreet = core.getInput('who-to-greet');
console.log(`Hello ${nameToGreet}!`);

20
src/github/Proxy.ts Normal file
View File

@@ -0,0 +1,20 @@
import { find, cacheDir } from '@actions/tool-cache';
import { debug, exportVariable, addPath } from '@actions/core';
import { which } from '@actions/io';
import { isExplicitVersion, evaluateVersions, createTempDir, cleanVersion, executeDotNet } from './ToolLib';
import { IProxy } from '../Interfaces';
export const Proxy: IProxy = {
find : find,
debug: debug,
exportVariable: exportVariable,
addPath: addPath,
which: which,
cacheDir: cacheDir,
isExplicitVersion: isExplicitVersion,
evaluateVersions: evaluateVersions,
cleanVersion: cleanVersion,
createTempDir: createTempDir,
executeDotNet: executeDotNet
}

114
src/github/ToolLib.ts Normal file
View File

@@ -0,0 +1,114 @@
import * as path from 'path';
import * as semver from 'semver';
import * as uuidV4 from "uuid/v4";
import * as io from '@actions/io';
import * as core from '@actions/core';
import * as exec from '@actions/exec';
import { IExecSyncResult } from '../Interfaces';
const cmp = require('semver-compare');
export async function createTempDir(): Promise<string> {
const IS_WINDOWS = process.platform === "win32";
let tempDirectory: string = process.env["RUNNER_TEMP"] || "";
if (!tempDirectory) {
let baseLocation: string;
if (IS_WINDOWS) {
// On Windows use the USERPROFILE env variable
baseLocation = process.env["USERPROFILE"] || "C:\\";
} else {
if (process.platform === "darwin") {
baseLocation = "/Users";
} else {
baseLocation = "/home";
}
}
tempDirectory = path.join(baseLocation, "actions", "temp");
}
const dest = path.join(tempDirectory, uuidV4());
await io.mkdirP(dest);
return dest;
}
/**
* Checks if a version spec is an explicit version (e.g. 1.0.1 or v1.0.1)
* As opposed to a version spec like 1.x
*
* @param versionSpec
*/
export function isExplicitVersion(versionSpec: string): boolean {
let c = semver.clean(versionSpec);
core.debug('isExplicit: ' + c);
let valid = semver.valid(c) != null;
core.debug('explicit? ' + valid);
return valid;
}
/**
* Returns cleaned (removed leading/trailing whitespace, remove '=v' prefix)
* and parsed version, or null if version is invalid.
*/
export function cleanVersion(version: string): string {
core.debug('cleaning: ' + version);
return semver.clean(version);
}
/**
* evaluates a list of versions and returns the latest version matching the version spec
*
* @param versions an array of versions to evaluate
* @param versionSpec a version spec (e.g. 1.x)
*/
export function evaluateVersions(versions: string[], versionSpec: string): string {
let version: string;
core.debug('evaluating ' + versions.length + ' versions');
versions = versions.sort(cmp);
for (let i = versions.length - 1; i >= 0; i--) {
let potential: string = versions[i];
let satisfied: boolean = semver.satisfies(potential, versionSpec);
if (satisfied) {
version = potential;
break;
}
}
if (version) {
core.debug('matched: ' + version);
}
else {
core.debug('match not found');
}
return version;
}
export async function executeDotNet(args: string[]) : Promise<IExecSyncResult> {
let dotnetPath = await io.which("dotnet", true);
let resultCode = 0;
let stdout = '';
let stderr = '';
resultCode = await exec.exec(
`"${dotnetPath}"`,
args,
{
listeners: {
stdout: (data: Buffer) => {
stdout += data.toString();
},
stderr: (data: Buffer) => {
stderr += data.toString();
}
}
});
return {
code: resultCode,
stdout: stdout,
stderr: stderr,
error: null
}
}

13
tsconfig.json Normal file
View File

@@ -0,0 +1,13 @@
{
"compilerOptions": {
"module": "commonjs",
"moduleResolution": "node",
"noImplicitAny": true,
"removeComments": true,
"preserveConstEnums": true,
"target": "es6",
"sourceMap": false,
"inlineSourceMap": true,
"declaration": false
},
}