mirror of
https://github.com/docker/build-push-action.git
synced 2025-06-14 07:07:12 +02:00
Compare commits
30 Commits
Author | SHA1 | Date | |
---|---|---|---|
e551b19e49 | |||
3554377aa3 | |||
a62bc1b22b | |||
c2085839e1 | |||
fcd91249e5 | |||
0ebe720aed | |||
38b45804b5 | |||
ba317382dc | |||
43721d2346 | |||
5ea21bf2ba | |||
300b1bdff7 | |||
84580d7737 | |||
a460b5e683 | |||
9f1392c9bf | |||
9472e90210 | |||
5accc8e023 | |||
f7a2a67b4c | |||
b905f177bc | |||
0779722168 | |||
fd75456293 | |||
ada965aa7b | |||
b5730d2471 | |||
839389a46c | |||
34c1caa1ce | |||
6ff230f13e | |||
75c825aabc | |||
5f7b938b8c | |||
7ae34a20f3 | |||
acb76cdd52 | |||
2d081a4fd5 |
23
.eslintrc.json
Normal file
23
.eslintrc.json
Normal 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"
|
||||
]
|
||||
}
|
24
.github/workflows/ci.yml
vendored
24
.github/workflows/ci.yml
vendored
@ -663,7 +663,7 @@ jobs:
|
||||
network=host
|
||||
-
|
||||
name: Cache Docker layers
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-local-${{ github.sha }}
|
||||
@ -724,7 +724,7 @@ jobs:
|
||||
network=host
|
||||
-
|
||||
name: Cache Docker layers
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
id: cache
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
@ -814,3 +814,23 @@ jobs:
|
||||
name: Inspect
|
||||
run: |
|
||||
docker buildx imagetools inspect localhost:5000/name/app:1.0.0
|
||||
|
||||
standalone:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Uninstall moby cli
|
||||
run: |
|
||||
sudo apt-get purge -y moby-cli moby-buildx
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
-
|
||||
name: Build
|
||||
uses: ./
|
||||
with:
|
||||
context: ./test
|
||||
file: ./test/Dockerfile
|
||||
|
2
.github/workflows/e2e.yml
vendored
2
.github/workflows/e2e.yml
vendored
@ -64,7 +64,7 @@ jobs:
|
||||
-
|
||||
name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v3
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: ${{ matrix.slug }}
|
||||
-
|
||||
|
2
.github/workflows/example.yml
vendored
2
.github/workflows/example.yml
vendored
@ -29,7 +29,7 @@ jobs:
|
||||
-
|
||||
name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v3
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: ${{ env.DOCKER_IMAGE }}
|
||||
tags: |
|
||||
|
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@ -27,6 +27,6 @@ jobs:
|
||||
targets: test
|
||||
-
|
||||
name: Upload coverage
|
||||
uses: codecov/codecov-action@v2
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
file: ./coverage/clover.xml
|
||||
|
18
.github/workflows/virtual-env.yml
vendored
18
.github/workflows/virtual-env.yml
vendored
@ -19,15 +19,33 @@ jobs:
|
||||
-
|
||||
name: File system
|
||||
run: df -ah
|
||||
-
|
||||
name: Mounts
|
||||
run: mount
|
||||
-
|
||||
name: Node info
|
||||
run: node -p process
|
||||
-
|
||||
name: NPM version
|
||||
run: npm version
|
||||
-
|
||||
name: List install packages
|
||||
run: apt list --installed
|
||||
-
|
||||
name: Docker daemon conf
|
||||
run: |
|
||||
cat /etc/docker/daemon.json
|
||||
-
|
||||
name: Docker info
|
||||
run: docker info
|
||||
-
|
||||
name: Docker version
|
||||
run: docker version
|
||||
-
|
||||
name: Cgroups
|
||||
run: |
|
||||
sudo apt-get install -y cgroup-tools
|
||||
lscgroup
|
||||
-
|
||||
name: buildx version
|
||||
run: docker buildx version
|
||||
|
@ -1,8 +1,8 @@
|
||||
import {describe, expect, it, jest, test} from '@jest/globals';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as semver from 'semver';
|
||||
import * as exec from '@actions/exec';
|
||||
|
||||
import * as buildx from '../src/buildx';
|
||||
import * as context from '../src/context';
|
||||
|
||||
@ -53,94 +53,47 @@ describe('getDigest', () => {
|
||||
});
|
||||
|
||||
describe('isLocalOrTarExporter', () => {
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
[
|
||||
[
|
||||
'type=registry,ref=user/app',
|
||||
],
|
||||
false
|
||||
],
|
||||
[
|
||||
[
|
||||
'type=docker',
|
||||
],
|
||||
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);
|
||||
}
|
||||
);
|
||||
[['type=registry,ref=user/app'], false],
|
||||
[['type=docker'], 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', () => {
|
||||
const execSpy: jest.SpyInstance = jest.spyOn(exec, 'getExecOutput');
|
||||
const execSpy = jest.spyOn(exec, 'getExecOutput');
|
||||
buildx.isAvailable();
|
||||
|
||||
// eslint-disable-next-line jest/no-standalone-expect
|
||||
expect(execSpy).toHaveBeenCalledWith(`docker`, ['buildx'], {
|
||||
silent: true,
|
||||
ignoreReturnCode: true
|
||||
});
|
||||
});
|
||||
|
||||
describe('isAvailable standalone', () => {
|
||||
const execSpy = jest.spyOn(exec, 'getExecOutput');
|
||||
buildx.isAvailable(true);
|
||||
|
||||
// eslint-disable-next-line jest/no-standalone-expect
|
||||
expect(execSpy).toHaveBeenCalledWith(`buildx`, [], {
|
||||
silent: true,
|
||||
ignoreReturnCode: true
|
||||
});
|
||||
});
|
||||
|
||||
describe('getVersion', () => {
|
||||
async function isDaemonRunning() {
|
||||
return await exec
|
||||
.getExecOutput(`docker`, ['version', '--format', '{{.Server.Os}}'], {
|
||||
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
|
||||
);
|
||||
it('valid', async () => {
|
||||
const version = await buildx.getVersion();
|
||||
expect(semver.valid(version)).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseVersion', () => {
|
||||
@ -187,6 +140,7 @@ describe('getSecret', () => {
|
||||
const secretValue = await fs.readFileSync(tmpNameSync, 'utf-8');
|
||||
expect(secretValue).toEqual(exValue);
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line jest/no-conditional-expect
|
||||
expect(true).toBe(invalid);
|
||||
}
|
||||
});
|
||||
|
@ -1,3 +1,4 @@
|
||||
import {beforeEach, describe, expect, it, jest, test} from '@jest/globals';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
@ -150,7 +151,6 @@ describe('getArgs', () => {
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'build',
|
||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||
'.'
|
||||
@ -167,7 +167,6 @@ describe('getArgs', () => {
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'build',
|
||||
'--build-arg', 'MY_ARG=val1,val2,val3',
|
||||
'--build-arg', 'ARG=val',
|
||||
@ -186,7 +185,6 @@ describe('getArgs', () => {
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'build',
|
||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||
'--tag', 'name/app:7.4',
|
||||
@ -207,7 +205,6 @@ describe('getArgs', () => {
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'build',
|
||||
'--label', 'org.opencontainers.image.title=buildkit',
|
||||
'--label', 'org.opencontainers.image.description=concurrent, cache-efficient, and Dockerfile-agnostic builder toolkit',
|
||||
@ -227,7 +224,6 @@ describe('getArgs', () => {
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'build',
|
||||
'--platform', 'linux/amd64,linux/arm64',
|
||||
'.'
|
||||
@ -244,7 +240,6 @@ describe('getArgs', () => {
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'build',
|
||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||
'.'
|
||||
@ -262,7 +257,6 @@ describe('getArgs', () => {
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'build',
|
||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||
'--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
||||
@ -281,7 +275,6 @@ describe('getArgs', () => {
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'build',
|
||||
'--output', '.',
|
||||
'--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
||||
@ -304,7 +297,6 @@ describe('getArgs', () => {
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'build',
|
||||
'--file', './test/Dockerfile',
|
||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||
@ -339,7 +331,6 @@ ccc"`],
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'build',
|
||||
'--file', './test/Dockerfile',
|
||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||
@ -377,7 +368,6 @@ ccc`],
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'build',
|
||||
'--file', './test/Dockerfile',
|
||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||
@ -407,7 +397,6 @@ ccc`],
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'build',
|
||||
'--file', './test/Dockerfile',
|
||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||
@ -431,7 +420,6 @@ ccc`],
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'build',
|
||||
'--label', 'org.opencontainers.image.title=filter_results_top_n',
|
||||
'--label', 'org.opencontainers.image.description=Reference implementation of operation "filter results (top-n)"',
|
||||
@ -454,7 +442,6 @@ ccc`],
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'build',
|
||||
'--add-host', 'docker:10.180.0.1',
|
||||
'--add-host', 'foo:10.0.0.1',
|
||||
@ -483,7 +470,6 @@ nproc=3`],
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'build',
|
||||
'--add-host', 'docker:10.180.0.1',
|
||||
'--add-host', 'foo:10.0.0.1',
|
||||
@ -508,7 +494,6 @@ nproc=3`],
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'build',
|
||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||
'--metadata-file', '/tmp/.docker-build-push-jest/metadata-file',
|
||||
@ -517,8 +502,8 @@ nproc=3`],
|
||||
],
|
||||
])(
|
||||
'[%d] given %p with %p as inputs, returns %p',
|
||||
async (num: number, buildxVersion: string, inputs: Map<string, any>, expected: Array<string>) => {
|
||||
await inputs.forEach((value: string, name: string) => {
|
||||
async (num: number, buildxVersion: string, inputs: Map<string, string>, expected: Array<string>) => {
|
||||
inputs.forEach((value: string, name: string) => {
|
||||
setInput(name, value);
|
||||
});
|
||||
const defContext = context.defaultContext();
|
||||
@ -666,7 +651,7 @@ FOO=bar`
|
||||
expect(res).toEqual([
|
||||
'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789',
|
||||
`MYSECRET=aaaaaaaa
|
||||
bbbb\"bbb
|
||||
bbbb"bbb
|
||||
ccccccccc`,
|
||||
'FOO=bar'
|
||||
]);
|
||||
@ -688,19 +673,22 @@ describe('asyncForEach', () => {
|
||||
|
||||
describe('setOutput', () => {
|
||||
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', () => {
|
||||
context.setOutput('some output', 'some value');
|
||||
assertWriteCalls([`::set-output name=some output::some value${os.EOL}`]);
|
||||
});
|
||||
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it('setOutput handles bools', () => {
|
||||
context.setOutput('some output', false);
|
||||
assertWriteCalls([`::set-output name=some output::false${os.EOL}`]);
|
||||
});
|
||||
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it('setOutput handles numbers', () => {
|
||||
context.setOutput('some output', 1.01);
|
||||
assertWriteCalls([`::set-output name=some output::1.01${os.EOL}`]);
|
||||
|
16
__tests__/docker.test.ts
Normal file
16
__tests__/docker.test.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import {describe, expect, it, jest} from '@jest/globals';
|
||||
import * as docker from '../src/docker';
|
||||
import * as exec from '@actions/exec';
|
||||
|
||||
describe('isAvailable', () => {
|
||||
it('cli', () => {
|
||||
const execSpy = jest.spyOn(exec, 'getExecOutput');
|
||||
docker.isAvailable();
|
||||
|
||||
// eslint-disable-next-line jest/no-standalone-expect
|
||||
expect(execSpy).toHaveBeenCalledWith(`docker`, undefined, {
|
||||
silent: true,
|
||||
ignoreReturnCode: true
|
||||
});
|
||||
});
|
||||
});
|
@ -100,6 +100,6 @@ outputs:
|
||||
description: 'Build result metadata'
|
||||
|
||||
runs:
|
||||
using: 'node12'
|
||||
using: 'node16'
|
||||
main: 'dist/index.js'
|
||||
post: 'dist/index.js'
|
||||
|
@ -1,8 +1,8 @@
|
||||
# syntax=docker/dockerfile:1.3-labs
|
||||
# syntax=docker/dockerfile:1.4
|
||||
|
||||
ARG NODE_VERSION
|
||||
ARG DOCKER_VERSION=20.10.10
|
||||
ARG BUILDX_VERSION=0.7.0
|
||||
ARG NODE_VERSION=16
|
||||
ARG DOCKER_VERSION=20.10.13
|
||||
ARG BUILDX_VERSION=0.8.0
|
||||
|
||||
FROM node:${NODE_VERSION}-alpine AS base
|
||||
RUN apk add --no-cache cpio findutils git
|
||||
@ -57,10 +57,10 @@ RUN --mount=type=bind,target=.,rw \
|
||||
FROM scratch AS format-update
|
||||
COPY --from=format /out /
|
||||
|
||||
FROM deps AS format-validate
|
||||
FROM deps AS lint
|
||||
RUN --mount=type=bind,target=.,rw \
|
||||
--mount=type=cache,target=/src/node_modules \
|
||||
yarn run format-check
|
||||
yarn run lint
|
||||
|
||||
FROM docker:${DOCKER_VERSION} as docker
|
||||
FROM docker/buildx-bin:${BUILDX_VERSION} as buildx
|
27909
dist/index.js
generated
vendored
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
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
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
1
dist/sourcemap-register.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -1,13 +1,3 @@
|
||||
variable "NODE_VERSION" {
|
||||
default = "12"
|
||||
}
|
||||
|
||||
target "node-version" {
|
||||
args = {
|
||||
NODE_VERSION = NODE_VERSION
|
||||
}
|
||||
}
|
||||
|
||||
group "default" {
|
||||
targets = ["build"]
|
||||
}
|
||||
@ -17,54 +7,47 @@ group "pre-checkin" {
|
||||
}
|
||||
|
||||
group "validate" {
|
||||
targets = ["format-validate", "build-validate", "vendor-validate"]
|
||||
targets = ["lint", "build-validate", "vendor-validate"]
|
||||
}
|
||||
|
||||
target "build" {
|
||||
inherits = ["node-version"]
|
||||
dockerfile = "./hack/build.Dockerfile"
|
||||
dockerfile = "dev.Dockerfile"
|
||||
target = "build-update"
|
||||
output = ["."]
|
||||
}
|
||||
|
||||
target "build-validate" {
|
||||
inherits = ["node-version"]
|
||||
dockerfile = "./hack/build.Dockerfile"
|
||||
dockerfile = "dev.Dockerfile"
|
||||
target = "build-validate"
|
||||
output = ["type=cacheonly"]
|
||||
}
|
||||
|
||||
target "format" {
|
||||
inherits = ["node-version"]
|
||||
dockerfile = "./hack/build.Dockerfile"
|
||||
dockerfile = "dev.Dockerfile"
|
||||
target = "format-update"
|
||||
output = ["."]
|
||||
}
|
||||
|
||||
target "format-validate" {
|
||||
inherits = ["node-version"]
|
||||
dockerfile = "./hack/build.Dockerfile"
|
||||
target = "format-validate"
|
||||
target "lint" {
|
||||
dockerfile = "dev.Dockerfile"
|
||||
target = "lint"
|
||||
output = ["type=cacheonly"]
|
||||
}
|
||||
|
||||
target "vendor-update" {
|
||||
inherits = ["node-version"]
|
||||
dockerfile = "./hack/build.Dockerfile"
|
||||
dockerfile = "dev.Dockerfile"
|
||||
target = "vendor-update"
|
||||
output = ["."]
|
||||
}
|
||||
|
||||
target "vendor-validate" {
|
||||
inherits = ["node-version"]
|
||||
dockerfile = "./hack/build.Dockerfile"
|
||||
dockerfile = "dev.Dockerfile"
|
||||
target = "vendor-validate"
|
||||
output = ["type=cacheonly"]
|
||||
}
|
||||
|
||||
target "test" {
|
||||
inherits = ["node-version"]
|
||||
dockerfile = "./hack/build.Dockerfile"
|
||||
dockerfile = "dev.Dockerfile"
|
||||
target = "test-coverage"
|
||||
output = ["./coverage"]
|
||||
}
|
||||
|
@ -1,12 +1,13 @@
|
||||
module.exports = {
|
||||
clearMocks: false,
|
||||
moduleFileExtensions: ['js', 'ts'],
|
||||
setupFiles: ["dotenv/config"],
|
||||
testEnvironment: 'node',
|
||||
setupFiles: ['dotenv/config'],
|
||||
testMatch: ['**/*.test.ts'],
|
||||
testRunner: 'jest-circus/runner',
|
||||
transform: {
|
||||
'^.+\\.ts$': 'ts-jest'
|
||||
},
|
||||
verbose: false
|
||||
}
|
||||
moduleNameMapper: {
|
||||
'^csv-parse/sync': '<rootDir>/node_modules/csv-parse/dist/cjs/sync.cjs'
|
||||
},
|
||||
verbose: true
|
||||
};
|
42
package.json
42
package.json
@ -3,11 +3,11 @@
|
||||
"description": "Build and push Docker images",
|
||||
"main": "lib/main.js",
|
||||
"scripts": {
|
||||
"build": "tsc && ncc build",
|
||||
"format": "prettier --write **/*.ts",
|
||||
"format-check": "prettier --check **/*.ts",
|
||||
"build": "ncc build src/main.ts --source-map --minify --license licenses.txt",
|
||||
"lint": "eslint src/**/*.ts __tests__/**/*.ts",
|
||||
"format": "eslint --fix src/**/*.ts __tests__/**/*.ts",
|
||||
"test": "jest --coverage",
|
||||
"pre-checkin": "yarn run format && yarn run build"
|
||||
"all": "yarn run build && yarn run format && yarn test"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -29,26 +29,30 @@
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.6.0",
|
||||
"@actions/exec": "^1.1.0",
|
||||
"@actions/github": "^5.0.0",
|
||||
"csv-parse": "^4.16.3",
|
||||
"@actions/exec": "^1.1.1",
|
||||
"@actions/github": "^5.0.1",
|
||||
"csv-parse": "^5.0.4",
|
||||
"handlebars": "^4.7.7",
|
||||
"semver": "^7.3.5",
|
||||
"semver": "^7.3.7",
|
||||
"tmp": "^0.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/csv-parse": "^1.2.2",
|
||||
"@types/jest": "^26.0.23",
|
||||
"@types/node": "^14.17.4",
|
||||
"@types/tmp": "^0.2.0",
|
||||
"@vercel/ncc": "^0.28.6",
|
||||
"dotenv": "^8.6.0",
|
||||
"jest": "^26.6.3",
|
||||
"jest-circus": "^26.6.3",
|
||||
"jest-runtime": "^26.6.3",
|
||||
"@types/node": "^16.11.26",
|
||||
"@types/semver": "^7.3.9",
|
||||
"@types/tmp": "^0.2.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.14.0",
|
||||
"@typescript-eslint/parser": "^5.14.0",
|
||||
"@vercel/ncc": "^0.33.3",
|
||||
"dotenv": "^16.0.0",
|
||||
"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",
|
||||
"ts-jest": "^26.5.6",
|
||||
"typescript": "^4.3.4",
|
||||
"typescript-formatter": "^7.2.2"
|
||||
"ts-jest": "^27.1.2",
|
||||
"ts-node": "^10.7.0",
|
||||
"typescript": "^4.4.4"
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import csvparse from 'csv-parse/lib/sync';
|
||||
import {parse} from 'csv-parse/sync';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import * as semver from 'semver';
|
||||
@ -76,19 +76,20 @@ export async function getSecret(kvp: string, file: boolean): Promise<string> {
|
||||
return `id=${key},src=${secretFile}`;
|
||||
}
|
||||
|
||||
export function isLocalOrTarExporter(outputs: string[]): Boolean {
|
||||
for (let output of csvparse(outputs.join(`\n`), {
|
||||
export function isLocalOrTarExporter(outputs: string[]): boolean {
|
||||
const records = parse(outputs.join(`\n`), {
|
||||
delimiter: ',',
|
||||
trim: true,
|
||||
columns: false,
|
||||
relaxColumnCount: true
|
||||
})) {
|
||||
});
|
||||
for (const record of records) {
|
||||
// Local if no type is defined
|
||||
// https://github.com/docker/buildx/blob/d2bf42f8b4784d83fde17acb3ed84703ddc2156b/build/output.go#L29-L43
|
||||
if (output.length == 1 && !output[0].startsWith('type=')) {
|
||||
if (record.length == 1 && !record[0].startsWith('type=')) {
|
||||
return true;
|
||||
}
|
||||
for (let [key, value] of output.map(chunk => chunk.split('=').map(item => item.trim()))) {
|
||||
for (const [key, value] of record.map(chunk => chunk.split('=').map(item => item.trim()))) {
|
||||
if (key == 'type' && (value == 'local' || value == 'tar')) {
|
||||
return true;
|
||||
}
|
||||
@ -97,8 +98,8 @@ export function isLocalOrTarExporter(outputs: string[]): Boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
export function hasGitAuthToken(secrets: string[]): Boolean {
|
||||
for (let secret of secrets) {
|
||||
export function hasGitAuthToken(secrets: string[]): boolean {
|
||||
for (const secret of secrets) {
|
||||
if (secret.startsWith('GIT_AUTH_TOKEN=')) {
|
||||
return true;
|
||||
}
|
||||
@ -106,9 +107,10 @@ export function hasGitAuthToken(secrets: string[]): Boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
export async function isAvailable(): Promise<Boolean> {
|
||||
export async function isAvailable(standalone?: boolean): Promise<boolean> {
|
||||
const cmd = getCommand([], standalone);
|
||||
return await exec
|
||||
.getExecOutput('docker', ['buildx'], {
|
||||
.getExecOutput(cmd.command, cmd.args, {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
})
|
||||
@ -117,12 +119,17 @@ export async function isAvailable(): Promise<Boolean> {
|
||||
return false;
|
||||
}
|
||||
return res.exitCode == 0;
|
||||
})
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
.catch(error => {
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
export async function getVersion(): Promise<string> {
|
||||
export async function getVersion(standalone?: boolean): Promise<string> {
|
||||
const cmd = getCommand(['version'], standalone);
|
||||
return await exec
|
||||
.getExecOutput('docker', ['buildx', 'version'], {
|
||||
.getExecOutput(cmd.command, cmd.args, {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
})
|
||||
@ -145,3 +152,10 @@ export function parseVersion(stdout: string): string {
|
||||
export function satisfies(version: string, range: string): boolean {
|
||||
return semver.satisfies(version, range) || /^[0-9a-f]{7}$/.exec(version) !== null;
|
||||
}
|
||||
|
||||
export function getCommand(args: Array<string>, standalone?: boolean) {
|
||||
return {
|
||||
command: standalone ? 'buildx' : 'docker',
|
||||
args: standalone ? args : ['buildx', ...args]
|
||||
};
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import csvparse from 'csv-parse/lib/sync';
|
||||
import {parse} from 'csv-parse/sync';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
@ -99,15 +99,16 @@ export async function getInputs(defaultContext: string): Promise<Inputs> {
|
||||
}
|
||||
|
||||
export async function getArgs(inputs: Inputs, defaultContext: string, buildxVersion: string): Promise<Array<string>> {
|
||||
let args: Array<string> = ['buildx'];
|
||||
args.push.apply(args, await getBuildArgs(inputs, defaultContext, buildxVersion));
|
||||
args.push.apply(args, await getCommonArgs(inputs, buildxVersion));
|
||||
args.push(handlebars.compile(inputs.context)({defaultContext}));
|
||||
return args;
|
||||
// prettier-ignore
|
||||
return [
|
||||
...await getBuildArgs(inputs, defaultContext, buildxVersion),
|
||||
...await getCommonArgs(inputs, buildxVersion),
|
||||
handlebars.compile(inputs.context)({defaultContext})
|
||||
];
|
||||
}
|
||||
|
||||
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 => {
|
||||
args.push('--add-host', addHost);
|
||||
});
|
||||
@ -182,7 +183,7 @@ async function getBuildArgs(inputs: Inputs, defaultContext: string, buildxVersio
|
||||
}
|
||||
|
||||
async function getCommonArgs(inputs: Inputs, buildxVersion: string): Promise<Array<string>> {
|
||||
let args: Array<string> = [];
|
||||
const args: Array<string> = [];
|
||||
if (inputs.builder) {
|
||||
args.push('--builder', inputs.builder);
|
||||
}
|
||||
@ -208,27 +209,29 @@ async function getCommonArgs(inputs: Inputs, buildxVersion: string): Promise<Arr
|
||||
}
|
||||
|
||||
export async function getInputList(name: string, ignoreComma?: boolean): Promise<string[]> {
|
||||
let res: Array<string> = [];
|
||||
const res: Array<string> = [];
|
||||
|
||||
const items = core.getInput(name);
|
||||
if (items == '') {
|
||||
return res;
|
||||
}
|
||||
|
||||
for (let output of (await csvparse(items, {
|
||||
const records = await parse(items, {
|
||||
columns: false,
|
||||
relax: true,
|
||||
relaxQuotes: true,
|
||||
relaxColumnCount: true,
|
||||
skipLinesWithEmptyValues: true
|
||||
})) as Array<string[]>) {
|
||||
if (output.length == 1) {
|
||||
res.push(output[0]);
|
||||
skipEmptyLines: true
|
||||
});
|
||||
|
||||
for (const record of records as Array<string[]>) {
|
||||
if (record.length == 1) {
|
||||
res.push(record[0]);
|
||||
continue;
|
||||
} else if (!ignoreComma) {
|
||||
res.push(...output);
|
||||
res.push(...record);
|
||||
continue;
|
||||
}
|
||||
res.push(output.join(','));
|
||||
res.push(record.join(','));
|
||||
}
|
||||
|
||||
return res.filter(item => item).map(pat => pat.trim());
|
||||
@ -241,6 +244,6 @@ export const asyncForEach = async (array, callback) => {
|
||||
};
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
19
src/docker.ts
Normal file
19
src/docker.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import * as exec from '@actions/exec';
|
||||
|
||||
export async function isAvailable(): Promise<boolean> {
|
||||
return await exec
|
||||
.getExecOutput('docker', undefined, {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
})
|
||||
.then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
return false;
|
||||
}
|
||||
return res.exitCode == 0;
|
||||
})
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
.catch(error => {
|
||||
return false;
|
||||
});
|
||||
}
|
36
src/main.ts
36
src/main.ts
@ -1,35 +1,55 @@
|
||||
import * as fs from 'fs';
|
||||
import * as buildx from './buildx';
|
||||
import * as context from './context';
|
||||
import * as docker from './docker';
|
||||
import * as stateHelper from './state-helper';
|
||||
import * as core from '@actions/core';
|
||||
import * as exec from '@actions/exec';
|
||||
|
||||
async function run(): Promise<void> {
|
||||
try {
|
||||
const defContext = context.defaultContext();
|
||||
const inputs: context.Inputs = await context.getInputs(defContext);
|
||||
|
||||
// standalone if docker cli not available
|
||||
const standalone = !(await docker.isAvailable());
|
||||
|
||||
core.startGroup(`Docker info`);
|
||||
await exec.exec('docker', ['version']);
|
||||
await exec.exec('docker', ['info']);
|
||||
if (standalone) {
|
||||
core.info(`Docker info skipped in standalone mode`);
|
||||
} else {
|
||||
await exec.exec('docker', ['version'], {
|
||||
failOnStdErr: false
|
||||
});
|
||||
await exec.exec('docker', ['info'], {
|
||||
failOnStdErr: false
|
||||
});
|
||||
}
|
||||
core.endGroup();
|
||||
|
||||
if (!(await buildx.isAvailable())) {
|
||||
if (!(await buildx.isAvailable(standalone))) {
|
||||
core.setFailed(`Docker buildx is required. See https://github.com/docker/setup-buildx-action to set up buildx.`);
|
||||
return;
|
||||
}
|
||||
stateHelper.setTmpDir(context.tmpDir());
|
||||
|
||||
const buildxVersion = await buildx.getVersion();
|
||||
const defContext = context.defaultContext();
|
||||
let inputs: context.Inputs = await context.getInputs(defContext);
|
||||
const buildxVersion = await buildx.getVersion(standalone);
|
||||
await core.group(`Buildx version`, async () => {
|
||||
const versionCmd = buildx.getCommand(['version'], standalone);
|
||||
await exec.exec(versionCmd.command, versionCmd.args, {
|
||||
failOnStdErr: false
|
||||
});
|
||||
});
|
||||
|
||||
const args: string[] = await context.getArgs(inputs, defContext, buildxVersion);
|
||||
const buildCmd = buildx.getCommand(args, standalone);
|
||||
await exec
|
||||
.getExecOutput('docker', args, {
|
||||
.getExecOutput(buildCmd.command, buildCmd.args, {
|
||||
ignoreReturnCode: true
|
||||
})
|
||||
.then(res => {
|
||||
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'}`);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -2,20 +2,18 @@
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"module": "commonjs",
|
||||
"lib": [
|
||||
"es6",
|
||||
"dom"
|
||||
],
|
||||
"newLine": "lf",
|
||||
"outDir": "./lib",
|
||||
"rootDir": "./src",
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noImplicitAny": false,
|
||||
"esModuleInterop": true,
|
||||
"sourceMap": true
|
||||
"useUnknownInCatchVariables": false,
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"**/*.test.ts"
|
||||
"**/*.test.ts",
|
||||
"jest.config.ts"
|
||||
]
|
||||
}
|
||||
|
Reference in New Issue
Block a user