7 Commits

Author SHA1 Message Date
9130a7accc 内网源 2023-10-24 13:40:03 +08:00
5119fcb908 v3 new release (#104)
bump @actions/core
2022-12-12 13:52:09 -05:00
f382f75448 v3 new release (#101) 2022-10-27 10:04:25 -04:00
b5b231a831 v3 new release (#89) 2022-07-25 14:01:37 -04:00
84b304dfb7 v3 new release (#87)
add token
2022-07-25 13:23:27 -04:00
e4f3964f67 v3 new release (#84)
swap to graphql
2022-07-11 13:48:02 -04:00
20d2b4f98d v3 new release (#80) 2022-06-27 14:17:15 -04:00
25 changed files with 23880 additions and 11862 deletions

View File

@ -0,0 +1,36 @@
name: Bug Report
description: File a bug report specifying all inputs you provided for the action, we will respond to this thread with any questions.
title: 'Bug: '
labels: ['bug', 'triage']
assignees: '@Azure/aks-atlanta'
body:
- type: textarea
id: What-happened
attributes:
label: What happened?
description: Tell us what happened and how is it different from the expected?
placeholder: Tell us what you see!
validations:
required: true
- type: checkboxes
id: Version
attributes:
label: Version
options:
- label: I am using the latest version
required: true
- type: input
id: Runner
attributes:
label: Runner
description: What runner are you using?
placeholder: Mention the runner info (self-hosted, operating system)
validations:
required: true
- type: textarea
id: Logs
attributes:
label: Relevant log output
description: Run in debug mode for the most verbose logs. Please feel free to attach a screenshot of the logs
validations:
required: true

6
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,6 @@
blank_issues_enabled: false
contact_links:
- name: GitHub Action "setup-helm" Support
url: https://github.com/Azure/setup-helm
security: https://github.com/Azure/setup-helm/blob/main/SECURITY.md
about: Please ask and answer questions here.

View File

@ -0,0 +1,13 @@
name: Feature Request
description: File a Feature Request form, we will respond to this thread with any questions.
title: 'Feature Request: '
labels: ['Feature']
assignees: '@Azure/aks-atlanta'
body:
- type: textarea
id: Feature_request
attributes:
label: Feature request
description: Provide example functionality and links to relevant docs
validations:
required: true

View File

@ -4,7 +4,4 @@ about: Create a report to help us improve
title: ''
labels: need-to-triage
assignees: ''
---

View File

@ -3,7 +3,7 @@ name: setting-default-labels
# Controls when the action will run.
on:
schedule:
- cron: "0 0/3 * * *"
- cron: '0 0/3 * * *'
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
@ -17,19 +17,19 @@ jobs:
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"
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"
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"
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,17 +1,17 @@
name: "Trigger Integration tests"
name: 'Trigger Integration tests'
on:
pull_request:
branches:
- main
- "releases/*"
- '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"
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

18
.github/workflows/prettify-code.yml vendored Normal file
View File

@ -0,0 +1,18 @@
name: 'Run prettify'
on:
pull_request:
push:
branches: [main]
jobs:
prettier:
name: Prettier Check
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v2
- name: Enforce Prettier
uses: actionsx/prettier@v2
with:
args: --check .

View File

@ -4,7 +4,7 @@ on:
workflow_dispatch:
inputs:
release:
description: "Define release version (ex: v1, v2, v3)"
description: 'Define release version (ex: v1, v2, v3)'
required: true
jobs:

View File

@ -1,13 +1,13 @@
name: "Run unit tests."
name: 'Run unit tests.'
on: # rebuild any PRs and main branch changes
pull_request:
branches:
- main
- "releases/*"
- 'releases/*'
push:
branches:
- main
- "releases/*"
- 'releases/*'
jobs:
build: # make sure build/ci works properly

3
.gitignore vendored
View File

@ -11,8 +11,6 @@ pids
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
@ -64,4 +62,3 @@ node_modules
coverage
# Transpiled JS
lib/

4
.prettierignore Normal file
View File

@ -0,0 +1,4 @@
# dependencies
/node_modules
coverage
/lib

8
.prettierrc.json Normal file
View File

@ -0,0 +1,8 @@
{
"trailingComma": "none",
"bracketSpacing": false,
"semi": false,
"tabWidth": 3,
"singleQuote": true,
"printWidth": 80
}

View File

@ -1,20 +1,25 @@
# Setup Helm
Install a specific version of helm binary on the runner.
## Example
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 v3.5.0 Use this action in workflow to define which version of helm will be used. v2 and v3 of this action only support Helm3.
```yaml
- uses: azure/setup-helm@v1
- uses: azure/setup-helm@v3
with:
version: '<version>' # default is latest stable
version: '<version>' # default is latest (stable)
token: ${{ secrets.GITHUB_TOKEN }} # only needed if version is 'latest'
id: install
```
> Note: When using latest version you might hit the GitHub GraphQL API hourly rate limit of 5,000. The action will then return the hardcoded default stable version (currently v3.9.0). If you rely on a certain version higher than the default, you should use that version instead of latest.
The cached helm binary path is prepended to the PATH environment variable as well as stored in the helm-path output variable.
Refer to the action metadata file for details about all the inputs https://github.com/Azure/setup-helm/blob/master/action.yml
# Contributing
## Contributing
This project welcomes contributions and suggestions. Most contributions require you to agree to a
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
@ -27,3 +32,7 @@ provided by the bot. You will only need to do this once across all repos using o
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
## Support
setup-helm is an open source project that is [**not** covered by the Microsoft Azure support policy](https://support.microsoft.com/en-us/help/2941892/support-for-linux-and-open-source-technology-in-azure). [Please search open issues here](https://github.com/Azure/setup-helm/issues), and if your issue isn't already represented please [open a new one](https://github.com/Azure/setup-helm/issues/new/choose). The project maintainers will respond to the best of their abilities.

View File

@ -4,7 +4,7 @@
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [many more](https://opensource.microsoft.com/).
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets Microsoft's [definition](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)) of a security vulnerability, please report it to us as described below.
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets Microsoft's [definition](<https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)>) of a security vulnerability, please report it to us as described below.
## Reporting Security Issues
@ -18,13 +18,13 @@ You should receive a response within 24 hours. If for some reason you do not, pl
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
- Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
- Full paths of source file(s) related to the manifestation of the issue
- The location of the affected source code (tag/branch/commit or direct URL)
- Any special configuration required to reproduce the issue
- Step-by-step instructions to reproduce the issue
- Proof-of-concept or exploit code (if possible)
- Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.

View File

@ -1,15 +1,18 @@
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"
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'
token:
description: GitHub token. Required only if 'version' == 'latest'
required: false
outputs:
helm-path:
description: "Path to the cached helm binary"
description: 'Path to the cached helm binary'
branding:
color: "blue"
color: 'blue'
runs:
using: "node16"
main: "lib/index.js"
using: 'node16'
main: 'lib/index.js'

View File

@ -8,11 +8,11 @@ module.exports = {
},
verbose: true,
coverageThreshold: {
"global": {
"branches": 0,
"functions": 14,
"lines": 27,
"statements": 27
global: {
branches: 0,
functions: 14,
lines: 27,
statements: 27
}
}
}

11879
lib/index.js Normal file

File diff suppressed because one or more lines are too long

1988
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -6,10 +6,11 @@
"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",
"@actions/core": "^1.10.0",
"@actions/exec": "^1.1.1",
"@actions/io": "^1.1.2",
"@actions/tool-cache": "2.0.1",
"@octokit/auth-action": "^2.0.0",
"@octokit/graphql": "^4.6.1",
"semver": "^6.1.0"
},
@ -17,12 +18,14 @@
"scripts": {
"build": "ncc build src/run.ts -o lib",
"test": "jest",
"test-coverage": "jest --coverage"
"test-coverage": "jest --coverage",
"format": "prettier --write .",
"format-check": "prettier --check ."
},
"devDependencies": {
"@types/jest": "^26.0.0",
"@types/node": "^12.0.10",
"@vercel/ncc": "^0.33.1",
"@vercel/ncc": "^0.34.0",
"jest": "^26.0.1",
"ts-jest": "^26.0.0",
"typescript": "^3.5.2"

View File

@ -1,268 +1,269 @@
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";
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");
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();
});
expect(run.getExecutableExtension()).toBe('.exe')
expect(os.type).toBeCalled()
})
test("getExecutableExtension() - return empty string for non-windows OS", () => {
jest.spyOn(os, "type").mockReturnValue("Darwin");
test('getExecutableExtension() - return empty string for non-windows OS', () => {
jest.spyOn(os, 'type').mockReturnValue('Darwin')
expect(run.getExecutableExtension()).toBe("");
expect(os.type).toBeCalled();
});
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";
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();
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");
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";
'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();
});
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";
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();
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");
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";
'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();
});
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('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");
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();
});
'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('getLatestHelmVersion() - return the stable version of HELM since its not authenticated', async () => {
expect(await run.getLatestHelmVersion()).toBe('v3.9.0')
})
test("walkSync() - return path to the all files matching fileToFind in dir", () => {
jest.spyOn(fs, "readdirSync").mockImplementation((file, _) => {
if (file == "mainFolder")
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"))
'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"))
'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) => {
'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;
});
(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);
});
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")
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"))
'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"))
'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) => {
'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;
});
(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);
});
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) => {
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");
(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")
);
});
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('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");
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(fs, "readdirSync")
.mockImplementation((file, _) => ["helm.exe" as unknown as fs.Dirent]);
jest.spyOn(fs, "statSync").mockImplementation((file) => {
.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;
});
(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(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");
'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"
);
});
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");
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");
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"
);
});
'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(() => {});
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(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"
);
});
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) => {
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;
});
(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");
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");
});
});
'https://get.helm.sh/helm-v3.2.1-windows-amd64.zip'
)
expect(fs.chmodSync).toBeCalledWith('pathToTool', '777')
expect(toolCache.extractZip).toBeCalledWith('pathToTool')
})
})

View File

@ -2,193 +2,209 @@
// 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 toolCache from "@actions/tool-cache";
import * as core from "@actions/core";
import * as toolCache from '@actions/tool-cache'
import * as core from '@actions/core'
import {graphql} from '@octokit/graphql'
import {createActionAuth} from '@octokit/auth-action'
import {create} from 'domain'
const helmToolName = "helm";
const stableHelmVersion = "v3.8.0";
const helmAllReleasesUrl = "https://api.github.com/repos/helm/helm/releases";
const helmToolName = 'helm'
const stableHelmVersion = 'v3.9.0'
export async function run() {
let version = core.getInput("version", { required: true });
let version = core.getInput('version', {required: true})
if(version !== "latest" && version[0] !== "v"){
version = getValidVersion(version);
if (version !== 'latest' && version[0] !== 'v') {
core.info('Getting latest Helm version')
version = getValidVersion(version)
}
if (version.toLocaleLowerCase() === "latest") {
version = await getLatestHelmVersion();
if (version.toLocaleLowerCase() === 'latest') {
version = await getLatestHelmVersion()
}
core.debug(util.format("Downloading %s", version));
let cachedPath = await downloadHelm(version);
core.startGroup(`Downloading ${version}`)
const cachedPath = await downloadHelm(version)
core.endGroup()
try {
if (!process.env["PATH"].startsWith(path.dirname(cachedPath))) {
core.addPath(path.dirname(cachedPath));
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);
core.info(`Helm tool version '${version}' has been cached at ${cachedPath}`)
core.setOutput('helm-path', cachedPath)
}
//Returns version with proper v before it
// Prefixes version with v
export function getValidVersion(version: string): string {
return "v" + version;
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
// Gets the latest helm version or returns a default stable if getting latest fails
export async function getLatestHelmVersion(): Promise<string> {
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;
const auth = createActionAuth()
const graphqlAuthenticated = graphql.defaults({
request: {hook: auth.hook}
})
const {repository} = await graphqlAuthenticated(
`
{
repository(name: "helm", owner: "helm") {
releases(first: 100, orderBy: {field: CREATED_AT, direction: DESC}) {
nodes {
tagName
isLatest
isDraft
isPrerelease
}
}
}
}
`
)
const latestValidRelease: string = repository.releases.nodes.find(
({tagName, isLatest, isDraft, isPreRelease}) =>
isValidVersion(tagName) && isLatest && !isDraft && !isPreRelease
)?.tagName
if (latestValidRelease) return latestValidRelease
} catch (err) {
core.warning(
util.format(
"Error while fetching the latest Helm release. Error: %s. Using default Helm version %s",
err.toString(),
stableHelmVersion
`Error while fetching latest Helm release: ${err.toString()}. Using default version ${stableHelmVersion}`
)
);
return stableHelmVersion;
return stableHelmVersion
}
return stableHelmVersion;
core.warning(
`Could not find valid release. Using default version ${stableHelmVersion}`
)
return stableHelmVersion
}
// isValidVersion checks if verison is a stable release
function isValidVersion(version: string): boolean {
return version.indexOf("rc") == -1;
return version.indexOf('rc') == -1
}
export function getExecutableExtension(): string {
if (os.type().match(/^Win/)) {
return ".exe";
return '.exe'
}
return "";
return ''
}
const LINUX = "Linux";
const MAC_OS = "Darwin";
const WINDOWS = "Windows_NT";
const ARM64 = "arm64";
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();
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",
'https://gitea.icodef.com/actions/binary-repo/raw/branch/main/helm/helm-%s-linux-arm64.zip',
version
);
)
case operatingSystem == LINUX:
return util.format(
"https://get.helm.sh/helm-%s-linux-amd64.zip",
'https://gitea.icodef.com/actions/binary-repo/raw/branch/main/helm/helm-%s-linux-amd64.zip',
version
);
)
case operatingSystem == MAC_OS && arch == ARM64:
return util.format(
"https://get.helm.sh/helm-%s-darwin-arm64.zip",
'https://gitea.icodef.com/actions/binary-repo/raw/branch/main/helm/helm-%s-darwin-arm64.zip',
version
);
)
case operatingSystem == MAC_OS:
return util.format(
"https://get.helm.sh/helm-%s-darwin-amd64.zip",
'https://gitea.icodef.com/actions/binary-repo/raw/branch/main/helm/helm-%s-darwin-amd64.zip',
version
);
)
case operatingSystem == WINDOWS:
default:
return util.format(
"https://get.helm.sh/helm-%s-windows-amd64.zip",
'https://gitea.icodef.com/actions/binary-repo/raw/branch/main/helm/helm-%s-windows-amd64.zip',
version
);
)
}
}
export async function downloadHelm(version: string): Promise<string> {
let cachedToolpath = toolCache.find(helmToolName, version);
let cachedToolpath = toolCache.find(helmToolName, version)
if (!cachedToolpath) {
let helmDownloadPath;
let helmDownloadPath
try {
helmDownloadPath = await toolCache.downloadTool(
getHelmDownloadURL(version)
);
)
} catch (exception) {
throw new Error(
util.format(
"Failed to download Helm from location",
getHelmDownloadURL(version)
`Failed to download Helm from location ${getHelmDownloadURL(
version
)}`
)
);
}
fs.chmodSync(helmDownloadPath, "777");
const unzipedHelmPath = await toolCache.extractZip(helmDownloadPath);
fs.chmodSync(helmDownloadPath, '777')
const unzipedHelmPath = await toolCache.extractZip(helmDownloadPath)
cachedToolpath = await toolCache.cacheDir(
unzipedHelmPath,
helmToolName,
version
);
)
}
const helmpath = findHelm(cachedToolpath);
const helmpath = findHelm(cachedToolpath)
if (!helmpath) {
throw new Error(
util.format("Helm executable not found in path", cachedToolpath)
);
util.format('Helm executable not found in path', cachedToolpath)
)
}
fs.chmodSync(helmpath, "777");
return helmpath;
fs.chmodSync(helmpath, '777')
return helmpath
}
export function findHelm(rootFolder: string): string {
fs.chmodSync(rootFolder, "777");
var filelist: string[] = [];
walkSync(rootFolder, filelist, helmToolName + getExecutableExtension());
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)
);
util.format('Helm executable not found in path', rootFolder)
)
} else {
return filelist[0];
return filelist[0]
}
}
export var walkSync = function (dir, filelist, fileToFind) {
var files = fs.readdirSync(dir);
filelist = filelist || [];
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);
filelist = walkSync(path.join(dir, file), filelist, fileToFind)
} else {
core.debug(file);
core.debug(file)
if (file == fileToFind) {
filelist.push(path.join(dir, file));
filelist.push(path.join(dir, file))
}
}
});
return filelist;
};
})
return filelist
}
run().catch(core.setFailed);
run().catch(core.setFailed)

View File

@ -2,8 +2,8 @@
"compilerOptions": {
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */,
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
@ -11,8 +11,8 @@
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./lib", /* Redirect output structure to the directory. */
"rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
"outDir": "./lib" /* Redirect output structure to the directory. */,
"rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
@ -23,7 +23,7 @@
/* Strict Type-Checking Options */
//"strict": true, /* Enable all strict type-checking options. */
"noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */
"noImplicitAny": false /* Raise error on expressions and declarations with an implied 'any' type. */,
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */