Compare commits

..

1 Commits

Author SHA1 Message Date
e045d11f39 Changed the documentation to specify v before 'version' and code changes to append 'v' if it not provided in version (#11)
* Chnaged the documentation to sepcify v before 'version'

* append v to version incase it does not already include

* review comments fix
2020-05-14 12:12:24 +05:30
18 changed files with 335 additions and 12346 deletions

1
.github/CODEOWNERS vendored
View File

@ -1 +0,0 @@
* @Azure/aks-atlanta

View File

@ -1,10 +0,0 @@
---
name: 'Issue: Bug Report / Feature Request'
about: Create a report to help us improve
title: ''
labels: need-to-triage
assignees: ''
---

View File

@ -1,35 +0,0 @@
name: setting-default-labels
# Controls when the action will run.
on:
schedule:
- cron: "0 0/3 * * *"
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
- uses: actions/stale@v3
name: Setting issue as idle
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: "This issue is idle because it has been open for 14 days with no activity."
stale-issue-label: "idle"
days-before-stale: 14
days-before-close: -1
operations-per-run: 100
exempt-issue-labels: "backlog"
- uses: actions/stale@v3
name: Setting PR as idle
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-pr-message: "This PR is idle because it has been open for 14 days with no activity."
stale-pr-label: "idle"
days-before-stale: 14
days-before-close: -1
operations-per-run: 100

View File

@ -1,62 +0,0 @@
name: "Trigger Integration tests"
on:
push:
jobs:
trigger-integration-tests:
name: Trigger Integration tests - macos-latest
runs-on: macos-latest
env:
HELM_3_8_0: "v3.8.0"
HELM_3_7_2: "v3.7.2"
HELM_NO_V: "3.5.0"
PR_BASE_REF: ${{ github.event.pull_request.base.ref }}
steps:
- name: Check out repository
uses: actions/checkout@v2
- name: npm install and build
id: action-npm-build
run: |
echo $PR_BASE_REF
if [[ $PR_BASE_REF != releases/* ]]; then
npm install
npm run build
fi
- name: Setup helm
uses: ./
with:
version: ${{ env.HELM_3_8_0 }}
- name: Validate helm 3.8.0
run: |
if [[ $(helm version) != *$HELM_3_8_0* ]]; then
echo "HELM VERSION INCORRECT: HELM VERSION DOES NOT CONTAIN v3.8.0"
echo "HELM VERSION OUTPUT: $(helm version)"
exit 1
else
echo "HELM VERSION $HELM_3_8_0 INSTALLED SUCCESSFULLY"
fi
- name: Setup helm 3.7.2
uses: ./
with:
version: ${{ env.HELM_3_7_2 }}
- name: Validate 3.7.2
run: |
if [[ $(helm version) != *$HELM_3_7_2* ]]; then
echo "HELM VERSION INCORRECT: HELM VERSION DOES NOT CONTAIN v3.7.2"
echo "HELM VERSION OUTPUT: $(helm version)"
exit 1
else
echo "HELM VERSION $HELM_3_7_2 INSTALLED SUCCESSFULLY"
fi
- name: Setup helm 3.5.0 with no v in version
uses: ./
with:
version: ${{ env.HELM_NO_V }}
- name: Validate 3.5.0 without v in version
run: |
if [[ $(helm version) != *$HELM_NO_V* ]]; then
echo "HELM VERSION INCORRECT: HELM VERSION DOES NOT CONTAIN v3.5.0"
echo "HELM VERSION OUTPUT: $(helm version)"
exit 1
else
echo "HELM VERSION $HELM_3_5_0 INSTALLED SUCCESSFULLY"
fi

View File

@ -1,65 +0,0 @@
name: "Trigger Integration tests"
on:
pull_request:
branches:
- main
- "releases/*"
jobs:
trigger-integration-tests:
name: Trigger Integration tests
runs-on: ubuntu-latest
env:
HELM_3_8_0: "v3.8.0"
HELM_3_7_2: "v3.7.2"
HELM_NO_V: "3.5.0"
PR_BASE_REF: ${{ github.event.pull_request.base.ref }}
steps:
- name: Check out repository
uses: actions/checkout@v2
- name: npm install and build
id: action-npm-build
run: |
echo $PR_BASE_REF
if [[ $PR_BASE_REF != releases/* ]]; then
npm install
npm run build
fi
- name: Setup helm
uses: ./
with:
version: ${{ env.HELM_3_8_0 }}
- name: Validate helm 3.8.0
run: |
if [[ $(helm version) != *$HELM_3_8_0* ]]; then
echo "HELM VERSION INCORRECT: HELM VERSION DOES NOT CONTAIN v3.8.0"
echo "HELM VERSION OUTPUT: $(helm version)"
exit 1
else
echo "HELM VERSION $HELM_3_8_0 INSTALLED SUCCESSFULLY"
fi
- name: Setup helm 3.7.2
uses: ./
with:
version: ${{ env.HELM_3_7_2 }}
- name: Validate 3.7.2
run: |
if [[ $(helm version) != *$HELM_3_7_2* ]]; then
echo "HELM VERSION INCORRECT: HELM VERSION DOES NOT CONTAIN v3.7.2"
echo "HELM VERSION OUTPUT: $(helm version)"
exit 1
else
echo "HELM VERSION $HELM_3_7_2 INSTALLED SUCCESSFULLY"
fi
- name: Setup helm 3.5.0 with no v in version
uses: ./
with:
version: ${{ env.HELM_NO_V }}
- name: Validate 3.5.0 without v in version
run: |
if [[ $(helm version) != *$HELM_NO_V* ]]; then
echo "HELM VERSION INCORRECT: HELM VERSION DOES NOT CONTAIN v3.5.0"
echo "HELM VERSION OUTPUT: $(helm version)"
exit 1
else
echo "HELM VERSION $HELM_3_5_0 INSTALLED SUCCESSFULLY"
fi

View File

@ -1,14 +0,0 @@
name: Create release PR
on:
workflow_dispatch:
inputs:
release:
description: "Define release version (ex: v1, v2, v3)"
required: true
jobs:
release-pr:
uses: OliverMKing/javascript-release-workflow/.github/workflows/release-pr.yml@main
with:
release: ${{ github.event.inputs.release }}

View File

@ -1,10 +0,0 @@
name: Tag and create release draft
on:
push:
branches:
- releases/*
jobs:
tag-and-release:
uses: OliverMKing/javascript-release-workflow/.github/workflows/tag-and-release.yml@main

View File

@ -1,21 +0,0 @@
name: "Run unit tests."
on: # rebuild any PRs and main branch changes
pull_request:
branches:
- main
- "releases/*"
push:
branches:
- main
- "releases/*"
jobs:
build: # make sure build/ci works properly
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Run L0 tests.
run: |
npm install
npm test

6
.gitignore vendored
View File

@ -59,9 +59,3 @@ typings/
# next.js build output
.next
node_modules
coverage
# Transpiled JS
lib/

View File

@ -1,8 +1,7 @@
# Setup Helm
Install a specific version of helm binary on the runner.
## Example
#### Install a specific version of helm binary on the runner.
Acceptable values are latest or any semantic version string like v3.5.0 Use this action in workflow to define which version of helm will be used. v2 of this action only supports Helm3.
Acceptable values are latest or any semantic version string like v2.16.7 Use this action in workflow to define which version of helm will be used.
```yaml
- uses: azure/setup-helm@v1

View File

@ -1,15 +1,15 @@
name: "Helm tool installer"
description: "Install a specific version of helm binary. Acceptable values are latest or any semantic version string like 1.15.0"
inputs:
name: 'Helm tool installer'
description: 'Install a specific version of helm binary. Acceptable values are latest or any semantic version string like 1.15.0'
inputs:
version:
description: "Version of helm"
description: 'Version of helm'
required: true
default: "latest"
default: 'latest'
outputs:
helm-path:
description: "Path to the cached helm binary"
description: 'Path to the cached helm binary'
branding:
color: "blue"
color: 'blue'
runs:
using: "node12"
main: "lib/index.js"
using: 'node12'
main: 'lib/run.js'

View File

@ -1,18 +0,0 @@
module.exports = {
clearMocks: true,
moduleFileExtensions: ['js', 'ts'],
testEnvironment: 'node',
testMatch: ['**/*.test.ts'],
transform: {
'^.+\\.ts$': 'ts-jest'
},
verbose: true,
coverageThreshold: {
"global": {
"branches": 0,
"functions": 14,
"lines": 27,
"statements": 27
}
}
}

149
lib/run.js Normal file
View File

@ -0,0 +1,149 @@
"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
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 os = __importStar(require("os"));
const path = __importStar(require("path"));
const util = __importStar(require("util"));
const fs = __importStar(require("fs"));
const semver = __importStar(require("semver"));
const toolCache = __importStar(require("@actions/tool-cache"));
const core = __importStar(require("@actions/core"));
const helmToolName = 'helm';
const stableHelmVersion = 'v3.2.1';
const helmAllReleasesUrl = 'https://api.github.com/repos/helm/helm/releases';
function getExecutableExtension() {
if (os.type().match(/^Win/)) {
return '.exe';
}
return '';
}
function getHelmDownloadURL(version) {
switch (os.type()) {
case 'Linux':
return util.format('https://get.helm.sh/helm-%s-linux-amd64.zip', version);
case 'Darwin':
return util.format('https://get.helm.sh/helm-%s-darwin-amd64.zip', version);
case 'Windows_NT':
default:
return util.format('https://get.helm.sh/helm-%s-windows-amd64.zip', version);
}
}
function getStableHelmVersion() {
return __awaiter(this, void 0, void 0, function* () {
try {
const downloadPath = yield toolCache.downloadTool(helmAllReleasesUrl);
const responseArray = JSON.parse(fs.readFileSync(downloadPath, 'utf8').toString().trim());
let latestHelmVersion = semver.clean(stableHelmVersion);
responseArray.forEach(response => {
if (response && response.tag_name) {
let currentHelmVerison = semver.clean(response.tag_name.toString());
if (currentHelmVerison) {
if (currentHelmVerison.toString().indexOf('rc') == -1 && semver.gt(currentHelmVerison, latestHelmVersion)) {
//If current helm version is not a pre release and is greater than latest helm version
latestHelmVersion = currentHelmVerison;
}
}
}
});
latestHelmVersion = "v" + latestHelmVersion;
return latestHelmVersion;
}
catch (error) {
core.warning(util.format("Cannot get the latest Helm info from %s. Error %s. Using default Helm version %s.", helmAllReleasesUrl, error, stableHelmVersion));
}
return stableHelmVersion;
});
}
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;
};
function downloadHelm(version) {
return __awaiter(this, void 0, void 0, function* () {
if (!version) {
version = yield getStableHelmVersion();
}
let cachedToolpath = toolCache.find(helmToolName, version);
if (!cachedToolpath) {
let helmDownloadPath;
try {
helmDownloadPath = yield 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 = yield toolCache.extractZip(helmDownloadPath);
cachedToolpath = yield 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;
});
}
function findHelm(rootFolder) {
fs.chmodSync(rootFolder, '777');
var filelist = [];
walkSync(rootFolder, filelist, helmToolName + getExecutableExtension());
if (!filelist) {
throw new Error(util.format("Helm executable not found in path ", rootFolder));
}
else {
return filelist[0];
}
}
function run() {
return __awaiter(this, void 0, void 0, function* () {
let version = core.getInput('version', { 'required': true });
if (version.toLocaleLowerCase() === 'latest') {
version = yield getStableHelmVersion();
}
else if (!version.toLocaleLowerCase().startsWith('v')) {
version = 'v' + version;
}
let cachedPath = yield downloadHelm(version);
try {
if (!process.env['PATH'].startsWith(path.dirname(cachedPath))) {
core.addPath(path.dirname(cachedPath));
}
}
catch (_a) {
//do nothing, set as output variable
}
console.log(`Helm tool version: '${version}' has been cached at ${cachedPath}`);
core.setOutput('helm-path', cachedPath);
});
}
run().catch(core.setFailed);

11685
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -6,25 +6,19 @@
"author": "Anumita Shenoy",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.2.6",
"@actions/exec": "^1.0.0",
"@actions/io": "^1.0.0",
"@actions/tool-cache": "1.1.2",
"@octokit/graphql": "^4.6.1",
"@actions/io": "^1.0.0",
"@actions/core": "^1.0.0",
"@actions/exec": "^1.0.0",
"semver": "^6.1.0"
},
"main": "lib/index.js",
"main": "lib/run.js",
"scripts": {
"build": "ncc build src/run.ts -o lib",
"test": "jest",
"test-coverage": "jest --coverage"
"build": "tsc",
"test": "echo \"Error: no test specified\" && exit 1"
},
"devDependencies": {
"@types/jest": "^25.2.2",
"@types/node": "^12.0.10",
"@vercel/ncc": "^0.33.1",
"jest": "^26.0.1",
"ts-jest": "^25.5.1",
"typescript": "^3.5.2"
}
}
}

View File

@ -1,268 +0,0 @@
import * as run from "./run";
import * as os from "os";
import * as toolCache from "@actions/tool-cache";
import * as fs from "fs";
import * as path from "path";
import * as core from "@actions/core";
describe("run.ts", () => {
test("getExecutableExtension() - return .exe when os is Windows", () => {
jest.spyOn(os, "type").mockReturnValue("Windows_NT");
expect(run.getExecutableExtension()).toBe(".exe");
expect(os.type).toBeCalled();
});
test("getExecutableExtension() - return empty string for non-windows OS", () => {
jest.spyOn(os, "type").mockReturnValue("Darwin");
expect(run.getExecutableExtension()).toBe("");
expect(os.type).toBeCalled();
});
test("getHelmDownloadURL() - return the URL to download helm for Linux", () => {
jest.spyOn(os, "type").mockReturnValue("Linux");
jest.spyOn(os, "arch").mockReturnValueOnce("unknown");
const kubectlLinuxUrl = "https://get.helm.sh/helm-v3.8.0-linux-amd64.zip";
expect(run.getHelmDownloadURL("v3.8.0")).toBe(kubectlLinuxUrl);
expect(os.type).toBeCalled();
expect(os.arch).toBeCalled();
// arm64
jest.spyOn(os, "type").mockReturnValue("Linux");
jest.spyOn(os, "arch").mockReturnValueOnce("arm64");
const kubectlLinuxArm64Url =
"https://get.helm.sh/helm-v3.8.0-linux-arm64.zip";
expect(run.getHelmDownloadURL("v3.8.0")).toBe(kubectlLinuxArm64Url);
expect(os.type).toBeCalled();
expect(os.arch).toBeCalled();
});
test("getHelmDownloadURL() - return the URL to download helm for Darwin", () => {
jest.spyOn(os, "type").mockReturnValue("Darwin");
jest.spyOn(os, "arch").mockReturnValueOnce("unknown");
const kubectlDarwinUrl = "https://get.helm.sh/helm-v3.8.0-darwin-amd64.zip";
expect(run.getHelmDownloadURL("v3.8.0")).toBe(kubectlDarwinUrl);
expect(os.type).toBeCalled();
expect(os.arch).toBeCalled();
// arm64
jest.spyOn(os, "type").mockReturnValue("Darwin");
jest.spyOn(os, "arch").mockReturnValueOnce("arm64");
const kubectlDarwinArm64Url =
"https://get.helm.sh/helm-v3.8.0-darwin-arm64.zip";
expect(run.getHelmDownloadURL("v3.8.0")).toBe(kubectlDarwinArm64Url);
expect(os.type).toBeCalled();
expect(os.arch).toBeCalled();
});
test("getValidVersion() - return version with v prepended", () => {
expect(run.getValidVersion("3.8.0")).toBe("v3.8.0");
});
test("getHelmDownloadURL() - return the URL to download helm for Windows", () => {
jest.spyOn(os, "type").mockReturnValue("Windows_NT");
const kubectlWindowsUrl =
"https://get.helm.sh/helm-v3.8.0-windows-amd64.zip";
expect(run.getHelmDownloadURL("v3.8.0")).toBe(kubectlWindowsUrl);
expect(os.type).toBeCalled();
});
test("getLatestHelmVersion() - return the latest version of HELM", async () => {
try {
expect(await run.getLatestHelmVersion()).toBe("v3.8.0");
} catch (e) {
return e;
}
});
test("walkSync() - return path to the all files matching fileToFind in dir", () => {
jest.spyOn(fs, "readdirSync").mockImplementation((file, _) => {
if (file == "mainFolder")
return [
"file1" as unknown as fs.Dirent,
"file2" as unknown as fs.Dirent,
"folder1" as unknown as fs.Dirent,
"folder2" as unknown as fs.Dirent,
];
if (file == path.join("mainFolder", "folder1"))
return [
"file11" as unknown as fs.Dirent,
"file12" as unknown as fs.Dirent,
];
if (file == path.join("mainFolder", "folder2"))
return [
"file21" as unknown as fs.Dirent,
"file22" as unknown as fs.Dirent,
];
});
jest.spyOn(core, "debug").mockImplementation();
jest.spyOn(fs, "statSync").mockImplementation((file) => {
const isDirectory =
(file as string).toLowerCase().indexOf("file") == -1 ? true : false;
return { isDirectory: () => isDirectory } as fs.Stats;
});
expect(run.walkSync("mainFolder", null, "file21")).toEqual([
path.join("mainFolder", "folder2", "file21"),
]);
expect(fs.readdirSync).toBeCalledTimes(3);
expect(fs.statSync).toBeCalledTimes(8);
});
test("walkSync() - return empty array if no file with name fileToFind exists", () => {
jest.spyOn(fs, "readdirSync").mockImplementation((file, _) => {
if (file == "mainFolder")
return [
"file1" as unknown as fs.Dirent,
"file2" as unknown as fs.Dirent,
"folder1" as unknown as fs.Dirent,
"folder2" as unknown as fs.Dirent,
];
if (file == path.join("mainFolder", "folder1"))
return [
"file11" as unknown as fs.Dirent,
"file12" as unknown as fs.Dirent,
];
if (file == path.join("mainFolder", "folder2"))
return [
"file21" as unknown as fs.Dirent,
"file22" as unknown as fs.Dirent,
];
});
jest.spyOn(core, "debug").mockImplementation();
jest.spyOn(fs, "statSync").mockImplementation((file) => {
const isDirectory =
(file as string).toLowerCase().indexOf("file") == -1 ? true : false;
return { isDirectory: () => isDirectory } as fs.Stats;
});
expect(run.walkSync("mainFolder", null, "helm.exe")).toEqual([]);
expect(fs.readdirSync).toBeCalledTimes(3);
expect(fs.statSync).toBeCalledTimes(8);
});
test("findHelm() - change access permissions and find the helm in given directory", () => {
jest.spyOn(fs, "chmodSync").mockImplementation(() => {});
jest.spyOn(fs, "readdirSync").mockImplementation((file, _) => {
if (file == "mainFolder") return ["helm.exe" as unknown as fs.Dirent];
});
jest.spyOn(fs, "statSync").mockImplementation((file) => {
const isDirectory =
(file as string).indexOf("folder") == -1 ? false : true;
return { isDirectory: () => isDirectory } as fs.Stats;
});
jest.spyOn(os, "type").mockReturnValue("Windows_NT");
expect(run.findHelm("mainFolder")).toBe(
path.join("mainFolder", "helm.exe")
);
});
test("findHelm() - throw error if executable not found", () => {
jest.spyOn(fs, "chmodSync").mockImplementation(() => {});
jest.spyOn(fs, "readdirSync").mockImplementation((file, _) => {
if (file == "mainFolder") return [];
});
jest.spyOn(fs, "statSync").mockImplementation((file) => {
return { isDirectory: () => true } as fs.Stats;
});
jest.spyOn(os, "type").mockReturnValue("Windows_NT");
expect(() => run.findHelm("mainFolder")).toThrow(
"Helm executable not found in path mainFolder"
);
});
test("downloadHelm() - download helm and return path to it", async () => {
jest.spyOn(toolCache, "find").mockReturnValue("");
jest.spyOn(toolCache, "downloadTool").mockResolvedValue("pathToTool");
const response = JSON.stringify([{ tag_name: "v4.0.0" }]);
jest.spyOn(fs, "readFileSync").mockReturnValue(response);
jest.spyOn(os, "type").mockReturnValue("Windows_NT");
jest.spyOn(fs, "chmodSync").mockImplementation(() => {});
jest.spyOn(toolCache, "extractZip").mockResolvedValue("pathToUnzippedHelm");
jest.spyOn(toolCache, "cacheDir").mockResolvedValue("pathToCachedDir");
jest
.spyOn(fs, "readdirSync")
.mockImplementation((file, _) => ["helm.exe" as unknown as fs.Dirent]);
jest.spyOn(fs, "statSync").mockImplementation((file) => {
const isDirectory =
(file as string).indexOf("folder") == -1 ? false : true;
return { isDirectory: () => isDirectory } as fs.Stats;
});
expect(await run.downloadHelm("v4.0.0")).toBe(
path.join("pathToCachedDir", "helm.exe")
);
expect(toolCache.find).toBeCalledWith("helm", "v4.0.0");
expect(toolCache.downloadTool).toBeCalledWith(
"https://get.helm.sh/helm-v4.0.0-windows-amd64.zip"
);
expect(fs.chmodSync).toBeCalledWith("pathToTool", "777");
expect(toolCache.extractZip).toBeCalledWith("pathToTool");
expect(fs.chmodSync).toBeCalledWith(
path.join("pathToCachedDir", "helm.exe"),
"777"
);
});
test("downloadHelm() - throw error if unable to download", async () => {
jest.spyOn(toolCache, "find").mockReturnValue("");
jest.spyOn(toolCache, "downloadTool").mockImplementation(async () => {
throw "Unable to download";
});
jest.spyOn(os, "type").mockReturnValue("Windows_NT");
await expect(run.downloadHelm("v3.2.1")).rejects.toThrow(
"Failed to download Helm from location https://get.helm.sh/helm-v3.2.1-windows-amd64.zip"
);
expect(toolCache.find).toBeCalledWith("helm", "v3.2.1");
expect(toolCache.downloadTool).toBeCalledWith(
"https://get.helm.sh/helm-v3.2.1-windows-amd64.zip"
);
});
test("downloadHelm() - return path to helm tool with same version from toolCache", async () => {
jest.spyOn(toolCache, "find").mockReturnValue("pathToCachedDir");
jest.spyOn(fs, "chmodSync").mockImplementation(() => {});
expect(await run.downloadHelm("v3.2.1")).toBe(
path.join("pathToCachedDir", "helm.exe")
);
expect(toolCache.find).toBeCalledWith("helm", "v3.2.1");
expect(fs.chmodSync).toBeCalledWith(
path.join("pathToCachedDir", "helm.exe"),
"777"
);
});
test("downloadHelm() - throw error is helm is not found in path", async () => {
jest.spyOn(toolCache, "find").mockReturnValue("");
jest.spyOn(toolCache, "downloadTool").mockResolvedValue("pathToTool");
jest.spyOn(os, "type").mockReturnValue("Windows_NT");
jest.spyOn(fs, "chmodSync").mockImplementation();
jest.spyOn(toolCache, "extractZip").mockResolvedValue("pathToUnzippedHelm");
jest.spyOn(toolCache, "cacheDir").mockResolvedValue("pathToCachedDir");
jest.spyOn(fs, "readdirSync").mockImplementation((file, _) => []);
jest.spyOn(fs, "statSync").mockImplementation((file) => {
const isDirectory =
(file as string).indexOf("folder") == -1 ? false : true;
return { isDirectory: () => isDirectory } as fs.Stats;
});
await expect(run.downloadHelm("v3.2.1")).rejects.toThrow(
"Helm executable not found in path pathToCachedDir"
);
expect(toolCache.find).toBeCalledWith("helm", "v3.2.1");
expect(toolCache.downloadTool).toBeCalledWith(
"https://get.helm.sh/helm-v3.2.1-windows-amd64.zip"
);
expect(fs.chmodSync).toBeCalledWith("pathToTool", "777");
expect(toolCache.extractZip).toBeCalledWith("pathToTool");
});
});

View File

@ -1,194 +1,143 @@
// 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 os from 'os';
import * as path from 'path';
import * as util from 'util';
import * as fs from 'fs';
import * as semver from 'semver';
import * as toolCache from "@actions/tool-cache";
import * as core from "@actions/core";
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";
const helmToolName = 'helm';
const stableHelmVersion = 'v3.2.1';
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));
function getExecutableExtension(): string {
if (os.type().match(/^Win/)) {
return '.exe';
}
} catch {
//do nothing, set as output variable
}
console.log(
`Helm tool version: '${version}' has been cached at ${cachedPath}`
);
core.setOutput("helm-path", cachedPath);
return '';
}
//Returns version with proper v before it
export function getValidVersion(version: string): string {
return "v" + version;
}
function getHelmDownloadURL(version: string): string {
switch (os.type()) {
case 'Linux':
return util.format('https://get.helm.sh/helm-%s-linux-amd64.zip', 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
case 'Darwin':
return util.format('https://get.helm.sh/helm-%s-darwin-amd64.zip', version);
export async function getLatestHelmVersion(): Promise<string> {
const helmJSONPath: string = await toolCache.downloadTool(helmAllReleasesUrl);
case 'Windows_NT':
default:
return util.format('https://get.helm.sh/helm-%s-windows-amd64.zip', version);
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<string> {
let cachedToolpath = toolCache.find(helmToolName, version);
if (!cachedToolpath) {
let helmDownloadPath;
async function getStableHelmVersion(): Promise<string> {
try {
helmDownloadPath = await toolCache.downloadTool(
getHelmDownloadURL(version)
);
} catch (exception) {
throw new Error(
util.format(
"Failed to download Helm from location",
getHelmDownloadURL(version)
)
);
const downloadPath = await toolCache.downloadTool(helmAllReleasesUrl);
const responseArray = JSON.parse(fs.readFileSync(downloadPath, 'utf8').toString().trim());
let latestHelmVersion = semver.clean(stableHelmVersion);
responseArray.forEach(response => {
if (response && response.tag_name) {
let currentHelmVerison = semver.clean(response.tag_name.toString());
if (currentHelmVerison) {
if (currentHelmVerison.toString().indexOf('rc') == -1 && semver.gt(currentHelmVerison, latestHelmVersion)) {
//If current helm version is not a pre release and is greater than latest helm version
latestHelmVersion = currentHelmVerison;
}
}
}
});
latestHelmVersion = "v" + latestHelmVersion;
return latestHelmVersion;
} catch (error) {
core.warning(util.format("Cannot get the latest Helm info from %s. Error %s. Using default Helm version %s.", helmAllReleasesUrl, error, stableHelmVersion));
}
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;
return stableHelmVersion;
}
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;
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);
async function downloadHelm(version: string): Promise<string> {
if (!version) { version = await getStableHelmVersion(); }
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;
}
function findHelm(rootFolder: string): string {
fs.chmodSync(rootFolder, '777');
var filelist: string[] = [];
walkSync(rootFolder, filelist, helmToolName + getExecutableExtension());
if (!filelist) {
throw new Error(util.format("Helm executable not found in path ", rootFolder));
}
else {
return filelist[0];
}
}
async function run() {
let version = core.getInput('version', { 'required': true });
if (version.toLocaleLowerCase() === 'latest') {
version = await getStableHelmVersion();
} else if (!version.toLocaleLowerCase().startsWith('v')) {
version = 'v' + 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);
}
run().catch(core.setFailed);

View File

@ -45,7 +45,7 @@
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
// "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
@ -58,7 +58,6 @@
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
"skipLibCheck": true
},
"exclude": ["node_modules", "**/*.test.ts"]
}