diff --git a/.gitignore b/.gitignore index cf46fef..94a8769 100644 --- a/.gitignore +++ b/.gitignore @@ -96,7 +96,7 @@ Thumbs.db # Ignore built ts files __tests__/runner/* -lib/**/* +# lib/**/* .idea/ *.iml diff --git a/lib/execution.js b/lib/execution.js new file mode 100644 index 0000000..b379297 --- /dev/null +++ b/lib/execution.js @@ -0,0 +1,51 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result["default"] = mod; + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const exec = __importStar(require("@actions/exec")); +function execute(executable, root, argv) { + return __awaiter(this, void 0, void 0, function* () { + let publishing = false; + let buildScanUrl; + const status = yield exec.exec(executable, argv, { + cwd: root, + ignoreReturnCode: true, + listeners: { + stdline: (line) => { + if (line.startsWith("Publishing build scan...")) { + publishing = true; + } + if (publishing && line.length == 0) { + publishing = false; + } + if (publishing && line.startsWith("http")) { + buildScanUrl = line.trim(); + publishing = false; + } + } + } + }); + return new BuildResultImpl(status, buildScanUrl); + }); +} +exports.execute = execute; +class BuildResultImpl { + constructor(status, buildScanUrl) { + this.status = status; + this.buildScanUrl = buildScanUrl; + } +} diff --git a/lib/gradlew.js b/lib/gradlew.js new file mode 100644 index 0000000..88d27cd --- /dev/null +++ b/lib/gradlew.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const IS_WINDOWS = process.platform === "win32"; +function wrapperFilename() { + return IS_WINDOWS ? "gradlew.bat" : "gradlew"; +} +exports.wrapperFilename = wrapperFilename; +function installScriptFilename() { + return IS_WINDOWS ? "gradle.bat" : "gradle"; +} +exports.installScriptFilename = installScriptFilename; diff --git a/lib/main.js b/lib/main.js new file mode 100644 index 0000000..824c37a --- /dev/null +++ b/lib/main.js @@ -0,0 +1,77 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result["default"] = mod; + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const core = __importStar(require("@actions/core")); +const path = __importStar(require("path")); +const string_argv_1 = require("string-argv"); +const execution = __importStar(require("./execution")); +const gradlew = __importStar(require("./gradlew")); +const provision = __importStar(require("./provision")); +function run() { + return __awaiter(this, void 0, void 0, function* () { + try { + const baseDirectory = process.env[`GITHUB_WORKSPACE`] || ""; + let result = yield execution.execute(yield resolveGradleExecutable(baseDirectory), resolveBuildRootDirectory(baseDirectory), parseCommandLineArguments()); + if (result.buildScanUrl) { + core.setOutput("build-scan-url", result.buildScanUrl); + } + if (result.status != 0) { + core.setFailed(`Gradle process exited with status ${result.status}`); + } + } + catch (error) { + core.setFailed(error.message); + } + }); +} +exports.run = run; +run(); +function resolveGradleExecutable(baseDirectory) { + return __awaiter(this, void 0, void 0, function* () { + const gradleVersion = inputOrNull("gradle-version"); + if (gradleVersion != null && gradleVersion != "wrapper") { + return path.resolve(yield provision.gradleVersion(gradleVersion)); + } + const gradleExecutable = inputOrNull("gradle-executable"); + if (gradleExecutable != null) { + return path.resolve(baseDirectory, gradleExecutable); + } + const wrapperDirectory = inputOrNull("wrapper-directory"); + const executableDirectory = wrapperDirectory != null + ? path.join(baseDirectory, wrapperDirectory) + : baseDirectory; + return path.resolve(executableDirectory, gradlew.wrapperFilename()); + }); +} +function resolveBuildRootDirectory(baseDirectory) { + let buildRootDirectory = inputOrNull("build-root-directory"); + return buildRootDirectory == null + ? path.resolve(baseDirectory) + : path.resolve(baseDirectory, buildRootDirectory); +} +function parseCommandLineArguments() { + const input = inputOrNull("arguments"); + return input == null ? [] : string_argv_1.parseArgsStringToArgv(input); +} +function inputOrNull(name) { + const inputString = core.getInput(name); + if (inputString.length == 0) { + return null; + } + return inputString; +} diff --git a/lib/provision.js b/lib/provision.js new file mode 100644 index 0000000..160f56d --- /dev/null +++ b/lib/provision.js @@ -0,0 +1,166 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result["default"] = mod; + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const fs = __importStar(require("fs")); +const path = __importStar(require("path")); +const httpm = __importStar(require("typed-rest-client/HttpClient")); +const unzip = __importStar(require("unzipper")); +const core = __importStar(require("@actions/core")); +const io = __importStar(require("@actions/io")); +const toolCache = __importStar(require("@actions/tool-cache")); +const gradlew = __importStar(require("./gradlew")); +const httpc = new httpm.HttpClient("eskatos/gradle-command-action"); +const gradleVersionsBaseUrl = "https://services.gradle.org/versions"; +function gradleVersion(gradleVersion) { + return __awaiter(this, void 0, void 0, function* () { + switch (gradleVersion) { + case "current": + return gradleCurrent(); + case "rc": + return gradleReleaseCandidate(); + case "nightly": + return gradleNightly(); + case "release-nightly": + return gradleReleaseNightly(); + default: + return gradle(gradleVersion); + } + }); +} +exports.gradleVersion = gradleVersion; +function gradleCurrent() { + return __awaiter(this, void 0, void 0, function* () { + const json = yield gradleVersionDeclaration(`${gradleVersionsBaseUrl}/current`); + return provisionGradle(json.version, json.downloadUrl); + }); +} +function gradleReleaseCandidate() { + return __awaiter(this, void 0, void 0, function* () { + const json = yield gradleVersionDeclaration(`${gradleVersionsBaseUrl}/release-candidate`); + if (json) { + return provisionGradle(json.version, json.downloadUrl); + } + return gradleCurrent(); + }); +} +function gradleNightly() { + return __awaiter(this, void 0, void 0, function* () { + const json = yield gradleVersionDeclaration(`${gradleVersionsBaseUrl}/nightly`); + return provisionGradle(json.version, json.downloadUrl); + }); +} +function gradleReleaseNightly() { + return __awaiter(this, void 0, void 0, function* () { + const json = yield gradleVersionDeclaration(`${gradleVersionsBaseUrl}/release-nightly`); + return provisionGradle(json.version, json.downloadUrl); + }); +} +function gradle(version) { + return __awaiter(this, void 0, void 0, function* () { + const declaration = yield findGradleVersionDeclaration(version); + if (!declaration) { + throw new Error(`Gradle version ${version} does not exists`); + } + return provisionGradle(declaration.version, declaration.downloadUrl); + }); +} +function gradleVersionDeclaration(url) { + return __awaiter(this, void 0, void 0, function* () { + const json = yield httpGetJson(url); + return (json.version && json.version.length > 0) ? json : undefined; + }); +} +function findGradleVersionDeclaration(version) { + return __awaiter(this, void 0, void 0, function* () { + const json = yield httpGetJson(`${gradleVersionsBaseUrl}/all`); + const found = json.find((entry) => { + return entry.version === version; + }); + return found ? found : undefined; + }); +} +function provisionGradle(version, url) { + return __awaiter(this, void 0, void 0, function* () { + const cachedInstall = toolCache.find("gradle", version); + if (cachedInstall.length > 0) { + const cachedExecutable = executableFrom(cachedInstall); + core.info(`Provisioned Gradle executable ${cachedExecutable}`); + return cachedExecutable; + } + const home = process.env["HOME"] || ""; + const tmpdir = path.join(home, "gradle-provision-tmpdir"); + const downloadsDir = path.join(tmpdir, "downloads"); + const installsDir = path.join(tmpdir, "installs"); + yield io.mkdirP(downloadsDir); + yield io.mkdirP(installsDir); + core.info(`Downloading ${url}`); + const downloadPath = path.join(downloadsDir, `gradle-${version}-bin.zip`); + yield httpDownload(url, downloadPath); + core.info(`Downloaded at ${downloadPath}, size ${fs.statSync(downloadPath).size}`); + yield extractZip(downloadPath, installsDir); + const installDir = path.join(installsDir, `gradle-${version}`); + core.info(`Extracted in ${installDir}`); + const executable = executableFrom(installDir); + fs.chmodSync(executable, "755"); + core.info(`Provisioned Gradle executable ${executable}`); + toolCache.cacheDir(installDir, "gradle", version); + return executable; + }); +} +function executableFrom(installDir) { + return path.join(installDir, "bin", `${gradlew.installScriptFilename()}`); +} +function httpGetJson(url) { + return __awaiter(this, void 0, void 0, function* () { + const response = yield httpc.get(url); + const body = yield response.readBody(); + return JSON.parse(body); + }); +} +function httpDownload(url, path) { + return __awaiter(this, void 0, void 0, function* () { + return new Promise(function (resolve, reject) { + const writeStream = fs.createWriteStream(path); + httpc.get(url).then(response => { + response.message.pipe(writeStream) + .on("close", () => { + resolve(); + }) + .on("error", err => { + reject(err); + }); + }).catch(reason => { + reject(reason); + }); + }); + }); +} +function extractZip(zip, destination) { + return __awaiter(this, void 0, void 0, function* () { + return new Promise(function (resolve, reject) { + fs.createReadStream(zip) + .pipe(unzip.Extract({ "path": destination })) + .on("close", () => { + resolve(); + }) + .on("error", err => { + reject(err); + }); + }); + }); +}