mirror of
https://github.com/docker/build-push-action.git
synced 2026-04-03 11:14:17 +00:00
fix: resolve eStargz version check bug and add test coverage
- Move buildx version check before adding compression parameters to prevent build failures on older buildx versions - Add comprehensive unit tests for estargz feature with 8 test cases - Simplify redundant ternary operator logic - Rebuild dist files to fix CI verification Fixes the critical bug where compression parameters were added before version validation, causing unsupported parameter errors on buildx < 0.10.0
This commit is contained in:
parent
527d67c3c7
commit
4008f7467f
2
dist/index.js
generated
vendored
2
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
189
src/__tests__/estargz.test.ts
Normal file
189
src/__tests__/estargz.test.ts
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
import * as core from '@actions/core';
|
||||||
|
import {getArgs, Inputs} from '../context';
|
||||||
|
import {Toolkit} from '@docker/actions-toolkit/lib/toolkit';
|
||||||
|
|
||||||
|
jest.mock('@actions/core');
|
||||||
|
|
||||||
|
// Mock the Toolkit.
|
||||||
|
jest.mock('@docker/actions-toolkit/lib/toolkit');
|
||||||
|
|
||||||
|
describe('eStargz compression', () => {
|
||||||
|
let mockToolkit: jest.Mocked<Toolkit>;
|
||||||
|
let baseInputs: Inputs;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
|
||||||
|
// Create a mock toolkit with all necessary methods.
|
||||||
|
mockToolkit = {
|
||||||
|
buildx: {
|
||||||
|
versionSatisfies: jest.fn(),
|
||||||
|
getCommand: jest.fn(),
|
||||||
|
printVersion: jest.fn(),
|
||||||
|
isAvailable: jest.fn()
|
||||||
|
},
|
||||||
|
buildxBuild: {
|
||||||
|
getImageIDFilePath: jest.fn().mockReturnValue('/tmp/iidfile'),
|
||||||
|
getMetadataFilePath: jest.fn().mockReturnValue('/tmp/metadata'),
|
||||||
|
resolveImageID: jest.fn(),
|
||||||
|
resolveMetadata: jest.fn(),
|
||||||
|
resolveDigest: jest.fn(),
|
||||||
|
resolveWarnings: jest.fn(),
|
||||||
|
resolveRef: jest.fn()
|
||||||
|
},
|
||||||
|
builder: {
|
||||||
|
inspect: jest.fn().mockResolvedValue({
|
||||||
|
name: 'default',
|
||||||
|
driver: 'docker-container',
|
||||||
|
nodes: []
|
||||||
|
})
|
||||||
|
},
|
||||||
|
buildkit: {
|
||||||
|
versionSatisfies: jest.fn().mockResolvedValue(false)
|
||||||
|
}
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
// Base inputs for testing.
|
||||||
|
baseInputs = {
|
||||||
|
'add-hosts': [],
|
||||||
|
allow: [],
|
||||||
|
annotations: [],
|
||||||
|
attests: [],
|
||||||
|
'build-args': [],
|
||||||
|
'build-contexts': [],
|
||||||
|
builder: '',
|
||||||
|
'cache-from': [],
|
||||||
|
'cache-to': [],
|
||||||
|
'cgroup-parent': '',
|
||||||
|
context: '.',
|
||||||
|
file: '',
|
||||||
|
labels: [],
|
||||||
|
load: false,
|
||||||
|
network: '',
|
||||||
|
'no-cache': false,
|
||||||
|
'no-cache-filters': [],
|
||||||
|
outputs: [],
|
||||||
|
platforms: [],
|
||||||
|
provenance: '',
|
||||||
|
pull: false,
|
||||||
|
push: false,
|
||||||
|
sbom: '',
|
||||||
|
secrets: [],
|
||||||
|
'secret-envs': [],
|
||||||
|
'secret-files': [],
|
||||||
|
'shm-size': '',
|
||||||
|
ssh: [],
|
||||||
|
tags: ['user/app:latest'],
|
||||||
|
target: '',
|
||||||
|
ulimit: [],
|
||||||
|
'github-token': '',
|
||||||
|
estargz: false
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not add estargz parameters when estargz is false', async () => {
|
||||||
|
(mockToolkit.buildx.versionSatisfies as jest.Mock).mockResolvedValue(true);
|
||||||
|
|
||||||
|
const inputs = {...baseInputs, push: true, estargz: false};
|
||||||
|
const args = await getArgs(inputs, mockToolkit);
|
||||||
|
|
||||||
|
expect(args.join(' ')).not.toContain('compression=estargz');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not add estargz parameters when push is false', async () => {
|
||||||
|
(mockToolkit.buildx.versionSatisfies as jest.Mock).mockResolvedValue(true);
|
||||||
|
|
||||||
|
const inputs = {...baseInputs, push: false, estargz: true};
|
||||||
|
const args = await getArgs(inputs, mockToolkit);
|
||||||
|
|
||||||
|
expect(args.join(' ')).not.toContain('compression=estargz');
|
||||||
|
expect(core.warning).toHaveBeenCalledWith("eStargz compression requires push: true; the input 'estargz' is ignored.");
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not add estargz parameters when buildx version is < 0.10.0', async () => {
|
||||||
|
(mockToolkit.buildx.versionSatisfies as jest.Mock).mockImplementation(async (version: string) => {
|
||||||
|
return version === '>=0.6.0'; // Only 0.6.0 check passes, not 0.10.0.
|
||||||
|
});
|
||||||
|
|
||||||
|
const inputs = {...baseInputs, push: true, estargz: true};
|
||||||
|
const args = await getArgs(inputs, mockToolkit);
|
||||||
|
|
||||||
|
expect(args.join(' ')).not.toContain('compression=estargz');
|
||||||
|
expect(core.warning).toHaveBeenCalledWith("eStargz compression requires buildx >= 0.10.0; the input 'estargz' is ignored.");
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should add estargz output when estargz is true, push is true, and buildx >= 0.10.0', async () => {
|
||||||
|
(mockToolkit.buildx.versionSatisfies as jest.Mock).mockResolvedValue(true);
|
||||||
|
|
||||||
|
const inputs = {...baseInputs, push: true, estargz: true};
|
||||||
|
const args = await getArgs(inputs, mockToolkit);
|
||||||
|
|
||||||
|
expect(args).toContain('--output');
|
||||||
|
const outputIndex = args.indexOf('--output');
|
||||||
|
expect(args[outputIndex + 1]).toBe('type=registry,compression=estargz,force-compression=true,oci-mediatypes=true');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should modify existing registry output with estargz parameters', async () => {
|
||||||
|
(mockToolkit.buildx.versionSatisfies as jest.Mock).mockResolvedValue(true);
|
||||||
|
|
||||||
|
const inputs = {
|
||||||
|
...baseInputs,
|
||||||
|
push: true,
|
||||||
|
estargz: true,
|
||||||
|
outputs: ['type=registry,dest=output.txt']
|
||||||
|
};
|
||||||
|
const args = await getArgs(inputs, mockToolkit);
|
||||||
|
|
||||||
|
expect(args).toContain('--output');
|
||||||
|
const outputIndex = args.indexOf('--output');
|
||||||
|
expect(args[outputIndex + 1]).toBe('type=registry,dest=output.txt,compression=estargz,force-compression=true,oci-mediatypes=true');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not modify non-registry outputs with estargz parameters', async () => {
|
||||||
|
(mockToolkit.buildx.versionSatisfies as jest.Mock).mockResolvedValue(true);
|
||||||
|
|
||||||
|
const inputs = {
|
||||||
|
...baseInputs,
|
||||||
|
push: true,
|
||||||
|
estargz: true,
|
||||||
|
outputs: ['type=docker']
|
||||||
|
};
|
||||||
|
const args = await getArgs(inputs, mockToolkit);
|
||||||
|
|
||||||
|
expect(args).toContain('--output');
|
||||||
|
const outputIndex = args.indexOf('--output');
|
||||||
|
expect(args[outputIndex + 1]).toBe('type=docker');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle multiple outputs correctly', async () => {
|
||||||
|
(mockToolkit.buildx.versionSatisfies as jest.Mock).mockResolvedValue(true);
|
||||||
|
|
||||||
|
const inputs = {
|
||||||
|
...baseInputs,
|
||||||
|
push: true,
|
||||||
|
estargz: true,
|
||||||
|
outputs: ['type=registry', 'type=docker']
|
||||||
|
};
|
||||||
|
const args = await getArgs(inputs, mockToolkit);
|
||||||
|
|
||||||
|
const argsStr = args.join(' ');
|
||||||
|
expect(argsStr).toContain('type=registry,compression=estargz,force-compression=true,oci-mediatypes=true');
|
||||||
|
expect(argsStr).toContain('type=docker');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should work with existing registry output without additional params', async () => {
|
||||||
|
(mockToolkit.buildx.versionSatisfies as jest.Mock).mockResolvedValue(true);
|
||||||
|
|
||||||
|
const inputs = {
|
||||||
|
...baseInputs,
|
||||||
|
push: true,
|
||||||
|
estargz: true,
|
||||||
|
outputs: ['type=registry']
|
||||||
|
};
|
||||||
|
const args = await getArgs(inputs, mockToolkit);
|
||||||
|
|
||||||
|
expect(args).toContain('--output');
|
||||||
|
const outputIndex = args.indexOf('--output');
|
||||||
|
expect(args[outputIndex + 1]).toBe('type=registry,compression=estargz,force-compression=true,oci-mediatypes=true');
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -209,27 +209,10 @@ async function getBuildArgs(inputs: Inputs, context: string, toolkit: Toolkit):
|
|||||||
await Util.asyncForEach(inputs['no-cache-filters'], async noCacheFilter => {
|
await Util.asyncForEach(inputs['no-cache-filters'], async noCacheFilter => {
|
||||||
args.push('--no-cache-filter', noCacheFilter);
|
args.push('--no-cache-filter', noCacheFilter);
|
||||||
});
|
});
|
||||||
await Util.asyncForEach(inputs.outputs, async output => {
|
|
||||||
if (inputs.estargz && inputs.push) {
|
// Check estargz requirements BEFORE modifying outputs.
|
||||||
if (output.startsWith('type=registry') || output === 'type=registry') {
|
const useEstargz = inputs.estargz && inputs.push && (await toolkit.buildx.versionSatisfies('>=0.10.0'));
|
||||||
const estargzOutput = output.includes(',')
|
|
||||||
? `${output},compression=estargz,force-compression=true,oci-mediatypes=true`
|
|
||||||
: `${output},compression=estargz,force-compression=true,oci-mediatypes=true`;
|
|
||||||
args.push('--output', estargzOutput);
|
|
||||||
} else {
|
|
||||||
args.push('--output', output);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
args.push('--output', output);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (inputs.estargz && inputs.push && inputs.outputs.length === 0) {
|
|
||||||
args.push('--output', 'type=registry,compression=estargz,force-compression=true,oci-mediatypes=true');
|
|
||||||
}
|
|
||||||
if (inputs.platforms.length > 0) {
|
|
||||||
args.push('--platform', inputs.platforms.join(','));
|
|
||||||
}
|
|
||||||
if (inputs.estargz) {
|
if (inputs.estargz) {
|
||||||
if (!(await toolkit.buildx.versionSatisfies('>=0.10.0'))) {
|
if (!(await toolkit.buildx.versionSatisfies('>=0.10.0'))) {
|
||||||
core.warning("eStargz compression requires buildx >= 0.10.0; the input 'estargz' is ignored.");
|
core.warning("eStargz compression requires buildx >= 0.10.0; the input 'estargz' is ignored.");
|
||||||
@ -237,6 +220,22 @@ async function getBuildArgs(inputs: Inputs, context: string, toolkit: Toolkit):
|
|||||||
core.warning("eStargz compression requires push: true; the input 'estargz' is ignored.");
|
core.warning("eStargz compression requires push: true; the input 'estargz' is ignored.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await Util.asyncForEach(inputs.outputs, async output => {
|
||||||
|
if (useEstargz && (output.startsWith('type=registry') || output === 'type=registry')) {
|
||||||
|
const estargzOutput = `${output},compression=estargz,force-compression=true,oci-mediatypes=true`;
|
||||||
|
args.push('--output', estargzOutput);
|
||||||
|
} else {
|
||||||
|
args.push('--output', output);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (useEstargz && inputs.outputs.length === 0) {
|
||||||
|
args.push('--output', 'type=registry,compression=estargz,force-compression=true,oci-mediatypes=true');
|
||||||
|
}
|
||||||
|
if (inputs.platforms.length > 0) {
|
||||||
|
args.push('--platform', inputs.platforms.join(','));
|
||||||
|
}
|
||||||
if (await toolkit.buildx.versionSatisfies('>=0.10.0')) {
|
if (await toolkit.buildx.versionSatisfies('>=0.10.0')) {
|
||||||
args.push(...(await getAttestArgs(inputs, toolkit)));
|
args.push(...(await getAttestArgs(inputs, toolkit)));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user