mirror of
https://github.com/balena-io/balena-cli.git
synced 2024-12-18 21:27:51 +00:00
Add runtime warning for unused .dockerignore files
Change-type: patch
This commit is contained in:
parent
2859d16b31
commit
11d1a3f5a0
@ -193,8 +193,12 @@ export async function tarDirectory(
|
||||
readFile = fs.readFile;
|
||||
}
|
||||
const pack = tar.pack();
|
||||
const fileStatsList = await filterFilesWithDockerignore(dir);
|
||||
for (const fileStats of fileStatsList) {
|
||||
const {
|
||||
filteredFileList,
|
||||
dockerignoreFiles,
|
||||
} = await filterFilesWithDockerignore(dir);
|
||||
printDockerignoreWarn(dockerignoreFiles);
|
||||
for (const fileStats of filteredFileList) {
|
||||
pack.entry(
|
||||
{
|
||||
name: toPosixPath(fileStats.relPath),
|
||||
@ -212,9 +216,40 @@ export async function tarDirectory(
|
||||
return pack;
|
||||
}
|
||||
|
||||
export function printDockerignoreWarn(
|
||||
dockerignoreFiles: Array<import('./ignore').FileStats>,
|
||||
) {
|
||||
const nonRootFiles = dockerignoreFiles.filter(
|
||||
(fileStats: import('./ignore').FileStats) => {
|
||||
const dirname = path.dirname(fileStats.relPath);
|
||||
return !!dirname && dirname !== '.';
|
||||
},
|
||||
);
|
||||
if (nonRootFiles.length === 0) {
|
||||
return;
|
||||
}
|
||||
const hr =
|
||||
'-------------------------------------------------------------------------------';
|
||||
const msg = [
|
||||
' ',
|
||||
hr,
|
||||
'The following .dockerignore file(s) will not be used:',
|
||||
];
|
||||
msg.push(...nonRootFiles.map((fileStats) => `* ${fileStats.filePath}`));
|
||||
msg.push(stripIndent`
|
||||
Only one .dockerignore file at the source folder (project root) is used.
|
||||
Additional .dockerignore files are disregarded. Microservices (multicontainer)
|
||||
apps should place the .dockerignore file alongside the docker-compose.yml file.
|
||||
See issue: https://github.com/balena-io/balena-cli/issues/1870
|
||||
See also CLI v12 release notes: https://git.io/Jf7hz
|
||||
`);
|
||||
msg.push(hr);
|
||||
Logger.getLogger().logWarn(msg.join('\n'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a deprecation warning if any '.gitignore' or '.dockerignore' file is
|
||||
* found and the --gitignore (-g) option has been provided.
|
||||
* 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
|
||||
*/
|
||||
@ -229,22 +264,22 @@ export function printGitignoreWarn(
|
||||
const hr =
|
||||
'-------------------------------------------------------------------------------';
|
||||
const msg = [' ', hr, 'Using file ignore patterns from:'];
|
||||
msg.push(...ignoreFiles);
|
||||
msg.push(...ignoreFiles.map((e) => `* ${e}`));
|
||||
if (gitignoreFiles.length) {
|
||||
msg.push(stripIndent`
|
||||
Note: .gitignore files are being considered because the --gitignore option was
|
||||
used. This option is deprecated and will be removed in the next major version
|
||||
release. For more information, see 'balena help ${Logger.command}'.
|
||||
.gitignore files are being considered because the --gitignore option was used.
|
||||
This option is deprecated and will be removed in the next major version release.
|
||||
For more information, see 'balena help ${Logger.command}'.
|
||||
`);
|
||||
msg.push(hr);
|
||||
Logger.getLogger().logWarn(msg.join('\n'));
|
||||
} else if (dockerignoreFile && process.platform === 'win32') {
|
||||
msg.push(stripIndent`
|
||||
The --gitignore option was used, but not .gitignore files were found.
|
||||
The --gitignore option was used, but no .gitignore files were found.
|
||||
The --gitignore option is deprecated and will be removed in the next major
|
||||
version release. It prevents the use of a better dockerignore parser and
|
||||
filter library that fixes several issues on Windows and improves compatibility
|
||||
with "docker build". For more information, see 'balena help ${Logger.command}'.
|
||||
with 'docker build'. For more information, see 'balena help ${Logger.command}'.
|
||||
`);
|
||||
msg.push(hr);
|
||||
Logger.getLogger().logWarn(msg.join('\n'));
|
||||
|
@ -190,7 +190,7 @@ export class FileIgnorer {
|
||||
}
|
||||
}
|
||||
|
||||
interface FileStats {
|
||||
export interface FileStats {
|
||||
filePath: string;
|
||||
relPath: string;
|
||||
stats: fs.Stats;
|
||||
@ -256,7 +256,7 @@ async function readDockerIgnoreFile(projectDir: string): Promise<string> {
|
||||
*/
|
||||
export async function filterFilesWithDockerignore(
|
||||
projectDir: string,
|
||||
): Promise<FileStats[]> {
|
||||
): Promise<{ filteredFileList: FileStats[]; dockerignoreFiles: FileStats[] }> {
|
||||
// path.resolve() also converts forward slashes to backslashes on Windows
|
||||
projectDir = path.resolve(projectDir);
|
||||
const dockerIgnoreStr = await readDockerIgnoreFile(projectDir);
|
||||
@ -276,5 +276,12 @@ export async function filterFilesWithDockerignore(
|
||||
]);
|
||||
|
||||
const files = await listFiles(projectDir);
|
||||
return files.filter((file: FileStats) => !ig.ignores(file.relPath));
|
||||
const dockerignoreFiles: FileStats[] = [];
|
||||
const filteredFileList = files.filter((file: FileStats) => {
|
||||
if (path.basename(file.relPath) === '.dockerignore') {
|
||||
dockerignoreFiles.push(file);
|
||||
}
|
||||
return !ig.ignores(file.relPath);
|
||||
});
|
||||
return { filteredFileList, dockerignoreFiles };
|
||||
}
|
||||
|
@ -24,7 +24,6 @@ import mock = require('mock-require');
|
||||
import { fs } from 'mz';
|
||||
import * as path from 'path';
|
||||
|
||||
import { isV12 } from '../../build/utils/version';
|
||||
import { BalenaAPIMock } from '../balena-api-mock';
|
||||
import { expectStreamNoCRLF, testDockerBuildStream } from '../docker-build';
|
||||
import { DockerMock, dockerResponsePath } from '../docker-mock';
|
||||
@ -87,12 +86,12 @@ describe('balena build', function () {
|
||||
|
||||
it('should create the expected tar stream (single container)', async () => {
|
||||
const projectPath = path.join(projectsPath, 'no-docker-compose', 'basic');
|
||||
const isV12W = isWindows && isV12();
|
||||
const expectedFiles: ExpectedTarStreamFiles = {
|
||||
'src/.dockerignore': { fileSize: 16, type: 'file' },
|
||||
'src/start.sh': { fileSize: 89, type: 'file' },
|
||||
'src/windows-crlf.sh': {
|
||||
fileSize: isV12W ? 68 : 70,
|
||||
testStream: isV12W ? expectStreamNoCRLF : undefined,
|
||||
fileSize: isWindows ? 68 : 70,
|
||||
testStream: isWindows ? expectStreamNoCRLF : undefined,
|
||||
type: 'file',
|
||||
},
|
||||
Dockerfile: { fileSize: 88, type: 'file' },
|
||||
@ -107,13 +106,11 @@ describe('balena build', function () {
|
||||
...commonResponseLines[responseFilename],
|
||||
`[Info] No "docker-compose.yml" file found at "${projectPath}"`,
|
||||
`[Info] Creating default composition with source: "${projectPath}"`,
|
||||
isV12()
|
||||
? '[Build] main Step 1/4 : FROM busybox'
|
||||
: '[Build] main Image size: 1.14 MB',
|
||||
'[Build] main Step 1/4 : FROM busybox',
|
||||
];
|
||||
if (isWindows) {
|
||||
const fname = path.join(projectPath, 'src', 'windows-crlf.sh');
|
||||
if (isV12()) {
|
||||
if (isWindows) {
|
||||
expectedResponseLines.push(
|
||||
`[Info] Converting line endings CRLF -> LF for file: ${fname}`,
|
||||
);
|
||||
@ -142,7 +139,6 @@ describe('balena build', function () {
|
||||
// downloading and installing QEMU
|
||||
itSS('should create the expected tar stream (--emulated)', async () => {
|
||||
const projectPath = path.join(projectsPath, 'no-docker-compose', 'basic');
|
||||
const isV12W = isWindows && isV12();
|
||||
const transposedDockerfile =
|
||||
stripIndent`
|
||||
FROM busybox
|
||||
@ -151,10 +147,11 @@ describe('balena build', function () {
|
||||
RUN ["/tmp/qemu-execve","-execve","/bin/sh","-c","chmod a+x /usr/src/*.sh"]
|
||||
CMD ["/usr/src/start.sh"]` + '\n';
|
||||
const expectedFiles: ExpectedTarStreamFiles = {
|
||||
'src/.dockerignore': { fileSize: 16, type: 'file' },
|
||||
'src/start.sh': { fileSize: 89, type: 'file' },
|
||||
'src/windows-crlf.sh': {
|
||||
fileSize: isV12W ? 68 : 70,
|
||||
testStream: isV12W ? expectStreamNoCRLF : undefined,
|
||||
fileSize: isWindows ? 68 : 70,
|
||||
testStream: isWindows ? expectStreamNoCRLF : undefined,
|
||||
type: 'file',
|
||||
},
|
||||
Dockerfile: {
|
||||
@ -174,23 +171,25 @@ describe('balena build', function () {
|
||||
`[Info] Creating default composition with source: "${projectPath}"`,
|
||||
'[Info] Building for rpi/raspberry-pi',
|
||||
'[Info] Emulation is enabled',
|
||||
isV12()
|
||||
? '[Build] main Step 1/4 : FROM busybox'
|
||||
: '[Build] main Image size: 1.14 MB',
|
||||
...[
|
||||
'[Warn] -------------------------------------------------------------------------------',
|
||||
'[Warn] The following .dockerignore file(s) will not be used:',
|
||||
`[Warn] * ${path.join(projectPath, 'src', '.dockerignore')}`,
|
||||
'[Warn] Only one .dockerignore file at the source folder (project root) is used.',
|
||||
'[Warn] Additional .dockerignore files are disregarded. Microservices (multicontainer)',
|
||||
'[Warn] apps should place the .dockerignore file alongside the docker-compose.yml file.',
|
||||
'[Warn] See issue: https://github.com/balena-io/balena-cli/issues/1870',
|
||||
'[Warn] See also CLI v12 release notes: https://git.io/Jf7hz',
|
||||
'[Warn] -------------------------------------------------------------------------------',
|
||||
],
|
||||
'[Build] main Step 1/4 : FROM busybox',
|
||||
'[Success] Build succeeded!',
|
||||
];
|
||||
if (isWindows) {
|
||||
const fname = path.join(projectPath, 'src', 'windows-crlf.sh');
|
||||
if (isV12()) {
|
||||
expectedResponseLines.push(
|
||||
`[Info] Converting line endings CRLF -> LF for file: ${fname}`,
|
||||
);
|
||||
} else {
|
||||
expectedResponseLines.push(
|
||||
`[Warn] CRLF (Windows) line endings detected in file: ${fname}`,
|
||||
'[Warn] Windows-format line endings were detected in some files. Consider using the `--convert-eol` option.',
|
||||
);
|
||||
}
|
||||
expectedResponseLines.push(
|
||||
`[Info] Converting line endings CRLF -> LF for file: ${fname}`,
|
||||
);
|
||||
}
|
||||
const arch = 'rpi';
|
||||
const deviceType = 'raspberry-pi';
|
||||
@ -230,12 +229,11 @@ describe('balena build', function () {
|
||||
|
||||
it('should create the expected tar stream (single container, --[no]convert-eol)', async () => {
|
||||
const projectPath = path.join(projectsPath, 'no-docker-compose', 'basic');
|
||||
const eol = isWindows && !isV12();
|
||||
const expectedFiles: ExpectedTarStreamFiles = {
|
||||
'src/.dockerignore': { fileSize: 16, type: 'file' },
|
||||
'src/start.sh': { fileSize: 89, type: 'file' },
|
||||
'src/windows-crlf.sh': {
|
||||
fileSize: eol ? 68 : 70,
|
||||
testStream: eol ? expectStreamNoCRLF : undefined,
|
||||
fileSize: 70,
|
||||
type: 'file',
|
||||
},
|
||||
Dockerfile: { fileSize: 88, type: 'file' },
|
||||
@ -250,28 +248,29 @@ describe('balena build', function () {
|
||||
...commonResponseLines[responseFilename],
|
||||
`[Info] No "docker-compose.yml" file found at "${projectPath}"`,
|
||||
`[Info] Creating default composition with source: "${projectPath}"`,
|
||||
isV12()
|
||||
? '[Build] main Step 1/4 : FROM busybox'
|
||||
: '[Build] main Image size: 1.14 MB',
|
||||
...[
|
||||
'[Warn] -------------------------------------------------------------------------------',
|
||||
'[Warn] The following .dockerignore file(s) will not be used:',
|
||||
`[Warn] * ${path.join(projectPath, 'src', '.dockerignore')}`,
|
||||
'[Warn] Only one .dockerignore file at the source folder (project root) is used.',
|
||||
'[Warn] Additional .dockerignore files are disregarded. Microservices (multicontainer)',
|
||||
'[Warn] apps should place the .dockerignore file alongside the docker-compose.yml file.',
|
||||
'[Warn] See issue: https://github.com/balena-io/balena-cli/issues/1870',
|
||||
'[Warn] See also CLI v12 release notes: https://git.io/Jf7hz',
|
||||
'[Warn] -------------------------------------------------------------------------------',
|
||||
],
|
||||
'[Build] main Step 1/4 : FROM busybox',
|
||||
];
|
||||
if (isWindows) {
|
||||
const fname = path.join(projectPath, 'src', 'windows-crlf.sh');
|
||||
if (isV12()) {
|
||||
expectedResponseLines.push(
|
||||
`[Warn] CRLF (Windows) line endings detected in file: ${fname}`,
|
||||
'[Warn] Windows-format line endings were detected in some files, but were not converted due to `--noconvert-eol` option.',
|
||||
);
|
||||
} else {
|
||||
expectedResponseLines.push(
|
||||
`[Info] Converting line endings CRLF -> LF for file: ${fname}`,
|
||||
);
|
||||
}
|
||||
expectedResponseLines.push(
|
||||
`[Warn] CRLF (Windows) line endings detected in file: ${fname}`,
|
||||
'[Warn] Windows-format line endings were detected in some files, but were not converted due to `--noconvert-eol` option.',
|
||||
);
|
||||
}
|
||||
docker.expectGetInfo({});
|
||||
await testDockerBuildStream({
|
||||
commandLine: isV12()
|
||||
? `build ${projectPath} --deviceType nuc --arch amd64 --noconvert-eol`
|
||||
: `build ${projectPath} --deviceType nuc --arch amd64 --convert-eol`,
|
||||
commandLine: `build ${projectPath} --deviceType nuc --arch amd64 --noconvert-eol`,
|
||||
dockerMock: docker,
|
||||
expectedFilesByService: { main: expectedFiles },
|
||||
expectedQueryParamsByService: { main: commonQueryParams },
|
||||
@ -302,6 +301,7 @@ describe('balena build', function () {
|
||||
'file1.sh': { fileSize: 12, type: 'file' },
|
||||
},
|
||||
service2: {
|
||||
'.dockerignore': { fileSize: 14, type: 'file' },
|
||||
'Dockerfile-alt': { fileSize: 40, type: 'file' },
|
||||
'file2-crlf.sh': {
|
||||
fileSize: isWindows ? 12 : 14,
|
||||
@ -328,15 +328,20 @@ describe('balena build', function () {
|
||||
};
|
||||
const expectedResponseLines: string[] = [
|
||||
...commonResponseLines[responseFilename],
|
||||
...(isV12()
|
||||
? [
|
||||
'[Build] service1 Step 1/4 : FROM busybox',
|
||||
'[Build] service2 Step 1/4 : FROM busybox',
|
||||
]
|
||||
: [
|
||||
`[Build] service1 Image size: 1.14 MB`,
|
||||
`[Build] service2 Image size: 1.14 MB`,
|
||||
]),
|
||||
...[
|
||||
'[Build] service1 Step 1/4 : FROM busybox',
|
||||
'[Build] service2 Step 1/4 : FROM busybox',
|
||||
],
|
||||
...[
|
||||
'[Warn] The following .dockerignore file(s) will not be used:',
|
||||
`[Warn] * ${path.join(projectPath, 'service2', '.dockerignore')}`,
|
||||
'[Warn] Only one .dockerignore file at the source folder (project root) is used.',
|
||||
'[Warn] Additional .dockerignore files are disregarded. Microservices (multicontainer)',
|
||||
'[Warn] apps should place the .dockerignore file alongside the docker-compose.yml file.',
|
||||
'[Warn] See issue: https://github.com/balena-io/balena-cli/issues/1870',
|
||||
'[Warn] See also CLI v12 release notes: https://git.io/Jf7hz',
|
||||
'[Warn] -------------------------------------------------------------------------------',
|
||||
],
|
||||
];
|
||||
if (isWindows) {
|
||||
expectedResponseLines.push(
|
||||
|
@ -23,7 +23,6 @@ import { fs } from 'mz';
|
||||
import * as path from 'path';
|
||||
import * as sinon from 'sinon';
|
||||
|
||||
import { isV12 } from '../../build/utils/version';
|
||||
import { BalenaAPIMock } from '../balena-api-mock';
|
||||
import { expectStreamNoCRLF, testDockerBuildStream } from '../docker-build';
|
||||
import { DockerMock, dockerResponsePath } from '../docker-mock';
|
||||
@ -39,9 +38,7 @@ const commonResponseLines = {
|
||||
'[Info] Docker Desktop detected (daemon architecture: "x86_64")',
|
||||
'[Info] Docker itself will determine and enable architecture emulation if required,',
|
||||
'[Info] without balena-cli intervention and regardless of the --emulated option.',
|
||||
isV12()
|
||||
? '[Build] main Step 1/4 : FROM busybox'
|
||||
: '[Build] main Image size: 1.14 MB',
|
||||
'[Build] main Step 1/4 : FROM busybox',
|
||||
'[Info] Creating release...',
|
||||
'[Info] Pushing images to registry...',
|
||||
'[Info] Saving release...',
|
||||
@ -59,20 +56,8 @@ const commonQueryParams = [
|
||||
describe('balena deploy', function () {
|
||||
let api: BalenaAPIMock;
|
||||
let docker: DockerMock;
|
||||
let sentryStatus: boolean | undefined;
|
||||
const isWindows = process.platform === 'win32';
|
||||
|
||||
this.beforeAll(async () => {
|
||||
sentryStatus = await switchSentry(false);
|
||||
sinon.stub(process, 'exit');
|
||||
});
|
||||
|
||||
this.afterAll(async () => {
|
||||
await switchSentry(sentryStatus);
|
||||
// @ts-ignore
|
||||
process.exit.restore();
|
||||
});
|
||||
|
||||
this.beforeEach(() => {
|
||||
api = new BalenaAPIMock();
|
||||
docker = new DockerMock();
|
||||
@ -106,12 +91,12 @@ describe('balena deploy', function () {
|
||||
|
||||
it('should create the expected --build tar stream (single container)', async () => {
|
||||
const projectPath = path.join(projectsPath, 'no-docker-compose', 'basic');
|
||||
const isV12W = isWindows && isV12();
|
||||
const expectedFiles: ExpectedTarStreamFiles = {
|
||||
'src/.dockerignore': { fileSize: 16, type: 'file' },
|
||||
'src/start.sh': { fileSize: 89, type: 'file' },
|
||||
'src/windows-crlf.sh': {
|
||||
fileSize: isV12W ? 68 : 70,
|
||||
testStream: isV12W ? expectStreamNoCRLF : undefined,
|
||||
fileSize: isWindows ? 68 : 70,
|
||||
testStream: isWindows ? expectStreamNoCRLF : undefined,
|
||||
type: 'file',
|
||||
},
|
||||
Dockerfile: { fileSize: 88, type: 'file' },
|
||||
@ -126,19 +111,23 @@ describe('balena deploy', function () {
|
||||
...commonResponseLines[responseFilename],
|
||||
`[Info] No "docker-compose.yml" file found at "${projectPath}"`,
|
||||
`[Info] Creating default composition with source: "${projectPath}"`,
|
||||
...[
|
||||
'[Warn] -------------------------------------------------------------------------------',
|
||||
'[Warn] The following .dockerignore file(s) will not be used:',
|
||||
`[Warn] * ${path.join(projectPath, 'src', '.dockerignore')}`,
|
||||
'[Warn] Only one .dockerignore file at the source folder (project root) is used.',
|
||||
'[Warn] Additional .dockerignore files are disregarded. Microservices (multicontainer)',
|
||||
'[Warn] apps should place the .dockerignore file alongside the docker-compose.yml file.',
|
||||
'[Warn] See issue: https://github.com/balena-io/balena-cli/issues/1870',
|
||||
'[Warn] See also CLI v12 release notes: https://git.io/Jf7hz',
|
||||
'[Warn] -------------------------------------------------------------------------------',
|
||||
],
|
||||
];
|
||||
if (isWindows) {
|
||||
const fname = path.join(projectPath, 'src', 'windows-crlf.sh');
|
||||
if (isV12()) {
|
||||
expectedResponseLines.push(
|
||||
`[Info] Converting line endings CRLF -> LF for file: ${fname}`,
|
||||
);
|
||||
} else {
|
||||
expectedResponseLines.push(
|
||||
`[Warn] CRLF (Windows) line endings detected in file: ${fname}`,
|
||||
'[Warn] Windows-format line endings were detected in some files. Consider using the `--convert-eol` option.',
|
||||
);
|
||||
}
|
||||
expectedResponseLines.push(
|
||||
`[Info] Converting line endings CRLF -> LF for file: ${fname}`,
|
||||
);
|
||||
}
|
||||
|
||||
api.expectPatchImage({});
|
||||
@ -158,8 +147,10 @@ describe('balena deploy', function () {
|
||||
});
|
||||
|
||||
it('should update a release with status="failed" on error (single container)', async () => {
|
||||
let sentryStatus: boolean | undefined;
|
||||
const projectPath = path.join(projectsPath, 'no-docker-compose', 'basic');
|
||||
const expectedFiles: ExpectedTarStreamFiles = {
|
||||
'src/.dockerignore': { fileSize: 16, type: 'file' },
|
||||
'src/start.sh': { fileSize: 89, type: 'file' },
|
||||
'src/windows-crlf.sh': { fileSize: 70, type: 'file' },
|
||||
Dockerfile: { fileSize: 88, type: 'file' },
|
||||
@ -199,24 +190,34 @@ describe('balena deploy', function () {
|
||||
},
|
||||
});
|
||||
|
||||
await testDockerBuildStream({
|
||||
commandLine: `deploy testApp --build --source ${projectPath} --noconvert-eol -G`,
|
||||
dockerMock: docker,
|
||||
expectedFilesByService: { main: expectedFiles },
|
||||
expectedQueryParamsByService: { main: commonQueryParams },
|
||||
expectedErrorLines,
|
||||
expectedExitCode,
|
||||
expectedResponseLines,
|
||||
projectPath,
|
||||
responseBody,
|
||||
responseCode: 200,
|
||||
services: ['main'],
|
||||
});
|
||||
try {
|
||||
sentryStatus = await switchSentry(false);
|
||||
sinon.stub(process, 'exit');
|
||||
|
||||
await testDockerBuildStream({
|
||||
commandLine: `deploy testApp --build --source ${projectPath} --noconvert-eol -G`,
|
||||
dockerMock: docker,
|
||||
expectedFilesByService: { main: expectedFiles },
|
||||
expectedQueryParamsByService: { main: commonQueryParams },
|
||||
expectedErrorLines,
|
||||
expectedExitCode,
|
||||
expectedResponseLines,
|
||||
projectPath,
|
||||
responseBody,
|
||||
responseCode: 200,
|
||||
services: ['main'],
|
||||
});
|
||||
} finally {
|
||||
await switchSentry(sentryStatus);
|
||||
// @ts-ignore
|
||||
process.exit.restore();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('balena deploy: project validation', function () {
|
||||
let api: BalenaAPIMock;
|
||||
|
||||
this.beforeEach(() => {
|
||||
api = new BalenaAPIMock();
|
||||
api.expectGetWhoAmI({ optional: true, persist: true });
|
||||
|
@ -22,7 +22,6 @@ import { expect } from 'chai';
|
||||
import { fs } from 'mz';
|
||||
import * as path from 'path';
|
||||
|
||||
import { isV12 } from '../../build/utils/version';
|
||||
import { BalenaAPIMock } from '../balena-api-mock';
|
||||
import { BuilderMock, builderResponsePath } from '../builder-mock';
|
||||
import { expectStreamNoCRLF, testPushBuildStream } from '../docker-build';
|
||||
@ -107,12 +106,12 @@ describe('balena push', function () {
|
||||
|
||||
it('should create the expected tar stream (single container)', async () => {
|
||||
const projectPath = path.join(projectsPath, 'no-docker-compose', 'basic');
|
||||
const isV12W = isWindows && isV12();
|
||||
const expectedFiles: ExpectedTarStreamFiles = {
|
||||
'src/.dockerignore': { fileSize: 16, type: 'file' },
|
||||
'src/start.sh': { fileSize: 89, type: 'file' },
|
||||
'src/windows-crlf.sh': {
|
||||
fileSize: isV12W ? 68 : 70,
|
||||
testStream: isV12W ? expectStreamNoCRLF : undefined,
|
||||
fileSize: isWindows ? 68 : 70,
|
||||
testStream: isWindows ? expectStreamNoCRLF : undefined,
|
||||
type: 'file',
|
||||
},
|
||||
Dockerfile: { fileSize: 88, type: 'file' },
|
||||
@ -124,19 +123,24 @@ describe('balena push', function () {
|
||||
path.join(builderResponsePath, responseFilename),
|
||||
'utf8',
|
||||
);
|
||||
const expectedResponseLines = [...commonResponseLines[responseFilename]];
|
||||
const expectedResponseLines = [
|
||||
...commonResponseLines[responseFilename],
|
||||
...[
|
||||
'[Warn] The following .dockerignore file(s) will not be used:',
|
||||
`[Warn] * ${path.join(projectPath, 'src', '.dockerignore')}`,
|
||||
'[Warn] Only one .dockerignore file at the source folder (project root) is used.',
|
||||
'[Warn] Additional .dockerignore files are disregarded. Microservices (multicontainer)',
|
||||
'[Warn] apps should place the .dockerignore file alongside the docker-compose.yml file.',
|
||||
'[Warn] See issue: https://github.com/balena-io/balena-cli/issues/1870',
|
||||
'[Warn] See also CLI v12 release notes: https://git.io/Jf7hz',
|
||||
'[Warn] -------------------------------------------------------------------------------',
|
||||
],
|
||||
];
|
||||
if (isWindows) {
|
||||
const fname = path.join(projectPath, 'src', 'windows-crlf.sh');
|
||||
if (isV12()) {
|
||||
expectedResponseLines.push(
|
||||
`[Info] Converting line endings CRLF -> LF for file: ${fname}`,
|
||||
);
|
||||
} else {
|
||||
expectedResponseLines.push(
|
||||
`[Warn] CRLF (Windows) line endings detected in file: ${fname}`,
|
||||
'[Warn] Windows-format line endings were detected in some files. Consider using the `--convert-eol` option.',
|
||||
);
|
||||
}
|
||||
expectedResponseLines.push(
|
||||
`[Info] Converting line endings CRLF -> LF for file: ${fname}`,
|
||||
);
|
||||
}
|
||||
|
||||
await testPushBuildStream({
|
||||
@ -154,6 +158,7 @@ describe('balena push', function () {
|
||||
it('should create the expected tar stream (alternative Dockerfile)', async () => {
|
||||
const projectPath = path.join(projectsPath, 'no-docker-compose', 'basic');
|
||||
const expectedFiles: ExpectedTarStreamFiles = {
|
||||
'src/.dockerignore': { fileSize: 16, type: 'file' },
|
||||
'src/start.sh': { fileSize: 89, type: 'file' },
|
||||
'src/windows-crlf.sh': { fileSize: 70, type: 'file' },
|
||||
Dockerfile: { fileSize: 88, type: 'file' },
|
||||
@ -165,6 +170,19 @@ describe('balena push', function () {
|
||||
path.join(builderResponsePath, responseFilename),
|
||||
'utf8',
|
||||
);
|
||||
const expectedResponseLines = [
|
||||
...commonResponseLines[responseFilename],
|
||||
...[
|
||||
'[Warn] The following .dockerignore file(s) will not be used:',
|
||||
`[Warn] * ${path.join(projectPath, 'src', '.dockerignore')}`,
|
||||
'[Warn] Only one .dockerignore file at the source folder (project root) is used.',
|
||||
'[Warn] Additional .dockerignore files are disregarded. Microservices (multicontainer)',
|
||||
'[Warn] apps should place the .dockerignore file alongside the docker-compose.yml file.',
|
||||
'[Warn] See issue: https://github.com/balena-io/balena-cli/issues/1870',
|
||||
'[Warn] See also CLI v12 release notes: https://git.io/Jf7hz',
|
||||
'[Warn] -------------------------------------------------------------------------------',
|
||||
],
|
||||
];
|
||||
const expectedQueryParams = commonQueryParams.map((i) =>
|
||||
i[0] === 'dockerfilePath' ? ['dockerfilePath', 'Dockerfile-alt'] : i,
|
||||
);
|
||||
@ -174,7 +192,7 @@ describe('balena push', function () {
|
||||
commandLine: `push testApp -s ${projectPath} -R ${regSecretsPath} --dockerfile Dockerfile-alt --noconvert-eol`,
|
||||
expectedFiles,
|
||||
expectedQueryParams,
|
||||
expectedResponseLines: commonResponseLines[responseFilename],
|
||||
expectedResponseLines,
|
||||
projectPath,
|
||||
responseBody,
|
||||
responseCode: 200,
|
||||
@ -183,12 +201,11 @@ describe('balena push', function () {
|
||||
|
||||
it('should create the expected tar stream (single container, --[no]convert-eol)', async () => {
|
||||
const projectPath = path.join(projectsPath, 'no-docker-compose', 'basic');
|
||||
const eol = isWindows && !isV12();
|
||||
const expectedFiles: ExpectedTarStreamFiles = {
|
||||
'src/.dockerignore': { fileSize: 16, type: 'file' },
|
||||
'src/start.sh': { fileSize: 89, type: 'file' },
|
||||
'src/windows-crlf.sh': {
|
||||
fileSize: eol ? 68 : 70,
|
||||
testStream: eol ? expectStreamNoCRLF : undefined,
|
||||
fileSize: 70,
|
||||
type: 'file',
|
||||
},
|
||||
Dockerfile: { fileSize: 88, type: 'file' },
|
||||
@ -200,26 +217,30 @@ describe('balena push', function () {
|
||||
path.join(builderResponsePath, responseFilename),
|
||||
'utf8',
|
||||
);
|
||||
const expectedResponseLines = [...commonResponseLines[responseFilename]];
|
||||
const expectedResponseLines = [
|
||||
...commonResponseLines[responseFilename],
|
||||
...[
|
||||
'[Warn] The following .dockerignore file(s) will not be used:',
|
||||
`[Warn] * ${path.join(projectPath, 'src', '.dockerignore')}`,
|
||||
'[Warn] Only one .dockerignore file at the source folder (project root) is used.',
|
||||
'[Warn] Additional .dockerignore files are disregarded. Microservices (multicontainer)',
|
||||
'[Warn] apps should place the .dockerignore file alongside the docker-compose.yml file.',
|
||||
'[Warn] See issue: https://github.com/balena-io/balena-cli/issues/1870',
|
||||
'[Warn] See also CLI v12 release notes: https://git.io/Jf7hz',
|
||||
'[Warn] -------------------------------------------------------------------------------',
|
||||
],
|
||||
];
|
||||
if (isWindows) {
|
||||
const fname = path.join(projectPath, 'src', 'windows-crlf.sh');
|
||||
if (isV12()) {
|
||||
expectedResponseLines.push(
|
||||
`[Warn] CRLF (Windows) line endings detected in file: ${fname}`,
|
||||
'[Warn] Windows-format line endings were detected in some files, but were not converted due to `--noconvert-eol` option.',
|
||||
);
|
||||
} else {
|
||||
expectedResponseLines.push(
|
||||
`[Info] Converting line endings CRLF -> LF for file: ${fname}`,
|
||||
);
|
||||
}
|
||||
expectedResponseLines.push(
|
||||
`[Warn] CRLF (Windows) line endings detected in file: ${fname}`,
|
||||
'[Warn] Windows-format line endings were detected in some files, but were not converted due to `--noconvert-eol` option.',
|
||||
);
|
||||
}
|
||||
|
||||
await testPushBuildStream({
|
||||
builderMock: builder,
|
||||
commandLine: isV12()
|
||||
? `push testApp -s ${projectPath} -R ${regSecretsPath} --noconvert-eol`
|
||||
: `push testApp -s ${projectPath} -R ${regSecretsPath} -l`,
|
||||
commandLine: `push testApp -s ${projectPath} -R ${regSecretsPath} --noconvert-eol`,
|
||||
expectedFiles,
|
||||
expectedQueryParams: commonQueryParams,
|
||||
expectedResponseLines,
|
||||
@ -269,17 +290,15 @@ describe('balena push', function () {
|
||||
'utf8',
|
||||
);
|
||||
const expectedResponseLines = [
|
||||
...(isV12()
|
||||
? [
|
||||
'[Warn] Using file ignore patterns from:',
|
||||
`[Warn] ${path.join(projectPath, '.dockerignore')}`,
|
||||
`[Warn] ${path.join(projectPath, '.gitignore')}`,
|
||||
`[Warn] ${path.join(projectPath, 'src', '.gitignore')}`,
|
||||
'[Warn] Note: .gitignore files are being considered because the --gitignore option was',
|
||||
'[Warn] used. This option is deprecated and will be removed in the next major version',
|
||||
"[Warn] release. For more information, see 'balena help push'.",
|
||||
]
|
||||
: []),
|
||||
...[
|
||||
'[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'.",
|
||||
],
|
||||
...commonResponseLines[responseFilename],
|
||||
];
|
||||
|
||||
@ -394,12 +413,12 @@ describe('balena push', function () {
|
||||
const expectedResponseLines = isWindows
|
||||
? [
|
||||
'[Warn] Using file ignore patterns from:',
|
||||
`[Warn] ${path.join(projectPath, '.dockerignore')}`,
|
||||
'[Warn] The --gitignore option was used, but not .gitignore files were found.',
|
||||
`[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] with 'docker build'. For more information, see 'balena help push'.",
|
||||
...commonResponseLines[responseFilename],
|
||||
]
|
||||
: commonResponseLines[responseFilename];
|
||||
@ -425,6 +444,7 @@ describe('balena push', function () {
|
||||
'service1/Dockerfile.template': { fileSize: 144, type: 'file' },
|
||||
'service1/file1.sh': { fileSize: 12, type: 'file' },
|
||||
'service2/Dockerfile-alt': { fileSize: 40, type: 'file' },
|
||||
'service2/.dockerignore': { fileSize: 14, type: 'file' },
|
||||
'service2/file2-crlf.sh': {
|
||||
fileSize: isWindows ? 12 : 14,
|
||||
testStream: isWindows ? expectStreamNoCRLF : undefined,
|
||||
@ -439,6 +459,16 @@ describe('balena push', function () {
|
||||
);
|
||||
const expectedResponseLines: string[] = [
|
||||
...commonResponseLines[responseFilename],
|
||||
...[
|
||||
'[Warn] The following .dockerignore file(s) will not be used:',
|
||||
`[Warn] * ${path.join(projectPath, 'service2', '.dockerignore')}`,
|
||||
'[Warn] Only one .dockerignore file at the source folder (project root) is used.',
|
||||
'[Warn] Additional .dockerignore files are disregarded. Microservices (multicontainer)',
|
||||
'[Warn] apps should place the .dockerignore file alongside the docker-compose.yml file.',
|
||||
'[Warn] See issue: https://github.com/balena-io/balena-cli/issues/1870',
|
||||
'[Warn] See also CLI v12 release notes: https://git.io/Jf7hz',
|
||||
'[Warn] -------------------------------------------------------------------------------',
|
||||
],
|
||||
];
|
||||
if (isWindows) {
|
||||
expectedResponseLines.push(
|
||||
@ -508,24 +538,16 @@ describe('balena push: project validation', function () {
|
||||
'basic',
|
||||
'service1',
|
||||
);
|
||||
const expectedErrorLines = isV12()
|
||||
? [
|
||||
'Error: "docker-compose.y[a]ml" file found in parent directory: please check that',
|
||||
"the correct source folder was specified. (Suppress with '--noparent-check'.)",
|
||||
]
|
||||
: ['The --nolive flag is only valid when pushing to a local mode device'];
|
||||
const expectedOutputLines = isV12()
|
||||
? []
|
||||
: [
|
||||
'[Warn] "docker-compose.y[a]ml" file found in parent directory: please check that',
|
||||
"[Warn] the correct source folder was specified. (Suppress with '--noparent-check'.)",
|
||||
];
|
||||
const expectedErrorLines = [
|
||||
'Error: "docker-compose.y[a]ml" file found in parent directory: please check that',
|
||||
"the correct source folder was specified. (Suppress with '--noparent-check'.)",
|
||||
];
|
||||
|
||||
const { out, err } = await runCommand(
|
||||
`push testApp --source ${projectPath} --nolive`,
|
||||
);
|
||||
expect(cleanOutput(err, true)).to.include.members(expectedErrorLines);
|
||||
expect(cleanOutput(out, true)).to.include.members(expectedOutputLines);
|
||||
expect(out).to.be.empty;
|
||||
});
|
||||
|
||||
it('should suppress a parent folder check with --noparent-check', async () => {
|
||||
|
@ -0,0 +1 @@
|
||||
file2-crlf.sh
|
@ -0,0 +1 @@
|
||||
windows-crlf.sh
|
Loading…
Reference in New Issue
Block a user