diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index b624be6..658031d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @aksatlanta \ No newline at end of file +* @Azure/aks-atlanta \ No newline at end of file diff --git a/.github/workflows/release-pr.yml b/.github/workflows/release-pr.yml index 4c012c4..ed7dd03 100644 --- a/.github/workflows/release-pr.yml +++ b/.github/workflows/release-pr.yml @@ -1,4 +1,4 @@ -name: "Create release PR" +name: Create release PR on: workflow_dispatch: @@ -8,49 +8,7 @@ on: required: true jobs: - createPullRequest: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - name: Check if remote branch exists - 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 \ No newline at end of file + release-pr: + uses: OliverMKing/javascript-release-workflow/.github/workflows/release-pr.yml@main + with: + release: ${{ github.event.inputs.release }} \ No newline at end of file diff --git a/.github/workflows/tag-and-draft.yml b/.github/workflows/tag-and-draft.yml new file mode 100644 index 0000000..ef653d0 --- /dev/null +++ b/.github/workflows/tag-and-draft.yml @@ -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 \ No newline at end of file diff --git a/.github/workflows/tag-and-release.yml b/.github/workflows/tag-and-release.yml deleted file mode 100644 index d301a52..0000000 --- a/.github/workflows/tag-and-release.yml +++ /dev/null @@ -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 \ No newline at end of file diff --git a/.gitignore b/.gitignore index d109d82..f2d06bb 100644 --- a/.gitignore +++ b/.gitignore @@ -328,3 +328,6 @@ ASALocalRun/ # MFractors (Xamarin productivity tool) working folder .mfractor/ node_modules + +# Transpiled JS +lib/ diff --git a/lib/helpers.js b/lib/helpers.js deleted file mode 100644 index 2273a05..0000000 --- a/lib/helpers.js +++ /dev/null @@ -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; diff --git a/lib/run.js b/lib/run.js deleted file mode 100644 index 1b8ede7..0000000 --- a/lib/run.js +++ /dev/null @@ -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); diff --git a/lib/run.test.js b/lib/run.test.js deleted file mode 100644 index 3bd7914..0000000 --- a/lib/run.test.js +++ /dev/null @@ -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')); - })); -});