Merge pull request #2301 from balena-io/add-multiarch-handling

Add multiarch support
This commit is contained in:
bulldozer-balena[bot] 2021-09-23 20:54:51 +00:00 committed by GitHub
commit b42af74983
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 235 additions and 32 deletions

View File

@ -1051,9 +1051,7 @@ export async function makeBuildTasks(
infoStr = `build [${task.context}]`; infoStr = `build [${task.context}]`;
} }
logger.logDebug(` ${task.serviceName}: ${infoStr}`); logger.logDebug(` ${task.serviceName}: ${infoStr}`);
// Workaround for Docker v20.10 + single-arch base images. See: task.logger = logger.getAdapter();
// https://www.flowdock.com/app/rulemotion/i-cli/threads/RuSu1KiWOn62xaGy7O2sn8m8BUc
task.dockerPlatform = 'none';
}); });
logger.logDebug( logger.logDebug(

View File

@ -30,6 +30,14 @@ enum Level {
LIVEPUSH = 'livepush', LIVEPUSH = 'livepush',
} }
interface LoggerAdapter {
debug: (msg: string) => void;
error: (msg: string) => void;
info: (msg: string) => void;
log: (msg: string) => void;
warn: (msg: string) => void;
}
/** /**
* General purpose logger class with support for log streams and colours. * General purpose logger class with support for log streams and colours.
* Call `Logger.getLogger()` to retrieve a global shared instance of this * Call `Logger.getLogger()` to retrieve a global shared instance of this
@ -57,6 +65,8 @@ class Logger {
protected deferredLogMessages: Array<[string, Level]>; protected deferredLogMessages: Array<[string, Level]>;
protected adapter: LoggerAdapter;
protected constructor() { protected constructor() {
const logger = new StreamLogger(); const logger = new StreamLogger();
const chalk = getChalk(); const chalk = getChalk();
@ -91,6 +101,14 @@ class Logger {
this.formatMessage = logger.formatWithPrefix.bind(logger); this.formatMessage = logger.formatWithPrefix.bind(logger);
this.deferredLogMessages = []; this.deferredLogMessages = [];
this.adapter = {
debug: (msg: string) => this.logDebug(msg),
error: (msg: string) => this.logError(msg),
info: (msg: string) => this.logInfo(msg),
log: (msg: string) => this.logLogs(msg),
warn: (msg: string) => this.logWarn(msg),
};
} }
protected static logger: Logger; protected static logger: Logger;
@ -151,6 +169,10 @@ class Logger {
}); });
this.deferredLogMessages = []; this.deferredLogMessages = [];
} }
public getAdapter(): LoggerAdapter {
return this.adapter;
}
} }
export = Logger; export = Logger;

35
npm-shrinkwrap.json generated
View File

@ -6497,6 +6497,14 @@
} }
} }
}, },
"dockerfile-ast": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/dockerfile-ast/-/dockerfile-ast-0.2.1.tgz",
"integrity": "sha512-ut04CVM1G6zIITTcYPDIXhPZk9mCa21m4dfW8FcDDGxwgTQhYyHDu6U7M8klZ7QsjqVcJhryKi+TGOX6bjgKdQ==",
"requires": {
"vscode-languageserver-types": "^3.16.0"
}
},
"dockerfile-template": { "dockerfile-template": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/dockerfile-template/-/dockerfile-template-0.2.0.tgz", "resolved": "https://registry.npmjs.org/dockerfile-template/-/dockerfile-template-0.2.0.tgz",
@ -8202,9 +8210,9 @@
"integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
}, },
"fp-ts": { "fp-ts": {
"version": "2.10.5", "version": "2.11.3",
"resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.10.5.tgz", "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.11.3.tgz",
"integrity": "sha512-X2KfTIV0cxIk3d7/2Pvp/pxL/xr2MV1WooyEzKtTWYSc1+52VF4YzjBTXqeOlSiZsPCxIBpDGfT9Dyo7WEY0DQ==" "integrity": "sha512-qHI5iaVSFNFmdl6yDensWfFMk32iafAINCnqx8m486DV1+Jht/bTnA9CyahL+Xm7h2y3erinviVBIAWvv5bPYw=="
}, },
"fragment-cache": { "fragment-cache": {
"version": "0.2.1", "version": "0.2.1",
@ -15556,9 +15564,12 @@
} }
}, },
"@types/klaw": { "@types/klaw": {
"version": "1.3.5", "version": "1.3.6",
"resolved": "https://registry.npmjs.org/@types/klaw/-/klaw-1.3.5.tgz", "resolved": "https://registry.npmjs.org/@types/klaw/-/klaw-1.3.6.tgz",
"integrity": "sha512-KZfv4ea6bEbdQhfwpxtDuTPO2mHAAXMQqPOZyS4MgNyCymKoLHp0FVzzYq3H2zCeIotN4h1453TahLCCm8rf2w==" "integrity": "sha512-4pr2RxwhfsLxFYa4Ip8JxrdXIvPX7fAqyBh9ofZPedMwf8M5CIcSQskqvX6/5Y/zpCBHtuC3218t8H+XJsg5FA==",
"requires": {
"@types/node": "*"
}
}, },
"bl": { "bl": {
"version": "1.2.3", "version": "1.2.3",
@ -15755,13 +15766,14 @@
} }
}, },
"resin-multibuild": { "resin-multibuild": {
"version": "4.11.0", "version": "4.12.2",
"resolved": "https://registry.npmjs.org/resin-multibuild/-/resin-multibuild-4.11.0.tgz", "resolved": "https://registry.npmjs.org/resin-multibuild/-/resin-multibuild-4.12.2.tgz",
"integrity": "sha512-rIYV9GDNuI8pU9N+wGdVRIOGAnw1BFdbyt3BkvERFxbf+b/e7jpBjHkbK8VPQdRMlKPyu137ZxQlR3z7EivJBg==", "integrity": "sha512-FkRqGEM588wA6v03pQbodPqWQdAs6aMh+GWvYQBz5IxqSVecn4FLHaRE0pF6VFKtjf/XBuPw7dtqiFzH+NIz5g==",
"requires": { "requires": {
"ajv": "^6.12.3", "ajv": "^6.12.3",
"bluebird": "^3.7.2", "bluebird": "^3.7.2",
"docker-progress": "^5.0.0", "docker-progress": "^5.0.0",
"dockerfile-ast": "^0.2.1",
"dockerfile-template": "^0.2.0", "dockerfile-template": "^0.2.0",
"dockerode": "^2.5.8", "dockerode": "^2.5.8",
"fp-ts": "^2.8.1", "fp-ts": "^2.8.1",
@ -18527,6 +18539,11 @@
} }
} }
}, },
"vscode-languageserver-types": {
"version": "3.16.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz",
"integrity": "sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA=="
},
"wcwidth": { "wcwidth": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",

View File

@ -66,6 +66,7 @@
"test:standalone": "npm run build:standalone && npm run test:standalone:fast", "test:standalone": "npm run build:standalone && npm run test:standalone:fast",
"test:standalone:fast": "cross-env BALENA_CLI_TEST_TYPE=standalone mocha --config .mocharc-standalone.js", "test:standalone:fast": "cross-env BALENA_CLI_TEST_TYPE=standalone mocha --config .mocharc-standalone.js",
"test:fast": "npm run build:fast && npm run test:source", "test:fast": "npm run build:fast && npm run test:source",
"test:debug": "cross-env BALENA_CLI_TEST_TYPE=source mocha --inspect-brk=0.0.0.0",
"test:only": "npm run build:fast && cross-env BALENA_CLI_TEST_TYPE=source mocha \"tests/**/${npm_config_test}.spec.ts\"", "test:only": "npm run build:fast && cross-env BALENA_CLI_TEST_TYPE=source mocha \"tests/**/${npm_config_test}.spec.ts\"",
"catch-uncommitted": "ts-node --transpile-only automation/run.ts catch-uncommitted", "catch-uncommitted": "ts-node --transpile-only automation/run.ts catch-uncommitted",
"ci": "npm run test && npm run catch-uncommitted", "ci": "npm run test && npm run catch-uncommitted",
@ -267,7 +268,7 @@
"resin-cli-visuals": "^1.8.0", "resin-cli-visuals": "^1.8.0",
"resin-compose-parse": "^2.1.3", "resin-compose-parse": "^2.1.3",
"resin-doodles": "^0.1.1", "resin-doodles": "^0.1.1",
"resin-multibuild": "^4.11.0", "resin-multibuild": "4.12.2",
"resin-stream-logger": "^0.1.2", "resin-stream-logger": "^0.1.2",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"semver": "^7.3.2", "semver": "^7.3.2",

View File

@ -53,6 +53,16 @@ const commonQueryParams = {
labels: '', labels: '',
}; };
const commonQueryParamsIntel = {
...commonQueryParams,
platform: 'linux/amd64',
};
const commonQueryParamsArmV6 = {
...commonQueryParams,
platform: 'linux/arm/v6',
};
const commonComposeQueryParams = { const commonComposeQueryParams = {
t: '${tag}', t: '${tag}',
buildargs: { buildargs: {
@ -62,6 +72,11 @@ const commonComposeQueryParams = {
labels: '', labels: '',
}; };
const commonComposeQueryParamsIntel = {
...commonComposeQueryParams,
platform: 'linux/amd64',
};
// "itSS" means "it() Skip Standalone" // "itSS" means "it() Skip Standalone"
const itSS = process.env.BALENA_CLI_TEST_TYPE === 'standalone' ? it.skip : it; const itSS = process.env.BALENA_CLI_TEST_TYPE === 'standalone' ? it.skip : it;
@ -76,7 +91,7 @@ describe('balena build', function () {
api.expectGetWhoAmI({ optional: true, persist: true }); api.expectGetWhoAmI({ optional: true, persist: true });
api.expectGetMixpanel({ optional: true }); api.expectGetMixpanel({ optional: true });
docker.expectGetPing(); docker.expectGetPing();
docker.expectGetVersion(); docker.expectGetVersion({ persist: true });
}); });
this.afterEach(() => { this.afterEach(() => {
@ -123,13 +138,16 @@ describe('balena build', function () {
} }
} }
docker.expectGetInfo({}); docker.expectGetInfo({});
docker.expectGetManifestBusybox();
await testDockerBuildStream({ await testDockerBuildStream({
commandLine: `build ${projectPath} --deviceType nuc --arch amd64 ${ commandLine: `build ${projectPath} --deviceType nuc --arch amd64 ${
isV13() ? '' : '-g' isV13() ? '' : '-g'
}`, }`,
dockerMock: docker, dockerMock: docker,
expectedFilesByService: { main: expectedFiles }, expectedFilesByService: { main: expectedFiles },
expectedQueryParamsByService: { main: Object.entries(commonQueryParams) }, expectedQueryParamsByService: {
main: Object.entries(commonQueryParamsIntel),
},
expectedResponseLines, expectedResponseLines,
projectPath, projectPath,
responseBody, responseBody,
@ -152,7 +170,7 @@ describe('balena build', function () {
'Dockerfile-alt': { fileSize: 30, type: 'file' }, 'Dockerfile-alt': { fileSize: 30, type: 'file' },
}; };
const expectedQueryParams = { const expectedQueryParams = {
...commonQueryParams, ...commonQueryParamsIntel,
buildargs: '{"BARG1":"b1","barg2":"B2"}', buildargs: '{"BARG1":"b1","barg2":"B2"}',
cachefrom: '["my/img1","my/img2"]', cachefrom: '["my/img1","my/img2"]',
}; };
@ -181,6 +199,7 @@ describe('balena build', function () {
} }
} }
docker.expectGetInfo({}); docker.expectGetInfo({});
docker.expectGetManifestBusybox();
await testDockerBuildStream({ await testDockerBuildStream({
commandLine: `build ${projectPath} --deviceType nuc --arch amd64 -B BARG1=b1 -B barg2=B2 --cache-from my/img1,my/img2`, commandLine: `build ${projectPath} --deviceType nuc --arch amd64 -B BARG1=b1 -B barg2=B2 --cache-from my/img1,my/img2`,
dockerMock: docker, dockerMock: docker,
@ -271,6 +290,7 @@ describe('balena build', function () {
}); });
mock.reRequire('../../build/utils/qemu'); mock.reRequire('../../build/utils/qemu');
docker.expectGetInfo({ OperatingSystem: 'balenaOS 2.44.0+rev1' }); docker.expectGetInfo({ OperatingSystem: 'balenaOS 2.44.0+rev1' });
docker.expectGetManifestBusybox();
await testDockerBuildStream({ await testDockerBuildStream({
commandLine: `build ${projectPath} --emulated --deviceType ${deviceType} --arch ${arch} ${ commandLine: `build ${projectPath} --emulated --deviceType ${deviceType} --arch ${arch} ${
isV13() ? '' : '--nogitignore' isV13() ? '' : '--nogitignore'
@ -278,7 +298,7 @@ describe('balena build', function () {
dockerMock: docker, dockerMock: docker,
expectedFilesByService: { main: expectedFiles }, expectedFilesByService: { main: expectedFiles },
expectedQueryParamsByService: { expectedQueryParamsByService: {
main: Object.entries(commonQueryParams), main: Object.entries(commonQueryParamsArmV6),
}, },
expectedResponseLines, expectedResponseLines,
projectPath, projectPath,
@ -327,11 +347,15 @@ describe('balena build', function () {
); );
} }
docker.expectGetInfo({}); docker.expectGetInfo({});
docker.expectGetManifestBusybox();
await testDockerBuildStream({ await testDockerBuildStream({
commandLine: `build ${projectPath} --deviceType nuc --arch amd64 --noconvert-eol -m`, commandLine: `build ${projectPath} --deviceType nuc --arch amd64 --noconvert-eol -m`,
dockerMock: docker, dockerMock: docker,
expectedFilesByService: { main: expectedFiles }, expectedFilesByService: { main: expectedFiles },
expectedQueryParamsByService: { main: Object.entries(commonQueryParams) }, expectedQueryParamsByService: {
main: Object.entries(commonQueryParamsIntel),
},
expectedResponseLines, expectedResponseLines,
projectPath, projectPath,
responseBody, responseBody,
@ -360,7 +384,7 @@ describe('balena build', function () {
}, },
service2: { service2: {
'.dockerignore': { fileSize: 12, type: 'file' }, '.dockerignore': { fileSize: 12, type: 'file' },
'Dockerfile-alt': { fileSize: 40, type: 'file' }, 'Dockerfile-alt': { fileSize: 13, type: 'file' },
'file2-crlf.sh': { 'file2-crlf.sh': {
fileSize: isWindows ? 12 : 14, fileSize: isWindows ? 12 : 14,
testStream: isWindows ? expectStreamNoCRLF : undefined, testStream: isWindows ? expectStreamNoCRLF : undefined,
@ -386,7 +410,7 @@ describe('balena build', function () {
}), }),
), ),
service2: Object.entries( service2: Object.entries(
_.merge({}, commonComposeQueryParams, { _.merge({}, commonComposeQueryParamsIntel, {
buildargs: { buildargs: {
COMPOSE_ARG: 'A', COMPOSE_ARG: 'A',
barg: 'b', barg: 'b',
@ -417,6 +441,8 @@ describe('balena build', function () {
); );
} }
docker.expectGetInfo({}); docker.expectGetInfo({});
docker.expectGetManifestNucAlpine();
docker.expectGetManifestBusybox();
await testDockerBuildStream({ await testDockerBuildStream({
commandLine: `build ${projectPath} --deviceType nuc --arch amd64 --convert-eol ${ commandLine: `build ${projectPath} --deviceType nuc --arch amd64 --convert-eol ${
isV13() ? '' : '-G' isV13() ? '' : '-G'
@ -453,7 +479,7 @@ describe('balena build', function () {
}, },
service2: { service2: {
'.dockerignore': { fileSize: 12, type: 'file' }, '.dockerignore': { fileSize: 12, type: 'file' },
'Dockerfile-alt': { fileSize: 40, type: 'file' }, 'Dockerfile-alt': { fileSize: 13, type: 'file' },
'file2-crlf.sh': { 'file2-crlf.sh': {
fileSize: isWindows ? 12 : 14, fileSize: isWindows ? 12 : 14,
testStream: isWindows ? expectStreamNoCRLF : undefined, testStream: isWindows ? expectStreamNoCRLF : undefined,
@ -473,7 +499,7 @@ describe('balena build', function () {
}), }),
), ),
service2: Object.entries( service2: Object.entries(
_.merge({}, commonComposeQueryParams, { _.merge({}, commonComposeQueryParamsIntel, {
buildargs: { buildargs: {
COMPOSE_ARG: 'an argument defined in the docker-compose.yml file', COMPOSE_ARG: 'an argument defined in the docker-compose.yml file',
}, },
@ -505,6 +531,9 @@ describe('balena build', function () {
); );
} }
docker.expectGetInfo({}); docker.expectGetInfo({});
docker.expectGetManifestBusybox();
docker.expectGetManifestNucAlpine();
await testDockerBuildStream({ await testDockerBuildStream({
commandLine: `build ${projectPath} --deviceType nuc --arch amd64 --convert-eol -m`, commandLine: `build ${projectPath} --deviceType nuc --arch amd64 --convert-eol -m`,
dockerMock: docker, dockerMock: docker,
@ -539,7 +568,7 @@ describe('balena build', function () {
}, },
service2: { service2: {
'.dockerignore': { fileSize: 12, type: 'file' }, '.dockerignore': { fileSize: 12, type: 'file' },
'Dockerfile-alt': { fileSize: 40, type: 'file' }, 'Dockerfile-alt': { fileSize: 13, type: 'file' },
'file2-crlf.sh': { 'file2-crlf.sh': {
fileSize: isWindows ? 12 : 14, fileSize: isWindows ? 12 : 14,
testStream: isWindows ? expectStreamNoCRLF : undefined, testStream: isWindows ? expectStreamNoCRLF : undefined,
@ -559,7 +588,7 @@ describe('balena build', function () {
}), }),
), ),
service2: Object.entries( service2: Object.entries(
_.merge({}, commonComposeQueryParams, { _.merge({}, commonComposeQueryParamsIntel, {
buildargs: { buildargs: {
COMPOSE_ARG: 'an argument defined in the docker-compose.yml file', COMPOSE_ARG: 'an argument defined in the docker-compose.yml file',
}, },
@ -593,6 +622,9 @@ describe('balena build', function () {
const projectName = 'spectest'; const projectName = 'spectest';
const tag = 'myTag'; const tag = 'myTag';
docker.expectGetInfo({}); docker.expectGetInfo({});
docker.expectGetManifestBusybox();
docker.expectGetManifestNucAlpine();
await testDockerBuildStream({ await testDockerBuildStream({
commandLine: `build ${projectPath} --deviceType nuc --arch amd64 --convert-eol -m --tag ${tag} --projectName ${projectName}`, commandLine: `build ${projectPath} --deviceType nuc --arch amd64 --convert-eol -m --tag ${tag} --projectName ${projectName}`,
dockerMock: docker, dockerMock: docker,

View File

@ -53,6 +53,7 @@ const commonResponseLines = {
}; };
const commonQueryParams = [ const commonQueryParams = [
['platform', 'linux/arm/v7'],
['t', '${tag}'], ['t', '${tag}'],
['buildargs', '{}'], ['buildargs', '{}'],
['labels', ''], ['labels', ''],
@ -67,6 +68,11 @@ const commonComposeQueryParams = {
labels: '', labels: '',
}; };
const commonComposeQueryParamsArmV7 = {
...commonComposeQueryParams,
platform: 'linux/arm/v7',
};
describe('balena deploy', function () { describe('balena deploy', function () {
let api: BalenaAPIMock; let api: BalenaAPIMock;
let docker: DockerMock; let docker: DockerMock;
@ -139,6 +145,7 @@ describe('balena deploy', function () {
api.expectPatchImage({}); api.expectPatchImage({});
api.expectPatchRelease({}); api.expectPatchRelease({});
api.expectPostImageLabel(); api.expectPostImageLabel();
docker.expectGetManifestBusybox();
await testDockerBuildStream({ await testDockerBuildStream({
commandLine: `deploy testApp --build --source ${projectPath} ${ commandLine: `deploy testApp --build --source ${projectPath} ${
@ -189,6 +196,7 @@ describe('balena deploy', function () {
api.expectPatchImage({}); api.expectPatchImage({});
api.expectPatchRelease({}); api.expectPatchRelease({});
api.expectPostImageLabel(); api.expectPostImageLabel();
docker.expectGetManifestBusybox();
await testDockerBuildStream({ await testDockerBuildStream({
commandLine: `deploy testApp --build --source ${projectPath}`, commandLine: `deploy testApp --build --source ${projectPath}`,
@ -238,6 +246,7 @@ describe('balena deploy', function () {
api.expectPatchImage({}); api.expectPatchImage({});
api.expectPatchRelease({}); api.expectPatchRelease({});
api.expectPostImageLabel(); api.expectPostImageLabel();
docker.expectGetManifestBusybox();
await testDockerBuildStream({ await testDockerBuildStream({
commandLine: `deploy testApp --build --draft --source ${projectPath}`, commandLine: `deploy testApp --build --draft --source ${projectPath}`,
@ -275,6 +284,7 @@ describe('balena deploy', function () {
const expectedExitCode = 1; const expectedExitCode = 1;
api.expectPostRelease({}); api.expectPostRelease({});
docker.expectGetManifestBusybox();
// Mock this patch HTTP request to return status code 500, in which case // Mock this patch HTTP request to return status code 500, in which case
// the release status should be saved as "failed" rather than "success" // the release status should be saved as "failed" rather than "success"
@ -352,7 +362,7 @@ describe('balena deploy', function () {
}, },
service2: { service2: {
'.dockerignore': { fileSize: 12, type: 'file' }, '.dockerignore': { fileSize: 12, type: 'file' },
'Dockerfile-alt': { fileSize: 40, type: 'file' }, 'Dockerfile-alt': { fileSize: 13, type: 'file' },
'file2-crlf.sh': { 'file2-crlf.sh': {
fileSize: isWindows ? 12 : 14, fileSize: isWindows ? 12 : 14,
testStream: isWindows ? expectStreamNoCRLF : undefined, testStream: isWindows ? expectStreamNoCRLF : undefined,
@ -372,7 +382,7 @@ describe('balena deploy', function () {
}), }),
), ),
service2: Object.entries( service2: Object.entries(
_.merge({}, commonComposeQueryParams, { _.merge({}, commonComposeQueryParamsArmV7, {
buildargs: { buildargs: {
COMPOSE_ARG: 'an argument defined in the docker-compose.yml file', COMPOSE_ARG: 'an argument defined in the docker-compose.yml file',
}, },
@ -407,6 +417,8 @@ describe('balena deploy', function () {
api.expectPostRelease({}); api.expectPostRelease({});
api.expectPatchImage({}); api.expectPatchImage({});
api.expectPatchRelease({}); api.expectPatchRelease({});
docker.expectGetManifestRpi3Alpine();
docker.expectGetManifestBusybox();
await testDockerBuildStream({ await testDockerBuildStream({
commandLine: `deploy testApp --build --source ${projectPath} --multi-dockerignore`, commandLine: `deploy testApp --build --source ${projectPath} --multi-dockerignore`,

View File

@ -455,7 +455,7 @@ describe('balena push', function () {
'docker-compose.yml': { fileSize: 332, type: 'file' }, 'docker-compose.yml': { fileSize: 332, type: 'file' },
'service1/Dockerfile.template': { fileSize: 144, type: 'file' }, 'service1/Dockerfile.template': { fileSize: 144, type: 'file' },
'service1/file1.sh': { fileSize: 12, type: 'file' }, 'service1/file1.sh': { fileSize: 12, type: 'file' },
'service2/Dockerfile-alt': { fileSize: 40, type: 'file' }, 'service2/Dockerfile-alt': { fileSize: 13, type: 'file' },
'service2/.dockerignore': { fileSize: 12, type: 'file' }, 'service2/.dockerignore': { fileSize: 12, type: 'file' },
'service2/file2-crlf.sh': { 'service2/file2-crlf.sh': {
fileSize: isWindows ? 12 : 14, fileSize: isWindows ? 12 : 14,
@ -508,7 +508,7 @@ describe('balena push', function () {
'service1/Dockerfile.template': { fileSize: 144, type: 'file' }, 'service1/Dockerfile.template': { fileSize: 144, type: 'file' },
'service1/file1.sh': { fileSize: 12, type: 'file' }, 'service1/file1.sh': { fileSize: 12, type: 'file' },
'service1/test-ignore.txt': { fileSize: 12, type: 'file' }, 'service1/test-ignore.txt': { fileSize: 12, type: 'file' },
'service2/Dockerfile-alt': { fileSize: 40, type: 'file' }, 'service2/Dockerfile-alt': { fileSize: 13, type: 'file' },
'service2/.dockerignore': { fileSize: 12, type: 'file' }, 'service2/.dockerignore': { fileSize: 12, type: 'file' },
'service2/file2-crlf.sh': { 'service2/file2-crlf.sh': {
fileSize: isWindows ? 12 : 14, fileSize: isWindows ? 12 : 14,

View File

@ -198,7 +198,7 @@ export async function testDockerBuildStream(o: {
tag, tag,
}); });
if (o.commandLine.startsWith('build')) { if (o.commandLine.startsWith('build')) {
o.dockerMock.expectGetImages(); o.dockerMock.expectGetImages({ optional: true });
} }
} }

View File

@ -133,4 +133,42 @@ export class DockerMock extends NockMock {
}, },
); );
} }
public expectGetManifestBusybox(opts: ScopeOpts = {}) {
// this.optGet(/^\/distribution\/.*/, opts).replyWithFile(
this.optGet('/distribution/busybox/json', opts).replyWithFile(
200,
path.join(dockerResponsePath, 'distribution-busybox-GET.json'),
{
'api-version': '1.38',
'Content-Type': 'application/json',
},
);
}
public expectGetManifestRpi3Alpine(opts: ScopeOpts = {}) {
this.optGet(
'/distribution/balenalib/raspberrypi3-alpine/json',
opts,
).replyWithFile(
200,
path.join(dockerResponsePath, 'distribution-rpi3alpine.json'),
{
'api-version': '1.38',
'Content-Type': 'application/json',
},
);
}
public expectGetManifestNucAlpine(opts: ScopeOpts = {}) {
// NOTE: This URL does no work in real life... it's "intel-nuc", not "nuc"
this.optGet('/distribution/balenalib/nuc-alpine/json', opts).replyWithFile(
200,
path.join(dockerResponsePath, 'distribution-nucalpine.json'),
{
'api-version': '1.38',
'Content-Type': 'application/json',
},
);
}
} }

View File

@ -33,7 +33,10 @@ export class NockMock {
public readonly expect; public readonly expect;
protected static instanceCount = 0; protected static instanceCount = 0;
constructor(public basePathPattern: string | RegExp) { constructor(
public basePathPattern: string | RegExp,
public allowUnmocked: boolean = false,
) {
if (NockMock.instanceCount === 0) { if (NockMock.instanceCount === 0) {
if (!nock.isActive()) { if (!nock.isActive()) {
nock.activate(); nock.activate();
@ -45,7 +48,7 @@ export class NockMock {
); );
} }
NockMock.instanceCount += 1; NockMock.instanceCount += 1;
this.scope = nock(this.basePathPattern); this.scope = nock(this.basePathPattern, { allowUnmocked });
this.expect = this.scope; this.expect = this.scope;
} }

View File

@ -0,0 +1,53 @@
{
"Descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
"digest": "sha256:52f73a0a43a16cf37cd0720c90887ce972fe60ee06a687ee71fb93a7ca601df7",
"size": 2295
},
"Platforms": [
{
"architecture": "amd64",
"os": "linux"
},
{
"architecture": "arm",
"os": "linux",
"variant": "v5"
},
{
"architecture": "arm",
"os": "linux",
"variant": "v6"
},
{
"architecture": "arm",
"os": "linux",
"variant": "v7"
},
{
"architecture": "arm64",
"os": "linux",
"variant": "v8"
},
{
"architecture": "386",
"os": "linux"
},
{
"architecture": "mips64le",
"os": "linux"
},
{
"architecture": "ppc64le",
"os": "linux"
},
{
"architecture": "riscv64",
"os": "linux"
},
{
"architecture": "s390x",
"os": "linux"
}
]
}

View File

@ -0,0 +1,13 @@
{
"Descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:d70bb0dd863198b41ea5d638993a9fbb912b3ea54b36480d1dc13e6b5b29021a",
"size": 2610
},
"Platforms": [
{
"architecture": "amd64",
"os": "linux"
}
]
}

View File

@ -0,0 +1,14 @@
{
"Descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:2e33dc19d8514e01f7676532c507ddd95d0be20497fee25f4cbfc972cc6343d0",
"size": 2821
},
"Platforms": [
{
"architecture": "arm",
"os": "linux",
"variant": "v7"
}
]
}

View File

@ -1 +1 @@
alternative Dockerfile (basic/service2) FROM busybox