Compare commits
40 commits
releases/v
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
2d66d6bef6 | ||
|
3b0a9a4ae3 | ||
|
66e812b74c | ||
|
fc19d5430f | ||
|
5f6d890454 | ||
|
27d304ebf8 | ||
|
b5a36385a8 | ||
|
0b4bd0b42d | ||
|
2a0a121944 | ||
|
619a3634cc | ||
|
688936d8db | ||
|
d1dc92d6ff | ||
|
f471212b11 | ||
|
6a79469612 | ||
|
4552b26c1d | ||
|
0a920068d6 | ||
|
340b2c4cf2 | ||
|
bc474d7b1f | ||
|
796733b6bf | ||
|
dd44a92c26 | ||
|
bd5ca45a62 | ||
|
ad011b0706 | ||
|
4beba283ef | ||
|
07847ca908 | ||
|
d41afda166 | ||
|
80632d0f30 | ||
|
84f5aafb14 | ||
|
6d0ea16244 | ||
|
3545f3a551 | ||
|
2eb2a370ff | ||
|
b474dc39ef | ||
|
d893f27da9 | ||
|
09392910a9 | ||
|
d449d75495 | ||
|
3866693c1e | ||
|
1c32e43e21 | ||
|
07e8ba6f62 | ||
|
799fd53a36 | ||
|
f98c9f7632 | ||
|
fe45ba1148 |
32 changed files with 7245 additions and 6879 deletions
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
|
@ -1 +1 @@
|
||||||
* @aksatlanta
|
* @Azure/aks-atlanta
|
|
@ -4,7 +4,4 @@ about: Create a report to help us improve
|
||||||
title: ''
|
title: ''
|
||||||
labels: need-to-triage
|
labels: need-to-triage
|
||||||
assignees: '@aksatlanta'
|
assignees: '@aksatlanta'
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
36
.github/ISSUE_TEMPLATE/bugReportForm.yml
vendored
Normal file
36
.github/ISSUE_TEMPLATE/bugReportForm.yml
vendored
Normal 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
6
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: GitHub Action "setup-kubectl" Support
|
||||||
|
url: https://github.com/Azure/setup-kubectl
|
||||||
|
security: https://github.com/Azure/setup-kubectl/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: textarea
|
||||||
|
id: Feature_request
|
||||||
|
attributes:
|
||||||
|
label: Feature request
|
||||||
|
description: Provide example functionality and links to relevant docs
|
||||||
|
validations:
|
||||||
|
required: true
|
18
.github/dependabot.yml
vendored
Normal file
18
.github/dependabot.yml
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: npm
|
||||||
|
directory: /
|
||||||
|
schedule:
|
||||||
|
interval: weekly
|
||||||
|
groups:
|
||||||
|
actions:
|
||||||
|
patterns:
|
||||||
|
- '*'
|
||||||
|
- package-ecosystem: github-actions
|
||||||
|
directory: .github/workflows
|
||||||
|
schedule:
|
||||||
|
interval: weekly
|
||||||
|
groups:
|
||||||
|
actions:
|
||||||
|
patterns:
|
||||||
|
- '*'
|
50
.github/workflows/defaultLabels.yml
vendored
50
.github/workflows/defaultLabels.yml
vendored
|
@ -1,30 +1,30 @@
|
||||||
name: setting-default-labels
|
name: setting-default-labels
|
||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: "0 0/3 * * *"
|
- cron: '0 0/3 * * *'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
label-issues:
|
label-issues:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@v3
|
- uses: actions/stale@v9
|
||||||
name: Setting issue as idle
|
name: Setting issue as idle
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
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-message: 'This issue is idle because it has been open for 14 days with no activity.'
|
||||||
stale-issue-label: 'idle'
|
stale-issue-label: 'idle'
|
||||||
days-before-stale: 14
|
days-before-stale: 14
|
||||||
days-before-close: -1
|
days-before-close: -1
|
||||||
operations-per-run: 100
|
operations-per-run: 100
|
||||||
exempt-issue-labels: 'backlog'
|
exempt-issue-labels: 'backlog'
|
||||||
|
|
||||||
- uses: actions/stale@v3
|
- uses: actions/stale@v9
|
||||||
name: Setting PR as idle
|
name: Setting PR as idle
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
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-message: 'This PR is idle because it has been open for 14 days with no activity.'
|
||||||
stale-pr-label: 'idle'
|
stale-pr-label: 'idle'
|
||||||
days-before-stale: 14
|
days-before-stale: 14
|
||||||
days-before-close: -1
|
days-before-close: -1
|
||||||
operations-per-run: 100
|
operations-per-run: 100
|
||||||
|
|
91
.github/workflows/integration-tests.yml
vendored
91
.github/workflows/integration-tests.yml
vendored
|
@ -1,49 +1,54 @@
|
||||||
name: Integration test for setup-kubectl
|
name: Integration test for setup-kubectl
|
||||||
on: # rebuild any PRs and main branch changes
|
on: # rebuild any PRs and main branch changes
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- 'releases/*'
|
- 'releases/*'
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- 'releases/*'
|
- 'releases/*'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
run-integration-test:
|
run-integration-test:
|
||||||
name: Validate release and master branch
|
name: Validate release and master branch
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
env:
|
||||||
KUBECONFIG: /home/runner/.kube/config
|
KUBECONFIG: /home/runner/.kube/config
|
||||||
PR_BASE_REF: ${{ github.event.pull_request.base.ref }}
|
PR_BASE_REF: ${{ github.event.pull_request.base.ref }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
name: Checkout from PR branch
|
name: Checkout from PR branch
|
||||||
|
|
||||||
- id: action-npm-build
|
|
||||||
name: npm install and build
|
|
||||||
run: |
|
|
||||||
echo $PR_BASE_REF
|
|
||||||
if [[ $PR_BASE_REF != releases/* ]]; then
|
|
||||||
npm install
|
|
||||||
npm run build
|
|
||||||
fi
|
|
||||||
|
|
||||||
- uses: actions/setup-python@v2
|
|
||||||
name: Install Python
|
|
||||||
with:
|
|
||||||
python-version: '3.x'
|
|
||||||
|
|
||||||
- name: Install requests library
|
|
||||||
run: pip install requests
|
|
||||||
|
|
||||||
- name: Validate kubectl setup
|
- id: action-npm-build
|
||||||
run: python test/validate-kubectl.py latest
|
name: npm install and build
|
||||||
|
run: |
|
||||||
|
echo $PR_BASE_REF
|
||||||
|
if [[ $PR_BASE_REF != releases/* ]]; then
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Setup kubectl
|
- uses: actions/setup-python@v5
|
||||||
uses: ./
|
name: Install Python
|
||||||
with:
|
with:
|
||||||
version: 'v1.15.1'
|
python-version: '3.x'
|
||||||
|
|
||||||
- name: Validate kubectl setup
|
- name: Install requests library
|
||||||
run: python test/validate-kubectl.py 'v1.15.1'
|
run: pip install requests
|
||||||
|
|
||||||
|
- name: Setup kubectl latest
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
version: 'latest'
|
||||||
|
|
||||||
|
- name: Validate kubectl setup
|
||||||
|
run: python test/validate-kubectl.py latest
|
||||||
|
|
||||||
|
- name: Setup kubectl old version
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
version: 'v1.15.1'
|
||||||
|
|
||||||
|
- name: Validate kubectl setup old version
|
||||||
|
run: python test/validate-kubectl.py 'v1.15.1'
|
||||||
|
|
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@v4
|
||||||
|
|
||||||
|
- name: Enforce Prettier
|
||||||
|
uses: actionsx/prettier@v3
|
||||||
|
with:
|
||||||
|
args: --check .
|
66
.github/workflows/release-pr.yml
vendored
66
.github/workflows/release-pr.yml
vendored
|
@ -1,56 +1,18 @@
|
||||||
name: "Create release PR"
|
name: Release Project
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
push:
|
||||||
inputs:
|
branches:
|
||||||
release:
|
- main
|
||||||
description: "Define release version (ex: v1, v2, v3)"
|
paths:
|
||||||
required: true
|
- CHANGELOG.md
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
createPullRequest:
|
release:
|
||||||
runs-on: ubuntu-latest
|
permissions:
|
||||||
steps:
|
actions: read
|
||||||
- uses: actions/checkout@v2
|
contents: write
|
||||||
with:
|
uses: Azure/action-release-workflows/.github/workflows/release_js_project.yaml@v1
|
||||||
fetch-depth: 0
|
with:
|
||||||
- name: Check if remote branch exists
|
changelogPath: ./CHANGELOG.md
|
||||||
env:
|
|
||||||
BRANCH: releases/${{ github.event.inputs.release }}
|
|
||||||
run: |
|
|
||||||
echo "##[set-output name=exists;]$(echo $(if [[ -z $(git ls-remote --heads origin ${BRANCH}) ]]; then echo false; else echo true; fi;))"
|
|
||||||
id: extract-branch-status
|
|
||||||
# these two only need to occur if the branch exists
|
|
||||||
- name: Checkout proper branch
|
|
||||||
if: ${{ steps.extract-branch-status.outputs.exists == 'true' }}
|
|
||||||
env:
|
|
||||||
BRANCH: releases/${{ github.event.inputs.release }}
|
|
||||||
run: git checkout ${BRANCH}
|
|
||||||
- name: Reset promotion branch
|
|
||||||
if: ${{ steps.extract-branch-status.outputs.exists == 'true' }}
|
|
||||||
run: |
|
|
||||||
git fetch origin main:main
|
|
||||||
git reset --hard main
|
|
||||||
- name: Install packages
|
|
||||||
run: |
|
|
||||||
rm -rf node_modules/
|
|
||||||
npm install --no-bin-links
|
|
||||||
npm run build
|
|
||||||
- name: Remove node_modules from gitignore
|
|
||||||
run: |
|
|
||||||
sed -i '/node_modules/d' ./.gitignore
|
|
||||||
- name: Create branch
|
|
||||||
uses: peterjgrainger/action-create-branch@v2.0.1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
branch: releases/${{ github.event.inputs.release }}
|
|
||||||
- name: Create pull request
|
|
||||||
uses: peter-evans/create-pull-request@v3
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
commit-message: Add node modules and new code for release
|
|
||||||
title: ${{ github.event.inputs.release }} new release
|
|
||||||
base: releases/${{ github.event.inputs.release }}
|
|
||||||
branch: create-release
|
|
||||||
delete-branch: true
|
|
||||||
|
|
77
.github/workflows/tag-and-release.yml
vendored
77
.github/workflows/tag-and-release.yml
vendored
|
@ -1,77 +0,0 @@
|
||||||
name: "Tag and create release draft"
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- releases/*
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
gh_tagged_release:
|
|
||||||
runs-on: "ubuntu-latest"
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Test release
|
|
||||||
run: |
|
|
||||||
sudo npm install n
|
|
||||||
sudo n latest
|
|
||||||
npm test
|
|
||||||
- name: Get branch ending
|
|
||||||
run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF##*/} | sed 's:.*/::')"
|
|
||||||
id: extract-branch
|
|
||||||
- name: Get tags
|
|
||||||
run: |
|
|
||||||
echo "##[set-output name=tags;]$(echo $(git tag))"
|
|
||||||
id: extract-tags
|
|
||||||
- name: Get latest tag
|
|
||||||
uses: actions/github-script@v5
|
|
||||||
env:
|
|
||||||
TAGS: ${{ steps.extract-tags.outputs.tags }}
|
|
||||||
BRANCH: ${{ steps.extract-branch.outputs.branch }}
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
const tags = process.env["TAGS"]
|
|
||||||
.split(" ")
|
|
||||||
.map((x) => x.trim());
|
|
||||||
const branch = process.env["BRANCH"];
|
|
||||||
const splitTag = (x) =>
|
|
||||||
x
|
|
||||||
.substring(branch.length + 1)
|
|
||||||
.split(".")
|
|
||||||
.map((x) => Number(x));
|
|
||||||
function compareTags(nums1, nums2, position = 0) {
|
|
||||||
if (nums1.length < position && nums2.length < position) return nums2;
|
|
||||||
const num1 = splitTag(nums1)[position] || 0;
|
|
||||||
const num2 = splitTag(nums2)[position] || 0;
|
|
||||||
if (num1 === num2) return compareTags(nums1, nums2, position + 1);
|
|
||||||
else if (num1 > num2) return nums1;
|
|
||||||
else return nums2;
|
|
||||||
}
|
|
||||||
const branchTags = tags.filter((tag) => tag.startsWith(branch));
|
|
||||||
if (branchTags.length < 1) return branch + ".-1"
|
|
||||||
return branchTags.reduce((prev, curr) => compareTags(prev, curr));
|
|
||||||
result-encoding: string
|
|
||||||
id: get-latest-tag
|
|
||||||
- name: Get new tag
|
|
||||||
uses: actions/github-script@v5
|
|
||||||
env:
|
|
||||||
PREV: ${{ steps.get-latest-tag.outputs.result }}
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
let version = process.env["PREV"]
|
|
||||||
if (!version.includes(".")) version += ".0"; // case of v1 or v2
|
|
||||||
const prefix = /^([a-zA-Z]+)/.exec(version)[0];
|
|
||||||
const numbers = version.substring(prefix.length);
|
|
||||||
let split = numbers.split(".");
|
|
||||||
split[split.length - 1] = parseInt(split[split.length - 1]) + 1;
|
|
||||||
return prefix + split.join(".");
|
|
||||||
result-encoding: string
|
|
||||||
id: get-new-tag
|
|
||||||
- uses: "marvinpinto/action-automatic-releases@v1.2.1"
|
|
||||||
with:
|
|
||||||
title: ${{ steps.get-new-tag.outputs.result }} release
|
|
||||||
automatic_release_tag: ${{ steps.get-new-tag.outputs.result }}
|
|
||||||
repo_token: "${{ secrets.GITHUB_TOKEN }}"
|
|
||||||
draft: true
|
|
41
.github/workflows/ts-build-check.yml
vendored
41
.github/workflows/ts-build-check.yml
vendored
|
@ -1,41 +0,0 @@
|
||||||
name: TypeScript Build Check
|
|
||||||
|
|
||||||
on: pull_request
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
ts-build-check:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout Pull Request
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
ref: ${{github.event.pull_request.head.ref}}
|
|
||||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
|
||||||
path: original-pr
|
|
||||||
- name: Setup Node
|
|
||||||
uses: actions/setup-node@v1
|
|
||||||
with:
|
|
||||||
node-version: 12.x
|
|
||||||
- name: Clone and Build Pull Request
|
|
||||||
run: |
|
|
||||||
cp $GITHUB_WORKSPACE/original-pr/ $GITHUB_WORKSPACE/built-pr -r
|
|
||||||
cd $GITHUB_WORKSPACE/built-pr/
|
|
||||||
npm i
|
|
||||||
npm run build
|
|
||||||
- name: Compare Built Directories
|
|
||||||
id: diff
|
|
||||||
run: |
|
|
||||||
DIFF=$(diff $GITHUB_WORKSPACE/original-pr/lib $GITHUB_WORKSPACE/built-pr/lib -rqiEZbwBd)
|
|
||||||
if [ "$DIFF" != "" ]; then exit 1; else echo -e "PR contains up-to-date compiled JavaScript."; fi
|
|
||||||
- name: Comment Unbuilt TypeScript
|
|
||||||
if: failure() && steps.diff.outcome == 'failure'
|
|
||||||
uses: actions/github-script@v2
|
|
||||||
with:
|
|
||||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
|
||||||
script: |
|
|
||||||
github.issues.createComment({
|
|
||||||
issue_number: ${{ github.event.number }},
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
body: 'Please compile the TypeScript code with `npm run build`. The compiled JavaScript is not up-to-date.'
|
|
||||||
})
|
|
36
.github/workflows/unit-tests.yml
vendored
36
.github/workflows/unit-tests.yml
vendored
|
@ -1,21 +1,21 @@
|
||||||
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:
|
||||||
- main
|
- main
|
||||||
- 'releases/*'
|
- 'releases/*'
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- 'releases/*'
|
- 'releases/*'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build: # make sure build/ci works properly
|
build: # make sure build/ci works properly
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Build and run L0 tests.
|
- name: Build and run L0 tests.
|
||||||
run: |
|
run: |
|
||||||
npm install
|
npm install
|
||||||
npm test
|
npm test
|
||||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -328,3 +328,6 @@ ASALocalRun/
|
||||||
# MFractors (Xamarin productivity tool) working folder
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
.mfractor/
|
.mfractor/
|
||||||
node_modules
|
node_modules
|
||||||
|
|
||||||
|
# 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
|
||||||
|
}
|
7
CHANGELOG.md
Normal file
7
CHANGELOG.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# Changelog
|
||||||
|
|
||||||
|
## [v4.0.0] - 2024-01-30
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- #90 Migrate to node 20 as node 16 is deprecated
|
|
@ -1,9 +1,9 @@
|
||||||
# Microsoft Open Source Code of Conduct
|
# Microsoft Open Source Code of Conduct
|
||||||
|
|
||||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||||
|
|
||||||
Resources:
|
Resources:
|
||||||
|
|
||||||
- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
|
- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
|
||||||
- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
|
- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
|
||||||
- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
|
- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
|
||||||
|
|
58
README.md
58
README.md
|
@ -1,26 +1,32 @@
|
||||||
# Setup Kubectl
|
# Setup Kubectl
|
||||||
#### Sample workflow to install a specific version of kubectl binary on the runner.
|
|
||||||
|
#### Sample workflow to install a specific version of kubectl binary on the runner.
|
||||||
Acceptable values are latest or any semantic version string like `v1.15.0`. Use this action in workflow to define which version of kubectl will be used.
|
|
||||||
|
Acceptable values are latest or any semantic version string like `v1.15.0`. Use this action in workflow to define which version of kubectl will be used.
|
||||||
```yaml
|
|
||||||
- uses: azure/setup-kubectl@v1
|
```yaml
|
||||||
with:
|
- uses: azure/setup-kubectl@v4
|
||||||
version: '<version>' # default is latest stable
|
with:
|
||||||
id: install
|
version: '<version>' # default is latest stable
|
||||||
```
|
id: install
|
||||||
Refer to the action metadata file for details about all the inputs https://github.com/Azure/setup-kubectl/blob/main/action.yml
|
```
|
||||||
|
|
||||||
# Contributing
|
Refer to the action metadata file for details about all the inputs https://github.com/Azure/setup-kubectl/blob/main/action.yml
|
||||||
|
|
||||||
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
# Contributing
|
||||||
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
|
|
||||||
the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
|
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
|
||||||
When you submit a pull request, a CLA bot will automatically determine whether you need to provide
|
the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
|
||||||
a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
|
|
||||||
provided by the bot. You will only need to do this once across all repos using our CLA.
|
When you submit a pull request, a CLA bot will automatically determine whether you need to provide
|
||||||
|
a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
|
||||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
provided by the bot. You will only need to do this once across all repos using our CLA.
|
||||||
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.
|
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-kubectl 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-kubectl/issues), and if your issue isn't already represented please [open a new one](https://github.com/Azure/setup-kubectl/issues/new/choose). The project maintainers will respond to the best of their abilities.
|
||||||
|
|
70
SECURITY.md
70
SECURITY.md
|
@ -1,35 +1,35 @@
|
||||||
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.1 BLOCK -->
|
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.1 BLOCK -->
|
||||||
|
|
||||||
## Security
|
## Security
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
**Please do not report security vulnerabilities through public GitHub issues.** Instead, please report them to the Microsoft Security Response Center at [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://technet.microsoft.com/en-us/security/dn606155).
|
**Please do not report security vulnerabilities through public GitHub issues.** Instead, please report them to the Microsoft Security Response Center at [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://technet.microsoft.com/en-us/security/dn606155).
|
||||||
|
|
||||||
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
|
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
## Preferred Languages
|
## Preferred Languages
|
||||||
|
|
||||||
We prefer all communications to be in English.
|
We prefer all communications to be in English.
|
||||||
|
|
||||||
## Policy
|
## Policy
|
||||||
|
|
||||||
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd).
|
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd).
|
||||||
|
|
||||||
<!-- END MICROSOFT SECURITY.MD BLOCK -->
|
<!-- END MICROSOFT SECURITY.MD BLOCK -->
|
||||||
|
|
30
action.yml
30
action.yml
|
@ -1,15 +1,15 @@
|
||||||
name: 'Kubectl tool installer'
|
name: 'Kubectl tool installer'
|
||||||
description: 'Install a specific version of kubectl binary. Acceptable values are latest or any semantic version string like 1.15.0'
|
description: 'Install a specific version of kubectl binary. Acceptable values are latest or any semantic version string like 1.15.0'
|
||||||
inputs:
|
inputs:
|
||||||
version:
|
version:
|
||||||
description: 'Version of kubectl'
|
description: 'Version of kubectl'
|
||||||
required: true
|
required: true
|
||||||
default: 'latest'
|
default: 'latest'
|
||||||
outputs:
|
outputs:
|
||||||
kubectl-path:
|
kubectl-path:
|
||||||
description: 'Path to the cached kubectl binary'
|
description: 'Path to the cached kubectl binary'
|
||||||
branding:
|
branding:
|
||||||
color: 'blue'
|
color: 'blue'
|
||||||
runs:
|
runs:
|
||||||
using: 'node12'
|
using: 'node20'
|
||||||
main: 'lib/run.js'
|
main: 'lib/index.js'
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
clearMocks: true,
|
clearMocks: true,
|
||||||
moduleFileExtensions: ['js', 'ts'],
|
moduleFileExtensions: ['js', 'ts'],
|
||||||
testEnvironment: 'node',
|
testEnvironment: 'node',
|
||||||
testMatch: ['**/*.test.ts'],
|
testMatch: ['**/*.test.ts'],
|
||||||
transform: {
|
transform: {
|
||||||
'^.+\\.ts$': 'ts-jest'
|
'^.+\\.ts$': 'ts-jest'
|
||||||
},
|
},
|
||||||
verbose: true,
|
verbose: true,
|
||||||
coverageThreshold: {
|
coverageThreshold: {
|
||||||
"global": {
|
global: {
|
||||||
"branches": 0,
|
branches: 0,
|
||||||
"functions": 14,
|
functions: 14,
|
||||||
"lines": 27,
|
lines: 27,
|
||||||
"statements": 27
|
statements: 27
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
"use strict";
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
exports.getExecutableExtension = exports.getkubectlDownloadURL = exports.getKubectlArch = void 0;
|
|
||||||
const os = require("os");
|
|
||||||
const util = require("util");
|
|
||||||
function getKubectlArch() {
|
|
||||||
const arch = os.arch();
|
|
||||||
if (arch === 'x64') {
|
|
||||||
return 'amd64';
|
|
||||||
}
|
|
||||||
return arch;
|
|
||||||
}
|
|
||||||
exports.getKubectlArch = getKubectlArch;
|
|
||||||
function getkubectlDownloadURL(version, arch) {
|
|
||||||
switch (os.type()) {
|
|
||||||
case 'Linux':
|
|
||||||
return util.format('https://storage.googleapis.com/kubernetes-release/release/%s/bin/linux/%s/kubectl', version, arch);
|
|
||||||
case 'Darwin':
|
|
||||||
return util.format('https://storage.googleapis.com/kubernetes-release/release/%s/bin/darwin/%s/kubectl', version, arch);
|
|
||||||
case 'Windows_NT':
|
|
||||||
default:
|
|
||||||
return util.format('https://storage.googleapis.com/kubernetes-release/release/%s/bin/windows/%s/kubectl.exe', version, arch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exports.getkubectlDownloadURL = getkubectlDownloadURL;
|
|
||||||
function getExecutableExtension() {
|
|
||||||
if (os.type().match(/^Win/)) {
|
|
||||||
return '.exe';
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
exports.getExecutableExtension = getExecutableExtension;
|
|
76
lib/run.js
76
lib/run.js
|
@ -1,76 +0,0 @@
|
||||||
"use strict";
|
|
||||||
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.downloadKubectl = exports.getStableKubectlVersion = exports.run = void 0;
|
|
||||||
const path = require("path");
|
|
||||||
const util = require("util");
|
|
||||||
const fs = require("fs");
|
|
||||||
const toolCache = require("@actions/tool-cache");
|
|
||||||
const core = require("@actions/core");
|
|
||||||
const helpers_1 = require("./helpers");
|
|
||||||
const kubectlToolName = 'kubectl';
|
|
||||||
const stableKubectlVersion = 'v1.15.0';
|
|
||||||
const stableVersionUrl = 'https://storage.googleapis.com/kubernetes-release/release/stable.txt';
|
|
||||||
function run() {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
let version = core.getInput('version', { 'required': true });
|
|
||||||
if (version.toLocaleLowerCase() === 'latest') {
|
|
||||||
version = yield getStableKubectlVersion();
|
|
||||||
}
|
|
||||||
const cachedPath = yield downloadKubectl(version);
|
|
||||||
core.addPath(path.dirname(cachedPath));
|
|
||||||
core.debug(`Kubectl tool version: '${version}' has been cached at ${cachedPath}`);
|
|
||||||
core.setOutput('kubectl-path', cachedPath);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
exports.run = run;
|
|
||||||
function getStableKubectlVersion() {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
return toolCache.downloadTool(stableVersionUrl).then((downloadPath) => {
|
|
||||||
let version = fs.readFileSync(downloadPath, 'utf8').toString().trim();
|
|
||||||
if (!version) {
|
|
||||||
version = stableKubectlVersion;
|
|
||||||
}
|
|
||||||
return version;
|
|
||||||
}, (error) => {
|
|
||||||
core.debug(error);
|
|
||||||
core.warning('GetStableVersionFailed');
|
|
||||||
return stableKubectlVersion;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
exports.getStableKubectlVersion = getStableKubectlVersion;
|
|
||||||
function downloadKubectl(version) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
let cachedToolpath = toolCache.find(kubectlToolName, version);
|
|
||||||
let kubectlDownloadPath = '';
|
|
||||||
const arch = helpers_1.getKubectlArch();
|
|
||||||
if (!cachedToolpath) {
|
|
||||||
try {
|
|
||||||
kubectlDownloadPath = yield toolCache.downloadTool(helpers_1.getkubectlDownloadURL(version, arch));
|
|
||||||
}
|
|
||||||
catch (exception) {
|
|
||||||
if (exception instanceof toolCache.HTTPError && exception.httpStatusCode === 404) {
|
|
||||||
throw new Error(util.format("Kubectl '%s' for '%s' arch not found.", version, arch));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new Error('DownloadKubectlFailed');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cachedToolpath = yield toolCache.cacheFile(kubectlDownloadPath, kubectlToolName + helpers_1.getExecutableExtension(), kubectlToolName, version);
|
|
||||||
}
|
|
||||||
const kubectlPath = path.join(cachedToolpath, kubectlToolName + helpers_1.getExecutableExtension());
|
|
||||||
fs.chmodSync(kubectlPath, '777');
|
|
||||||
return kubectlPath;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
exports.downloadKubectl = downloadKubectl;
|
|
||||||
run().catch(core.setFailed);
|
|
163
lib/run.test.js
163
lib/run.test.js
|
@ -1,163 +0,0 @@
|
||||||
"use strict";
|
|
||||||
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 });
|
|
||||||
const run = require("./run");
|
|
||||||
const helpers_1 = require("./helpers");
|
|
||||||
const os = require("os");
|
|
||||||
const toolCache = require("@actions/tool-cache");
|
|
||||||
const fs = require("fs");
|
|
||||||
const path = require("path");
|
|
||||||
const core = require("@actions/core");
|
|
||||||
const util = require("util");
|
|
||||||
describe('Testing all functions in run file.', () => {
|
|
||||||
test('getExecutableExtension() - return .exe when os is Windows', () => {
|
|
||||||
jest.spyOn(os, 'type').mockReturnValue('Windows_NT');
|
|
||||||
expect(helpers_1.getExecutableExtension()).toBe('.exe');
|
|
||||||
expect(os.type).toBeCalled();
|
|
||||||
});
|
|
||||||
test('getExecutableExtension() - return empty string for non-windows OS', () => {
|
|
||||||
jest.spyOn(os, 'type').mockReturnValue('Darwin');
|
|
||||||
expect(helpers_1.getExecutableExtension()).toBe('');
|
|
||||||
expect(os.type).toBeCalled();
|
|
||||||
});
|
|
||||||
test.each([
|
|
||||||
['arm', 'arm'],
|
|
||||||
['arm64', 'arm64'],
|
|
||||||
['x64', 'amd64']
|
|
||||||
])("getKubectlArch() - return on %s os arch %s kubectl arch", (osArch, kubectlArch) => {
|
|
||||||
jest.spyOn(os, 'arch').mockReturnValue(osArch);
|
|
||||||
expect(helpers_1.getKubectlArch()).toBe(kubectlArch);
|
|
||||||
expect(os.arch).toBeCalled();
|
|
||||||
});
|
|
||||||
test.each([
|
|
||||||
['arm'],
|
|
||||||
['arm64'],
|
|
||||||
['amd64']
|
|
||||||
])('getkubectlDownloadURL() - return the URL to download %s kubectl for Linux', (arch) => {
|
|
||||||
jest.spyOn(os, 'type').mockReturnValue('Linux');
|
|
||||||
const kubectlLinuxUrl = util.format('https://storage.googleapis.com/kubernetes-release/release/v1.15.0/bin/linux/%s/kubectl', arch);
|
|
||||||
expect(helpers_1.getkubectlDownloadURL('v1.15.0', arch)).toBe(kubectlLinuxUrl);
|
|
||||||
expect(os.type).toBeCalled();
|
|
||||||
});
|
|
||||||
test.each([
|
|
||||||
['arm'],
|
|
||||||
['arm64'],
|
|
||||||
['amd64']
|
|
||||||
])('getkubectlDownloadURL() - return the URL to download %s kubectl for Darwin', (arch) => {
|
|
||||||
jest.spyOn(os, 'type').mockReturnValue('Darwin');
|
|
||||||
const kubectlDarwinUrl = util.format('https://storage.googleapis.com/kubernetes-release/release/v1.15.0/bin/darwin/%s/kubectl', arch);
|
|
||||||
expect(helpers_1.getkubectlDownloadURL('v1.15.0', arch)).toBe(kubectlDarwinUrl);
|
|
||||||
expect(os.type).toBeCalled();
|
|
||||||
});
|
|
||||||
test.each([
|
|
||||||
['arm'],
|
|
||||||
['arm64'],
|
|
||||||
['amd64']
|
|
||||||
])('getkubectlDownloadURL() - return the URL to download %s kubectl for Windows', (arch) => {
|
|
||||||
jest.spyOn(os, 'type').mockReturnValue('Windows_NT');
|
|
||||||
const kubectlWindowsUrl = util.format('https://storage.googleapis.com/kubernetes-release/release/v1.15.0/bin/windows/%s/kubectl.exe', arch);
|
|
||||||
expect(helpers_1.getkubectlDownloadURL('v1.15.0', arch)).toBe(kubectlWindowsUrl);
|
|
||||||
expect(os.type).toBeCalled();
|
|
||||||
});
|
|
||||||
test('getStableKubectlVersion() - download stable version file, read version and return it', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
||||||
jest.spyOn(toolCache, 'downloadTool').mockReturnValue(Promise.resolve('pathToTool'));
|
|
||||||
jest.spyOn(fs, 'readFileSync').mockReturnValue('v1.20.4');
|
|
||||||
expect(yield run.getStableKubectlVersion()).toBe('v1.20.4');
|
|
||||||
expect(toolCache.downloadTool).toBeCalled();
|
|
||||||
expect(fs.readFileSync).toBeCalledWith('pathToTool', 'utf8');
|
|
||||||
}));
|
|
||||||
test('getStableKubectlVersion() - return default v1.15.0 if version read is empty', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
||||||
jest.spyOn(toolCache, 'downloadTool').mockReturnValue(Promise.resolve('pathToTool'));
|
|
||||||
jest.spyOn(fs, 'readFileSync').mockReturnValue('');
|
|
||||||
expect(yield run.getStableKubectlVersion()).toBe('v1.15.0');
|
|
||||||
expect(toolCache.downloadTool).toBeCalled();
|
|
||||||
expect(fs.readFileSync).toBeCalledWith('pathToTool', 'utf8');
|
|
||||||
}));
|
|
||||||
test('getStableKubectlVersion() - return default v1.15.0 if unable to download file', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
||||||
jest.spyOn(toolCache, 'downloadTool').mockRejectedValue('Unable to download.');
|
|
||||||
expect(yield run.getStableKubectlVersion()).toBe('v1.15.0');
|
|
||||||
expect(toolCache.downloadTool).toBeCalled();
|
|
||||||
}));
|
|
||||||
test('downloadKubectl() - download kubectl, add it to toolCache and return path to it', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
||||||
jest.spyOn(toolCache, 'find').mockReturnValue('');
|
|
||||||
jest.spyOn(toolCache, 'downloadTool').mockReturnValue(Promise.resolve('pathToTool'));
|
|
||||||
jest.spyOn(toolCache, 'cacheFile').mockReturnValue(Promise.resolve('pathToCachedTool'));
|
|
||||||
jest.spyOn(os, 'type').mockReturnValue('Windows_NT');
|
|
||||||
jest.spyOn(fs, 'chmodSync').mockImplementation(() => { });
|
|
||||||
expect(yield run.downloadKubectl('v1.15.0')).toBe(path.join('pathToCachedTool', 'kubectl.exe'));
|
|
||||||
expect(toolCache.find).toBeCalledWith('kubectl', 'v1.15.0');
|
|
||||||
expect(toolCache.downloadTool).toBeCalled();
|
|
||||||
expect(toolCache.cacheFile).toBeCalled();
|
|
||||||
expect(os.type).toBeCalled();
|
|
||||||
expect(fs.chmodSync).toBeCalledWith(path.join('pathToCachedTool', 'kubectl.exe'), '777');
|
|
||||||
}));
|
|
||||||
test('downloadKubectl() - throw DownloadKubectlFailed error when unable to download kubectl', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
||||||
jest.spyOn(toolCache, 'find').mockReturnValue('');
|
|
||||||
jest.spyOn(toolCache, 'downloadTool').mockRejectedValue('Unable to download kubectl.');
|
|
||||||
yield expect(run.downloadKubectl('v1.15.0')).rejects.toThrow('DownloadKubectlFailed');
|
|
||||||
expect(toolCache.find).toBeCalledWith('kubectl', 'v1.15.0');
|
|
||||||
expect(toolCache.downloadTool).toBeCalled();
|
|
||||||
}));
|
|
||||||
test('downloadKubectl() - throw kubectl not found error when receive 404 response', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
||||||
const kubectlVersion = 'v1.15.0';
|
|
||||||
const arch = 'arm128';
|
|
||||||
jest.spyOn(os, 'arch').mockReturnValue(arch);
|
|
||||||
jest.spyOn(toolCache, 'find').mockReturnValue('');
|
|
||||||
jest.spyOn(toolCache, 'downloadTool').mockImplementation(_ => {
|
|
||||||
throw new toolCache.HTTPError(404);
|
|
||||||
});
|
|
||||||
yield expect(run.downloadKubectl(kubectlVersion)).rejects
|
|
||||||
.toThrow(util.format("Kubectl '%s' for '%s' arch not found.", kubectlVersion, arch));
|
|
||||||
expect(os.arch).toBeCalled();
|
|
||||||
expect(toolCache.find).toBeCalledWith('kubectl', kubectlVersion);
|
|
||||||
expect(toolCache.downloadTool).toBeCalled();
|
|
||||||
}));
|
|
||||||
test('downloadKubectl() - return path to existing cache of kubectl', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
||||||
jest.spyOn(toolCache, 'find').mockReturnValue('pathToCachedTool');
|
|
||||||
jest.spyOn(os, 'type').mockReturnValue('Windows_NT');
|
|
||||||
jest.spyOn(fs, 'chmodSync').mockImplementation(() => { });
|
|
||||||
jest.spyOn(toolCache, 'downloadTool');
|
|
||||||
expect(yield run.downloadKubectl('v1.15.0')).toBe(path.join('pathToCachedTool', 'kubectl.exe'));
|
|
||||||
expect(toolCache.find).toBeCalledWith('kubectl', 'v1.15.0');
|
|
||||||
expect(os.type).toBeCalled();
|
|
||||||
expect(fs.chmodSync).toBeCalledWith(path.join('pathToCachedTool', 'kubectl.exe'), '777');
|
|
||||||
expect(toolCache.downloadTool).not.toBeCalled();
|
|
||||||
}));
|
|
||||||
test('run() - download specified version and set output', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
||||||
jest.spyOn(core, 'getInput').mockReturnValue('v1.15.5');
|
|
||||||
jest.spyOn(toolCache, 'find').mockReturnValue('pathToCachedTool');
|
|
||||||
jest.spyOn(os, 'type').mockReturnValue('Windows_NT');
|
|
||||||
jest.spyOn(fs, 'chmodSync').mockImplementation();
|
|
||||||
jest.spyOn(core, 'addPath').mockImplementation();
|
|
||||||
jest.spyOn(console, 'log').mockImplementation();
|
|
||||||
jest.spyOn(core, 'setOutput').mockImplementation();
|
|
||||||
expect(yield run.run()).toBeUndefined();
|
|
||||||
expect(core.getInput).toBeCalledWith('version', { 'required': true });
|
|
||||||
expect(core.addPath).toBeCalledWith('pathToCachedTool');
|
|
||||||
expect(core.setOutput).toBeCalledWith('kubectl-path', path.join('pathToCachedTool', 'kubectl.exe'));
|
|
||||||
}));
|
|
||||||
test('run() - get latest version, download it and set output', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
||||||
jest.spyOn(core, 'getInput').mockReturnValue('latest');
|
|
||||||
jest.spyOn(toolCache, 'downloadTool').mockReturnValue(Promise.resolve('pathToTool'));
|
|
||||||
jest.spyOn(fs, 'readFileSync').mockReturnValue('v1.20.4');
|
|
||||||
jest.spyOn(toolCache, 'find').mockReturnValue('pathToCachedTool');
|
|
||||||
jest.spyOn(os, 'type').mockReturnValue('Windows_NT');
|
|
||||||
jest.spyOn(fs, 'chmodSync').mockImplementation();
|
|
||||||
jest.spyOn(core, 'addPath').mockImplementation();
|
|
||||||
jest.spyOn(console, 'log').mockImplementation();
|
|
||||||
jest.spyOn(core, 'setOutput').mockImplementation();
|
|
||||||
expect(yield run.run()).toBeUndefined();
|
|
||||||
expect(toolCache.downloadTool).toBeCalledWith('https://storage.googleapis.com/kubernetes-release/release/stable.txt');
|
|
||||||
expect(core.getInput).toBeCalledWith('version', { 'required': true });
|
|
||||||
expect(core.addPath).toBeCalledWith('pathToCachedTool');
|
|
||||||
expect(core.setOutput).toBeCalledWith('kubectl-path', path.join('pathToCachedTool', 'kubectl.exe'));
|
|
||||||
}));
|
|
||||||
});
|
|
12458
package-lock.json
generated
12458
package-lock.json
generated
File diff suppressed because it is too large
Load diff
64
package.json
64
package.json
|
@ -1,30 +1,34 @@
|
||||||
{
|
{
|
||||||
"name": "setup-kubectl-action",
|
"name": "setup-kubectl-action",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"main": "lib/run.js",
|
"main": "lib/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc --outDir ./lib --rootDir ./src",
|
"build": "npm i ncc && npx ncc build src/run.ts -o lib",
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
"test-coverage": "jest --coverage"
|
"test-coverage": "jest --coverage",
|
||||||
},
|
"format": "prettier --write .",
|
||||||
"keywords": [
|
"format-check": "prettier --check ."
|
||||||
"actions",
|
},
|
||||||
"node",
|
"keywords": [
|
||||||
"setup"
|
"actions",
|
||||||
],
|
"node",
|
||||||
"author": "GitHub",
|
"setup"
|
||||||
"license": "MIT",
|
],
|
||||||
"dependencies": {
|
"author": "GitHub",
|
||||||
"@actions/core": "^1.2.6",
|
"license": "MIT",
|
||||||
"@actions/exec": "^1.0.0",
|
"dependencies": {
|
||||||
"@actions/tool-cache": "^1.0.0"
|
"@actions/core": "^1.11.1",
|
||||||
},
|
"@actions/exec": "^1.0.0",
|
||||||
"devDependencies": {
|
"@actions/tool-cache": "^2.0.1"
|
||||||
"@types/node": "^12.0.4",
|
},
|
||||||
"jest": "^26.0.1",
|
"devDependencies": {
|
||||||
"@types/jest": "^25.2.2",
|
"@types/jest": "^29.5.14",
|
||||||
"ts-jest": "^25.5.1",
|
"@types/node": "^22.10.2",
|
||||||
"typescript": "3.9.2"
|
"@vercel/ncc": "^0.38.3",
|
||||||
}
|
"jest": "^29.7.0",
|
||||||
}
|
"prettier": "3.4.2",
|
||||||
|
"ts-jest": "^29.2.5",
|
||||||
|
"typescript": "5.7.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,31 +1,31 @@
|
||||||
import * as os from 'os';
|
import * as os from 'os'
|
||||||
import * as util from 'util';
|
import * as util from 'util'
|
||||||
|
|
||||||
export function getKubectlArch(): string {
|
export function getKubectlArch(): string {
|
||||||
const arch = os.arch();
|
const arch = os.arch()
|
||||||
if (arch === 'x64') {
|
if (arch === 'x64') {
|
||||||
return 'amd64';
|
return 'amd64'
|
||||||
}
|
}
|
||||||
return arch;
|
return arch
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getkubectlDownloadURL(version: string, arch: string): string {
|
export function getkubectlDownloadURL(version: string, arch: string): string {
|
||||||
switch (os.type()) {
|
switch (os.type()) {
|
||||||
case 'Linux':
|
case 'Linux':
|
||||||
return util.format('https://storage.googleapis.com/kubernetes-release/release/%s/bin/linux/%s/kubectl', version, arch);
|
return `https://dl.k8s.io/release/${version}/bin/linux/${arch}/kubectl`
|
||||||
|
|
||||||
case 'Darwin':
|
case 'Darwin':
|
||||||
return util.format('https://storage.googleapis.com/kubernetes-release/release/%s/bin/darwin/%s/kubectl', version, arch);
|
return `https://dl.k8s.io/release/${version}/bin/darwin/${arch}/kubectl`
|
||||||
|
|
||||||
case 'Windows_NT':
|
case 'Windows_NT':
|
||||||
default:
|
default:
|
||||||
return util.format('https://storage.googleapis.com/kubernetes-release/release/%s/bin/windows/%s/kubectl.exe', version, arch);
|
return `https://dl.k8s.io/release/${version}/bin/windows/${arch}/kubectl.exe`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getExecutableExtension(): string {
|
export function getExecutableExtension(): string {
|
||||||
if (os.type().match(/^Win/)) {
|
if (os.type().match(/^Win/)) {
|
||||||
return '.exe';
|
return '.exe'
|
||||||
}
|
}
|
||||||
return '';
|
return ''
|
||||||
}
|
}
|
||||||
|
|
352
src/run.test.ts
352
src/run.test.ts
|
@ -1,183 +1,235 @@
|
||||||
import * as run from './run'
|
import * as run from './run'
|
||||||
import { getkubectlDownloadURL, getKubectlArch, getExecutableExtension } from './helpers';
|
import {
|
||||||
import * as os from 'os';
|
getkubectlDownloadURL,
|
||||||
import * as toolCache from '@actions/tool-cache';
|
getKubectlArch,
|
||||||
import * as fs from 'fs';
|
getExecutableExtension
|
||||||
import * as path from 'path';
|
} from './helpers'
|
||||||
import * as core from '@actions/core';
|
import * as os from 'os'
|
||||||
import * as util from 'util';
|
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 util from 'util'
|
||||||
|
|
||||||
describe('Testing all functions in run file.', () => {
|
describe('Testing all functions in run file.', () => {
|
||||||
test('getExecutableExtension() - return .exe when os is Windows', () => {
|
test('getExecutableExtension() - return .exe when os is Windows', () => {
|
||||||
jest.spyOn(os, 'type').mockReturnValue('Windows_NT');
|
jest.spyOn(os, 'type').mockReturnValue('Windows_NT')
|
||||||
|
|
||||||
expect(getExecutableExtension()).toBe('.exe');
|
expect(getExecutableExtension()).toBe('.exe')
|
||||||
expect(os.type).toBeCalled();
|
expect(os.type).toBeCalled()
|
||||||
});
|
})
|
||||||
|
|
||||||
test('getExecutableExtension() - return empty string for non-windows OS', () => {
|
test('getExecutableExtension() - return empty string for non-windows OS', () => {
|
||||||
jest.spyOn(os, 'type').mockReturnValue('Darwin');
|
jest.spyOn(os, 'type').mockReturnValue('Darwin')
|
||||||
|
|
||||||
expect(getExecutableExtension()).toBe('');
|
expect(getExecutableExtension()).toBe('')
|
||||||
expect(os.type).toBeCalled();
|
expect(os.type).toBeCalled()
|
||||||
});
|
})
|
||||||
|
|
||||||
test.each([
|
test.each([
|
||||||
['arm', 'arm'],
|
['arm', 'arm'],
|
||||||
['arm64', 'arm64'],
|
['arm64', 'arm64'],
|
||||||
['x64', 'amd64']
|
['x64', 'amd64']
|
||||||
])("getKubectlArch() - return on %s os arch %s kubectl arch", (osArch, kubectlArch) => {
|
])(
|
||||||
jest.spyOn(os, 'arch').mockReturnValue(osArch);
|
'getKubectlArch() - return on %s os arch %s kubectl arch',
|
||||||
|
(osArch, kubectlArch) => {
|
||||||
|
jest.spyOn(os, 'arch').mockReturnValue(osArch)
|
||||||
|
|
||||||
expect(getKubectlArch()).toBe(kubectlArch);
|
expect(getKubectlArch()).toBe(kubectlArch)
|
||||||
expect(os.arch).toBeCalled();
|
expect(os.arch).toBeCalled()
|
||||||
});
|
}
|
||||||
|
)
|
||||||
|
|
||||||
test.each([
|
test.each([['arm'], ['arm64'], ['amd64']])(
|
||||||
['arm'],
|
'getkubectlDownloadURL() - return the URL to download %s kubectl for Linux',
|
||||||
['arm64'],
|
(arch) => {
|
||||||
['amd64']
|
jest.spyOn(os, 'type').mockReturnValue('Linux')
|
||||||
])('getkubectlDownloadURL() - return the URL to download %s kubectl for Linux', (arch) => {
|
const kubectlLinuxUrl = util.format(
|
||||||
jest.spyOn(os, 'type').mockReturnValue('Linux');
|
'https://dl.k8s.io/release/v1.15.0/bin/linux/%s/kubectl',
|
||||||
const kubectlLinuxUrl = util.format('https://storage.googleapis.com/kubernetes-release/release/v1.15.0/bin/linux/%s/kubectl', arch);
|
arch
|
||||||
|
)
|
||||||
|
|
||||||
expect(getkubectlDownloadURL('v1.15.0', arch)).toBe(kubectlLinuxUrl);
|
expect(getkubectlDownloadURL('v1.15.0', arch)).toBe(kubectlLinuxUrl)
|
||||||
expect(os.type).toBeCalled();
|
expect(os.type).toBeCalled()
|
||||||
});
|
}
|
||||||
|
)
|
||||||
|
|
||||||
test.each([
|
test.each([['arm'], ['arm64'], ['amd64']])(
|
||||||
['arm'],
|
'getkubectlDownloadURL() - return the URL to download %s kubectl for Darwin',
|
||||||
['arm64'],
|
(arch) => {
|
||||||
['amd64']
|
jest.spyOn(os, 'type').mockReturnValue('Darwin')
|
||||||
])('getkubectlDownloadURL() - return the URL to download %s kubectl for Darwin', (arch) => {
|
const kubectlDarwinUrl = util.format(
|
||||||
jest.spyOn(os, 'type').mockReturnValue('Darwin');
|
'https://dl.k8s.io/release/v1.15.0/bin/darwin/%s/kubectl',
|
||||||
const kubectlDarwinUrl = util.format('https://storage.googleapis.com/kubernetes-release/release/v1.15.0/bin/darwin/%s/kubectl', arch);
|
arch
|
||||||
|
)
|
||||||
|
|
||||||
expect(getkubectlDownloadURL('v1.15.0', arch)).toBe(kubectlDarwinUrl);
|
expect(getkubectlDownloadURL('v1.15.0', arch)).toBe(kubectlDarwinUrl)
|
||||||
expect(os.type).toBeCalled();
|
expect(os.type).toBeCalled()
|
||||||
});
|
}
|
||||||
|
)
|
||||||
|
|
||||||
test.each([
|
test.each([['arm'], ['arm64'], ['amd64']])(
|
||||||
['arm'],
|
'getkubectlDownloadURL() - return the URL to download %s kubectl for Windows',
|
||||||
['arm64'],
|
(arch) => {
|
||||||
['amd64']
|
jest.spyOn(os, 'type').mockReturnValue('Windows_NT')
|
||||||
])('getkubectlDownloadURL() - return the URL to download %s kubectl for Windows', (arch) => {
|
|
||||||
jest.spyOn(os, 'type').mockReturnValue('Windows_NT');
|
|
||||||
|
|
||||||
const kubectlWindowsUrl = util.format('https://storage.googleapis.com/kubernetes-release/release/v1.15.0/bin/windows/%s/kubectl.exe', arch);
|
const kubectlWindowsUrl = util.format(
|
||||||
expect(getkubectlDownloadURL('v1.15.0', arch)).toBe(kubectlWindowsUrl);
|
'https://dl.k8s.io/release/v1.15.0/bin/windows/%s/kubectl.exe',
|
||||||
expect(os.type).toBeCalled();
|
arch
|
||||||
});
|
)
|
||||||
|
expect(getkubectlDownloadURL('v1.15.0', arch)).toBe(kubectlWindowsUrl)
|
||||||
|
expect(os.type).toBeCalled()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
test('getStableKubectlVersion() - download stable version file, read version and return it', async () => {
|
test('getStableKubectlVersion() - download stable version file, read version and return it', async () => {
|
||||||
jest.spyOn(toolCache, 'downloadTool').mockReturnValue(Promise.resolve('pathToTool'));
|
jest
|
||||||
jest.spyOn(fs, 'readFileSync').mockReturnValue('v1.20.4');
|
.spyOn(toolCache, 'downloadTool')
|
||||||
|
.mockReturnValue(Promise.resolve('pathToTool'))
|
||||||
|
jest.spyOn(fs, 'readFileSync').mockReturnValue('v1.20.4')
|
||||||
|
|
||||||
expect(await run.getStableKubectlVersion()).toBe('v1.20.4');
|
expect(await run.getStableKubectlVersion()).toBe('v1.20.4')
|
||||||
expect(toolCache.downloadTool).toBeCalled();
|
expect(toolCache.downloadTool).toBeCalled()
|
||||||
expect(fs.readFileSync).toBeCalledWith('pathToTool', 'utf8');
|
expect(fs.readFileSync).toBeCalledWith('pathToTool', 'utf8')
|
||||||
});
|
})
|
||||||
|
|
||||||
test('getStableKubectlVersion() - return default v1.15.0 if version read is empty', async () => {
|
test('getStableKubectlVersion() - return default v1.15.0 if version read is empty', async () => {
|
||||||
jest.spyOn(toolCache, 'downloadTool').mockReturnValue(Promise.resolve('pathToTool'));
|
jest
|
||||||
jest.spyOn(fs, 'readFileSync').mockReturnValue('');
|
.spyOn(toolCache, 'downloadTool')
|
||||||
|
.mockReturnValue(Promise.resolve('pathToTool'))
|
||||||
|
jest.spyOn(fs, 'readFileSync').mockReturnValue('')
|
||||||
|
|
||||||
expect(await run.getStableKubectlVersion()).toBe('v1.15.0');
|
expect(await run.getStableKubectlVersion()).toBe('v1.15.0')
|
||||||
expect(toolCache.downloadTool).toBeCalled();
|
expect(toolCache.downloadTool).toBeCalled()
|
||||||
expect(fs.readFileSync).toBeCalledWith('pathToTool', 'utf8');
|
expect(fs.readFileSync).toBeCalledWith('pathToTool', 'utf8')
|
||||||
});
|
})
|
||||||
|
|
||||||
test('getStableKubectlVersion() - return default v1.15.0 if unable to download file', async () => {
|
test('getStableKubectlVersion() - return default v1.15.0 if unable to download file', async () => {
|
||||||
jest.spyOn(toolCache, 'downloadTool').mockRejectedValue('Unable to download.');
|
jest
|
||||||
|
.spyOn(toolCache, 'downloadTool')
|
||||||
|
.mockRejectedValue('Unable to download.')
|
||||||
|
|
||||||
expect(await run.getStableKubectlVersion()).toBe('v1.15.0');
|
expect(await run.getStableKubectlVersion()).toBe('v1.15.0')
|
||||||
expect(toolCache.downloadTool).toBeCalled();
|
expect(toolCache.downloadTool).toBeCalled()
|
||||||
});
|
})
|
||||||
|
|
||||||
test('downloadKubectl() - download kubectl, add it to toolCache and return path to it', async () => {
|
test('downloadKubectl() - download kubectl, add it to toolCache and return path to it', async () => {
|
||||||
jest.spyOn(toolCache, 'find').mockReturnValue('');
|
jest.spyOn(toolCache, 'find').mockReturnValue('')
|
||||||
jest.spyOn(toolCache, 'downloadTool').mockReturnValue(Promise.resolve('pathToTool'));
|
jest
|
||||||
jest.spyOn(toolCache, 'cacheFile').mockReturnValue(Promise.resolve('pathToCachedTool'));
|
.spyOn(toolCache, 'downloadTool')
|
||||||
jest.spyOn(os, 'type').mockReturnValue('Windows_NT');
|
.mockReturnValue(Promise.resolve('pathToTool'))
|
||||||
jest.spyOn(fs, 'chmodSync').mockImplementation(() => { });
|
jest
|
||||||
|
.spyOn(toolCache, 'cacheFile')
|
||||||
|
.mockReturnValue(Promise.resolve('pathToCachedTool'))
|
||||||
|
jest.spyOn(os, 'type').mockReturnValue('Windows_NT')
|
||||||
|
jest.spyOn(fs, 'chmodSync').mockImplementation(() => {})
|
||||||
|
|
||||||
expect(await run.downloadKubectl('v1.15.0')).toBe(path.join('pathToCachedTool', 'kubectl.exe'));
|
expect(await run.downloadKubectl('v1.15.0')).toBe(
|
||||||
expect(toolCache.find).toBeCalledWith('kubectl', 'v1.15.0');
|
path.join('pathToCachedTool', 'kubectl.exe')
|
||||||
expect(toolCache.downloadTool).toBeCalled();
|
)
|
||||||
expect(toolCache.cacheFile).toBeCalled();
|
expect(toolCache.find).toBeCalledWith('kubectl', 'v1.15.0')
|
||||||
expect(os.type).toBeCalled();
|
expect(toolCache.downloadTool).toBeCalled()
|
||||||
expect(fs.chmodSync).toBeCalledWith(path.join('pathToCachedTool', 'kubectl.exe'), '777');
|
expect(toolCache.cacheFile).toBeCalled()
|
||||||
});
|
expect(os.type).toBeCalled()
|
||||||
|
expect(fs.chmodSync).toBeCalledWith(
|
||||||
|
path.join('pathToCachedTool', 'kubectl.exe'),
|
||||||
|
'775'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
test('downloadKubectl() - throw DownloadKubectlFailed error when unable to download kubectl', async () => {
|
test('downloadKubectl() - throw DownloadKubectlFailed error when unable to download kubectl', async () => {
|
||||||
jest.spyOn(toolCache, 'find').mockReturnValue('');
|
jest.spyOn(toolCache, 'find').mockReturnValue('')
|
||||||
jest.spyOn(toolCache, 'downloadTool').mockRejectedValue('Unable to download kubectl.');
|
jest
|
||||||
|
.spyOn(toolCache, 'downloadTool')
|
||||||
|
.mockRejectedValue('Unable to download kubectl.')
|
||||||
|
|
||||||
await expect(run.downloadKubectl('v1.15.0')).rejects.toThrow('DownloadKubectlFailed');
|
await expect(run.downloadKubectl('v1.15.0')).rejects.toThrow(
|
||||||
expect(toolCache.find).toBeCalledWith('kubectl', 'v1.15.0');
|
'DownloadKubectlFailed'
|
||||||
expect(toolCache.downloadTool).toBeCalled();
|
)
|
||||||
});
|
expect(toolCache.find).toBeCalledWith('kubectl', 'v1.15.0')
|
||||||
|
expect(toolCache.downloadTool).toBeCalled()
|
||||||
|
})
|
||||||
|
|
||||||
test('downloadKubectl() - throw kubectl not found error when receive 404 response', async () => {
|
test('downloadKubectl() - throw kubectl not found error when receive 404 response', async () => {
|
||||||
const kubectlVersion = 'v1.15.0'
|
const kubectlVersion = 'v1.15.0'
|
||||||
const arch = 'arm128';
|
const arch = 'arm128'
|
||||||
|
|
||||||
jest.spyOn(os, 'arch').mockReturnValue(arch);
|
jest.spyOn(os, 'arch').mockReturnValue(arch)
|
||||||
jest.spyOn(toolCache, 'find').mockReturnValue('');
|
jest.spyOn(toolCache, 'find').mockReturnValue('')
|
||||||
jest.spyOn(toolCache, 'downloadTool').mockImplementation(_ => {
|
jest.spyOn(toolCache, 'downloadTool').mockImplementation((_) => {
|
||||||
throw new toolCache.HTTPError(404);
|
throw new toolCache.HTTPError(404)
|
||||||
});
|
})
|
||||||
|
|
||||||
await expect(run.downloadKubectl(kubectlVersion)).rejects
|
await expect(run.downloadKubectl(kubectlVersion)).rejects.toThrow(
|
||||||
.toThrow(util.format("Kubectl '%s' for '%s' arch not found.", kubectlVersion, arch));
|
util.format(
|
||||||
expect(os.arch).toBeCalled();
|
"Kubectl '%s' for '%s' arch not found.",
|
||||||
expect(toolCache.find).toBeCalledWith('kubectl', kubectlVersion);
|
kubectlVersion,
|
||||||
expect(toolCache.downloadTool).toBeCalled();
|
arch
|
||||||
});
|
)
|
||||||
|
)
|
||||||
|
expect(os.arch).toBeCalled()
|
||||||
|
expect(toolCache.find).toBeCalledWith('kubectl', kubectlVersion)
|
||||||
|
expect(toolCache.downloadTool).toBeCalled()
|
||||||
|
})
|
||||||
|
|
||||||
test('downloadKubectl() - return path to existing cache of kubectl', async () => {
|
test('downloadKubectl() - return path to existing cache of kubectl', async () => {
|
||||||
jest.spyOn(toolCache, 'find').mockReturnValue('pathToCachedTool');
|
jest.spyOn(toolCache, 'find').mockReturnValue('pathToCachedTool')
|
||||||
jest.spyOn(os, 'type').mockReturnValue('Windows_NT');
|
jest.spyOn(os, 'type').mockReturnValue('Windows_NT')
|
||||||
jest.spyOn(fs, 'chmodSync').mockImplementation(() => { });
|
jest.spyOn(fs, 'chmodSync').mockImplementation(() => {})
|
||||||
jest.spyOn(toolCache, 'downloadTool');
|
jest.spyOn(toolCache, 'downloadTool')
|
||||||
|
|
||||||
expect(await run.downloadKubectl('v1.15.0')).toBe(path.join('pathToCachedTool', 'kubectl.exe'));
|
expect(await run.downloadKubectl('v1.15.0')).toBe(
|
||||||
expect(toolCache.find).toBeCalledWith('kubectl', 'v1.15.0');
|
path.join('pathToCachedTool', 'kubectl.exe')
|
||||||
expect(os.type).toBeCalled();
|
)
|
||||||
expect(fs.chmodSync).toBeCalledWith(path.join('pathToCachedTool', 'kubectl.exe'), '777');
|
expect(toolCache.find).toBeCalledWith('kubectl', 'v1.15.0')
|
||||||
expect(toolCache.downloadTool).not.toBeCalled();
|
expect(os.type).toBeCalled()
|
||||||
});
|
expect(fs.chmodSync).toBeCalledWith(
|
||||||
|
path.join('pathToCachedTool', 'kubectl.exe'),
|
||||||
|
'775'
|
||||||
|
)
|
||||||
|
expect(toolCache.downloadTool).not.toBeCalled()
|
||||||
|
})
|
||||||
|
|
||||||
test('run() - download specified version and set output', async () => {
|
test('run() - download specified version and set output', async () => {
|
||||||
jest.spyOn(core, 'getInput').mockReturnValue('v1.15.5');
|
jest.spyOn(core, 'getInput').mockReturnValue('v1.15.5')
|
||||||
jest.spyOn(toolCache, 'find').mockReturnValue('pathToCachedTool');
|
jest.spyOn(toolCache, 'find').mockReturnValue('pathToCachedTool')
|
||||||
jest.spyOn(os, 'type').mockReturnValue('Windows_NT');
|
jest.spyOn(os, 'type').mockReturnValue('Windows_NT')
|
||||||
jest.spyOn(fs, 'chmodSync').mockImplementation();
|
jest.spyOn(fs, 'chmodSync').mockImplementation()
|
||||||
jest.spyOn(core, 'addPath').mockImplementation();
|
jest.spyOn(core, 'addPath').mockImplementation()
|
||||||
jest.spyOn(console, 'log').mockImplementation();
|
jest.spyOn(console, 'log').mockImplementation()
|
||||||
jest.spyOn(core, 'setOutput').mockImplementation();
|
jest.spyOn(core, 'setOutput').mockImplementation()
|
||||||
|
|
||||||
expect(await run.run()).toBeUndefined();
|
expect(await run.run()).toBeUndefined()
|
||||||
expect(core.getInput).toBeCalledWith('version', { 'required': true });
|
expect(core.getInput).toBeCalledWith('version', {required: true})
|
||||||
expect(core.addPath).toBeCalledWith('pathToCachedTool');
|
expect(core.addPath).toBeCalledWith('pathToCachedTool')
|
||||||
expect(core.setOutput).toBeCalledWith('kubectl-path', path.join('pathToCachedTool', 'kubectl.exe'));
|
expect(core.setOutput).toBeCalledWith(
|
||||||
});
|
'kubectl-path',
|
||||||
|
path.join('pathToCachedTool', 'kubectl.exe')
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
test('run() - get latest version, download it and set output', async () => {
|
test('run() - get latest version, download it and set output', async () => {
|
||||||
jest.spyOn(core, 'getInput').mockReturnValue('latest');
|
jest.spyOn(core, 'getInput').mockReturnValue('latest')
|
||||||
jest.spyOn(toolCache, 'downloadTool').mockReturnValue(Promise.resolve('pathToTool'));
|
jest
|
||||||
jest.spyOn(fs, 'readFileSync').mockReturnValue('v1.20.4');
|
.spyOn(toolCache, 'downloadTool')
|
||||||
jest.spyOn(toolCache, 'find').mockReturnValue('pathToCachedTool');
|
.mockReturnValue(Promise.resolve('pathToTool'))
|
||||||
jest.spyOn(os, 'type').mockReturnValue('Windows_NT');
|
jest.spyOn(fs, 'readFileSync').mockReturnValue('v1.20.4')
|
||||||
jest.spyOn(fs, 'chmodSync').mockImplementation();
|
jest.spyOn(toolCache, 'find').mockReturnValue('pathToCachedTool')
|
||||||
jest.spyOn(core, 'addPath').mockImplementation();
|
jest.spyOn(os, 'type').mockReturnValue('Windows_NT')
|
||||||
jest.spyOn(console, 'log').mockImplementation();
|
jest.spyOn(fs, 'chmodSync').mockImplementation()
|
||||||
jest.spyOn(core, 'setOutput').mockImplementation();
|
jest.spyOn(core, 'addPath').mockImplementation()
|
||||||
|
jest.spyOn(console, 'log').mockImplementation()
|
||||||
|
jest.spyOn(core, 'setOutput').mockImplementation()
|
||||||
|
|
||||||
expect(await run.run()).toBeUndefined();
|
expect(await run.run()).toBeUndefined()
|
||||||
expect(toolCache.downloadTool).toBeCalledWith('https://storage.googleapis.com/kubernetes-release/release/stable.txt');
|
expect(toolCache.downloadTool).toBeCalledWith(
|
||||||
expect(core.getInput).toBeCalledWith('version', { 'required': true });
|
'https://storage.googleapis.com/kubernetes-release/release/stable.txt'
|
||||||
expect(core.addPath).toBeCalledWith('pathToCachedTool');
|
)
|
||||||
expect(core.setOutput).toBeCalledWith('kubectl-path', path.join('pathToCachedTool', 'kubectl.exe'));
|
expect(core.getInput).toBeCalledWith('version', {required: true})
|
||||||
});
|
expect(core.addPath).toBeCalledWith('pathToCachedTool')
|
||||||
});
|
expect(core.setOutput).toBeCalledWith(
|
||||||
|
'kubectl-path',
|
||||||
|
path.join('pathToCachedTool', 'kubectl.exe')
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
157
src/run.ts
157
src/run.ts
|
@ -1,64 +1,93 @@
|
||||||
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 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 { getkubectlDownloadURL, getKubectlArch, getExecutableExtension } from './helpers';
|
import {
|
||||||
|
getkubectlDownloadURL,
|
||||||
const kubectlToolName = 'kubectl';
|
getKubectlArch,
|
||||||
const stableKubectlVersion = 'v1.15.0';
|
getExecutableExtension
|
||||||
const stableVersionUrl = 'https://storage.googleapis.com/kubernetes-release/release/stable.txt';
|
} from './helpers'
|
||||||
|
|
||||||
export async function run() {
|
const kubectlToolName = 'kubectl'
|
||||||
let version = core.getInput('version', { 'required': true });
|
const stableKubectlVersion = 'v1.15.0'
|
||||||
if (version.toLocaleLowerCase() === 'latest') {
|
const stableVersionUrl =
|
||||||
version = await getStableKubectlVersion();
|
'https://storage.googleapis.com/kubernetes-release/release/stable.txt'
|
||||||
}
|
|
||||||
const cachedPath = await downloadKubectl(version);
|
export async function run() {
|
||||||
|
let version = core.getInput('version', {required: true})
|
||||||
core.addPath(path.dirname(cachedPath));
|
if (version.toLocaleLowerCase() === 'latest') {
|
||||||
|
version = await getStableKubectlVersion()
|
||||||
core.debug(`Kubectl tool version: '${version}' has been cached at ${cachedPath}`);
|
}
|
||||||
core.setOutput('kubectl-path', cachedPath);
|
const cachedPath = await downloadKubectl(version)
|
||||||
}
|
|
||||||
|
core.addPath(path.dirname(cachedPath))
|
||||||
export async function getStableKubectlVersion(): Promise<string> {
|
|
||||||
return toolCache.downloadTool(stableVersionUrl).then((downloadPath) => {
|
core.debug(
|
||||||
let version = fs.readFileSync(downloadPath, 'utf8').toString().trim();
|
`Kubectl tool version: '${version}' has been cached at ${cachedPath}`
|
||||||
if (!version) {
|
)
|
||||||
version = stableKubectlVersion;
|
core.setOutput('kubectl-path', cachedPath)
|
||||||
}
|
}
|
||||||
return version;
|
|
||||||
}, (error) => {
|
export async function getStableKubectlVersion(): Promise<string> {
|
||||||
core.debug(error);
|
return toolCache.downloadTool(stableVersionUrl).then(
|
||||||
core.warning('GetStableVersionFailed');
|
(downloadPath) => {
|
||||||
return stableKubectlVersion;
|
let version = fs.readFileSync(downloadPath, 'utf8').toString().trim()
|
||||||
});
|
if (!version) {
|
||||||
}
|
version = stableKubectlVersion
|
||||||
|
}
|
||||||
export async function downloadKubectl(version: string): Promise<string> {
|
return version
|
||||||
let cachedToolpath = toolCache.find(kubectlToolName, version);
|
},
|
||||||
let kubectlDownloadPath = '';
|
(error) => {
|
||||||
const arch = getKubectlArch();
|
core.debug(error)
|
||||||
if (!cachedToolpath) {
|
core.warning('GetStableVersionFailed')
|
||||||
try {
|
return stableKubectlVersion
|
||||||
kubectlDownloadPath = await toolCache.downloadTool(getkubectlDownloadURL(version, arch));
|
}
|
||||||
} catch (exception) {
|
)
|
||||||
if (exception instanceof toolCache.HTTPError && exception.httpStatusCode === 404) {
|
}
|
||||||
throw new Error(util.format("Kubectl '%s' for '%s' arch not found.", version, arch));
|
|
||||||
} else {
|
export async function downloadKubectl(version: string): Promise<string> {
|
||||||
throw new Error('DownloadKubectlFailed');
|
let cachedToolpath = toolCache.find(kubectlToolName, version)
|
||||||
}
|
let kubectlDownloadPath = ''
|
||||||
}
|
const arch = getKubectlArch()
|
||||||
|
if (!cachedToolpath) {
|
||||||
cachedToolpath = await toolCache.cacheFile(kubectlDownloadPath, kubectlToolName + getExecutableExtension(), kubectlToolName, version);
|
try {
|
||||||
}
|
kubectlDownloadPath = await toolCache.downloadTool(
|
||||||
|
getkubectlDownloadURL(version, arch)
|
||||||
const kubectlPath = path.join(cachedToolpath, kubectlToolName + getExecutableExtension());
|
)
|
||||||
fs.chmodSync(kubectlPath, '777');
|
} catch (exception) {
|
||||||
return kubectlPath;
|
if (
|
||||||
}
|
exception instanceof toolCache.HTTPError &&
|
||||||
|
exception.httpStatusCode === 404
|
||||||
run().catch(core.setFailed);
|
) {
|
||||||
|
throw new Error(
|
||||||
|
util.format(
|
||||||
|
"Kubectl '%s' for '%s' arch not found.",
|
||||||
|
version,
|
||||||
|
arch
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
throw new Error('DownloadKubectlFailed')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedToolpath = await toolCache.cacheFile(
|
||||||
|
kubectlDownloadPath,
|
||||||
|
kubectlToolName + getExecutableExtension(),
|
||||||
|
kubectlToolName,
|
||||||
|
version
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const kubectlPath = path.join(
|
||||||
|
cachedToolpath,
|
||||||
|
kubectlToolName + getExecutableExtension()
|
||||||
|
)
|
||||||
|
fs.chmodSync(kubectlPath, '775')
|
||||||
|
return kubectlPath
|
||||||
|
}
|
||||||
|
|
||||||
|
run().catch(core.setFailed)
|
||||||
|
|
|
@ -1,31 +1,65 @@
|
||||||
import os, sys, json, requests, time
|
import os
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
import time
|
||||||
|
|
||||||
version_to_check = sys.argv[1]
|
|
||||||
version_info = None
|
def get_latest_version():
|
||||||
PASSED = False
|
response = None
|
||||||
|
time_to_sleep = 2
|
||||||
|
for _ in range(10):
|
||||||
|
response = requests.get(
|
||||||
|
'https://storage.googleapis.com/kubernetes-release/release/stable.txt')
|
||||||
|
if response.status_code == 200:
|
||||||
|
break
|
||||||
|
print('Failed to obtain latest version info, retrying.')
|
||||||
|
time.sleep(time_to_sleep)
|
||||||
|
time_to_sleep *= 2
|
||||||
|
return response.content.decode('utf-8')
|
||||||
|
|
||||||
|
|
||||||
|
version_arg = sys.argv[1]
|
||||||
|
installed_version_info = None
|
||||||
|
PASSED = True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
print('kubectl version --client -o json')
|
print('kubectl version --client -o json')
|
||||||
version_info = json.load(os.popen('kubectl version --client -o json'))
|
installed_version_info = json.load(
|
||||||
|
os.popen('kubectl version --client -o json'))
|
||||||
|
print(
|
||||||
|
f'installed version: {installed_version_info["clientVersion"]["gitVersion"]}')
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
sys.exit('kubectl not installed')
|
sys.exit('kubectl not installed')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if version_to_check == 'latest':
|
installed_version = installed_version_info['clientVersion']['gitVersion']
|
||||||
response = None
|
# NOT Match
|
||||||
time_to_sleep = 2
|
if version_arg[0] == '!':
|
||||||
for _ in range(10):
|
undesired_version = version_arg[1:]
|
||||||
response = requests.get('https://storage.googleapis.com/kubernetes-release/release/stable.txt')
|
print(f'undesired version: {undesired_version}')
|
||||||
if response.status_code == 200:
|
if installed_version == undesired_version:
|
||||||
break
|
print(
|
||||||
print('Failed to obtain latest version info, retrying.')
|
f'installed version ({installed_version}) matches undesire {undesired_version} - FAIL')
|
||||||
time.sleep(time_to_sleep)
|
PASSED = False
|
||||||
time_to_sleep *= 2
|
# Exact Match
|
||||||
version_to_check = response.content.decode('utf-8')
|
else:
|
||||||
PASSED = True if version_info['clientVersion']['gitVersion'] == version_to_check else False
|
if version_arg == 'latest':
|
||||||
except:
|
print('checking latest version')
|
||||||
|
desired_version = get_latest_version()
|
||||||
|
else:
|
||||||
|
desired_version = version_arg
|
||||||
|
|
||||||
|
print(f'desired version: {desired_version}')
|
||||||
|
if installed_version != desired_version:
|
||||||
|
print(
|
||||||
|
f'installed version ({installed_version}) does not match desired ({desired_version}) - FAIL')
|
||||||
|
PASSED = False
|
||||||
|
except Exception as ex:
|
||||||
|
print(f'Exception: {ex}')
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if not PASSED:
|
if not PASSED:
|
||||||
sys.exit('Setting up of '+version_to_check+' kubectl failed')
|
sys.exit('Setting up of '+version_arg+' kubectl failed')
|
||||||
print('Test passed')
|
print('Test passed')
|
||||||
|
sys.exit()
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ES6",
|
"target": "ES6",
|
||||||
"module": "commonjs"
|
"module": "commonjs"
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": ["node_modules", "test"]
|
||||||
"node_modules",
|
}
|
||||||
"test"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue