Documentation update with debugging notes

Signed-off-by: Paul Jonathan <pj@balena.io>
This commit is contained in:
toochevere 2021-08-25 17:11:15 +00:00
parent 972c2470c5
commit 9937b91606
2 changed files with 34 additions and 10 deletions

View File

@ -259,3 +259,12 @@ gotchas to bear in mind:
`node_modules/balena-sdk/node_modules/balena-errors`
In the case of subclasses of `TypedError`, a string comparison may be used instead:
`error.name === 'BalenaApplicationNotFound'`
## Further debugging notes
* If you need to selectively run specific tests, `it.only` will not work in cases when authorization is required as part of the test cycle. In order to target specific tests, control execution via `.mocharc.js` instead. Here is an example of targeting the `deploy` tests.
replace: `spec: 'tests/**/*.spec.ts',`
with: `spec: ['tests/auth/*.spec.ts', 'tests/**/deploy.spec.ts'],`

View File

@ -45,6 +45,8 @@ import Logger = require('./logger');
import { exists } from './which';
import jsyaml = require('js-yaml');
const allowedContractTypes = ['sw.application', 'sw.block'];
/**
* Given an array representing the raw `--release-tag` flag of the deploy and
* push commands, parse it into separate arrays of release tag keys and values.
@ -1312,11 +1314,17 @@ export async function deployProject(
const prefix = getChalk().cyan('[Info]') + ' ';
const spinner = createSpinner();
const contract = await getContractContent(`${projectPath}/balena.yml`);
const contract = await getContractContent(
path.join(projectPath, 'balena.yml'),
);
if (contract?.version && !PLAIN_SEMVER_REGEX.test(contract?.version)) {
throw new ExpectedError(
stripIndent`Error: expected the version field in ${projectPath}/balena.yml to be a valid semver (e.g.: 1.0.0). Got '${contract.version}' instead`,
stripIndent`Error: expected the version field in ${path.join(
projectPath,
'balena.yml',
)} to be a basic semver in the format '1.2.3'. Got '${
contract.version
}' instead`,
);
}
@ -1423,26 +1431,29 @@ export function createRunLoop(tick: (...args: any[]) => void) {
return runloop;
}
async function getContractContent(filePath: string): Promise<any | undefined> {
async function getContractContent(
filePath: string,
): Promise<Dictionary<any> | undefined> {
let fileContentAsString;
try {
fileContentAsString = await fs.readFile(filePath, 'utf8');
} catch {
// File does not exist. Return undefined
return;
} catch (e) {
if (e.code === 'ENOENT') {
return; // File does not exist
}
throw e;
}
let asJson;
try {
asJson = jsyaml.load(fileContentAsString) as any;
asJson = jsyaml.load(fileContentAsString);
} catch (err) {
throw new ExpectedError(
`Error parsing file "${filePath}":\n ${err.message}`,
);
}
const allowedContractTypes = ['sw.application', 'sw.block'];
if (!asJson?.type || !allowedContractTypes.includes(asJson.type)) {
if (!isContract(asJson)) {
throw new ExpectedError(
stripIndent`Error: application contract in '${filePath}' needs to
define a top level "type" field with an allowed application type.
@ -1452,6 +1463,10 @@ async function getContractContent(filePath: string): Promise<any | undefined> {
return asJson;
}
function isContract(obj: any): obj is Dictionary<any> {
return obj?.type && allowedContractTypes.includes(obj.type);
}
function createLogStream(input: Readable) {
const split = require('split') as typeof import('split');
const stripAnsi = require('strip-ansi-stream');