Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,17 @@ async function oclifRun(command: string[], options: AppOptions) {

const { trackPromise } = await import('./hooks/prerun');

await Promise.all([trackPromise, deprecationPromise, runPromise]);
// Help command and others may not trigger the prerun hook, so we need
// to handle the case where trackPromise never resolves. We use Promise.race

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would argue that trackResolve should always settle to something, and how we have it atm isn't really great. It seems that we really care about is whether we need to still wait for tracking events to be sent, and not whether an event was really sent or not w/ the current command. This way it seems that trackResolve should be in a finally block in the hooks, so that it's always called even if the currently issued command didn't call the tracking code at all.

// to complete when runPromise finishes, even if trackPromise hasn't resolved.
await Promise.race([
Promise.all([trackPromise, deprecationPromise, runPromise]),
runPromise.then(async () => {
if (deprecationPromise) {
await deprecationPromise;
}
}),
]);
Comment on lines +154 to +161

@thgreasi thgreasi Oct 20, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks equivalent to this v

Suggested change
await Promise.race([
Promise.all([trackPromise, deprecationPromise, runPromise]),
runPromise.then(async () => {
if (deprecationPromise) {
await deprecationPromise;
}
}),
]);
void trackPromise;
await runPromise;
if (deprecationPromise) {
await deprecationPromise;
}

and the void trackPromise; shouldn't even be necessary, since should be a side-effect of await import('./hooks/prerun'); anyway. ie we probably don't need to import any specific export of ./hooks/prerun.

}

/** CLI entrypoint. Called by the `bin/run.js` and `bin/dev.js` scripts. */
Expand Down
240 changes: 167 additions & 73 deletions tests/commands/help.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

import { expect } from 'chai';

import { BalenaAPIMock } from '../nock/balena-api-mock';
import { cleanOutput, runCommand } from '../helpers';
import * as messages from '../../build/utils/messages';

Expand All @@ -26,69 +25,154 @@ USAGE
$ balena [COMMAND] [OPTIONS]

PRIMARY COMMANDS
login login to balena
push start a remote build on the balenaCloud build servers or a local mode device
app display information about a single application
device show info about a single device
preload preload an app on a disk image (or Edison zip archive)
build build a project locally
deploy deploy a single image or a multicontainer project to a balena application
join move a local device to an application on another balena server
leave remove a local device from its balena application
login login to balena
push build release images on balenaCloud servers or on a local mode device
fleet display information about a single fleet
device show info about a single device
preload preload a release on a disk image (or Edison zip archive)
build build a project locally
deploy deploy a single image or a multicontainer project to a balena fleet
join move a local device to a fleet on another balena server
leave remove a local device from its balena fleet

`;

const SIMPLE_HELP_VERBOSE = `
USAGE
$ balena [COMMAND] [OPTIONS]

PRIMARY COMMANDS
login login to balena
push build release images on balenaCloud servers or on a
local mode device
fleet display information about a single fleet
device show info about a single device
preload preload a release on a disk image (or Edison zip
archive)
build build a project locally
deploy deploy a single image or a multicontainer project to a
balena fleet

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't sound right

join move a local device to a fleet on another balena
server
leave remove a local device from its balena fleet

`;

const ADDITIONAL_HELP = `
ADDITIONAL COMMANDS
api-key generate generate a new balenaCloud API key
app create create an application
app restart restart an application
app rm remove an application
config generate generate a config.json file
config inject inject a configuration file into a device or OS image
config read read the configuration of a device or OS image
config reconfigure interactively reconfigure a device or OS image
config write write a key-value pair to configuration of a device or OS image
device detect scan for balenaOS devices on your local network
device identify identify a device
device init initialise a device with balenaOS
device list list all devices
device logs show device logs
device move move one or more devices to another application
device os-update start a Host OS update for a device
device public-url get or manage the public URL for a device
device reboot restart a device
device register register a device
device rename rename a device
device rm remove one or more devices
device shutdown shutdown a device
device ssh SSH into the host or application container of a device
device tunnel tunnel local ports to your balenaOS device
device-type list list the device types supported by balena (like 'raspberrypi3' or 'intel-nuc').
env set add or update env or config variable to application(s), device(s) or service(s)
env list list the environment or config variables of an application, device or service
env rename change the value of a config or env var for an app, device or service
env rm remove a config or env var from an application, device or service
ssh-key display an SSH key
ssh-key add add an SSH key to balenaCloud
ssh-key list list the SSH keys in balenaCloud
ssh-key rm remove an SSH key from balenaCloud
local configure (Re)configure a balenaOS drive or image
local flash flash an image to a drive
logout logout from balena
note set a device note
os build-config build an OS config and save it to a JSON file
os configure configure a previously downloaded balenaOS image
os download download an unconfigured OS image
os initialize initialize an os image for a device
os versions show available balenaOS versions for the given device type
settings print current settings
tag list list all tags for a app, block, fleet, device or release
tag rm remove a tag from an app, block, fleet, device or release
tag set set a tag on an app, block, fleet, device or release
util available-drives list available drives
version display version information for the balena CLI and/or Node.js
whoami display account information for current user
api-key generate generate a new balenaCloud API key

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you had to manually copy paste this all here? That does not sound very maintainable, and would require a change to this file following many PRs. It may be nice if we can just have npm run build send help output to a txt file in the tests folder and we use that for the tests

api-key list print a list of balenaCloud API keys
api-keys print a list of balenaCloud API keys
api-key revoke revoke balenaCloud API keys
app create create an app
block create create an block
config generate generate a config.json file
config inject inject a config.json file to a balenaOS image or
attached media
config read read the config.json file of a balenaOS image or
attached media
config reconfigure interactively reconfigure a balenaOS image file or
attached media
config write write a key-value pair to the config.json file of an
OS image or attached media
device-type list list the device types supported by balena (like
'raspberrypi3' or 'intel-nuc')
devices supported list the device types supported by balena (like
'raspberrypi3' or 'intel-nuc')
device deactivate deactivate a device
device detect scan for balenaOS devices on your local network
scan scan for balenaOS devices on your local network
device identify identify a device
device init initialize a device with balenaOS
device list list all devices
devices list all devices
device local-mode get or manage the local mode status for a device
device logs show device logs
logs show device logs
device move move one or more devices to another fleet
device note set a device note
notes set a device note
device os-update start a Host OS update for a device
device pin pin a device to a release
device public-url get or manage the public URL for a device
device purge purge data from a device
device reboot restart a device
device register register a new device
device rename rename a device
device restart restart containers on a device
device rm remove one or more devices
device shutdown shutdown a device
device ssh open a SSH prompt on a device's host OS or service
container
ssh open a SSH prompt on a device's host OS or service
container
device start-service start containers on a device
device stop-service stop containers on a device
device track-fleet make a device track the fleet's pinned release
device tunnel tunnel local ports to your balenaOS device
tunnel tunnel local ports to your balenaOS device
env list list the environment or config variables of a fleet,
device or service
envs list the environment or config variables of a fleet,
device or service
env rename change the value of a config or env var for a fleet,
device or service
env rm remove a config or env var from a fleet, device or
service
env set add or update env or config variable to fleets,
devices or services
env add add or update env or config variable to fleets,
devices or services
fleet create create a fleet
fleet list list all fleets
fleets list all fleets
fleet pin pin a fleet to a release
fleet purge purge data from a fleet
fleet rename rename a fleet
fleet restart restart a fleet
fleet rm remove a fleet
fleet track-latest make this fleet track the latest release
local configure (Re)configure a balenaOS drive or image
local flash flash an image to a drive
logout logout from balena
organization list list all organizations
orgs list all organizations
os build-config prepare a configuration file for use by the 'os
configure' command
os configure configure a previously downloaded balenaOS image
os download download an unconfigured OS image
os initialize initialize an os image for a device
os versions show available balenaOS versions for the given device
type
release get info for a release
release-asset delete delete a release asset
release-asset download download a release asset
release-asset list list all release assets
release-asset upload upload a release asset
release finalize finalize a release
release invalidate invalidate a release
release list list all releases of a fleet
releases list all releases of a fleet
release validate validate a release
settings print current settings
ssh-key display an SSH key
key display an SSH key
ssh-key add add an SSH key to balenaCloud
key add add an SSH key to balenaCloud
ssh-key list list the SSH keys in balenaCloud
keys list the SSH keys in balenaCloud
key list list the SSH keys in balenaCloud
ssh-key rm remove an SSH key from balenaCloud
key rm remove an SSH key from balenaCloud
support grant or revoke support access for devices or fleets
tag list list all tags for a fleet, device or release
tags list all tags for a fleet, device or release
tag rm remove a tag from a fleet, device or release
tag set set a tag on a fleet, device or release
util available-drives list available drives
version display version information for the balena CLI and/or
Node.js
whoami display account information for current user

`;

Expand All @@ -98,25 +182,35 @@ const LIST_ADDITIONAL = `

const GLOBAL_OPTIONS = `
GLOBAL OPTIONS
--help
--debug
--help display command help
--debug enable debug output
--unsupported prevent exit with an error as per Deprecation Policy
See: https://git.io/JRHUW#deprecation-policy

Deprecation Policy Reminder
The balena CLI enforces its deprecation policy by exiting with an error a year
after the release of the next major version, unless the --unsupported option is
used. Find out more at: https://git.io/JRHUW#deprecation-policy

`;

const ONLINE_RESOURCES = messages.reachingOut;
const GLOBAL_OPTIONS_VERBOSE = `
GLOBAL OPTIONS
--help display command help
--debug enable debug output
--unsupported prevent exit with an error as per Deprecation Policy
See: https://git.io/JRHUW#deprecation-policy

describe.skip('balena help', function () {
let api: BalenaAPIMock;
Deprecation Policy Reminder
The balena CLI enforces its deprecation policy by exiting with an error a year
after the release of the next major version, unless the --unsupported option is
used. Find out more at: https://git.io/JRHUW#deprecation-policy

this.beforeEach(() => {
api = new BalenaAPIMock();
});
`;

this.afterEach(() => {
// Check all expected api calls have been made and clean up.
api.done();
});
const ONLINE_RESOURCES = messages.reachingOut;

describe('balena help', function () {
it('should list primary command summaries', async () => {
const { out, err } = await runCommand('help');

Expand All @@ -137,9 +231,9 @@ describe.skip('balena help', function () {

expect(cleanOutput(out)).to.deep.equal(
cleanOutput([
SIMPLE_HELP,
SIMPLE_HELP_VERBOSE,
ADDITIONAL_HELP,
GLOBAL_OPTIONS,
GLOBAL_OPTIONS_VERBOSE,
ONLINE_RESOURCES,
]),
);
Expand Down
Loading