Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,57 @@ jobs:
exit 1
fi

git-context-query:
runs-on: ubuntu-latest
env:
BUILDX_SEND_GIT_QUERY_AS_INPUT: true
services:
registry:
image: registry:2.8.3@sha256:a3d8aaa63ed8681a604f1dea0aa03f100d5895b6a58ace528858a7b332415373
ports:
- 5000:5000
steps:
-
name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
path: action
-
name: Set up QEMU
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
-
name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
with:
version: v0.29.0
driver-opts: |
network=host
image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }}
-
name: Build and push
id: docker_build
uses: ./action
with:
file: ./test/Dockerfile
builder: ${{ steps.buildx.outputs.name }}
platforms: linux/amd64,linux/arm64
push: true
tags: |
localhost:5000/name/app:latest
localhost:5000/name/app:1.0.0
-
name: Inspect
run: |
docker buildx imagetools inspect localhost:5000/name/app:1.0.0 --format '{{json .}}'
-
name: Check digest
run: |
if [ -z "${{ steps.docker_build.outputs.digest }}" ]; then
echo "::error::Digest should not be empty"
exit 1
fi

git-context-secret:
runs-on: ubuntu-latest
services:
Expand Down Expand Up @@ -394,6 +445,29 @@ jobs:
MYSECRET=foo
INVALID_SECRET=

secret-files:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
with:
version: ${{ inputs.buildx-version || env.BUILDX_VERSION }}
driver-opts: |
image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }}
-
name: Build
uses: ./
with:
context: .
file: ./test/secret.Dockerfile
secret-files: |
MYSECRET=./test/secret.txt
INVALID_SECRET=

secret-envs:
runs-on: ubuntu-latest
steps:
Expand Down
97 changes: 94 additions & 3 deletions __tests__/context.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import {Toolkit} from '@docker/actions-toolkit/lib/toolkit.js';

import {BuilderInfo} from '@docker/actions-toolkit/lib/types/buildx/builder.js';

import * as context from '../src/context.js';

const tmpDir = fs.mkdtempSync(path.join(process.env.TEMP || os.tmpdir(), 'context-'));
const tmpName = path.join(tmpDir, '.tmpname-vi');
const fixturesDir = path.join(__dirname, 'fixtures');
Expand Down Expand Up @@ -52,6 +50,53 @@ vi.spyOn(Builder.prototype, 'inspect').mockImplementation(async (): Promise<Buil
};
});

describe('getInputs', () => {
const originalEnv = process.env;

beforeEach(() => {
process.env = Object.keys(process.env).reduce((object, key) => {
if (!key.startsWith('INPUT_')) {
object[key] = process.env[key];
}
return object;
}, {});
});

afterEach(() => {
process.env = originalEnv;
});

function setRequiredBooleanInputs(): void {
setInput('load', 'false');
setInput('no-cache', 'false');
setInput('push', 'false');
setInput('pull', 'false');
}

test('uses Build git context when context input is empty', async () => {
const gitContext = 'https://github.com/docker/build-push-action.git?ref=refs/heads/master';
const gitContextSpy = vi.spyOn(Build.prototype, 'gitContext').mockResolvedValue(gitContext);
setRequiredBooleanInputs();
const context = await loadContextModule();
const inputs = await context.getInputs();
expect(inputs.context).toBe(gitContext);
expect(gitContextSpy).toHaveBeenCalledTimes(1);
gitContextSpy.mockRestore();
});

test('renders defaultContext templates from Build git context', async () => {
const gitContext = 'https://github.com/docker/build-push-action.git#refs/heads/master';
const gitContextSpy = vi.spyOn(Build.prototype, 'gitContext').mockResolvedValue(gitContext);
setRequiredBooleanInputs();
setInput('context', '{{defaultContext}}:subdir');
const context = await loadContextModule();
const inputs = await context.getInputs();
expect(inputs.context).toBe(`${gitContext}:subdir`);
expect(gitContextSpy).toHaveBeenCalledTimes(1);
gitContextSpy.mockRestore();
});
});

describe('getArgs', () => {
const originalEnv = process.env;
beforeEach(() => {
Expand Down Expand Up @@ -344,7 +389,7 @@ ccc`],
'build',
'--file', './test/Dockerfile',
'--iidfile', imageIDFilePath,
'--secret', `id=MY_SECRET,src=${tmpName}`,
'--secret', `id=MY_SECRET,src=${path.join(fixturesDir, 'secret.txt')}`,
'--builder', 'builder-git-context-2',
'--network', 'host',
'--push',
Expand Down Expand Up @@ -888,6 +933,46 @@ ANOTHER_SECRET=ANOTHER_SECRET_ENV`]
['GITHUB_SERVER_URL', 'https://github.cds.internal.unity3d.com'],
])
],
[
37,
'0.29.0',
new Map<string, string>([
['load', 'false'],
['no-cache', 'false'],
['push', 'false'],
['pull', 'false'],
]),
[
'build',
'--iidfile', imageIDFilePath,
'--attest', `type=provenance,mode=min,inline-only=true,builder-id=https://github.com/docker/build-push-action/actions/runs/123456789/attempts/1`,
'--metadata-file', metadataJson,
'https://github.com/docker/build-push-action.git?ref=refs/heads/master'
],
new Map<string, string>([
['BUILDX_SEND_GIT_QUERY_AS_INPUT', 'true']
])
],
[
38,
'0.28.0',
new Map<string, string>([
['load', 'false'],
['no-cache', 'false'],
['push', 'false'],
['pull', 'false'],
]),
[
'build',
'--iidfile', imageIDFilePath,
'--attest', `type=provenance,mode=min,inline-only=true,builder-id=https://github.com/docker/build-push-action/actions/runs/123456789/attempts/1`,
'--metadata-file', metadataJson,
'https://github.com/docker/build-push-action.git#refs/heads/master'
],
new Map<string, string>([
['BUILDX_SEND_GIT_QUERY_AS_INPUT', 'true']
])
],
])(
'[%d] given %o with %o as inputs, returns %o',
async (num: number, buildxVersion: string, inputs: Map<string, string>, expected: Array<string>, envs: Map<string, string> | undefined) => {
Expand All @@ -903,6 +988,7 @@ ANOTHER_SECRET=ANOTHER_SECRET_ENV`]
vi.spyOn(Buildx.prototype, 'version').mockImplementation(async (): Promise<string> => {
return buildxVersion;
});
const context = await loadContextModule();
const inp = await context.getInputs();
const res = await context.getArgs(inp, toolkit);
expect(res).toEqual(expected);
Expand All @@ -918,3 +1004,8 @@ function getInputName(name: string): string {
function setInput(name: string, value: string): void {
process.env[getInputName(name)] = value;
}

async function loadContextModule(): Promise<typeof import('../src/context.js')> {
vi.resetModules();
return await import('../src/context.js');
}
45 changes: 29 additions & 16 deletions dist/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"packageManager": "yarn@4.9.2",
"dependencies": {
"@actions/core": "^3.0.0",
"@docker/actions-toolkit": "0.79.0",
"@docker/actions-toolkit": "0.86.0",
"handlebars": "^4.7.9"
},
"devDependencies": {
Expand Down
24 changes: 15 additions & 9 deletions src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@ import * as core from '@actions/core';
import * as handlebars from 'handlebars';

import {Build} from '@docker/actions-toolkit/lib/buildx/build.js';
import {Context} from '@docker/actions-toolkit/lib/context.js';
import {GitHub} from '@docker/actions-toolkit/lib/github/github.js';
import {Toolkit} from '@docker/actions-toolkit/lib/toolkit.js';
import {Util} from '@docker/actions-toolkit/lib/util.js';

let defaultContextPromise: Promise<string> | undefined;

async function getDefaultContext(): Promise<string> {
defaultContextPromise ??= new Build().gitContext();
return await defaultContextPromise;
}

export interface Inputs {
'add-hosts': string[];
allow: string[];
Expand Down Expand Up @@ -44,6 +50,7 @@ export interface Inputs {
}

export async function getInputs(): Promise<Inputs> {
const defaultContext = await getDefaultContext();
return {
'add-hosts': Util.getInputList('add-hosts'),
allow: Util.getInputList('allow'),
Expand All @@ -56,7 +63,7 @@ export async function getInputs(): Promise<Inputs> {
'cache-to': Util.getInputList('cache-to', {ignoreComma: true}),
call: core.getInput('call'),
'cgroup-parent': core.getInput('cgroup-parent'),
context: core.getInput('context') || Context.gitContext(),
context: handlebars.compile(core.getInput('context'))({defaultContext}) || defaultContext,
file: core.getInput('file'),
labels: Util.getInputList('labels', {ignoreComma: true}),
load: core.getBooleanInput('load'),
Expand All @@ -82,18 +89,17 @@ export async function getInputs(): Promise<Inputs> {
}

export async function getArgs(inputs: Inputs, toolkit: Toolkit): Promise<Array<string>> {
const context = handlebars.compile(inputs.context)({
defaultContext: Context.gitContext()
});
// prettier-ignore
return [
...await getBuildArgs(inputs, context, toolkit),
...await getBuildArgs(inputs, inputs.context, toolkit),
...await getCommonArgs(inputs, toolkit),
context
inputs.context
];
}

async function getBuildArgs(inputs: Inputs, context: string, toolkit: Toolkit): Promise<Array<string>> {
const defaultContext = await getDefaultContext();

const args: Array<string> = ['build'];
await Util.asyncForEach(inputs['add-hosts'], async addHost => {
args.push('--add-host', addHost);
Expand All @@ -116,7 +122,7 @@ async function getBuildArgs(inputs: Inputs, context: string, toolkit: Toolkit):
args.push(
'--build-context',
handlebars.compile(buildContext)({
defaultContext: Context.gitContext()
defaultContext: defaultContext
})
);
});
Expand Down Expand Up @@ -182,7 +188,7 @@ async function getBuildArgs(inputs: Inputs, context: string, toolkit: Toolkit):
core.warning(err.message);
}
});
if (inputs['github-token'] && !Build.hasGitAuthTokenSecret(inputs.secrets) && context.startsWith(Context.gitContext())) {
if (inputs['github-token'] && !Build.hasGitAuthTokenSecret(inputs.secrets) && context.startsWith(defaultContext)) {
args.push('--secret', Build.resolveSecretString(`GIT_AUTH_TOKEN.${new URL(GitHub.serverURL).host.trimEnd()}=${inputs['github-token']}`));
}
if (inputs['shm-size']) {
Expand Down
1 change: 1 addition & 0 deletions test/secret.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
foo
Loading
Loading