mirror of
https://github.com/balena-io/balena-cli.git
synced 2024-12-18 21:27:51 +00:00
Merge pull request #2895 from balena-io/bump-balena-lint-v9
Update @balena/lint to v9.1.3
This commit is contained in:
commit
45f482fad1
@ -145,7 +145,7 @@ export async function getCapitanoDoc(): Promise<typeof capitanoDoc> {
|
||||
throw new Error(`Error parsing section title`);
|
||||
}
|
||||
// match[1] has the title, match[2] has the rest
|
||||
return match && match[2];
|
||||
return match?.[2];
|
||||
}),
|
||||
mdParser.getSectionOfTitle('Installation'),
|
||||
mdParser.getSectionOfTitle('Choosing a shell (command prompt/terminal)'),
|
||||
|
@ -3,7 +3,7 @@ import * as semver from 'semver';
|
||||
|
||||
const changeTypes = ['major', 'minor', 'patch'] as const;
|
||||
|
||||
const validateChangeType = (maybeChangeType: string = 'minor') => {
|
||||
const validateChangeType = (maybeChangeType = 'minor') => {
|
||||
maybeChangeType = maybeChangeType.toLowerCase();
|
||||
switch (maybeChangeType) {
|
||||
case 'patch':
|
||||
@ -136,5 +136,4 @@ async function main() {
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
main();
|
||||
void main();
|
||||
|
@ -19,6 +19,7 @@ import { spawn } from 'child_process';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import { diffTrimmedLines } from 'diff';
|
||||
import * as whichMod from 'which';
|
||||
|
||||
export const ROOT = path.join(__dirname, '..');
|
||||
|
||||
@ -101,7 +102,6 @@ export function loadPackageJson() {
|
||||
* @returns The program's full path, e.g. 'C:\WINDOWS\System32\OpenSSH\ssh.EXE'
|
||||
*/
|
||||
export async function which(program: string): Promise<string> {
|
||||
const whichMod = await import('which');
|
||||
let programPath: string;
|
||||
try {
|
||||
programPath = await whichMod(program);
|
||||
@ -132,7 +132,7 @@ export async function whichSpawn(
|
||||
.on('error', reject)
|
||||
.on('close', resolve);
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
reject(err as Error);
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
|
@ -57,7 +57,10 @@ require('ts-node').register({
|
||||
project: path.join(rootDir, 'tsconfig.json'),
|
||||
transpileOnly: true,
|
||||
});
|
||||
require('../src/app').run(undefined, { dir: __dirname, development: true });
|
||||
void require('../src/app').run(undefined, {
|
||||
dir: __dirname,
|
||||
development: true,
|
||||
});
|
||||
|
||||
// Modify package.json oclif paths from build/ -> src/, or vice versa
|
||||
function modifyOclifPaths(revert) {
|
||||
|
@ -5,7 +5,7 @@
|
||||
process.env.UV_THREADPOOL_SIZE = '64';
|
||||
|
||||
// Disable oclif registering ts-node
|
||||
process.env.OCLIF_TS_NODE = 0;
|
||||
process.env.OCLIF_TS_NODE = '0';
|
||||
|
||||
async function run() {
|
||||
// Use fast-boot to cache require lookups, speeding up startup
|
||||
@ -18,4 +18,4 @@ async function run() {
|
||||
await require('../build/app').run(undefined, { dir: __dirname });
|
||||
}
|
||||
|
||||
run();
|
||||
void run();
|
||||
|
32
eslint.config.js
Normal file
32
eslint.config.js
Normal file
@ -0,0 +1,32 @@
|
||||
const { FlatCompat } = require('@eslint/eslintrc');
|
||||
|
||||
const compat = new FlatCompat({
|
||||
baseDirectory: __dirname,
|
||||
});
|
||||
module.exports = [
|
||||
...require('@balena/lint/config/eslint.config'),
|
||||
...compat.config({
|
||||
parserOptions: {
|
||||
project: 'tsconfig.dev.json',
|
||||
},
|
||||
ignorePatterns: ['**/generate-completion.js', '**/bin/**/*'],
|
||||
rules: {
|
||||
ignoreDefinitionFiles: 0,
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
'@typescript-eslint/no-shadow': 'off',
|
||||
'@typescript-eslint/no-var-requires': 'off',
|
||||
'@typescript-eslint/no-require-imports': 'off',
|
||||
'@typescript-eslint/no-unnecessary-type-assertion': 'off',
|
||||
'@typescript-eslint/prefer-nullish-coalescing': 'warn',
|
||||
|
||||
'no-restricted-imports': ['error', {
|
||||
paths: ['resin-cli-visuals', 'chalk', 'common-tags', 'resin-cli-form'],
|
||||
}],
|
||||
|
||||
'@typescript-eslint/no-unused-vars': ['error', {
|
||||
argsIgnorePattern: '^_',
|
||||
caughtErrorsIgnorePattern: '^_',
|
||||
}],
|
||||
},
|
||||
}),
|
||||
];
|
2145
npm-shrinkwrap.json
generated
2145
npm-shrinkwrap.json
generated
File diff suppressed because it is too large
Load Diff
@ -111,7 +111,7 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@balena/lint": "^8.0.0",
|
||||
"@balena/lint": "^9.1.3",
|
||||
"@electron/notarize": "^2.0.0",
|
||||
"@types/archiver": "^6.0.2",
|
||||
"@types/bluebird": "^3.5.36",
|
||||
|
@ -50,9 +50,9 @@ export default class RevokeCmd extends Command {
|
||||
return;
|
||||
}
|
||||
await Promise.all(
|
||||
apiKeyIds.map(
|
||||
async (id) => await getBalenaSdk().models.apiKey.revoke(Number(id)),
|
||||
),
|
||||
apiKeyIds.map(async (id) => {
|
||||
await getBalenaSdk().models.apiKey.revoke(Number(id));
|
||||
}),
|
||||
);
|
||||
console.log('Successfully revoked the given API keys');
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ export default class DeviceDetectCmd extends Command {
|
||||
try {
|
||||
await docker.ping();
|
||||
return true;
|
||||
} catch (err) {
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}),
|
||||
|
@ -155,7 +155,7 @@ export default class DeviceInitCmd extends Command {
|
||||
try {
|
||||
logger.logDebug(`Process failed, removing device ${device.uuid}`);
|
||||
await balena.models.device.remove(device.uuid);
|
||||
} catch (e) {
|
||||
} catch {
|
||||
// Ignore removal failures, and throw original error
|
||||
}
|
||||
throw e;
|
||||
|
@ -135,7 +135,7 @@ export default class DeviceLogsCmd extends Command {
|
||||
logger.logDebug('Checking we can access device');
|
||||
try {
|
||||
await deviceApi.ping();
|
||||
} catch (e) {
|
||||
} catch {
|
||||
const { ExpectedError } = await import('../../errors');
|
||||
throw new ExpectedError(
|
||||
`Cannot access device at address ${params.device}. Device may not be in local mode.`,
|
||||
|
@ -76,6 +76,6 @@ export default class DeviceRegisterCmd extends Command {
|
||||
options.deviceType,
|
||||
);
|
||||
|
||||
return result && result.uuid;
|
||||
return result.uuid;
|
||||
}
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ export default class DeviceSSHCmd extends Command {
|
||||
SSH server port number (default 22222) if the target is an IP address or .local
|
||||
hostname. Otherwise, port number for the balenaCloud gateway (default 22).`,
|
||||
char: 'p',
|
||||
parse: async (p) => parseAsInteger(p, 'port'),
|
||||
parse: (p) => parseAsInteger(p, 'port'),
|
||||
}),
|
||||
tty: Flags.boolean({
|
||||
default: false,
|
||||
@ -110,13 +110,14 @@ export default class DeviceSSHCmd extends Command {
|
||||
// Local connection
|
||||
if (validateLocalHostnameOrIp(params.fleetOrDevice)) {
|
||||
const { performLocalDeviceSSH } = await import('../../utils/device/ssh');
|
||||
return await performLocalDeviceSSH({
|
||||
await performLocalDeviceSSH({
|
||||
hostname: params.fleetOrDevice,
|
||||
port: options.port || 'local',
|
||||
forceTTY: options.tty,
|
||||
verbose: options.verbose,
|
||||
service: params.service,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Remote connection
|
||||
@ -132,7 +133,7 @@ export default class DeviceSSHCmd extends Command {
|
||||
const useProxy = !!proxyConfig && !options.noproxy;
|
||||
|
||||
// this will be a tunnelled SSH connection...
|
||||
await checkNotUsingOfflineMode();
|
||||
checkNotUsingOfflineMode();
|
||||
await checkLoggedIn();
|
||||
const deviceUuid = await getOnlineTargetDeviceUuid(
|
||||
sdk,
|
||||
|
2
src/commands/env/rename.ts
vendored
2
src/commands/env/rename.ts
vendored
@ -41,7 +41,7 @@ export default class EnvRenameCmd extends Command {
|
||||
id: Args.integer({
|
||||
required: true,
|
||||
description: "variable's numeric database ID",
|
||||
parse: async (input) => parseAsInteger(input, 'id'),
|
||||
parse: (input) => parseAsInteger(input, 'id'),
|
||||
}),
|
||||
value: Args.string({
|
||||
required: true,
|
||||
|
2
src/commands/env/rm.ts
vendored
2
src/commands/env/rm.ts
vendored
@ -46,7 +46,7 @@ export default class EnvRmCmd extends Command {
|
||||
id: Args.integer({
|
||||
required: true,
|
||||
description: "variable's numeric database ID",
|
||||
parse: async (input) => parseAsInteger(input, 'id'),
|
||||
parse: (input) => parseAsInteger(input, 'id'),
|
||||
}),
|
||||
};
|
||||
|
||||
|
@ -252,10 +252,7 @@ export default class LocalConfigureCmd extends Command {
|
||||
`${this.CONNECTIONS_FOLDER}/resin-sample.ignore`,
|
||||
{ encoding: 'utf8' },
|
||||
);
|
||||
return await writeFileAsync(
|
||||
`${this.CONNECTIONS_FOLDER}/resin-wifi`,
|
||||
contents,
|
||||
);
|
||||
await writeFileAsync(`${this.CONNECTIONS_FOLDER}/resin-wifi`, contents);
|
||||
});
|
||||
} else if (_.includes(files, 'resin-sample')) {
|
||||
// Legacy mode, to be removed later
|
||||
@ -269,13 +266,13 @@ export default class LocalConfigureCmd extends Command {
|
||||
} else {
|
||||
// In case there's no file at all (shouldn't happen normally, but the file might have been removed)
|
||||
await imagefs.interact(target, bootPartition, async (_fs) => {
|
||||
return await promisify(_fs.writeFile)(
|
||||
await promisify(_fs.writeFile)(
|
||||
`${this.CONNECTIONS_FOLDER}/resin-wifi`,
|
||||
this.CONNECTION_FILE,
|
||||
);
|
||||
});
|
||||
}
|
||||
return await this.getConfigurationSchema(bootPartition, connectionFileName);
|
||||
return this.getConfigurationSchema(bootPartition, connectionFileName);
|
||||
}
|
||||
|
||||
async removeHostname(schema: any) {
|
||||
|
@ -132,7 +132,7 @@ export default class LoginCmd extends Command {
|
||||
// We can safely assume this won't be undefined as doLogin will throw if this call fails
|
||||
// We also don't need to worry too much about the amount of calls to whoami
|
||||
// as these are cached by the SDK
|
||||
const whoamiResult = (await balena.auth.whoami()) as WhoamiResult;
|
||||
const whoamiResult = (await balena.auth.whoami())!;
|
||||
|
||||
if (whoamiResult.actorType !== 'user' && !options.hideExperimentalWarning) {
|
||||
console.info(stripIndent`
|
||||
@ -168,7 +168,7 @@ ${messages.reachingOut}`);
|
||||
|
||||
async doLogin(
|
||||
loginOptions: FlagsDef,
|
||||
balenaUrl: string = 'balena-cloud.com',
|
||||
balenaUrl = 'balena-cloud.com',
|
||||
token?: string,
|
||||
): Promise<void> {
|
||||
// Token
|
||||
|
@ -292,7 +292,7 @@ export default class OsConfigureCmd extends Command {
|
||||
|
||||
for (const { name, content } of files) {
|
||||
await imagefs.interact(image, bootPartition, async (_fs) => {
|
||||
return await promisify(_fs.writeFile)(
|
||||
await promisify(_fs.writeFile)(
|
||||
path.join(CONNECTIONS_FOLDER, name),
|
||||
content,
|
||||
);
|
||||
|
@ -109,7 +109,7 @@ https://github.com/balena-io-examples/staged-releases\
|
||||
'additional-space': Flags.integer({
|
||||
description:
|
||||
'expand the image by this amount of bytes instead of automatically estimating the required amount',
|
||||
parse: async (x) => parseAsInteger(x, 'additional-space'),
|
||||
parse: (x) => parseAsInteger(x, 'additional-space'),
|
||||
}),
|
||||
'add-certificate': Flags.string({
|
||||
description: `\
|
||||
@ -126,7 +126,7 @@ Can be repeated to add multiple certificates.\
|
||||
dockerPort: Flags.integer({
|
||||
description:
|
||||
'Docker daemon TCP port number (hint: 2375 for balena devices)',
|
||||
parse: async (p) => parseAsInteger(p, 'dockerPort'),
|
||||
parse: (p) => parseAsInteger(p, 'dockerPort'),
|
||||
}),
|
||||
};
|
||||
|
||||
@ -155,7 +155,7 @@ Can be repeated to add multiple certificates.\
|
||||
------------------------------------------------------------------------------
|
||||
`);
|
||||
}
|
||||
} catch (error) {
|
||||
} catch {
|
||||
throw new ExpectedError(
|
||||
`The provided image path does not exist: ${params.image}`,
|
||||
);
|
||||
@ -192,11 +192,11 @@ Can be repeated to add multiple certificates.\
|
||||
event.name,
|
||||
));
|
||||
if (event.action === 'start') {
|
||||
return spinner.start();
|
||||
} else {
|
||||
console.log();
|
||||
return spinner.stop();
|
||||
spinner.start();
|
||||
return;
|
||||
}
|
||||
console.log();
|
||||
spinner.stop();
|
||||
};
|
||||
|
||||
const commit = this.isCurrentCommit(options.commit || '')
|
||||
|
@ -24,7 +24,7 @@ import { tryAsInteger } from '../../utils/validation';
|
||||
import { jsonInfo } from '../../utils/messages';
|
||||
|
||||
export const commitOrIdArg = Args.custom({
|
||||
parse: async (commitOrId: string) => tryAsInteger(commitOrId),
|
||||
parse: tryAsInteger,
|
||||
});
|
||||
|
||||
type FlagsDef = Interfaces.InferredFlags<typeof ReleaseCmd.flags>;
|
||||
|
@ -34,7 +34,7 @@ export default class SSHKeyCmd extends Command {
|
||||
public static args = {
|
||||
id: Args.integer({
|
||||
description: 'balenaCloud ID for the SSH key',
|
||||
parse: async (x) => parseAsInteger(x, 'id'),
|
||||
parse: (x) => parseAsInteger(x, 'id'),
|
||||
required: true,
|
||||
}),
|
||||
};
|
||||
|
@ -40,7 +40,7 @@ export default class SSHKeyRmCmd extends Command {
|
||||
public static args = {
|
||||
id: Args.integer({
|
||||
description: 'balenaCloud ID for the SSH key',
|
||||
parse: async (x) => parseAsInteger(x, 'id'),
|
||||
parse: (x) => parseAsInteger(x, 'id'),
|
||||
required: true,
|
||||
}),
|
||||
};
|
||||
|
@ -69,8 +69,7 @@ export default class VersionCmd extends Command {
|
||||
const { flags: options } = await this.parse(VersionCmd);
|
||||
const versions: JsonVersions = {
|
||||
'balena-cli': (await import('../../../package.json')).version,
|
||||
'Node.js':
|
||||
process.version && process.version.startsWith('v')
|
||||
'Node.js': process.version.startsWith('v')
|
||||
? process.version.slice(1)
|
||||
: process.version,
|
||||
};
|
||||
|
@ -93,7 +93,7 @@ function interpret(error: Error): string {
|
||||
|
||||
if (hasCode(error)) {
|
||||
const errorCodeHandler = messages[error.code];
|
||||
const message = errorCodeHandler && errorCodeHandler(error);
|
||||
const message = errorCodeHandler?.(error);
|
||||
|
||||
if (message) {
|
||||
return message;
|
||||
@ -229,7 +229,7 @@ async function sentryCaptureException(error: Error) {
|
||||
Sentry.captureException(error);
|
||||
try {
|
||||
await Sentry.close(1000);
|
||||
} catch (e) {
|
||||
} catch {
|
||||
if (process.env.DEBUG) {
|
||||
console.error('[debug] Timeout reporting error to sentry.io');
|
||||
}
|
||||
|
@ -209,12 +209,12 @@ See: https://git.io/JRHUW#deprecation-policy`,
|
||||
return indent(body, 2);
|
||||
}
|
||||
|
||||
protected formatDescription(desc: string = '') {
|
||||
protected formatDescription(desc = '') {
|
||||
const chalk = getChalk();
|
||||
|
||||
desc = desc.split('\n')[0];
|
||||
// Remove any ending .
|
||||
if (desc[desc.length - 1] === '.') {
|
||||
if (desc.endsWith('.')) {
|
||||
desc = desc.substring(0, desc.length - 1);
|
||||
}
|
||||
// Lowercase first letter if second char is lowercase, to preserve e.g. 'SSH ...')
|
||||
|
@ -103,7 +103,7 @@ const hook: Hook<'prerun'> = async function (options) {
|
||||
.offlineCompatible ?? DEFAULT_OFFLINE_COMPATIBLE
|
||||
)
|
||||
) {
|
||||
await checkNotUsingOfflineMode();
|
||||
checkNotUsingOfflineMode();
|
||||
}
|
||||
} catch (error) {
|
||||
this.error(error);
|
||||
|
@ -48,7 +48,7 @@ export async function preparseArgs(argv: string[]): Promise<string[]> {
|
||||
if (
|
||||
cmdSlice.length > 1 &&
|
||||
cmdSlice[0] === 'help' &&
|
||||
cmdSlice[1][0] !== '-'
|
||||
!cmdSlice[1].startsWith('-')
|
||||
) {
|
||||
cmdSlice.shift();
|
||||
cmdSlice.push('--help');
|
||||
|
@ -164,9 +164,8 @@ export async function downloadOSImage(
|
||||
stream.on('progress', (state: any) => {
|
||||
if (state != null) {
|
||||
return bar.update(state);
|
||||
} else {
|
||||
return spinner.start();
|
||||
}
|
||||
spinner.start();
|
||||
});
|
||||
|
||||
stream.on('end', () => {
|
||||
|
@ -386,7 +386,7 @@ export class BuildProgressUI implements Renderer {
|
||||
.map(function (service) {
|
||||
const stream = through.obj(function (event, _enc, cb) {
|
||||
eventHandler(service, event);
|
||||
return cb();
|
||||
cb();
|
||||
});
|
||||
stream.pipe(tty.stream, { end: false });
|
||||
return [service, stream];
|
||||
@ -471,17 +471,20 @@ export class BuildProgressUI implements Renderer {
|
||||
const { status, progress, error } = serviceToDataMap[service] ?? {};
|
||||
if (error) {
|
||||
return `${error}`;
|
||||
} else if (progress) {
|
||||
}
|
||||
|
||||
if (progress) {
|
||||
const bar = renderProgressBar(progress, 20);
|
||||
if (status) {
|
||||
return `${bar} ${status}`;
|
||||
}
|
||||
return `${bar}`;
|
||||
} else if (status) {
|
||||
return `${status}`;
|
||||
} else {
|
||||
return 'Waiting...';
|
||||
return bar;
|
||||
}
|
||||
|
||||
if (status) {
|
||||
return status;
|
||||
}
|
||||
return 'Waiting...';
|
||||
})
|
||||
.map((data, index) => [services[index], data])
|
||||
.fromPairs()
|
||||
@ -552,7 +555,7 @@ export class BuildProgressInline implements Renderer {
|
||||
.map(function (service) {
|
||||
const stream = through.obj(function (event, _enc, cb) {
|
||||
eventHandler(service, event);
|
||||
return cb();
|
||||
cb();
|
||||
});
|
||||
stream.pipe(outStream, { end: false });
|
||||
return [service, stream];
|
||||
@ -606,11 +609,11 @@ export class BuildProgressInline implements Renderer {
|
||||
const { status, error } = event;
|
||||
if (error) {
|
||||
return `${error}`;
|
||||
} else if (status) {
|
||||
return `${status}`;
|
||||
} else {
|
||||
return 'Waiting...';
|
||||
}
|
||||
if (status) {
|
||||
return status;
|
||||
}
|
||||
return 'Waiting...';
|
||||
})();
|
||||
|
||||
const prefix = _.padEnd(getChalk().bold(service), this._prefixWidth);
|
||||
|
@ -966,7 +966,7 @@ export async function makeBuildTasks(
|
||||
deviceInfo: DeviceInfo,
|
||||
logger: Logger,
|
||||
projectName: string,
|
||||
releaseHash: string = 'unavailable',
|
||||
releaseHash = 'unavailable',
|
||||
preprocessHook?: (dockerfile: string) => string,
|
||||
): Promise<MultiBuild.BuildTask[]> {
|
||||
const multiBuild = await import('@balena/compose/dist/multibuild');
|
||||
@ -1492,7 +1492,7 @@ export function createRunLoop(tick: (...args: any[]) => void) {
|
||||
},
|
||||
end() {
|
||||
clearInterval(timerId);
|
||||
return runloop.onEnd();
|
||||
runloop.onEnd();
|
||||
},
|
||||
};
|
||||
return runloop;
|
||||
@ -1549,7 +1549,7 @@ function dropEmptyLinesStream() {
|
||||
if (str.trim()) {
|
||||
this.push(str);
|
||||
}
|
||||
return cb();
|
||||
cb();
|
||||
});
|
||||
}
|
||||
|
||||
@ -1570,7 +1570,7 @@ function buildLogCapture(objectMode: boolean, buffer: string[]) {
|
||||
buffer.push(data);
|
||||
}
|
||||
|
||||
return cb(null, data);
|
||||
cb(null, data);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1585,14 +1585,16 @@ function buildProgressAdapter(inline: boolean) {
|
||||
|
||||
return through({ objectMode: true }, function (str, _enc, cb) {
|
||||
if (str == null) {
|
||||
return cb(null, str);
|
||||
cb(null, str);
|
||||
return;
|
||||
}
|
||||
|
||||
if (inline) {
|
||||
return cb(null, { status: str });
|
||||
cb(null, { status: str });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!/^Successfully tagged /.test(str)) {
|
||||
if (!str.startsWith('Successfully tagged ')) {
|
||||
const match = stepRegex.exec(str);
|
||||
if (match) {
|
||||
step = match[1];
|
||||
@ -1607,7 +1609,7 @@ function buildProgressAdapter(inline: boolean) {
|
||||
}
|
||||
}
|
||||
|
||||
return cb(null, { status: str, progress });
|
||||
cb(null, { status: str, progress });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ export async function generateApplicationConfig(
|
||||
)) as ImgConfig;
|
||||
|
||||
// merge sshKeys to config, when they have been specified
|
||||
if (options.os && options.os.sshKeys) {
|
||||
if (options.os?.sshKeys) {
|
||||
// Create config.os object if it does not exist
|
||||
config.os = config.os ? config.os : {};
|
||||
config.os.sshKeys = config.os.sshKeys
|
||||
|
@ -86,7 +86,7 @@ const uploadToPromise = (uploadRequest: Request, logger: Logger) =>
|
||||
obj = JSON.parse(data);
|
||||
} catch (e) {
|
||||
logger.logError('Error parsing reply from remote side');
|
||||
reject(e);
|
||||
reject(e as Error);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -232,7 +232,7 @@ export const deployLegacy = async function (
|
||||
username,
|
||||
appName,
|
||||
]);
|
||||
await uploadLogs(...args);
|
||||
uploadLogs(...args);
|
||||
}
|
||||
|
||||
return buildId;
|
||||
|
@ -74,7 +74,7 @@ export class DeviceAPI {
|
||||
public constructor(
|
||||
private logger: Logger,
|
||||
addr: string,
|
||||
port: number = 48484,
|
||||
port = 48484,
|
||||
) {
|
||||
this.deviceAddress = `http://${addr}:${port}/`;
|
||||
}
|
||||
@ -201,7 +201,7 @@ export class DeviceAPI {
|
||||
return new Promise((resolve, reject) => {
|
||||
const req = request.get(url);
|
||||
|
||||
req.on('error', reject).on('response', async (res) => {
|
||||
req.on('error', reject).on('response', (res) => {
|
||||
if (res.statusCode !== 200) {
|
||||
reject(
|
||||
new ApiErrors.DeviceAPIError(
|
||||
@ -213,7 +213,7 @@ export class DeviceAPI {
|
||||
try {
|
||||
res.socket.setKeepAlive(true, 1000);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
reject(error as Error);
|
||||
}
|
||||
resolve(res);
|
||||
});
|
||||
@ -238,7 +238,7 @@ export class DeviceAPI {
|
||||
if (_.isObject(opts) && (opts as ObjectWithUrl).url != null) {
|
||||
// the `as string` shouldn't be necessary, but the type system
|
||||
// is getting a little confused
|
||||
url = (opts as ObjectWithUrl).url as string;
|
||||
url = (opts as ObjectWithUrl).url!;
|
||||
} else if (typeof opts === 'string') {
|
||||
url = opts;
|
||||
}
|
||||
@ -252,21 +252,26 @@ export class DeviceAPI {
|
||||
return await new Promise((resolve, reject) => {
|
||||
return request(opts, (err, response, body) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
reject(err as Error);
|
||||
return;
|
||||
}
|
||||
switch (response.statusCode) {
|
||||
case 200:
|
||||
return resolve(body);
|
||||
case 400:
|
||||
return reject(
|
||||
new ApiErrors.BadRequestDeviceAPIError(body.message),
|
||||
);
|
||||
case 503:
|
||||
return reject(
|
||||
new ApiErrors.ServiceUnavailableAPIError(body.message),
|
||||
);
|
||||
default:
|
||||
return reject(new ApiErrors.DeviceAPIError(body.message));
|
||||
case 200: {
|
||||
resolve(body);
|
||||
return;
|
||||
}
|
||||
case 400: {
|
||||
reject(new ApiErrors.BadRequestDeviceAPIError(body.message));
|
||||
return;
|
||||
}
|
||||
case 503: {
|
||||
reject(new ApiErrors.ServiceUnavailableAPIError(body.message));
|
||||
return;
|
||||
}
|
||||
default: {
|
||||
reject(new ApiErrors.DeviceAPIError(body.message));
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -74,11 +74,11 @@ interface ParsedEnvironment {
|
||||
[serviceName: string]: { [key: string]: string };
|
||||
}
|
||||
|
||||
async function environmentFromInput(
|
||||
function environmentFromInput(
|
||||
envs: string[],
|
||||
serviceNames: string[],
|
||||
logger: Logger,
|
||||
): Promise<ParsedEnvironment> {
|
||||
): ParsedEnvironment {
|
||||
// A normal environment variable regex, with an added part
|
||||
// to find a colon followed servicename at the start
|
||||
const varRegex = /^(?:([^\s:]+):)?([^\s]+?)=(.*)$/;
|
||||
@ -143,7 +143,7 @@ export async function deployToDevice(opts: DeviceDeployOptions): Promise<void> {
|
||||
try {
|
||||
globalLogger.logDebug('Checking we can access device');
|
||||
await api.ping();
|
||||
} catch (e) {
|
||||
} catch {
|
||||
throw new ExpectedError(stripIndent`
|
||||
Could not communicate with device supervisor at address ${opts.deviceHost}:${port}.
|
||||
Device may not have local mode enabled. Check with:
|
||||
@ -191,10 +191,7 @@ export async function deployToDevice(opts: DeviceDeployOptions): Promise<void> {
|
||||
});
|
||||
|
||||
// Attempt to attach to the device's docker daemon
|
||||
const docker = connectToDocker(
|
||||
opts.deviceHost,
|
||||
opts.devicePort != null ? opts.devicePort : 2375,
|
||||
);
|
||||
const docker = connectToDocker(opts.deviceHost, opts.devicePort ?? 2375);
|
||||
|
||||
await checkBuildSecretsRequirements(docker, opts.source);
|
||||
globalLogger.logDebug('Tarring all non-ignored files...');
|
||||
@ -231,7 +228,7 @@ export async function deployToDevice(opts: DeviceDeployOptions): Promise<void> {
|
||||
// Print a newline to clearly separate build time and runtime
|
||||
console.log();
|
||||
|
||||
const envs = await environmentFromInput(
|
||||
const envs = environmentFromInput(
|
||||
opts.env,
|
||||
Object.getOwnPropertyNames(project.composition.services),
|
||||
globalLogger,
|
||||
@ -388,7 +385,7 @@ async function performBuilds(
|
||||
);
|
||||
|
||||
// Check for failures
|
||||
await inspectBuildResults(localImages);
|
||||
inspectBuildResults(localImages);
|
||||
|
||||
const imagesToRemove: string[] = [];
|
||||
|
||||
@ -497,7 +494,7 @@ export async function rebuildSingleTask(
|
||||
}
|
||||
|
||||
await assignDockerBuildOpts(docker, [task], opts);
|
||||
await assignOutputHandlers([task], logger, logHandler);
|
||||
assignOutputHandlers([task], logger, logHandler);
|
||||
|
||||
const [localImage] = await multibuild.performBuilds(
|
||||
[task],
|
||||
@ -568,7 +565,7 @@ async function assignDockerBuildOpts(
|
||||
globalLogger.logDebug(`Using ${images.length} on-device images for cache...`);
|
||||
|
||||
await Promise.all(
|
||||
buildTasks.map(async (task: BuildTask) => {
|
||||
buildTasks.map((task: BuildTask) => {
|
||||
task.dockerOpts = {
|
||||
...(task.dockerOpts || {}),
|
||||
...{
|
||||
@ -666,7 +663,7 @@ export function generateTargetState(
|
||||
return targetState;
|
||||
}
|
||||
|
||||
async function inspectBuildResults(images: LocalImage[]): Promise<void> {
|
||||
function inspectBuildResults(images: LocalImage[]): void {
|
||||
const failures: LocalPushErrors.BuildFailure[] = [];
|
||||
|
||||
_.each(images, (image) => {
|
||||
@ -679,6 +676,6 @@ async function inspectBuildResults(images: LocalImage[]): Promise<void> {
|
||||
});
|
||||
|
||||
if (failures.length > 0) {
|
||||
throw new LocalPushErrors.BuildError(failures).toString();
|
||||
throw new LocalPushErrors.BuildError(failures);
|
||||
}
|
||||
}
|
||||
|
@ -191,8 +191,8 @@ export class LivepushManager {
|
||||
);
|
||||
const eventQueue = this.updateEventsWaiting[$serviceName];
|
||||
eventQueue.push(changedPath);
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.getDebouncedEventHandler($serviceName)();
|
||||
|
||||
void this.getDebouncedEventHandler($serviceName)();
|
||||
};
|
||||
|
||||
const monitor = this.setupFilesystemWatcher(
|
||||
@ -252,7 +252,7 @@ export class LivepushManager {
|
||||
try {
|
||||
// sync because chokidar defines a sync interface
|
||||
stats = fs.lstatSync(filePath);
|
||||
} catch (err) {
|
||||
} catch {
|
||||
// OK: the file may have been deleted. See also:
|
||||
// https://github.com/paulmillr/chokidar/blob/3.4.3/lib/fsevents-handler.js#L326-L328
|
||||
// https://github.com/paulmillr/chokidar/blob/3.4.3/lib/nodefs-handler.js#L364
|
||||
@ -267,15 +267,15 @@ export class LivepushManager {
|
||||
return dockerignore.ignores(relPath);
|
||||
},
|
||||
});
|
||||
monitor.on('add', (changedPath: string) =>
|
||||
changedPathHandler(serviceName, changedPath),
|
||||
);
|
||||
monitor.on('change', (changedPath: string) =>
|
||||
changedPathHandler(serviceName, changedPath),
|
||||
);
|
||||
monitor.on('unlink', (changedPath: string) =>
|
||||
changedPathHandler(serviceName, changedPath),
|
||||
);
|
||||
monitor.on('add', (changedPath: string) => {
|
||||
changedPathHandler(serviceName, changedPath);
|
||||
});
|
||||
monitor.on('change', (changedPath: string) => {
|
||||
changedPathHandler(serviceName, changedPath);
|
||||
});
|
||||
monitor.on('unlink', (changedPath: string) => {
|
||||
changedPathHandler(serviceName, changedPath);
|
||||
});
|
||||
return monitor;
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ export const dockerConnectionCliFlags = {
|
||||
description:
|
||||
'Docker daemon TCP port number (hint: 2375 for balena devices)',
|
||||
char: 'p',
|
||||
parse: async (p) => parseAsInteger(p, 'dockerPort'),
|
||||
parse: (p) => parseAsInteger(p, 'dockerPort'),
|
||||
}),
|
||||
ca: Flags.string({
|
||||
description: 'Docker host TLS certificate authority file',
|
||||
@ -169,9 +169,7 @@ export async function isBalenaEngine(docker: dockerode): Promise<boolean> {
|
||||
// version of balenaEngine, but it was at one point (mis)spelt 'balaena':
|
||||
// https://github.com/balena-os/balena-engine/pull/32/files
|
||||
const dockerVersion = (await docker.version()) as BalenaEngineVersion;
|
||||
return !!(
|
||||
dockerVersion.Engine && dockerVersion.Engine.match(/balena|balaena/)
|
||||
);
|
||||
return !!dockerVersion.Engine?.match(/balena|balaena/);
|
||||
}
|
||||
|
||||
export async function getDocker(
|
||||
|
@ -84,7 +84,7 @@ export async function readFileWithEolConversion(
|
||||
}
|
||||
|
||||
// Analyse encoding
|
||||
const encoding = await detectEncoding(fileBuffer);
|
||||
const encoding = detectEncoding(fileBuffer);
|
||||
|
||||
// Skip further processing of non-convertible encodings
|
||||
if (!CONVERTIBLE_ENCODINGS.includes(encoding)) {
|
||||
@ -132,10 +132,10 @@ export async function readFileWithEolConversion(
|
||||
* @param fileBuffer File contents whose encoding should be detected
|
||||
* @param bytesRead Optional "file size" if smaller than the buffer size
|
||||
*/
|
||||
export async function detectEncoding(
|
||||
export function detectEncoding(
|
||||
fileBuffer: Buffer,
|
||||
bytesRead = fileBuffer.length,
|
||||
): Promise<string> {
|
||||
): string {
|
||||
// empty file
|
||||
if (bytesRead === 0) {
|
||||
return '';
|
||||
|
@ -281,8 +281,7 @@ export function isWindowsComExeShell() {
|
||||
// neither bash nor sh (e.g. not MSYS, MSYS2, Cygwin, WSL)
|
||||
process.env.SHELL == null &&
|
||||
// Windows cmd.exe or PowerShell
|
||||
process.env.ComSpec != null &&
|
||||
process.env.ComSpec.endsWith('cmd.exe')
|
||||
process.env.ComSpec?.endsWith('cmd.exe')
|
||||
);
|
||||
}
|
||||
|
||||
@ -366,7 +365,7 @@ export function getProxyConfig(): ProxyConfig | undefined {
|
||||
let url: InstanceType<typeof URL>;
|
||||
try {
|
||||
url = new URL(proxyUrl);
|
||||
} catch (_e) {
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
return {
|
||||
@ -469,7 +468,7 @@ export function pickAndRename<T extends Dictionary<any>>(
|
||||
let renameFrom = f;
|
||||
let renameTo = f;
|
||||
const match = f.match(/(?<from>\S+)\s+=>\s+(?<to>\S+)/);
|
||||
if (match && match.groups) {
|
||||
if (match?.groups) {
|
||||
renameFrom = match.groups.from;
|
||||
renameTo = match.groups.to;
|
||||
}
|
||||
|
@ -118,7 +118,7 @@ export const isImageFresh = async (deviceType: string, version: string) => {
|
||||
*/
|
||||
export const isESR = (version: string) => {
|
||||
const match = version.match(/^v?(\d+)\.\d+\.\d+/);
|
||||
const major = parseInt((match && match[1]) || '', 10);
|
||||
const major = parseInt(match?.[1] || '', 10);
|
||||
return major >= 2018; // note: (NaN >= 2018) is false
|
||||
};
|
||||
|
||||
|
@ -39,7 +39,7 @@ export async function disambiguateReleaseParam(
|
||||
|
||||
// Accepting short hashes of 7,8,9 chars.
|
||||
const possibleUuidHashLength = [7, 8, 9, 32, 40, 62].includes(release.length);
|
||||
const hasLeadingZero = release[0] === '0';
|
||||
const hasLeadingZero = release.startsWith('0');
|
||||
const isOnlyNumerical = /^[0-9]+$/.test(release);
|
||||
|
||||
// Reject non-numerical values with invalid uuid/hash lengths
|
||||
@ -78,14 +78,16 @@ export async function disambiguateReleaseParam(
|
||||
/**
|
||||
* Convert to lowercase if looks like slug
|
||||
*/
|
||||
export async function lowercaseIfSlug(s: string) {
|
||||
return s.includes('/') ? s.toLowerCase() : s;
|
||||
export function lowercaseIfSlug(s: string) {
|
||||
return s.includes('/')
|
||||
? Promise.resolve(s.toLowerCase())
|
||||
: Promise.resolve(s);
|
||||
}
|
||||
|
||||
export function normalizeOsVersion(version: string) {
|
||||
// Note that `version` may also be 'latest', 'recommended', 'default'
|
||||
if (/^v?\d+\.\d+\.\d+/.test(version)) {
|
||||
if (version[0] === 'v') {
|
||||
if (version.startsWith('v')) {
|
||||
version = version.slice(1);
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ export function capitanoizeOclifUsage(
|
||||
.toLowerCase();
|
||||
}
|
||||
|
||||
export async function getCommandsFromManifest() {
|
||||
export function getCommandsFromManifest() {
|
||||
const manifest = require('../../oclif.manifest.json');
|
||||
|
||||
if (manifest.commands == null) {
|
||||
|
@ -119,7 +119,7 @@ export const checkLoggedInIf = async (doCheck: boolean) => {
|
||||
*
|
||||
* @throws {NotAvailableInOfflineModeError}
|
||||
*/
|
||||
export const checkNotUsingOfflineMode = async () => {
|
||||
export const checkNotUsingOfflineMode = () => {
|
||||
if (process.env.BALENARC_OFFLINE_MODE) {
|
||||
throw new NotAvailableInOfflineModeError(stripIndent`
|
||||
This command requires an internet connection, and cannot be used in offline mode.
|
||||
|
@ -390,13 +390,12 @@ async function createApplication(
|
||||
try {
|
||||
const userInfo = await sdk.auth.getUserInfo();
|
||||
username = userInfo.username;
|
||||
} catch (err) {
|
||||
} catch {
|
||||
throw new sdk.errors.BalenaNotLoggedIn();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-async-promise-executor
|
||||
const applicationName = await new Promise<string>(async (resolve, reject) => {
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
try {
|
||||
const appName = await getCliForm().ask({
|
||||
@ -418,11 +417,13 @@ async function createApplication(
|
||||
'You already have a fleet with that name; please choose another.',
|
||||
);
|
||||
continue;
|
||||
} catch (err) {
|
||||
return resolve(appName);
|
||||
} catch {
|
||||
resolve(appName);
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
return reject(err);
|
||||
reject(err as Error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -452,9 +453,7 @@ async function generateApplicationConfig(
|
||||
const manifest = await sdk.models.config.getDeviceTypeManifestBySlug(
|
||||
app.is_for__device_type[0].slug,
|
||||
);
|
||||
const opts =
|
||||
manifest.options &&
|
||||
manifest.options.filter((opt) => opt.name !== 'network');
|
||||
const opts = manifest.options?.filter((opt) => opt.name !== 'network');
|
||||
|
||||
const override = {
|
||||
appUpdatePollInterval: options.appUpdatePollInterval,
|
||||
|
@ -114,7 +114,7 @@ async function installQemu(arch: string, qemuPath: string) {
|
||||
stream.resume();
|
||||
}
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
reject(err as Error);
|
||||
}
|
||||
});
|
||||
request(qemuUrl)
|
||||
|
@ -246,7 +246,8 @@ function getBuilderMessageHandler(
|
||||
console.error(`[debug] handling message: ${JSON.stringify(obj)}`);
|
||||
}
|
||||
if (obj.type != null && obj.type === 'metadata') {
|
||||
return handleBuilderMetadata(obj, build);
|
||||
handleBuilderMetadata(obj, build);
|
||||
return;
|
||||
}
|
||||
if (obj.message) {
|
||||
readline.clearLine(process.stdout, 0);
|
||||
@ -423,10 +424,20 @@ async function getRemoteBuildStream(
|
||||
stream = buildRequest.pipe(JSONStream.parse('*')) as NodeJS.ReadStream;
|
||||
}
|
||||
stream = stream
|
||||
.once('error', () => uploadSpinner.stop())
|
||||
.once('close', () => uploadSpinner.stop())
|
||||
.once('data', () => uploadSpinner.stop())
|
||||
.once('end', () => uploadSpinner.stop())
|
||||
.once('finish', () => uploadSpinner.stop());
|
||||
.once('error', () => {
|
||||
uploadSpinner.stop();
|
||||
})
|
||||
.once('close', () => {
|
||||
uploadSpinner.stop();
|
||||
})
|
||||
.once('data', () => {
|
||||
uploadSpinner.stop();
|
||||
})
|
||||
.once('end', () => {
|
||||
uploadSpinner.stop();
|
||||
})
|
||||
.once('finish', () => {
|
||||
uploadSpinner.stop();
|
||||
});
|
||||
return [buildRequest, stream];
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ export function sshArgsForRemoteCommand({
|
||||
...['-o', 'LogLevel=ERROR'],
|
||||
...['-o', 'StrictHostKeyChecking=no'],
|
||||
...['-o', 'UserKnownHostsFile=/dev/null'],
|
||||
...(proxyCommand && proxyCommand.length
|
||||
...(proxyCommand?.length
|
||||
? ['-o', `ProxyCommand=${proxyCommand.join(' ')}`]
|
||||
: []),
|
||||
`${username}@${hostname}`,
|
||||
@ -155,9 +155,9 @@ export async function runRemoteCommand({
|
||||
[exitCode, exitSignal] = await new Promise((resolve, reject) => {
|
||||
const ps = spawn(program, args, { stdio })
|
||||
.on('error', reject)
|
||||
.on('close', (code, signal) =>
|
||||
resolve([code ?? undefined, signal ?? undefined]),
|
||||
);
|
||||
.on('close', (code, signal) => {
|
||||
resolve([code ?? undefined, signal ?? undefined]);
|
||||
});
|
||||
|
||||
if (ps.stdin && stdin && typeof stdin !== 'string') {
|
||||
stdin.pipe(ps.stdin);
|
||||
@ -272,7 +272,7 @@ export async function getLocalDeviceCmdStdout(
|
||||
export const isRootUserGood = _.memoize(async (hostname: string, port) => {
|
||||
try {
|
||||
await runRemoteCommand({ cmd: 'exit 0', hostname, port, ...stdioIgnore });
|
||||
} catch (e) {
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -29,7 +29,11 @@ export function buffer(
|
||||
new Promise(function (resolve, reject) {
|
||||
const fstream = fs.createReadStream(bufferFile);
|
||||
|
||||
fstream.on('open', () => resolve(fstream)).on('error', reject);
|
||||
fstream
|
||||
.on('open', () => {
|
||||
resolve(fstream);
|
||||
})
|
||||
.on('error', reject);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ async function spawnAndPipe(
|
||||
});
|
||||
}
|
||||
|
||||
async function windosuExec(
|
||||
function windosuExec(
|
||||
escapedArgs: string[],
|
||||
stderr?: NodeJS.WritableStream,
|
||||
): Promise<void> {
|
||||
|
@ -42,9 +42,9 @@ export = (stream: NodeJS.WriteStream = process.stdout) => {
|
||||
|
||||
const showCursor = () => stream.write('\u001B[?25h');
|
||||
|
||||
const cursorUp = (rows: number = 0) => stream.write(`\u001B[${rows}A`);
|
||||
const cursorUp = (rows = 0) => stream.write(`\u001B[${rows}A`);
|
||||
|
||||
const cursorDown = (rows: number = 0) => stream.write(`\u001B[${rows}B`);
|
||||
const cursorDown = (rows = 0) => stream.write(`\u001B[${rows}B`);
|
||||
|
||||
const write = (str: string) => stream.write(str);
|
||||
|
||||
|
@ -61,11 +61,11 @@ export const tunnelConnectionToDevice = (
|
||||
client.pipe(remote);
|
||||
remote.pipe(client);
|
||||
remote.on('error', (err) => {
|
||||
console.error('Remote: ' + err);
|
||||
console.error(`Remote: ${err}`);
|
||||
client.end();
|
||||
});
|
||||
client.on('error', (err) => {
|
||||
console.error('Client: ' + err);
|
||||
console.error(`Client: ${err}`);
|
||||
remote.end();
|
||||
});
|
||||
remote.on('close', () => {
|
||||
|
@ -97,24 +97,24 @@ export function parseAsInteger(input: string, paramName?: string) {
|
||||
throw new ExpectedError(message);
|
||||
}
|
||||
|
||||
return Number(input);
|
||||
return Promise.resolve(Number(input));
|
||||
}
|
||||
|
||||
export function tryAsInteger(input: string): number | string {
|
||||
export async function tryAsInteger(input: string): Promise<number | string> {
|
||||
try {
|
||||
return parseAsInteger(input);
|
||||
return await parseAsInteger(input);
|
||||
} catch {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
export async function parseAsLocalHostnameOrIp(input: string) {
|
||||
export function parseAsLocalHostnameOrIp(input: string) {
|
||||
if (input && !validateLocalHostnameOrIp(input)) {
|
||||
throw new ExpectedError(
|
||||
'The parameter must be a local hostname or IP address.',
|
||||
);
|
||||
}
|
||||
return input;
|
||||
return Promise.resolve(input);
|
||||
}
|
||||
|
||||
export function looksLikeFleetSlug(input: string) {
|
||||
|
@ -31,7 +31,7 @@ chai.use(chaiAsPromised);
|
||||
|
||||
const { expect } = chai;
|
||||
|
||||
async function getPage(name: string): Promise<string> {
|
||||
function getPage(name: string): string {
|
||||
const pagePath = path.join(
|
||||
__dirname,
|
||||
'..',
|
||||
@ -88,7 +88,7 @@ describe('Login server:', function () {
|
||||
expect(body).to.equal(opt.expectedBody);
|
||||
resolve();
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
reject(err as Error);
|
||||
}
|
||||
},
|
||||
);
|
||||
@ -143,7 +143,7 @@ describe('Login server:', function () {
|
||||
|
||||
it('should eventually be the token', async () => {
|
||||
await testLogin({
|
||||
expectedBody: await getPage('success'),
|
||||
expectedBody: getPage('success'),
|
||||
expectedStatusCode: 200,
|
||||
expectedToken: tokens.johndoe.token,
|
||||
});
|
||||
@ -162,7 +162,7 @@ describe('Login server:', function () {
|
||||
|
||||
it('should be rejected', async () => {
|
||||
await testLogin({
|
||||
expectedBody: await getPage('error'),
|
||||
expectedBody: getPage('error'),
|
||||
expectedStatusCode: 401,
|
||||
expectedToken: tokens.johndoe.token,
|
||||
expectedErrorMsg: 'Invalid token',
|
||||
@ -171,7 +171,7 @@ describe('Login server:', function () {
|
||||
|
||||
it('should be rejected if no token', async () => {
|
||||
await testLogin({
|
||||
expectedBody: await getPage('error'),
|
||||
expectedBody: getPage('error'),
|
||||
expectedStatusCode: 401,
|
||||
expectedToken: '',
|
||||
expectedErrorMsg: 'No token',
|
||||
@ -180,7 +180,7 @@ describe('Login server:', function () {
|
||||
|
||||
it('should be rejected if token is malformed', async () => {
|
||||
await testLogin({
|
||||
expectedBody: await getPage('error'),
|
||||
expectedBody: getPage('error'),
|
||||
expectedStatusCode: 401,
|
||||
expectedToken: 'asdf',
|
||||
expectedErrorMsg: 'Invalid token',
|
||||
|
@ -267,15 +267,15 @@ describe('balena build', function () {
|
||||
...fsMod,
|
||||
promises: {
|
||||
...fsMod.promises,
|
||||
access: async (p: string) =>
|
||||
access: (p: string) =>
|
||||
p === qemuBinPath ? undefined : fsMod.promises.access(p),
|
||||
stat: async (p: string) =>
|
||||
stat: (p: string) =>
|
||||
p === qemuBinPath ? { size: 1 } : fsMod.promises.stat(p),
|
||||
},
|
||||
});
|
||||
mock(qemuModPath, {
|
||||
...qemuMod,
|
||||
copyQemu: async () => '',
|
||||
copyQemu: () => '',
|
||||
});
|
||||
mock.reRequire('../../build/utils/qemu');
|
||||
docker.expectGetInfo({ OperatingSystem: 'balenaOS 2.44.0+rev1' });
|
||||
|
@ -169,8 +169,12 @@ async function startMockSshServer(): Promise<[Server, number]> {
|
||||
console.error(`[debug] mock ssh server: ${msg}`);
|
||||
}
|
||||
};
|
||||
c.on('error', (err) => handler(err.message));
|
||||
c.on('end', () => handler('client disconnected'));
|
||||
c.on('error', (err) => {
|
||||
handler(err.message);
|
||||
});
|
||||
c.on('end', () => {
|
||||
handler('client disconnected');
|
||||
});
|
||||
c.end();
|
||||
});
|
||||
server.on('error', (err) => {
|
||||
|
@ -462,7 +462,13 @@ describe('balena push', function () {
|
||||
tmp.setGracefulCleanup();
|
||||
const projectPath = await new Promise<string>((resolve, reject) => {
|
||||
const opts = { template: 'tmp-XXXXXX', unsafeCleanup: true };
|
||||
tmp.dir(opts, (e, p) => (e ? reject(e) : resolve(p)));
|
||||
tmp.dir(opts, (e, p) => {
|
||||
if (e) {
|
||||
reject(e);
|
||||
} else {
|
||||
resolve(p);
|
||||
}
|
||||
});
|
||||
});
|
||||
console.error(`[debug] Temp project dir: ${projectPath}`);
|
||||
|
||||
@ -475,7 +481,7 @@ describe('balena push', function () {
|
||||
try {
|
||||
server.listen(socketPath, resolve);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
reject(e as Error);
|
||||
}
|
||||
});
|
||||
console.error(`[debug] Checking existence of socket at '${socketPath}'`);
|
||||
@ -505,7 +511,13 @@ describe('balena push', function () {
|
||||
|
||||
// Terminate Unix Domain Socket server
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
server.close((e) => (e ? reject(e) : resolve()));
|
||||
server.close((e) => {
|
||||
if (e) {
|
||||
reject(e);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
expect(await exists(socketPath), 'Socket existence').to.be.false;
|
||||
|
@ -26,7 +26,7 @@ describe('balena whoami', function () {
|
||||
api = new BalenaAPIMock();
|
||||
});
|
||||
|
||||
this.afterEach(async () => {
|
||||
this.afterEach(() => {
|
||||
// Check all expected api calls have been made and clean up.
|
||||
api.done();
|
||||
});
|
||||
|
@ -26,7 +26,6 @@ import * as tar from 'tar-stream';
|
||||
import { streamToBuffer } from 'tar-utils';
|
||||
import { URL } from 'url';
|
||||
import { diff } from 'deep-object-diff';
|
||||
|
||||
import { makeImageName } from '../build/utils/compose_ts';
|
||||
import { stripIndent } from '../build/utils/lazy';
|
||||
import type { BuilderMock } from './nock/builder-mock';
|
||||
@ -77,13 +76,13 @@ export async function inspectTarStream(
|
||||
type: header.type,
|
||||
};
|
||||
const expected = expectedFiles[header.name];
|
||||
if (expected && expected.testStream) {
|
||||
if (expected?.testStream) {
|
||||
await expected.testStream(header, stream, expected);
|
||||
} else {
|
||||
await defaultTestStream(header, stream, expected, projectPath);
|
||||
}
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
reject(err as Error);
|
||||
}
|
||||
next();
|
||||
},
|
||||
@ -144,9 +143,8 @@ export async function expectStreamNoCRLF(
|
||||
_header: tar.Headers,
|
||||
stream: Readable,
|
||||
): Promise<void> {
|
||||
const chai = await import('chai');
|
||||
const buf = await streamToBuffer(stream);
|
||||
await chai.expect(buf.includes('\r\n')).to.be.false;
|
||||
expect(buf.includes('\r\n')).to.be.false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -184,12 +182,13 @@ export async function testDockerBuildStream(o: {
|
||||
|
||||
o.dockerMock.expectPostBuild({
|
||||
...o,
|
||||
checkURI: async (uri: string) => {
|
||||
checkURI: (uri: string) => {
|
||||
const url = new URL(uri, 'http://test.net/');
|
||||
const queryParams = Array.from(url.searchParams.entries());
|
||||
expect(deepJsonParse(queryParams)).to.have.deep.members(
|
||||
deepJsonParse(expectedQueryParams),
|
||||
);
|
||||
return Promise.resolve();
|
||||
},
|
||||
checkBuildRequestBody: (buildRequestBody: string) =>
|
||||
inspectTarStream(buildRequestBody, expectedFiles, projectPath),
|
||||
@ -241,12 +240,13 @@ export async function testPushBuildStream(o: {
|
||||
|
||||
o.builderMock.expectPostBuild({
|
||||
...o,
|
||||
checkURI: async (uri: string) => {
|
||||
checkURI: (uri: string) => {
|
||||
const url = new URL(uri, 'http://test.net/');
|
||||
const queryParams = Array.from(url.searchParams.entries());
|
||||
expect(deepJsonParse(queryParams)).to.have.deep.members(
|
||||
deepJsonParse(expectedQueryParams),
|
||||
);
|
||||
return Promise.resolve();
|
||||
},
|
||||
checkBuildRequestBody: (buildRequestBody) =>
|
||||
inspectTarStream(buildRequestBody, o.expectedFiles, o.projectPath),
|
||||
|
@ -287,15 +287,14 @@ export function monochrome(text: string): string {
|
||||
*/
|
||||
export function fillTemplate(
|
||||
templateString: string,
|
||||
templateVars: object,
|
||||
templateVars: Record<string, unknown>,
|
||||
): string {
|
||||
const escaped = templateString.replace(/\\/g, '\\\\').replace(/`/g, '\\`');
|
||||
const resolved = new Function(
|
||||
...Object.keys(templateVars),
|
||||
`return \`${escaped}\`;`,
|
||||
).call(null, ...Object.values(templateVars));
|
||||
const unescaped = resolved.replace(/\\`/g, '`').replace(/\\\\/g, '\\');
|
||||
return unescaped;
|
||||
return templateString.replace(/\$\{(\w+)\}/g, (_, key) => {
|
||||
if (key in templateVars) {
|
||||
return String(templateVars[key]);
|
||||
}
|
||||
throw new Error(`Missing template variable: ${key}`);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -283,7 +283,7 @@ export class BalenaAPIMock extends NockMock {
|
||||
this.optGet(/^\/v\d+\/service_environment_variable($|\?)/, opts).reply(
|
||||
function (uri, _requestBody) {
|
||||
const match = uri.match(/service_name%20eq%20%27(.+?)%27/);
|
||||
const serviceName = (match && match[1]) || undefined;
|
||||
const serviceName = match?.[1] || undefined;
|
||||
let varArray: any[];
|
||||
if (serviceName) {
|
||||
const varObj = appServiceVarsByService[serviceName];
|
||||
@ -331,7 +331,7 @@ export class BalenaAPIMock extends NockMock {
|
||||
opts,
|
||||
).reply(function (uri, _requestBody) {
|
||||
const match = uri.match(/service_name%20eq%20%27(.+?)%27/);
|
||||
const serviceName = (match && match[1]) || undefined;
|
||||
const serviceName = match?.[1] || undefined;
|
||||
let varArray: any[];
|
||||
if (serviceName) {
|
||||
const varObj = deviceServiceVarsByService[serviceName];
|
||||
|
@ -37,7 +37,7 @@ export class NockMock {
|
||||
|
||||
constructor(
|
||||
public basePathPattern: string | RegExp,
|
||||
public allowUnmocked: boolean = false,
|
||||
public allowUnmocked = false,
|
||||
) {
|
||||
if (NockMock.instanceCount === 0) {
|
||||
if (!nock.isActive()) {
|
||||
|
@ -50,7 +50,7 @@ export async function exists(fPath: string) {
|
||||
try {
|
||||
await fs.stat(fPath);
|
||||
return true;
|
||||
} catch (e) {
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import * as stream from 'stream';
|
||||
import { AssertionError, expect } from 'chai';
|
||||
import { expect } from 'chai';
|
||||
import { stub } from 'sinon';
|
||||
import * as tmp from 'tmp';
|
||||
import { delay } from '../../utils';
|
||||
@ -62,7 +62,7 @@ describe('image-manager', function () {
|
||||
|
||||
return stream.on('end', function () {
|
||||
expect(result).to.equal('Cache image');
|
||||
return done();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -153,9 +153,7 @@ describe('image-manager', function () {
|
||||
const contents = await fsAsync
|
||||
.stat(this.image.name + '.inprogress')
|
||||
.then(function () {
|
||||
throw new AssertionError(
|
||||
'Image cache should be deleted on failure',
|
||||
);
|
||||
throw new Error('Image cache should be deleted on failure');
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err.code !== 'ENOENT') {
|
||||
@ -174,7 +172,7 @@ describe('image-manager', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('given a stream with the mime property', async function () {
|
||||
describe('given a stream with the mime property', function () {
|
||||
beforeEach(function () {
|
||||
this.osDownloadStub = stub(balena.models.os, 'download');
|
||||
const message = 'Lorem ipsum dolor sit amet';
|
||||
@ -422,7 +420,7 @@ describe('image-manager', function () {
|
||||
.then(function (stream) {
|
||||
let result = '';
|
||||
|
||||
stream.on('data', (chunk) => (result += chunk));
|
||||
stream.on('data', (chunk: string) => (result += chunk));
|
||||
|
||||
stream.on('end', function () {
|
||||
expect(result).to.equal('Lorem ipsum dolor sit amet');
|
||||
@ -554,7 +552,9 @@ describe('image-manager', function () {
|
||||
mockFs({});
|
||||
});
|
||||
|
||||
afterEach(() => mockFs.restore());
|
||||
afterEach(() => {
|
||||
mockFs.restore();
|
||||
});
|
||||
|
||||
it('should keep the cache directory removed', async function () {
|
||||
const exists = await fsExistsAsync(this.cacheDirectory);
|
||||
|
@ -210,31 +210,31 @@ describe('parseAsInteger() function', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should parse integers to number type', () => {
|
||||
expect(v.parseAsInteger('100')).to.equal(100);
|
||||
expect(v.parseAsInteger('100')).to.be.a('number');
|
||||
expect(v.parseAsInteger('0')).to.equal(0);
|
||||
expect(v.parseAsInteger('0')).to.be.a('number');
|
||||
it('should parse integers to number type', async () => {
|
||||
expect(await v.parseAsInteger('100')).to.equal(100);
|
||||
expect(await v.parseAsInteger('100')).to.be.a('number');
|
||||
expect(await v.parseAsInteger('0')).to.equal(0);
|
||||
expect(await v.parseAsInteger('0')).to.be.a('number');
|
||||
});
|
||||
});
|
||||
|
||||
describe('tryAsInteger() function', () => {
|
||||
it('should return string with non-numeric characters as string', () => {
|
||||
expect(v.tryAsInteger('abc')).to.be.a('string');
|
||||
expect(v.tryAsInteger('1a')).to.be.a('string');
|
||||
expect(v.tryAsInteger('a1')).to.be.a('string');
|
||||
expect(v.tryAsInteger('a')).to.be.a('string');
|
||||
expect(v.tryAsInteger('1.0')).to.be.a('string');
|
||||
it('should return string with non-numeric characters as string', async () => {
|
||||
expect(await v.tryAsInteger('abc')).to.be.a('string');
|
||||
expect(await v.tryAsInteger('1a')).to.be.a('string');
|
||||
expect(await v.tryAsInteger('a1')).to.be.a('string');
|
||||
expect(await v.tryAsInteger('a')).to.be.a('string');
|
||||
expect(await v.tryAsInteger('1.0')).to.be.a('string');
|
||||
});
|
||||
|
||||
it('should return numerical strings with leading zeros as string', () => {
|
||||
expect(v.tryAsInteger('01')).to.be.a('string');
|
||||
expect(v.tryAsInteger('001')).to.be.a('string');
|
||||
it('should return numerical strings with leading zeros as string', async () => {
|
||||
expect(await v.tryAsInteger('01')).to.be.a('string');
|
||||
expect(await v.tryAsInteger('001')).to.be.a('string');
|
||||
});
|
||||
|
||||
it('should return numerical strings without leading zeros as number', () => {
|
||||
expect(v.tryAsInteger('100')).to.be.a('number');
|
||||
expect(v.tryAsInteger('256')).to.be.a('number');
|
||||
expect(v.tryAsInteger('0')).to.be.a('number');
|
||||
it('should return numerical strings without leading zeros as number', async () => {
|
||||
expect(await v.tryAsInteger('100')).to.be.a('number');
|
||||
expect(await v.tryAsInteger('256')).to.be.a('number');
|
||||
expect(await v.tryAsInteger('0')).to.be.a('number');
|
||||
});
|
||||
});
|
||||
|
@ -9,6 +9,7 @@
|
||||
"./src/**/*",
|
||||
"./patches/*",
|
||||
"./tests/**/*",
|
||||
"./typings/**/*"
|
||||
"./typings/**/*",
|
||||
".mocharc-standalone.js",
|
||||
]
|
||||
}
|
||||
|
2
typings/JSONStream/index.d.ts
vendored
2
typings/JSONStream/index.d.ts
vendored
@ -32,7 +32,7 @@ declare module 'JSONStream' {
|
||||
recurse: boolean;
|
||||
}
|
||||
|
||||
export function parse(pattern: any | any[]): NodeJS.ReadWriteStream;
|
||||
export function parse(pattern: any): NodeJS.ReadWriteStream;
|
||||
|
||||
type NewlineOnlyIndicator = false;
|
||||
|
||||
|
10
typings/balena-device-init/index.d.ts
vendored
10
typings/balena-device-init/index.d.ts
vendored
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
declare module 'balena-device-init' {
|
||||
import { DeviceTypeJson } from 'balena-sdk';
|
||||
import type { DeviceTypeJson } from 'balena-sdk';
|
||||
|
||||
interface OperationState {
|
||||
operation:
|
||||
@ -83,23 +83,23 @@ declare module 'balena-device-init' {
|
||||
|
||||
export function configure(
|
||||
image: string,
|
||||
manifest: BalenaSdk.DeviceTypeJson.DeviceType.DeviceType,
|
||||
manifest: DeviceTypeJson.DeviceType,
|
||||
config: object,
|
||||
options?: object,
|
||||
): Promise<InitializeEmitter>;
|
||||
|
||||
export function initialize(
|
||||
image: string,
|
||||
manifest: BalenaSdk.DeviceTypeJson.DeviceType.DeviceType,
|
||||
manifest: DeviceTypeJson.DeviceType,
|
||||
config: object,
|
||||
): Promise<InitializeEmitter>;
|
||||
|
||||
export function getImageOsVersion(
|
||||
image: string,
|
||||
manifest: BalenaSdk.DeviceTypeJson.DeviceType.DeviceType,
|
||||
manifest: DeviceTypeJson.DeviceType,
|
||||
): Promise<string | null>;
|
||||
|
||||
export function getImageManifest(
|
||||
image: string,
|
||||
): Promise<BalenaSdk.DeviceTypeJson.DeviceType.DeviceType | null>;
|
||||
): Promise<DeviceTypeJson.DeviceType | null>;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user