Compare commits

...

13 Commits

Author SHA1 Message Date
Imran Ismail
ff25099d8b Update manifests 2020-09-25 22:16:19 +08:00
Imran Ismail
359e84cbc9 Cache by requested version name 2020-09-25 22:14:20 +08:00
Imran Ismail
430fa071e8 Run jest tests sequentially 2020-09-25 13:06:21 +08:00
Imran Ismail
b0afa08459 Remove unused import 2020-09-25 12:58:37 +08:00
Imran Ismail
9503343f5a Update test.yml 2020-09-25 12:55:49 +08:00
Imran Ismail
51957eba2f Simplify installer logic 2020-09-25 12:53:36 +08:00
Imran Ismail
399ab9d4d6 Fix dependabot config typo 2020-09-25 10:53:18 +08:00
Imran Ismail
f54a2cb09e Add support for version ranges (#9)
* Add support for version ranges

* Fix audit

* Update workflow

* Update dist

* Remove unexpected input

* Add  as step
2020-09-25 10:47:06 +08:00
Imran Ismail
2a4b82aea8 Merge pull request #6 from imranismail/dependabot/npm_and_yarn/lodash-4.17.19
Bump lodash from 4.17.15 to 4.17.19
2020-09-07 16:21:55 +08:00
dependabot[bot]
fff6152ccc Bump lodash from 4.17.15 to 4.17.19
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19)

Signed-off-by: dependabot[bot] <support@github.com>
2020-07-18 04:28:03 +00:00
Imran Ismail
dd60f3d86e Merge pull request #5 from imranismail/dependabot/npm_and_yarn/actions/http-client-1.0.8
Bump @actions/http-client from 1.0.6 to 1.0.8
2020-04-30 02:04:54 +08:00
dependabot[bot]
3f35d588be Bump @actions/http-client from 1.0.6 to 1.0.8
Bumps [@actions/http-client](https://github.com/actions/http-client) from 1.0.6 to 1.0.8.
- [Release notes](https://github.com/actions/http-client/releases)
- [Changelog](https://github.com/actions/http-client/blob/master/RELEASES.md)
- [Commits](https://github.com/actions/http-client/commits)

Signed-off-by: dependabot[bot] <support@github.com>
2020-04-29 18:03:39 +00:00
Imran Ismail
823fe14c9e Update README.md 2020-03-31 03:04:29 +08:00
17 changed files with 13328 additions and 4108 deletions

View File

@@ -1,6 +1,6 @@
{
"plugins": ["jest", "@typescript-eslint"],
"extends": ["plugin:github/es6"],
"extends": ["plugin:github/recommended"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 9,
@@ -16,13 +16,11 @@
"@typescript-eslint/no-require-imports": "error",
"@typescript-eslint/array-type": "error",
"@typescript-eslint/await-thenable": "error",
"@typescript-eslint/ban-ts-ignore": "error",
"@typescript-eslint/ban-ts-comment": "error",
"camelcase": "off",
"@typescript-eslint/camelcase": "error",
"@typescript-eslint/class-name-casing": "error",
"@typescript-eslint/consistent-type-assertions": "error",
"@typescript-eslint/explicit-function-return-type": ["error", {"allowExpressions": true}],
"@typescript-eslint/func-call-spacing": ["error", "never"],
"@typescript-eslint/generic-type-naming": ["error", "^[A-Z][A-Za-z]*$"],
"@typescript-eslint/no-array-constructor": "error",
"@typescript-eslint/no-empty-interface": "error",
"@typescript-eslint/no-explicit-any": "error",
@@ -32,7 +30,6 @@
"@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/no-namespace": "error",
"@typescript-eslint/no-non-null-assertion": "warn",
"@typescript-eslint/no-object-literal-type-assertion": "error",
"@typescript-eslint/no-unnecessary-qualifier": "error",
"@typescript-eslint/no-unnecessary-type-assertion": "error",
"@typescript-eslint/no-useless-constructor": "error",
@@ -40,7 +37,6 @@
"@typescript-eslint/prefer-for-of": "warn",
"@typescript-eslint/prefer-function-type": "warn",
"@typescript-eslint/prefer-includes": "error",
"@typescript-eslint/prefer-interface": "error",
"@typescript-eslint/prefer-string-starts-ends-with": "error",
"@typescript-eslint/promise-function-async": "error",
"@typescript-eslint/require-array-sort-compare": "error",

9
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,9 @@
version: 2
updates:
# Enable version updates for npm
- package-ecosystem: 'npm'
# Look for `package.json` and `lock` files in the `root` directory
directory: '/'
# Check the npm registry for updates every day (weekdays)
schedule:
interval: 'daily'

View File

@@ -1,16 +0,0 @@
name: "build-test"
on: # rebuild any PRs and main branch changes
pull_request:
push:
branches:
- master
- 'releases/*'
jobs:
build: # make sure build/ci work properly
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- run: |
npm ci
npm run all

23
.github/workflows/test.yml vendored Normal file
View File

@@ -0,0 +1,23 @@
name: 'build-test'
on: # rebuild any PRs and main branch changes
pull_request:
push:
branches:
- master
- 'releases/*'
jobs:
build: # make sure build/ci work properly
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: |
npm install
- run: |
npm run all
test: # make sure the action works on a clean machine without building
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ./
- run: kustomize version

View File

@@ -1,11 +0,0 @@
{
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": false,
"singleQuote": true,
"trailingComma": "none",
"bracketSpacing": false,
"arrowParens": "avoid",
"parser": "typescript"
}

10
.prettierrc.json Normal file
View File

@@ -0,0 +1,10 @@
{
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": false,
"singleQuote": true,
"trailingComma": "none",
"bracketSpacing": false,
"arrowParens": "avoid"
}

1
.tool-versions Normal file
View File

@@ -0,0 +1 @@
nodejs 14.12.0

View File

@@ -4,29 +4,32 @@
# Create a JavaScript Action using TypeScript
Use this template to bootstrap the creation of a JavaScript action.:rocket:
Use this template to bootstrap the creation of a TypeScript action.:rocket:
This template includes compilication support, tests, a validation workflow, publishing, and versioning guidance.
This template includes compilation support, tests, a validation workflow, publishing, and versioning guidance.
If you are new, there's also a simpler introduction. See the [Hello World JavaScript Action](https://github.com/actions/hello-world-javascript-action)
If you are new, there's also a simpler introduction. See the [Hello World JavaScript Action](https://github.com/actions/hello-world-javascript-action)
## Create an action from this template
Click the `Use this Template` and provide the new repo details for your action
## Code in Master
## Code in Main
Install the dependencies
Install the dependencies
```bash
$ npm install
```
Build the typescript and package it for distribution
```bash
$ npm run build && npm run pack
$ npm run build && npm run package
```
Run the tests :heavy_check_mark:
Run the tests :heavy_check_mark:
```bash
$ npm test
@@ -55,9 +58,9 @@ import * as core from '@actions/core';
...
async function run() {
try {
try {
...
}
}
catch (error) {
core.setFailed(error.message);
}
@@ -70,23 +73,26 @@ See the [toolkit documentation](https://github.com/actions/toolkit/blob/master/R
## Publish to a distribution branch
Actions are run from GitHub repos so we will checkin the packed dist folder.
Actions are run from GitHub repos so we will checkin the packed dist folder.
Then run [ncc](https://github.com/zeit/ncc) and push the results:
```bash
$ npm run pack
$ npm run package
$ git add dist
$ git commit -a -m "prod dependencies"
$ git push origin releases/v1
```
Your action is now published! :rocket:
Note: We recommend using the `--license` option for ncc, which will create a license file for all of the production node modules used in your project.
Your action is now published! :rocket:
See the [versioning documentation](https://github.com/actions/toolkit/blob/master/docs/action-versioning.md)
## Validate
You can now validate the action by referencing `./` in a workflow in your repo (see [test.yml](.github/workflows/test.yml)])
You can now validate the action by referencing `./` in a workflow in your repo (see [test.yml](.github/workflows/test.yml))
```yaml
uses: ./
@@ -94,8 +100,8 @@ with:
milliseconds: 1000
```
See the [actions tab](https://github.com/actions/javascript-action/actions) for runs of this action! :rocket:
See the [actions tab](https://github.com/actions/typescript-action/actions) for runs of this action! :rocket:
## Usage:
After testing you can [create a v1 tag](https://github.com/actions/toolkit/blob/master/docs/action-versioning.md) to reference the stable and latest V1 action
After testing you can [create a v1 tag](https://github.com/actions/toolkit/blob/master/docs/action-versioning.md) to reference the stable and latest V1 action

View File

@@ -12,7 +12,7 @@ jobs:
needs:
- publish-image
steps:
- uses: imranismail/setup-kustomize@master
- uses: imranismail/setup-kustomize@v1
with:
kustomize-version: "3.1.0"
- run: git clone https://${REPO_TOKEN}@github.com/org/deployment.git .

View File

@@ -17,14 +17,24 @@ describe('installer tests', () => {
beforeAll(async () => {
await io.rmRF(toolDir)
await io.rmRF(tempDir)
}, 100000)
})
afterAll(async () => {
await io.rmRF(toolDir)
await io.rmRF(tempDir)
}, 100000)
it('Acquires the max satisfying version range', async () => {
await installer.getKustomize('~> 3.0')
const kustomizeDir = path.join(toolDir, 'kustomize', '~> 3.0', os.arch())
expect(fs.existsSync(`${kustomizeDir}.complete`)).toBe(true)
it('Acquires kustomize version 3.2.0 successfully', async () => {
if (IS_WINDOWS) {
expect(fs.existsSync(path.join(kustomizeDir, 'kustomize.exe'))).toBe(true)
} else {
expect(fs.existsSync(path.join(kustomizeDir, 'kustomize'))).toBe(true)
expect(() =>
fs.accessSync(path.join(kustomizeDir, 'kustomize'), fs.constants.X_OK)
).not.toThrow()
}
})
it('Acquires kustomize version 3.2.0', async () => {
await installer.getKustomize('3.2.0')
const kustomizeDir = path.join(toolDir, 'kustomize', '3.2.0', os.arch())
@@ -38,9 +48,9 @@ describe('installer tests', () => {
fs.accessSync(path.join(kustomizeDir, 'kustomize'), fs.constants.X_OK)
).not.toThrow()
}
}, 100000)
})
it('Acquires kustomize version 3.2.1 successfully', async () => {
it('Acquires kustomize version 3.2.1', async () => {
await installer.getKustomize('3.2.1')
const kustomizeDir = path.join(toolDir, 'kustomize', '3.2.1', os.arch())
@@ -54,9 +64,9 @@ describe('installer tests', () => {
fs.accessSync(path.join(kustomizeDir, 'kustomize'), fs.constants.X_OK)
).not.toThrow()
}
}, 100000)
})
it('Acquires kustomize version 3.3.0 successfully', async () => {
it('Acquires kustomize version 3.3.0', async () => {
await installer.getKustomize('3.3.0')
const kustomizeDir = path.join(toolDir, 'kustomize', '3.3.0', os.arch())
@@ -70,7 +80,7 @@ describe('installer tests', () => {
fs.accessSync(path.join(kustomizeDir, 'kustomize'), fs.constants.X_OK)
).not.toThrow()
}
}, 100000)
})
it('Throws if no location contains correct kustomize version', async () => {
let thrown = false

7149
dist/index.js vendored

File diff suppressed because it is too large Load Diff

1
dist/index.js.map vendored Normal file

File diff suppressed because one or more lines are too long

3906
dist/sourcemap-register.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -4,8 +4,9 @@ module.exports = {
testEnvironment: 'node',
testMatch: ['**/*.test.ts'],
testRunner: 'jest-circus/runner',
testTimeout: 60000,
transform: {
'^.+\\.ts$': 'ts-jest'
},
verbose: true
}
}

5972
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -9,9 +9,9 @@
"format": "prettier --write **/*.ts",
"format-check": "prettier --check **/*.ts",
"lint": "eslint src/**/*.ts",
"pack": "ncc build",
"test": "jest",
"all": "npm run build && npm run format && npm run lint && npm run pack && npm test"
"package": "ncc build --source-map",
"test": "jest -i",
"all": "npm run build && npm run format && npm run lint && npm run package && npm test"
},
"repository": {
"type": "git",
@@ -25,26 +25,26 @@
"author": "Imran Ismail",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.2.0",
"@actions/core": "^1.2.4",
"@actions/io": "^1.0.2",
"@actions/tool-cache": "^1.3.3",
"semver": "^7.1.3",
"typed-rest-client": "^1.7.2"
"@octokit/rest": "^18.0.6",
"semver": "^7.3.2"
},
"devDependencies": {
"@types/jest": "^24.0.23",
"@types/node": "^12.7.12",
"@types/semver": "^7.1.0",
"@types/jest": "^26.0.5",
"@types/node": "^14.0.23",
"@types/semver": "^7.3.4",
"@typescript-eslint/parser": "^2.8.0",
"@zeit/ncc": "^0.20.5",
"eslint": "^5.16.0",
"eslint-plugin-github": "^2.0.0",
"eslint-plugin-jest": "^22.21.0",
"eslint": "^7.5.0",
"eslint-plugin-github": "^4.0.1",
"eslint-plugin-jest": "^23.18.0",
"jest": "^24.9.0",
"jest-circus": "^24.9.0",
"jest-circus": "^26.1.0",
"js-yaml": "^3.13.1",
"prettier": "^1.19.1",
"prettier": "^2.0.5",
"ts-jest": "^24.2.0",
"typescript": "^3.6.4"
"typescript": "^3.9.4"
}
}

View File

@@ -1,15 +1,17 @@
// Load tempDirectory before it gets wiped by tool-cache
import {Octokit} from '@octokit/rest'
import * as core from '@actions/core'
import * as tc from '@actions/tool-cache'
import * as restm from 'typed-rest-client/RestClient'
import * as os from 'os'
import * as cache from '@actions/tool-cache'
import * as path from 'path'
import * as semver from 'semver'
import * as fs from 'fs'
let tempDirectory = process.env['RUNNER_TEMPDIRECTORY'] || ''
const osPlat: string = os.platform()
const osArch: string = os.arch()
const octokit = new Octokit()
const versionRegex = /\d+\.?\d*\.?\d*/
const toolName = 'kustomize'
const platform = process.platform
const arch = process.arch === 'x64' ? 'amd64' : process.arch
if (!tempDirectory) {
let baseLocation
@@ -26,186 +28,99 @@ if (!tempDirectory) {
tempDirectory = path.join(baseLocation, 'actions', 'temp')
}
export async function getKustomize(versionSpec: string): Promise<void> {
// check cache
let toolPath: string
export async function getKustomize(targetVersion: string): Promise<void> {
if (!semver.validRange(targetVersion))
throw new Error(`invalid semver requested: ${targetVersion}`)
toolPath = tc.find('kustomize', versionSpec)
let kustomizePath = cache.find('kustomize', targetVersion)
// If not found in cache, download
if (!toolPath) {
let version: string
const c = semver.clean(versionSpec) || ''
// If explicit version
if (semver.valid(c) != null) {
// version to download
version = versionSpec
} else {
// query kustomize for a matching version
version = await queryLatestMatch(versionSpec)
if (!version) {
throw new Error(
`Unable to find Kustomize version '${versionSpec}' for platform ${osPlat} and architecture ${osArch}.`
)
}
if (!kustomizePath) {
const version = await getMaxSatisfyingVersion(targetVersion)
kustomizePath = await acquireVersion(version)
}
// check cache
toolPath = tc.find('kustomize', version)
return core.addPath(kustomizePath)
}
interface Version {
resolved: string
target: string
url: string
}
async function getMaxSatisfyingVersion(
targetVersion: string
): Promise<Version> {
const version = {target: targetVersion}
const availableVersions: Map<string, string> = new Map()
for await (const response of octokit.paginate.iterator(
octokit.repos.listReleases,
{
owner: 'kubernetes-sigs',
repo: 'kustomize'
}
)) {
for (const release of response.data) {
const matchingAsset = release.assets.find(
asset =>
asset.name.includes('kustomize') &&
asset.name.includes(platform) &&
asset.name.includes(arch)
)
if (!toolPath) {
// download, extract, cache
toolPath = await acquireKustomize(version)
}
}
if (matchingAsset) {
const kustomizeVersion = (versionRegex.exec(release.name) || []).shift()
core.addPath(toolPath)
}
interface IAsset {
browser_download_url: string
name: string
}
interface IKustomizeVersion {
name: string
assets: IAsset[]
}
async function queryLatestMatch(versionSpec: string): Promise<string> {
let dataFileName: string
switch (osPlat) {
case 'linux':
case 'darwin':
case 'win32':
dataFileName = osPlat
break
default:
throw new Error(`Unexpected OS '${osPlat}'`)
}
switch (osArch) {
case 'x64':
dataFileName = `${dataFileName}_amd64`
break
default:
dataFileName = `${dataFileName}_${osArch}`
}
const versions: string[] = []
const dataUrl =
'https://api.github.com/repos/kubernetes-sigs/kustomize/releases'
const rest: restm.RestClient = new restm.RestClient('setup-kustomize')
const kustomizeVersions: IKustomizeVersion[] =
(await rest.get<IKustomizeVersion[]>(dataUrl)).result || []
for (const kustomizeVersion of kustomizeVersions) {
if (
kustomizeVersion.assets.some(asset => asset.name.includes(dataFileName))
) {
const version = semver.clean(kustomizeVersion.name)
if (version != null) {
versions.push(version)
if (kustomizeVersion != null) {
availableVersions.set(
kustomizeVersion,
matchingAsset.browser_download_url
)
}
}
}
}
return evaluateVersions(versions, versionSpec)
}
const resolved = semver.maxSatisfying(
[...availableVersions.keys()],
version.target
)
function evaluateVersions(versions: string[], versionSpec: string): string {
let version = ''
core.debug(`evaluating ${versions.length} versions`)
versions = versions.sort((a, b) => {
if (semver.gt(a, b)) {
return 1
}
return -1
})
for (let i = versions.length - 1; i >= 0; i--) {
const potential: string = versions[i]
const satisfied: boolean = semver.satisfies(potential, versionSpec)
if (satisfied) {
version = potential
break
}
if (!resolved) {
throw new Error(
`Unable to find Kustomize version '${version.target}' for platform '${platform}' and architecture ${arch}.`
)
}
if (version) {
core.debug(`matched: ${version}`)
} else {
core.debug('match not found')
}
const url = availableVersions.get(resolved) as string
return version
return {...version, resolved, url}
}
async function acquireKustomize(version: string): Promise<string> {
version = semver.clean(version) || ''
let downloadUrl: string
async function acquireVersion(version: Version): Promise<string> {
const toolFilename =
process.platform === 'win32' ? `${toolName}.exe` : toolName
let toolPath: string
let toolFilename = 'kustomize'
const toolName = 'kustomize'
if (osPlat === 'win32') {
toolFilename = `${toolFilename}.exe`
}
if (semver.gte(version, '3.3.0')) {
downloadUrl = `https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/v${version}/kustomize_v${version}_%{os}_%{arch}.tar.gz`
} else if (semver.gte(version, '3.2.1')) {
downloadUrl = `https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/v${version}/kustomize_kustomize.v${version}_%{os}_%{arch}`
} else {
downloadUrl = `https://github.com/kubernetes-sigs/kustomize/releases/download/v${version}/kustomize_${version}_%{os}_%{arch}`
}
switch (osPlat) {
case 'win32':
if (semver.lte(version, '3.2.1'))
throw new Error(`Unexpected OS '${osPlat}'`)
downloadUrl = downloadUrl.replace('%{os}', 'windows')
if (semver.lt(version, '3.3.0')) downloadUrl = `${downloadUrl}.exe`
break
case 'linux':
case 'darwin':
downloadUrl = downloadUrl.replace('%{os}', osPlat)
break
default:
throw new Error(`Unexpected OS '${osPlat}'`)
}
switch (osArch) {
case 'x64':
downloadUrl = downloadUrl.replace('%{arch}', 'amd64')
break
default:
throw new Error(`Unexpected Arch '${osArch}'`)
}
try {
toolPath = await tc.downloadTool(downloadUrl)
toolPath = await cache.downloadTool(version.url)
} catch (err) {
core.debug(err)
throw new Error(`Failed to download version ${version}: ${err}`)
throw new Error(`Failed to download version ${version.target}: ${err}`)
}
if (downloadUrl.endsWith('.tar.gz')) {
toolPath = await tc.extractTar(toolPath)
if (version.url.endsWith('.tar.gz')) {
toolPath = await cache.extractTar(toolPath)
toolPath = path.join(toolPath, toolFilename)
}
switch (osPlat) {
switch (process.platform) {
case 'linux':
case 'darwin':
fs.chmodSync(toolPath, 0o755)
break
}
return await tc.cacheFile(toolPath, toolFilename, toolName, version)
return await cache.cacheFile(toolPath, toolFilename, toolName, version.target)
}