chore: update dev dependencies and workflow

Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
This commit is contained in:
CrazyMax 2022-03-15 21:59:52 +01:00
parent ac9327eae2
commit 2d081a4fd5
No known key found for this signature in database
GPG key ID: 3248E46B6BB8C7F7
16 changed files with 2706 additions and 29647 deletions

23
.eslintrc.json Normal file
View file

@ -0,0 +1,23 @@
{
"env": {
"node": true,
"es2021": true,
"jest/globals": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:jest/recommended",
"plugin:prettier/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"@typescript-eslint",
"jest",
"prettier"
]
}

View file

@ -1,8 +1,8 @@
import {describe, expect, it, jest, test} from '@jest/globals';
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import * as semver from 'semver'; import * as semver from 'semver';
import * as exec from '@actions/exec'; import * as exec from '@actions/exec';
import * as buildx from '../src/buildx'; import * as buildx from '../src/buildx';
import * as context from '../src/context'; import * as context from '../src/context';
@ -53,69 +53,25 @@ describe('getDigest', () => {
}); });
describe('isLocalOrTarExporter', () => { describe('isLocalOrTarExporter', () => {
// prettier-ignore
test.each([ test.each([
[ [['type=registry,ref=user/app'], false],
[ [['type=docker'], false],
'type=registry,ref=user/app', [['type=local,dest=./release-out'], true],
], [['type=tar,dest=/tmp/image.tar'], true],
false [['type=docker', 'type=tar,dest=/tmp/image.tar'], true],
], [['"type=tar","dest=/tmp/image.tar"'], true],
[ [['" type= local" , dest=./release-out'], true],
[ [['.'], true]
'type=docker', ])('given %p returns %p', async (outputs: Array<string>, expected: boolean) => {
], expect(buildx.isLocalOrTarExporter(outputs)).toEqual(expected);
false });
],
[
[
'type=local,dest=./release-out'
],
true
],
[
[
'type=tar,dest=/tmp/image.tar'
],
true
],
[
[
'type=docker',
'type=tar,dest=/tmp/image.tar'
],
true
],
[
[
'"type=tar","dest=/tmp/image.tar"'
],
true
],
[
[
'" type= local" , dest=./release-out'
],
true
],
[
[
'.'
],
true
],
])(
'given %p returns %p',
async (outputs: Array<string>, expected: boolean) => {
expect(buildx.isLocalOrTarExporter(outputs)).toEqual(expected);
}
);
}); });
describe('isAvailable', () => { describe('isAvailable', () => {
const execSpy: jest.SpyInstance = jest.spyOn(exec, 'getExecOutput'); const execSpy = jest.spyOn(exec, 'getExecOutput');
buildx.isAvailable(); buildx.isAvailable();
// eslint-disable-next-line jest/no-standalone-expect
expect(execSpy).toHaveBeenCalledWith(`docker`, ['buildx'], { expect(execSpy).toHaveBeenCalledWith(`docker`, ['buildx'], {
silent: true, silent: true,
ignoreReturnCode: true ignoreReturnCode: true
@ -123,24 +79,10 @@ describe('isAvailable', () => {
}); });
describe('getVersion', () => { describe('getVersion', () => {
async function isDaemonRunning() { it('valid', async () => {
return await exec const version = await buildx.getVersion();
.getExecOutput(`docker`, ['version', '--format', '{{.Server.Os}}'], { expect(semver.valid(version)).not.toBeNull();
ignoreReturnCode: true, });
silent: true
})
.then(res => {
return !res.stdout.includes(' ') && res.exitCode == 0;
});
}
(isDaemonRunning() ? it : it.skip)(
'valid',
async () => {
const version = await buildx.getVersion();
expect(semver.valid(version)).not.toBeNull();
},
100000
);
}); });
describe('parseVersion', () => { describe('parseVersion', () => {
@ -187,6 +129,7 @@ describe('getSecret', () => {
const secretValue = await fs.readFileSync(tmpNameSync, 'utf-8'); const secretValue = await fs.readFileSync(tmpNameSync, 'utf-8');
expect(secretValue).toEqual(exValue); expect(secretValue).toEqual(exValue);
} catch (err) { } catch (err) {
// eslint-disable-next-line jest/no-conditional-expect
expect(true).toBe(invalid); expect(true).toBe(invalid);
} }
}); });

View file

@ -1,3 +1,4 @@
import {beforeEach, describe, expect, it, jest, test} from '@jest/globals';
import * as fs from 'fs'; import * as fs from 'fs';
import * as os from 'os'; import * as os from 'os';
import * as path from 'path'; import * as path from 'path';
@ -517,8 +518,8 @@ nproc=3`],
], ],
])( ])(
'[%d] given %p with %p as inputs, returns %p', '[%d] given %p with %p as inputs, returns %p',
async (num: number, buildxVersion: string, inputs: Map<string, any>, expected: Array<string>) => { async (num: number, buildxVersion: string, inputs: Map<string, string>, expected: Array<string>) => {
await inputs.forEach((value: string, name: string) => { inputs.forEach((value: string, name: string) => {
setInput(name, value); setInput(name, value);
}); });
const defContext = context.defaultContext(); const defContext = context.defaultContext();
@ -666,7 +667,7 @@ FOO=bar`
expect(res).toEqual([ expect(res).toEqual([
'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789', 'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789',
`MYSECRET=aaaaaaaa `MYSECRET=aaaaaaaa
bbbb\"bbb bbbb"bbb
ccccccccc`, ccccccccc`,
'FOO=bar' 'FOO=bar'
]); ]);
@ -688,19 +689,22 @@ describe('asyncForEach', () => {
describe('setOutput', () => { describe('setOutput', () => {
beforeEach(() => { beforeEach(() => {
process.stdout.write = jest.fn(); process.stdout.write = jest.fn() as typeof process.stdout.write;
}); });
// eslint-disable-next-line jest/expect-expect
it('setOutput produces the correct command', () => { it('setOutput produces the correct command', () => {
context.setOutput('some output', 'some value'); context.setOutput('some output', 'some value');
assertWriteCalls([`::set-output name=some output::some value${os.EOL}`]); assertWriteCalls([`::set-output name=some output::some value${os.EOL}`]);
}); });
// eslint-disable-next-line jest/expect-expect
it('setOutput handles bools', () => { it('setOutput handles bools', () => {
context.setOutput('some output', false); context.setOutput('some output', false);
assertWriteCalls([`::set-output name=some output::false${os.EOL}`]); assertWriteCalls([`::set-output name=some output::false${os.EOL}`]);
}); });
// eslint-disable-next-line jest/expect-expect
it('setOutput handles numbers', () => { it('setOutput handles numbers', () => {
context.setOutput('some output', 1.01); context.setOutput('some output', 1.01);
assertWriteCalls([`::set-output name=some output::1.01${os.EOL}`]); assertWriteCalls([`::set-output name=some output::1.01${os.EOL}`]);

View file

@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1.3-labs # syntax=docker/dockerfile:1.4
ARG NODE_VERSION ARG NODE_VERSION=12
ARG DOCKER_VERSION=20.10.10 ARG DOCKER_VERSION=20.10.10
ARG BUILDX_VERSION=0.7.0 ARG BUILDX_VERSION=0.7.0
@ -57,10 +57,10 @@ RUN --mount=type=bind,target=.,rw \
FROM scratch AS format-update FROM scratch AS format-update
COPY --from=format /out / COPY --from=format /out /
FROM deps AS format-validate FROM deps AS lint
RUN --mount=type=bind,target=.,rw \ RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/node_modules \ --mount=type=cache,target=/src/node_modules \
yarn run format-check yarn run lint
FROM docker:${DOCKER_VERSION} as docker FROM docker:${DOCKER_VERSION} as docker
FROM docker/buildx-bin:${BUILDX_VERSION} as buildx FROM docker/buildx-bin:${BUILDX_VERSION} as buildx

27909
dist/index.js generated vendored

File diff suppressed because one or more lines are too long

1
dist/index.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

1045
dist/licenses.txt generated vendored Normal file

File diff suppressed because it is too large Load diff

1
dist/sourcemap-register.js generated vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -1,13 +1,3 @@
variable "NODE_VERSION" {
default = "12"
}
target "node-version" {
args = {
NODE_VERSION = NODE_VERSION
}
}
group "default" { group "default" {
targets = ["build"] targets = ["build"]
} }
@ -17,54 +7,47 @@ group "pre-checkin" {
} }
group "validate" { group "validate" {
targets = ["format-validate", "build-validate", "vendor-validate"] targets = ["lint", "build-validate", "vendor-validate"]
} }
target "build" { target "build" {
inherits = ["node-version"] dockerfile = "dev.Dockerfile"
dockerfile = "./hack/build.Dockerfile"
target = "build-update" target = "build-update"
output = ["."] output = ["."]
} }
target "build-validate" { target "build-validate" {
inherits = ["node-version"] dockerfile = "dev.Dockerfile"
dockerfile = "./hack/build.Dockerfile"
target = "build-validate" target = "build-validate"
output = ["type=cacheonly"] output = ["type=cacheonly"]
} }
target "format" { target "format" {
inherits = ["node-version"] dockerfile = "dev.Dockerfile"
dockerfile = "./hack/build.Dockerfile"
target = "format-update" target = "format-update"
output = ["."] output = ["."]
} }
target "format-validate" { target "lint" {
inherits = ["node-version"] dockerfile = "dev.Dockerfile"
dockerfile = "./hack/build.Dockerfile" target = "lint"
target = "format-validate"
output = ["type=cacheonly"] output = ["type=cacheonly"]
} }
target "vendor-update" { target "vendor-update" {
inherits = ["node-version"] dockerfile = "dev.Dockerfile"
dockerfile = "./hack/build.Dockerfile"
target = "vendor-update" target = "vendor-update"
output = ["."] output = ["."]
} }
target "vendor-validate" { target "vendor-validate" {
inherits = ["node-version"] dockerfile = "dev.Dockerfile"
dockerfile = "./hack/build.Dockerfile"
target = "vendor-validate" target = "vendor-validate"
output = ["type=cacheonly"] output = ["type=cacheonly"]
} }
target "test" { target "test" {
inherits = ["node-version"] dockerfile = "dev.Dockerfile"
dockerfile = "./hack/build.Dockerfile"
target = "test-coverage" target = "test-coverage"
output = ["./coverage"] output = ["./coverage"]
} }

View file

@ -2,11 +2,9 @@ module.exports = {
clearMocks: false, clearMocks: false,
moduleFileExtensions: ['js', 'ts'], moduleFileExtensions: ['js', 'ts'],
setupFiles: ["dotenv/config"], setupFiles: ["dotenv/config"],
testEnvironment: 'node',
testMatch: ['**/*.test.ts'], testMatch: ['**/*.test.ts'],
testRunner: 'jest-circus/runner',
transform: { transform: {
'^.+\\.ts$': 'ts-jest' '^.+\\.ts$': 'ts-jest'
}, },
verbose: false verbose: true
} }

View file

@ -3,11 +3,11 @@
"description": "Build and push Docker images", "description": "Build and push Docker images",
"main": "lib/main.js", "main": "lib/main.js",
"scripts": { "scripts": {
"build": "tsc && ncc build", "build": "ncc build src/main.ts --source-map --minify --license licenses.txt",
"format": "prettier --write **/*.ts", "lint": "eslint src/**/*.ts __tests__/**/*.ts",
"format-check": "prettier --check **/*.ts", "format": "eslint --fix src/**/*.ts __tests__/**/*.ts",
"test": "jest --coverage", "test": "jest --coverage",
"pre-checkin": "yarn run format && yarn run build" "all": "yarn run build && yarn run format && yarn test"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -38,17 +38,21 @@
}, },
"devDependencies": { "devDependencies": {
"@types/csv-parse": "^1.2.2", "@types/csv-parse": "^1.2.2",
"@types/jest": "^26.0.23", "@types/node": "^16.11.26",
"@types/node": "^14.17.4", "@types/semver": "^7.3.9",
"@types/tmp": "^0.2.0", "@types/tmp": "^0.2.3",
"@vercel/ncc": "^0.28.6", "@typescript-eslint/eslint-plugin": "^5.14.0",
"dotenv": "^8.6.0", "@typescript-eslint/parser": "^5.14.0",
"jest": "^26.6.3", "@vercel/ncc": "^0.33.3",
"jest-circus": "^26.6.3", "dotenv": "^16.0.0",
"jest-runtime": "^26.6.3", "eslint": "^8.11.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-jest": "^26.1.1",
"eslint-plugin-prettier": "^4.0.0",
"jest": "^27.2.5",
"prettier": "^2.3.1", "prettier": "^2.3.1",
"ts-jest": "^26.5.6", "ts-jest": "^27.1.2",
"typescript": "^4.3.4", "ts-node": "^10.7.0",
"typescript-formatter": "^7.2.2" "typescript": "^4.4.4"
} }
} }

View file

@ -76,8 +76,8 @@ export async function getSecret(kvp: string, file: boolean): Promise<string> {
return `id=${key},src=${secretFile}`; return `id=${key},src=${secretFile}`;
} }
export function isLocalOrTarExporter(outputs: string[]): Boolean { export function isLocalOrTarExporter(outputs: string[]): boolean {
for (let output of csvparse(outputs.join(`\n`), { for (const output of csvparse(outputs.join(`\n`), {
delimiter: ',', delimiter: ',',
trim: true, trim: true,
columns: false, columns: false,
@ -88,7 +88,7 @@ export function isLocalOrTarExporter(outputs: string[]): Boolean {
if (output.length == 1 && !output[0].startsWith('type=')) { if (output.length == 1 && !output[0].startsWith('type=')) {
return true; return true;
} }
for (let [key, value] of output.map(chunk => chunk.split('=').map(item => item.trim()))) { for (const [key, value] of output.map(chunk => chunk.split('=').map(item => item.trim()))) {
if (key == 'type' && (value == 'local' || value == 'tar')) { if (key == 'type' && (value == 'local' || value == 'tar')) {
return true; return true;
} }
@ -97,8 +97,8 @@ export function isLocalOrTarExporter(outputs: string[]): Boolean {
return false; return false;
} }
export function hasGitAuthToken(secrets: string[]): Boolean { export function hasGitAuthToken(secrets: string[]): boolean {
for (let secret of secrets) { for (const secret of secrets) {
if (secret.startsWith('GIT_AUTH_TOKEN=')) { if (secret.startsWith('GIT_AUTH_TOKEN=')) {
return true; return true;
} }
@ -106,7 +106,7 @@ export function hasGitAuthToken(secrets: string[]): Boolean {
return false; return false;
} }
export async function isAvailable(): Promise<Boolean> { export async function isAvailable(): Promise<boolean> {
return await exec return await exec
.getExecOutput('docker', ['buildx'], { .getExecOutput('docker', ['buildx'], {
ignoreReturnCode: true, ignoreReturnCode: true,

View file

@ -99,15 +99,17 @@ export async function getInputs(defaultContext: string): Promise<Inputs> {
} }
export async function getArgs(inputs: Inputs, defaultContext: string, buildxVersion: string): Promise<Array<string>> { export async function getArgs(inputs: Inputs, defaultContext: string, buildxVersion: string): Promise<Array<string>> {
let args: Array<string> = ['buildx']; // prettier-ignore
args.push.apply(args, await getBuildArgs(inputs, defaultContext, buildxVersion)); return [
args.push.apply(args, await getCommonArgs(inputs, buildxVersion)); 'buildx',
args.push(handlebars.compile(inputs.context)({defaultContext})); ...await getBuildArgs(inputs, defaultContext, buildxVersion),
return args; ...await getCommonArgs(inputs, buildxVersion),
handlebars.compile(inputs.context)({defaultContext})
];
} }
async function getBuildArgs(inputs: Inputs, defaultContext: string, buildxVersion: string): Promise<Array<string>> { async function getBuildArgs(inputs: Inputs, defaultContext: string, buildxVersion: string): Promise<Array<string>> {
let args: Array<string> = ['build']; const args: Array<string> = ['build'];
await asyncForEach(inputs.addHosts, async addHost => { await asyncForEach(inputs.addHosts, async addHost => {
args.push('--add-host', addHost); args.push('--add-host', addHost);
}); });
@ -182,7 +184,7 @@ async function getBuildArgs(inputs: Inputs, defaultContext: string, buildxVersio
} }
async function getCommonArgs(inputs: Inputs, buildxVersion: string): Promise<Array<string>> { async function getCommonArgs(inputs: Inputs, buildxVersion: string): Promise<Array<string>> {
let args: Array<string> = []; const args: Array<string> = [];
if (inputs.builder) { if (inputs.builder) {
args.push('--builder', inputs.builder); args.push('--builder', inputs.builder);
} }
@ -208,14 +210,14 @@ async function getCommonArgs(inputs: Inputs, buildxVersion: string): Promise<Arr
} }
export async function getInputList(name: string, ignoreComma?: boolean): Promise<string[]> { export async function getInputList(name: string, ignoreComma?: boolean): Promise<string[]> {
let res: Array<string> = []; const res: Array<string> = [];
const items = core.getInput(name); const items = core.getInput(name);
if (items == '') { if (items == '') {
return res; return res;
} }
for (let output of (await csvparse(items, { for (const output of (await csvparse(items, {
columns: false, columns: false,
relax: true, relax: true,
relaxColumnCount: true, relaxColumnCount: true,
@ -241,6 +243,6 @@ export const asyncForEach = async (array, callback) => {
}; };
// FIXME: Temp fix https://github.com/actions/toolkit/issues/777 // FIXME: Temp fix https://github.com/actions/toolkit/issues/777
export function setOutput(name: string, value: any): void { export function setOutput(name: string, value: unknown): void {
issueCommand('set-output', {name}, value); issueCommand('set-output', {name}, value);
} }

View file

@ -20,7 +20,7 @@ async function run(): Promise<void> {
const buildxVersion = await buildx.getVersion(); const buildxVersion = await buildx.getVersion();
const defContext = context.defaultContext(); const defContext = context.defaultContext();
let inputs: context.Inputs = await context.getInputs(defContext); const inputs: context.Inputs = await context.getInputs(defContext);
const args: string[] = await context.getArgs(inputs, defContext, buildxVersion); const args: string[] = await context.getArgs(inputs, defContext, buildxVersion);
await exec await exec
@ -29,7 +29,7 @@ async function run(): Promise<void> {
}) })
.then(res => { .then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) { if (res.stderr.length > 0 && res.exitCode != 0) {
throw new Error(`buildx failed with: ${res.stderr.match(/(.*)\s*$/)![0].trim()}`); throw new Error(`buildx failed with: ${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`);
} }
}); });

View file

@ -2,20 +2,18 @@
"compilerOptions": { "compilerOptions": {
"target": "es6", "target": "es6",
"module": "commonjs", "module": "commonjs",
"lib": [
"es6",
"dom"
],
"newLine": "lf", "newLine": "lf",
"outDir": "./lib", "outDir": "./lib",
"rootDir": "./src", "rootDir": "./src",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true, "strict": true,
"noImplicitAny": false, "noImplicitAny": false,
"esModuleInterop": true, "useUnknownInCatchVariables": false,
"sourceMap": true
}, },
"exclude": [ "exclude": [
"node_modules", "node_modules",
"**/*.test.ts" "**/*.test.ts",
"jest.config.ts"
] ]
} }

3134
yarn.lock

File diff suppressed because it is too large Load diff