From 6a9c174a1985021d0403f09c3626a4b50bc09de5 Mon Sep 17 00:00:00 2001 From: Silvano Cerza Date: Fri, 31 Jul 2020 15:54:44 +0200 Subject: [PATCH 1/2] Fix action not downloading correct version on ARM --- src/installer.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/installer.ts b/src/installer.ts index 6c3428d..f5d79df 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -83,7 +83,7 @@ async function downloadRelease(version: string): Promise { } function getFileName(version: string): string { - const arch: string = osArch == "x64" ? "64bit" : "32bit"; + let arch = ""; let platform = ""; let ext = ""; switch (osPlat) { @@ -101,6 +101,21 @@ function getFileName(version: string): string { break; } + switch (osArch) { + case "x32": + arch = "32bit"; + break; + case "x64": + arch = "64bit"; + break; + case "arm": + arch = "ARMv7"; + break; + case "arm64": + arch = "ARM64"; + break; + } + return util.format("arduino-cli_%s_%s_%s.%s", version, platform, arch, ext); } From e918087058efebbbd8b6f33fada91a71f3a9989c Mon Sep 17 00:00:00 2001 From: Silvano Cerza Date: Mon, 3 Aug 2020 12:13:59 +0200 Subject: [PATCH 2/2] Added debug message to show download url --- dist/index.js | 268 ++++++++++++++++++++++++++++++++++++++--------- src/installer.ts | 1 + 2 files changed, 218 insertions(+), 51 deletions(-) diff --git a/dist/index.js b/dist/index.js index 231edef..ede3966 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1421,6 +1421,72 @@ run(); module.exports = require("https"); +/***/ }), + +/***/ 226: +/***/ (function(__unusedmodule, exports) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +class BasicCredentialHandler { + constructor(username, password) { + this.username = username; + this.password = password; + } + prepareRequest(options) { + options.headers['Authorization'] = + 'Basic ' + + Buffer.from(this.username + ':' + this.password).toString('base64'); + } + // This handler cannot handle 401 + canHandleAuthentication(response) { + return false; + } + handleAuthentication(httpClient, requestInfo, objs) { + return null; + } +} +exports.BasicCredentialHandler = BasicCredentialHandler; +class BearerCredentialHandler { + constructor(token) { + this.token = token; + } + // currently implements pre-authorization + // TODO: support preAuth = false where it hooks on 401 + prepareRequest(options) { + options.headers['Authorization'] = 'Bearer ' + this.token; + } + // This handler cannot handle 401 + canHandleAuthentication(response) { + return false; + } + handleAuthentication(httpClient, requestInfo, objs) { + return null; + } +} +exports.BearerCredentialHandler = BearerCredentialHandler; +class PersonalAccessTokenCredentialHandler { + constructor(token) { + this.token = token; + } + // currently implements pre-authorization + // TODO: support preAuth = false where it hooks on 401 + prepareRequest(options) { + options.headers['Authorization'] = + 'Basic ' + Buffer.from('PAT:' + this.token).toString('base64'); + } + // This handler cannot handle 401 + canHandleAuthentication(response) { + return false; + } + handleAuthentication(httpClient, requestInfo, objs) { + return null; + } +} +exports.PersonalAccessTokenCredentialHandler = PersonalAccessTokenCredentialHandler; + + /***/ }), /***/ 280: @@ -3053,17 +3119,24 @@ module.exports = require("crypto"); "use strict"; +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 os = __webpack_require__(87); +const os = __importStar(__webpack_require__(87)); /** * Commands * * Command Format: - * ##[name key=value;key=value]message + * ::name key=value,key=value::message * * Examples: - * ##[warning]This is the user warning message - * ##[set-secret name=mypassword]definitelyNotAPassword! + * ::warning::This is the message + * ::set-env name=MY_VAR::some value */ function issueCommand(command, properties, message) { const cmd = new Command(command, properties, message); @@ -3074,7 +3147,7 @@ function issue(name, message = '') { issueCommand(name, {}, message); } exports.issue = issue; -const CMD_PREFIX = '##['; +const CMD_STRING = '::'; class Command { constructor(command, properties, message) { if (!command) { @@ -3085,37 +3158,56 @@ class Command { this.message = message; } toString() { - let cmdStr = CMD_PREFIX + this.command; + let cmdStr = CMD_STRING + this.command; if (this.properties && Object.keys(this.properties).length > 0) { cmdStr += ' '; + let first = true; for (const key in this.properties) { if (this.properties.hasOwnProperty(key)) { const val = this.properties[key]; if (val) { - // safely append the val - avoid blowing up when attempting to - // call .replace() if message is not a string for some reason - cmdStr += `${key}=${escape(`${val || ''}`)};`; + if (first) { + first = false; + } + else { + cmdStr += ','; + } + cmdStr += `${key}=${escapeProperty(val)}`; } } } } - cmdStr += ']'; - // safely append the message - avoid blowing up when attempting to - // call .replace() if message is not a string for some reason - const message = `${this.message || ''}`; - cmdStr += escapeData(message); + cmdStr += `${CMD_STRING}${escapeData(this.message)}`; return cmdStr; } } +/** + * Sanitizes an input into a string so it can be passed into issueCommand safely + * @param input input to sanitize into a string + */ +function toCommandValue(input) { + if (input === null || input === undefined) { + return ''; + } + else if (typeof input === 'string' || input instanceof String) { + return input; + } + return JSON.stringify(input); +} +exports.toCommandValue = toCommandValue; function escapeData(s) { - return s.replace(/\r/g, '%0D').replace(/\n/g, '%0A'); + return toCommandValue(s) + .replace(/%/g, '%25') + .replace(/\r/g, '%0D') + .replace(/\n/g, '%0A'); } -function escape(s) { - return s +function escapeProperty(s) { + return toCommandValue(s) + .replace(/%/g, '%25') .replace(/\r/g, '%0D') .replace(/\n/g, '%0A') - .replace(/]/g, '%5D') - .replace(/;/g, '%3B'); + .replace(/:/g, '%3A') + .replace(/,/g, '%2C'); } //# sourceMappingURL=command.js.map @@ -3135,9 +3227,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge 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 command_1 = __webpack_require__(431); -const path = __webpack_require__(622); +const os = __importStar(__webpack_require__(87)); +const path = __importStar(__webpack_require__(622)); /** * The code to exit an action */ @@ -3156,28 +3256,25 @@ var ExitCode; // Variables //----------------------------------------------------------------------- /** - * sets env variable for this action and future actions in the job + * Sets env variable for this action and future actions in the job * @param name the name of the variable to set - * @param val the value of the variable + * @param val the value of the variable. Non-string values will be converted to a string via JSON.stringify */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any function exportVariable(name, val) { - process.env[name] = val; - command_1.issueCommand('set-env', { name }, val); + const convertedVal = command_1.toCommandValue(val); + process.env[name] = convertedVal; + command_1.issueCommand('set-env', { name }, convertedVal); } exports.exportVariable = exportVariable; /** - * exports the variable and registers a secret which will get masked from logs - * @param name the name of the variable to set - * @param val value of the secret + * Registers a secret which will get masked from logs + * @param secret value of the secret */ -function exportSecret(name, val) { - exportVariable(name, val); - // the runner will error with not implemented - // leaving the function but raising the error earlier - command_1.issueCommand('set-secret', {}, val); - throw new Error('Not implemented.'); -} -exports.exportSecret = exportSecret; +function setSecret(secret) { + command_1.issueCommand('add-mask', {}, secret); +} +exports.setSecret = setSecret; /** * Prepends inputPath to the PATH (for this action and future actions) * @param inputPath @@ -3195,7 +3292,7 @@ exports.addPath = addPath; * @returns string */ function getInput(name, options) { - const val = process.env[`INPUT_${name.replace(' ', '_').toUpperCase()}`] || ''; + const val = process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] || ''; if (options && options.required && !val) { throw new Error(`Input required and not supplied: ${name}`); } @@ -3206,12 +3303,22 @@ exports.getInput = getInput; * Sets the value of an output. * * @param name name of the output to set - * @param value value to store + * @param value value to store. Non-string values will be converted to a string via JSON.stringify */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any function setOutput(name, value) { command_1.issueCommand('set-output', { name }, value); } exports.setOutput = setOutput; +/** + * Enables or disables the echoing of commands into stdout for the rest of the step. + * Echoing is disabled by default if ACTIONS_STEP_DEBUG is not set. + * + */ +function setCommandEcho(enabled) { + command_1.issue('echo', enabled ? 'on' : 'off'); +} +exports.setCommandEcho = setCommandEcho; //----------------------------------------------------------------------- // Results //----------------------------------------------------------------------- @@ -3228,6 +3335,13 @@ exports.setFailed = setFailed; //----------------------------------------------------------------------- // Logging Commands //----------------------------------------------------------------------- +/** + * Gets whether Actions Step Debug is on or not + */ +function isDebug() { + return process.env['RUNNER_DEBUG'] === '1'; +} +exports.isDebug = isDebug; /** * Writes debug message to user log * @param message debug message @@ -3238,20 +3352,28 @@ function debug(message) { exports.debug = debug; /** * Adds an error issue - * @param message error issue message + * @param message error issue message. Errors will be converted to string via toString() */ function error(message) { - command_1.issue('error', message); + command_1.issue('error', message instanceof Error ? message.toString() : message); } exports.error = error; /** * Adds an warning issue - * @param message warning issue message + * @param message warning issue message. Errors will be converted to string via toString() */ function warning(message) { - command_1.issue('warning', message); + command_1.issue('warning', message instanceof Error ? message.toString() : message); } exports.warning = warning; +/** + * Writes info to log with console.log. + * @param message info message + */ +function info(message) { + process.stdout.write(message + os.EOL); +} +exports.info = info; /** * Begin an output group. * @@ -3292,6 +3414,30 @@ function group(name, fn) { }); } exports.group = group; +//----------------------------------------------------------------------- +// Wrapper action state +//----------------------------------------------------------------------- +/** + * Saves state for current action, the state can only be retrieved by this action's post job execution. + * + * @param name name of the state to store + * @param value value to store. Non-string values will be converted to a string via JSON.stringify + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function saveState(name, value) { + command_1.issueCommand('save-state', { name }, value); +} +exports.saveState = saveState; +/** + * Gets the value of an state set by this action's main execution. + * + * @param name name of the state to get + * @returns string + */ +function getState(name) { + return process.env[`STATE_${name}`] || ''; +} +exports.getState = getState; //# sourceMappingURL=core.js.map /***/ }), @@ -4751,6 +4897,7 @@ const os = __importStar(__webpack_require__(87)); const path = __importStar(__webpack_require__(622)); const util = __importStar(__webpack_require__(669)); const httpm = __importStar(__webpack_require__(539)); +const auth = __importStar(__webpack_require__(226)); const semver = __importStar(__webpack_require__(280)); if (!tempDirectory) { let baseLocation; @@ -4796,10 +4943,11 @@ function downloadRelease(version) { // Download let fileName = getFileName(version); let downloadUrl = util.format("https://github.com/Arduino/arduino-cli/releases/download/%s/%s", version, fileName); + core.debug("Downloading " + downloadUrl); let downloadPath = null; try { const token = core.getInput("token", { required: true }); - downloadPath = yield tc.downloadTool(downloadUrl, "", token); + downloadPath = yield tc.downloadTool(downloadUrl, undefined, token); } catch (error) { core.debug(error); @@ -4818,7 +4966,7 @@ function downloadRelease(version) { }); } function getFileName(version) { - const arch = osArch == "x64" ? "64bit" : "32bit"; + let arch = ""; let platform = ""; let ext = ""; switch (osPlat) { @@ -4835,16 +4983,34 @@ function getFileName(version) { ext = "tar.gz"; break; } + switch (osArch) { + case "x32": + arch = "32bit"; + break; + case "x64": + arch = "64bit"; + break; + case "arm": + arch = "ARMv7"; + break; + case "arm64": + arch = "ARM64"; + break; + } return util.format("arduino-cli_%s_%s_%s.%s", version, platform, arch, ext); } // Retrieve a list of versions scraping tags from the Github API function fetchVersions() { return __awaiter(this, void 0, void 0, function* () { - let rest = new httpm.HttpClient("setup-arduino-cli"); + const token = core.getInput("token", { required: true }); + const authHandler = new auth.PersonalAccessTokenCredentialHandler(token); + let rest = new httpm.HttpClient("setup-arduino-cli", [ + authHandler + ]); let tags = (yield rest.getJson("https://api.github.com/repos/Arduino/arduino-cli/git/refs/tags")).result || []; return tags - .filter((tag) => tag.ref.match(/\d+\.[\w\.]+/g)) - .map((tag) => tag.ref.replace("refs/tags/", "")); + .filter(tag => tag.ref.match(/\d+\.[\w\.]+/g)) + .map(tag => tag.ref.replace("refs/tags/", "")); }); } // Compute an actual version starting from the `version` configuration param. @@ -4855,12 +5021,12 @@ function computeVersion(version) { version = version.slice(0, version.length - 2); } const allVersions = yield fetchVersions(); - const possibleVersions = allVersions.filter((v) => v.startsWith(version)); + const possibleVersions = allVersions.filter(v => v.startsWith(version)); const versionMap = new Map(); - possibleVersions.forEach((v) => versionMap.set(normalizeVersion(v), v)); + possibleVersions.forEach(v => versionMap.set(normalizeVersion(v), v)); const versions = Array.from(versionMap.keys()) .sort(semver.rcompare) - .map((v) => versionMap.get(v)); + .map(v => versionMap.get(v)); core.debug(`evaluating ${versions.length} versions`); if (versions.length === 0) { throw new Error("unable to get latest version"); @@ -4881,7 +5047,7 @@ function normalizeVersion(version) { else { // handle beta and rc // e.g. 1.10beta1 -? 1.10.0-beta1, 1.10rc1 -> 1.10.0-rc1 - if (preStrings.some((el) => versionPart[1].includes(el))) { + if (preStrings.some(el => versionPart[1].includes(el))) { versionPart[1] = versionPart[1] .replace("beta", ".0-beta") .replace("rc", ".0-rc") @@ -4897,7 +5063,7 @@ function normalizeVersion(version) { else { // handle beta and rc // e.g. 1.8.5beta1 -> 1.8.5-beta1, 1.8.5rc1 -> 1.8.5-rc1 - if (preStrings.some((el) => versionPart[2].includes(el))) { + if (preStrings.some(el => versionPart[2].includes(el))) { versionPart[2] = versionPart[2] .replace("beta", "-beta") .replace("rc", "-rc") diff --git a/src/installer.ts b/src/installer.ts index f5d79df..b8b7462 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -61,6 +61,7 @@ async function downloadRelease(version: string): Promise { version, fileName ); + core.debug("Downloading " + downloadUrl); let downloadPath: string | null = null; try { const token: string = core.getInput("token", { required: true });