// Copyright (c) Microsoft Corporation. // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. import * as os from 'os' import * as path from 'path' import * as util from 'util' import * as fs from 'fs' import * as toolCache from '@actions/tool-cache' import * as core from '@actions/core' const helmToolName = 'helm' const stableHelmVersion = 'v3.8.0' const helmAllReleasesUrl = 'https://api.github.com/repos/helm/helm/releases' export async function run() { let version = core.getInput('version', {required: true}) if (version !== 'latest' && version[0] !== 'v') { version = getValidVersion(version) } if (version.toLocaleLowerCase() === 'latest') { version = await getLatestHelmVersion() } core.debug(util.format('Downloading %s', version)) let cachedPath = await downloadHelm(version) try { if (!process.env['PATH'].startsWith(path.dirname(cachedPath))) { core.addPath(path.dirname(cachedPath)) } } catch { //do nothing, set as output variable } console.log( `Helm tool version: '${version}' has been cached at ${cachedPath}` ) core.setOutput('helm-path', cachedPath) } //Returns version with proper v before it export function getValidVersion(version: string): string { return 'v' + version } // Downloads the helm releases JSON and parses all the recent versions of helm from it. // Defaults to sending stable helm version if none are valid or if it fails export async function getLatestHelmVersion(): Promise { const helmJSONPath: string = await toolCache.downloadTool(helmAllReleasesUrl) try { const helmJSON = JSON.parse(fs.readFileSync(helmJSONPath, 'utf-8')) for (let i in helmJSON) { if (isValidVersion(helmJSON[i].tag_name)) { return helmJSON[i].tag_name } } } catch (err) { core.warning( util.format( 'Error while fetching the latest Helm release. Error: %s. Using default Helm version %s', err.toString(), stableHelmVersion ) ) return stableHelmVersion } return stableHelmVersion } // isValidVersion checks if verison is a stable release function isValidVersion(version: string): boolean { return version.indexOf('rc') == -1 } export function getExecutableExtension(): string { if (os.type().match(/^Win/)) { return '.exe' } return '' } const LINUX = 'Linux' const MAC_OS = 'Darwin' const WINDOWS = 'Windows_NT' const ARM64 = 'arm64' export function getHelmDownloadURL(version: string): string { const arch = os.arch() const operatingSystem = os.type() switch (true) { case operatingSystem == LINUX && arch == ARM64: return util.format( 'https://get.helm.sh/helm-%s-linux-arm64.zip', version ) case operatingSystem == LINUX: return util.format( 'https://get.helm.sh/helm-%s-linux-amd64.zip', version ) case operatingSystem == MAC_OS && arch == ARM64: return util.format( 'https://get.helm.sh/helm-%s-darwin-arm64.zip', version ) case operatingSystem == MAC_OS: return util.format( 'https://get.helm.sh/helm-%s-darwin-amd64.zip', version ) case operatingSystem == WINDOWS: default: return util.format( 'https://get.helm.sh/helm-%s-windows-amd64.zip', version ) } } export async function downloadHelm(version: string): Promise { let cachedToolpath = toolCache.find(helmToolName, version) if (!cachedToolpath) { let helmDownloadPath try { helmDownloadPath = await toolCache.downloadTool( getHelmDownloadURL(version) ) } catch (exception) { throw new Error( util.format( 'Failed to download Helm from location', getHelmDownloadURL(version) ) ) } fs.chmodSync(helmDownloadPath, '777') const unzipedHelmPath = await toolCache.extractZip(helmDownloadPath) cachedToolpath = await toolCache.cacheDir( unzipedHelmPath, helmToolName, version ) } const helmpath = findHelm(cachedToolpath) if (!helmpath) { throw new Error( util.format('Helm executable not found in path', cachedToolpath) ) } fs.chmodSync(helmpath, '777') return helmpath } export function findHelm(rootFolder: string): string { fs.chmodSync(rootFolder, '777') var filelist: string[] = [] walkSync(rootFolder, filelist, helmToolName + getExecutableExtension()) if (!filelist || filelist.length == 0) { throw new Error( util.format('Helm executable not found in path', rootFolder) ) } else { return filelist[0] } } export var walkSync = function (dir, filelist, fileToFind) { var files = fs.readdirSync(dir) filelist = filelist || [] files.forEach(function (file) { if (fs.statSync(path.join(dir, file)).isDirectory()) { filelist = walkSync(path.join(dir, file), filelist, fileToFind) } else { core.debug(file) if (file == fileToFind) { filelist.push(path.join(dir, file)) } } }) return filelist } run().catch(core.setFailed)