refactor: use new gitContext for build context resolution

Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
This commit is contained in:
CrazyMax 2026-04-01 14:46:23 +02:00
parent 6cc04c1209
commit 3b7fd34174
No known key found for this signature in database
GPG key ID: ADE44D8C9D44FBE4
3 changed files with 159 additions and 11 deletions

View file

@ -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:

View file

@ -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');
@ -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(() => {
@ -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) => {
@ -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);
@ -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');
}

View file

@ -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[];
@ -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'),
@ -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'),
@ -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);
@ -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
})
);
});
@ -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']) {