v13 preparations: Add feature switch for removal of '--gitignore' (push, build)

Change-type: patch
This commit is contained in:
Paulo Castro 2021-09-08 18:10:22 +01:00
parent 352fd197b7
commit d6faf060e6
17 changed files with 254 additions and 164 deletions

View File

@ -2926,16 +2926,16 @@ Don't convert line endings from CRLF (Windows format) to LF (Unix format).
Have each service use its own .dockerignore file. See "balena help push".
#### -G, --nogitignore
No-op (default behavior) since balena CLI v12.0.0. See "balena help push".
#### -g, --gitignore
Consider .gitignore files in addition to the .dockerignore file. This reverts
to the CLI v11 behavior/implementation (deprecated) if compatibility is
required until your project can be adapted.
#### -G, --nogitignore
No-op (default behavior) since balena CLI v12.0.0. See "balena help push".
#### --release-tag RELEASE-TAG
Set release tags if the image build is successful (balenaCloud only). Multiple
@ -3159,14 +3159,14 @@ Consider .gitignore files in addition to the .dockerignore file. This reverts
to the CLI v11 behavior/implementation (deprecated) if compatibility is required
until your project can be adapted.
#### -m, --multi-dockerignore
Have each service use its own .dockerignore file. See "balena help build".
#### -G, --nogitignore
No-op (default behavior) since balena CLI v12.0.0. See "balena help build".
#### -m, --multi-dockerignore
Have each service use its own .dockerignore file. See "balena help build".
#### --noparent-check
Disable project validation check of 'docker-compose.yml' file in parent folder
@ -3398,14 +3398,14 @@ Consider .gitignore files in addition to the .dockerignore file. This reverts
to the CLI v11 behavior/implementation (deprecated) if compatibility is required
until your project can be adapted.
#### -m, --multi-dockerignore
Have each service use its own .dockerignore file. See "balena help build".
#### -G, --nogitignore
No-op (default behavior) since balena CLI v12.0.0. See "balena help build".
#### -m, --multi-dockerignore
Have each service use its own .dockerignore file. See "balena help build".
#### --noparent-check
Disable project validation check of 'docker-compose.yml' file in parent folder

View File

@ -266,7 +266,7 @@ ${dockerignoreHelp}
inlineLogs: composeOpts.inlineLogs,
convertEol: composeOpts.convertEol,
dockerfilePath: composeOpts.dockerfilePath,
nogitignore: composeOpts.nogitignore,
nogitignore: composeOpts.nogitignore, // v13: delete this line
multiDockerignore: composeOpts.multiDockerignore,
});
}

View File

@ -314,7 +314,7 @@ ${dockerignoreHelp}
inlineLogs: composeOpts.inlineLogs,
convertEol: composeOpts.convertEol,
dockerfilePath: composeOpts.dockerfilePath,
nogitignore: composeOpts.nogitignore,
nogitignore: composeOpts.nogitignore, // v13: delete this line
multiDockerignore: composeOpts.multiDockerignore,
});
builtImagesByService = _.keyBy(builtImages, 'serviceName');

View File

@ -47,8 +47,8 @@ interface FlagsDef {
pull: boolean;
'noparent-check': boolean;
'registry-secrets'?: string;
gitignore?: boolean;
nogitignore?: boolean;
gitignore?: boolean; // v13: delete this flag
nogitignore?: boolean; // v13: delete this flag
nolive: boolean;
detached: boolean;
service?: string[];
@ -237,11 +237,20 @@ export default class PushCmd extends Command {
'Have each service use its own .dockerignore file. See "balena help push".',
char: 'm',
default: false,
exclusive: ['gitignore'],
exclusive: ['gitignore'], // v13: delete this line
}),
...(isV13()
? {}
: {
gitignore: flags.boolean({
description: stripIndent`
Consider .gitignore files in addition to the .dockerignore file. This reverts
to the CLI v11 behavior/implementation (deprecated) if compatibility is
required until your project can be adapted.`,
char: 'g',
default: false,
exclusive: ['multi-dockerignore'],
}),
nogitignore: flags.boolean({
description:
'No-op (default behavior) since balena CLI v12.0.0. See "balena help push".',
@ -250,15 +259,6 @@ export default class PushCmd extends Command {
default: false,
}),
}),
gitignore: flags.boolean({
description: stripIndent`
Consider .gitignore files in addition to the .dockerignore file. This reverts
to the CLI v11 behavior/implementation (deprecated) if compatibility is
required until your project can be adapted.`,
char: 'g',
default: false,
exclusive: ['multi-dockerignore'],
}),
'release-tag': flags.string({
description: stripIndent`
Set release tags if the image build is successful (balenaCloud only). Multiple
@ -378,7 +378,7 @@ export default class PushCmd extends Command {
source: options.source,
auth: token,
baseUrl,
nogitignore: !options.gitignore,
nogitignore: !options.gitignore, // v13: delete this line
sdk,
opts,
};
@ -422,7 +422,7 @@ export default class PushCmd extends Command {
multiDockerignore: options['multi-dockerignore'],
nocache: options.nocache,
pull: options.pull,
nogitignore: !options.gitignore,
nogitignore: !options.gitignore, // v13: delete this line
noParentCheck: options['noparent-check'],
nolive: options.nolive,
detached: options.detached,

View File

@ -51,7 +51,7 @@ export interface ComposeOpts {
dockerfilePath?: string;
inlineLogs?: boolean;
multiDockerignore: boolean;
nogitignore: boolean;
nogitignore: boolean; // v13: delete this line
noParentCheck: boolean;
projectName: string;
projectPath: string;
@ -63,9 +63,9 @@ export interface ComposeCliFlags {
dockerfile?: string;
logs: boolean;
nologs: boolean;
gitignore: boolean;
gitignore?: boolean; // v13: delete this line
nogitignore?: boolean; // v13: delete this line
'multi-dockerignore': boolean;
nogitignore: boolean;
'noparent-check': boolean;
'registry-secrets'?: RegistrySecrets;
'convert-eol': boolean;
@ -102,6 +102,6 @@ interface TarDirectoryOptions {
composition?: Composition;
convertEol?: boolean;
multiDockerignore?: boolean;
nogitignore: boolean;
nogitignore: boolean; // v13: delete this line
preFinalizeCallback?: (pack: Pack) => void | Promise<void>;
}

View File

@ -18,6 +18,7 @@
import * as path from 'path';
import { ExpectedError } from '../errors';
import { getChalk } from './lazy';
import { isV13 } from './version';
/**
* @returns Promise<{import('./compose-types').ComposeOpts}>
@ -25,7 +26,7 @@ import { getChalk } from './lazy';
export function generateOpts(options) {
const { promises: fs } = require('fs');
if (options.gitignore && options['multi-dockerignore']) {
if (!isV13() && options.gitignore && options['multi-dockerignore']) {
throw new ExpectedError(
'The --gitignore and --multi-dockerignore options cannot be used together',
);
@ -37,7 +38,7 @@ export function generateOpts(options) {
convertEol: !options['noconvert-eol'],
dockerfilePath: options.dockerfile,
multiDockerignore: !!options['multi-dockerignore'],
nogitignore: !options.gitignore,
nogitignore: !options.gitignore, // v13: delete this line
noParentCheck: options['noparent-check'],
}));
}
@ -92,6 +93,8 @@ export function createProject(composePath, composeStr, projectName = null) {
* @param {string} dir Source directory
* @param {import('./compose-types').TarDirectoryOptions} param
* @returns {Promise<import('stream').Readable>}
*
* v13: delete this function
*/
export async function originalTarDirectory(dir, param) {
let {

View File

@ -18,8 +18,9 @@ import { flags } from '@oclif/command';
import { BalenaSDK } from 'balena-sdk';
import type { TransposeOptions } from 'docker-qemu-transpose';
import type * as Dockerode from 'dockerode';
import * as _ from 'lodash';
import { promises as fs } from 'fs';
import jsyaml = require('js-yaml');
import * as _ from 'lodash';
import * as path from 'path';
import type {
BuildConfig,
@ -42,8 +43,8 @@ import {
import type { DeviceInfo } from './device/api';
import { getBalenaSdk, getChalk, stripIndent } from './lazy';
import Logger = require('./logger');
import { isV13 } from './version';
import { exists } from './which';
import jsyaml = require('js-yaml');
const allowedContractTypes = ['sw.application', 'sw.block'];
@ -250,7 +251,7 @@ export interface BuildProjectOpts {
inlineLogs?: boolean;
convertEol: boolean;
dockerfilePath?: string;
nogitignore: boolean;
nogitignore: boolean; // v13: delete this line
multiDockerignore: boolean;
}
@ -737,8 +738,8 @@ export async function tarDirectory(
dir: string,
param: TarDirectoryOptions,
): Promise<import('stream').Readable> {
const { nogitignore = false } = param;
if (nogitignore) {
const { nogitignore = false } = param; // v13: delete this line
if (isV13() || nogitignore) {
return newTarDirectory(dir, param);
} else {
return (await import('./compose')).originalTarDirectory(dir, param);
@ -759,11 +760,13 @@ async function newTarDirectory(
composition,
convertEol = false,
multiDockerignore = false,
nogitignore = false,
nogitignore = false, // v13: delete this line
preFinalizeCallback,
}: TarDirectoryOptions,
): Promise<import('stream').Readable> {
require('assert').strict.equal(nogitignore, true);
if (!isV13()) {
require('assert').strict.equal(nogitignore, true);
}
const { filterFilesWithDockerignore } = await import('./ignore');
const { toPosixPath } = (await import('resin-multibuild')).PathUtils;
@ -879,7 +882,8 @@ function printDockerignoreWarn(
}
}
if (msg.length) {
logFunc.call(logger, [' ', hr, ...msg, hr].join('\n'));
const { warnify } = require('./messages') as typeof import('./messages');
logFunc.call(logger, ' \n' + warnify(msg.join('\n'), ''));
}
}
@ -888,11 +892,16 @@ function printDockerignoreWarn(
* found and the --gitignore (-g) option has been provided (v11 compatibility).
* @param dockerignoreFile Absolute path to a .dockerignore file
* @param gitignoreFiles Array of absolute paths to .gitginore files
*
* v13: delete this function
*/
export function printGitignoreWarn(
dockerignoreFile: string,
gitignoreFiles: string[],
) {
if (isV13()) {
return;
}
const ignoreFiles = [dockerignoreFile, ...gitignoreFiles].filter((e) => e);
if (ignoreFiles.length === 0) {
return;
@ -1619,22 +1628,26 @@ export const composeCliFlags: flags.Input<ComposeCliFlags> = {
description:
'Hide the image build log output (produce less verbose output)',
}),
gitignore: flags.boolean({
description: stripIndent`
Consider .gitignore files in addition to the .dockerignore file. This reverts
to the CLI v11 behavior/implementation (deprecated) if compatibility is required
until your project can be adapted.`,
char: 'g',
}),
...(isV13()
? {}
: {
gitignore: flags.boolean({
description: stripIndent`
Consider .gitignore files in addition to the .dockerignore file. This reverts
to the CLI v11 behavior/implementation (deprecated) if compatibility is required
until your project can be adapted.`,
char: 'g',
}),
nogitignore: flags.boolean({
description: `No-op (default behavior) since balena CLI v12.0.0. See "balena help build".`,
char: 'G',
}),
}),
'multi-dockerignore': flags.boolean({
description:
'Have each service use its own .dockerignore file. See "balena help build".',
char: 'm',
}),
nogitignore: flags.boolean({
description: `No-op (default behavior) since balena CLI v12.0.0. See "balena help build".`,
char: 'G',
}),
'noparent-check': flags.boolean({
description:
"Disable project validation check of 'docker-compose.yml' file in parent folder",

View File

@ -57,7 +57,7 @@ export interface DeviceDeployOptions {
registrySecrets: RegistrySecrets;
multiDockerignore: boolean;
nocache: boolean;
nogitignore: boolean;
nogitignore: boolean; // v13: delete this line
noParentCheck: boolean;
nolive: boolean;
pull: boolean;
@ -182,7 +182,7 @@ export async function deployToDevice(opts: DeviceDeployOptions): Promise<void> {
convertEol: opts.convertEol,
dockerfilePath: opts.dockerfilePath,
multiDockerignore: opts.multiDockerignore,
nogitignore: opts.nogitignore,
nogitignore: opts.nogitignore, // v13: delete this line
noParentCheck: opts.noParentCheck,
projectName: 'local',
projectPath: opts.source,
@ -201,7 +201,7 @@ export async function deployToDevice(opts: DeviceDeployOptions): Promise<void> {
composition: project.composition,
convertEol: opts.convertEol,
multiDockerignore: opts.multiDockerignore,
nogitignore: opts.nogitignore,
nogitignore: opts.nogitignore, // v13: delete this line
});
// Try to detect the device information
@ -426,7 +426,7 @@ export async function rebuildSingleTask(
composition,
convertEol: opts.convertEol,
multiDockerignore: opts.multiDockerignore,
nogitignore: opts.nogitignore,
nogitignore: opts.nogitignore, // v13: delete this line
});
const task = _.find(

View File

@ -27,6 +27,7 @@ import { ExpectedError } from '../errors';
const { toPosixPath } = MultiBuild.PathUtils;
// v13: delete this enum
export enum IgnoreFileType {
DockerIgnore,
GitIgnore,
@ -42,6 +43,8 @@ interface IgnoreEntry {
* This class is used by the CLI v10 / v11 "original" tarDirectory function
* in `compose.js`. It is still around for the benefit of the `--gitignore`
* option, but is expected to be deleted in CLI v13.
*
* v13: delete this class
*/
export class FileIgnorer {
private dockerIgnoreEntries: IgnoreEntry[];

View File

@ -15,6 +15,8 @@
* limitations under the License.
*/
import { isV13 } from './version';
export const reachingOut = `\
For further help or support, visit:
https://www.balena.io/docs/reference/balena-cli/#support-faq-and-troubleshooting
@ -48,7 +50,8 @@ used. Find out more at: https://git.io/JRHUW#deprecation-policy
* where the length of the dash rows matches the length of the longest line.
*/
export function warnify(msg: string, prefix = '[Warn] ') {
const lines = msg.split('\n').map((l) => `${prefix}${l}`);
let lines = msg.split('\n');
lines = prefix ? lines.map((l) => `${prefix}${l}`) : lines;
const maxLength = Math.max(...lines.map((l) => l.length));
const hr = '-'.repeat(maxLength);
return [hr, ...lines, hr].join('\n');
@ -85,7 +88,7 @@ If the --registry-secrets option is not specified, and a secrets.yml or
secrets.json file exists in the balena directory (usually $HOME/.balena),
this file will be used instead.`;
export const dockerignoreHelp =
const dockerignoreHelpV12 =
'DOCKERIGNORE AND GITIGNORE FILES \n' +
`By default, the balena CLI will use a single ".dockerignore" file (if any) at
the project root (--source directory) in order to decide which source files to
@ -138,6 +141,60 @@ adding counter patterns to the applicable .dockerignore file(s), for example
- https://docs.docker.com/engine/reference/builder/#dockerignore-file
- https://www.npmjs.com/package/@balena/dockerignore`;
const dockerignoreHelpV13 =
'DOCKERIGNORE AND GITIGNORE FILES \n' +
`By default, the balena CLI will use a single ".dockerignore" file (if any) at
the project root (--source directory) in order to decide which source files to
exclude from the "build context" (tar stream) sent to balenaCloud, Docker
daemon or balenaEngine. In a microservices (multicontainer) fleet, the
source directory is the directory that contains the "docker-compose.yml" file.
The --multi-dockerignore (-m) option may be used with microservices
(multicontainer) fleets that define a docker-compose.yml file. When this
option is used, each service subdirectory (defined by the \`build\` or
\`build.context\` service properties in the docker-compose.yml file) is
filtered separately according to a .dockerignore file defined in the service
subdirectory. If no .dockerignore file exists in a service subdirectory, then
only the default .dockerignore patterns (see below) apply for that service
subdirectory.
When the --multi-dockerignore (-m) option is used, the .dockerignore file (if
any) defined at the overall project root will be used to filter files and
subdirectories other than service subdirectories. It will not have any effect
on service subdirectories, whether or not a service subdirectory defines its
own .dockerignore file. Multiple .dockerignore files are not merged or added
together, and cannot override or extend other files. This behavior maximizes
compatibility with the standard docker-compose tool, while still allowing a
root .dockerignore file (at the overall project root) to filter files and
folders that are outside service subdirectories.
balena CLI v11 also took .gitignore files into account. This behavior was
deprecated in CLI v12 and removed in CLI v13. Please use .dockerignore files
instead.
Default .dockerignore patterns \n` +
`A few default/hardcoded dockerignore patterns are "merged" (in memory) with the
patterns found in the applicable .dockerignore files, in the following order:
\`\`\`
**/.git
< user's patterns from the applicable '.dockerignore' file, if any >
!**/.balena
!**/.resin
!**/Dockerfile
!**/Dockerfile.*
!**/docker-compose.yml
\`\`\`
These patterns always apply, whether or not .dockerignore files exist in the
project. If necessary, the effect of the \`**/.git\` pattern may be modified by
adding exception patterns to the applicable .dockerignore file(s), for example
\`!mysubmodule/.git\`. For documentation on pattern format, see:
- https://docs.docker.com/engine/reference/builder/#dockerignore-file
- https://www.npmjs.com/package/@balena/dockerignore`;
export const dockerignoreHelp = isV13()
? dockerignoreHelpV13
: dockerignoreHelpV12;
export const applicationIdInfo = `\
Fleets may be specified by fleet name, slug, or numeric ID. Fleet slugs are
the recommended option, as they are unique and unambiguous. Slugs can be

View File

@ -50,7 +50,7 @@ export interface RemoteBuild {
source: string;
auth: string;
baseUrl: string;
nogitignore: boolean;
nogitignore: boolean; // v13: delete this line
opts: BuildOpts;
sdk: BalenaSDK;
// For internal use
@ -321,7 +321,7 @@ async function getTarStream(build: RemoteBuild): Promise<Stream.Readable> {
preFinalizeCallback: preFinalizeCb,
convertEol: build.opts.convertEol,
multiDockerignore: build.opts.multiDockerignore,
nogitignore: build.nogitignore,
nogitignore: build.nogitignore, // v13: delete this line
});
} finally {
tarSpinner.stop();

View File

@ -21,7 +21,8 @@ import mock = require('mock-require');
import { promises as fs } from 'fs';
import * as path from 'path';
import { stripIndent } from '../../lib/utils/lazy';
import { stripIndent } from '../../build/utils/lazy';
import { isV13 } from '../../build/utils/version';
import { BalenaAPIMock } from '../nock/balena-api-mock';
import { expectStreamNoCRLF, testDockerBuildStream } from '../docker-build';
import { DockerMock, dockerResponsePath } from '../nock/docker-mock';
@ -61,9 +62,6 @@ const commonComposeQueryParams = {
labels: '',
};
const hr =
'----------------------------------------------------------------------';
// "itSS" means "it() Skip Standalone"
const itSS = process.env.BALENA_CLI_TEST_TYPE === 'standalone' ? it.skip : it;
@ -126,7 +124,9 @@ describe('balena build', function () {
}
docker.expectGetInfo({});
await testDockerBuildStream({
commandLine: `build ${projectPath} --deviceType nuc --arch amd64 -g`,
commandLine: `build ${projectPath} --deviceType nuc --arch amd64 ${
isV13() ? '' : '-g'
}`,
dockerMock: docker,
expectedFilesByService: { main: expectedFiles },
expectedQueryParamsByService: { main: Object.entries(commonQueryParams) },
@ -272,7 +272,9 @@ describe('balena build', function () {
mock.reRequire('../../build/utils/qemu');
docker.expectGetInfo({ OperatingSystem: 'balenaOS 2.44.0+rev1' });
await testDockerBuildStream({
commandLine: `build ${projectPath} --emulated --deviceType ${deviceType} --arch ${arch} --nogitignore`,
commandLine: `build ${projectPath} --emulated --deviceType ${deviceType} --arch ${arch} ${
isV13() ? '' : '--nogitignore'
}`,
dockerMock: docker,
expectedFilesByService: { main: expectedFiles },
expectedQueryParamsByService: {
@ -416,7 +418,9 @@ describe('balena build', function () {
}
docker.expectGetInfo({});
await testDockerBuildStream({
commandLine: `build ${projectPath} --deviceType nuc --arch amd64 --convert-eol -G -B COMPOSE_ARG=A -B barg=b --cache-from my/img1,my/img2`,
commandLine: `build ${projectPath} --deviceType nuc --arch amd64 --convert-eol ${
isV13() ? '' : '-G'
} -B COMPOSE_ARG=A -B barg=b --cache-from my/img1,my/img2`,
dockerMock: docker,
expectedFilesByService,
expectedQueryParamsByService,
@ -484,11 +488,11 @@ describe('balena build', function () {
'[Build] service2 Step 1/4 : FROM busybox',
],
...[
`[Info] ${hr}`,
`[Info] ---------------------------------------------------------------------------`,
'[Info] The --multi-dockerignore option is being used, and a .dockerignore file was',
'[Info] found at the project source (root) directory. Note that this file will not',
'[Info] be used to filter service subdirectories. See "balena help build".',
`[Info] ${hr}`,
`[Info] ---------------------------------------------------------------------------`,
],
];
if (isWindows) {

View File

@ -23,6 +23,7 @@ import * as nock from 'nock';
import * as path from 'path';
import * as sinon from 'sinon';
import { isV13 } from '../../build/utils/version';
import { BalenaAPIMock } from '../nock/balena-api-mock';
import { expectStreamNoCRLF, testDockerBuildStream } from '../docker-build';
import { DockerMock, dockerResponsePath } from '../nock/docker-mock';
@ -66,9 +67,6 @@ const commonComposeQueryParams = {
labels: '',
};
const hr =
'----------------------------------------------------------------------';
describe('balena deploy', function () {
let api: BalenaAPIMock;
let docker: DockerMock;
@ -143,7 +141,9 @@ describe('balena deploy', function () {
api.expectPostImageLabel();
await testDockerBuildStream({
commandLine: `deploy testApp --build --source ${projectPath} -G`,
commandLine: `deploy testApp --build --source ${projectPath} ${
isV13() ? '' : '-G'
}`,
dockerMock: docker,
expectedFilesByService: { main: expectedFiles },
expectedQueryParamsByService: { main: commonQueryParams },
@ -304,7 +304,9 @@ describe('balena deploy', function () {
sinon.stub(process, 'exit');
await testDockerBuildStream({
commandLine: `deploy testApp --build --source ${projectPath} --noconvert-eol -G`,
commandLine: `deploy testApp --build --source ${projectPath} --noconvert-eol ${
isV13() ? '' : '-G'
}`,
dockerMock: docker,
expectedFilesByService: { main: expectedFiles },
expectedQueryParamsByService: { main: commonQueryParams },
@ -385,11 +387,11 @@ describe('balena deploy', function () {
'[Build] service2 Step 1/4 : FROM busybox',
],
...[
`[Info] ${hr}`,
`[Info] ---------------------------------------------------------------------------`,
'[Info] The --multi-dockerignore option is being used, and a .dockerignore file was',
'[Info] found at the project source (root) directory. Note that this file will not',
'[Info] be used to filter service subdirectories. See "balena help deploy".',
`[Info] ${hr}`,
`[Info] ---------------------------------------------------------------------------`,
],
];
if (isWindows) {

View File

@ -19,6 +19,7 @@ import { expect } from 'chai';
import { promises as fs } from 'fs';
import * as path from 'path';
import { isV13 } from '../../build/utils/version';
import { BalenaAPIMock } from '../nock/balena-api-mock';
import { BuilderMock, builderResponsePath } from '../nock/builder-mock';
import { expectStreamNoCRLF, testPushBuildStream } from '../docker-build';
@ -34,6 +35,8 @@ import {
const repoPath = path.normalize(path.join(__dirname, '..', '..'));
const projectsPath = path.join(repoPath, 'tests', 'test-data', 'projects');
const itNoV13 = isV13() ? it.skip : it;
const commonResponseLines = {
'build-POST-v3.json': [
'[Info] Starting build for testApp, user gh_user',
@ -234,71 +237,74 @@ describe('balena push', function () {
});
});
it('should create the expected tar stream (single container, --gitignore)', async () => {
const projectPath = path.join(
projectsPath,
'no-docker-compose',
'dockerignore1',
);
const expectedFiles: ExpectedTarStreamFiles = {
'.balena/balena.yml': { fileSize: 12, type: 'file' },
'.dockerignore': { fileSize: 438, type: 'file' },
'.gitignore': { fileSize: 20, type: 'file' },
'.git/bar.txt': { fileSize: 4, type: 'file' },
'.git/foo.txt': { fileSize: 4, type: 'file' },
'c.txt': { fileSize: 1, type: 'file' },
Dockerfile: { fileSize: 13, type: 'file' },
'src/.balena/balena.yml': { fileSize: 16, type: 'file' },
'src/.gitignore': { fileSize: 10, type: 'file' },
'vendor/.git/vendor-git-contents': { fileSize: 20, type: 'file' },
// When --gitignore (-g) is provided for v11 compatibility, the old
// `zeit/dockerignore` npm package is still used but it is broken on
// Windows (reason why we created `@balena/dockerignore`).
...(isWindows
? {
'src/src-b.txt': { fileSize: 5, type: 'file' },
'dot.git/bar.txt': { fileSize: 4, type: 'file' },
'dot.git/foo.txt': { fileSize: 4, type: 'file' },
'vendor/dot.git/vendor-git-contents': {
fileSize: 20,
type: 'file',
},
}
: {}),
};
itNoV13(
'should create the expected tar stream (single container, --gitignore)',
async () => {
const projectPath = path.join(
projectsPath,
'no-docker-compose',
'dockerignore1',
);
const expectedFiles: ExpectedTarStreamFiles = {
'.balena/balena.yml': { fileSize: 12, type: 'file' },
'.dockerignore': { fileSize: 438, type: 'file' },
'.gitignore': { fileSize: 20, type: 'file' },
'.git/bar.txt': { fileSize: 4, type: 'file' },
'.git/foo.txt': { fileSize: 4, type: 'file' },
'c.txt': { fileSize: 1, type: 'file' },
Dockerfile: { fileSize: 13, type: 'file' },
'src/.balena/balena.yml': { fileSize: 16, type: 'file' },
'src/.gitignore': { fileSize: 10, type: 'file' },
'vendor/.git/vendor-git-contents': { fileSize: 20, type: 'file' },
// When --gitignore (-g) is provided for v11 compatibility, the old
// `zeit/dockerignore` npm package is still used but it is broken on
// Windows (reason why we created `@balena/dockerignore`).
...(isWindows
? {
'src/src-b.txt': { fileSize: 5, type: 'file' },
'dot.git/bar.txt': { fileSize: 4, type: 'file' },
'dot.git/foo.txt': { fileSize: 4, type: 'file' },
'vendor/dot.git/vendor-git-contents': {
fileSize: 20,
type: 'file',
},
}
: {}),
};
const regSecretsPath = await addRegSecretsEntries(expectedFiles);
const responseFilename = 'build-POST-v3.json';
const responseBody = await fs.readFile(
path.join(builderResponsePath, responseFilename),
'utf8',
);
const expectedResponseLines = [
...[
`[Warn] ${hr}`,
'[Warn] Using file ignore patterns from:',
`[Warn] * ${path.join(projectPath, '.dockerignore')}`,
`[Warn] * ${path.join(projectPath, '.gitignore')}`,
`[Warn] * ${path.join(projectPath, 'src', '.gitignore')}`,
'[Warn] .gitignore files are being considered because the --gitignore option was used.',
'[Warn] This option is deprecated and will be removed in the next major version release.',
"[Warn] For more information, see 'balena help push'.",
`[Warn] ${hr}`,
],
...commonResponseLines[responseFilename],
];
const regSecretsPath = await addRegSecretsEntries(expectedFiles);
const responseFilename = 'build-POST-v3.json';
const responseBody = await fs.readFile(
path.join(builderResponsePath, responseFilename),
'utf8',
);
const expectedResponseLines = [
...[
`[Warn] ${hr}`,
'[Warn] Using file ignore patterns from:',
`[Warn] * ${path.join(projectPath, '.dockerignore')}`,
`[Warn] * ${path.join(projectPath, '.gitignore')}`,
`[Warn] * ${path.join(projectPath, 'src', '.gitignore')}`,
'[Warn] .gitignore files are being considered because the --gitignore option was used.',
'[Warn] This option is deprecated and will be removed in the next major version release.',
"[Warn] For more information, see 'balena help push'.",
`[Warn] ${hr}`,
],
...commonResponseLines[responseFilename],
];
await testPushBuildStream({
builderMock: builder,
commandLine: `push testApp -s ${projectPath} -R ${regSecretsPath} -g`,
expectedFiles,
expectedQueryParams: commonQueryParams,
expectedResponseLines,
projectPath,
responseBody,
responseCode: 200,
});
});
await testPushBuildStream({
builderMock: builder,
commandLine: `push testApp -s ${projectPath} -R ${regSecretsPath} -g`,
expectedFiles,
expectedQueryParams: commonQueryParams,
expectedResponseLines,
projectPath,
responseBody,
responseCode: 200,
});
},
);
it('should create the expected tar stream (single container, --nogitignore)', async () => {
const projectPath = path.join(
@ -370,24 +376,27 @@ describe('balena push', function () {
path.join(builderResponsePath, responseFilename),
'utf8',
);
const expectedResponseLines = isWindows
? [
`[Warn] ${hr}`,
'[Warn] Using file ignore patterns from:',
`[Warn] * ${path.join(projectPath, '.dockerignore')}`,
'[Warn] The --gitignore option was used, but no .gitignore files were found.',
'[Warn] The --gitignore option is deprecated and will be removed in the next major',
'[Warn] version release. It prevents the use of a better dockerignore parser and',
'[Warn] filter library that fixes several issues on Windows and improves compatibility',
"[Warn] with 'docker build'. For more information, see 'balena help push'.",
`[Warn] ${hr}`,
...commonResponseLines[responseFilename],
]
: commonResponseLines[responseFilename];
const expectedResponseLines =
!isV13() && isWindows
? [
`[Warn] ${hr}`,
'[Warn] Using file ignore patterns from:',
`[Warn] * ${path.join(projectPath, '.dockerignore')}`,
'[Warn] The --gitignore option was used, but no .gitignore files were found.',
'[Warn] The --gitignore option is deprecated and will be removed in the next major',
'[Warn] version release. It prevents the use of a better dockerignore parser and',
'[Warn] filter library that fixes several issues on Windows and improves compatibility',
"[Warn] with 'docker build'. For more information, see 'balena help push'.",
`[Warn] ${hr}`,
...commonResponseLines[responseFilename],
]
: commonResponseLines[responseFilename];
await testPushBuildStream({
builderMock: builder,
commandLine: `push testApp -s ${projectPath} -R ${regSecretsPath} --gitignore`,
commandLine: `push testApp -s ${projectPath} -R ${regSecretsPath} ${
isV13() ? '' : '--gitignore'
}`,
expectedFiles,
expectedQueryParams: commonQueryParams,
expectedResponseLines,
@ -516,11 +525,11 @@ describe('balena push', function () {
const expectedResponseLines: string[] = [
...commonResponseLines[responseFilename],
...[
`[Info] ${hr}`,
`[Info] ---------------------------------------------------------------------------`,
'[Info] The --multi-dockerignore option is being used, and a .dockerignore file was',
'[Info] found at the project source (root) directory. Note that this file will not',
'[Info] be used to filter service subdirectories. See "balena help push".',
`[Info] ${hr}`,
`[Info] ---------------------------------------------------------------------------`,
],
];
if (isWindows) {
@ -571,7 +580,7 @@ describe('balena push: project validation', function () {
];
const { out, err } = await runCommand(
`push testApp --source ${projectPath} --gitignore`,
`push testApp --source ${projectPath}`,
);
expect(cleanOutput(err, true)).to.include.members(expectedErrorLines);
expect(out).to.be.empty;

View File

@ -105,7 +105,7 @@ async function runCommandInProcess(cmd: string): Promise<TestOutput> {
const unhookIntercept = intercept(stdoutHook, stderrHook);
try {
await balenaCLI.run(preArgs.concat(cmd.split(' ')), {
await balenaCLI.run(preArgs.concat(cmd.split(' ').filter((c) => c)), {
noFlush: true,
});
} finally {
@ -160,7 +160,7 @@ async function runCommandInSubprocess(
await new Promise<void>((resolve) => {
const child = execFile(
standalonePath,
cmd.split(' '),
cmd.split(' ').filter((c) => c),
{ env: { ...process.env, ...addedEnvs } },
($error, $stdout, $stderr) => {
stderr = $stderr || '';

View File

@ -86,7 +86,6 @@ export async function addRegSecretsEntries(
export function getDockerignoreWarn1(paths: string[], cmd: string) {
const lines = [
'[Warn] ----------------------------------------------------------------------',
'[Warn] The following .dockerignore file(s) will not be used:',
];
lines.push(...paths.map((p) => `[Warn] * ${p}`));
@ -96,7 +95,6 @@ export function getDockerignoreWarn1(paths: string[], cmd: string) {
'[Warn] root) is used. Microservices (multicontainer) fleets may use a separate',
'[Warn] .dockerignore file for each service with the --multi-dockerignore (-m)',
`[Warn] option. See "balena help ${cmd}" for more details.`,
'[Warn] ----------------------------------------------------------------------',
],
);
return lines;
@ -104,7 +102,6 @@ export function getDockerignoreWarn1(paths: string[], cmd: string) {
export function getDockerignoreWarn2(paths: string[], cmd: string) {
const lines = [
'[Warn] ----------------------------------------------------------------------',
'[Warn] The following .dockerignore file(s) will not be used:',
];
lines.push(...paths.map((p) => `[Warn] * ${p}`));
@ -114,7 +111,6 @@ export function getDockerignoreWarn2(paths: string[], cmd: string) {
"[Warn] root of each service's build context (in a microservices/multicontainer",
'[Warn] fleet), plus a .dockerignore file at the overall project root, are used.',
`[Warn] See "balena help ${cmd}" for more details.`,
'[Warn] ----------------------------------------------------------------------',
],
);
return lines;

View File

@ -7,6 +7,9 @@ import { FileIgnorer, IgnoreFileType } from '../../build/utils/ignore';
// of the FileIgnorer class to prevent a Typescript compilation error (this
// behavior is by design: see
// https://github.com/microsoft/TypeScript/issues/19335 )
//
// v13: delete this file
//
describe('File ignorer', function () {
it('should detect ignore files', function () {
const f = new FileIgnorer(`.${path.sep}`);