mirror of
https://github.com/Azure/setup-helm.git
synced 2025-07-17 11:20:42 +00:00
Compare commits
23 Commits
updating-r
...
Vidyareddy
Author | SHA1 | Date | |
---|---|---|---|
2caaa2f023 | |||
79266a2b40 | |||
6b0e7a31f6 | |||
85664e9295 | |||
f850d12cb3 | |||
17cd77473c | |||
484a64052d | |||
6e32762c2e | |||
17c21ab68c | |||
7f0153c54c | |||
a14110f6e6 | |||
a767c8d3a1 | |||
97c3a3f138 | |||
0a86c98d61 | |||
39f78708c2 | |||
fa870ea9a2 | |||
e00756a00e | |||
2998c83e16 | |||
5876560d6c | |||
7e6f48e5b4 | |||
da63a48ad7 | |||
cc2c85bd7e | |||
7e3c8fd604 |
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@ -1 +1 @@
|
|||||||
* @ds-ms
|
* @Azure/aks-atlanta
|
||||||
|
28
.github/ISSUE_TEMPLATE/bugReportForm.yml
vendored
Normal file
28
.github/ISSUE_TEMPLATE/bugReportForm.yml
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
name: Bug Report
|
||||||
|
description: File a bug report, we will respond to this thread with any questions.
|
||||||
|
title: 'Bug: '
|
||||||
|
labels: ['bug', 'triage']
|
||||||
|
assignees: '@Azure/aks-atlanta'
|
||||||
|
body:
|
||||||
|
- type: input
|
||||||
|
id: What-happened
|
||||||
|
attributes:
|
||||||
|
label: What happened?
|
||||||
|
description: Tell us what happened and how is it different form the expected?
|
||||||
|
placeholder: Tell us what you see!
|
||||||
|
validations:
|
||||||
|
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: input
|
||||||
|
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
|
||||||
|
render: shell
|
6
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
6
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: GitHub Action "aks-set-context" Support
|
||||||
|
url: https://github.com/Azure/aks-set-context
|
||||||
|
security: https://github.com/Azure/aks-set-context/blob/main/SECURITY.md
|
||||||
|
about: Please ask and answer questions here.
|
13
.github/ISSUE_TEMPLATE/featureRequestForm.yml
vendored
Normal file
13
.github/ISSUE_TEMPLATE/featureRequestForm.yml
vendored
Normal 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: input
|
||||||
|
id: Feature request
|
||||||
|
attributes:
|
||||||
|
label: Feature request
|
||||||
|
description: Provide example functionality and links to relevant docs
|
||||||
|
validations:
|
||||||
|
required: true
|
@ -4,7 +4,4 @@ about: Create a report to help us improve
|
|||||||
title: ''
|
title: ''
|
||||||
labels: need-to-triage
|
labels: need-to-triage
|
||||||
assignees: ''
|
assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
|
33
.github/workflows/TriggerIntegrationTests.sh
vendored
33
.github/workflows/TriggerIntegrationTests.sh
vendored
@ -1,33 +0,0 @@
|
|||||||
token=$1
|
|
||||||
commit=$2
|
|
||||||
repository=$3
|
|
||||||
prNumber=$4
|
|
||||||
frombranch=$5
|
|
||||||
tobranch=$6
|
|
||||||
patUser=$7
|
|
||||||
|
|
||||||
getPayLoad() {
|
|
||||||
cat <<EOF
|
|
||||||
{
|
|
||||||
"event_type": "SetupHelmActionPR",
|
|
||||||
"client_payload":
|
|
||||||
{
|
|
||||||
"action": "SetupHelm",
|
|
||||||
"commit": "$commit",
|
|
||||||
"repository": "$repository",
|
|
||||||
"prNumber": "$prNumber",
|
|
||||||
"tobranch": "$tobranch",
|
|
||||||
"frombranch": "$frombranch"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
response=$(curl -u $patUser:$token -X POST https://api.github.com/repos/Azure/azure-actions-integration-tests/dispatches --data "$(getPayLoad)")
|
|
||||||
|
|
||||||
if [ "$response" == "" ]; then
|
|
||||||
echo "Integration tests triggered successfully"
|
|
||||||
else
|
|
||||||
echo "Triggering integration tests failed with: '$response'"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
3
.github/workflows/defaultLabels.yml
vendored
3
.github/workflows/defaultLabels.yml
vendored
@ -3,7 +3,7 @@ name: setting-default-labels
|
|||||||
# Controls when the action will run.
|
# Controls when the action will run.
|
||||||
on:
|
on:
|
||||||
schedule:
|
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
|
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||||
jobs:
|
jobs:
|
||||||
@ -13,7 +13,6 @@ jobs:
|
|||||||
|
|
||||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- uses: actions/stale@v3
|
- uses: actions/stale@v3
|
||||||
name: Setting issue as idle
|
name: Setting issue as idle
|
||||||
with:
|
with:
|
||||||
|
60
.github/workflows/integration-tests.yml
vendored
60
.github/workflows/integration-tests.yml
vendored
@ -1,19 +1,65 @@
|
|||||||
name: "Trigger Integration tests"
|
name: 'Trigger Integration tests'
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- main
|
||||||
- 'releases/*'
|
- 'releases/*'
|
||||||
jobs:
|
jobs:
|
||||||
trigger-integration-tests:
|
trigger-integration-tests:
|
||||||
name: Trigger Integration tests
|
name: Trigger Integration tests
|
||||||
runs-on: ubuntu-latest
|
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:
|
steps:
|
||||||
- name: Check out repository
|
- name: Check out repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
with:
|
- name: npm install and build
|
||||||
path: IntegrationTests
|
id: action-npm-build
|
||||||
|
|
||||||
- name: Trigger Test run
|
|
||||||
run: |
|
run: |
|
||||||
bash ./IntegrationTests/.github/workflows/TriggerIntegrationTests.sh ${{ secrets.L2_REPO_TOKEN }} ${{ github.event.pull_request.head.sha }} ${{ github.repository }} ${{ github.event.pull_request.number }} ${{ github.event.pull_request.head.ref }} ${{ github.event.pull_request.base.ref }} ${{ secrets.L2_REPO_USER }}
|
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
|
||||||
|
18
.github/workflows/prettify-code.yml
vendored
Normal file
18
.github/workflows/prettify-code.yml
vendored
Normal 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 .
|
14
.github/workflows/release-pr.yml
vendored
Normal file
14
.github/workflows/release-pr.yml
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
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 }}
|
10
.github/workflows/tag-and-draft.yml
vendored
Normal file
10
.github/workflows/tag-and-draft.yml
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
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
|
6
.github/workflows/unit-tests.yml
vendored
6
.github/workflows/unit-tests.yml
vendored
@ -1,12 +1,12 @@
|
|||||||
name: "Run unit tests."
|
name: 'Run unit tests.'
|
||||||
on: # rebuild any PRs and main branch changes
|
on: # rebuild any PRs and main branch changes
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- main
|
||||||
- 'releases/*'
|
- 'releases/*'
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- main
|
||||||
- 'releases/*'
|
- 'releases/*'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -62,3 +62,6 @@ typings/
|
|||||||
|
|
||||||
node_modules
|
node_modules
|
||||||
coverage
|
coverage
|
||||||
|
|
||||||
|
# Transpiled JS
|
||||||
|
lib/
|
||||||
|
4
.prettierignore
Normal file
4
.prettierignore
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
coverage
|
||||||
|
/lib
|
8
.prettierrc.json
Normal file
8
.prettierrc.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"trailingComma": "none",
|
||||||
|
"bracketSpacing": false,
|
||||||
|
"semi": false,
|
||||||
|
"tabWidth": 3,
|
||||||
|
"singleQuote": true,
|
||||||
|
"printWidth": 80
|
||||||
|
}
|
13
README.md
13
README.md
@ -1,20 +1,25 @@
|
|||||||
# Setup Helm
|
# Setup Helm
|
||||||
|
|
||||||
Install a specific version of helm binary on the runner.
|
Install a specific version of helm binary on the runner.
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
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.
|
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
|
```yaml
|
||||||
- uses: azure/setup-helm@v1
|
- uses: azure/setup-helm@v3
|
||||||
with:
|
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
|
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.
|
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
|
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
|
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
|
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
|
||||||
|
16
SECURITY.md
16
SECURITY.md
@ -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/).
|
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
|
## 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:
|
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.)
|
- 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
|
- 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)
|
- The location of the affected source code (tag/branch/commit or direct URL)
|
||||||
* Any special configuration required to reproduce the issue
|
- Any special configuration required to reproduce the issue
|
||||||
* Step-by-step instructions to reproduce the issue
|
- Step-by-step instructions to reproduce the issue
|
||||||
* Proof-of-concept or exploit code (if possible)
|
- Proof-of-concept or exploit code (if possible)
|
||||||
* Impact of the issue, including how an attacker might exploit the issue
|
- Impact of the issue, including how an attacker might exploit the issue
|
||||||
|
|
||||||
This information will help us triage your report more quickly.
|
This information will help us triage your report more quickly.
|
||||||
|
|
||||||
|
@ -1,195 +0,0 @@
|
|||||||
import * as run from '../src/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');
|
|
||||||
const kubectlLinuxUrl = 'https://get.helm.sh/helm-v3.2.1-linux-amd64.zip'
|
|
||||||
|
|
||||||
expect(run.getHelmDownloadURL('v3.2.1')).toBe(kubectlLinuxUrl);
|
|
||||||
expect(os.type).toBeCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('getHelmDownloadURL() - return the URL to download helm for Darwin', () => {
|
|
||||||
jest.spyOn(os, 'type').mockReturnValue('Darwin');
|
|
||||||
const kubectlDarwinUrl = 'https://get.helm.sh/helm-v3.2.1-darwin-amd64.zip'
|
|
||||||
|
|
||||||
expect(run.getHelmDownloadURL('v3.2.1')).toBe(kubectlDarwinUrl);
|
|
||||||
expect(os.type).toBeCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
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.2.1-windows-amd64.zip'
|
|
||||||
expect(run.getHelmDownloadURL('v3.2.1')).toBe(kubectlWindowsUrl);
|
|
||||||
expect(os.type).toBeCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('getStableHelmVersion() - download stable version file, read version and return it', async () => {
|
|
||||||
jest.spyOn(toolCache, 'downloadTool').mockResolvedValue('pathToTool');
|
|
||||||
const response = JSON.stringify(
|
|
||||||
[
|
|
||||||
{
|
|
||||||
'tag_name': 'v4.0.0'
|
|
||||||
}, {
|
|
||||||
'tag_name': 'v3.0.0'
|
|
||||||
}, {
|
|
||||||
'tag_name': 'v2.0.0'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
);
|
|
||||||
jest.spyOn(fs, 'readFileSync').mockReturnValue(response);
|
|
||||||
|
|
||||||
expect(await run.getStableHelmVersion()).toBe('v4.0.0');
|
|
||||||
expect(toolCache.downloadTool).toBeCalled();
|
|
||||||
expect(fs.readFileSync).toBeCalledWith('pathToTool', 'utf8');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('getStableHelmVersion() - return default version if error occurs while getting latest version', async () => {
|
|
||||||
jest.spyOn(toolCache, 'downloadTool').mockRejectedValue('Unable to download');
|
|
||||||
jest.spyOn(core, 'warning').mockImplementation();
|
|
||||||
|
|
||||||
expect(await run.getStableHelmVersion()).toBe('v3.2.1');
|
|
||||||
expect(toolCache.downloadTool).toBeCalled();
|
|
||||||
expect(core.warning).toBeCalledWith("Cannot get the latest Helm info from https://api.github.com/repos/helm/helm/releases. Error Unable to download. Using default Helm version v3.2.1.");
|
|
||||||
});
|
|
||||||
|
|
||||||
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(null)).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');
|
|
||||||
});
|
|
||||||
});
|
|
@ -6,14 +6,13 @@ inputs:
|
|||||||
required: true
|
required: true
|
||||||
default: 'latest'
|
default: 'latest'
|
||||||
token:
|
token:
|
||||||
description: 'Github token'
|
description: GitHub token. Required only if 'version' == 'latest'
|
||||||
default: ${{ github.token }}
|
required: false
|
||||||
required: true
|
|
||||||
outputs:
|
outputs:
|
||||||
helm-path:
|
helm-path:
|
||||||
description: 'Path to the cached helm binary'
|
description: 'Path to the cached helm binary'
|
||||||
branding:
|
branding:
|
||||||
color: 'blue'
|
color: 'blue'
|
||||||
runs:
|
runs:
|
||||||
using: 'node12'
|
using: 'node16'
|
||||||
main: 'lib/run.js'
|
main: 'lib/index.js'
|
||||||
|
@ -8,11 +8,11 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
verbose: true,
|
verbose: true,
|
||||||
coverageThreshold: {
|
coverageThreshold: {
|
||||||
"global": {
|
global: {
|
||||||
"branches": 0,
|
branches: 0,
|
||||||
"functions": 14,
|
functions: 14,
|
||||||
"lines": 27,
|
lines: 27,
|
||||||
"statements": 27
|
statements: 27
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
222
lib/run.js
222
lib/run.js
@ -1,222 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
// Copyright (c) Microsoft Corporation.
|
|
||||||
// Copyright (c) Microsoft Corporation.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
||||||
}) : (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
o[k2] = m[k];
|
|
||||||
}));
|
|
||||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
||||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
||||||
}) : function(o, v) {
|
|
||||||
o["default"] = v;
|
|
||||||
});
|
|
||||||
var __importStar = (this && this.__importStar) || function (mod) {
|
|
||||||
if (mod && mod.__esModule) return mod;
|
|
||||||
var result = {};
|
|
||||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
||||||
__setModuleDefault(result, mod);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
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());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
exports.getStableHelmVersion = void 0;
|
|
||||||
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 graphql_1 = require("@octokit/graphql");
|
|
||||||
const helmToolName = 'helm';
|
|
||||||
const stableHelmVersion = 'v3.2.1';
|
|
||||||
const stableHelm3Version = 'v3.5.3';
|
|
||||||
const stableHelm2Version = 'v2.17.0';
|
|
||||||
const LATEST_HELM2_VERSION = '2.*';
|
|
||||||
const LATEST_HELM3_VERSION = '3.*';
|
|
||||||
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;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
exports.getStableHelmVersion = getStableHelmVersion;
|
|
||||||
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 getLatestHelmVersionFor("v3");
|
|
||||||
}
|
|
||||||
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 getLatestHelmVersionFor(type) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
const token = core.getInput('token', { 'required': true });
|
|
||||||
try {
|
|
||||||
const { repository } = yield graphql_1.graphql(`{
|
|
||||||
repository(name: "helm", owner: "helm") {
|
|
||||||
releases(last: 100) {
|
|
||||||
nodes {
|
|
||||||
tagName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`, {
|
|
||||||
headers: {
|
|
||||||
authorization: `token ${token}`
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const releases = repository.releases.nodes.reverse();
|
|
||||||
let latestValidRelease = releases.find(release => isValidVersion(release.tagName, type));
|
|
||||||
if (latestValidRelease)
|
|
||||||
return latestValidRelease.tagName;
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
core.warning(util.format("Error while fetching the latest Helm %s release. Error: %s. Using default Helm version %s.", type, err.toString(), getStableHelmVersionFor(type)));
|
|
||||||
return getStableHelmVersionFor(type);
|
|
||||||
}
|
|
||||||
core.warning(util.format("Could not find stable release for Helm %s. Using default Helm version %s.", type, getStableHelmVersionFor(type)));
|
|
||||||
return getStableHelmVersionFor(type);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
function getStableHelmVersionFor(type) {
|
|
||||||
return type === "v2" ? stableHelm2Version : stableHelm3Version;
|
|
||||||
}
|
|
||||||
// isValidVersion checks if verison matches the specified type and is a stable release
|
|
||||||
function isValidVersion(version, type) {
|
|
||||||
if (!version.toLocaleLowerCase().startsWith(type))
|
|
||||||
return false;
|
|
||||||
return version.indexOf('rc') == -1;
|
|
||||||
}
|
|
||||||
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 (process.env['HELM_INSTALLER_LEGACY_VERSIONING'] == 'true') {
|
|
||||||
if (version.toLocaleLowerCase() === 'latest') {
|
|
||||||
version = yield getStableHelmVersion();
|
|
||||||
}
|
|
||||||
else if (!version.toLocaleLowerCase().startsWith('v')) {
|
|
||||||
version = 'v' + version;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (version.toLocaleLowerCase() === 'latest' || version === LATEST_HELM3_VERSION) {
|
|
||||||
version = yield getLatestHelmVersionFor("v3");
|
|
||||||
}
|
|
||||||
else if (version === LATEST_HELM2_VERSION) {
|
|
||||||
version = yield getLatestHelmVersionFor("v2");
|
|
||||||
}
|
|
||||||
else if (!version.toLocaleLowerCase().startsWith('v')) {
|
|
||||||
version = 'v' + version;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
core.debug(util.format("Downloading %s", 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);
|
|
11328
package-lock.json
generated
11328
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
16
package.json
16
package.json
@ -10,20 +10,24 @@
|
|||||||
"@actions/exec": "^1.0.0",
|
"@actions/exec": "^1.0.0",
|
||||||
"@actions/io": "^1.0.0",
|
"@actions/io": "^1.0.0",
|
||||||
"@actions/tool-cache": "1.1.2",
|
"@actions/tool-cache": "1.1.2",
|
||||||
|
"@octokit/auth-action": "^2.0.0",
|
||||||
"@octokit/graphql": "^4.6.1",
|
"@octokit/graphql": "^4.6.1",
|
||||||
"semver": "^6.1.0"
|
"semver": "^6.1.0"
|
||||||
},
|
},
|
||||||
"main": "lib/run.js",
|
"main": "lib/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc --outDir ./lib --rootDir ./src",
|
"build": "ncc build src/run.ts -o lib",
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
"test-coverage": "jest --coverage"
|
"test-coverage": "jest --coverage",
|
||||||
|
"format": "prettier --write .",
|
||||||
|
"format-check": "prettier --check ."
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/jest": "^26.0.0",
|
||||||
"@types/node": "^12.0.10",
|
"@types/node": "^12.0.10",
|
||||||
"typescript": "^3.5.2",
|
"@vercel/ncc": "^0.34.0",
|
||||||
"jest": "^26.0.1",
|
"jest": "^26.0.1",
|
||||||
"@types/jest": "^25.2.2",
|
"ts-jest": "^26.0.0",
|
||||||
"ts-jest": "^25.5.1"
|
"typescript": "^3.5.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
269
src/run.test.ts
Normal file
269
src/run.test.ts
Normal file
@ -0,0 +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'
|
||||||
|
|
||||||
|
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 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')
|
||||||
|
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')
|
||||||
|
})
|
||||||
|
})
|
318
src/run.ts
318
src/run.ts
@ -2,117 +2,62 @@
|
|||||||
// Copyright (c) Microsoft Corporation.
|
// Copyright (c) Microsoft Corporation.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
import * as os from 'os';
|
import * as os from 'os'
|
||||||
import * as path from 'path';
|
import * as path from 'path'
|
||||||
import * as util from 'util';
|
import * as util from 'util'
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs'
|
||||||
import * as semver from 'semver';
|
|
||||||
|
|
||||||
import * as toolCache from '@actions/tool-cache';
|
import * as toolCache from '@actions/tool-cache'
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core'
|
||||||
import { graphql } from '@octokit/graphql';
|
import {graphql} from '@octokit/graphql'
|
||||||
|
import {createActionAuth} from '@octokit/auth-action'
|
||||||
|
import {create} from 'domain'
|
||||||
|
|
||||||
const helmToolName = 'helm';
|
const helmToolName = 'helm'
|
||||||
const stableHelmVersion = 'v3.2.1';
|
const stableHelmVersion = 'v3.9.0'
|
||||||
const stableHelm3Version = 'v3.5.3';
|
|
||||||
const stableHelm2Version = 'v2.17.0';
|
|
||||||
const LATEST_HELM2_VERSION = '2.*';
|
|
||||||
const LATEST_HELM3_VERSION = '3.*';
|
|
||||||
const helmAllReleasesUrl = 'https://api.github.com/repos/helm/helm/releases';
|
|
||||||
|
|
||||||
export function getExecutableExtension(): string {
|
export async function run() {
|
||||||
if (os.type().match(/^Win/)) {
|
let version = core.getInput('version', {required: true})
|
||||||
return '.exe';
|
|
||||||
|
if (version !== 'latest' && version[0] !== 'v') {
|
||||||
|
core.info('Getting latest Helm version')
|
||||||
|
version = getValidVersion(version)
|
||||||
}
|
}
|
||||||
return '';
|
if (version.toLocaleLowerCase() === 'latest') {
|
||||||
|
version = await getLatestHelmVersion()
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getHelmDownloadURL(version: string): string {
|
core.startGroup(`Downloading ${version}`)
|
||||||
switch (os.type()) {
|
const cachedPath = await downloadHelm(version)
|
||||||
case 'Linux':
|
core.endGroup()
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getStableHelmVersion(): Promise<string> {
|
|
||||||
try {
|
try {
|
||||||
const downloadPath = await toolCache.downloadTool(helmAllReleasesUrl);
|
if (!process.env['PATH'].startsWith(path.dirname(cachedPath))) {
|
||||||
const responseArray = JSON.parse(fs.readFileSync(downloadPath, 'utf8').toString().trim());
|
core.addPath(path.dirname(cachedPath))
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
} catch {
|
||||||
}
|
//do nothing, set as output variable
|
||||||
});
|
|
||||||
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;
|
core.info(`Helm tool version '${version}' has been cached at ${cachedPath}`)
|
||||||
|
core.setOutput('helm-path', cachedPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
export var walkSync = function (dir, filelist, fileToFind) {
|
// Prefixes version with v
|
||||||
var files = fs.readdirSync(dir);
|
export function getValidVersion(version: string): string {
|
||||||
filelist = filelist || [];
|
return 'v' + version
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
export async function downloadHelm(version: string): Promise<string> {
|
// Gets the latest helm version or returns a default stable if getting latest fails
|
||||||
if (!version) { version = await getStableHelmVersion(); }
|
export async function getLatestHelmVersion(): Promise<string> {
|
||||||
let cachedToolpath = toolCache.find(helmToolName, version);
|
|
||||||
if (!cachedToolpath) {
|
|
||||||
let helmDownloadPath;
|
|
||||||
try {
|
try {
|
||||||
helmDownloadPath = await toolCache.downloadTool(getHelmDownloadURL(version));
|
const auth = createActionAuth()
|
||||||
} catch (exception) {
|
const graphqlAuthenticated = graphql.defaults({
|
||||||
throw new Error(util.format("Failed to download Helm from location", getHelmDownloadURL(version)));
|
request: {hook: auth.hook}
|
||||||
}
|
})
|
||||||
|
const {repository} = await graphqlAuthenticated(
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getLatestHelmVersionFor(type: string): Promise<string> {
|
|
||||||
const token = core.getInput('token', { 'required': true });
|
|
||||||
try {
|
|
||||||
const { repository } = await graphql(
|
|
||||||
`{
|
|
||||||
repository(name: "helm", owner: "helm") {
|
repository(name: "helm", owner: "helm") {
|
||||||
releases(last: 100) {
|
releases(last: 100) {
|
||||||
nodes {
|
nodes {
|
||||||
@ -120,83 +65,142 @@ async function getLatestHelmVersionFor(type: string): Promise<string> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}`,
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
authorization: `token ${token}`
|
|
||||||
}
|
}
|
||||||
}
|
`
|
||||||
);
|
)
|
||||||
|
const releases: string[] = repository.releases.nodes
|
||||||
const releases = repository.releases.nodes.reverse();
|
.reverse()
|
||||||
let latestValidRelease = releases.find(release => isValidVersion(release.tagName, type));
|
.map((node: {tagName: string}) => node.tagName)
|
||||||
if (latestValidRelease)
|
const latestValidRelease = releases.find((tag) => isValidVersion(tag))
|
||||||
return latestValidRelease.tagName;
|
if (latestValidRelease) return latestValidRelease
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
core.warning(util.format("Error while fetching the latest Helm %s release. Error: %s. Using default Helm version %s.", type, err.toString(), getStableHelmVersionFor(type)));
|
core.warning(
|
||||||
return getStableHelmVersionFor(type);
|
`Error while fetching latest Helm release: ${err.toString()}. Using default version ${stableHelmVersion}`
|
||||||
}
|
)
|
||||||
core.warning(util.format("Could not find stable release for Helm %s. Using default Helm version %s.", type, getStableHelmVersionFor(type)));
|
return stableHelmVersion
|
||||||
return getStableHelmVersionFor(type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStableHelmVersionFor(type: string) {
|
core.warning(
|
||||||
return type === "v2" ? stableHelm2Version : stableHelm3Version;
|
`Could not find valid release. Using default version ${stableHelmVersion}`
|
||||||
|
)
|
||||||
|
return stableHelmVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
// isValidVersion checks if verison matches the specified type and is a stable release
|
// isValidVersion checks if verison is a stable release
|
||||||
function isValidVersion(version: string, type: string): boolean {
|
function isValidVersion(version: string): boolean {
|
||||||
if (!version.toLocaleLowerCase().startsWith(type))
|
return version.indexOf('rc') == -1
|
||||||
return false;
|
}
|
||||||
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
|
||||||
|
try {
|
||||||
|
helmDownloadPath = await toolCache.downloadTool(
|
||||||
|
getHelmDownloadURL(version)
|
||||||
|
)
|
||||||
|
} catch (exception) {
|
||||||
|
throw new Error(
|
||||||
|
`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 {
|
export function findHelm(rootFolder: string): string {
|
||||||
fs.chmodSync(rootFolder, '777');
|
fs.chmodSync(rootFolder, '777')
|
||||||
var filelist: string[] = [];
|
var filelist: string[] = []
|
||||||
walkSync(rootFolder, filelist, helmToolName + getExecutableExtension());
|
walkSync(rootFolder, filelist, helmToolName + getExecutableExtension())
|
||||||
if (!filelist || filelist.length == 0) {
|
if (!filelist || filelist.length == 0) {
|
||||||
throw new Error(util.format("Helm executable not found in path", rootFolder));
|
throw new Error(
|
||||||
}
|
util.format('Helm executable not found in path', rootFolder)
|
||||||
else {
|
)
|
||||||
return filelist[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function run() {
|
|
||||||
let version = core.getInput('version', { 'required': true });
|
|
||||||
|
|
||||||
if (process.env['HELM_INSTALLER_LEGACY_VERSIONING'] == 'true') {
|
|
||||||
if (version.toLocaleLowerCase() === 'latest') {
|
|
||||||
version = await getStableHelmVersion();
|
|
||||||
} else if (!version.toLocaleLowerCase().startsWith('v')) {
|
|
||||||
version = 'v' + version;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (version.toLocaleLowerCase() === 'latest' || version === LATEST_HELM3_VERSION) {
|
return filelist[0]
|
||||||
version = await getLatestHelmVersionFor("v3");
|
|
||||||
} else if (version === LATEST_HELM2_VERSION) {
|
|
||||||
version = await getLatestHelmVersionFor("v2");
|
|
||||||
} else if (!version.toLocaleLowerCase().startsWith('v')) {
|
|
||||||
version = 'v' + version;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
core.debug(util.format("Downloading %s", version));
|
export var walkSync = function (dir, filelist, fileToFind) {
|
||||||
let cachedPath = await downloadHelm(version);
|
var files = fs.readdirSync(dir)
|
||||||
|
filelist = filelist || []
|
||||||
try {
|
files.forEach(function (file) {
|
||||||
|
if (fs.statSync(path.join(dir, file)).isDirectory()) {
|
||||||
if (!process.env['PATH'].startsWith(path.dirname(cachedPath))) {
|
filelist = walkSync(path.join(dir, file), filelist, fileToFind)
|
||||||
core.addPath(path.dirname(cachedPath));
|
} else {
|
||||||
|
core.debug(file)
|
||||||
|
if (file == fileToFind) {
|
||||||
|
filelist.push(path.join(dir, file))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch {
|
})
|
||||||
//do nothing, set as output variable
|
return filelist
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Helm tool version: '${version}' has been cached at ${cachedPath}`);
|
run().catch(core.setFailed)
|
||||||
core.setOutput('helm-path', cachedPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
run().catch(core.setFailed);
|
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
/* Basic Options */
|
/* Basic Options */
|
||||||
// "incremental": true, /* Enable incremental compilation */
|
// "incremental": true, /* Enable incremental compilation */
|
||||||
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' 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'. */
|
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
|
||||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||||
// "checkJs": true, /* Report errors in .js files. */
|
// "checkJs": true, /* Report errors in .js files. */
|
||||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
// "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. */
|
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||||
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
||||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||||
"outDir": "./lib", /* Redirect output structure to the directory. */
|
"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. */
|
"rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,
|
||||||
// "composite": true, /* Enable project compilation */
|
// "composite": true, /* Enable project compilation */
|
||||||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
||||||
// "removeComments": true, /* Do not emit comments to output. */
|
// "removeComments": true, /* Do not emit comments to output. */
|
||||||
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
/* Strict Type-Checking Options */
|
/* Strict Type-Checking Options */
|
||||||
//"strict": true, /* Enable all 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. */
|
// "strictNullChecks": true, /* Enable strict null checks. */
|
||||||
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||||
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
||||||
|
Reference in New Issue
Block a user