mirror of
https://github.com/balena-io/balena-cli.git
synced 2024-12-30 02:28:51 +00:00
Update 'balena-lint' and apply new prettier rules
Change-type: patch
This commit is contained in:
parent
19c3069b22
commit
c619bd4b99
automation
lib
actions-oclif
actions
app-capitano.jsapp-common.tsapp-oclif.tsauth
errors.tsevents.tshooks/prerun
preparser.tsutils
tests
@ -118,7 +118,7 @@ async function buildPkg() {
|
|||||||
|
|
||||||
console.log(`\nCopying to build-bin:\n${nativeExtensionPaths.join('\n')}`);
|
console.log(`\nCopying to build-bin:\n${nativeExtensionPaths.join('\n')}`);
|
||||||
|
|
||||||
await Bluebird.map(nativeExtensionPaths, extPath =>
|
await Bluebird.map(nativeExtensionPaths, (extPath) =>
|
||||||
fs.copy(
|
fs.copy(
|
||||||
extPath,
|
extPath,
|
||||||
extPath.replace(
|
extPath.replace(
|
||||||
@ -268,7 +268,7 @@ export async function buildOclifInstaller() {
|
|||||||
}
|
}
|
||||||
for (const dir of dirs) {
|
for (const dir of dirs) {
|
||||||
console.log(`rimraf(${dir})`);
|
console.log(`rimraf(${dir})`);
|
||||||
await Bluebird.fromCallback(cb => rimraf(dir, cb));
|
await Bluebird.fromCallback((cb) => rimraf(dir, cb));
|
||||||
}
|
}
|
||||||
console.log('=======================================================');
|
console.log('=======================================================');
|
||||||
console.log(`oclif-dev "${packCmd}" "${packOpts.join('" "')}"`);
|
console.log(`oclif-dev "${packCmd}" "${packOpts.join('" "')}"`);
|
||||||
|
@ -55,7 +55,7 @@ function renderOclifCommand(command: OclifCommand): string[] {
|
|||||||
result.push(description);
|
result.push(description);
|
||||||
|
|
||||||
if (!_.isEmpty(command.examples)) {
|
if (!_.isEmpty(command.examples)) {
|
||||||
result.push('Examples:', command.examples!.map(v => `\t${v}`).join('\n'));
|
result.push('Examples:', command.examples!.map((v) => `\t${v}`).join('\n'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_.isEmpty(command.args)) {
|
if (!_.isEmpty(command.args)) {
|
||||||
@ -106,7 +106,7 @@ function renderToc(categories: Category[]): string[] {
|
|||||||
result.push(`- ${category.title}`);
|
result.push(`- ${category.title}`);
|
||||||
result.push(
|
result.push(
|
||||||
category.commands
|
category.commands
|
||||||
.map(command => {
|
.map((command) => {
|
||||||
const signature =
|
const signature =
|
||||||
typeof command === 'object'
|
typeof command === 'object'
|
||||||
? command.signature // Capitano
|
? command.signature // Capitano
|
||||||
@ -139,10 +139,7 @@ function sortCommands(doc: Document): void {
|
|||||||
(cmd: CapitanoCommand | OclifCommand, x: string) =>
|
(cmd: CapitanoCommand | OclifCommand, x: string) =>
|
||||||
typeof cmd === 'object' // Capitano vs oclif command
|
typeof cmd === 'object' // Capitano vs oclif command
|
||||||
? cmd.signature.replace(/\W+/g, ' ').includes(x)
|
? cmd.signature.replace(/\W+/g, ' ').includes(x)
|
||||||
: (cmd.usage || '')
|
: (cmd.usage || '').toString().replace(/\W+/g, ' ').includes(x),
|
||||||
.toString()
|
|
||||||
.replace(/\W+/g, ' ')
|
|
||||||
.includes(x),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@ export class MarkdownFileParser {
|
|||||||
crlfDelay: Infinity,
|
crlfDelay: Infinity,
|
||||||
});
|
});
|
||||||
|
|
||||||
rl.on('line', line => {
|
rl.on('line', (line) => {
|
||||||
// try to match a line like "## Getting Started", where the number
|
// try to match a line like "## Getting Started", where the number
|
||||||
// of '#' characters is the sectionLevel ('##' -> 2), and the
|
// of '#' characters is the sectionLevel ('##' -> 2), and the
|
||||||
// sectionTitle is "Getting Started"
|
// sectionTitle is "Getting Started"
|
||||||
|
@ -40,13 +40,13 @@ async function checkBuildTimestamps() {
|
|||||||
const stagedFiles = _.uniq([
|
const stagedFiles = _.uniq([
|
||||||
...gitStatus.created,
|
...gitStatus.created,
|
||||||
...gitStatus.staged,
|
...gitStatus.staged,
|
||||||
...gitStatus.renamed.map(o => o.to),
|
...gitStatus.renamed.map((o) => o.to),
|
||||||
])
|
])
|
||||||
// select only staged files that start with lib/ or typings/
|
// select only staged files that start with lib/ or typings/
|
||||||
.filter(f => f.match(/^(lib|typings)[/\\]/))
|
.filter((f) => f.match(/^(lib|typings)[/\\]/))
|
||||||
.map(f => path.join(ROOT, f));
|
.map((f) => path.join(ROOT, f));
|
||||||
|
|
||||||
const fStats = await Promise.all(stagedFiles.map(f => fs.stat(f)));
|
const fStats = await Promise.all(stagedFiles.map((f) => fs.stat(f)));
|
||||||
fStats.forEach((fStat, index) => {
|
fStats.forEach((fStat, index) => {
|
||||||
if (fStat.mtimeMs > docStat.mtimeMs) {
|
if (fStat.mtimeMs > docStat.mtimeMs) {
|
||||||
const fPath = stagedFiles[index];
|
const fPath = stagedFiles[index];
|
||||||
|
@ -31,9 +31,7 @@ function semverGte(v1, v2) {
|
|||||||
|
|
||||||
function checkNpmVersion() {
|
function checkNpmVersion() {
|
||||||
const execSync = require('child_process').execSync;
|
const execSync = require('child_process').execSync;
|
||||||
const npmVersion = execSync('npm --version')
|
const npmVersion = execSync('npm --version').toString().trim();
|
||||||
.toString()
|
|
||||||
.trim();
|
|
||||||
const requiredVersion = '6.9.0';
|
const requiredVersion = '6.9.0';
|
||||||
if (!semverGte(npmVersion, requiredVersion)) {
|
if (!semverGte(npmVersion, requiredVersion)) {
|
||||||
// In case you take issue with the error message below:
|
// In case you take issue with the error message below:
|
||||||
|
@ -61,7 +61,7 @@ export async function release() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Return a cached Octokit instance, creating a new one as needed. */
|
/** Return a cached Octokit instance, creating a new one as needed. */
|
||||||
const getOctokit = _.once(function() {
|
const getOctokit = _.once(function () {
|
||||||
const Octokit = (require('@octokit/rest') as typeof import('@octokit/rest')).Octokit.plugin(
|
const Octokit = (require('@octokit/rest') as typeof import('@octokit/rest')).Octokit.plugin(
|
||||||
require('@octokit/plugin-throttling'),
|
require('@octokit/plugin-throttling'),
|
||||||
);
|
);
|
||||||
|
@ -87,7 +87,7 @@ async function main() {
|
|||||||
|
|
||||||
const upstreamName = process.argv[2];
|
const upstreamName = process.argv[2];
|
||||||
|
|
||||||
const upstream = upstreams.find(v => v.repo === upstreamName);
|
const upstream = upstreams.find((v) => v.repo === upstreamName);
|
||||||
|
|
||||||
if (!upstream) {
|
if (!upstream) {
|
||||||
console.error(
|
console.error(
|
||||||
|
@ -50,7 +50,7 @@ export async function runUnderMsys(argv?: string[]) {
|
|||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
const args = ['-lc', shellEscape(newArgv)];
|
const args = ['-lc', shellEscape(newArgv)];
|
||||||
const child = spawn(MSYS2_BASH, args, { stdio: 'inherit' });
|
const child = spawn(MSYS2_BASH, args, { stdio: 'inherit' });
|
||||||
child.on('close', code => {
|
child.on('close', (code) => {
|
||||||
if (code) {
|
if (code) {
|
||||||
console.log(`runUnderMsys: child process exited with code ${code}`);
|
console.log(`runUnderMsys: child process exited with code ${code}`);
|
||||||
reject(code);
|
reject(code);
|
||||||
@ -93,7 +93,7 @@ export async function getSubprocessStdout(
|
|||||||
// every line provided to the stderr stream
|
// every line provided to the stderr stream
|
||||||
const lines = _.filter(
|
const lines = _.filter(
|
||||||
stderr.trim().split(/\r?\n/),
|
stderr.trim().split(/\r?\n/),
|
||||||
line => !line.startsWith('[debug]'),
|
(line) => !line.startsWith('[debug]'),
|
||||||
);
|
);
|
||||||
if (lines.length > 0) {
|
if (lines.length > 0) {
|
||||||
reject(
|
reject(
|
||||||
|
@ -74,9 +74,9 @@ export default class AppsCmd extends Command {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Add extended properties
|
// Add extended properties
|
||||||
applications.forEach(application => {
|
applications.forEach((application) => {
|
||||||
application.device_count = _.size(application.owns__device);
|
application.device_count = _.size(application.owns__device);
|
||||||
application.online_devices = _.sumBy(application.owns__device, d =>
|
application.online_devices = _.sumBy(application.owns__device, (d) =>
|
||||||
d.is_online === true ? 1 : 0,
|
d.is_online === true ? 1 : 0,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -60,13 +60,13 @@ export default class DevicePublicUrlCmd extends Command {
|
|||||||
{
|
{
|
||||||
name: 'uuid',
|
name: 'uuid',
|
||||||
description: 'the uuid of the device to manage',
|
description: 'the uuid of the device to manage',
|
||||||
parse: dev => tryAsInteger(dev),
|
parse: (dev) => tryAsInteger(dev),
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Optional hidden arg to support old command format
|
// Optional hidden arg to support old command format
|
||||||
name: 'legacyUuid',
|
name: 'legacyUuid',
|
||||||
parse: dev => tryAsInteger(dev),
|
parse: (dev) => tryAsInteger(dev),
|
||||||
hidden: true,
|
hidden: true,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -80,7 +80,7 @@ export default class DevicesSupportedCmd extends Command {
|
|||||||
const { flags: options } = this.parse<FlagsDef, {}>(DevicesSupportedCmd);
|
const { flags: options } = this.parse<FlagsDef, {}>(DevicesSupportedCmd);
|
||||||
let deviceTypes: Array<Partial<SDK.DeviceType>> = await getBalenaSdk()
|
let deviceTypes: Array<Partial<SDK.DeviceType>> = await getBalenaSdk()
|
||||||
.models.config.getDeviceTypes()
|
.models.config.getDeviceTypes()
|
||||||
.map(d => {
|
.map((d) => {
|
||||||
if (d.aliases && d.aliases.length) {
|
if (d.aliases && d.aliases.length) {
|
||||||
// remove aliases that are equal to the slug
|
// remove aliases that are equal to the slug
|
||||||
d.aliases = d.aliases.filter((alias: string) => alias !== d.slug);
|
d.aliases = d.aliases.filter((alias: string) => alias !== d.slug);
|
||||||
@ -95,7 +95,7 @@ export default class DevicesSupportedCmd extends Command {
|
|||||||
return d;
|
return d;
|
||||||
});
|
});
|
||||||
if (!options.discontinued) {
|
if (!options.discontinued) {
|
||||||
deviceTypes = deviceTypes.filter(dt => dt.state !== 'DISCONTINUED');
|
deviceTypes = deviceTypes.filter((dt) => dt.state !== 'DISCONTINUED');
|
||||||
}
|
}
|
||||||
const fields = options.verbose
|
const fields = options.verbose
|
||||||
? ['slug', 'aliases', 'arch', 'state', 'name']
|
? ['slug', 'aliases', 'arch', 'state', 'name']
|
||||||
@ -103,7 +103,7 @@ export default class DevicesSupportedCmd extends Command {
|
|||||||
? ['slug', 'aliases', 'arch', 'name']
|
? ['slug', 'aliases', 'arch', 'name']
|
||||||
: ['slug', 'name'];
|
: ['slug', 'name'];
|
||||||
deviceTypes = _.sortBy(
|
deviceTypes = _.sortBy(
|
||||||
deviceTypes.map(d => _.pick(d, fields) as Partial<SDK.DeviceType>),
|
deviceTypes.map((d) => _.pick(d, fields) as Partial<SDK.DeviceType>),
|
||||||
fields,
|
fields,
|
||||||
);
|
);
|
||||||
if (options.json) {
|
if (options.json) {
|
||||||
|
2
lib/actions-oclif/env/add.ts
vendored
2
lib/actions-oclif/env/add.ts
vendored
@ -130,7 +130,7 @@ export default class EnvAddCmd extends Command {
|
|||||||
|
|
||||||
const balena = getBalenaSdk();
|
const balena = getBalenaSdk();
|
||||||
const reservedPrefixes = await getReservedPrefixes(balena);
|
const reservedPrefixes = await getReservedPrefixes(balena);
|
||||||
const isConfigVar = _.some(reservedPrefixes, prefix =>
|
const isConfigVar = _.some(reservedPrefixes, (prefix) =>
|
||||||
_.startsWith(params.name, prefix),
|
_.startsWith(params.name, prefix),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
2
lib/actions-oclif/env/rename.ts
vendored
2
lib/actions-oclif/env/rename.ts
vendored
@ -61,7 +61,7 @@ export default class EnvRenameCmd extends Command {
|
|||||||
name: 'id',
|
name: 'id',
|
||||||
required: true,
|
required: true,
|
||||||
description: "variable's numeric database ID",
|
description: "variable's numeric database ID",
|
||||||
parse: input => parseAsInteger(input, 'id'),
|
parse: (input) => parseAsInteger(input, 'id'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'value',
|
name: 'value',
|
||||||
|
2
lib/actions-oclif/env/rm.ts
vendored
2
lib/actions-oclif/env/rm.ts
vendored
@ -64,7 +64,7 @@ export default class EnvRmCmd extends Command {
|
|||||||
name: 'id',
|
name: 'id',
|
||||||
required: true,
|
required: true,
|
||||||
description: "variable's numeric database ID",
|
description: "variable's numeric database ID",
|
||||||
parse: input => parseAsInteger(input, 'id'),
|
parse: (input) => parseAsInteger(input, 'id'),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ export default class KeyCmd extends Command {
|
|||||||
{
|
{
|
||||||
name: 'id',
|
name: 'id',
|
||||||
description: 'balenaCloud ID for the SSH key',
|
description: 'balenaCloud ID for the SSH key',
|
||||||
parse: x => parseAsInteger(x, 'id'),
|
parse: (x) => parseAsInteger(x, 'id'),
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -48,7 +48,7 @@ export default class KeyRmCmd extends Command {
|
|||||||
{
|
{
|
||||||
name: 'id',
|
name: 'id',
|
||||||
description: 'balenaCloud ID for the SSH key',
|
description: 'balenaCloud ID for the SSH key',
|
||||||
parse: x => parseAsInteger(x, 'id'),
|
parse: (x) => parseAsInteger(x, 'id'),
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -47,7 +47,7 @@ export default class KeysCmd extends Command {
|
|||||||
const keys = await getBalenaSdk().models.key.getAll();
|
const keys = await getBalenaSdk().models.key.getAll();
|
||||||
|
|
||||||
// Use 'name' instead of 'title' to match dashboard.
|
// Use 'name' instead of 'title' to match dashboard.
|
||||||
const displayKeys: Array<{ id: number; name: string }> = keys.map(k => {
|
const displayKeys: Array<{ id: number; name: string }> = keys.map((k) => {
|
||||||
return { id: k.id, name: k.title };
|
return { id: k.id, name: k.title };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -261,7 +261,7 @@ export default class OsConfigureCmd extends Command {
|
|||||||
if (options['system-connection']) {
|
if (options['system-connection']) {
|
||||||
const files = await Bluebird.map(
|
const files = await Bluebird.map(
|
||||||
options['system-connection'],
|
options['system-connection'],
|
||||||
async filePath => {
|
async (filePath) => {
|
||||||
const content = await fs.readFile(filePath, 'utf8');
|
const content = await fs.readFile(filePath, 'utf8');
|
||||||
const name = path.basename(filePath);
|
const name = path.basename(filePath);
|
||||||
|
|
||||||
@ -485,7 +485,7 @@ function camelifyConfigOptions(options: FlagsDef): { [key: string]: any } {
|
|||||||
if (key.startsWith('config-')) {
|
if (key.startsWith('config-')) {
|
||||||
return key
|
return key
|
||||||
.substring('config-'.length)
|
.substring('config-'.length)
|
||||||
.replace(/-[a-z]/g, match => match.substring(1).toUpperCase());
|
.replace(/-[a-z]/g, (match) => match.substring(1).toUpperCase());
|
||||||
}
|
}
|
||||||
return key;
|
return key;
|
||||||
});
|
});
|
||||||
|
@ -33,10 +33,10 @@ Opts must be an object with the following keys:
|
|||||||
buildEmulated
|
buildEmulated
|
||||||
buildOpts: arguments to forward to docker build command
|
buildOpts: arguments to forward to docker build command
|
||||||
*/
|
*/
|
||||||
const buildProject = function(docker, logger, composeOpts, opts) {
|
const buildProject = function (docker, logger, composeOpts, opts) {
|
||||||
const { loadProject } = require('../utils/compose_ts');
|
const { loadProject } = require('../utils/compose_ts');
|
||||||
return Promise.resolve(loadProject(logger, composeOpts))
|
return Promise.resolve(loadProject(logger, composeOpts))
|
||||||
.then(function(project) {
|
.then(function (project) {
|
||||||
const appType = opts.app?.application_type?.[0];
|
const appType = opts.app?.application_type?.[0];
|
||||||
if (
|
if (
|
||||||
appType != null &&
|
appType != null &&
|
||||||
@ -65,7 +65,7 @@ const buildProject = function(docker, logger, composeOpts, opts) {
|
|||||||
composeOpts.nogitignore,
|
composeOpts.nogitignore,
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.then(function() {
|
.then(function () {
|
||||||
logger.outputDeferredMessages();
|
logger.outputDeferredMessages();
|
||||||
logger.logSuccess('Build succeeded!');
|
logger.logSuccess('Build succeeded!');
|
||||||
})
|
})
|
||||||
@ -154,7 +154,7 @@ Examples:
|
|||||||
|
|
||||||
const { application, arch, deviceType } = options;
|
const { application, arch, deviceType } = options;
|
||||||
|
|
||||||
return Promise.try(function() {
|
return Promise.try(function () {
|
||||||
if (
|
if (
|
||||||
(application == null && (arch == null || deviceType == null)) ||
|
(application == null && (arch == null || deviceType == null)) ||
|
||||||
(application != null && (arch != null || deviceType != null))
|
(application != null && (arch != null || deviceType != null))
|
||||||
@ -175,7 +175,7 @@ Examples:
|
|||||||
registrySecretsPath: options['registry-secrets'],
|
registrySecretsPath: options['registry-secrets'],
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.then(function({ dockerfilePath, registrySecrets }) {
|
.then(function ({ dockerfilePath, registrySecrets }) {
|
||||||
options.dockerfile = dockerfilePath;
|
options.dockerfile = dockerfilePath;
|
||||||
options['registry-secrets'] = registrySecrets;
|
options['registry-secrets'] = registrySecrets;
|
||||||
|
|
||||||
@ -184,11 +184,11 @@ Examples:
|
|||||||
} else {
|
} else {
|
||||||
return helpers
|
return helpers
|
||||||
.getAppWithArch(application)
|
.getAppWithArch(application)
|
||||||
.then(app => [app, app.arch, app.device_type]);
|
.then((app) => [app, app.arch, app.device_type]);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
.then(function([app, resolvedArch, resolvedDeviceType]) {
|
.then(function ([app, resolvedArch, resolvedDeviceType]) {
|
||||||
return Promise.join(
|
return Promise.join(
|
||||||
dockerUtils.getDocker(options),
|
dockerUtils.getDocker(options),
|
||||||
dockerUtils.generateBuildOpts(options),
|
dockerUtils.generateBuildOpts(options),
|
||||||
|
@ -58,8 +58,8 @@ Examples:
|
|||||||
() => options.drive || getVisuals().drive('Select the device drive'),
|
() => options.drive || getVisuals().drive('Select the device drive'),
|
||||||
)
|
)
|
||||||
.tap(umountAsync)
|
.tap(umountAsync)
|
||||||
.then(drive => config.read(drive, options.type))
|
.then((drive) => config.read(drive, options.type))
|
||||||
.tap(configJSON => {
|
.tap((configJSON) => {
|
||||||
console.info(prettyjson.render(configJSON));
|
console.info(prettyjson.render(configJSON));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -105,16 +105,16 @@ Examples:
|
|||||||
() => options.drive || getVisuals().drive('Select the device drive'),
|
() => options.drive || getVisuals().drive('Select the device drive'),
|
||||||
)
|
)
|
||||||
.tap(umountAsync)
|
.tap(umountAsync)
|
||||||
.then(drive =>
|
.then((drive) =>
|
||||||
config
|
config
|
||||||
.read(drive, options.type)
|
.read(drive, options.type)
|
||||||
.then(function(configJSON) {
|
.then(function (configJSON) {
|
||||||
console.info(`Setting ${params.key} to ${params.value}`);
|
console.info(`Setting ${params.key} to ${params.value}`);
|
||||||
_.set(configJSON, params.key, params.value);
|
_.set(configJSON, params.key, params.value);
|
||||||
return configJSON;
|
return configJSON;
|
||||||
})
|
})
|
||||||
.tap(() => umountAsync(drive))
|
.tap(() => umountAsync(drive))
|
||||||
.then(configJSON => config.write(drive, options.type, configJSON)),
|
.then((configJSON) => config.write(drive, options.type, configJSON)),
|
||||||
)
|
)
|
||||||
.tap(() => {
|
.tap(() => {
|
||||||
console.info('Done');
|
console.info('Done');
|
||||||
@ -163,10 +163,10 @@ Examples:
|
|||||||
() => options.drive || getVisuals().drive('Select the device drive'),
|
() => options.drive || getVisuals().drive('Select the device drive'),
|
||||||
)
|
)
|
||||||
.tap(umountAsync)
|
.tap(umountAsync)
|
||||||
.then(drive =>
|
.then((drive) =>
|
||||||
readFileAsync(params.file, 'utf8')
|
readFileAsync(params.file, 'utf8')
|
||||||
.then(JSON.parse)
|
.then(JSON.parse)
|
||||||
.then(configJSON => config.write(drive, options.type, configJSON)),
|
.then((configJSON) => config.write(drive, options.type, configJSON)),
|
||||||
)
|
)
|
||||||
.tap(() => {
|
.tap(() => {
|
||||||
console.info('Done');
|
console.info('Done');
|
||||||
@ -220,12 +220,12 @@ Examples:
|
|||||||
() => options.drive || getVisuals().drive('Select the device drive'),
|
() => options.drive || getVisuals().drive('Select the device drive'),
|
||||||
)
|
)
|
||||||
.tap(umountAsync)
|
.tap(umountAsync)
|
||||||
.then(drive =>
|
.then((drive) =>
|
||||||
config
|
config
|
||||||
.read(drive, options.type)
|
.read(drive, options.type)
|
||||||
.get('uuid')
|
.get('uuid')
|
||||||
.tap(() => umountAsync(drive))
|
.tap(() => umountAsync(drive))
|
||||||
.then(function(uuid) {
|
.then(function (uuid) {
|
||||||
let configureCommand = `os configure ${drive} --device ${uuid}`;
|
let configureCommand = `os configure ${drive} --device ${uuid}`;
|
||||||
if (options.advanced) {
|
if (options.advanced) {
|
||||||
configureCommand += ' --advanced';
|
configureCommand += ' --advanced';
|
||||||
@ -349,14 +349,14 @@ See the help page for examples:
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Promise.try(
|
return Promise.try(
|
||||||
/** @returns {Promise<any>} */ function() {
|
/** @returns {Promise<any>} */ function () {
|
||||||
if (options.device != null) {
|
if (options.device != null) {
|
||||||
return balena.models.device.get(options.device);
|
return balena.models.device.get(options.device);
|
||||||
}
|
}
|
||||||
return balena.models.application.get(options.application);
|
return balena.models.application.get(options.application);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.then(function(resource) {
|
.then(function (resource) {
|
||||||
const deviceType = options.deviceType || resource.device_type;
|
const deviceType = options.deviceType || resource.device_type;
|
||||||
let manifestPromise = balena.models.device.getManifestBySlug(
|
let manifestPromise = balena.models.device.getManifestBySlug(
|
||||||
deviceType,
|
deviceType,
|
||||||
@ -367,8 +367,8 @@ See the help page for examples:
|
|||||||
const appManifestPromise = balena.models.device.getManifestBySlug(
|
const appManifestPromise = balena.models.device.getManifestBySlug(
|
||||||
app.device_type,
|
app.device_type,
|
||||||
);
|
);
|
||||||
manifestPromise = manifestPromise.tap(paramDeviceType =>
|
manifestPromise = manifestPromise.tap((paramDeviceType) =>
|
||||||
appManifestPromise.then(function(appDeviceType) {
|
appManifestPromise.then(function (appDeviceType) {
|
||||||
if (
|
if (
|
||||||
!helpers.areDeviceTypesCompatible(
|
!helpers.areDeviceTypesCompatible(
|
||||||
appDeviceType,
|
appDeviceType,
|
||||||
@ -391,7 +391,7 @@ See the help page for examples:
|
|||||||
// required option, that value is used (and the corresponding question is not asked)
|
// required option, that value is used (and the corresponding question is not asked)
|
||||||
form.run(formOptions, { override: options }),
|
form.run(formOptions, { override: options }),
|
||||||
)
|
)
|
||||||
.then(function(answers) {
|
.then(function (answers) {
|
||||||
answers.version = options.version;
|
answers.version = options.version;
|
||||||
|
|
||||||
if (resource.uuid != null) {
|
if (resource.uuid != null) {
|
||||||
@ -406,7 +406,7 @@ See the help page for examples:
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then(function(config) {
|
.then(function (config) {
|
||||||
if (options.output != null) {
|
if (options.output != null) {
|
||||||
return writeFileAsync(options.output, JSON.stringify(config));
|
return writeFileAsync(options.output, JSON.stringify(config));
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ Opts must be an object with the following keys:
|
|||||||
buildEmulated
|
buildEmulated
|
||||||
buildOpts: arguments to forward to docker build command
|
buildOpts: arguments to forward to docker build command
|
||||||
*/
|
*/
|
||||||
const deployProject = function(docker, logger, composeOpts, opts) {
|
const deployProject = function (docker, logger, composeOpts, opts) {
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const doodles = require('resin-doodles');
|
const doodles = require('resin-doodles');
|
||||||
const sdk = getBalenaSdk();
|
const sdk = getBalenaSdk();
|
||||||
@ -46,7 +46,7 @@ const deployProject = function(docker, logger, composeOpts, opts) {
|
|||||||
} = require('../utils/compose_ts');
|
} = require('../utils/compose_ts');
|
||||||
|
|
||||||
return Promise.resolve(loadProject(logger, composeOpts, opts.image))
|
return Promise.resolve(loadProject(logger, composeOpts, opts.image))
|
||||||
.then(function(project) {
|
.then(function (project) {
|
||||||
if (
|
if (
|
||||||
project.descriptors.length > 1 &&
|
project.descriptors.length > 1 &&
|
||||||
!opts.app.application_type?.[0]?.supports_multicontainer
|
!opts.app.application_type?.[0]?.supports_multicontainer
|
||||||
@ -58,7 +58,7 @@ const deployProject = function(docker, logger, composeOpts, opts) {
|
|||||||
|
|
||||||
// find which services use images that already exist locally
|
// find which services use images that already exist locally
|
||||||
return (
|
return (
|
||||||
Promise.map(project.descriptors, function(d) {
|
Promise.map(project.descriptors, function (d) {
|
||||||
// unconditionally build (or pull) if explicitly requested
|
// unconditionally build (or pull) if explicitly requested
|
||||||
if (opts.shouldPerformBuild) {
|
if (opts.shouldPerformBuild) {
|
||||||
return d;
|
return d;
|
||||||
@ -69,8 +69,8 @@ const deployProject = function(docker, logger, composeOpts, opts) {
|
|||||||
.return(d.serviceName)
|
.return(d.serviceName)
|
||||||
.catchReturn();
|
.catchReturn();
|
||||||
})
|
})
|
||||||
.filter(d => !!d)
|
.filter((d) => !!d)
|
||||||
.then(function(servicesToSkip) {
|
.then(function (servicesToSkip) {
|
||||||
// multibuild takes in a composition and always attempts to
|
// multibuild takes in a composition and always attempts to
|
||||||
// build or pull all services. we workaround that here by
|
// build or pull all services. we workaround that here by
|
||||||
// passing a modified composition.
|
// passing a modified composition.
|
||||||
@ -101,11 +101,11 @@ const deployProject = function(docker, logger, composeOpts, opts) {
|
|||||||
composeOpts.dockerfilePath,
|
composeOpts.dockerfilePath,
|
||||||
composeOpts.nogitignore,
|
composeOpts.nogitignore,
|
||||||
)
|
)
|
||||||
.then(builtImages => _.keyBy(builtImages, 'serviceName'));
|
.then((builtImages) => _.keyBy(builtImages, 'serviceName'));
|
||||||
})
|
})
|
||||||
.then(builtImages =>
|
.then((builtImages) =>
|
||||||
project.descriptors.map(
|
project.descriptors.map(
|
||||||
d =>
|
(d) =>
|
||||||
builtImages[d.serviceName] ?? {
|
builtImages[d.serviceName] ?? {
|
||||||
serviceName: d.serviceName,
|
serviceName: d.serviceName,
|
||||||
name: typeof d.image === 'string' ? d.image : d.image.tag,
|
name: typeof d.image === 'string' ? d.image : d.image.tag,
|
||||||
@ -115,7 +115,7 @@ const deployProject = function(docker, logger, composeOpts, opts) {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
// @ts-ignore slightly different return types of partial vs non-partial release
|
// @ts-ignore slightly different return types of partial vs non-partial release
|
||||||
.then(function(images) {
|
.then(function (images) {
|
||||||
if (opts.app.application_type?.[0]?.is_legacy) {
|
if (opts.app.application_type?.[0]?.is_legacy) {
|
||||||
const { deployLegacy } = require('../utils/deploy-legacy');
|
const { deployLegacy } = require('../utils/deploy-legacy');
|
||||||
|
|
||||||
@ -138,7 +138,7 @@ const deployProject = function(docker, logger, composeOpts, opts) {
|
|||||||
shouldUploadLogs: opts.shouldUploadLogs,
|
shouldUploadLogs: opts.shouldUploadLogs,
|
||||||
},
|
},
|
||||||
deployLegacy,
|
deployLegacy,
|
||||||
).then(releaseId =>
|
).then((releaseId) =>
|
||||||
// @ts-ignore releaseId should be inferred as a number because that's what deployLegacy is
|
// @ts-ignore releaseId should be inferred as a number because that's what deployLegacy is
|
||||||
// typed as returning but the .js type-checking doesn't manage to infer it correctly due to
|
// typed as returning but the .js type-checking doesn't manage to infer it correctly due to
|
||||||
// Promise.join typings
|
// Promise.join typings
|
||||||
@ -165,7 +165,7 @@ const deployProject = function(docker, logger, composeOpts, opts) {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.then(function(release) {
|
.then(function (release) {
|
||||||
logger.outputDeferredMessages();
|
logger.outputDeferredMessages();
|
||||||
logger.logSuccess('Deploy succeeded!');
|
logger.logSuccess('Deploy succeeded!');
|
||||||
logger.logSuccess(`Release: ${release.commit}`);
|
logger.logSuccess(`Release: ${release.commit}`);
|
||||||
@ -263,7 +263,7 @@ Examples:
|
|||||||
appName = appName_raw || appName || options.application;
|
appName = appName_raw || appName || options.application;
|
||||||
delete options.application;
|
delete options.application;
|
||||||
|
|
||||||
return Promise.try(function() {
|
return Promise.try(function () {
|
||||||
if (appName == null) {
|
if (appName == null) {
|
||||||
throw new ExpectedError(
|
throw new ExpectedError(
|
||||||
'Please specify the name of the application to deploy',
|
'Please specify the name of the application to deploy',
|
||||||
@ -276,10 +276,10 @@ Examples:
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(function() {
|
.then(function () {
|
||||||
if (image) {
|
if (image) {
|
||||||
return getRegistrySecrets(sdk, options['registry-secrets']).then(
|
return getRegistrySecrets(sdk, options['registry-secrets']).then(
|
||||||
registrySecrets => {
|
(registrySecrets) => {
|
||||||
options['registry-secrets'] = registrySecrets;
|
options['registry-secrets'] = registrySecrets;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -289,14 +289,14 @@ Examples:
|
|||||||
noParentCheck: options['noparent-check'] || false,
|
noParentCheck: options['noparent-check'] || false,
|
||||||
projectPath: options.source || '.',
|
projectPath: options.source || '.',
|
||||||
registrySecretsPath: options['registry-secrets'],
|
registrySecretsPath: options['registry-secrets'],
|
||||||
}).then(function({ dockerfilePath, registrySecrets }) {
|
}).then(function ({ dockerfilePath, registrySecrets }) {
|
||||||
options.dockerfile = dockerfilePath;
|
options.dockerfile = dockerfilePath;
|
||||||
options['registry-secrets'] = registrySecrets;
|
options['registry-secrets'] = registrySecrets;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(() => helpers.getAppWithArch(appName))
|
.then(() => helpers.getAppWithArch(appName))
|
||||||
.then(function(app) {
|
.then(function (app) {
|
||||||
return Promise.join(
|
return Promise.join(
|
||||||
dockerUtils.getDocker(options),
|
dockerUtils.getDocker(options),
|
||||||
dockerUtils.generateBuildOpts(options),
|
dockerUtils.generateBuildOpts(options),
|
||||||
|
@ -47,7 +47,7 @@ Examples:
|
|||||||
const Promise = require('bluebird');
|
const Promise = require('bluebird');
|
||||||
const balena = getBalenaSdk();
|
const balena = getBalenaSdk();
|
||||||
|
|
||||||
return Promise.try(function() {
|
return Promise.try(function () {
|
||||||
if (options.application != null) {
|
if (options.application != null) {
|
||||||
return balena.models.device.getAllByApplication(
|
return balena.models.device.getAllByApplication(
|
||||||
options.application,
|
options.application,
|
||||||
@ -55,8 +55,8 @@ Examples:
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
return balena.models.device.getAll(expandForAppName);
|
return balena.models.device.getAll(expandForAppName);
|
||||||
}).tap(function(devices) {
|
}).tap(function (devices) {
|
||||||
devices = _.map(devices, function(device) {
|
devices = _.map(devices, function (device) {
|
||||||
// @ts-ignore extending the device object with extra props
|
// @ts-ignore extending the device object with extra props
|
||||||
device.dashboard_url = balena.models.device.getDashboardUrl(
|
device.dashboard_url = balena.models.device.getDashboardUrl(
|
||||||
device.uuid,
|
device.uuid,
|
||||||
@ -105,10 +105,10 @@ Examples:
|
|||||||
|
|
||||||
return balena.models.device
|
return balena.models.device
|
||||||
.get(params.uuid, expandForAppName)
|
.get(params.uuid, expandForAppName)
|
||||||
.then(device =>
|
.then((device) =>
|
||||||
// @ts-ignore `device.getStatus` requires a device with service info, but
|
// @ts-ignore `device.getStatus` requires a device with service info, but
|
||||||
// this device isn't typed with them, possibly needs fixing?
|
// this device isn't typed with them, possibly needs fixing?
|
||||||
balena.models.device.getStatus(params.uuid).then(function(status) {
|
balena.models.device.getStatus(params.uuid).then(function (status) {
|
||||||
device.status = status;
|
device.status = status;
|
||||||
// @ts-ignore extending the device object with extra props
|
// @ts-ignore extending the device object with extra props
|
||||||
device.dashboard_url = balena.models.device.getDashboardUrl(
|
device.dashboard_url = balena.models.device.getDashboardUrl(
|
||||||
@ -173,7 +173,7 @@ Examples:
|
|||||||
return Promise.join(
|
return Promise.join(
|
||||||
balena.models.application.get(params.application),
|
balena.models.application.get(params.application),
|
||||||
options.uuid ?? balena.models.device.generateUniqueKey(),
|
options.uuid ?? balena.models.device.generateUniqueKey(),
|
||||||
function(application, uuid) {
|
function (application, uuid) {
|
||||||
console.info(`Registering to ${application.app_name}: ${uuid}`);
|
console.info(`Registering to ${application.app_name}: ${uuid}`);
|
||||||
return balena.models.device.register(application.id, uuid);
|
return balena.models.device.register(application.id, uuid);
|
||||||
},
|
},
|
||||||
@ -286,7 +286,7 @@ Examples:
|
|||||||
const balena = getBalenaSdk();
|
const balena = getBalenaSdk();
|
||||||
const form = require('resin-cli-form');
|
const form = require('resin-cli-form');
|
||||||
|
|
||||||
return Promise.try(function() {
|
return Promise.try(function () {
|
||||||
if (!_.isEmpty(params.newName)) {
|
if (!_.isEmpty(params.newName)) {
|
||||||
return params.newName;
|
return params.newName;
|
||||||
}
|
}
|
||||||
@ -321,7 +321,7 @@ Examples:
|
|||||||
|
|
||||||
return balena.models.device
|
return balena.models.device
|
||||||
.get(params.uuid, expandForAppName)
|
.get(params.uuid, expandForAppName)
|
||||||
.then(function(device) {
|
.then(function (device) {
|
||||||
// @ts-ignore extending the device object with extra props
|
// @ts-ignore extending the device object with extra props
|
||||||
device.application_name = device.belongs_to__application?.[0]
|
device.application_name = device.belongs_to__application?.[0]
|
||||||
? device.belongs_to__application[0].app_name
|
? device.belongs_to__application[0].app_name
|
||||||
@ -333,9 +333,9 @@ Examples:
|
|||||||
return Promise.all([
|
return Promise.all([
|
||||||
balena.models.device.getManifestBySlug(device.device_type),
|
balena.models.device.getManifestBySlug(device.device_type),
|
||||||
balena.models.config.getDeviceTypes(),
|
balena.models.config.getDeviceTypes(),
|
||||||
]).then(function([deviceDeviceType, deviceTypes]) {
|
]).then(function ([deviceDeviceType, deviceTypes]) {
|
||||||
const compatibleDeviceTypes = deviceTypes.filter(
|
const compatibleDeviceTypes = deviceTypes.filter(
|
||||||
dt =>
|
(dt) =>
|
||||||
balena.models.os.isArchitectureCompatibleWith(
|
balena.models.os.isArchitectureCompatibleWith(
|
||||||
deviceDeviceType.arch,
|
deviceDeviceType.arch,
|
||||||
dt.arch,
|
dt.arch,
|
||||||
@ -344,11 +344,11 @@ Examples:
|
|||||||
dt.state !== 'DISCONTINUED',
|
dt.state !== 'DISCONTINUED',
|
||||||
);
|
);
|
||||||
|
|
||||||
return patterns.selectApplication(application =>
|
return patterns.selectApplication((application) =>
|
||||||
_.every([
|
_.every([
|
||||||
_.some(
|
_.some(
|
||||||
compatibleDeviceTypes,
|
compatibleDeviceTypes,
|
||||||
dt => dt.slug === application.device_type,
|
(dt) => dt.slug === application.device_type,
|
||||||
),
|
),
|
||||||
// @ts-ignore using the extended device object prop
|
// @ts-ignore using the extended device object prop
|
||||||
device.application_name !== application.app_name,
|
device.application_name !== application.app_name,
|
||||||
@ -356,8 +356,8 @@ Examples:
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.tap(application => balena.models.device.move(params.uuid, application))
|
.tap((application) => balena.models.device.move(params.uuid, application))
|
||||||
.then(application => {
|
.then((application) => {
|
||||||
console.info(`${params.uuid} was moved to ${application}`);
|
console.info(`${params.uuid} was moved to ${application}`);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -404,28 +404,28 @@ Examples:
|
|||||||
const patterns = require('../utils/patterns');
|
const patterns = require('../utils/patterns');
|
||||||
const { runCommand } = require('../utils/helpers');
|
const { runCommand } = require('../utils/helpers');
|
||||||
|
|
||||||
return Promise.try(function() {
|
return Promise.try(function () {
|
||||||
if (options.application != null) {
|
if (options.application != null) {
|
||||||
return options.application;
|
return options.application;
|
||||||
}
|
}
|
||||||
return patterns.selectApplication();
|
return patterns.selectApplication();
|
||||||
})
|
})
|
||||||
.then(balena.models.application.get)
|
.then(balena.models.application.get)
|
||||||
.then(function(application) {
|
.then(function (application) {
|
||||||
const download = () =>
|
const download = () =>
|
||||||
tmpNameAsync()
|
tmpNameAsync()
|
||||||
.then(function(tempPath) {
|
.then(function (tempPath) {
|
||||||
const osVersion = options['os-version'] || 'default';
|
const osVersion = options['os-version'] || 'default';
|
||||||
return runCommand(
|
return runCommand(
|
||||||
`os download ${application.device_type} --output '${tempPath}' --version ${osVersion}`,
|
`os download ${application.device_type} --output '${tempPath}' --version ${osVersion}`,
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.disposer(tempPath => rimraf(tempPath));
|
.disposer((tempPath) => rimraf(tempPath));
|
||||||
|
|
||||||
return Promise.using(download(), tempPath =>
|
return Promise.using(download(), (tempPath) =>
|
||||||
runCommand(`device register ${application.app_name}`)
|
runCommand(`device register ${application.app_name}`)
|
||||||
.then(balena.models.device.get)
|
.then(balena.models.device.get)
|
||||||
.tap(function(device) {
|
.tap(function (device) {
|
||||||
let configureCommand = `os configure '${tempPath}' --device ${device.uuid}`;
|
let configureCommand = `os configure '${tempPath}' --device ${device.uuid}`;
|
||||||
if (options.config) {
|
if (options.config) {
|
||||||
configureCommand += ` --config '${options.config}'`;
|
configureCommand += ` --config '${options.config}'`;
|
||||||
@ -433,7 +433,7 @@ Examples:
|
|||||||
configureCommand += ' --advanced';
|
configureCommand += ' --advanced';
|
||||||
}
|
}
|
||||||
return runCommand(configureCommand)
|
return runCommand(configureCommand)
|
||||||
.then(function() {
|
.then(function () {
|
||||||
let osInitCommand = `os initialize '${tempPath}' --type ${application.device_type}`;
|
let osInitCommand = `os initialize '${tempPath}' --type ${application.device_type}`;
|
||||||
if (options.yes) {
|
if (options.yes) {
|
||||||
osInitCommand += ' --yes';
|
osInitCommand += ' --yes';
|
||||||
@ -443,13 +443,13 @@ Examples:
|
|||||||
}
|
}
|
||||||
return runCommand(osInitCommand);
|
return runCommand(osInitCommand);
|
||||||
})
|
})
|
||||||
.catch(error =>
|
.catch((error) =>
|
||||||
balena.models.device.remove(device.uuid).finally(function() {
|
balena.models.device.remove(device.uuid).finally(function () {
|
||||||
throw error;
|
throw error;
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
).then(function(device) {
|
).then(function (device) {
|
||||||
console.log('Done');
|
console.log('Done');
|
||||||
return device.uuid;
|
return device.uuid;
|
||||||
});
|
});
|
||||||
|
@ -100,7 +100,7 @@ export const osUpdate: CommandDefinition<OsUpdate.Args, OsUpdate.Options> = {
|
|||||||
targetOsVersion = await form.ask({
|
targetOsVersion = await form.ask({
|
||||||
message: 'Target OS version',
|
message: 'Target OS version',
|
||||||
type: 'list',
|
type: 'list',
|
||||||
choices: hupVersionInfo.versions.map(version => ({
|
choices: hupVersionInfo.versions.map((version) => ({
|
||||||
name:
|
name:
|
||||||
hupVersionInfo.recommended === version
|
hupVersionInfo.recommended === version
|
||||||
? `${version} (recommended)`
|
? `${version} (recommended)`
|
||||||
|
@ -23,8 +23,8 @@ import { getManualSortCompareFunction } from '../utils/helpers';
|
|||||||
import { exitWithExpectedError } from '../errors';
|
import { exitWithExpectedError } from '../errors';
|
||||||
import { getOclifHelpLinePairs } from './help_ts';
|
import { getOclifHelpLinePairs } from './help_ts';
|
||||||
|
|
||||||
const parse = object =>
|
const parse = (object) =>
|
||||||
_.map(object, function(item) {
|
_.map(object, function (item) {
|
||||||
// Hacky way to determine if an object is
|
// Hacky way to determine if an object is
|
||||||
// a function or a command
|
// a function or a command
|
||||||
let signature;
|
let signature;
|
||||||
@ -37,12 +37,12 @@ const parse = object =>
|
|||||||
return [signature, item.description];
|
return [signature, item.description];
|
||||||
});
|
});
|
||||||
|
|
||||||
const indent = function(text) {
|
const indent = function (text) {
|
||||||
text = _.map(text.split('\n'), line => ' ' + line);
|
text = _.map(text.split('\n'), (line) => ' ' + line);
|
||||||
return text.join('\n');
|
return text.join('\n');
|
||||||
};
|
};
|
||||||
|
|
||||||
const print = usageDescriptionPairs =>
|
const print = (usageDescriptionPairs) =>
|
||||||
console.log(
|
console.log(
|
||||||
indent(
|
indent(
|
||||||
columnify(_.fromPairs(usageDescriptionPairs), {
|
columnify(_.fromPairs(usageDescriptionPairs), {
|
||||||
@ -71,7 +71,7 @@ const manuallySortedPrimaryCommands = [
|
|||||||
'local scan',
|
'local scan',
|
||||||
];
|
];
|
||||||
|
|
||||||
const general = function(_params, options, done) {
|
const general = function (_params, options, done) {
|
||||||
console.log('Usage: balena [COMMAND] [OPTIONS]\n');
|
console.log('Usage: balena [COMMAND] [OPTIONS]\n');
|
||||||
|
|
||||||
console.log('Primary commands:\n');
|
console.log('Primary commands:\n');
|
||||||
@ -79,10 +79,10 @@ const general = function(_params, options, done) {
|
|||||||
// We do not want the wildcard command
|
// We do not want the wildcard command
|
||||||
// to be printed in the help screen.
|
// to be printed in the help screen.
|
||||||
const commands = capitano.state.commands.filter(
|
const commands = capitano.state.commands.filter(
|
||||||
command => !command.hidden && !command.isWildcard(),
|
(command) => !command.hidden && !command.isWildcard(),
|
||||||
);
|
);
|
||||||
|
|
||||||
const capitanoCommands = _.groupBy(commands, function(command) {
|
const capitanoCommands = _.groupBy(commands, function (command) {
|
||||||
if (command.primary) {
|
if (command.primary) {
|
||||||
return 'primary';
|
return 'primary';
|
||||||
}
|
}
|
||||||
@ -90,11 +90,11 @@ const general = function(_params, options, done) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return getOclifHelpLinePairs()
|
return getOclifHelpLinePairs()
|
||||||
.then(function(oclifHelpLinePairs) {
|
.then(function (oclifHelpLinePairs) {
|
||||||
const primaryHelpLinePairs = parse(capitanoCommands.primary)
|
const primaryHelpLinePairs = parse(capitanoCommands.primary)
|
||||||
.concat(oclifHelpLinePairs.primary)
|
.concat(oclifHelpLinePairs.primary)
|
||||||
.sort(
|
.sort(
|
||||||
getManualSortCompareFunction(manuallySortedPrimaryCommands, function(
|
getManualSortCompareFunction(manuallySortedPrimaryCommands, function (
|
||||||
[signature],
|
[signature],
|
||||||
manualItem,
|
manualItem,
|
||||||
) {
|
) {
|
||||||
@ -133,7 +133,7 @@ const general = function(_params, options, done) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const commandHelp = (params, _options, done) =>
|
const commandHelp = (params, _options, done) =>
|
||||||
capitano.state.getMatchCommand(params.command, function(error, command) {
|
capitano.state.getMatchCommand(params.command, function (error, command) {
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
return done(error);
|
return done(error);
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import { getChalk } from '../../utils/lazy';
|
|||||||
export const dockerPort = 2375;
|
export const dockerPort = 2375;
|
||||||
export const dockerTimeout = 2000;
|
export const dockerTimeout = 2000;
|
||||||
|
|
||||||
export const filterOutSupervisorContainer = function(container) {
|
export const filterOutSupervisorContainer = function (container) {
|
||||||
for (const name of container.Names) {
|
for (const name of container.Names) {
|
||||||
if (
|
if (
|
||||||
name.includes('resin_supervisor') ||
|
name.includes('resin_supervisor') ||
|
||||||
@ -19,7 +19,7 @@ export const filterOutSupervisorContainer = function(container) {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const selectContainerFromDevice = Promise.method(function(
|
export const selectContainerFromDevice = Promise.method(function (
|
||||||
deviceIp,
|
deviceIp,
|
||||||
filterSupervisor,
|
filterSupervisor,
|
||||||
) {
|
) {
|
||||||
@ -34,8 +34,8 @@ export const selectContainerFromDevice = Promise.method(function(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// List all containers, including those not running
|
// List all containers, including those not running
|
||||||
return docker.listContainers({ all: true }).then(function(containers) {
|
return docker.listContainers({ all: true }).then(function (containers) {
|
||||||
containers = containers.filter(function(container) {
|
containers = containers.filter(function (container) {
|
||||||
if (!filterSupervisor) {
|
if (!filterSupervisor) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -48,7 +48,7 @@ export const selectContainerFromDevice = Promise.method(function(
|
|||||||
return form.ask({
|
return form.ask({
|
||||||
message: 'Select a container',
|
message: 'Select a container',
|
||||||
type: 'list',
|
type: 'list',
|
||||||
choices: _.map(containers, function(container) {
|
choices: _.map(containers, function (container) {
|
||||||
const containerName = container.Names?.[0] || 'Untitled';
|
const containerName = container.Names?.[0] || 'Untitled';
|
||||||
const shortContainerId = ('' + container.Id).substr(0, 11);
|
const shortContainerId = ('' + container.Id).substr(0, 11);
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ export const selectContainerFromDevice = Promise.method(function(
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
export const pipeContainerStream = Promise.method(function({
|
export const pipeContainerStream = Promise.method(function ({
|
||||||
deviceIp,
|
deviceIp,
|
||||||
name,
|
name,
|
||||||
outStream,
|
outStream,
|
||||||
@ -75,8 +75,8 @@ export const pipeContainerStream = Promise.method(function({
|
|||||||
const container = docker.getContainer(name);
|
const container = docker.getContainer(name);
|
||||||
return container
|
return container
|
||||||
.inspect()
|
.inspect()
|
||||||
.then(containerInfo => containerInfo?.State?.Running)
|
.then((containerInfo) => containerInfo?.State?.Running)
|
||||||
.then(isRunning =>
|
.then((isRunning) =>
|
||||||
container.attach({
|
container.attach({
|
||||||
logs: !follow || !isRunning,
|
logs: !follow || !isRunning,
|
||||||
stream: follow && isRunning,
|
stream: follow && isRunning,
|
||||||
@ -84,8 +84,8 @@ export const pipeContainerStream = Promise.method(function({
|
|||||||
stderr: true,
|
stderr: true,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.then(containerStream => containerStream.pipe(outStream))
|
.then((containerStream) => containerStream.pipe(outStream))
|
||||||
.catch(function(err) {
|
.catch(function (err) {
|
||||||
err = '' + err.statusCode;
|
err = '' + err.statusCode;
|
||||||
if (err === '404') {
|
if (err === '404') {
|
||||||
return console.log(
|
return console.log(
|
||||||
|
@ -17,7 +17,7 @@ limitations under the License.
|
|||||||
const BOOT_PARTITION = 1;
|
const BOOT_PARTITION = 1;
|
||||||
const CONNECTIONS_FOLDER = '/system-connections';
|
const CONNECTIONS_FOLDER = '/system-connections';
|
||||||
|
|
||||||
const getConfigurationSchema = function(connnectionFileName) {
|
const getConfigurationSchema = function (connnectionFileName) {
|
||||||
if (connnectionFileName == null) {
|
if (connnectionFileName == null) {
|
||||||
connnectionFileName = 'resin-wifi';
|
connnectionFileName = 'resin-wifi';
|
||||||
}
|
}
|
||||||
@ -72,7 +72,7 @@ const getConfigurationSchema = function(connnectionFileName) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const inquirerOptions = data => [
|
const inquirerOptions = (data) => [
|
||||||
{
|
{
|
||||||
message: 'Network SSID',
|
message: 'Network SSID',
|
||||||
type: 'input',
|
type: 'input',
|
||||||
@ -111,7 +111,7 @@ const inquirerOptions = data => [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const getConfiguration = function(data) {
|
const getConfiguration = function (data) {
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const inquirer = require('inquirer');
|
const inquirer = require('inquirer');
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ const getConfiguration = function(data) {
|
|||||||
|
|
||||||
return inquirer
|
return inquirer
|
||||||
.prompt(inquirerOptions(data))
|
.prompt(inquirerOptions(data))
|
||||||
.then(answers => _.merge(data, answers));
|
.then((answers) => _.merge(data, answers));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Taken from https://goo.gl/kr1kCt
|
// Taken from https://goo.gl/kr1kCt
|
||||||
@ -154,7 +154,7 @@ method=auto\
|
|||||||
* if the `resin-sample` exists it's reconfigured (legacy mode, will be removed eventually)
|
* if the `resin-sample` exists it's reconfigured (legacy mode, will be removed eventually)
|
||||||
* otherwise, the new file is created
|
* otherwise, the new file is created
|
||||||
*/
|
*/
|
||||||
const prepareConnectionFile = function(target) {
|
const prepareConnectionFile = function (target) {
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const imagefs = require('resin-image-fs');
|
const imagefs = require('resin-image-fs');
|
||||||
|
|
||||||
@ -164,7 +164,7 @@ const prepareConnectionFile = function(target) {
|
|||||||
partition: BOOT_PARTITION,
|
partition: BOOT_PARTITION,
|
||||||
path: CONNECTIONS_FOLDER,
|
path: CONNECTIONS_FOLDER,
|
||||||
})
|
})
|
||||||
.then(function(files) {
|
.then(function (files) {
|
||||||
// The required file already exists
|
// The required file already exists
|
||||||
if (_.includes(files, 'resin-wifi')) {
|
if (_.includes(files, 'resin-wifi')) {
|
||||||
return null;
|
return null;
|
||||||
@ -211,12 +211,12 @@ const prepareConnectionFile = function(target) {
|
|||||||
)
|
)
|
||||||
.thenReturn(null);
|
.thenReturn(null);
|
||||||
})
|
})
|
||||||
.then(connectionFileName => getConfigurationSchema(connectionFileName));
|
.then((connectionFileName) => getConfigurationSchema(connectionFileName));
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeHostname = function(schema) {
|
const removeHostname = function (schema) {
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
schema.mapper = _.reject(schema.mapper, mapper =>
|
schema.mapper = _.reject(schema.mapper, (mapper) =>
|
||||||
_.isEqual(Object.keys(mapper.template), ['hostname']),
|
_.isEqual(Object.keys(mapper.template), ['hostname']),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -244,14 +244,14 @@ Examples:
|
|||||||
|
|
||||||
return prepareConnectionFile(params.target)
|
return prepareConnectionFile(params.target)
|
||||||
.tap(() =>
|
.tap(() =>
|
||||||
isMountedAsync(params.target).then(function(isMounted) {
|
isMountedAsync(params.target).then(function (isMounted) {
|
||||||
if (!isMounted) {
|
if (!isMounted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return umountAsync(params.target);
|
return umountAsync(params.target);
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.then(function(configurationSchema) {
|
.then(function (configurationSchema) {
|
||||||
const dmOpts = {};
|
const dmOpts = {};
|
||||||
if (process.pkg) {
|
if (process.pkg) {
|
||||||
// when running in a standalone pkg install, the 'denymount'
|
// when running in a standalone pkg install, the 'denymount'
|
||||||
@ -261,11 +261,11 @@ Examples:
|
|||||||
'denymount',
|
'denymount',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const dmHandler = cb =>
|
const dmHandler = (cb) =>
|
||||||
reconfix
|
reconfix
|
||||||
.readConfiguration(configurationSchema, params.target)
|
.readConfiguration(configurationSchema, params.target)
|
||||||
.then(getConfiguration)
|
.then(getConfiguration)
|
||||||
.then(function(answers) {
|
.then(function (answers) {
|
||||||
if (!answers.hostname) {
|
if (!answers.hostname) {
|
||||||
removeHostname(configurationSchema);
|
removeHostname(configurationSchema);
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ import * as commandOptions from './command-options';
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import { getBalenaSdk, getVisuals } from '../utils/lazy';
|
import { getBalenaSdk, getVisuals } from '../utils/lazy';
|
||||||
|
|
||||||
const formatVersion = function(v, isRecommended) {
|
const formatVersion = function (v, isRecommended) {
|
||||||
let result = `v${v}`;
|
let result = `v${v}`;
|
||||||
if (isRecommended) {
|
if (isRecommended) {
|
||||||
result += ' (recommended)';
|
result += ' (recommended)';
|
||||||
@ -27,7 +27,7 @@ const formatVersion = function(v, isRecommended) {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
const resolveVersion = function(deviceType, version) {
|
const resolveVersion = function (deviceType, version) {
|
||||||
if (version !== 'menu') {
|
if (version !== 'menu') {
|
||||||
if (version[0] === 'v') {
|
if (version[0] === 'v') {
|
||||||
version = version.slice(1);
|
version = version.slice(1);
|
||||||
@ -40,8 +40,8 @@ const resolveVersion = function(deviceType, version) {
|
|||||||
|
|
||||||
return balena.models.os
|
return balena.models.os
|
||||||
.getSupportedVersions(deviceType)
|
.getSupportedVersions(deviceType)
|
||||||
.then(function({ versions: vs, recommended }) {
|
.then(function ({ versions: vs, recommended }) {
|
||||||
const choices = vs.map(v => ({
|
const choices = vs.map((v) => ({
|
||||||
value: v,
|
value: v,
|
||||||
name: formatVersion(v, v === recommended),
|
name: formatVersion(v, v === recommended),
|
||||||
}));
|
}));
|
||||||
@ -72,7 +72,7 @@ Example:
|
|||||||
return balena.models.os
|
return balena.models.os
|
||||||
.getSupportedVersions(params.type)
|
.getSupportedVersions(params.type)
|
||||||
.then(({ versions: vs, recommended }) => {
|
.then(({ versions: vs, recommended }) => {
|
||||||
vs.forEach(v => {
|
vs.forEach((v) => {
|
||||||
console.log(formatVersion(v, v === recommended));
|
console.log(formatVersion(v, v === recommended));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -123,7 +123,7 @@ Examples:
|
|||||||
console.info(`Getting device operating system for ${params.type}`);
|
console.info(`Getting device operating system for ${params.type}`);
|
||||||
|
|
||||||
let displayVersion = '';
|
let displayVersion = '';
|
||||||
return Promise.try(function() {
|
return Promise.try(function () {
|
||||||
if (!options.version) {
|
if (!options.version) {
|
||||||
console.warn(`OS version is not specified, using the default version: \
|
console.warn(`OS version is not specified, using the default version: \
|
||||||
the newest stable (non-pre-release) version if available, \
|
the newest stable (non-pre-release) version if available, \
|
||||||
@ -133,13 +133,13 @@ versions for the given device type are pre-release).`);
|
|||||||
}
|
}
|
||||||
return resolveVersion(params.type, options.version);
|
return resolveVersion(params.type, options.version);
|
||||||
})
|
})
|
||||||
.then(function(version) {
|
.then(function (version) {
|
||||||
if (version !== 'default') {
|
if (version !== 'default') {
|
||||||
displayVersion = ` ${version}`;
|
displayVersion = ` ${version}`;
|
||||||
}
|
}
|
||||||
return manager.get(params.type, version);
|
return manager.get(params.type, version);
|
||||||
})
|
})
|
||||||
.then(function(stream) {
|
.then(function (stream) {
|
||||||
const visuals = getVisuals();
|
const visuals = getVisuals();
|
||||||
const bar = new visuals.Progress(
|
const bar = new visuals.Progress(
|
||||||
`Downloading Device OS${displayVersion}`,
|
`Downloading Device OS${displayVersion}`,
|
||||||
@ -148,7 +148,7 @@ versions for the given device type are pre-release).`);
|
|||||||
`Downloading Device OS${displayVersion} (size unknown)`,
|
`Downloading Device OS${displayVersion} (size unknown)`,
|
||||||
);
|
);
|
||||||
|
|
||||||
stream.on('progress', function(state) {
|
stream.on('progress', function (state) {
|
||||||
if (state != null) {
|
if (state != null) {
|
||||||
return bar.update(state);
|
return bar.update(state);
|
||||||
} else {
|
} else {
|
||||||
@ -178,7 +178,7 @@ versions for the given device type are pre-release).`);
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const buildConfigForDeviceType = function(deviceType, advanced) {
|
const buildConfigForDeviceType = function (deviceType, advanced) {
|
||||||
if (advanced == null) {
|
if (advanced == null) {
|
||||||
advanced = false;
|
advanced = false;
|
||||||
}
|
}
|
||||||
@ -201,7 +201,7 @@ const buildConfigForDeviceType = function(deviceType, advanced) {
|
|||||||
return form.run(questions, { override });
|
return form.run(questions, { override });
|
||||||
};
|
};
|
||||||
|
|
||||||
const $buildConfig = function(image, deviceTypeSlug, advanced) {
|
const $buildConfig = function (image, deviceTypeSlug, advanced) {
|
||||||
if (advanced == null) {
|
if (advanced == null) {
|
||||||
advanced = false;
|
advanced = false;
|
||||||
}
|
}
|
||||||
@ -210,7 +210,7 @@ const $buildConfig = function(image, deviceTypeSlug, advanced) {
|
|||||||
|
|
||||||
return Promise.resolve(
|
return Promise.resolve(
|
||||||
helpers.getManifest(image, deviceTypeSlug),
|
helpers.getManifest(image, deviceTypeSlug),
|
||||||
).then(deviceTypeManifest =>
|
).then((deviceTypeManifest) =>
|
||||||
buildConfigForDeviceType(deviceTypeManifest, advanced),
|
buildConfigForDeviceType(deviceTypeManifest, advanced),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -246,7 +246,7 @@ Example:
|
|||||||
params.image,
|
params.image,
|
||||||
params['device-type'],
|
params['device-type'],
|
||||||
options.advanced,
|
options.advanced,
|
||||||
).then(answers =>
|
).then((answers) =>
|
||||||
writeFileAsync(options.output, JSON.stringify(answers, null, 4)),
|
writeFileAsync(options.output, JSON.stringify(answers, null, 4)),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -295,14 +295,14 @@ Initializing device
|
|||||||
${INIT_WARNING_MESSAGE}\
|
${INIT_WARNING_MESSAGE}\
|
||||||
`);
|
`);
|
||||||
return Promise.resolve(helpers.getManifest(params.image, options.type))
|
return Promise.resolve(helpers.getManifest(params.image, options.type))
|
||||||
.then(manifest =>
|
.then((manifest) =>
|
||||||
form.run(manifest.initialization?.options, {
|
form.run(manifest.initialization?.options, {
|
||||||
override: {
|
override: {
|
||||||
drive: options.drive,
|
drive: options.drive,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.tap(function(answers) {
|
.tap(function (answers) {
|
||||||
if (answers.drive == null) {
|
if (answers.drive == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -316,7 +316,7 @@ ${INIT_WARNING_MESSAGE}\
|
|||||||
.return(answers.drive)
|
.return(answers.drive)
|
||||||
.then(umountAsync);
|
.then(umountAsync);
|
||||||
})
|
})
|
||||||
.tap(answers =>
|
.tap((answers) =>
|
||||||
helpers.sudo([
|
helpers.sudo([
|
||||||
'internal',
|
'internal',
|
||||||
'osinit',
|
'osinit',
|
||||||
@ -325,7 +325,7 @@ ${INIT_WARNING_MESSAGE}\
|
|||||||
JSON.stringify(answers),
|
JSON.stringify(answers),
|
||||||
]),
|
]),
|
||||||
)
|
)
|
||||||
.then(function(answers) {
|
.then(function (answers) {
|
||||||
if (answers.drive == null) {
|
if (answers.drive == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -18,10 +18,10 @@ import * as _ from 'lodash';
|
|||||||
import { getBalenaSdk, getVisuals } from '../utils/lazy';
|
import { getBalenaSdk, getVisuals } from '../utils/lazy';
|
||||||
import * as dockerUtils from '../utils/docker';
|
import * as dockerUtils from '../utils/docker';
|
||||||
|
|
||||||
const isCurrent = commit => commit === 'latest' || commit === 'current';
|
const isCurrent = (commit) => commit === 'latest' || commit === 'current';
|
||||||
|
|
||||||
let allDeviceTypes;
|
let allDeviceTypes;
|
||||||
const getDeviceTypes = function() {
|
const getDeviceTypes = function () {
|
||||||
const Bluebird = require('bluebird');
|
const Bluebird = require('bluebird');
|
||||||
if (allDeviceTypes !== undefined) {
|
if (allDeviceTypes !== undefined) {
|
||||||
return Bluebird.resolve(allDeviceTypes);
|
return Bluebird.resolve(allDeviceTypes);
|
||||||
@ -29,27 +29,24 @@ const getDeviceTypes = function() {
|
|||||||
const balena = getBalenaSdk();
|
const balena = getBalenaSdk();
|
||||||
return balena.models.config
|
return balena.models.config
|
||||||
.getDeviceTypes()
|
.getDeviceTypes()
|
||||||
.then(deviceTypes => _.sortBy(deviceTypes, 'name'))
|
.then((deviceTypes) => _.sortBy(deviceTypes, 'name'))
|
||||||
.tap(dt => {
|
.tap((dt) => {
|
||||||
allDeviceTypes = dt;
|
allDeviceTypes = dt;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const getDeviceTypesWithSameArch = function(deviceTypeSlug) {
|
const getDeviceTypesWithSameArch = function (deviceTypeSlug) {
|
||||||
return getDeviceTypes().then(function(deviceTypes) {
|
return getDeviceTypes().then(function (deviceTypes) {
|
||||||
const deviceType = _.find(deviceTypes, { slug: deviceTypeSlug });
|
const deviceType = _.find(deviceTypes, { slug: deviceTypeSlug });
|
||||||
return _(deviceTypes)
|
return _(deviceTypes).filter({ arch: deviceType.arch }).map('slug').value();
|
||||||
.filter({ arch: deviceType.arch })
|
|
||||||
.map('slug')
|
|
||||||
.value();
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const getApplicationsWithSuccessfulBuilds = function(deviceType) {
|
const getApplicationsWithSuccessfulBuilds = function (deviceType) {
|
||||||
const balenaPreload = require('balena-preload');
|
const balenaPreload = require('balena-preload');
|
||||||
const balena = getBalenaSdk();
|
const balena = getBalenaSdk();
|
||||||
|
|
||||||
return getDeviceTypesWithSameArch(deviceType).then(deviceTypes => {
|
return getDeviceTypesWithSameArch(deviceType).then((deviceTypes) => {
|
||||||
/** @type {import('balena-sdk').PineOptionsFor<import('balena-sdk').Application>} */
|
/** @type {import('balena-sdk').PineOptionsFor<import('balena-sdk').Application>} */
|
||||||
const options = {
|
const options = {
|
||||||
$filter: {
|
$filter: {
|
||||||
@ -84,7 +81,7 @@ const getApplicationsWithSuccessfulBuilds = function(deviceType) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectApplication = function(deviceType) {
|
const selectApplication = function (deviceType) {
|
||||||
const visuals = getVisuals();
|
const visuals = getVisuals();
|
||||||
const form = require('resin-cli-form');
|
const form = require('resin-cli-form');
|
||||||
const { exitWithExpectedError } = require('../errors');
|
const { exitWithExpectedError } = require('../errors');
|
||||||
@ -94,7 +91,7 @@ const selectApplication = function(deviceType) {
|
|||||||
);
|
);
|
||||||
applicationInfoSpinner.start();
|
applicationInfoSpinner.start();
|
||||||
|
|
||||||
return getApplicationsWithSuccessfulBuilds(deviceType).then(function(
|
return getApplicationsWithSuccessfulBuilds(deviceType).then(function (
|
||||||
applications,
|
applications,
|
||||||
) {
|
) {
|
||||||
applicationInfoSpinner.stop();
|
applicationInfoSpinner.stop();
|
||||||
@ -106,7 +103,7 @@ const selectApplication = function(deviceType) {
|
|||||||
return form.ask({
|
return form.ask({
|
||||||
message: 'Select an application',
|
message: 'Select an application',
|
||||||
type: 'list',
|
type: 'list',
|
||||||
choices: applications.map(app => ({
|
choices: applications.map((app) => ({
|
||||||
name: app.app_name,
|
name: app.app_name,
|
||||||
value: app,
|
value: app,
|
||||||
})),
|
})),
|
||||||
@ -114,7 +111,7 @@ const selectApplication = function(deviceType) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectApplicationCommit = function(releases) {
|
const selectApplicationCommit = function (releases) {
|
||||||
const form = require('resin-cli-form');
|
const form = require('resin-cli-form');
|
||||||
const { exitWithExpectedError } = require('../errors');
|
const { exitWithExpectedError } = require('../errors');
|
||||||
|
|
||||||
@ -123,7 +120,7 @@ const selectApplicationCommit = function(releases) {
|
|||||||
}
|
}
|
||||||
const DEFAULT_CHOICE = { name: 'current', value: 'current' };
|
const DEFAULT_CHOICE = { name: 'current', value: 'current' };
|
||||||
const choices = [DEFAULT_CHOICE].concat(
|
const choices = [DEFAULT_CHOICE].concat(
|
||||||
releases.map(release => ({
|
releases.map((release) => ({
|
||||||
name: `${release.end_timestamp} - ${release.commit}`,
|
name: `${release.end_timestamp} - ${release.commit}`,
|
||||||
value: release.commit,
|
value: release.commit,
|
||||||
})),
|
})),
|
||||||
@ -136,7 +133,7 @@ const selectApplicationCommit = function(releases) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const offerToDisableAutomaticUpdates = function(
|
const offerToDisableAutomaticUpdates = function (
|
||||||
application,
|
application,
|
||||||
commit,
|
commit,
|
||||||
pinDevice,
|
pinDevice,
|
||||||
@ -170,7 +167,7 @@ Alternatively you can pass the --pin-device-to-release flag to pin only this dev
|
|||||||
message,
|
message,
|
||||||
type: 'confirm',
|
type: 'confirm',
|
||||||
})
|
})
|
||||||
.then(function(update) {
|
.then(function (update) {
|
||||||
if (!update) {
|
if (!update) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -268,7 +265,7 @@ Examples:
|
|||||||
|
|
||||||
const progressBars = {};
|
const progressBars = {};
|
||||||
|
|
||||||
const progressHandler = function(event) {
|
const progressHandler = function (event) {
|
||||||
let progressBar = progressBars[event.name];
|
let progressBar = progressBars[event.name];
|
||||||
if (!progressBar) {
|
if (!progressBar) {
|
||||||
progressBar = progressBars[event.name] = new visuals.Progress(
|
progressBar = progressBars[event.name] = new visuals.Progress(
|
||||||
@ -280,7 +277,7 @@ Examples:
|
|||||||
|
|
||||||
const spinners = {};
|
const spinners = {};
|
||||||
|
|
||||||
const spinnerHandler = function(event) {
|
const spinnerHandler = function (event) {
|
||||||
let spinner = spinners[event.name];
|
let spinner = spinners[event.name];
|
||||||
if (!spinner) {
|
if (!spinner) {
|
||||||
spinner = spinners[event.name] = new visuals.Spinner(event.name);
|
spinner = spinners[event.name] = new visuals.Spinner(event.name);
|
||||||
@ -326,7 +323,7 @@ Examples:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get a configured dockerode instance
|
// Get a configured dockerode instance
|
||||||
return dockerUtils.getDocker(options).then(function(docker) {
|
return dockerUtils.getDocker(options).then(function (docker) {
|
||||||
const preloader = new balenaPreload.Preloader(
|
const preloader = new balenaPreload.Preloader(
|
||||||
balena,
|
balena,
|
||||||
docker,
|
docker,
|
||||||
@ -342,7 +339,7 @@ Examples:
|
|||||||
|
|
||||||
let gotSignal = false;
|
let gotSignal = false;
|
||||||
|
|
||||||
nodeCleanup(function(_exitCode, signal) {
|
nodeCleanup(function (_exitCode, signal) {
|
||||||
if (signal) {
|
if (signal) {
|
||||||
gotSignal = true;
|
gotSignal = true;
|
||||||
nodeCleanup.uninstall(); // don't call cleanup handler again
|
nodeCleanup.uninstall(); // don't call cleanup handler again
|
||||||
@ -361,7 +358,7 @@ Examples:
|
|||||||
preloader.on('progress', progressHandler);
|
preloader.on('progress', progressHandler);
|
||||||
preloader.on('spinner', spinnerHandler);
|
preloader.on('spinner', spinnerHandler);
|
||||||
|
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
preloader.on('error', reject);
|
preloader.on('error', reject);
|
||||||
|
|
||||||
return preloader
|
return preloader
|
||||||
@ -371,7 +368,7 @@ Examples:
|
|||||||
if (!preloader.appId) {
|
if (!preloader.appId) {
|
||||||
return selectApplication(
|
return selectApplication(
|
||||||
preloader.config.deviceType,
|
preloader.config.deviceType,
|
||||||
).then(application => preloader.setApplication(application));
|
).then((application) => preloader.setApplication(application));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@ -381,7 +378,7 @@ Examples:
|
|||||||
// handle `--commit current` (and its `--commit latest` synonym)
|
// handle `--commit current` (and its `--commit latest` synonym)
|
||||||
return 'latest';
|
return 'latest';
|
||||||
}
|
}
|
||||||
const release = _.find(preloader.application.owns__release, r =>
|
const release = _.find(preloader.application.owns__release, (r) =>
|
||||||
r.commit.startsWith(options.commit),
|
r.commit.startsWith(options.commit),
|
||||||
);
|
);
|
||||||
if (!release) {
|
if (!release) {
|
||||||
@ -393,7 +390,7 @@ Examples:
|
|||||||
}
|
}
|
||||||
return selectApplicationCommit(preloader.application.owns__release);
|
return selectApplicationCommit(preloader.application.owns__release);
|
||||||
})
|
})
|
||||||
.then(function(commit) {
|
.then(function (commit) {
|
||||||
if (isCurrent(commit)) {
|
if (isCurrent(commit)) {
|
||||||
preloader.commit = preloader.application.commit;
|
preloader.commit = preloader.application.commit;
|
||||||
} else {
|
} else {
|
||||||
@ -416,7 +413,7 @@ Examples:
|
|||||||
.catch(reject);
|
.catch(reject);
|
||||||
})
|
})
|
||||||
.then(done)
|
.then(done)
|
||||||
.finally(function() {
|
.finally(function () {
|
||||||
if (!gotSignal) {
|
if (!gotSignal) {
|
||||||
return preloader.cleanup();
|
return preloader.cleanup();
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ async function getAppOwner(sdk: BalenaSDK, appName: string) {
|
|||||||
// user has access to a collab app with the same name as a personal app. We
|
// user has access to a collab app with the same name as a personal app. We
|
||||||
// present a list to the user which shows the fully qualified application
|
// present a list to the user which shows the fully qualified application
|
||||||
// name (user/appname) and allows them to select
|
// name (user/appname) and allows them to select
|
||||||
const entries = _.map(applications, app => {
|
const entries = _.map(applications, (app) => {
|
||||||
const username = _.get(app, 'user[0].username');
|
const username = _.get(app, 'user[0].username');
|
||||||
return {
|
return {
|
||||||
name: `${username}/${appName}`,
|
name: `${username}/${appName}`,
|
||||||
@ -406,7 +406,7 @@ export const push: CommandDefinition<
|
|||||||
: options.env || [],
|
: options.env || [],
|
||||||
convertEol,
|
convertEol,
|
||||||
}),
|
}),
|
||||||
).catch(BuildError, e => {
|
).catch(BuildError, (e) => {
|
||||||
throw new ExpectedError(e.toString());
|
throw new ExpectedError(e.toString());
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
@ -101,7 +101,7 @@ async function getContainerId(
|
|||||||
});
|
});
|
||||||
const containers = await new Promise<string>((resolve, reject) => {
|
const containers = await new Promise<string>((resolve, reject) => {
|
||||||
const output: string[] = [];
|
const output: string[] = [];
|
||||||
subprocess.stdout.on('data', chunk => output.push(chunk.toString()));
|
subprocess.stdout.on('data', (chunk) => output.push(chunk.toString()));
|
||||||
subprocess.on('close', (code: number) => {
|
subprocess.on('close', (code: number) => {
|
||||||
if (code !== 0) {
|
if (code !== 0) {
|
||||||
reject(
|
reject(
|
||||||
|
@ -130,7 +130,7 @@ export const tunnel: CommandDefinition<Args, Options> = {
|
|||||||
logger.logInfo(`Opening a tunnel to ${device.uuid}...`);
|
logger.logInfo(`Opening a tunnel to ${device.uuid}...`);
|
||||||
|
|
||||||
const localListeners = _.chain(ports)
|
const localListeners = _.chain(ports)
|
||||||
.map(mapping => {
|
.map((mapping) => {
|
||||||
const regexResult = /^([0-9]+)(?:$|\:(?:([\w\:\.]+)\:|)([0-9]+))$/.exec(
|
const regexResult = /^([0-9]+)(?:$|\:(?:([\w\:\.]+)\:|)([0-9]+))$/.exec(
|
||||||
mapping,
|
mapping,
|
||||||
);
|
);
|
||||||
@ -168,7 +168,7 @@ export const tunnel: CommandDefinition<Args, Options> = {
|
|||||||
})
|
})
|
||||||
.map(({ localPort, localAddress, remotePort }) => {
|
.map(({ localPort, localAddress, remotePort }) => {
|
||||||
return tunnelConnectionToDevice(device.uuid, remotePort, sdk)
|
return tunnelConnectionToDevice(device.uuid, remotePort, sdk)
|
||||||
.then(handler =>
|
.then((handler) =>
|
||||||
createServer((client: Socket) => {
|
createServer((client: Socket) => {
|
||||||
return handler(client)
|
return handler(client)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@ -181,7 +181,7 @@ export const tunnel: CommandDefinition<Args, Options> = {
|
|||||||
remotePort,
|
remotePort,
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.catch(err =>
|
.catch((err) =>
|
||||||
logConnection(
|
logConnection(
|
||||||
client.remoteAddress || '',
|
client.remoteAddress || '',
|
||||||
client.remotePort || 0,
|
client.remotePort || 0,
|
||||||
@ -195,7 +195,7 @@ export const tunnel: CommandDefinition<Args, Options> = {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.then(
|
.then(
|
||||||
server =>
|
(server) =>
|
||||||
new Bluebird.Promise<Server>((resolve, reject) => {
|
new Bluebird.Promise<Server>((resolve, reject) => {
|
||||||
server.on('error', reject);
|
server.on('error', reject);
|
||||||
server.listen(localPort, localAddress, () => {
|
server.listen(localPort, localAddress, () => {
|
||||||
|
@ -20,10 +20,8 @@ import * as capitano from 'capitano';
|
|||||||
import * as actions from './actions';
|
import * as actions from './actions';
|
||||||
import * as events from './events';
|
import * as events from './events';
|
||||||
|
|
||||||
capitano.permission('user', done =>
|
capitano.permission('user', (done) =>
|
||||||
require('./utils/patterns')
|
require('./utils/patterns').checkLoggedIn().then(done, done),
|
||||||
.checkLoggedIn()
|
|
||||||
.then(done, done),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
capitano.command({
|
capitano.command({
|
||||||
@ -108,7 +106,7 @@ capitano.command(actions.push.push);
|
|||||||
|
|
||||||
export function run(argv) {
|
export function run(argv) {
|
||||||
const cli = capitano.parse(argv.slice(2));
|
const cli = capitano.parse(argv.slice(2));
|
||||||
const runCommand = function() {
|
const runCommand = function () {
|
||||||
const capitanoExecuteAsync = Promise.promisify(capitano.execute);
|
const capitanoExecuteAsync = Promise.promisify(capitano.execute);
|
||||||
if (cli.global?.help) {
|
if (cli.global?.help) {
|
||||||
return capitanoExecuteAsync({
|
return capitanoExecuteAsync({
|
||||||
@ -119,11 +117,11 @@ export function run(argv) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const trackCommand = function() {
|
const trackCommand = function () {
|
||||||
const getMatchCommandAsync = Promise.promisify(
|
const getMatchCommandAsync = Promise.promisify(
|
||||||
capitano.state.getMatchCommand,
|
capitano.state.getMatchCommand,
|
||||||
);
|
);
|
||||||
return getMatchCommandAsync(cli.command).then(function(command) {
|
return getMatchCommandAsync(cli.command).then(function (command) {
|
||||||
// cmdSignature is literally a string like, for example:
|
// cmdSignature is literally a string like, for example:
|
||||||
// "push <applicationOrDevice>"
|
// "push <applicationOrDevice>"
|
||||||
// ("applicationOrDevice" is NOT replaced with its actual value)
|
// ("applicationOrDevice" is NOT replaced with its actual value)
|
||||||
|
@ -54,7 +54,7 @@ export const setupSentry = onceAsync(async () => {
|
|||||||
dsn: config.sentryDsn,
|
dsn: config.sentryDsn,
|
||||||
release: packageJSON.version,
|
release: packageJSON.version,
|
||||||
});
|
});
|
||||||
Sentry.configureScope(scope => {
|
Sentry.configureScope((scope) => {
|
||||||
scope.setExtras({
|
scope.setExtras({
|
||||||
is_pkg: !!(process as any).pkg,
|
is_pkg: !!(process as any).pkg,
|
||||||
node_version: process.version,
|
node_version: process.version,
|
||||||
@ -173,9 +173,9 @@ async function setupGlobalAgentProxy(
|
|||||||
env.GLOBAL_AGENT_ENVIRONMENT_VARIABLE_NAMESPACE = '';
|
env.GLOBAL_AGENT_ENVIRONMENT_VARIABLE_NAMESPACE = '';
|
||||||
env.NO_PROXY = [
|
env.NO_PROXY = [
|
||||||
...requiredNoProxy,
|
...requiredNoProxy,
|
||||||
...(noProxy ? noProxy.split(',').filter(v => v) : privateNoProxy),
|
...(noProxy ? noProxy.split(',').filter((v) => v) : privateNoProxy),
|
||||||
]
|
]
|
||||||
.filter(i => !doProxy.includes(i))
|
.filter((i) => !doProxy.includes(i))
|
||||||
.join(',');
|
.join(',');
|
||||||
|
|
||||||
if (proxy) {
|
if (proxy) {
|
||||||
|
@ -42,7 +42,7 @@ export async function run(command: string[], options: AppOptions) {
|
|||||||
return require('@oclif/command/flush');
|
return require('@oclif/command/flush');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error => {
|
(error) => {
|
||||||
// oclif sometimes exits with ExitError code 0 (not an error)
|
// oclif sometimes exits with ExitError code 0 (not an error)
|
||||||
// (Avoid `error instanceof ExitError` here for the reasons explained
|
// (Avoid `error instanceof ExitError` here for the reasons explained
|
||||||
// in the CONTRIBUTING.md file regarding the `instanceof` operator.)
|
// in the CONTRIBUTING.md file regarding the `instanceof` operator.)
|
||||||
|
@ -36,7 +36,7 @@ const createServer = ({ port }: { port: number }) => {
|
|||||||
app.set('views', path.join(__dirname, 'pages'));
|
app.set('views', path.join(__dirname, 'pages'));
|
||||||
|
|
||||||
const server = app.listen(port);
|
const server = app.listen(port);
|
||||||
server.on('connection', socket => serverSockets.push(socket));
|
server.on('connection', (socket) => serverSockets.push(socket));
|
||||||
|
|
||||||
return { app, server };
|
return { app, server };
|
||||||
};
|
};
|
||||||
@ -55,7 +55,7 @@ const createServer = ({ port }: { port: number }) => {
|
|||||||
* https://github.com/nodejs/node-v0.x-archive/issues/9066
|
* https://github.com/nodejs/node-v0.x-archive/issues/9066
|
||||||
*/
|
*/
|
||||||
export function shutdownServer() {
|
export function shutdownServer() {
|
||||||
serverSockets.forEach(s => s.unref());
|
serverSockets.forEach((s) => s.unref());
|
||||||
serverSockets.splice(0);
|
serverSockets.splice(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ export const getDashboardLoginURL = (callbackUrl: string) => {
|
|||||||
|
|
||||||
return getBalenaSdk()
|
return getBalenaSdk()
|
||||||
.settings.get('dashboardUrl')
|
.settings.get('dashboardUrl')
|
||||||
.then(dashboardUrl =>
|
.then((dashboardUrl) =>
|
||||||
url.resolve(dashboardUrl, `/login/cli/${callbackUrl}`),
|
url.resolve(dashboardUrl, `/login/cli/${callbackUrl}`),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -73,12 +73,12 @@ export const loginIfTokenValid = (token: string) => {
|
|||||||
return balena.auth
|
return balena.auth
|
||||||
.getToken()
|
.getToken()
|
||||||
.catchReturn(undefined)
|
.catchReturn(undefined)
|
||||||
.then(currentToken =>
|
.then((currentToken) =>
|
||||||
balena.auth
|
balena.auth
|
||||||
.loginWithToken(token)
|
.loginWithToken(token)
|
||||||
.return(token)
|
.return(token)
|
||||||
.then(balena.auth.isLoggedIn)
|
.then(balena.auth.isLoggedIn)
|
||||||
.tap(isLoggedIn => {
|
.tap((isLoggedIn) => {
|
||||||
if (isLoggedIn) {
|
if (isLoggedIn) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -94,9 +94,9 @@ function interpret(error: Error): string {
|
|||||||
const messages: {
|
const messages: {
|
||||||
[key: string]: (error: Error & { path?: string }) => string;
|
[key: string]: (error: Error & { path?: string }) => string;
|
||||||
} = {
|
} = {
|
||||||
EISDIR: error => `File is a directory: ${error.path}`,
|
EISDIR: (error) => `File is a directory: ${error.path}`,
|
||||||
|
|
||||||
ENOENT: error => `No such file or directory: ${error.path}`,
|
ENOENT: (error) => `No such file or directory: ${error.path}`,
|
||||||
|
|
||||||
ENOGIT: () => stripIndent`
|
ENOGIT: () => stripIndent`
|
||||||
Git is not installed on this system.
|
Git is not installed on this system.
|
||||||
@ -112,7 +112,7 @@ const messages: {
|
|||||||
|
|
||||||
If this is not the case, and you're trying to burn an SDCard, check that the write lock is not set.`,
|
If this is not the case, and you're trying to burn an SDCard, check that the write lock is not set.`,
|
||||||
|
|
||||||
EACCES: e => messages.EPERM(e),
|
EACCES: (e) => messages.EPERM(e),
|
||||||
|
|
||||||
ETIMEDOUT: () =>
|
ETIMEDOUT: () =>
|
||||||
'Oops something went wrong, please check your connection and try again.',
|
'Oops something went wrong, please check your connection and try again.',
|
||||||
@ -166,8 +166,8 @@ export async function handleError(error: Error) {
|
|||||||
// Expected?
|
// Expected?
|
||||||
const isExpectedError =
|
const isExpectedError =
|
||||||
error instanceof ExpectedError ||
|
error instanceof ExpectedError ||
|
||||||
EXPECTED_ERROR_REGEXES.some(re => re.test(message[0])) ||
|
EXPECTED_ERROR_REGEXES.some((re) => re.test(message[0])) ||
|
||||||
EXPECTED_ERROR_REGEXES.some(re => re.test((error as BalenaError).code));
|
EXPECTED_ERROR_REGEXES.some((re) => re.test((error as BalenaError).code));
|
||||||
|
|
||||||
// Output/report error
|
// Output/report error
|
||||||
if (isExpectedError) {
|
if (isExpectedError) {
|
||||||
@ -198,7 +198,7 @@ export function printErrorMessage(message: string) {
|
|||||||
const messageLines = message.split('\n');
|
const messageLines = message.split('\n');
|
||||||
console.error(chalk.red(messageLines.shift()));
|
console.error(chalk.red(messageLines.shift()));
|
||||||
|
|
||||||
messageLines.forEach(line => {
|
messageLines.forEach((line) => {
|
||||||
console.error(line);
|
console.error(line);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ const getMixpanel = _.once((balenaUrl: string) => {
|
|||||||
*/
|
*/
|
||||||
export async function trackCommand(commandSignature: string) {
|
export async function trackCommand(commandSignature: string) {
|
||||||
const Sentry = await import('@sentry/node');
|
const Sentry = await import('@sentry/node');
|
||||||
Sentry.configureScope(scope => {
|
Sentry.configureScope((scope) => {
|
||||||
scope.setExtra('command', commandSignature);
|
scope.setExtra('command', commandSignature);
|
||||||
});
|
});
|
||||||
const balena = getBalenaSdk();
|
const balena = getBalenaSdk();
|
||||||
@ -56,7 +56,7 @@ export async function trackCommand(commandSignature: string) {
|
|||||||
mixpanel: balenaUrlPromise.then(getMixpanel),
|
mixpanel: balenaUrlPromise.then(getMixpanel),
|
||||||
})
|
})
|
||||||
.then(({ username, balenaUrl, mixpanel }) => {
|
.then(({ username, balenaUrl, mixpanel }) => {
|
||||||
Sentry.configureScope(scope => {
|
Sentry.configureScope((scope) => {
|
||||||
scope.setUser({
|
scope.setUser({
|
||||||
id: username,
|
id: username,
|
||||||
username,
|
username,
|
||||||
|
@ -19,7 +19,7 @@ import { Hook } from '@oclif/config';
|
|||||||
let trackResolve: (result: Promise<any>) => void;
|
let trackResolve: (result: Promise<any>) => void;
|
||||||
|
|
||||||
// note: trackPromise is subject to a Bluebird.timeout, defined in events.ts
|
// note: trackPromise is subject to a Bluebird.timeout, defined in events.ts
|
||||||
export const trackPromise = new Promise(resolve => {
|
export const trackPromise = new Promise((resolve) => {
|
||||||
trackResolve = resolve;
|
trackResolve = resolve;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ export const trackPromise = new Promise(resolve => {
|
|||||||
* A command signature is something like "env add NAME [VALUE]". That's
|
* A command signature is something like "env add NAME [VALUE]". That's
|
||||||
* literally so: 'NAME' and 'VALUE' are NOT replaced with actual values.
|
* literally so: 'NAME' and 'VALUE' are NOT replaced with actual values.
|
||||||
*/
|
*/
|
||||||
const hook: Hook<'prerun'> = async function(options) {
|
const hook: Hook<'prerun'> = async function (options) {
|
||||||
const events = await import('../../events');
|
const events = await import('../../events');
|
||||||
const usage: string | string[] | undefined = options.Command.usage;
|
const usage: string | string[] | undefined = options.Command.usage;
|
||||||
const cmdSignature =
|
const cmdSignature =
|
||||||
|
@ -75,11 +75,9 @@ export async function routeCliFramework(argv: string[], options: AppOptions) {
|
|||||||
}
|
}
|
||||||
if (process.env.DEBUG) {
|
if (process.env.DEBUG) {
|
||||||
console.log(
|
console.log(
|
||||||
`[debug] new argv=[${[
|
`[debug] new argv=[${[argv[0], argv[1], ...oclifArgs]}] length=${
|
||||||
argv[0],
|
oclifArgs.length + 2
|
||||||
argv[1],
|
}`,
|
||||||
...oclifArgs,
|
|
||||||
]}] length=${oclifArgs.length + 2}`,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
await (await import('./app-oclif')).run(oclifArgs, options);
|
await (await import('./app-oclif')).run(oclifArgs, options);
|
||||||
|
@ -21,7 +21,7 @@ import * as path from 'path';
|
|||||||
|
|
||||||
import { getChalk } from './lazy';
|
import { getChalk } from './lazy';
|
||||||
|
|
||||||
export const appendProjectOptions = opts =>
|
export const appendProjectOptions = (opts) =>
|
||||||
opts.concat([
|
opts.concat([
|
||||||
{
|
{
|
||||||
signature: 'projectName',
|
signature: 'projectName',
|
||||||
@ -119,7 +119,7 @@ Source files are not modified.`,
|
|||||||
export function generateOpts(options) {
|
export function generateOpts(options) {
|
||||||
const fs = require('mz/fs');
|
const fs = require('mz/fs');
|
||||||
const { isV12 } = require('./version');
|
const { isV12 } = require('./version');
|
||||||
return fs.realpath(options.source || '.').then(projectPath => ({
|
return fs.realpath(options.source || '.').then((projectPath) => ({
|
||||||
projectName: options.projectName,
|
projectName: options.projectName,
|
||||||
projectPath,
|
projectPath,
|
||||||
inlineLogs: !options.nologs && (!!options.logs || isV12()),
|
inlineLogs: !options.nologs && (!!options.logs || isV12()),
|
||||||
@ -152,7 +152,7 @@ export function createProject(composePath, composeStr, projectName = null) {
|
|||||||
if (projectName == null) {
|
if (projectName == null) {
|
||||||
projectName = path.basename(composePath);
|
projectName = path.basename(composePath);
|
||||||
}
|
}
|
||||||
const descriptors = compose.parse(composition).map(function(descr) {
|
const descriptors = compose.parse(composition).map(function (descr) {
|
||||||
// generate an image name based on the project and service names
|
// generate an image name based on the project and service names
|
||||||
// if one is not given and the service requires a build
|
// if one is not given and the service requires a build
|
||||||
if (
|
if (
|
||||||
@ -216,7 +216,7 @@ function originalTarDirectory(dir, param) {
|
|||||||
let readFile;
|
let readFile;
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
const { readFileWithEolConversion } = require('./eol-conversion');
|
const { readFileWithEolConversion } = require('./eol-conversion');
|
||||||
readFile = file => readFileWithEolConversion(file, convertEol);
|
readFile = (file) => readFileWithEolConversion(file, convertEol);
|
||||||
} else {
|
} else {
|
||||||
({ readFile } = fs);
|
({ readFile } = fs);
|
||||||
}
|
}
|
||||||
@ -224,14 +224,14 @@ function originalTarDirectory(dir, param) {
|
|||||||
const getFiles = () =>
|
const getFiles = () =>
|
||||||
// @ts-ignore `klaw` returns a `Walker` which is close enough to a stream to work but ts complains
|
// @ts-ignore `klaw` returns a `Walker` which is close enough to a stream to work but ts complains
|
||||||
Promise.resolve(streamToPromise(klaw(dir)))
|
Promise.resolve(streamToPromise(klaw(dir)))
|
||||||
.filter(item => !item.stats.isDirectory())
|
.filter((item) => !item.stats.isDirectory())
|
||||||
.map(item => item.path);
|
.map((item) => item.path);
|
||||||
|
|
||||||
const ignore = new FileIgnorer(dir);
|
const ignore = new FileIgnorer(dir);
|
||||||
const pack = tar.pack();
|
const pack = tar.pack();
|
||||||
const ignoreFiles = {};
|
const ignoreFiles = {};
|
||||||
return getFiles()
|
return getFiles()
|
||||||
.each(function(file) {
|
.each(function (file) {
|
||||||
const type = ignore.getIgnoreFileType(path.relative(dir, file));
|
const type = ignore.getIgnoreFileType(path.relative(dir, file));
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
ignoreFiles[type] = ignoreFiles[type] || [];
|
ignoreFiles[type] = ignoreFiles[type] || [];
|
||||||
@ -248,7 +248,7 @@ function originalTarDirectory(dir, param) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.filter(ignore.filter)
|
.filter(ignore.filter)
|
||||||
.map(function(file) {
|
.map(function (file) {
|
||||||
const relPath = path.relative(path.resolve(dir), file);
|
const relPath = path.relative(path.resolve(dir), file);
|
||||||
return Promise.join(
|
return Promise.join(
|
||||||
relPath,
|
relPath,
|
||||||
@ -267,7 +267,7 @@ function originalTarDirectory(dir, param) {
|
|||||||
);
|
);
|
||||||
})
|
})
|
||||||
.then(() => preFinalizeCallback?.(pack))
|
.then(() => preFinalizeCallback?.(pack))
|
||||||
.then(function() {
|
.then(function () {
|
||||||
pack.finalize();
|
pack.finalize();
|
||||||
return pack;
|
return pack;
|
||||||
});
|
});
|
||||||
@ -278,7 +278,7 @@ function originalTarDirectory(dir, param) {
|
|||||||
* @param {number} len
|
* @param {number} len
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
const truncateString = function(str, len) {
|
const truncateString = function (str, len) {
|
||||||
if (str.length < len) {
|
if (str.length < len) {
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
@ -341,13 +341,13 @@ export function buildProject(
|
|||||||
|
|
||||||
return Promise.resolve(checkBuildSecretsRequirements(docker, projectPath))
|
return Promise.resolve(checkBuildSecretsRequirements(docker, projectPath))
|
||||||
.then(() => qemu.installQemuIfNeeded(emulated, logger, arch, docker))
|
.then(() => qemu.installQemuIfNeeded(emulated, logger, arch, docker))
|
||||||
.tap(function(needsQemu) {
|
.tap(function (needsQemu) {
|
||||||
if (!needsQemu) {
|
if (!needsQemu) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logger.logInfo('Emulation is enabled');
|
logger.logInfo('Emulation is enabled');
|
||||||
// Copy qemu into all build contexts
|
// Copy qemu into all build contexts
|
||||||
return Promise.map(imageDescriptors, function(d) {
|
return Promise.map(imageDescriptors, function (d) {
|
||||||
if (typeof d.image === 'string' || d.image.context == null) {
|
if (typeof d.image === 'string' || d.image.context == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -359,7 +359,7 @@ export function buildProject(
|
|||||||
needsQemu, // Tar up the directory, ready for the build stream
|
needsQemu, // Tar up the directory, ready for the build stream
|
||||||
) =>
|
) =>
|
||||||
tarDirectory(projectPath, { convertEol, nogitignore })
|
tarDirectory(projectPath, { convertEol, nogitignore })
|
||||||
.then(tarStream =>
|
.then((tarStream) =>
|
||||||
makeBuildTasks(
|
makeBuildTasks(
|
||||||
composition,
|
composition,
|
||||||
tarStream,
|
tarStream,
|
||||||
@ -368,7 +368,7 @@ export function buildProject(
|
|||||||
projectName,
|
projectName,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.map(function(/** @type {any} */ task) {
|
.map(function (/** @type {any} */ task) {
|
||||||
const d = imageDescriptorsByServiceName[task.serviceName];
|
const d = imageDescriptorsByServiceName[task.serviceName];
|
||||||
|
|
||||||
// multibuild parses the composition internally so any tags we've
|
// multibuild parses the composition internally so any tags we've
|
||||||
@ -428,7 +428,7 @@ export function buildProject(
|
|||||||
.return([task, binPath]);
|
.return([task, binPath]);
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.map(function([task, qemuPath]) {
|
.map(function ([task, qemuPath]) {
|
||||||
const captureStream = buildLogCapture(task.external, task.logBuffer);
|
const captureStream = buildLogCapture(task.external, task.logBuffer);
|
||||||
|
|
||||||
if (task.external) {
|
if (task.external) {
|
||||||
@ -437,7 +437,7 @@ export function buildProject(
|
|||||||
captureStream.pipe(task.logStream);
|
captureStream.pipe(task.logStream);
|
||||||
task.progressHook = pullProgressAdapter(captureStream);
|
task.progressHook = pullProgressAdapter(captureStream);
|
||||||
} else {
|
} else {
|
||||||
task.streamHook = function(stream) {
|
task.streamHook = function (stream) {
|
||||||
let rawStream;
|
let rawStream;
|
||||||
stream = createLogStream(stream);
|
stream = createLogStream(stream);
|
||||||
if (qemuPath != null) {
|
if (qemuPath != null) {
|
||||||
@ -461,11 +461,11 @@ export function buildProject(
|
|||||||
}
|
}
|
||||||
return task;
|
return task;
|
||||||
})
|
})
|
||||||
.then(function(tasks) {
|
.then(function (tasks) {
|
||||||
logger.logDebug('Prepared tasks; building...');
|
logger.logDebug('Prepared tasks; building...');
|
||||||
return Promise.map(
|
return Promise.map(
|
||||||
builder.performBuilds(tasks, docker, BALENA_ENGINE_TMP_PATH),
|
builder.performBuilds(tasks, docker, BALENA_ENGINE_TMP_PATH),
|
||||||
function(builtImage) {
|
function (builtImage) {
|
||||||
if (!builtImage.successful) {
|
if (!builtImage.successful) {
|
||||||
/** @type {Error & {serviceName?: string}} */
|
/** @type {Error & {serviceName?: string}} */
|
||||||
const error = builtImage.error ?? new Error();
|
const error = builtImage.error ?? new Error();
|
||||||
@ -499,12 +499,12 @@ export function buildProject(
|
|||||||
.getImage(image.name)
|
.getImage(image.name)
|
||||||
.inspect()
|
.inspect()
|
||||||
.get('Size')
|
.get('Size')
|
||||||
.then(size => {
|
.then((size) => {
|
||||||
image.props.size = size;
|
image.props.size = size;
|
||||||
})
|
})
|
||||||
.return(image);
|
.return(image);
|
||||||
},
|
},
|
||||||
).tap(function(images) {
|
).tap(function (images) {
|
||||||
const summary = _(images)
|
const summary = _(images)
|
||||||
.map(({ serviceName, props }) => [
|
.map(({ serviceName, props }) => [
|
||||||
serviceName,
|
serviceName,
|
||||||
@ -526,7 +526,7 @@ export function buildProject(
|
|||||||
* @param {import('resin-compose-parse').Composition} composition
|
* @param {import('resin-compose-parse').Composition} composition
|
||||||
* @returns {Promise<import('./compose-types').Release>}
|
* @returns {Promise<import('./compose-types').Release>}
|
||||||
*/
|
*/
|
||||||
export const createRelease = function(
|
export const createRelease = function (
|
||||||
apiEndpoint,
|
apiEndpoint,
|
||||||
auth,
|
auth,
|
||||||
userId,
|
userId,
|
||||||
@ -546,12 +546,9 @@ export const createRelease = function(
|
|||||||
application: appId,
|
application: appId,
|
||||||
composition,
|
composition,
|
||||||
source: 'local',
|
source: 'local',
|
||||||
commit: crypto
|
commit: crypto.pseudoRandomBytes(16).toString('hex').toLowerCase(),
|
||||||
.pseudoRandomBytes(16)
|
|
||||||
.toString('hex')
|
|
||||||
.toLowerCase(),
|
|
||||||
})
|
})
|
||||||
.then(function({ release, serviceImages }) {
|
.then(function ({ release, serviceImages }) {
|
||||||
return {
|
return {
|
||||||
client,
|
client,
|
||||||
release: _.omit(release, [
|
release: _.omit(release, [
|
||||||
@ -560,7 +557,7 @@ export const createRelease = function(
|
|||||||
'is_created_by__user',
|
'is_created_by__user',
|
||||||
'__metadata',
|
'__metadata',
|
||||||
]),
|
]),
|
||||||
serviceImages: _.mapValues(serviceImages, serviceImage =>
|
serviceImages: _.mapValues(serviceImages, (serviceImage) =>
|
||||||
_.omit(serviceImage, [
|
_.omit(serviceImage, [
|
||||||
'created_at',
|
'created_at',
|
||||||
'is_a_build_of__service',
|
'is_a_build_of__service',
|
||||||
@ -579,7 +576,7 @@ export const createRelease = function(
|
|||||||
* @returns {Promise<Array<import('./compose-types').TaggedImage>>}
|
* @returns {Promise<Array<import('./compose-types').TaggedImage>>}
|
||||||
*/
|
*/
|
||||||
export const tagServiceImages = (docker, images, serviceImages) =>
|
export const tagServiceImages = (docker, images, serviceImages) =>
|
||||||
Promise.map(images, function(d) {
|
Promise.map(images, function (d) {
|
||||||
const serviceImage = serviceImages[d.serviceName];
|
const serviceImage = serviceImages[d.serviceName];
|
||||||
const imageName = serviceImage.is_stored_at__image_location;
|
const imageName = serviceImage.is_stored_at__image_location;
|
||||||
const match = /(.*?)\/(.*?)(?::([^/]*))?$/.exec(imageName);
|
const match = /(.*?)\/(.*?)(?::([^/]*))?$/.exec(imageName);
|
||||||
@ -592,7 +589,7 @@ export const tagServiceImages = (docker, images, serviceImages) =>
|
|||||||
.getImage(d.name)
|
.getImage(d.name)
|
||||||
.tag({ repo: name, tag, force: true })
|
.tag({ repo: name, tag, force: true })
|
||||||
.then(() => docker.getImage(`${name}:${tag}`))
|
.then(() => docker.getImage(`${name}:${tag}`))
|
||||||
.then(localImage => ({
|
.then((localImage) => ({
|
||||||
serviceName: d.serviceName,
|
serviceName: d.serviceName,
|
||||||
serviceImage,
|
serviceImage,
|
||||||
localImage,
|
localImage,
|
||||||
@ -629,13 +626,13 @@ export const getPreviousRepos = (sdk, docker, logger, appID) =>
|
|||||||
$top: 1,
|
$top: 1,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(function(release) {
|
.then(function (release) {
|
||||||
// grab all images from the latest release, return all image locations in the registry
|
// grab all images from the latest release, return all image locations in the registry
|
||||||
if (release.length > 0) {
|
if (release.length > 0) {
|
||||||
const images = release[0].contains__image;
|
const images = release[0].contains__image;
|
||||||
return Promise.map(images, function(d) {
|
return Promise.map(images, function (d) {
|
||||||
const imageName = d.image[0].is_stored_at__image_location;
|
const imageName = d.image[0].is_stored_at__image_location;
|
||||||
return docker.getRegistryAndName(imageName).then(function(registry) {
|
return docker.getRegistryAndName(imageName).then(function (registry) {
|
||||||
logger.logDebug(
|
logger.logDebug(
|
||||||
`Requesting access to previously pushed image repo (${registry.imageName})`,
|
`Requesting access to previously pushed image repo (${registry.imageName})`,
|
||||||
);
|
);
|
||||||
@ -646,7 +643,7 @@ export const getPreviousRepos = (sdk, docker, logger, appID) =>
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch((e) => {
|
||||||
logger.logDebug(`Failed to access previously pushed image repo: ${e}`);
|
logger.logDebug(`Failed to access previously pushed image repo: ${e}`);
|
||||||
return [];
|
return [];
|
||||||
});
|
});
|
||||||
@ -659,7 +656,7 @@ export const getPreviousRepos = (sdk, docker, logger, appID) =>
|
|||||||
* @param {string[]} previousRepos
|
* @param {string[]} previousRepos
|
||||||
* @returns {Promise<string>}
|
* @returns {Promise<string>}
|
||||||
*/
|
*/
|
||||||
export const authorizePush = function(
|
export const authorizePush = function (
|
||||||
sdk,
|
sdk,
|
||||||
tokenAuthEndpoint,
|
tokenAuthEndpoint,
|
||||||
registry,
|
registry,
|
||||||
@ -677,7 +674,7 @@ export const authorizePush = function(
|
|||||||
url: '/auth/v1/token',
|
url: '/auth/v1/token',
|
||||||
qs: {
|
qs: {
|
||||||
service: registry,
|
service: registry,
|
||||||
scope: images.map(repo => `repository:${repo}:pull,push`),
|
scope: images.map((repo) => `repository:${repo}:pull,push`),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.get('body')
|
.get('body')
|
||||||
@ -691,7 +688,7 @@ export const authorizePush = function(
|
|||||||
* @param {Array<import('./compose-types').TaggedImage>} images
|
* @param {Array<import('./compose-types').TaggedImage>} images
|
||||||
* @param {(serviceImage: import('balena-release/build/models').ImageModel, props: object) => void} afterEach
|
* @param {(serviceImage: import('balena-release/build/models').ImageModel, props: object) => void} afterEach
|
||||||
*/
|
*/
|
||||||
export const pushAndUpdateServiceImages = function(
|
export const pushAndUpdateServiceImages = function (
|
||||||
docker,
|
docker,
|
||||||
token,
|
token,
|
||||||
images,
|
images,
|
||||||
@ -725,7 +722,7 @@ export const pushAndUpdateServiceImages = function(
|
|||||||
1.4, // `backoffScaler` - wait multiplier for each retry
|
1.4, // `backoffScaler` - wait multiplier for each retry
|
||||||
).finally(renderer.end),
|
).finally(renderer.end),
|
||||||
/** @type {(size: number, digest: string) => void} */
|
/** @type {(size: number, digest: string) => void} */
|
||||||
function(size, digest) {
|
function (size, digest) {
|
||||||
serviceImage.image_size = size;
|
serviceImage.image_size = size;
|
||||||
serviceImage.content_hash = digest;
|
serviceImage.content_hash = digest;
|
||||||
serviceImage.build_log = logs;
|
serviceImage.build_log = logs;
|
||||||
@ -741,7 +738,7 @@ export const pushAndUpdateServiceImages = function(
|
|||||||
serviceImage.status = 'success';
|
serviceImage.status = 'success';
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.tapCatch(function(e) {
|
.tapCatch(function (e) {
|
||||||
serviceImage.error_message = '' + e;
|
serviceImage.error_message = '' + e;
|
||||||
serviceImage.status = 'failed';
|
serviceImage.status = 'failed';
|
||||||
})
|
})
|
||||||
@ -752,7 +749,7 @@ export const pushAndUpdateServiceImages = function(
|
|||||||
|
|
||||||
// utilities
|
// utilities
|
||||||
|
|
||||||
const renderProgressBar = function(percentage, stepCount) {
|
const renderProgressBar = function (percentage, stepCount) {
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
percentage = _.clamp(percentage, 0, 100);
|
percentage = _.clamp(percentage, 0, 100);
|
||||||
const barCount = Math.floor((stepCount * percentage) / 100);
|
const barCount = Math.floor((stepCount * percentage) / 100);
|
||||||
@ -761,8 +758,8 @@ const renderProgressBar = function(percentage, stepCount) {
|
|||||||
return `${bar} ${_.padStart(percentage, 3)}%`;
|
return `${bar} ${_.padStart(percentage, 3)}%`;
|
||||||
};
|
};
|
||||||
|
|
||||||
var pushProgressRenderer = function(tty, prefix) {
|
var pushProgressRenderer = function (tty, prefix) {
|
||||||
const fn = function(e) {
|
const fn = function (e) {
|
||||||
const { error, percentage } = e;
|
const { error, percentage } = e;
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
throw new Error(error);
|
throw new Error(error);
|
||||||
@ -776,15 +773,15 @@ var pushProgressRenderer = function(tty, prefix) {
|
|||||||
return fn;
|
return fn;
|
||||||
};
|
};
|
||||||
|
|
||||||
var createLogStream = function(input) {
|
var createLogStream = function (input) {
|
||||||
const split = require('split');
|
const split = require('split');
|
||||||
const stripAnsi = require('strip-ansi-stream');
|
const stripAnsi = require('strip-ansi-stream');
|
||||||
return input.pipe(stripAnsi()).pipe(split());
|
return input.pipe(stripAnsi()).pipe(split());
|
||||||
};
|
};
|
||||||
|
|
||||||
var dropEmptyLinesStream = function() {
|
var dropEmptyLinesStream = function () {
|
||||||
const through = require('through2');
|
const through = require('through2');
|
||||||
return through(function(data, _enc, cb) {
|
return through(function (data, _enc, cb) {
|
||||||
const str = data.toString('utf-8');
|
const str = data.toString('utf-8');
|
||||||
if (str.trim()) {
|
if (str.trim()) {
|
||||||
this.push(str);
|
this.push(str);
|
||||||
@ -793,10 +790,10 @@ var dropEmptyLinesStream = function() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
var buildLogCapture = function(objectMode, buffer) {
|
var buildLogCapture = function (objectMode, buffer) {
|
||||||
const through = require('through2');
|
const through = require('through2');
|
||||||
|
|
||||||
return through({ objectMode }, function(data, _enc, cb) {
|
return through({ objectMode }, function (data, _enc, cb) {
|
||||||
// data from pull stream
|
// data from pull stream
|
||||||
if (data.error) {
|
if (data.error) {
|
||||||
buffer.push(`${data.error}`);
|
buffer.push(`${data.error}`);
|
||||||
@ -814,7 +811,7 @@ var buildLogCapture = function(objectMode, buffer) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
var buildProgressAdapter = function(inline) {
|
var buildProgressAdapter = function (inline) {
|
||||||
const through = require('through2');
|
const through = require('through2');
|
||||||
|
|
||||||
const stepRegex = /^\s*Step\s+(\d+)\/(\d+)\s*: (.+)$/;
|
const stepRegex = /^\s*Step\s+(\d+)\/(\d+)\s*: (.+)$/;
|
||||||
@ -823,7 +820,7 @@ var buildProgressAdapter = function(inline) {
|
|||||||
let numSteps = null;
|
let numSteps = null;
|
||||||
let progress;
|
let progress;
|
||||||
|
|
||||||
return through({ objectMode: true }, function(str, _enc, cb) {
|
return through({ objectMode: true }, function (str, _enc, cb) {
|
||||||
if (str == null) {
|
if (str == null) {
|
||||||
return cb(null, str);
|
return cb(null, str);
|
||||||
}
|
}
|
||||||
@ -855,8 +852,8 @@ var buildProgressAdapter = function(inline) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
var pullProgressAdapter = outStream =>
|
var pullProgressAdapter = (outStream) =>
|
||||||
function({ status, id, percentage, error, errorDetail }) {
|
function ({ status, id, percentage, error, errorDetail }) {
|
||||||
if (status != null) {
|
if (status != null) {
|
||||||
status = status.replace(/^Status: /, '');
|
status = status.replace(/^Status: /, '');
|
||||||
}
|
}
|
||||||
@ -887,8 +884,8 @@ class BuildProgressUI {
|
|||||||
const services = _.map(descriptors, 'serviceName');
|
const services = _.map(descriptors, 'serviceName');
|
||||||
|
|
||||||
const streams = _(services)
|
const streams = _(services)
|
||||||
.map(function(service) {
|
.map(function (service) {
|
||||||
const stream = through.obj(function(event, _enc, cb) {
|
const stream = through.obj(function (event, _enc, cb) {
|
||||||
eventHandler(service, event);
|
eventHandler(service, event);
|
||||||
return cb();
|
return cb();
|
||||||
});
|
});
|
||||||
@ -937,7 +934,7 @@ class BuildProgressUI {
|
|||||||
start() {
|
start() {
|
||||||
process.on('SIGINT', this._handleInterrupt);
|
process.on('SIGINT', this._handleInterrupt);
|
||||||
this._tty.hideCursor();
|
this._tty.hideCursor();
|
||||||
this._services.forEach(service => {
|
this._services.forEach((service) => {
|
||||||
this.streams[service].write({ status: 'Preparing...' });
|
this.streams[service].write({ status: 'Preparing...' });
|
||||||
});
|
});
|
||||||
this._runloop = require('./compose_ts').createRunLoop(this._display);
|
this._runloop = require('./compose_ts').createRunLoop(this._display);
|
||||||
@ -978,7 +975,7 @@ class BuildProgressUI {
|
|||||||
const serviceToDataMap = this._serviceToDataMap;
|
const serviceToDataMap = this._serviceToDataMap;
|
||||||
|
|
||||||
return _(services)
|
return _(services)
|
||||||
.map(function(service) {
|
.map(function (service) {
|
||||||
const { status, progress, error } = serviceToDataMap[service] ?? {};
|
const { status, progress, error } = serviceToDataMap[service] ?? {};
|
||||||
if (error) {
|
if (error) {
|
||||||
return `${error}`;
|
return `${error}`;
|
||||||
@ -1060,8 +1057,8 @@ class BuildProgressInline {
|
|||||||
const services = _.map(descriptors, 'serviceName');
|
const services = _.map(descriptors, 'serviceName');
|
||||||
const eventHandler = this._renderEvent;
|
const eventHandler = this._renderEvent;
|
||||||
const streams = _(services)
|
const streams = _(services)
|
||||||
.map(function(service) {
|
.map(function (service) {
|
||||||
const stream = through.obj(function(event, _enc, cb) {
|
const stream = through.obj(function (event, _enc, cb) {
|
||||||
eventHandler(service, event);
|
eventHandler(service, event);
|
||||||
return cb();
|
return cb();
|
||||||
});
|
});
|
||||||
@ -1083,7 +1080,7 @@ class BuildProgressInline {
|
|||||||
|
|
||||||
start() {
|
start() {
|
||||||
this._outStream.write('Building services...\n');
|
this._outStream.write('Building services...\n');
|
||||||
this._services.forEach(service => {
|
this._services.forEach((service) => {
|
||||||
this.streams[service].write({ status: 'Preparing...' });
|
this.streams[service].write({ status: 'Preparing...' });
|
||||||
});
|
});
|
||||||
this._startTime = Date.now();
|
this._startTime = Date.now();
|
||||||
@ -1099,7 +1096,7 @@ class BuildProgressInline {
|
|||||||
this._ended = true;
|
this._ended = true;
|
||||||
|
|
||||||
if (summary != null) {
|
if (summary != null) {
|
||||||
this._services.forEach(service => {
|
this._services.forEach((service) => {
|
||||||
this._renderEvent(service, summary[service]);
|
this._renderEvent(service, summary[service]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1122,7 +1119,7 @@ class BuildProgressInline {
|
|||||||
_renderEvent(service, event) {
|
_renderEvent(service, event) {
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
|
|
||||||
const str = (function() {
|
const str = (function () {
|
||||||
const { status, error } = event;
|
const { status, error } = event;
|
||||||
if (error) {
|
if (error) {
|
||||||
return `${error}`;
|
return `${error}`;
|
||||||
|
@ -188,7 +188,7 @@ export async function tarDirectory(
|
|||||||
let readFile: (file: string) => Promise<Buffer>;
|
let readFile: (file: string) => Promise<Buffer>;
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
const { readFileWithEolConversion } = require('./eol-conversion');
|
const { readFileWithEolConversion } = require('./eol-conversion');
|
||||||
readFile = file => readFileWithEolConversion(file, convertEol);
|
readFile = (file) => readFileWithEolConversion(file, convertEol);
|
||||||
} else {
|
} else {
|
||||||
readFile = fs.readFile;
|
readFile = fs.readFile;
|
||||||
}
|
}
|
||||||
@ -222,7 +222,7 @@ export function printGitignoreWarn(
|
|||||||
dockerignoreFile: string,
|
dockerignoreFile: string,
|
||||||
gitignoreFiles: string[],
|
gitignoreFiles: string[],
|
||||||
) {
|
) {
|
||||||
const ignoreFiles = [dockerignoreFile, ...gitignoreFiles].filter(e => e);
|
const ignoreFiles = [dockerignoreFile, ...gitignoreFiles].filter((e) => e);
|
||||||
if (ignoreFiles.length === 0) {
|
if (ignoreFiles.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -346,7 +346,7 @@ export async function makeBuildTasks(
|
|||||||
const buildTasks = await MultiBuild.splitBuildStream(composition, tarStream);
|
const buildTasks = await MultiBuild.splitBuildStream(composition, tarStream);
|
||||||
|
|
||||||
logger.logDebug('Found build tasks:');
|
logger.logDebug('Found build tasks:');
|
||||||
_.each(buildTasks, task => {
|
_.each(buildTasks, (task) => {
|
||||||
let infoStr: string;
|
let infoStr: string;
|
||||||
if (task.external) {
|
if (task.external) {
|
||||||
infoStr = `image pull [${task.imageName}]`;
|
infoStr = `image pull [${task.imageName}]`;
|
||||||
@ -369,7 +369,7 @@ export async function makeBuildTasks(
|
|||||||
);
|
);
|
||||||
|
|
||||||
logger.logDebug('Found project types:');
|
logger.logDebug('Found project types:');
|
||||||
_.each(buildTasks, task => {
|
_.each(buildTasks, (task) => {
|
||||||
if (task.external) {
|
if (task.external) {
|
||||||
logger.logDebug(` ${task.serviceName}: External image`);
|
logger.logDebug(` ${task.serviceName}: External image`);
|
||||||
} else {
|
} else {
|
||||||
@ -403,7 +403,7 @@ async function performResolution(
|
|||||||
);
|
);
|
||||||
// Do one task at a time (Bluebird.each instead of Bluebird.all)
|
// Do one task at a time (Bluebird.each instead of Bluebird.all)
|
||||||
// in order to reduce peak memory usage. Resolves to buildTasks.
|
// in order to reduce peak memory usage. Resolves to buildTasks.
|
||||||
Bluebird.each(buildTasks, buildTask => {
|
Bluebird.each(buildTasks, (buildTask) => {
|
||||||
// buildStream is falsy for "external" tasks (image pull)
|
// buildStream is falsy for "external" tasks (image pull)
|
||||||
if (!buildTask.buildStream) {
|
if (!buildTask.buildStream) {
|
||||||
return buildTask;
|
return buildTask;
|
||||||
@ -551,7 +551,7 @@ export async function validateProjectDirectory(
|
|||||||
const checkCompose = async (folder: string) => {
|
const checkCompose = async (folder: string) => {
|
||||||
return _.some(
|
return _.some(
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
compositionFileNames.map(filename =>
|
compositionFileNames.map((filename) =>
|
||||||
fs.exists(path.join(folder, filename)),
|
fs.exists(path.join(folder, filename)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -615,7 +615,7 @@ async function pushServiceImages(
|
|||||||
const { pushAndUpdateServiceImages } = await import('./compose');
|
const { pushAndUpdateServiceImages } = await import('./compose');
|
||||||
const releaseMod = await import('balena-release');
|
const releaseMod = await import('balena-release');
|
||||||
logger.logInfo('Pushing images to registry...');
|
logger.logInfo('Pushing images to registry...');
|
||||||
await pushAndUpdateServiceImages(docker, token, taggedImages, async function(
|
await pushAndUpdateServiceImages(docker, token, taggedImages, async function (
|
||||||
serviceImage,
|
serviceImage,
|
||||||
) {
|
) {
|
||||||
logger.logDebug(
|
logger.logDebug(
|
||||||
@ -713,12 +713,12 @@ function runSpinner(
|
|||||||
spinner: () => string,
|
spinner: () => string,
|
||||||
msg: string,
|
msg: string,
|
||||||
) {
|
) {
|
||||||
const runloop = createRunLoop(function() {
|
const runloop = createRunLoop(function () {
|
||||||
tty.clearLine();
|
tty.clearLine();
|
||||||
tty.writeLine(`${msg} ${spinner()}`);
|
tty.writeLine(`${msg} ${spinner()}`);
|
||||||
return tty.cursorUp();
|
return tty.cursorUp();
|
||||||
});
|
});
|
||||||
runloop.onEnd = function() {
|
runloop.onEnd = function () {
|
||||||
tty.clearLine();
|
tty.clearLine();
|
||||||
return tty.writeLine(msg);
|
return tty.writeLine(msg);
|
||||||
};
|
};
|
||||||
|
@ -72,7 +72,7 @@ export function generateBaseConfig(
|
|||||||
application.app_name,
|
application.app_name,
|
||||||
options,
|
options,
|
||||||
) as Promise<ImgConfig & { apiKey?: string }>;
|
) as Promise<ImgConfig & { apiKey?: string }>;
|
||||||
return promise.tap(config => {
|
return promise.tap((config) => {
|
||||||
// os.getConfig always returns a config for an app
|
// os.getConfig always returns a config for an app
|
||||||
delete config.apiKey;
|
delete config.apiKey;
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ export function generateApplicationConfig(
|
|||||||
application: BalenaSdk.Application,
|
application: BalenaSdk.Application,
|
||||||
options: { version: string; deviceType?: string },
|
options: { version: string; deviceType?: string },
|
||||||
) {
|
) {
|
||||||
return generateBaseConfig(application, options).tap(config => {
|
return generateBaseConfig(application, options).tap((config) => {
|
||||||
if (semver.satisfies(options.version, '<2.7.8')) {
|
if (semver.satisfies(options.version, '<2.7.8')) {
|
||||||
return addApplicationKey(config, application.id);
|
return addApplicationKey(config, application.id);
|
||||||
}
|
}
|
||||||
@ -108,12 +108,12 @@ export function generateDeviceConfig(
|
|||||||
) {
|
) {
|
||||||
return getBalenaSdk()
|
return getBalenaSdk()
|
||||||
.models.application.get(device.belongs_to__application.__id)
|
.models.application.get(device.belongs_to__application.__id)
|
||||||
.then(application => {
|
.then((application) => {
|
||||||
const baseConfigOpts = {
|
const baseConfigOpts = {
|
||||||
...options,
|
...options,
|
||||||
deviceType: device.device_type,
|
deviceType: device.device_type,
|
||||||
};
|
};
|
||||||
return generateBaseConfig(application, baseConfigOpts).tap(config => {
|
return generateBaseConfig(application, baseConfigOpts).tap((config) => {
|
||||||
if (
|
if (
|
||||||
deviceApiKey == null &&
|
deviceApiKey == null &&
|
||||||
semver.satisfies(options.version, '<2.0.3')
|
semver.satisfies(options.version, '<2.0.3')
|
||||||
@ -123,7 +123,7 @@ export function generateDeviceConfig(
|
|||||||
return addDeviceKey(config, device.uuid, deviceApiKey || true);
|
return addDeviceKey(config, device.uuid, deviceApiKey || true);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then(config => {
|
.then((config) => {
|
||||||
// Associate a device, to prevent the supervisor
|
// Associate a device, to prevent the supervisor
|
||||||
// from creating another one on its own.
|
// from creating another one on its own.
|
||||||
config.registered_at = Math.floor(Date.now() / 1000);
|
config.registered_at = Math.floor(Date.now() / 1000);
|
||||||
@ -137,7 +137,7 @@ export function generateDeviceConfig(
|
|||||||
function addApplicationKey(config: any, applicationNameOrId: string | number) {
|
function addApplicationKey(config: any, applicationNameOrId: string | number) {
|
||||||
return getBalenaSdk()
|
return getBalenaSdk()
|
||||||
.models.application.generateApiKey(applicationNameOrId)
|
.models.application.generateApiKey(applicationNameOrId)
|
||||||
.tap(apiKey => {
|
.tap((apiKey) => {
|
||||||
config.apiKey = apiKey;
|
config.apiKey = apiKey;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -145,7 +145,7 @@ function addApplicationKey(config: any, applicationNameOrId: string | number) {
|
|||||||
function addProvisioningKey(config: any, applicationNameOrId: string | number) {
|
function addProvisioningKey(config: any, applicationNameOrId: string | number) {
|
||||||
return getBalenaSdk()
|
return getBalenaSdk()
|
||||||
.models.application.generateProvisioningKey(applicationNameOrId)
|
.models.application.generateProvisioningKey(applicationNameOrId)
|
||||||
.tap(apiKey => {
|
.tap((apiKey) => {
|
||||||
config.apiKey = apiKey;
|
config.apiKey = apiKey;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -161,7 +161,7 @@ function addDeviceKey(
|
|||||||
} else {
|
} else {
|
||||||
return customDeviceApiKey;
|
return customDeviceApiKey;
|
||||||
}
|
}
|
||||||
}).tap(deviceApiKey => {
|
}).tap((deviceApiKey) => {
|
||||||
config.deviceApiKey = deviceApiKey;
|
config.deviceApiKey = deviceApiKey;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -18,19 +18,19 @@
|
|||||||
import * as Promise from 'bluebird';
|
import * as Promise from 'bluebird';
|
||||||
import { getVisuals } from './lazy';
|
import { getVisuals } from './lazy';
|
||||||
|
|
||||||
const getBuilderPushEndpoint = function(baseUrl, owner, app) {
|
const getBuilderPushEndpoint = function (baseUrl, owner, app) {
|
||||||
const querystring = require('querystring');
|
const querystring = require('querystring');
|
||||||
const args = querystring.stringify({ owner, app });
|
const args = querystring.stringify({ owner, app });
|
||||||
return `https://builder.${baseUrl}/v1/push?${args}`;
|
return `https://builder.${baseUrl}/v1/push?${args}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getBuilderLogPushEndpoint = function(baseUrl, buildId, owner, app) {
|
const getBuilderLogPushEndpoint = function (baseUrl, buildId, owner, app) {
|
||||||
const querystring = require('querystring');
|
const querystring = require('querystring');
|
||||||
const args = querystring.stringify({ owner, app, buildId });
|
const args = querystring.stringify({ owner, app, buildId });
|
||||||
return `https://builder.${baseUrl}/v1/pushLogs?${args}`;
|
return `https://builder.${baseUrl}/v1/pushLogs?${args}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const bufferImage = function(docker, imageId, bufferFile) {
|
const bufferImage = function (docker, imageId, bufferFile) {
|
||||||
const streamUtils = require('./streams');
|
const streamUtils = require('./streams');
|
||||||
|
|
||||||
const image = docker.getImage(imageId);
|
const image = docker.getImage(imageId);
|
||||||
@ -40,14 +40,14 @@ const bufferImage = function(docker, imageId, bufferFile) {
|
|||||||
image.get(),
|
image.get(),
|
||||||
imageMetadata.get('Size'),
|
imageMetadata.get('Size'),
|
||||||
(imageStream, imageSize) =>
|
(imageStream, imageSize) =>
|
||||||
streamUtils.buffer(imageStream, bufferFile).tap(bufferedStream => {
|
streamUtils.buffer(imageStream, bufferFile).tap((bufferedStream) => {
|
||||||
// @ts-ignore adding an extra property
|
// @ts-ignore adding an extra property
|
||||||
bufferedStream.length = imageSize;
|
bufferedStream.length = imageSize;
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const showPushProgress = function(message) {
|
const showPushProgress = function (message) {
|
||||||
const visuals = getVisuals();
|
const visuals = getVisuals();
|
||||||
const progressBar = new visuals.Progress(message);
|
const progressBar = new visuals.Progress(message);
|
||||||
progressBar.update({ percentage: 0 });
|
progressBar.update({ percentage: 0 });
|
||||||
@ -55,8 +55,8 @@ const showPushProgress = function(message) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const uploadToPromise = (uploadRequest, logger) =>
|
const uploadToPromise = (uploadRequest, logger) =>
|
||||||
new Promise(function(resolve, reject) {
|
new Promise(function (resolve, reject) {
|
||||||
const handleMessage = function(data) {
|
const handleMessage = function (data) {
|
||||||
let obj;
|
let obj;
|
||||||
data = data.toString();
|
data = data.toString();
|
||||||
logger.logDebug(`Received data: ${data}`);
|
logger.logDebug(`Received data: ${data}`);
|
||||||
@ -90,7 +90,7 @@ const uploadToPromise = (uploadRequest, logger) =>
|
|||||||
/**
|
/**
|
||||||
* @returns {Promise<{ buildId: number }>}
|
* @returns {Promise<{ buildId: number }>}
|
||||||
*/
|
*/
|
||||||
const uploadImage = function(
|
const uploadImage = function (
|
||||||
imageStream,
|
imageStream,
|
||||||
token,
|
token,
|
||||||
username,
|
username,
|
||||||
@ -139,7 +139,7 @@ const uploadImage = function(
|
|||||||
return uploadToPromise(uploadRequest, logger);
|
return uploadToPromise(uploadRequest, logger);
|
||||||
};
|
};
|
||||||
|
|
||||||
const uploadLogs = function(logs, token, url, buildId, username, appName) {
|
const uploadLogs = function (logs, token, url, buildId, username, appName) {
|
||||||
const request = require('request');
|
const request = require('request');
|
||||||
return request.post({
|
return request.post({
|
||||||
json: true,
|
json: true,
|
||||||
@ -159,7 +159,7 @@ opts must be a hash with the following keys:
|
|||||||
- buildLogs: a string with build output
|
- buildLogs: a string with build output
|
||||||
- shouldUploadLogs
|
- shouldUploadLogs
|
||||||
*/
|
*/
|
||||||
export const deployLegacy = function(
|
export const deployLegacy = function (
|
||||||
docker,
|
docker,
|
||||||
logger,
|
logger,
|
||||||
token,
|
token,
|
||||||
@ -177,10 +177,10 @@ export const deployLegacy = function(
|
|||||||
const logs = buildLogs;
|
const logs = buildLogs;
|
||||||
|
|
||||||
return tmpNameAsync()
|
return tmpNameAsync()
|
||||||
.then(function(bufferFile) {
|
.then(function (bufferFile) {
|
||||||
logger.logInfo('Initializing deploy...');
|
logger.logInfo('Initializing deploy...');
|
||||||
return bufferImage(docker, imageName, bufferFile)
|
return bufferImage(docker, imageName, bufferFile)
|
||||||
.then(stream =>
|
.then((stream) =>
|
||||||
uploadImage(stream, token, username, url, appName, logger),
|
uploadImage(stream, token, username, url, appName, logger),
|
||||||
)
|
)
|
||||||
.finally(() =>
|
.finally(() =>
|
||||||
@ -192,7 +192,7 @@ export const deployLegacy = function(
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.tap(function({ buildId }) {
|
.tap(function ({ buildId }) {
|
||||||
if (!shouldUploadLogs) {
|
if (!shouldUploadLogs) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ export class DeviceAPI {
|
|||||||
json: true,
|
json: true,
|
||||||
},
|
},
|
||||||
this.logger,
|
this.logger,
|
||||||
).then(body => {
|
).then((body) => {
|
||||||
return body.state;
|
return body.state;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -120,7 +120,7 @@ export class DeviceAPI {
|
|||||||
json: true,
|
json: true,
|
||||||
},
|
},
|
||||||
this.logger,
|
this.logger,
|
||||||
).then(body => {
|
).then((body) => {
|
||||||
return body.info;
|
return body.info;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -166,7 +166,7 @@ export class DeviceAPI {
|
|||||||
return DeviceAPI.promisifiedRequest(request.get, {
|
return DeviceAPI.promisifiedRequest(request.get, {
|
||||||
url,
|
url,
|
||||||
json: true,
|
json: true,
|
||||||
}).then(body => {
|
}).then((body) => {
|
||||||
if (body.status !== 'success') {
|
if (body.status !== 'success') {
|
||||||
throw new ApiErrors.DeviceAPIError(
|
throw new ApiErrors.DeviceAPIError(
|
||||||
'Non-successful response from supervisor version endpoint',
|
'Non-successful response from supervisor version endpoint',
|
||||||
@ -183,7 +183,7 @@ export class DeviceAPI {
|
|||||||
return DeviceAPI.promisifiedRequest(request.get, {
|
return DeviceAPI.promisifiedRequest(request.get, {
|
||||||
url,
|
url,
|
||||||
json: true,
|
json: true,
|
||||||
}).then(body => {
|
}).then((body) => {
|
||||||
if (body.status !== 'success') {
|
if (body.status !== 'success') {
|
||||||
throw new ApiErrors.DeviceAPIError(
|
throw new ApiErrors.DeviceAPIError(
|
||||||
'Non-successful response from supervisor status endpoint',
|
'Non-successful response from supervisor status endpoint',
|
||||||
@ -201,7 +201,7 @@ export class DeviceAPI {
|
|||||||
return new Bluebird((resolve, reject) => {
|
return new Bluebird((resolve, reject) => {
|
||||||
const req = request.get(url);
|
const req = request.get(url);
|
||||||
|
|
||||||
req.on('error', reject).on('response', async res => {
|
req.on('error', reject).on('response', async (res) => {
|
||||||
if (res.statusCode !== 200) {
|
if (res.statusCode !== 200) {
|
||||||
reject(
|
reject(
|
||||||
new ApiErrors.DeviceAPIError(
|
new ApiErrors.DeviceAPIError(
|
||||||
@ -261,7 +261,7 @@ export class DeviceAPI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Bluebird.fromCallback<[request.Response, { message: string }]>(
|
return Bluebird.fromCallback<[request.Response, { message: string }]>(
|
||||||
cb => {
|
(cb) => {
|
||||||
return requestMethod(opts, cb);
|
return requestMethod(opts, cb);
|
||||||
},
|
},
|
||||||
{ multiArgs: true },
|
{ multiArgs: true },
|
||||||
|
@ -315,7 +315,7 @@ export async function performBuilds(
|
|||||||
logger,
|
logger,
|
||||||
LOCAL_APPNAME,
|
LOCAL_APPNAME,
|
||||||
LOCAL_RELEASEHASH,
|
LOCAL_RELEASEHASH,
|
||||||
content => {
|
(content) => {
|
||||||
if (!opts.nolive) {
|
if (!opts.nolive) {
|
||||||
return LivepushManager.preprocessDockerfile(content);
|
return LivepushManager.preprocessDockerfile(content);
|
||||||
} else {
|
} else {
|
||||||
@ -356,7 +356,7 @@ export async function performBuilds(
|
|||||||
|
|
||||||
// Now tag any external images with the correct name that they should be,
|
// Now tag any external images with the correct name that they should be,
|
||||||
// as this won't be done by resin-multibuild
|
// as this won't be done by resin-multibuild
|
||||||
await Bluebird.map(localImages, async localImage => {
|
await Bluebird.map(localImages, async (localImage) => {
|
||||||
if (localImage.external) {
|
if (localImage.external) {
|
||||||
// We can be sure that localImage.name is set here, because of the failure code above
|
// We can be sure that localImage.name is set here, because of the failure code above
|
||||||
const image = docker.getImage(localImage.name!);
|
const image = docker.getImage(localImage.name!);
|
||||||
@ -368,7 +368,7 @@ export async function performBuilds(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
await Bluebird.map(_.uniq(imagesToRemove), image =>
|
await Bluebird.map(_.uniq(imagesToRemove), (image) =>
|
||||||
docker.getImage(image).remove({ force: true }),
|
docker.getImage(image).remove({ force: true }),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -419,7 +419,7 @@ export async function rebuildSingleTask(
|
|||||||
logger,
|
logger,
|
||||||
LOCAL_APPNAME,
|
LOCAL_APPNAME,
|
||||||
LOCAL_RELEASEHASH,
|
LOCAL_RELEASEHASH,
|
||||||
content => {
|
(content) => {
|
||||||
if (!opts.nolive) {
|
if (!opts.nolive) {
|
||||||
return LivepushManager.preprocessDockerfile(content);
|
return LivepushManager.preprocessDockerfile(content);
|
||||||
} else {
|
} else {
|
||||||
@ -460,16 +460,16 @@ function assignOutputHandlers(
|
|||||||
logger: Logger,
|
logger: Logger,
|
||||||
logCb?: (serviceName: string, line: string) => void,
|
logCb?: (serviceName: string, line: string) => void,
|
||||||
) {
|
) {
|
||||||
_.each(buildTasks, task => {
|
_.each(buildTasks, (task) => {
|
||||||
if (task.external) {
|
if (task.external) {
|
||||||
task.progressHook = progressObj => {
|
task.progressHook = (progressObj) => {
|
||||||
displayBuildLog(
|
displayBuildLog(
|
||||||
{ serviceName: task.serviceName, message: progressObj.progress },
|
{ serviceName: task.serviceName, message: progressObj.progress },
|
||||||
logger,
|
logger,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
task.streamHook = stream => {
|
task.streamHook = (stream) => {
|
||||||
stream.on('data', (buf: Buffer) => {
|
stream.on('data', (buf: Buffer) => {
|
||||||
const str = _.trimEnd(buf.toString());
|
const str = _.trimEnd(buf.toString());
|
||||||
if (str !== '') {
|
if (str !== '') {
|
||||||
@ -601,7 +601,7 @@ async function inspectBuildResults(images: LocalImage[]): Promise<void> {
|
|||||||
|
|
||||||
const failures: LocalPushErrors.BuildFailure[] = [];
|
const failures: LocalPushErrors.BuildFailure[] = [];
|
||||||
|
|
||||||
_.each(images, image => {
|
_.each(images, (image) => {
|
||||||
if (!image.successful) {
|
if (!image.successful) {
|
||||||
failures.push({
|
failures.push({
|
||||||
error: image.error!,
|
error: image.error!,
|
||||||
|
@ -17,14 +17,14 @@ export class BuildError extends TypedError {
|
|||||||
|
|
||||||
public toString(): string {
|
public toString(): string {
|
||||||
let str = 'Some services failed to build:\n';
|
let str = 'Some services failed to build:\n';
|
||||||
_.each(this.failures, failure => {
|
_.each(this.failures, (failure) => {
|
||||||
str += `\t${failure.serviceName}: ${failure.error.message}\n`;
|
str += `\t${failure.serviceName}: ${failure.error.message}\n`;
|
||||||
});
|
});
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getServiceError(serviceName: string): string {
|
public getServiceError(serviceName: string): string {
|
||||||
const failure = _.find(this.failures, f => f.serviceName === serviceName);
|
const failure = _.find(this.failures, (f) => f.serviceName === serviceName);
|
||||||
if (failure == null) {
|
if (failure == null) {
|
||||||
return 'Unknown build failure';
|
return 'Unknown build failure';
|
||||||
}
|
}
|
||||||
|
@ -199,7 +199,7 @@ export class LivepushManager {
|
|||||||
process.on('SIGINT', async () => {
|
process.on('SIGINT', async () => {
|
||||||
this.logger.logLivepush('Cleaning up device...');
|
this.logger.logLivepush('Cleaning up device...');
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
_.map(this.containers, container => {
|
_.map(this.containers, (container) => {
|
||||||
container.livepush.cleanupIntermediateContainers();
|
container.livepush.cleanupIntermediateContainers();
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@ -263,8 +263,8 @@ export class LivepushManager {
|
|||||||
// First we detect if the file changed is the Dockerfile
|
// First we detect if the file changed is the Dockerfile
|
||||||
// used to build the service
|
// used to build the service
|
||||||
if (
|
if (
|
||||||
_.some(this.dockerfilePaths[serviceName], name =>
|
_.some(this.dockerfilePaths[serviceName], (name) =>
|
||||||
_.some(updated, changed => name === changed),
|
_.some(updated, (changed) => name === changed),
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
this.logger.logLivepush(
|
this.logger.logLivepush(
|
||||||
@ -330,7 +330,7 @@ export class LivepushManager {
|
|||||||
this.composition,
|
this.composition,
|
||||||
this.buildContext,
|
this.buildContext,
|
||||||
this.deployOpts,
|
this.deployOpts,
|
||||||
id => {
|
(id) => {
|
||||||
this.rebuildRunningIds[serviceName] = id;
|
this.rebuildRunningIds[serviceName] = id;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -430,10 +430,10 @@ export class LivepushManager {
|
|||||||
const error = (msg: string) => this.logger.logError(msgString(msg));
|
const error = (msg: string) => this.logger.logError(msgString(msg));
|
||||||
const debugLog = (msg: string) => this.logger.logDebug(msgString(msg));
|
const debugLog = (msg: string) => this.logger.logDebug(msgString(msg));
|
||||||
|
|
||||||
livepush.on('commandExecute', command =>
|
livepush.on('commandExecute', (command) =>
|
||||||
log(`Executing command: \`${command.command}\``),
|
log(`Executing command: \`${command.command}\``),
|
||||||
);
|
);
|
||||||
livepush.on('commandOutput', output =>
|
livepush.on('commandOutput', (output) =>
|
||||||
log(` ${output.output.data.toString()}`),
|
log(` ${output.output.data.toString()}`),
|
||||||
);
|
);
|
||||||
livepush.on('commandReturn', ({ returnCode, command }) => {
|
livepush.on('commandReturn', ({ returnCode, command }) => {
|
||||||
|
@ -40,7 +40,7 @@ export function displayDeviceLogs(
|
|||||||
filterServices?: string[],
|
filterServices?: string[],
|
||||||
): Bluebird<void> {
|
): Bluebird<void> {
|
||||||
return new Bluebird((resolve, reject) => {
|
return new Bluebird((resolve, reject) => {
|
||||||
logs.on('data', log => {
|
logs.on('data', (log) => {
|
||||||
displayLogLine(log, logger, system, filterServices);
|
displayLogLine(log, logger, system, filterServices);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ export async function performLocalDeviceSSH(
|
|||||||
|
|
||||||
const serviceNames: string[] = [];
|
const serviceNames: string[] = [];
|
||||||
const containers = allContainers
|
const containers = allContainers
|
||||||
.map(container => {
|
.map((container) => {
|
||||||
for (const name of container.Names) {
|
for (const name of container.Names) {
|
||||||
if (regex.test(name)) {
|
if (regex.test(name)) {
|
||||||
return { id: container.Id, name };
|
return { id: container.Id, name };
|
||||||
@ -75,7 +75,7 @@ export async function performLocalDeviceSSH(
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
})
|
})
|
||||||
.filter(c => c != null);
|
.filter((c) => c != null);
|
||||||
|
|
||||||
if (containers.length === 0) {
|
if (containers.length === 0) {
|
||||||
throw new ExpectedError(
|
throw new ExpectedError(
|
||||||
|
@ -26,7 +26,7 @@ import * as _ from 'lodash';
|
|||||||
//
|
//
|
||||||
// NOTE: Care MUST be taken when using the function, so as to
|
// NOTE: Care MUST be taken when using the function, so as to
|
||||||
// not redefine/override options already provided.
|
// not redefine/override options already provided.
|
||||||
export const appendConnectionOptions = opts =>
|
export const appendConnectionOptions = (opts) =>
|
||||||
opts.concat([
|
opts.concat([
|
||||||
{
|
{
|
||||||
signature: 'docker',
|
signature: 'docker',
|
||||||
@ -106,10 +106,10 @@ Implements the same feature as the "docker build --cache-from" option.`,
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const generateConnectOpts = function(opts) {
|
const generateConnectOpts = function (opts) {
|
||||||
const fs = require('mz/fs');
|
const fs = require('mz/fs');
|
||||||
|
|
||||||
return Promise.try(function() {
|
return Promise.try(function () {
|
||||||
const connectOpts = {};
|
const connectOpts = {};
|
||||||
// Firsly need to decide between a local docker socket
|
// Firsly need to decide between a local docker socket
|
||||||
// and a host available over a host:port combo
|
// and a host available over a host:port combo
|
||||||
@ -152,7 +152,7 @@ const generateConnectOpts = function(opts) {
|
|||||||
cert: fs.readFile(opts.cert, 'utf-8'),
|
cert: fs.readFile(opts.cert, 'utf-8'),
|
||||||
key: fs.readFile(opts.key, 'utf-8'),
|
key: fs.readFile(opts.key, 'utf-8'),
|
||||||
};
|
};
|
||||||
return Promise.props(certBodies).then(toMerge =>
|
return Promise.props(certBodies).then((toMerge) =>
|
||||||
_.merge(connectOpts, toMerge),
|
_.merge(connectOpts, toMerge),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -161,12 +161,12 @@ const generateConnectOpts = function(opts) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const parseBuildArgs = function(args) {
|
const parseBuildArgs = function (args) {
|
||||||
if (!Array.isArray(args)) {
|
if (!Array.isArray(args)) {
|
||||||
args = [args];
|
args = [args];
|
||||||
}
|
}
|
||||||
const buildArgs = {};
|
const buildArgs = {};
|
||||||
args.forEach(function(arg) {
|
args.forEach(function (arg) {
|
||||||
// note: [^] matches any character, including line breaks
|
// note: [^] matches any character, including line breaks
|
||||||
const pair = /^([^\s]+?)=([^]*)$/.exec(arg);
|
const pair = /^([^\s]+?)=([^]*)$/.exec(arg);
|
||||||
if (pair != null) {
|
if (pair != null) {
|
||||||
@ -187,7 +187,7 @@ export function generateBuildOpts(options) {
|
|||||||
opts.nocache = true;
|
opts.nocache = true;
|
||||||
}
|
}
|
||||||
if (options['cache-from']?.trim()) {
|
if (options['cache-from']?.trim()) {
|
||||||
opts.cachefrom = options['cache-from'].split(',').filter(i => !!i.trim());
|
opts.cachefrom = options['cache-from'].split(',').filter((i) => !!i.trim());
|
||||||
}
|
}
|
||||||
if (options.squash != null) {
|
if (options.squash != null) {
|
||||||
opts.squash = true;
|
opts.squash = true;
|
||||||
@ -220,7 +220,7 @@ export function getDocker(options) {
|
|||||||
.tap(ensureDockerSeemsAccessible);
|
.tap(ensureDockerSeemsAccessible);
|
||||||
}
|
}
|
||||||
|
|
||||||
const getDockerToolbelt = _.once(function() {
|
const getDockerToolbelt = _.once(function () {
|
||||||
const Docker = require('docker-toolbelt');
|
const Docker = require('docker-toolbelt');
|
||||||
Promise.promisifyAll(Docker.prototype, {
|
Promise.promisifyAll(Docker.prototype, {
|
||||||
filter(name) {
|
filter(name) {
|
||||||
@ -252,7 +252,7 @@ const getDockerToolbelt = _.once(function() {
|
|||||||
* }} opts
|
* }} opts
|
||||||
* @returns {import('docker-toolbelt')}
|
* @returns {import('docker-toolbelt')}
|
||||||
*/
|
*/
|
||||||
export const createClient = function(opts) {
|
export const createClient = function (opts) {
|
||||||
const Docker = getDockerToolbelt();
|
const Docker = getDockerToolbelt();
|
||||||
const docker = new Docker(opts);
|
const docker = new Docker(opts);
|
||||||
const { modem } = docker;
|
const { modem } = docker;
|
||||||
@ -269,7 +269,7 @@ export const createClient = function(opts) {
|
|||||||
return docker;
|
return docker;
|
||||||
};
|
};
|
||||||
|
|
||||||
var ensureDockerSeemsAccessible = function(docker) {
|
var ensureDockerSeemsAccessible = function (docker) {
|
||||||
const { exitWithExpectedError } = require('../errors');
|
const { exitWithExpectedError } = require('../errors');
|
||||||
return docker
|
return docker
|
||||||
.ping()
|
.ping()
|
||||||
|
@ -30,7 +30,7 @@ export function getGroupDefaults(group: {
|
|||||||
}): { [name: string]: string | number | undefined } {
|
}): { [name: string]: string | number | undefined } {
|
||||||
return _.chain(group)
|
return _.chain(group)
|
||||||
.get('options')
|
.get('options')
|
||||||
.map(question => [question.name, question.default])
|
.map((question) => [question.name, question.default])
|
||||||
.fromPairs()
|
.fromPairs()
|
||||||
.value();
|
.value();
|
||||||
}
|
}
|
||||||
@ -96,7 +96,7 @@ export async function sudo(
|
|||||||
|
|
||||||
export function runCommand<T>(command: string): Bluebird<T> {
|
export function runCommand<T>(command: string): Bluebird<T> {
|
||||||
const capitano = require('capitano');
|
const capitano = require('capitano');
|
||||||
return Bluebird.fromCallback(resolver => capitano.run(command, resolver));
|
return Bluebird.fromCallback((resolver) => capitano.run(command, resolver));
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getManifest(
|
export async function getManifest(
|
||||||
@ -122,7 +122,7 @@ export async function osProgressHandler(step: InitializeEmitter) {
|
|||||||
step.on('stdout', process.stdout.write.bind(process.stdout));
|
step.on('stdout', process.stdout.write.bind(process.stdout));
|
||||||
step.on('stderr', process.stderr.write.bind(process.stderr));
|
step.on('stderr', process.stderr.write.bind(process.stderr));
|
||||||
|
|
||||||
step.on('state', function(state) {
|
step.on('state', function (state) {
|
||||||
if (state.operation.command === 'burn') {
|
if (state.operation.command === 'burn') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -135,7 +135,7 @@ export async function osProgressHandler(step: InitializeEmitter) {
|
|||||||
check: new visuals.Progress('Validating Device OS'),
|
check: new visuals.Progress('Validating Device OS'),
|
||||||
};
|
};
|
||||||
|
|
||||||
step.on('burn', state => progressBars[state.type].update(state));
|
step.on('burn', (state) => progressBars[state.type].update(state));
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
step.on('error', reject);
|
step.on('error', reject);
|
||||||
@ -149,7 +149,7 @@ export function getAppWithArch(
|
|||||||
return Bluebird.join(
|
return Bluebird.join(
|
||||||
getApplication(applicationName),
|
getApplication(applicationName),
|
||||||
getBalenaSdk().models.config.getDeviceTypes(),
|
getBalenaSdk().models.config.getDeviceTypes(),
|
||||||
function(app, deviceTypes) {
|
function (app, deviceTypes) {
|
||||||
const config = _.find<BalenaSdk.DeviceType>(deviceTypes, {
|
const config = _.find<BalenaSdk.DeviceType>(deviceTypes, {
|
||||||
slug: app.device_type,
|
slug: app.device_type,
|
||||||
});
|
});
|
||||||
@ -214,8 +214,9 @@ export function retry<T>(
|
|||||||
promise = promise.catch((err: Error) => {
|
promise = promise.catch((err: Error) => {
|
||||||
const delay = backoffScaler ** count * delayMs;
|
const delay = backoffScaler ** count * delayMs;
|
||||||
console.log(
|
console.log(
|
||||||
`Retrying "${label}" after ${(delay / 1000).toFixed(2)}s (${count +
|
`Retrying "${label}" after ${(delay / 1000).toFixed(2)}s (${
|
||||||
1} of ${times}) due to: ${err}`,
|
count + 1
|
||||||
|
} of ${times}) due to: ${err}`,
|
||||||
);
|
);
|
||||||
return Bluebird.delay(delay).then(() =>
|
return Bluebird.delay(delay).then(() =>
|
||||||
retry(func, times, label, delayMs, backoffScaler, count + 1),
|
retry(func, times, label, delayMs, backoffScaler, count + 1),
|
||||||
@ -255,7 +256,7 @@ export function getManualSortCompareFunction<T, U = T>(
|
|||||||
manuallySortedArray: U[],
|
manuallySortedArray: U[],
|
||||||
equalityFunc: (a: T, x: U, index: number, array: U[]) => boolean,
|
equalityFunc: (a: T, x: U, index: number, array: U[]) => boolean,
|
||||||
): (a: T, b: T) => number {
|
): (a: T, b: T) => number {
|
||||||
return function(a: T, b: T): number {
|
return function (a: T, b: T): number {
|
||||||
const indexA = manuallySortedArray.findIndex((x, index, array) =>
|
const indexA = manuallySortedArray.findIndex((x, index, array) =>
|
||||||
equalityFunc(a, x, index, array),
|
equalityFunc(a, x, index, array),
|
||||||
);
|
);
|
||||||
@ -302,10 +303,10 @@ export function shellEscape(args: string[], detectShell = false): string[] {
|
|||||||
? isWindowsComExeShell()
|
? isWindowsComExeShell()
|
||||||
: process.platform === 'win32';
|
: process.platform === 'win32';
|
||||||
if (isCmdExe) {
|
if (isCmdExe) {
|
||||||
return args.map(v => windowsCmdExeEscapeArg(v));
|
return args.map((v) => windowsCmdExeEscapeArg(v));
|
||||||
} else {
|
} else {
|
||||||
const shellEscapeFunc: typeof ShellEscape = require('shell-escape');
|
const shellEscapeFunc: typeof ShellEscape = require('shell-escape');
|
||||||
return args.map(v => shellEscapeFunc([v]));
|
return args.map((v) => shellEscapeFunc([v]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ export class FileIgnorer {
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const contents = await fs.readFile(fullPath, 'utf8');
|
const contents = await fs.readFile(fullPath, 'utf8');
|
||||||
|
|
||||||
contents.split('\n').forEach(line => {
|
contents.split('\n').forEach((line) => {
|
||||||
// ignore empty lines and comments
|
// ignore empty lines and comments
|
||||||
if (/\s*#/.test(line) || _.isEmpty(line)) {
|
if (/\s*#/.test(line) || _.isEmpty(line)) {
|
||||||
return;
|
return;
|
||||||
@ -205,7 +205,7 @@ async function listFiles(
|
|||||||
const files: FileStats[] = [];
|
const files: FileStats[] = [];
|
||||||
const dirEntries = await fs.readdir(dir);
|
const dirEntries = await fs.readdir(dir);
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
dirEntries.map(async entry => {
|
dirEntries.map(async (entry) => {
|
||||||
const filePath = path.join(dir, entry);
|
const filePath = path.join(dir, entry);
|
||||||
const stats = await fs.stat(filePath);
|
const stats = await fs.stat(filePath);
|
||||||
if (stats.isDirectory()) {
|
if (stats.isDirectory()) {
|
||||||
|
@ -80,7 +80,7 @@ class Logger {
|
|||||||
livepush: logger.createLogStream('live'),
|
livepush: logger.createLogStream('live'),
|
||||||
};
|
};
|
||||||
|
|
||||||
_.forEach(this.streams, function(stream, key) {
|
_.forEach(this.streams, function (stream, key) {
|
||||||
if (key !== 'debug') {
|
if (key !== 'debug') {
|
||||||
stream.pipe(process.stdout);
|
stream.pipe(process.stdout);
|
||||||
} else if (process.env.DEBUG) {
|
} else if (process.env.DEBUG) {
|
||||||
@ -139,14 +139,14 @@ class Logger {
|
|||||||
* Log a message for output later, ignore duplicates.
|
* Log a message for output later, ignore duplicates.
|
||||||
*/
|
*/
|
||||||
public deferredLog(msg: string, level: Level) {
|
public deferredLog(msg: string, level: Level) {
|
||||||
if (!this.deferredLogMessages.find(entry => entry[0] === msg)) {
|
if (!this.deferredLogMessages.find((entry) => entry[0] === msg)) {
|
||||||
this.deferredLogMessages.push([msg, level]);
|
this.deferredLogMessages.push([msg, level]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Output any messages that have been queued for deferred output */
|
/** Output any messages that have been queued for deferred output */
|
||||||
public outputDeferredMessages() {
|
public outputDeferredMessages() {
|
||||||
this.deferredLogMessages.forEach(m => {
|
this.deferredLogMessages.forEach((m) => {
|
||||||
this.streams[m[1]].write(m[0] + eol);
|
this.streams[m[1]].write(m[0] + eol);
|
||||||
});
|
});
|
||||||
this.deferredLogMessages = [];
|
this.deferredLogMessages = [];
|
||||||
|
@ -37,8 +37,8 @@ export class CommandHelp {
|
|||||||
return CommandHelp.compact([
|
return CommandHelp.compact([
|
||||||
// this.command.id,
|
// this.command.id,
|
||||||
(this.command.args || [])
|
(this.command.args || [])
|
||||||
.filter(a => !a.hidden)
|
.filter((a) => !a.hidden)
|
||||||
.map(a => this.arg(a))
|
.map((a) => this.arg(a))
|
||||||
.join(' '),
|
.join(' '),
|
||||||
]).join(' ');
|
]).join(' ');
|
||||||
}
|
}
|
||||||
@ -54,6 +54,6 @@ export function capitanoizeOclifUsage(
|
|||||||
): string {
|
): string {
|
||||||
return (oclifUsage || '')
|
return (oclifUsage || '')
|
||||||
.toString()
|
.toString()
|
||||||
.replace(/(?<=\s)[A-Z]+(?=(\s|$))/g, match => `<${match}>`)
|
.replace(/(?<=\s)[A-Z]+(?=(\s|$))/g, (match) => `<${match}>`)
|
||||||
.toLowerCase();
|
.toLowerCase();
|
||||||
}
|
}
|
||||||
|
@ -123,9 +123,9 @@ export function askLoginType() {
|
|||||||
export function selectDeviceType() {
|
export function selectDeviceType() {
|
||||||
return getBalenaSdk()
|
return getBalenaSdk()
|
||||||
.models.config.getDeviceTypes()
|
.models.config.getDeviceTypes()
|
||||||
.then(deviceTypes => {
|
.then((deviceTypes) => {
|
||||||
deviceTypes = _.sortBy(deviceTypes, 'name').filter(
|
deviceTypes = _.sortBy(deviceTypes, 'name').filter(
|
||||||
dt => dt.state !== 'DISCONTINUED',
|
(dt) => dt.state !== 'DISCONTINUED',
|
||||||
);
|
);
|
||||||
return getForm().ask({
|
return getForm().ask({
|
||||||
message: 'Device Type',
|
message: 'Device Type',
|
||||||
@ -144,7 +144,7 @@ export function confirm(
|
|||||||
yesMessage?: string,
|
yesMessage?: string,
|
||||||
exitIfDeclined = false,
|
exitIfDeclined = false,
|
||||||
) {
|
) {
|
||||||
return Bluebird.try(function() {
|
return Bluebird.try(function () {
|
||||||
if (yesOption) {
|
if (yesOption) {
|
||||||
if (yesMessage) {
|
if (yesMessage) {
|
||||||
console.log(yesMessage);
|
console.log(yesMessage);
|
||||||
@ -157,7 +157,7 @@ export function confirm(
|
|||||||
type: 'confirm',
|
type: 'confirm',
|
||||||
default: false,
|
default: false,
|
||||||
});
|
});
|
||||||
}).then(function(confirmed) {
|
}).then(function (confirmed) {
|
||||||
if (!confirmed) {
|
if (!confirmed) {
|
||||||
const err = new Error('Aborted');
|
const err = new Error('Aborted');
|
||||||
if (exitIfDeclined) {
|
if (exitIfDeclined) {
|
||||||
@ -174,7 +174,7 @@ export function selectApplication(
|
|||||||
const balena = getBalenaSdk();
|
const balena = getBalenaSdk();
|
||||||
return balena.models.application
|
return balena.models.application
|
||||||
.hasAny()
|
.hasAny()
|
||||||
.then(function(hasAnyApplications) {
|
.then(function (hasAnyApplications) {
|
||||||
if (!hasAnyApplications) {
|
if (!hasAnyApplications) {
|
||||||
throw new Error("You don't have any applications");
|
throw new Error("You don't have any applications");
|
||||||
}
|
}
|
||||||
@ -182,11 +182,11 @@ export function selectApplication(
|
|||||||
return balena.models.application.getAll();
|
return balena.models.application.getAll();
|
||||||
})
|
})
|
||||||
.filter(filter || _.constant(true))
|
.filter(filter || _.constant(true))
|
||||||
.then(applications => {
|
.then((applications) => {
|
||||||
return getForm().ask({
|
return getForm().ask({
|
||||||
message: 'Select an application',
|
message: 'Select an application',
|
||||||
type: 'list',
|
type: 'list',
|
||||||
choices: _.map(applications, application => ({
|
choices: _.map(applications, (application) => ({
|
||||||
name: `${application.app_name} (${application.device_type})`,
|
name: `${application.app_name} (${application.device_type})`,
|
||||||
value: application.app_name,
|
value: application.app_name,
|
||||||
})),
|
})),
|
||||||
@ -198,17 +198,17 @@ export function selectOrCreateApplication() {
|
|||||||
const balena = getBalenaSdk();
|
const balena = getBalenaSdk();
|
||||||
return balena.models.application
|
return balena.models.application
|
||||||
.hasAny()
|
.hasAny()
|
||||||
.then(hasAnyApplications => {
|
.then((hasAnyApplications) => {
|
||||||
if (!hasAnyApplications) {
|
if (!hasAnyApplications) {
|
||||||
// Just to make TS happy
|
// Just to make TS happy
|
||||||
return Promise.resolve(undefined);
|
return Promise.resolve(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
return balena.models.application.getAll().then(applications => {
|
return balena.models.application.getAll().then((applications) => {
|
||||||
const appOptions = _.map<
|
const appOptions = _.map<
|
||||||
BalenaSdk.Application,
|
BalenaSdk.Application,
|
||||||
{ name: string; value: string | null }
|
{ name: string; value: string | null }
|
||||||
>(applications, application => ({
|
>(applications, (application) => ({
|
||||||
name: `${application.app_name} (${application.device_type})`,
|
name: `${application.app_name} (${application.device_type})`,
|
||||||
value: application.app_name,
|
value: application.app_name,
|
||||||
}));
|
}));
|
||||||
@ -225,7 +225,7 @@ export function selectOrCreateApplication() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then(application => {
|
.then((application) => {
|
||||||
if (application) {
|
if (application) {
|
||||||
return application;
|
return application;
|
||||||
}
|
}
|
||||||
@ -240,14 +240,14 @@ export function selectOrCreateApplication() {
|
|||||||
|
|
||||||
export function awaitDevice(uuid: string) {
|
export function awaitDevice(uuid: string) {
|
||||||
const balena = getBalenaSdk();
|
const balena = getBalenaSdk();
|
||||||
return balena.models.device.getName(uuid).then(deviceName => {
|
return balena.models.device.getName(uuid).then((deviceName) => {
|
||||||
const visuals = getVisuals();
|
const visuals = getVisuals();
|
||||||
const spinner = new visuals.Spinner(
|
const spinner = new visuals.Spinner(
|
||||||
`Waiting for ${deviceName} to come online`,
|
`Waiting for ${deviceName} to come online`,
|
||||||
);
|
);
|
||||||
|
|
||||||
const poll = (): Bluebird<void> => {
|
const poll = (): Bluebird<void> => {
|
||||||
return balena.models.device.isOnline(uuid).then(function(isOnline) {
|
return balena.models.device.isOnline(uuid).then(function (isOnline) {
|
||||||
if (isOnline) {
|
if (isOnline) {
|
||||||
spinner.stop();
|
spinner.stop();
|
||||||
console.info(`The device **${deviceName}** is online!`);
|
console.info(`The device **${deviceName}** is online!`);
|
||||||
@ -270,7 +270,7 @@ export function awaitDevice(uuid: string) {
|
|||||||
export function awaitDeviceOsUpdate(uuid: string, targetOsVersion: string) {
|
export function awaitDeviceOsUpdate(uuid: string, targetOsVersion: string) {
|
||||||
const balena = getBalenaSdk();
|
const balena = getBalenaSdk();
|
||||||
|
|
||||||
return balena.models.device.getName(uuid).then(deviceName => {
|
return balena.models.device.getName(uuid).then((deviceName) => {
|
||||||
const visuals = getVisuals();
|
const visuals = getVisuals();
|
||||||
const progressBar = new visuals.Progress(
|
const progressBar = new visuals.Progress(
|
||||||
`Updating the OS of ${deviceName} to v${targetOsVersion}`,
|
`Updating the OS of ${deviceName} to v${targetOsVersion}`,
|
||||||
@ -314,15 +314,13 @@ export function inferOrSelectDevice(preferredUuid: string) {
|
|||||||
const balena = getBalenaSdk();
|
const balena = getBalenaSdk();
|
||||||
return balena.models.device
|
return balena.models.device
|
||||||
.getAll()
|
.getAll()
|
||||||
.filter<BalenaSdk.Device>(device => device.is_online)
|
.filter<BalenaSdk.Device>((device) => device.is_online)
|
||||||
.then(onlineDevices => {
|
.then((onlineDevices) => {
|
||||||
if (_.isEmpty(onlineDevices)) {
|
if (_.isEmpty(onlineDevices)) {
|
||||||
throw new Error("You don't have any devices online");
|
throw new Error("You don't have any devices online");
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultUuid = _(onlineDevices)
|
const defaultUuid = _(onlineDevices).map('uuid').includes(preferredUuid)
|
||||||
.map('uuid')
|
|
||||||
.includes(preferredUuid)
|
|
||||||
? preferredUuid
|
? preferredUuid
|
||||||
: onlineDevices[0].uuid;
|
: onlineDevices[0].uuid;
|
||||||
|
|
||||||
@ -330,7 +328,7 @@ export function inferOrSelectDevice(preferredUuid: string) {
|
|||||||
message: 'Select a device',
|
message: 'Select a device',
|
||||||
type: 'list',
|
type: 'list',
|
||||||
default: defaultUuid,
|
default: defaultUuid,
|
||||||
choices: _.map(onlineDevices, device => ({
|
choices: _.map(onlineDevices, (device) => ({
|
||||||
name: `${device.device_name || 'Untitled'} (${device.uuid.slice(
|
name: `${device.device_name || 'Untitled'} (${device.uuid.slice(
|
||||||
0,
|
0,
|
||||||
7,
|
7,
|
||||||
@ -385,7 +383,7 @@ export async function getOnlineTargetUuid(
|
|||||||
message: 'Select a device',
|
message: 'Select a device',
|
||||||
type: 'list',
|
type: 'list',
|
||||||
default: devices[0].uuid,
|
default: devices[0].uuid,
|
||||||
choices: _.map(devices, device => ({
|
choices: _.map(devices, (device) => ({
|
||||||
name: `${device.device_name || 'Untitled'} (${device.uuid.slice(
|
name: `${device.device_name || 'Untitled'} (${device.uuid.slice(
|
||||||
0,
|
0,
|
||||||
7,
|
7,
|
||||||
@ -419,7 +417,7 @@ export function selectFromList<T>(
|
|||||||
return getForm().ask<T>({
|
return getForm().ask<T>({
|
||||||
message,
|
message,
|
||||||
type: 'list',
|
type: 'list',
|
||||||
choices: _.map(choices, s => ({
|
choices: _.map(choices, (s) => ({
|
||||||
name: s.name,
|
name: s.name,
|
||||||
value: s,
|
value: s,
|
||||||
})),
|
})),
|
||||||
|
@ -93,7 +93,7 @@ async function execCommand(
|
|||||||
const spinner = new visuals.Spinner(`[${deviceIp}] Connecting...`);
|
const spinner = new visuals.Spinner(`[${deviceIp}] Connecting...`);
|
||||||
const innerSpinner = spinner.spinner;
|
const innerSpinner = spinner.spinner;
|
||||||
|
|
||||||
const stream = through(function(data, _enc, cb) {
|
const stream = through(function (data, _enc, cb) {
|
||||||
innerSpinner.setSpinnerTitle(`%s [${deviceIp}] ${msg}`);
|
innerSpinner.setSpinnerTitle(`%s [${deviceIp}] ${msg}`);
|
||||||
cb(null, data);
|
cb(null, data);
|
||||||
});
|
});
|
||||||
@ -160,7 +160,7 @@ async function getOrSelectLocalDevice(deviceIp?: string): Promise<string> {
|
|||||||
const through = await import('through2');
|
const through = await import('through2');
|
||||||
|
|
||||||
let ip: string | null = null;
|
let ip: string | null = null;
|
||||||
const stream = through(function(data, _enc, cb) {
|
const stream = through(function (data, _enc, cb) {
|
||||||
const match = /^==> Selected device: (.*)$/m.exec(data.toString());
|
const match = /^==> Selected device: (.*)$/m.exec(data.toString());
|
||||||
if (match) {
|
if (match) {
|
||||||
ip = match[1];
|
ip = match[1];
|
||||||
@ -195,7 +195,7 @@ async function selectAppFromList(applications: BalenaSdk.Application[]) {
|
|||||||
// name (user/appname) and allows them to select.
|
// name (user/appname) and allows them to select.
|
||||||
return selectFromList(
|
return selectFromList(
|
||||||
'Select application',
|
'Select application',
|
||||||
_.map(applications, app => {
|
_.map(applications, (app) => {
|
||||||
return { name: app.slug, ...app };
|
return { name: app.slug, ...app };
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@ -216,7 +216,7 @@ async function getOrSelectApplication(
|
|||||||
}
|
}
|
||||||
const compatibleDeviceTypes = _(allDeviceTypes)
|
const compatibleDeviceTypes = _(allDeviceTypes)
|
||||||
.filter(
|
.filter(
|
||||||
dt =>
|
(dt) =>
|
||||||
sdk.models.os.isArchitectureCompatibleWith(
|
sdk.models.os.isArchitectureCompatibleWith(
|
||||||
deviceTypeManifest.arch,
|
deviceTypeManifest.arch,
|
||||||
dt.arch,
|
dt.arch,
|
||||||
@ -224,7 +224,7 @@ async function getOrSelectApplication(
|
|||||||
!!dt.isDependent === !!deviceTypeManifest.isDependent &&
|
!!dt.isDependent === !!deviceTypeManifest.isDependent &&
|
||||||
dt.state !== 'DISCONTINUED',
|
dt.state !== 'DISCONTINUED',
|
||||||
)
|
)
|
||||||
.map(type => type.slug)
|
.map((type) => type.slug)
|
||||||
.value();
|
.value();
|
||||||
|
|
||||||
if (!appName) {
|
if (!appName) {
|
||||||
@ -270,7 +270,7 @@ async function getOrSelectApplication(
|
|||||||
|
|
||||||
// We've found at least one app with the given name.
|
// We've found at least one app with the given name.
|
||||||
// Filter out apps for non-matching device types and see what we're left with.
|
// Filter out apps for non-matching device types and see what we're left with.
|
||||||
const validApplications = applications.filter(app =>
|
const validApplications = applications.filter((app) =>
|
||||||
_.includes(compatibleDeviceTypes, app.device_type),
|
_.includes(compatibleDeviceTypes, app.device_type),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -382,7 +382,8 @@ async function generateApplicationConfig(
|
|||||||
|
|
||||||
const manifest = await sdk.models.device.getManifestBySlug(app.device_type);
|
const manifest = await sdk.models.device.getManifestBySlug(app.device_type);
|
||||||
const opts =
|
const opts =
|
||||||
manifest.options && manifest.options.filter(opt => opt.name !== 'network');
|
manifest.options &&
|
||||||
|
manifest.options.filter((opt) => opt.name !== 'network');
|
||||||
const values = {
|
const values = {
|
||||||
...(opts ? await form.run(opts) : {}),
|
...(opts ? await form.run(opts) : {}),
|
||||||
...options,
|
...options,
|
||||||
|
@ -39,13 +39,13 @@ export function copyQemu(context: string, arch: string) {
|
|||||||
const binPath = path.join(binDir, QEMU_BIN_NAME);
|
const binPath = path.join(binDir, QEMU_BIN_NAME);
|
||||||
|
|
||||||
return Bluebird.resolve(fs.mkdir(binDir))
|
return Bluebird.resolve(fs.mkdir(binDir))
|
||||||
.catch({ code: 'EEXIST' }, function() {
|
.catch({ code: 'EEXIST' }, function () {
|
||||||
// noop
|
// noop
|
||||||
})
|
})
|
||||||
.then(() => getQemuPath(arch))
|
.then(() => getQemuPath(arch))
|
||||||
.then(
|
.then(
|
||||||
qemu =>
|
(qemu) =>
|
||||||
new Bluebird(function(resolve, reject) {
|
new Bluebird(function (resolve, reject) {
|
||||||
const read = fs.createReadStream(qemu);
|
const read = fs.createReadStream(qemu);
|
||||||
const write = fs.createWriteStream(binPath);
|
const write = fs.createWriteStream(binPath);
|
||||||
|
|
||||||
@ -60,14 +60,14 @@ export function copyQemu(context: string, arch: string) {
|
|||||||
.then(() => path.relative(context, binPath));
|
.then(() => path.relative(context, binPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getQemuPath = function(arch: string) {
|
export const getQemuPath = function (arch: string) {
|
||||||
const balena = getBalenaSdk();
|
const balena = getBalenaSdk();
|
||||||
const path = require('path') as typeof import('path');
|
const path = require('path') as typeof import('path');
|
||||||
const fs = require('mz/fs') as typeof import('mz/fs');
|
const fs = require('mz/fs') as typeof import('mz/fs');
|
||||||
|
|
||||||
return balena.settings.get('binDirectory').then(binDir =>
|
return balena.settings.get('binDirectory').then((binDir) =>
|
||||||
Bluebird.resolve(fs.mkdir(binDir))
|
Bluebird.resolve(fs.mkdir(binDir))
|
||||||
.catch({ code: 'EEXIST' }, function() {
|
.catch({ code: 'EEXIST' }, function () {
|
||||||
// noop
|
// noop
|
||||||
})
|
})
|
||||||
.then(() =>
|
.then(() =>
|
||||||
@ -83,8 +83,8 @@ export function installQemu(arch: string) {
|
|||||||
const tar = require('tar-stream') as typeof import('tar-stream');
|
const tar = require('tar-stream') as typeof import('tar-stream');
|
||||||
|
|
||||||
return getQemuPath(arch).then(
|
return getQemuPath(arch).then(
|
||||||
qemuPath =>
|
(qemuPath) =>
|
||||||
new Bluebird(function(resolve, reject) {
|
new Bluebird(function (resolve, reject) {
|
||||||
const installStream = fs.createWriteStream(qemuPath);
|
const installStream = fs.createWriteStream(qemuPath);
|
||||||
|
|
||||||
const qemuArch = balenaArchToQemuArch(arch);
|
const qemuArch = balenaArchToQemuArch(arch);
|
||||||
@ -96,7 +96,7 @@ export function installQemu(arch: string) {
|
|||||||
const qemuUrl = `https://github.com/balena-io/qemu/releases/download/${urlVersion}/${urlFile}`;
|
const qemuUrl = `https://github.com/balena-io/qemu/releases/download/${urlVersion}/${urlFile}`;
|
||||||
|
|
||||||
const extract = tar.extract();
|
const extract = tar.extract();
|
||||||
extract.on('entry', function(header, stream, next) {
|
extract.on('entry', function (header, stream, next) {
|
||||||
stream.on('end', next);
|
stream.on('end', next);
|
||||||
if (header.name.includes(`qemu-${qemuArch}-static`)) {
|
if (header.name.includes(`qemu-${qemuArch}-static`)) {
|
||||||
stream.pipe(installStream);
|
stream.pipe(installStream);
|
||||||
@ -111,7 +111,7 @@ export function installQemu(arch: string) {
|
|||||||
.on('error', reject)
|
.on('error', reject)
|
||||||
.pipe(extract)
|
.pipe(extract)
|
||||||
.on('error', reject)
|
.on('error', reject)
|
||||||
.on('finish', function() {
|
.on('finish', function () {
|
||||||
fs.chmodSync(qemuPath, '755');
|
fs.chmodSync(qemuPath, '755');
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
@ -119,7 +119,7 @@ export function installQemu(arch: string) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const balenaArchToQemuArch = function(arch: string) {
|
const balenaArchToQemuArch = function (arch: string) {
|
||||||
switch (arch) {
|
switch (arch) {
|
||||||
case 'armv7hf':
|
case 'armv7hf':
|
||||||
case 'rpi':
|
case 'rpi':
|
||||||
|
@ -95,7 +95,7 @@ export async function execBuffered(
|
|||||||
await exec(
|
await exec(
|
||||||
deviceIp,
|
deviceIp,
|
||||||
cmd,
|
cmd,
|
||||||
through(function(data, _enc, cb) {
|
through(function (data, _enc, cb) {
|
||||||
buffer.push(data.toString(enc));
|
buffer.push(data.toString(enc));
|
||||||
cb();
|
cb();
|
||||||
}),
|
}),
|
||||||
|
@ -23,14 +23,11 @@ export function buffer(
|
|||||||
): Promise<NodeJS.ReadableStream> {
|
): Promise<NodeJS.ReadableStream> {
|
||||||
const fileWriteStream = fs.createWriteStream(bufferFile);
|
const fileWriteStream = fs.createWriteStream(bufferFile);
|
||||||
|
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
stream
|
stream.on('error', reject).on('end', resolve).pipe(fileWriteStream);
|
||||||
.on('error', reject)
|
|
||||||
.on('end', resolve)
|
|
||||||
.pipe(fileWriteStream);
|
|
||||||
}).then(
|
}).then(
|
||||||
() =>
|
() =>
|
||||||
new Promise(function(resolve, reject) {
|
new Promise(function (resolve, reject) {
|
||||||
const fstream = fs.createReadStream(bufferFile);
|
const fstream = fs.createReadStream(bufferFile);
|
||||||
|
|
||||||
fstream.on('open', () => resolve(fstream)).on('error', reject);
|
fstream.on('open', () => resolve(fstream)).on('error', reject);
|
||||||
|
@ -86,7 +86,7 @@ async function spawnAndPipe(
|
|||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
const ps: ChildProcess = spawn(spawnCmd, spawnArgs, spawnOpts);
|
const ps: ChildProcess = spawn(spawnCmd, spawnArgs, spawnOpts);
|
||||||
ps.on('error', reject);
|
ps.on('error', reject);
|
||||||
ps.on('exit', codeOrSignal => {
|
ps.on('exit', (codeOrSignal) => {
|
||||||
if (codeOrSignal !== 0) {
|
if (codeOrSignal !== 0) {
|
||||||
const errMsgCmd = `[${[spawnCmd, ...spawnArgs].join()}]`;
|
const errMsgCmd = `[${[spawnCmd, ...spawnArgs].join()}]`;
|
||||||
reject(
|
reject(
|
||||||
|
@ -54,14 +54,14 @@ export const tunnelConnectionToDevice = (
|
|||||||
|
|
||||||
return (client: Socket): Bluebird<void> =>
|
return (client: Socket): Bluebird<void> =>
|
||||||
openPortThroughProxy(vpnUrl, 3128, auth, uuid, port)
|
openPortThroughProxy(vpnUrl, 3128, auth, uuid, port)
|
||||||
.then(remote => {
|
.then((remote) => {
|
||||||
client.pipe(remote);
|
client.pipe(remote);
|
||||||
remote.pipe(client);
|
remote.pipe(client);
|
||||||
remote.on('error', err => {
|
remote.on('error', (err) => {
|
||||||
console.error('Remote: ' + err);
|
console.error('Remote: ' + err);
|
||||||
client.end();
|
client.end();
|
||||||
});
|
});
|
||||||
client.on('error', err => {
|
client.on('error', (err) => {
|
||||||
console.error('Client: ' + err);
|
console.error('Client: ' + err);
|
||||||
remote.end();
|
remote.end();
|
||||||
});
|
});
|
||||||
|
800
npm-shrinkwrap.json
generated
800
npm-shrinkwrap.json
generated
File diff suppressed because it is too large
Load Diff
@ -100,7 +100,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@balena/lint": "^4.1.1",
|
"@balena/lint": "^5.1.0",
|
||||||
"@oclif/config": "^1.14.0",
|
"@oclif/config": "^1.14.0",
|
||||||
"@oclif/dev-cli": "1.22.0",
|
"@oclif/dev-cli": "1.22.0",
|
||||||
"@oclif/parser": "^3.8.4",
|
"@oclif/parser": "^3.8.4",
|
||||||
|
@ -22,7 +22,7 @@ import {
|
|||||||
makeUrlFromTunnelNgConfig,
|
makeUrlFromTunnelNgConfig,
|
||||||
} from '../build/app-common';
|
} from '../build/app-common';
|
||||||
|
|
||||||
describe('makeUrlFromTunnelNgConfig() function', function() {
|
describe('makeUrlFromTunnelNgConfig() function', function () {
|
||||||
it('should return a URL given a GlobalTunnelNgConfig object', () => {
|
it('should return a URL given a GlobalTunnelNgConfig object', () => {
|
||||||
const tunnelNgConfig: GlobalTunnelNgConfig = {
|
const tunnelNgConfig: GlobalTunnelNgConfig = {
|
||||||
host: 'proxy.company.com',
|
host: 'proxy.company.com',
|
||||||
|
@ -51,8 +51,8 @@ async function getPage(name: string): Promise<string> {
|
|||||||
return compiledTpl();
|
return compiledTpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('Server:', function() {
|
describe('Server:', function () {
|
||||||
it('should get 404 if posting to an unknown path', function(done) {
|
it('should get 404 if posting to an unknown path', function (done) {
|
||||||
const promise = server.awaitForToken(options);
|
const promise = server.awaitForToken(options);
|
||||||
expect(promise).to.be.rejectedWith('Unknown path or verb');
|
expect(promise).to.be.rejectedWith('Unknown path or verb');
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ describe('Server:', function() {
|
|||||||
token: tokens.johndoe.token,
|
token: tokens.johndoe.token,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
function(error, response, body) {
|
function (error, response, body) {
|
||||||
expect(error).to.not.exist;
|
expect(error).to.not.exist;
|
||||||
expect(response.statusCode).to.equal(404);
|
expect(response.statusCode).to.equal(404);
|
||||||
expect(body).to.equal('Not found');
|
expect(body).to.equal('Not found');
|
||||||
@ -72,7 +72,7 @@ describe('Server:', function() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get 404 if not using the correct verb', function(done) {
|
it('should get 404 if not using the correct verb', function (done) {
|
||||||
const promise = server.awaitForToken(options);
|
const promise = server.awaitForToken(options);
|
||||||
expect(promise).to.be.rejectedWith('Unknown path or verb');
|
expect(promise).to.be.rejectedWith('Unknown path or verb');
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ describe('Server:', function() {
|
|||||||
token: tokens.johndoe.token,
|
token: tokens.johndoe.token,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
function(error, response, body) {
|
function (error, response, body) {
|
||||||
expect(error).to.not.exist;
|
expect(error).to.not.exist;
|
||||||
expect(response.statusCode).to.equal(404);
|
expect(response.statusCode).to.equal(404);
|
||||||
expect(body).to.equal('Not found');
|
expect(body).to.equal('Not found');
|
||||||
@ -92,17 +92,17 @@ describe('Server:', function() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('given the token authenticates with the server', function() {
|
describe('given the token authenticates with the server', function () {
|
||||||
beforeEach(function() {
|
beforeEach(function () {
|
||||||
this.loginIfTokenValidStub = sinon.stub(utils, 'loginIfTokenValid');
|
this.loginIfTokenValidStub = sinon.stub(utils, 'loginIfTokenValid');
|
||||||
return this.loginIfTokenValidStub.returns(Bluebird.resolve(true));
|
return this.loginIfTokenValidStub.returns(Bluebird.resolve(true));
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function() {
|
afterEach(function () {
|
||||||
return this.loginIfTokenValidStub.restore();
|
return this.loginIfTokenValidStub.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
return it('should eventually be the token', function(done) {
|
return it('should eventually be the token', function (done) {
|
||||||
const promise = server.awaitForToken(options);
|
const promise = server.awaitForToken(options);
|
||||||
expect(promise).to.eventually.equal(tokens.johndoe.token);
|
expect(promise).to.eventually.equal(tokens.johndoe.token);
|
||||||
|
|
||||||
@ -113,10 +113,10 @@ describe('Server:', function() {
|
|||||||
token: tokens.johndoe.token,
|
token: tokens.johndoe.token,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
function(error, response, body) {
|
function (error, response, body) {
|
||||||
expect(error).to.not.exist;
|
expect(error).to.not.exist;
|
||||||
expect(response.statusCode).to.equal(200);
|
expect(response.statusCode).to.equal(200);
|
||||||
return getPage('success').then(function(expectedBody) {
|
return getPage('success').then(function (expectedBody) {
|
||||||
expect(body).to.equal(expectedBody);
|
expect(body).to.equal(expectedBody);
|
||||||
return done();
|
return done();
|
||||||
});
|
});
|
||||||
@ -125,17 +125,17 @@ describe('Server:', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return describe('given the token does not authenticate with the server', function() {
|
return describe('given the token does not authenticate with the server', function () {
|
||||||
beforeEach(function() {
|
beforeEach(function () {
|
||||||
this.loginIfTokenValidStub = sinon.stub(utils, 'loginIfTokenValid');
|
this.loginIfTokenValidStub = sinon.stub(utils, 'loginIfTokenValid');
|
||||||
return this.loginIfTokenValidStub.returns(Bluebird.resolve(false));
|
return this.loginIfTokenValidStub.returns(Bluebird.resolve(false));
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function() {
|
afterEach(function () {
|
||||||
return this.loginIfTokenValidStub.restore();
|
return this.loginIfTokenValidStub.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be rejected', function(done) {
|
it('should be rejected', function (done) {
|
||||||
const promise = server.awaitForToken(options);
|
const promise = server.awaitForToken(options);
|
||||||
expect(promise).to.be.rejectedWith('Invalid token');
|
expect(promise).to.be.rejectedWith('Invalid token');
|
||||||
|
|
||||||
@ -146,10 +146,10 @@ describe('Server:', function() {
|
|||||||
token: tokens.johndoe.token,
|
token: tokens.johndoe.token,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
function(error, response, body) {
|
function (error, response, body) {
|
||||||
expect(error).to.not.exist;
|
expect(error).to.not.exist;
|
||||||
expect(response.statusCode).to.equal(401);
|
expect(response.statusCode).to.equal(401);
|
||||||
return getPage('error').then(function(expectedBody) {
|
return getPage('error').then(function (expectedBody) {
|
||||||
expect(body).to.equal(expectedBody);
|
expect(body).to.equal(expectedBody);
|
||||||
return done();
|
return done();
|
||||||
});
|
});
|
||||||
@ -157,7 +157,7 @@ describe('Server:', function() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be rejected if no token', function(done) {
|
it('should be rejected if no token', function (done) {
|
||||||
const promise = server.awaitForToken(options);
|
const promise = server.awaitForToken(options);
|
||||||
expect(promise).to.be.rejectedWith('No token');
|
expect(promise).to.be.rejectedWith('No token');
|
||||||
|
|
||||||
@ -168,10 +168,10 @@ describe('Server:', function() {
|
|||||||
token: '',
|
token: '',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
function(error, response, body) {
|
function (error, response, body) {
|
||||||
expect(error).to.not.exist;
|
expect(error).to.not.exist;
|
||||||
expect(response.statusCode).to.equal(401);
|
expect(response.statusCode).to.equal(401);
|
||||||
return getPage('error').then(function(expectedBody) {
|
return getPage('error').then(function (expectedBody) {
|
||||||
expect(body).to.equal(expectedBody);
|
expect(body).to.equal(expectedBody);
|
||||||
return done();
|
return done();
|
||||||
});
|
});
|
||||||
@ -179,7 +179,7 @@ describe('Server:', function() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
return it('should be rejected if token is malformed', function(done) {
|
return it('should be rejected if token is malformed', function (done) {
|
||||||
const promise = server.awaitForToken(options);
|
const promise = server.awaitForToken(options);
|
||||||
expect(promise).to.be.rejectedWith('Invalid token');
|
expect(promise).to.be.rejectedWith('Invalid token');
|
||||||
|
|
||||||
@ -190,10 +190,10 @@ describe('Server:', function() {
|
|||||||
token: 'asdf',
|
token: 'asdf',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
function(error, response, body) {
|
function (error, response, body) {
|
||||||
expect(error).to.not.exist;
|
expect(error).to.not.exist;
|
||||||
expect(response.statusCode).to.equal(401);
|
expect(response.statusCode).to.equal(401);
|
||||||
return getPage('error').then(function(expectedBody) {
|
return getPage('error').then(function (expectedBody) {
|
||||||
expect(body).to.equal(expectedBody);
|
expect(body).to.equal(expectedBody);
|
||||||
return done();
|
return done();
|
||||||
});
|
});
|
||||||
|
@ -9,8 +9,8 @@ import tokens from './tokens';
|
|||||||
const utils = rewire('../../build/auth/utils');
|
const utils = rewire('../../build/auth/utils');
|
||||||
const balena = getBalenaSdk();
|
const balena = getBalenaSdk();
|
||||||
|
|
||||||
describe('Utils:', function() {
|
describe('Utils:', function () {
|
||||||
describe('.getDashboardLoginURL()', function() {
|
describe('.getDashboardLoginURL()', function () {
|
||||||
it('should eventually be a valid url', () =>
|
it('should eventually be a valid url', () =>
|
||||||
utils
|
utils
|
||||||
.getDashboardLoginURL('https://127.0.0.1:3000/callback')
|
.getDashboardLoginURL('https://127.0.0.1:3000/callback')
|
||||||
@ -22,7 +22,7 @@ describe('Utils:', function() {
|
|||||||
Promise.props({
|
Promise.props({
|
||||||
dashboardUrl: balena.settings.get('dashboardUrl'),
|
dashboardUrl: balena.settings.get('dashboardUrl'),
|
||||||
loginUrl: utils.getDashboardLoginURL('https://127.0.0.1:3000/callback'),
|
loginUrl: utils.getDashboardLoginURL('https://127.0.0.1:3000/callback'),
|
||||||
}).then(function({ dashboardUrl, loginUrl }) {
|
}).then(function ({ dashboardUrl, loginUrl }) {
|
||||||
const { protocol } = url.parse(loginUrl);
|
const { protocol } = url.parse(loginUrl);
|
||||||
return expect(protocol).to.equal(url.parse(dashboardUrl).protocol);
|
return expect(protocol).to.equal(url.parse(dashboardUrl).protocol);
|
||||||
}));
|
}));
|
||||||
@ -31,7 +31,7 @@ describe('Utils:', function() {
|
|||||||
Promise.props({
|
Promise.props({
|
||||||
dashboardUrl: balena.settings.get('dashboardUrl'),
|
dashboardUrl: balena.settings.get('dashboardUrl'),
|
||||||
loginUrl: utils.getDashboardLoginURL('http://127.0.0.1:3000'),
|
loginUrl: utils.getDashboardLoginURL('http://127.0.0.1:3000'),
|
||||||
}).then(function({ dashboardUrl, loginUrl }) {
|
}).then(function ({ dashboardUrl, loginUrl }) {
|
||||||
const expectedUrl = `${dashboardUrl}/login/cli/http%253A%252F%252F127.0.0.1%253A3000`;
|
const expectedUrl = `${dashboardUrl}/login/cli/http%253A%252F%252F127.0.0.1%253A3000`;
|
||||||
return expect(loginUrl).to.equal(expectedUrl);
|
return expect(loginUrl).to.equal(expectedUrl);
|
||||||
}));
|
}));
|
||||||
@ -40,55 +40,55 @@ describe('Utils:', function() {
|
|||||||
Promise.props({
|
Promise.props({
|
||||||
dashboardUrl: balena.settings.get('dashboardUrl'),
|
dashboardUrl: balena.settings.get('dashboardUrl'),
|
||||||
loginUrl: utils.getDashboardLoginURL('http://127.0.0.1:3000/callback'),
|
loginUrl: utils.getDashboardLoginURL('http://127.0.0.1:3000/callback'),
|
||||||
}).then(function({ dashboardUrl, loginUrl }) {
|
}).then(function ({ dashboardUrl, loginUrl }) {
|
||||||
const expectedUrl = `${dashboardUrl}/login/cli/http%253A%252F%252F127.0.0.1%253A3000%252Fcallback`;
|
const expectedUrl = `${dashboardUrl}/login/cli/http%253A%252F%252F127.0.0.1%253A3000%252Fcallback`;
|
||||||
return expect(loginUrl).to.equal(expectedUrl);
|
return expect(loginUrl).to.equal(expectedUrl);
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
return describe('.loginIfTokenValid()', function() {
|
return describe('.loginIfTokenValid()', function () {
|
||||||
it('should eventually be false if token is undefined', function() {
|
it('should eventually be false if token is undefined', function () {
|
||||||
const promise = utils.loginIfTokenValid(undefined);
|
const promise = utils.loginIfTokenValid(undefined);
|
||||||
return expect(promise).to.eventually.be.false;
|
return expect(promise).to.eventually.be.false;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should eventually be false if token is null', function() {
|
it('should eventually be false if token is null', function () {
|
||||||
const promise = utils.loginIfTokenValid(null);
|
const promise = utils.loginIfTokenValid(null);
|
||||||
return expect(promise).to.eventually.be.false;
|
return expect(promise).to.eventually.be.false;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should eventually be false if token is an empty string', function() {
|
it('should eventually be false if token is an empty string', function () {
|
||||||
const promise = utils.loginIfTokenValid('');
|
const promise = utils.loginIfTokenValid('');
|
||||||
return expect(promise).to.eventually.be.false;
|
return expect(promise).to.eventually.be.false;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should eventually be false if token is a string containing only spaces', function() {
|
it('should eventually be false if token is a string containing only spaces', function () {
|
||||||
const promise = utils.loginIfTokenValid(' ');
|
const promise = utils.loginIfTokenValid(' ');
|
||||||
return expect(promise).to.eventually.be.false;
|
return expect(promise).to.eventually.be.false;
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('given the token does not authenticate with the server', function() {
|
describe('given the token does not authenticate with the server', function () {
|
||||||
beforeEach(function() {
|
beforeEach(function () {
|
||||||
this.balenaAuthIsLoggedInStub = sinon.stub(balena.auth, 'isLoggedIn');
|
this.balenaAuthIsLoggedInStub = sinon.stub(balena.auth, 'isLoggedIn');
|
||||||
return this.balenaAuthIsLoggedInStub.returns(Promise.resolve(false));
|
return this.balenaAuthIsLoggedInStub.returns(Promise.resolve(false));
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function() {
|
afterEach(function () {
|
||||||
return this.balenaAuthIsLoggedInStub.restore();
|
return this.balenaAuthIsLoggedInStub.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should eventually be false', function() {
|
it('should eventually be false', function () {
|
||||||
const promise = utils.loginIfTokenValid(tokens.johndoe.token);
|
const promise = utils.loginIfTokenValid(tokens.johndoe.token);
|
||||||
return expect(promise).to.eventually.be.false;
|
return expect(promise).to.eventually.be.false;
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('given there was a token already', function() {
|
describe('given there was a token already', function () {
|
||||||
beforeEach(() => balena.auth.loginWithToken(tokens.janedoe.token));
|
beforeEach(() => balena.auth.loginWithToken(tokens.janedoe.token));
|
||||||
|
|
||||||
return it('should preserve the old token', () =>
|
return it('should preserve the old token', () =>
|
||||||
balena.auth
|
balena.auth
|
||||||
.getToken()
|
.getToken()
|
||||||
.then(function(originalToken: string) {
|
.then(function (originalToken: string) {
|
||||||
expect(originalToken).to.equal(tokens.janedoe.token);
|
expect(originalToken).to.equal(tokens.janedoe.token);
|
||||||
return utils.loginIfTokenValid(tokens.johndoe.token);
|
return utils.loginIfTokenValid(tokens.johndoe.token);
|
||||||
})
|
})
|
||||||
@ -98,7 +98,7 @@ describe('Utils:', function() {
|
|||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
||||||
return describe('given there was no token', function() {
|
return describe('given there was no token', function () {
|
||||||
beforeEach(() => balena.auth.logout());
|
beforeEach(() => balena.auth.logout());
|
||||||
|
|
||||||
return it('should stay without a token', () =>
|
return it('should stay without a token', () =>
|
||||||
@ -109,17 +109,17 @@ describe('Utils:', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return describe('given the token does authenticate with the server', function() {
|
return describe('given the token does authenticate with the server', function () {
|
||||||
beforeEach(function() {
|
beforeEach(function () {
|
||||||
this.balenaAuthIsLoggedInStub = sinon.stub(balena.auth, 'isLoggedIn');
|
this.balenaAuthIsLoggedInStub = sinon.stub(balena.auth, 'isLoggedIn');
|
||||||
return this.balenaAuthIsLoggedInStub.returns(Promise.resolve(true));
|
return this.balenaAuthIsLoggedInStub.returns(Promise.resolve(true));
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function() {
|
afterEach(function () {
|
||||||
return this.balenaAuthIsLoggedInStub.restore();
|
return this.balenaAuthIsLoggedInStub.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
return it('should eventually be true', function() {
|
return it('should eventually be true', function () {
|
||||||
const promise = utils.loginIfTokenValid(tokens.johndoe.token);
|
const promise = utils.loginIfTokenValid(tokens.johndoe.token);
|
||||||
return expect(promise).to.eventually.be.true;
|
return expect(promise).to.eventually.be.true;
|
||||||
});
|
});
|
||||||
|
@ -217,7 +217,7 @@ export class BalenaAPIMock extends NockMock {
|
|||||||
|
|
||||||
public expectGetAppServiceVars(opts: ScopeOpts = {}) {
|
public expectGetAppServiceVars(opts: ScopeOpts = {}) {
|
||||||
this.optGet(/^\/v\d+\/service_environment_variable($|\?)/, opts).reply(
|
this.optGet(/^\/v\d+\/service_environment_variable($|\?)/, opts).reply(
|
||||||
function(uri, _requestBody) {
|
function (uri, _requestBody) {
|
||||||
const match = uri.match(/service_name%20eq%20%27(.+?)%27/);
|
const match = uri.match(/service_name%20eq%20%27(.+?)%27/);
|
||||||
const serviceName = (match && match[1]) || undefined;
|
const serviceName = (match && match[1]) || undefined;
|
||||||
let varArray: any[];
|
let varArray: any[];
|
||||||
@ -225,7 +225,7 @@ export class BalenaAPIMock extends NockMock {
|
|||||||
const varObj = appServiceVarsByService[serviceName];
|
const varObj = appServiceVarsByService[serviceName];
|
||||||
varArray = varObj ? [varObj] : [];
|
varArray = varObj ? [varObj] : [];
|
||||||
} else {
|
} else {
|
||||||
varArray = _.map(appServiceVarsByService, value => value);
|
varArray = _.map(appServiceVarsByService, (value) => value);
|
||||||
}
|
}
|
||||||
return [200, { d: varArray }];
|
return [200, { d: varArray }];
|
||||||
},
|
},
|
||||||
@ -265,7 +265,7 @@ export class BalenaAPIMock extends NockMock {
|
|||||||
this.optGet(
|
this.optGet(
|
||||||
/^\/v\d+\/device_service_environment_variable($|\?)/,
|
/^\/v\d+\/device_service_environment_variable($|\?)/,
|
||||||
opts,
|
opts,
|
||||||
).reply(function(uri, _requestBody) {
|
).reply(function (uri, _requestBody) {
|
||||||
const match = uri.match(/service_name%20eq%20%27(.+?)%27/);
|
const match = uri.match(/service_name%20eq%20%27(.+?)%27/);
|
||||||
const serviceName = (match && match[1]) || undefined;
|
const serviceName = (match && match[1]) || undefined;
|
||||||
let varArray: any[];
|
let varArray: any[];
|
||||||
@ -273,7 +273,7 @@ export class BalenaAPIMock extends NockMock {
|
|||||||
const varObj = deviceServiceVarsByService[serviceName];
|
const varObj = deviceServiceVarsByService[serviceName];
|
||||||
varArray = varObj ? [varObj] : [];
|
varArray = varObj ? [varObj] : [];
|
||||||
} else {
|
} else {
|
||||||
varArray = _.map(deviceServiceVarsByService, value => value);
|
varArray = _.map(deviceServiceVarsByService, (value) => value);
|
||||||
}
|
}
|
||||||
return [200, { d: varArray }];
|
return [200, { d: varArray }];
|
||||||
});
|
});
|
||||||
|
@ -38,7 +38,7 @@ export class BuilderMock extends NockMock {
|
|||||||
checkURI: (uri: string) => Promise<void>;
|
checkURI: (uri: string) => Promise<void>;
|
||||||
checkBuildRequestBody: (requestBody: string | Buffer) => Promise<void>;
|
checkBuildRequestBody: (requestBody: string | Buffer) => Promise<void>;
|
||||||
}) {
|
}) {
|
||||||
this.optPost(/^\/v3\/build($|[(?])/, opts).reply(async function(
|
this.optPost(/^\/v3\/build($|[(?])/, opts).reply(async function (
|
||||||
uri,
|
uri,
|
||||||
requestBody,
|
requestBody,
|
||||||
callback,
|
callback,
|
||||||
@ -48,7 +48,7 @@ export class BuilderMock extends NockMock {
|
|||||||
await opts.checkURI(uri);
|
await opts.checkURI(uri);
|
||||||
if (typeof requestBody === 'string') {
|
if (typeof requestBody === 'string') {
|
||||||
const gzipped = Buffer.from(requestBody, 'hex');
|
const gzipped = Buffer.from(requestBody, 'hex');
|
||||||
const gunzipped = await Bluebird.fromCallback<Buffer>(cb => {
|
const gunzipped = await Bluebird.fromCallback<Buffer>((cb) => {
|
||||||
zlib.gunzip(gzipped, cb);
|
zlib.gunzip(gzipped, cb);
|
||||||
});
|
});
|
||||||
await opts.checkBuildRequestBody(gunzipped);
|
await opts.checkBuildRequestBody(gunzipped);
|
||||||
|
@ -41,7 +41,7 @@ Options:
|
|||||||
--type, -t <type> application device type (Check available types with \`balena devices supported\`)
|
--type, -t <type> application device type (Check available types with \`balena devices supported\`)
|
||||||
`;
|
`;
|
||||||
|
|
||||||
describe('balena app create', function() {
|
describe('balena app create', function () {
|
||||||
let api: BalenaAPIMock;
|
let api: BalenaAPIMock;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -65,7 +65,7 @@ const commonComposeQueryParams = [
|
|||||||
// "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;
|
||||||
|
|
||||||
describe('balena build', function() {
|
describe('balena build', function () {
|
||||||
let api: BalenaAPIMock;
|
let api: BalenaAPIMock;
|
||||||
let docker: DockerMock;
|
let docker: DockerMock;
|
||||||
const isWindows = process.platform === 'win32';
|
const isWindows = process.platform === 'win32';
|
||||||
@ -360,7 +360,7 @@ describe('balena build', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('balena build: project validation', function() {
|
describe('balena build: project validation', function () {
|
||||||
it('should raise ExpectedError if a Dockerfile cannot be found', async () => {
|
it('should raise ExpectedError if a Dockerfile cannot be found', async () => {
|
||||||
const projectPath = path.join(
|
const projectPath = path.join(
|
||||||
projectsPath,
|
projectsPath,
|
||||||
|
@ -56,7 +56,7 @@ const commonQueryParams = [
|
|||||||
['labels', ''],
|
['labels', ''],
|
||||||
];
|
];
|
||||||
|
|
||||||
describe('balena deploy', function() {
|
describe('balena deploy', function () {
|
||||||
let api: BalenaAPIMock;
|
let api: BalenaAPIMock;
|
||||||
let docker: DockerMock;
|
let docker: DockerMock;
|
||||||
let sentryStatus: boolean | undefined;
|
let sentryStatus: boolean | undefined;
|
||||||
@ -215,7 +215,7 @@ describe('balena deploy', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('balena deploy: project validation', function() {
|
describe('balena deploy: project validation', function () {
|
||||||
let api: BalenaAPIMock;
|
let api: BalenaAPIMock;
|
||||||
this.beforeEach(() => {
|
this.beforeEach(() => {
|
||||||
api = new BalenaAPIMock();
|
api = new BalenaAPIMock();
|
||||||
|
@ -36,7 +36,7 @@ Options:
|
|||||||
--application, -a, --app <application> application name
|
--application, -a, --app <application> application name
|
||||||
`;
|
`;
|
||||||
|
|
||||||
describe('balena device move', function() {
|
describe('balena device move', function () {
|
||||||
let api: BalenaAPIMock;
|
let api: BalenaAPIMock;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -31,7 +31,7 @@ Examples:
|
|||||||
\t$ balena device 7cf02a6
|
\t$ balena device 7cf02a6
|
||||||
`;
|
`;
|
||||||
|
|
||||||
describe('balena device', function() {
|
describe('balena device', function () {
|
||||||
let api: BalenaAPIMock;
|
let api: BalenaAPIMock;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -40,7 +40,7 @@ Options:
|
|||||||
--application, -a, --app <application> application name
|
--application, -a, --app <application> application name
|
||||||
`;
|
`;
|
||||||
|
|
||||||
describe('balena devices', function() {
|
describe('balena devices', function () {
|
||||||
let api: BalenaAPIMock;
|
let api: BalenaAPIMock;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@ -85,11 +85,11 @@ describe('balena devices', function() {
|
|||||||
);
|
);
|
||||||
expect(lines).to.have.lengthOf.at.least(2);
|
expect(lines).to.have.lengthOf.at.least(2);
|
||||||
|
|
||||||
expect(lines.some(l => l.includes('test app'))).to.be.true;
|
expect(lines.some((l) => l.includes('test app'))).to.be.true;
|
||||||
|
|
||||||
// Devices with missing applications will have application name set to `N/a`.
|
// Devices with missing applications will have application name set to `N/a`.
|
||||||
// e.g. When user has a device associated with app that user is no longer a collaborator of.
|
// e.g. When user has a device associated with app that user is no longer a collaborator of.
|
||||||
expect(lines.some(l => l.includes('N/a'))).to.be.true;
|
expect(lines.some((l) => l.includes('N/a'))).to.be.true;
|
||||||
|
|
||||||
expect(err).to.eql([]);
|
expect(err).to.eql([]);
|
||||||
});
|
});
|
||||||
|
@ -21,7 +21,7 @@ import { isV12 } from '../../../build/utils/version';
|
|||||||
import { BalenaAPIMock } from '../../balena-api-mock';
|
import { BalenaAPIMock } from '../../balena-api-mock';
|
||||||
import { cleanOutput, runCommand } from '../../helpers';
|
import { cleanOutput, runCommand } from '../../helpers';
|
||||||
|
|
||||||
describe('balena devices supported', function() {
|
describe('balena devices supported', function () {
|
||||||
let api: BalenaAPIMock;
|
let api: BalenaAPIMock;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@ -59,11 +59,11 @@ describe('balena devices supported', function() {
|
|||||||
expect(lines).to.have.lengthOf.at.least(2);
|
expect(lines).to.have.lengthOf.at.least(2);
|
||||||
|
|
||||||
// Discontinued devices should be filtered out from results
|
// Discontinued devices should be filtered out from results
|
||||||
expect(lines.some(l => l.includes('DISCONTINUED'))).to.be.false;
|
expect(lines.some((l) => l.includes('DISCONTINUED'))).to.be.false;
|
||||||
|
|
||||||
// Experimental devices should be listed as beta
|
// Experimental devices should be listed as beta
|
||||||
expect(lines.some(l => l.includes('EXPERIMENTAL'))).to.be.false;
|
expect(lines.some((l) => l.includes('EXPERIMENTAL'))).to.be.false;
|
||||||
expect(lines.some(l => l.includes('NEW'))).to.be.true;
|
expect(lines.some((l) => l.includes('NEW'))).to.be.true;
|
||||||
|
|
||||||
expect(err).to.eql([]);
|
expect(err).to.eql([]);
|
||||||
});
|
});
|
||||||
|
2
tests/commands/env/add.spec.ts
vendored
2
tests/commands/env/add.spec.ts
vendored
@ -20,7 +20,7 @@ import { expect } from 'chai';
|
|||||||
import { BalenaAPIMock } from '../../balena-api-mock';
|
import { BalenaAPIMock } from '../../balena-api-mock';
|
||||||
import { runCommand } from '../../helpers';
|
import { runCommand } from '../../helpers';
|
||||||
|
|
||||||
describe('balena env add', function() {
|
describe('balena env add', function () {
|
||||||
let api: BalenaAPIMock;
|
let api: BalenaAPIMock;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
6
tests/commands/env/envs.spec.ts
vendored
6
tests/commands/env/envs.spec.ts
vendored
@ -22,7 +22,7 @@ import { isV12 } from '../../../lib/utils/version';
|
|||||||
import { BalenaAPIMock } from '../../balena-api-mock';
|
import { BalenaAPIMock } from '../../balena-api-mock';
|
||||||
import { runCommand } from '../../helpers';
|
import { runCommand } from '../../helpers';
|
||||||
|
|
||||||
describe('balena envs', function() {
|
describe('balena envs', function () {
|
||||||
const appName = 'test';
|
const appName = 'test';
|
||||||
let fullUUID: string;
|
let fullUUID: string;
|
||||||
let shortUUID: string;
|
let shortUUID: string;
|
||||||
@ -33,9 +33,7 @@ describe('balena envs', function() {
|
|||||||
api.expectGetWhoAmI({ optional: true, persist: true });
|
api.expectGetWhoAmI({ optional: true, persist: true });
|
||||||
api.expectGetMixpanel({ optional: true });
|
api.expectGetMixpanel({ optional: true });
|
||||||
// Random device UUID used to frustrate _.memoize() in utils/cloud.ts
|
// Random device UUID used to frustrate _.memoize() in utils/cloud.ts
|
||||||
fullUUID = require('crypto')
|
fullUUID = require('crypto').randomBytes(16).toString('hex');
|
||||||
.randomBytes(16)
|
|
||||||
.toString('hex');
|
|
||||||
shortUUID = fullUUID.substring(0, 7);
|
shortUUID = fullUUID.substring(0, 7);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
2
tests/commands/env/rename.spec.ts
vendored
2
tests/commands/env/rename.spec.ts
vendored
@ -20,7 +20,7 @@ import { expect } from 'chai';
|
|||||||
import { BalenaAPIMock } from '../../balena-api-mock';
|
import { BalenaAPIMock } from '../../balena-api-mock';
|
||||||
import { runCommand } from '../../helpers';
|
import { runCommand } from '../../helpers';
|
||||||
|
|
||||||
describe('balena env rename', function() {
|
describe('balena env rename', function () {
|
||||||
let api: BalenaAPIMock;
|
let api: BalenaAPIMock;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
2
tests/commands/env/rm.spec.ts
vendored
2
tests/commands/env/rm.spec.ts
vendored
@ -20,7 +20,7 @@ import { expect } from 'chai';
|
|||||||
import { BalenaAPIMock } from '../../balena-api-mock';
|
import { BalenaAPIMock } from '../../balena-api-mock';
|
||||||
import { runCommand } from '../../helpers';
|
import { runCommand } from '../../helpers';
|
||||||
|
|
||||||
describe('balena env rm', function() {
|
describe('balena env rm', function () {
|
||||||
let api: BalenaAPIMock;
|
let api: BalenaAPIMock;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -92,7 +92,7 @@ const ONLINE_RESOURCES = `
|
|||||||
For bug reports or feature requests, see: https://github.com/balena-io/balena-cli/issues/
|
For bug reports or feature requests, see: https://github.com/balena-io/balena-cli/issues/
|
||||||
`;
|
`;
|
||||||
|
|
||||||
describe('balena help', function() {
|
describe('balena help', function () {
|
||||||
it('should list primary command summaries', async () => {
|
it('should list primary command summaries', async () => {
|
||||||
const { out, err } = await runCommand('help');
|
const { out, err } = await runCommand('help');
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ import { SupervisorMock } from '../supervisor-mock';
|
|||||||
|
|
||||||
const itS = process.env.BALENA_CLI_TEST_TYPE === 'standalone' ? it : it.skip;
|
const itS = process.env.BALENA_CLI_TEST_TYPE === 'standalone' ? it : it.skip;
|
||||||
|
|
||||||
describe('balena logs', function() {
|
describe('balena logs', function () {
|
||||||
let api: BalenaAPIMock;
|
let api: BalenaAPIMock;
|
||||||
let supervisor: SupervisorMock;
|
let supervisor: SupervisorMock;
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ describe('balena logs', function() {
|
|||||||
|
|
||||||
const removeTimestamps = (logLine: string) =>
|
const removeTimestamps = (logLine: string) =>
|
||||||
logLine.replace(/(?<=\[Logs\]) \[.+?\]/, '');
|
logLine.replace(/(?<=\[Logs\]) \[.+?\]/, '');
|
||||||
const cleanedOut = cleanOutput(out, true).map(l => removeTimestamps(l));
|
const cleanedOut = cleanOutput(out, true).map((l) => removeTimestamps(l));
|
||||||
|
|
||||||
expect(cleanedOut).to.deep.equal([
|
expect(cleanedOut).to.deep.equal([
|
||||||
'[Logs] Streaming logs',
|
'[Logs] Streaming logs',
|
||||||
|
@ -6,7 +6,7 @@ import { runCommand } from '../../helpers';
|
|||||||
import { BalenaAPIMock } from '../../balena-api-mock';
|
import { BalenaAPIMock } from '../../balena-api-mock';
|
||||||
|
|
||||||
if (process.platform !== 'win32') {
|
if (process.platform !== 'win32') {
|
||||||
describe('balena os configure', function() {
|
describe('balena os configure', function () {
|
||||||
let api: BalenaAPIMock;
|
let api: BalenaAPIMock;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
@ -80,7 +80,7 @@ const commonQueryParams = [
|
|||||||
|
|
||||||
const itSkipWindows = process.platform === 'win32' ? it.skip : it;
|
const itSkipWindows = process.platform === 'win32' ? it.skip : it;
|
||||||
|
|
||||||
describe('balena push', function() {
|
describe('balena push', function () {
|
||||||
let api: BalenaAPIMock;
|
let api: BalenaAPIMock;
|
||||||
let builder: BuilderMock;
|
let builder: BuilderMock;
|
||||||
const isWindows = process.platform === 'win32';
|
const isWindows = process.platform === 'win32';
|
||||||
@ -167,7 +167,7 @@ describe('balena push', function() {
|
|||||||
path.join(builderResponsePath, responseFilename),
|
path.join(builderResponsePath, responseFilename),
|
||||||
'utf8',
|
'utf8',
|
||||||
);
|
);
|
||||||
const expectedQueryParams = commonQueryParams.map(i =>
|
const expectedQueryParams = commonQueryParams.map((i) =>
|
||||||
i[0] === 'dockerfilePath' ? ['dockerfilePath', 'Dockerfile-alt'] : i,
|
i[0] === 'dockerfilePath' ? ['dockerfilePath', 'Dockerfile-alt'] : i,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -471,7 +471,7 @@ describe('balena push', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('balena push: project validation', function() {
|
describe('balena push: project validation', function () {
|
||||||
it('should raise ExpectedError if the project folder is not a directory', async () => {
|
it('should raise ExpectedError if the project folder is not a directory', async () => {
|
||||||
const projectPath = path.join(
|
const projectPath = path.join(
|
||||||
projectsPath,
|
projectsPath,
|
||||||
|
@ -23,7 +23,7 @@ const nodeVersion = process.version.startsWith('v')
|
|||||||
? process.version.slice(1)
|
? process.version.slice(1)
|
||||||
: process.version;
|
: process.version;
|
||||||
|
|
||||||
describe('balena version', function() {
|
describe('balena version', function () {
|
||||||
it('should print the installed version of the CLI', async () => {
|
it('should print the installed version of the CLI', async () => {
|
||||||
const { err, out } = await runCommand('version');
|
const { err, out } = await runCommand('version');
|
||||||
expect(err).to.be.empty;
|
expect(err).to.be.empty;
|
||||||
|
@ -89,7 +89,7 @@ export async function inspectTarStream(
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(found).to.deep.equal(
|
expect(found).to.deep.equal(
|
||||||
_.mapValues(expectedFiles, v => _.omit(v, 'testStream', 'contents')),
|
_.mapValues(expectedFiles, (v) => _.omit(v, 'testStream', 'contents')),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +220,7 @@ export async function testPushBuildStream(o: {
|
|||||||
const queryParams = Array.from(url.searchParams.entries());
|
const queryParams = Array.from(url.searchParams.entries());
|
||||||
expect(queryParams).to.have.deep.members(expectedQueryParams);
|
expect(queryParams).to.have.deep.members(expectedQueryParams);
|
||||||
},
|
},
|
||||||
checkBuildRequestBody: buildRequestBody =>
|
checkBuildRequestBody: (buildRequestBody) =>
|
||||||
inspectTarStream(buildRequestBody, o.expectedFiles, o.projectPath),
|
inspectTarStream(buildRequestBody, o.expectedFiles, o.projectPath),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ export class DockerMock extends NockMock {
|
|||||||
this.optPost(
|
this.optPost(
|
||||||
new RegExp(`^/build\\?t=${_.escapeRegExp(opts.tag)}&`),
|
new RegExp(`^/build\\?t=${_.escapeRegExp(opts.tag)}&`),
|
||||||
opts,
|
opts,
|
||||||
).reply(async function(uri, requestBody, cb) {
|
).reply(async function (uri, requestBody, cb) {
|
||||||
let error: Error | null = null;
|
let error: Error | null = null;
|
||||||
try {
|
try {
|
||||||
await opts.checkURI(uri);
|
await opts.checkURI(uri);
|
||||||
|
@ -124,7 +124,7 @@ describe('handleError() function', () => {
|
|||||||
'to be one of',
|
'to be one of',
|
||||||
];
|
];
|
||||||
|
|
||||||
messagesToMatch.forEach(message => {
|
messagesToMatch.forEach((message) => {
|
||||||
it(`should match as expected: "${message}"`, async () => {
|
it(`should match as expected: "${message}"`, async () => {
|
||||||
await ErrorsModule.handleError(new Error(message));
|
await ErrorsModule.handleError(new Error(message));
|
||||||
|
|
||||||
@ -146,7 +146,7 @@ describe('handleError() function', () => {
|
|||||||
new BalenaExpiredToken('test'),
|
new BalenaExpiredToken('test'),
|
||||||
];
|
];
|
||||||
|
|
||||||
typedErrorsToMatch.forEach(typedError => {
|
typedErrorsToMatch.forEach((typedError) => {
|
||||||
it(`should treat typedError ${typedError.name} as expected`, async () => {
|
it(`should treat typedError ${typedError.name} as expected`, async () => {
|
||||||
await ErrorsModule.handleError(typedError);
|
await ErrorsModule.handleError(typedError);
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ async function runCommandInSubprocess(
|
|||||||
// override default proxy exclusion to allow proxying of requests to 127.0.0.1
|
// override default proxy exclusion to allow proxying of requests to 127.0.0.1
|
||||||
BALENARC_DO_PROXY: '127.0.0.1,localhost',
|
BALENARC_DO_PROXY: '127.0.0.1,localhost',
|
||||||
};
|
};
|
||||||
await new Promise(resolve => {
|
await new Promise((resolve) => {
|
||||||
const child = execFile(
|
const child = execFile(
|
||||||
standalonePath,
|
standalonePath,
|
||||||
cmd.split(' '),
|
cmd.split(' '),
|
||||||
@ -165,8 +165,8 @@ ${$error}
|
|||||||
const splitLines = (lines: string) =>
|
const splitLines = (lines: string) =>
|
||||||
lines
|
lines
|
||||||
.split(/[\r\n]/) // includes '\r' in isolation, used in progress bars
|
.split(/[\r\n]/) // includes '\r' in isolation, used in progress bars
|
||||||
.filter(l => l)
|
.filter((l) => l)
|
||||||
.map(l => l + '\n');
|
.map((l) => l + '\n');
|
||||||
|
|
||||||
return filterCliOutputForTests({
|
return filterCliOutputForTests({
|
||||||
exitCode,
|
exitCode,
|
||||||
@ -207,17 +207,15 @@ export const balenaAPIMock = () => {
|
|||||||
nock.activate();
|
nock.activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
return nock(/./)
|
return nock(/./).get('/config/vars').reply(200, {
|
||||||
.get('/config/vars')
|
reservedNames: [],
|
||||||
.reply(200, {
|
reservedNamespaces: [],
|
||||||
reservedNames: [],
|
invalidRegex: '/^d|W/',
|
||||||
reservedNamespaces: [],
|
whiteListedNames: [],
|
||||||
invalidRegex: '/^d|W/',
|
whiteListedNamespaces: [],
|
||||||
whiteListedNames: [],
|
blackListedNames: [],
|
||||||
whiteListedNamespaces: [],
|
configVarSchema: [],
|
||||||
blackListedNames: [],
|
});
|
||||||
configVarSchema: [],
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function cleanOutput(
|
export function cleanOutput(
|
||||||
@ -280,7 +278,7 @@ export function fillTemplateArray(
|
|||||||
templateStringArray: Array<string | string[]>,
|
templateStringArray: Array<string | string[]>,
|
||||||
templateVars: object,
|
templateVars: object,
|
||||||
): Array<string | string[]> {
|
): Array<string | string[]> {
|
||||||
return templateStringArray.map(i =>
|
return templateStringArray.map((i) =>
|
||||||
Array.isArray(i)
|
Array.isArray(i)
|
||||||
? fillTemplateArray(i, templateVars)
|
? fillTemplateArray(i, templateVars)
|
||||||
: fillTemplate(i, templateVars),
|
: fillTemplate(i, templateVars),
|
||||||
|
@ -91,7 +91,7 @@ export class NockMock {
|
|||||||
inspectRequest: (uri: string, requestBody: nock.Body) => void,
|
inspectRequest: (uri: string, requestBody: nock.Body) => void,
|
||||||
replyBody: nock.ReplyBody,
|
replyBody: nock.ReplyBody,
|
||||||
) {
|
) {
|
||||||
return function(
|
return function (
|
||||||
this: nock.ReplyFnContext,
|
this: nock.ReplyFnContext,
|
||||||
uri: string,
|
uri: string,
|
||||||
requestBody: nock.Body,
|
requestBody: nock.Body,
|
||||||
@ -166,13 +166,13 @@ export class NockMock {
|
|||||||
let mocks = scope.pendingMocks();
|
let mocks = scope.pendingMocks();
|
||||||
console.error(`pending mocks ${mocks.length}: ${mocks}`);
|
console.error(`pending mocks ${mocks.length}: ${mocks}`);
|
||||||
|
|
||||||
this.scope.on('request', function(_req, _interceptor, _body) {
|
this.scope.on('request', function (_req, _interceptor, _body) {
|
||||||
console.log(`>> REQUEST:` + _req.path);
|
console.log(`>> REQUEST:` + _req.path);
|
||||||
mocks = scope.pendingMocks();
|
mocks = scope.pendingMocks();
|
||||||
console.error(`pending mocks ${mocks.length}: ${mocks}`);
|
console.error(`pending mocks ${mocks.length}: ${mocks}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.scope.on('replied', function(_req) {
|
this.scope.on('replied', function (_req) {
|
||||||
console.log(`<< REPLIED:` + _req.path);
|
console.log(`<< REPLIED:` + _req.path);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -58,14 +58,14 @@ import * as http from 'http';
|
|||||||
|
|
||||||
const proxyServers: http.Server[] = [];
|
const proxyServers: http.Server[] = [];
|
||||||
|
|
||||||
after(function() {
|
after(function () {
|
||||||
if (proxyServers.length) {
|
if (proxyServers.length) {
|
||||||
if (process.env.DEBUG) {
|
if (process.env.DEBUG) {
|
||||||
console.error(
|
console.error(
|
||||||
`[debug] Closing proxy servers (count=${proxyServers.length})`,
|
`[debug] Closing proxy servers (count=${proxyServers.length})`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
proxyServers.forEach(s => s.close());
|
proxyServers.forEach((s) => s.close());
|
||||||
proxyServers.splice(0);
|
proxyServers.splice(0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -86,7 +86,7 @@ async function createProxyServer(): Promise<[number, number]> {
|
|||||||
const interceptorPort = await createInterceptorServer();
|
const interceptorPort = await createInterceptorServer();
|
||||||
|
|
||||||
const proxy = httpProxy.createProxyServer();
|
const proxy = httpProxy.createProxyServer();
|
||||||
proxy.on('error', function(
|
proxy.on('error', function (
|
||||||
err: Error,
|
err: Error,
|
||||||
_req: http.IncomingMessage,
|
_req: http.IncomingMessage,
|
||||||
res: http.ServerResponse,
|
res: http.ServerResponse,
|
||||||
@ -97,7 +97,7 @@ async function createProxyServer(): Promise<[number, number]> {
|
|||||||
res.end(msg);
|
res.end(msg);
|
||||||
});
|
});
|
||||||
|
|
||||||
const server = http.createServer(function(
|
const server = http.createServer(function (
|
||||||
req: http.IncomingMessage,
|
req: http.IncomingMessage,
|
||||||
res: http.ServerResponse,
|
res: http.ServerResponse,
|
||||||
) {
|
) {
|
||||||
@ -166,7 +166,7 @@ async function createInterceptorServer(): Promise<number> {
|
|||||||
};
|
};
|
||||||
const srvReq = http.request(reqOpts);
|
const srvReq = http.request(reqOpts);
|
||||||
srvReq
|
srvReq
|
||||||
.on('error', err => {
|
.on('error', (err) => {
|
||||||
console.error(
|
console.error(
|
||||||
`Interceptor server error in onward request:\n${err}`,
|
`Interceptor server error in onward request:\n${err}`,
|
||||||
);
|
);
|
||||||
|
@ -24,7 +24,7 @@ import {
|
|||||||
detectEncoding,
|
detectEncoding,
|
||||||
} from '../../build/utils/eol-conversion';
|
} from '../../build/utils/eol-conversion';
|
||||||
|
|
||||||
describe('convertEolInPlace() function', function() {
|
describe('convertEolInPlace() function', function () {
|
||||||
it('should return expected values', () => {
|
it('should return expected values', () => {
|
||||||
// pairs of [given input, expected output]
|
// pairs of [given input, expected output]
|
||||||
const testVector = [
|
const testVector = [
|
||||||
@ -59,7 +59,7 @@ describe('convertEolInPlace() function', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('detectEncoding() function', function() {
|
describe('detectEncoding() function', function () {
|
||||||
it('should correctly detect the encoding of a few selected files', async () => {
|
it('should correctly detect the encoding of a few selected files', async () => {
|
||||||
const sampleBinary = [
|
const sampleBinary = [
|
||||||
'ext2fs/build/Release/bindings.node',
|
'ext2fs/build/Release/bindings.node',
|
||||||
|
@ -19,7 +19,7 @@ import { expect } from 'chai';
|
|||||||
|
|
||||||
import { getProxyConfig } from '../../build/utils/helpers';
|
import { getProxyConfig } from '../../build/utils/helpers';
|
||||||
|
|
||||||
describe('getProxyConfig() function', function() {
|
describe('getProxyConfig() function', function () {
|
||||||
let originalProxyConfig: [boolean, object | undefined];
|
let originalProxyConfig: [boolean, object | undefined];
|
||||||
let originalHttpProxy: [boolean, string | undefined];
|
let originalHttpProxy: [boolean, string | undefined];
|
||||||
let originalHttpsProxy: [boolean, string | undefined];
|
let originalHttpsProxy: [boolean, string | undefined];
|
||||||
|
@ -7,8 +7,8 @@ import { FileIgnorer, IgnoreFileType } from '../../build/utils/ignore';
|
|||||||
// of the FileIgnorer class to prevent a Typescript compilation error (this
|
// of the FileIgnorer class to prevent a Typescript compilation error (this
|
||||||
// behavior is by design: see
|
// behavior is by design: see
|
||||||
// https://github.com/microsoft/TypeScript/issues/19335 )
|
// https://github.com/microsoft/TypeScript/issues/19335 )
|
||||||
describe('File ignorer', function() {
|
describe('File ignorer', function () {
|
||||||
it('should detect ignore files', function() {
|
it('should detect ignore files', function () {
|
||||||
const f = new FileIgnorer(`.${path.sep}`);
|
const f = new FileIgnorer(`.${path.sep}`);
|
||||||
expect(f.getIgnoreFileType('.gitignore')).to.equal(
|
expect(f.getIgnoreFileType('.gitignore')).to.equal(
|
||||||
IgnoreFileType.GitIgnore,
|
IgnoreFileType.GitIgnore,
|
||||||
@ -36,7 +36,7 @@ describe('File ignorer', function() {
|
|||||||
return expect(f.getIgnoreFileType('./file')).to.equal(null);
|
return expect(f.getIgnoreFileType('./file')).to.equal(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should filter files from the root directory', function() {
|
it('should filter files from the root directory', function () {
|
||||||
const ignore = new FileIgnorer(`.${path.sep}`);
|
const ignore = new FileIgnorer(`.${path.sep}`);
|
||||||
ignore['gitIgnoreEntries'] = [
|
ignore['gitIgnoreEntries'] = [
|
||||||
{ pattern: '*.ignore', filePath: '.gitignore' },
|
{ pattern: '*.ignore', filePath: '.gitignore' },
|
||||||
@ -61,7 +61,7 @@ describe('File ignorer', function() {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
return it('should filter files from subdirectories', function() {
|
return it('should filter files from subdirectories', function () {
|
||||||
const ignore = new FileIgnorer(`.${path.sep}`);
|
const ignore = new FileIgnorer(`.${path.sep}`);
|
||||||
ignore['gitIgnoreEntries'] = [
|
ignore['gitIgnoreEntries'] = [
|
||||||
{ pattern: '*.ignore', filePath: 'lib/.gitignore' },
|
{ pattern: '*.ignore', filePath: 'lib/.gitignore' },
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
|
|
||||||
describe('resin-multibuild consistency', function() {
|
describe('resin-multibuild consistency', function () {
|
||||||
it('should use the same values for selected constants', async () => {
|
it('should use the same values for selected constants', async () => {
|
||||||
const { QEMU_BIN_NAME: MQEMU_BIN_NAME } = await import('resin-multibuild');
|
const { QEMU_BIN_NAME: MQEMU_BIN_NAME } = await import('resin-multibuild');
|
||||||
const { QEMU_BIN_NAME } = await import('../../build/utils/qemu');
|
const { QEMU_BIN_NAME } = await import('../../build/utils/qemu');
|
||||||
|
@ -38,7 +38,7 @@ interface TarFiles {
|
|||||||
|
|
||||||
const itSkipWindows = process.platform === 'win32' ? it.skip : it;
|
const itSkipWindows = process.platform === 'win32' ? it.skip : it;
|
||||||
|
|
||||||
describe('compare new and old tarDirectory implementations', function() {
|
describe('compare new and old tarDirectory implementations', function () {
|
||||||
const extraContent = 'extra';
|
const extraContent = 'extra';
|
||||||
const extraEntry: tar.Headers = {
|
const extraEntry: tar.Headers = {
|
||||||
name: 'extra.txt',
|
name: 'extra.txt',
|
||||||
@ -61,7 +61,7 @@ describe('compare new and old tarDirectory implementations', function() {
|
|||||||
// (with a mismatched fileSize 13 vs 5 for 'symlink-a.txt'), ensure that the
|
// (with a mismatched fileSize 13 vs 5 for 'symlink-a.txt'), ensure that the
|
||||||
// `core.symlinks` property is set to `true` in the `.git/config` file. Ref:
|
// `core.symlinks` property is set to `true` in the `.git/config` file. Ref:
|
||||||
// https://git-scm.com/docs/git-config#Documentation/git-config.txt-coresymlinks
|
// https://git-scm.com/docs/git-config#Documentation/git-config.txt-coresymlinks
|
||||||
it('should produce the expected file list', async function() {
|
it('should produce the expected file list', async function () {
|
||||||
const dockerignoreProjDir = path.join(
|
const dockerignoreProjDir = path.join(
|
||||||
projectsPath,
|
projectsPath,
|
||||||
'no-docker-compose',
|
'no-docker-compose',
|
||||||
@ -92,7 +92,7 @@ describe('compare new and old tarDirectory implementations', function() {
|
|||||||
expect(fileList).to.deep.equal(expectedFiles);
|
expect(fileList).to.deep.equal(expectedFiles);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should produce the expected file list (symbolic links)', async function() {
|
it('should produce the expected file list (symbolic links)', async function () {
|
||||||
const projectPath = path.join(
|
const projectPath = path.join(
|
||||||
projectsPath,
|
projectsPath,
|
||||||
'no-docker-compose',
|
'no-docker-compose',
|
||||||
@ -115,7 +115,7 @@ describe('compare new and old tarDirectory implementations', function() {
|
|||||||
// Skip Windows because the old tarDirectory() implementation (still used when
|
// Skip Windows because the old tarDirectory() implementation (still used when
|
||||||
// '--nogitignore' is not provided) uses the old `zeit/dockerignore` npm package
|
// '--nogitignore' is not provided) uses the old `zeit/dockerignore` npm package
|
||||||
// that is broken on Windows (reason why we created `@balena/dockerignore`).
|
// that is broken on Windows (reason why we created `@balena/dockerignore`).
|
||||||
itSkipWindows('should produce a compatible tar stream', async function() {
|
itSkipWindows('should produce a compatible tar stream', async function () {
|
||||||
const dockerignoreProjDir = path.join(
|
const dockerignoreProjDir = path.join(
|
||||||
projectsPath,
|
projectsPath,
|
||||||
'no-docker-compose',
|
'no-docker-compose',
|
||||||
@ -146,7 +146,7 @@ describe('compare new and old tarDirectory implementations', function() {
|
|||||||
|
|
||||||
itSkipWindows(
|
itSkipWindows(
|
||||||
'should produce a compatible tar stream (symbolic links)',
|
'should produce a compatible tar stream (symbolic links)',
|
||||||
async function() {
|
async function () {
|
||||||
const dockerignoreProjDir = path.join(
|
const dockerignoreProjDir = path.join(
|
||||||
projectsPath,
|
projectsPath,
|
||||||
'no-docker-compose',
|
'no-docker-compose',
|
||||||
@ -179,7 +179,7 @@ async function getTarPackFiles(
|
|||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
extract
|
extract
|
||||||
.on('error', reject)
|
.on('error', reject)
|
||||||
.on('entry', async function(header, stream, next) {
|
.on('entry', async function (header, stream, next) {
|
||||||
expect(fileList).to.not.have.property(header.name);
|
expect(fileList).to.not.have.property(header.name);
|
||||||
fileList[header.name] = {
|
fileList[header.name] = {
|
||||||
fileSize: header.size,
|
fileSize: header.size,
|
||||||
@ -188,7 +188,7 @@ async function getTarPackFiles(
|
|||||||
await drainStream(stream);
|
await drainStream(stream);
|
||||||
next();
|
next();
|
||||||
})
|
})
|
||||||
.on('finish', function() {
|
.on('finish', function () {
|
||||||
resolve(fileList);
|
resolve(fileList);
|
||||||
});
|
});
|
||||||
pack.pipe(extract);
|
pack.pipe(extract);
|
||||||
|
Loading…
Reference in New Issue
Block a user