mirror of
https://github.com/docker/build-push-action.git
synced 2024-12-26 08:42:09 -05:00
Merge pull request #601 from crazy-max/standalone-mode
Standalone mode support
This commit is contained in:
commit
c2085839e1
10 changed files with 152 additions and 31 deletions
59
.github/workflows/ci.yml
vendored
59
.github/workflows/ci.yml
vendored
|
@ -814,3 +814,62 @@ jobs:
|
||||||
name: Inspect
|
name: Inspect
|
||||||
run: |
|
run: |
|
||||||
docker buildx imagetools inspect localhost:5000/name/app:1.0.0
|
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
|
||||||
|
|
||||||
|
standalone-kubernetes:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
-
|
||||||
|
name: Uninstall moby
|
||||||
|
run: |
|
||||||
|
sudo apt-get purge -y moby-engine moby-cli moby-buildx
|
||||||
|
-
|
||||||
|
name: Setup k8s cluster
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
|
||||||
|
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y kubelet kubeadm kubectl
|
||||||
|
sudo swapoff -a
|
||||||
|
sudo kubeadm init --cri-socket /run/containerd/containerd.sock
|
||||||
|
mkdir -p $HOME/.kube/
|
||||||
|
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
|
||||||
|
sudo chown $USER $HOME/.kube/config
|
||||||
|
kubectl taint nodes --all node-role.kubernetes.io/master-
|
||||||
|
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
|
||||||
|
kubectl wait --for=condition=ready --timeout=30s node --all
|
||||||
|
kubectl get nodes -o wide
|
||||||
|
-
|
||||||
|
name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
with:
|
||||||
|
driver: kubernetes
|
||||||
|
-
|
||||||
|
name: Build
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
context: ./test
|
||||||
|
file: ./test/Dockerfile
|
||||||
|
|
|
@ -78,6 +78,17 @@ describe('isAvailable', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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', () => {
|
describe('getVersion', () => {
|
||||||
it('valid', async () => {
|
it('valid', async () => {
|
||||||
const version = await buildx.getVersion();
|
const version = await buildx.getVersion();
|
||||||
|
|
|
@ -151,7 +151,6 @@ describe('getArgs', () => {
|
||||||
['pull', 'false'],
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
'.'
|
'.'
|
||||||
|
@ -168,7 +167,6 @@ describe('getArgs', () => {
|
||||||
['pull', 'false'],
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
'--build-arg', 'MY_ARG=val1,val2,val3',
|
'--build-arg', 'MY_ARG=val1,val2,val3',
|
||||||
'--build-arg', 'ARG=val',
|
'--build-arg', 'ARG=val',
|
||||||
|
@ -187,7 +185,6 @@ describe('getArgs', () => {
|
||||||
['pull', 'false'],
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
'--tag', 'name/app:7.4',
|
'--tag', 'name/app:7.4',
|
||||||
|
@ -208,7 +205,6 @@ describe('getArgs', () => {
|
||||||
['pull', 'false'],
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
'--label', 'org.opencontainers.image.title=buildkit',
|
'--label', 'org.opencontainers.image.title=buildkit',
|
||||||
'--label', 'org.opencontainers.image.description=concurrent, cache-efficient, and Dockerfile-agnostic builder toolkit',
|
'--label', 'org.opencontainers.image.description=concurrent, cache-efficient, and Dockerfile-agnostic builder toolkit',
|
||||||
|
@ -228,7 +224,6 @@ describe('getArgs', () => {
|
||||||
['pull', 'false'],
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
'--platform', 'linux/amd64,linux/arm64',
|
'--platform', 'linux/amd64,linux/arm64',
|
||||||
'.'
|
'.'
|
||||||
|
@ -245,7 +240,6 @@ describe('getArgs', () => {
|
||||||
['pull', 'false'],
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
'.'
|
'.'
|
||||||
|
@ -263,7 +257,6 @@ describe('getArgs', () => {
|
||||||
['pull', 'false'],
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
'--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
'--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
||||||
|
@ -282,7 +275,6 @@ describe('getArgs', () => {
|
||||||
['pull', 'false'],
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
'--output', '.',
|
'--output', '.',
|
||||||
'--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
'--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
||||||
|
@ -305,7 +297,6 @@ describe('getArgs', () => {
|
||||||
['pull', 'false'],
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
'--file', './test/Dockerfile',
|
'--file', './test/Dockerfile',
|
||||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
|
@ -340,7 +331,6 @@ ccc"`],
|
||||||
['pull', 'false'],
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
'--file', './test/Dockerfile',
|
'--file', './test/Dockerfile',
|
||||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
|
@ -378,7 +368,6 @@ ccc`],
|
||||||
['pull', 'false'],
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
'--file', './test/Dockerfile',
|
'--file', './test/Dockerfile',
|
||||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
|
@ -408,7 +397,6 @@ ccc`],
|
||||||
['pull', 'false'],
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
'--file', './test/Dockerfile',
|
'--file', './test/Dockerfile',
|
||||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
|
@ -432,7 +420,6 @@ ccc`],
|
||||||
['pull', 'false'],
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
'--label', 'org.opencontainers.image.title=filter_results_top_n',
|
'--label', 'org.opencontainers.image.title=filter_results_top_n',
|
||||||
'--label', 'org.opencontainers.image.description=Reference implementation of operation "filter results (top-n)"',
|
'--label', 'org.opencontainers.image.description=Reference implementation of operation "filter results (top-n)"',
|
||||||
|
@ -455,7 +442,6 @@ ccc`],
|
||||||
['pull', 'false'],
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
'--add-host', 'docker:10.180.0.1',
|
'--add-host', 'docker:10.180.0.1',
|
||||||
'--add-host', 'foo:10.0.0.1',
|
'--add-host', 'foo:10.0.0.1',
|
||||||
|
@ -484,7 +470,6 @@ nproc=3`],
|
||||||
['pull', 'false'],
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
'--add-host', 'docker:10.180.0.1',
|
'--add-host', 'docker:10.180.0.1',
|
||||||
'--add-host', 'foo:10.0.0.1',
|
'--add-host', 'foo:10.0.0.1',
|
||||||
|
@ -509,7 +494,6 @@ nproc=3`],
|
||||||
['pull', 'false'],
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
'--metadata-file', '/tmp/.docker-build-push-jest/metadata-file',
|
'--metadata-file', '/tmp/.docker-build-push-jest/metadata-file',
|
||||||
|
|
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
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
4
dist/index.js
generated
vendored
4
dist/index.js
generated
vendored
File diff suppressed because one or more lines are too long
2
dist/index.js.map
generated
vendored
2
dist/index.js.map
generated
vendored
File diff suppressed because one or more lines are too long
|
@ -107,9 +107,10 @@ export function hasGitAuthToken(secrets: string[]): boolean {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function isAvailable(): Promise<boolean> {
|
export async function isAvailable(standalone?: boolean): Promise<boolean> {
|
||||||
|
const cmd = getCommand([], standalone);
|
||||||
return await exec
|
return await exec
|
||||||
.getExecOutput('docker', ['buildx'], {
|
.getExecOutput(cmd.command, cmd.args, {
|
||||||
ignoreReturnCode: true,
|
ignoreReturnCode: true,
|
||||||
silent: true
|
silent: true
|
||||||
})
|
})
|
||||||
|
@ -118,12 +119,17 @@ export async function isAvailable(): Promise<boolean> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return res.exitCode == 0;
|
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
|
return await exec
|
||||||
.getExecOutput('docker', ['buildx', 'version'], {
|
.getExecOutput(cmd.command, cmd.args, {
|
||||||
ignoreReturnCode: true,
|
ignoreReturnCode: true,
|
||||||
silent: true
|
silent: true
|
||||||
})
|
})
|
||||||
|
@ -146,3 +152,10 @@ export function parseVersion(stdout: string): string {
|
||||||
export function satisfies(version: string, range: string): boolean {
|
export function satisfies(version: string, range: string): boolean {
|
||||||
return semver.satisfies(version, range) || /^[0-9a-f]{7}$/.exec(version) !== null;
|
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]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -101,7 +101,6 @@ 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>> {
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
return [
|
return [
|
||||||
'buildx',
|
|
||||||
...await getBuildArgs(inputs, defaultContext, buildxVersion),
|
...await getBuildArgs(inputs, defaultContext, buildxVersion),
|
||||||
...await getCommonArgs(inputs, buildxVersion),
|
...await getCommonArgs(inputs, buildxVersion),
|
||||||
handlebars.compile(inputs.context)({defaultContext})
|
handlebars.compile(inputs.context)({defaultContext})
|
||||||
|
|
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;
|
||||||
|
});
|
||||||
|
}
|
34
src/main.ts
34
src/main.ts
|
@ -1,30 +1,50 @@
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as buildx from './buildx';
|
import * as buildx from './buildx';
|
||||||
import * as context from './context';
|
import * as context from './context';
|
||||||
|
import * as docker from './docker';
|
||||||
import * as stateHelper from './state-helper';
|
import * as stateHelper from './state-helper';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import * as exec from '@actions/exec';
|
import * as exec from '@actions/exec';
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
try {
|
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`);
|
core.startGroup(`Docker info`);
|
||||||
await exec.exec('docker', ['version']);
|
if (standalone) {
|
||||||
await exec.exec('docker', ['info']);
|
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();
|
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.`);
|
core.setFailed(`Docker buildx is required. See https://github.com/docker/setup-buildx-action to set up buildx.`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
stateHelper.setTmpDir(context.tmpDir());
|
stateHelper.setTmpDir(context.tmpDir());
|
||||||
|
|
||||||
const buildxVersion = await buildx.getVersion();
|
const buildxVersion = await buildx.getVersion(standalone);
|
||||||
const defContext = context.defaultContext();
|
await core.group(`Buildx version`, async () => {
|
||||||
const inputs: context.Inputs = await context.getInputs(defContext);
|
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 args: string[] = await context.getArgs(inputs, defContext, buildxVersion);
|
||||||
|
const buildCmd = buildx.getCommand(args, standalone);
|
||||||
await exec
|
await exec
|
||||||
.getExecOutput('docker', args, {
|
.getExecOutput(buildCmd.command, buildCmd.args, {
|
||||||
ignoreReturnCode: true
|
ignoreReturnCode: true
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
|
|
Loading…
Reference in a new issue