Compare commits

...

1839 Commits

Author SHA1 Message Date
b616fbdd79 v21.1.5 2025-04-03 13:28:12 +00:00
81edfbbae1 Merge pull request #2930 from balena-io/bump_dockerode_cachefrom
Update dockerode/docker-modem dependencies for cachefrom fix
2025-04-03 09:27:11 -04:00
663e83c3b8 Dedupe dependencies 2025-04-02 18:50:31 -04:00
b650f8ff6d Update dockerode/docker-modem dependencies for fixes
Change-type: patch
Signed-off-by: Ken Bannister <kb2ma@runbox.com>
2025-04-02 18:47:43 -04:00
58234f17e1 v21.1.4 2025-04-02 09:16:30 +00:00
77905f4a74 Merge pull request #2928 from balena-io/comment_sig_file
Add comment with example of signature file in a flasher image
2025-04-02 09:15:23 +00:00
30076fabe6 Dedupe dependencies 2025-04-01 18:25:20 -04:00
28703bb5ae Add comment with secure boot signature file example for preload
Change-type: patch
Signed-off-by: Ken Bannister <kb2ma@runbox.com>
2025-04-01 18:25:16 -04:00
37b3c6abe9 v21.1.3 2025-03-28 16:57:03 +00:00
b4e473e4d4 Merge pull request #2927 from balena-io/fix-ob-device-detail
Fix device detail for open balena
2025-03-28 16:55:56 +00:00
0d4e411777 Fix device detail for open balena
Change-type: patch
2025-03-28 13:29:52 -03:00
7e6f2189e8 v21.1.2 2025-03-27 12:20:26 +00:00
3903daf8a8 Merge pull request #2914 from balena-io/deny-preload-sb
Deny preload for an image with secure boot enabled
2025-03-27 08:19:14 -04:00
18bc0d61e7 Dedupe dependencies 2025-03-26 22:55:54 -04:00
7f2daeebb0 Deny preload for an image with secure boot enabled
Change-type: patch
Signed-off-by: Ken Bannister <kb2ma@runbox.com>
2025-03-26 22:40:43 -04:00
813e9cb82e v21.1.1 2025-03-26 20:34:47 +00:00
3bcb3c1b2e Merge pull request #2925 from balena-io/add-overall-status
Add overall status
2025-03-26 20:33:52 +00:00
20d76556c2 Add explicit read properties for device command
Change-tye: minor
2025-03-26 17:12:45 -03:00
e829068725 Bump balena-sdk to 21.3.0
Update balena-sdk from 21.2.1 to 21.3.0

Change-type: patch
2025-03-26 17:07:20 -03:00
650e896f70 v21.1.0 2025-03-12 19:34:20 +00:00
a9042124ea Merge pull request #2922 from balena-io/compose-requirement-labels
Add support for requirement labels feature
2025-03-12 19:33:23 +00:00
d24d78dac7 Fix package release action for macOS
Depending on the signing password value, the script may interpret the
contents of the password and cause the signing process to fail.

This puts quotes around the password on assignment to prevent this.
2025-03-12 15:30:49 -03:00
42c50ef8ae Add support for new requirement labels feature
Updates @balena/compose to v7 to include this new feature.

See: https://balena.fibery.io/Work/Project/Refactoring-container-contracts-1205
Depends-on: https://github.com/balena-io-modules/balena-compose/pull/64
Change-type: minor
2025-03-12 15:30:21 -03:00
ba4b9bd447 v21.0.0 2025-03-11 14:42:31 +00:00
02c0ea5b59 Merge pull request #2921 from balena-io/major-21-second-attempt
Major 21
2025-03-11 10:41:28 -04:00
bc3558dd8e Address SDK major v21 breaking changes 2025-03-11 08:19:10 -04:00
aad62d1ccd Drop support for OS versions <2.14.0
Change-type: major
2025-03-11 08:19:10 -04:00
ecc6f80164 api-key generate: Add required argument expiryDate
Change-type: major
2025-03-11 08:19:10 -04:00
c0fd1e3886 Deduplicate dependencies 2025-03-11 08:18:56 -04:00
9d3120b144 Update balena-preload to 18.0.1
Change-type: patch
2025-03-11 08:17:27 -04:00
ed0e03ddb2 Add dependency date-fns
Change-type: patch
2025-03-11 08:16:50 -04:00
8fe6d6c026 Update balena-sdk to 21.2.1
Change-type: patch
2025-03-11 08:16:31 -04:00
727033ae14 v20.2.10 2025-03-10 17:33:13 +00:00
c19ce6a905 Merge pull request #2923 from balena-io/bump-typescript-to-5.8.2
Bump typescript to 5.8.2
2025-03-10 17:32:13 +00:00
1a33029738 Deduplicate dependencies 2025-03-10 17:51:18 +02:00
043bc48a1c Add a "deduplicate-dependencies" npm script to standardize such commits 2025-03-04 08:48:31 +02:00
a10156a441 Update TypeScript to 5.8.2
Change-type: patch
2025-03-04 08:48:31 +02:00
4f665f43d2 v20.2.9 2025-02-26 12:52:10 +00:00
9f097a96f5 Merge pull request #2920 from balena-io/x-balena-client-fix
Fix CORS issue with X-Balena-Client header
2025-02-26 12:51:20 +00:00
64d1943804 Fix CORS issue with X-Balena-Client header
Change-type: patch
See: https://balena.fibery.io/Work/Project/Extend-the-X-Balena-Client-header-to-include-the-UI-CLI-version-as-well-1174
2025-02-26 14:24:57 +02:00
666ce876e6 v20.2.8 2025-02-26 00:22:16 +00:00
e01184080f Merge pull request #2915 from balena-io/fix_os_configure_test
Update balena-config-json dependency and fix test
2025-02-25 19:21:25 -05:00
93039b010d Update balena-config-json dependency and fix test
Change-type: patch
Signed-off-by: Ken Bannister <kb2ma@runbox.com>
2025-02-25 18:43:12 -05:00
795259bf30 v20.2.7 2025-02-25 20:21:03 +00:00
fa134d2d39 Merge pull request #2917 from balena-io/x-balena-client
Use the CLI version in the X-Balena-Client header
2025-02-25 20:20:10 +00:00
bef5221ed8 Use the CLI version in the X-Balena-Client header
Change-type: patch
See: https://balena.fibery.io/Work/Project/Extend-the-X-Balena-Client-header-to-include-the-UI-CLI-version-as-well-1174
2025-02-25 21:59:35 +02:00
72d6db796c v20.2.6 2025-02-25 19:13:51 +00:00
e848eb63ee Merge pull request #2918 from balena-io/renovate/actions-upload-artifact-digest
Update actions/upload-artifact digest to 4cec3d8
2025-02-25 19:12:56 +00:00
6f0f7350cf Update actions/upload-artifact digest to 4cec3d8
Update actions/upload-artifact

Change-type: patch
2025-02-25 18:51:27 +00:00
07a88c700e v20.2.5 2025-02-25 18:10:50 +00:00
9cae66bd92 Merge pull request #2913 from balena-io/renovate/actions-setup-node-digest
Update actions/setup-node digest to 1d0ff46
2025-02-25 18:09:54 +00:00
cddea24cef Update actions/setup-node digest to 1d0ff46
Update actions/setup-node

Change-type: patch
2025-02-25 17:45:52 +00:00
b1c246c0b4 v20.2.4 2025-02-25 17:17:03 +00:00
00b4d57a03 Merge pull request #2916 from balena-io/pin_docker-modem_regression
Pin docker-modem and dockerode to avoid regression in docker-modem v5.0.6
2025-02-25 12:16:10 -05:00
2cba82e914 Pin docker-modem and dockerode to avoid regression
Change-type: patch
Signed-off-by: Ken Bannister <kb2ma@runbox.com>
2025-02-24 20:22:59 -05:00
1352c5c823 v20.2.3 2025-01-15 18:21:09 +00:00
c86eb97010 Merge pull request #2910 from balena-io/clean-eslint
Remove unused old eslint version files
2025-01-15 18:19:22 +00:00
53be743b9d Remove unused old eslint version files
Change-type: patch
2025-01-15 08:37:35 -03:00
d9f21b4c3f v20.2.2 2025-01-12 14:49:07 +00:00
261ab398dd Merge pull request #2906 from balena-io/bump-balena-image-fs
Use the promises namespace of balena-image-fs
2025-01-12 16:48:08 +02:00
f28a9992e4 Deduplicate dependencies 2025-01-09 23:33:54 +02:00
29e7827eb1 Use the promises namespace of balena-image-fs
Change-type: patch
2025-01-09 23:33:54 +02:00
1d77cf3665 Update balena-device-init to 8.1.3 & balena-image-fs to 7.3.0
Update balena-device-init from 8.1.0 to 8.1.3
Update balena-image-fs from 7.0.6 to 7.3.0

Change-type: patch
2025-01-09 23:33:54 +02:00
017c767f61 v20.2.1 2025-01-01 18:05:02 +00:00
7d79c4e24b Merge pull request #2905 from balena-io/update-balena-preload-17.0.0
Update balena-preload to 17.0.0
2025-01-01 20:04:01 +02:00
60bc5092e0 Update balena-preload to 17.0.0
Update balena-preload from 16.0.0 to 17.0.0

Change-type: patch
2024-12-31 20:42:54 +02:00
a33a794931 v20.2.0 2024-12-31 18:41:50 +00:00
f0ede6fca2 Merge pull request #2901 from balena-io/balena-device-init-v-8-1-0
os configure: Locate the boot partition w/o using the device-type.json's partition field
2024-12-31 10:40:54 -08:00
dbe177e766 os configure: Give precedence to the boot partition located in the image over the device-type.json contents
Update balena-device-init from 8.0.0 to 8.1.0

Change-type: minor
2024-12-31 19:48:11 +02:00
09f80730a8 Deduplicate dependencies 2024-12-31 19:47:11 +02:00
327d28c103 v20.1.6 2024-12-30 17:16:14 +00:00
56ab785a82 Merge pull request #2903 from balena-io/os-configure-tests
Add more realistic os configure tests
2024-12-30 17:15:09 +00:00
305d65d5ed Add more realistic os configure tests
Change-type: patch
2024-12-30 18:44:07 +02:00
c4d3686a34 Deduplicate dependencies 2024-12-30 15:57:12 +02:00
ce06854b55 v20.1.5 2024-12-20 17:55:24 +00:00
8db05cc8a7 Merge pull request #2902 from oskarwilliams/express-version-4.21.2
Update shrinkwrapped express to v4.21.2
2024-12-20 17:54:36 +00:00
7a22c987d2 Update shrinkwrapped express to v4.21.2
Change-type: patch
2024-12-20 17:23:28 +00:00
45efbcdfe3 v20.1.4 2024-12-20 16:57:38 +00:00
d6a9b78b3e Merge pull request #2899 from balena-io/balena-device-init-v8
Update balena-device-init to 8.0.0
2024-12-20 16:56:43 +00:00
e8ac3ea960 Update balena-device-init to 8.0.0
Update balena-device-init from 7.0.1 to 8.0.0

Change-type: patch
See: https://github.com/balena-io-modules/balena-device-init/pull/46
2024-12-20 18:36:50 +02:00
0ffa0f85a2 v20.1.3 2024-12-20 14:33:05 +00:00
5e7479f60e Merge pull request #2898 from balena-io/bump-oclif-and-oclif-core
Update oclif to 4.17.0 and @oclif/core 4.1.0
2024-12-20 11:32:01 -03:00
07365c45f2 Update oclif to 4.17.0 and @oclif/core 4.1.0
Change-type: patch
2024-12-20 11:09:29 -03:00
e5076434c6 v20.1.2 2024-12-17 11:35:00 +00:00
5d687f5a55 Merge pull request #2896 from balena-io/unnecessary-promise-resolve-reject
Remove unnecessary `Promise.resolve` and `Promise.reject`
2024-12-17 11:34:05 +00:00
e192767156 Remove unnecessary Promise.resolve and Promise.reject
Change-type: patch
2024-12-16 21:12:02 +00:00
5a8d2fad5f v20.1.1 2024-12-16 17:36:44 +00:00
45f482fad1 Merge pull request #2895 from balena-io/bump-balena-lint-v9
Update @balena/lint to v9.1.3
2024-12-16 17:35:45 +00:00
c0e7ae9c91 Update @balena/lint to v9.1.3
Update @balena/lint from 8.0.0 to 9.1.3

Change-type: patch
2024-12-16 14:09:47 -03:00
36077cacda v20.1.0 2024-12-12 14:17:22 +00:00
82b9983450 Merge pull request #2890 from balena-io/takeover
`device os-update`: Add support for updates that require takeover
2024-12-12 09:16:14 -05:00
703dbd01c9 device os-update: Add handling for updates that require takeover
Change-type: minor
2024-12-11 12:04:53 -05:00
602e63c8a9 Fix typings in release and release list commands 2024-12-11 12:00:08 -05:00
2ab635f49a Update expected warnings 2024-12-11 12:00:08 -05:00
322736a145 Deduplicate dependencies 2024-12-11 12:00:08 -05:00
c347b67b25 Update balena-sdk
Change-type: patch
2024-12-11 12:00:08 -05:00
4022beeb56 Update @balena/compose
Change-type: patch
2024-12-11 12:00:08 -05:00
ccf97cfc9f v20.0.9 2024-12-05 12:08:28 +00:00
9c5fe14f2e Merge pull request #2889 from oskarwilliams/express-version-4.21.1
Update shrinkwrapped express to v4.21.1
2024-12-05 12:07:23 +00:00
38e29251e7 Update shrinkwrapped express to v4.21.1
Change-type: patch
2024-12-05 09:59:57 +00:00
bfc7a14646 v20.0.8 2024-12-04 19:37:38 +00:00
610db81fcb Merge pull request #2893 from balena-io/bump-macos-13
Run test and publish with macos-13
2024-12-04 16:36:42 -03:00
d1f7d6d07f Run test and publish with macos-13
Change-type: patch
2024-12-04 16:16:52 -03:00
694eb78aaa v20.0.7 2024-11-23 17:38:10 +00:00
1caccafbcd Merge pull request #2891 from balena-io/bump-typescript-to-5.7.2
Bump typescript to 5.7.2
2024-11-23 17:37:10 +00:00
61d4d1f1e7 Update TypeScript to 5.7.2
Change-type: patch
2024-11-23 00:40:43 +02:00
a01c85bc15 Deduplicate dependencies 2024-11-23 00:40:28 +02:00
5d7b7cfc6f v20.0.6 2024-11-08 08:10:12 +00:00
92fd9e0883 Merge pull request #2887 from balena-io/refactor-build
Refactor balena build for clarity
2024-11-08 08:09:19 +00:00
24273b5ac0 Deduplicate dependencies 2024-11-07 17:33:14 +02:00
6155509f4c Refactor balena build for clarity
Change-type: patch
2024-11-07 16:24:10 +02:00
735af9f6a9 v20.0.5 2024-11-05 10:12:26 +00:00
d7c60e6dea Merge pull request #2884 from balena-io/renovate/actions-upload-artifact-digest
Update actions/upload-artifact digest to b4b15b8
2024-11-05 10:11:38 +00:00
bcb42c8a21 Update actions/upload-artifact digest to b4b15b8
Update actions/upload-artifact

Change-type: patch
2024-11-05 09:50:56 +00:00
04f5e0fa2b v20.0.4 2024-11-05 09:13:22 +00:00
8cb5804848 Merge pull request #2883 from balena-io/renovate/actions-setup-node-digest
Update actions/setup-node digest to 39370e3
2024-11-05 09:12:31 +00:00
91c3fced49 Update actions/setup-node digest to 39370e3
Update actions/setup-node

Change-type: patch
2024-11-05 08:52:19 +00:00
99a94eafbb v20.0.3 2024-11-05 08:12:01 +00:00
b4cff78588 Merge pull request #2885 from balena-io/non-sudo-api-keys
api-key generate: Display a descriptive error when the generation fails due to a stale JWT
2024-11-05 08:11:04 +00:00
8577bb6281 Deduplicate dependencies 2024-11-04 20:51:28 +02:00
e0f081623b api-key generate: Display a descriptive error when the generation fails due to a stale JWT
Change-type: patch
2024-11-04 20:51:27 +02:00
2887ab8200 v20.0.2 2024-10-29 12:57:11 +00:00
aaf4625abb Merge pull request #2881 from balena-io/fix-ssh-key-add-piping
Restore ability to cat key into `ssh-key add`
2024-10-29 12:56:13 +00:00
6f30dc0550 Restore ability to cat key into ssh-key add
Change-type: patch
2024-10-29 07:48:42 -04:00
6565ef4392 v20.0.1 2024-10-29 11:37:14 +00:00
60b46192a2 Merge pull request #2879 from balena-io/bump-oclif-core
Fix sending input to some aliases not working
2024-10-29 11:36:24 +00:00
bb101de96e Update @oclif/core patch 2024-10-29 07:16:51 -04:00
ca6344bf4c Deduplicate dependencies 2024-10-29 07:09:06 -04:00
48596fa318 Fix sending input to some aliases not working
Change-type: patch
2024-10-29 07:05:37 -04:00
7fb28ddb21 v20.0.0 2024-10-25 17:33:42 +00:00
6dd6f43d64 Merge pull request #2833 from balena-io/api-v7
Api v7
2024-10-25 17:32:44 +00:00
07a7bd76fe Deduplicate dependencies 2024-10-25 12:57:41 -04:00
4b3fdcf99c device update: Use detached HUP for os updates
This will not track HUP progress when we call
OS update in the CLI but will allow for more
reliable OS updates by default.

Change-type: major
2024-10-25 12:57:15 -04:00
d023d0af91 Drop -h flag for help and stop manually adding help per command in favor of oclif automatically adding it
Change-type: major
2024-10-25 12:57:12 -04:00
de1821d7ac Stop checking for very old, long-removed commands
Change-type: major
2024-10-25 12:57:12 -04:00
12923c9b84 Deprecate devices supported command in favor of device-type list
Change-type: patch
2024-10-25 12:57:12 -04:00
8be069dbdb Deprecate notes command in favor of device note
Change-type: patch
2024-10-25 12:57:12 -04:00
9d3f9128a8 Deprecate tunnel command in favor of device tunnel
Change-type: patch
2024-10-25 12:57:12 -04:00
61ebf9e4fd Deprecate env add in favor of env set
Change-type: patch
2024-10-25 12:57:12 -04:00
84985022e5 Deprecate ssh command in favor of device ssh
Change-type: patch
2024-10-25 12:57:12 -04:00
c5d8f73263 Deprecate logs command in favor of device logs
Change-type: patch
2024-10-25 12:57:12 -04:00
5db0c71bb3 Deprecate scan command in favor of device detect
Change-type: patch
2024-10-25 12:57:12 -04:00
c7a06f7259 Deprecate orgs command in favor of organization list
Change-type: patch
2024-10-25 12:57:12 -04:00
bc66febc50 Deprecate tags command in favor of tag list
Change-type: patch
2024-10-25 12:57:12 -04:00
bb80311700 Deprecate envs command in favor of env list
Change-type: patch
2024-10-25 12:57:12 -04:00
3dee7bd6f6 Deprecate key commands in favor of ssh-key
Change-type: patch
2024-10-25 12:57:12 -04:00
3251f04287 Deprecate keys command in favor of key list
Change-type: patch
2024-10-25 12:57:12 -04:00
35dce4579a Deprecate releases command in favor of release list
Change-type: patch
2024-10-25 12:57:12 -04:00
71ef00534d Deprecate fleets command in favor of fleet list
Change-type: patch
2024-10-25 12:57:12 -04:00
b6f8be27ec Deprecate api-keys command in favor of api-key list
Change-type: patch
2024-10-25 12:57:12 -04:00
13110cca45 Deprecate devices command in favor of device list
Change-type: patch
2024-10-25 12:57:12 -04:00
d4b554da1b Docs: Show whether an alias is deprecated
Change-type: patch
2024-10-25 12:57:12 -04:00
1275c11573 Update balena-preload to 16.0.0
Change-type: patch
2024-10-25 12:57:10 -04:00
593233a99f Tests: Drop unused my_application resource mock
Change-type: patch
2024-10-25 12:56:48 -04:00
ec92f21b70 Drop the no longer needed __metadata property handling 2024-10-25 12:56:48 -04:00
5adc43bcbd Update image_size type from number to string 2024-10-25 12:56:48 -04:00
1ee9a68288 Update device.overall_status comments with their respective replacements
Changelog-entry: Rename `device.overall_status` values: `IDLE` to `OPERATIONAL`, `OFFLINE` to `DISCONNECTED`; add `REDUCED_FUNCTIONALITY`
Change-type: major
2024-10-25 12:56:48 -04:00
56e5dafb20 Drop the device.is_managed_by__device property from test-data 2024-10-25 12:56:48 -04:00
f0e0c0d728 Update all API queries to use the v7 model 2024-10-25 12:56:48 -04:00
afd14794f5 git mv v6 test-data api-responses to v7 2024-10-25 12:56:48 -04:00
37e08e4667 Update actor to use PineDeferred type 2024-10-25 12:56:48 -04:00
61af57acc9 Update release.contract type from string to JsonType 2024-10-25 12:56:48 -04:00
19be0fec1a Replace device should_be_running__release with is_pinned_on__release 2024-10-25 12:56:48 -04:00
2b656c23b3 Update @balena/compose to 5.0.0
Change-type: patch
2024-10-25 12:56:48 -04:00
2bf7b81645 Bump balena-sdk to 20.3.0
Change-type: patch
2024-10-25 12:56:43 -04:00
746b6fa439 v19.16.0 2024-10-23 13:18:23 +00:00
f52e218290 Merge pull request #2877 from balena-io/devices-support-to-device-type-list
Add alias `device-type list` for command `devices supported`
2024-10-23 09:17:22 -04:00
8655b89313 Deduplicate dependencies 2024-10-23 07:33:16 -04:00
09d52c504d device-type list: Add --all flag for including no longer supported device types in the list
Change-type: minor
2024-10-23 07:23:40 -04:00
e5cee648f2 Add alias device-type list for command devices supported
Change-type: minor
2024-10-23 07:23:40 -04:00
98a6b431d9 git mv devices/supported to device/list 2024-10-23 07:17:59 -04:00
f305d5d9a0 v19.15.0 2024-10-23 11:01:55 +00:00
5cb5ac80a6 Merge pull request #2876 from balena-io/notes-to-device-note
Add alias `device note` for command `note`
2024-10-23 07:00:58 -04:00
3eb3b3b584 Add alias device note for command notes
Change-type: minor
2024-10-21 21:07:38 -04:00
8ee5ede34d git mv notes/index to device/note 2024-10-21 21:02:18 -04:00
d6d08cc7c9 v19.14.0 2024-10-22 00:51:16 +00:00
76c63d4b20 Merge pull request #2875 from balena-io/tunnel-to-device-tunnel
Add alias `device tunnel` for command `tunnel`
2024-10-22 00:50:25 +00:00
bff5897047 Add alias device tunnel for command tunnel
Change-type: minor
2024-10-21 20:29:20 -04:00
22c9fd399e git mv tunnel/index to device/tunnel 2024-10-21 20:29:20 -04:00
65222b5fc9 v19.13.1 2024-10-21 19:13:36 +00:00
d554658eee Merge pull request #2865 from balena-io/renovate/major-4-chalk
Update dependency chalk to v4
2024-10-21 20:12:31 +01:00
8ded517dd9 Update dependency chalk to v4
Update chalk from 3.0.0 to 4.1.2

Change-type: patch
2024-10-21 18:50:41 +00:00
b0d8b021d5 v19.13.0 2024-10-21 18:14:05 +00:00
2eb5d7f6b3 Merge pull request #2874 from balena-io/envs-add-to-envs-set
Add alias `env set` for command `env add`
2024-10-21 14:13:14 -04:00
f1924bba6b Add alias env set for command env add
Change-type: minor
2024-10-21 12:06:17 -04:00
44082e22e4 git mv env/add to env/set 2024-10-21 12:06:17 -04:00
2d15530f61 v19.12.1 2024-10-21 16:04:19 +00:00
a7c612f7de Merge pull request #2873 from balena-io/bump-oclif-core
Update `@oclif/core`
2024-10-21 16:03:04 +00:00
147ce8067a Update @oclif/core
Change-type: patch
2024-10-21 11:42:30 -04:00
5e7ac09dd0 v19.12.0 2024-10-21 15:07:55 +00:00
4c9fc89a6b Merge pull request #2871 from balena-io/ssh-to-device-ssh
Add alias `device ssh` for `ssh` command
2024-10-21 15:06:26 +00:00
9b1eb57973 Update help.spec per recent help output change 2024-10-21 10:46:08 -04:00
76c08b6c13 Add alias device ssh for ssh command
Change-type: minor
2024-10-21 10:46:08 -04:00
3f82f42652 git mv ssh/index to device/ssh 2024-10-21 10:46:08 -04:00
69d820878a v19.11.1 2024-10-21 13:05:19 +00:00
aaaee47e0c Merge pull request #2869 from balena-io/renovate/major-19-sinon
Update dependency sinon to v19
2024-10-21 14:04:22 +01:00
e7761a616b Update dependency sinon to v19
Update sinon from 18.0.0 to 19.0.2

Change-type: patch
2024-10-21 12:43:26 +00:00
9559d5cba3 v19.11.0 2024-10-21 12:08:59 +00:00
c1649dd828 Merge pull request #2864 from balena-io/logs-to-device-logs
Add alias `device logs` for `logs` command
2024-10-21 12:07:57 +00:00
8e9b992a59 Deduplicate dependencies 2024-10-21 07:45:11 -04:00
b77f266bd7 Add alias device logs for logs
Change-type: minor
2024-10-21 07:35:58 -04:00
3c9ac76982 git mv logs/index to device/logs
Change-type: patch
2024-10-21 07:31:24 -04:00
e483d06d2b v19.10.0 2024-10-21 11:13:10 +00:00
24d2d19d33 Merge pull request #2862 from balena-io/scan-to-device-detect
`scan` to `device detect`
2024-10-21 07:12:05 -04:00
ba5bb7b12c Add alias device detect for scan
Change-type: minor
2024-10-18 10:45:06 -04:00
9082e7b3f7 git mv scan/index to device/detect 2024-10-18 10:39:24 -04:00
0716544042 v19.9.0 2024-10-18 14:25:43 +00:00
e1858aa69d Merge pull request #2861 from balena-io/orgs-to-organization-list
Orgs to organization list
2024-10-18 10:24:49 -04:00
082cce332a Add alias organization list for orgs command
Change-type: minor
2024-10-18 09:33:27 -04:00
218e0a1b6b git mv orgs/ to organization/ 2024-10-18 09:29:01 -04:00
4065c5775c v19.8.0 2024-10-18 13:25:54 +00:00
fd966df1f0 Merge pull request #2860 from balena-io/tags-to-tag-list
`tags` to `tag list`
2024-10-18 13:24:59 +00:00
5eba175bf1 Add alias tag list for tags command
Change-type: minor
2024-10-18 08:49:53 -04:00
bd1b71bf2f git mv tags/index to tag/list 2024-10-18 08:40:05 -04:00
bd7ea3d21a v19.7.0 2024-10-18 12:35:38 +00:00
31662d9175 Merge pull request #2859 from balena-io/envs-to-env-list
`envs` to `env list`
2024-10-18 12:34:15 +00:00
417c75484b Add alias env list for command envs
Change-type: minor
2024-10-18 07:47:46 -04:00
fcd77e97d9 git mv envs/index to env/list 2024-10-18 07:12:39 -04:00
1dd819ae61 v19.6.0 2024-10-18 11:04:31 +00:00
388e02ce85 Merge pull request #2857 from balena-io/key-to-ssh-key
Add `ssh-key` as aliases for all `key` commands
2024-10-18 07:03:26 -04:00
30446605e1 Deduplicate dependencies 2024-10-17 11:46:52 -04:00
e853b15f12 Add ssh-key as aliases for all key commands
Change-type: minor
2024-10-17 11:46:52 -04:00
96cf380f66 git mv key to ssh-key 2024-10-17 11:05:52 -04:00
5d0d02a24d v19.5.0 2024-10-17 14:56:42 +00:00
f5ca07a422 Merge pull request #2856 from balena-io/keys-to-key-list
Add `key list` alias for `keys` command
2024-10-17 10:55:51 -04:00
6b5c6e072b Add key list alias for keys command
Change-type: minor
2024-10-16 15:21:44 -04:00
3615f8e525 git mv keys/index to key/list 2024-10-16 15:15:23 -04:00
ec6cbd120e v19.4.0 2024-10-16 19:12:09 +00:00
65b278e40b Merge pull request #2855 from balena-io/releases-to-release-list
Add `release list` alias for `releases` command
2024-10-16 19:11:21 +00:00
8d1394a77d Add release list alias for releases command
Change-type: minor
2024-10-16 14:50:44 -04:00
ca0a3ee147 git mv releases/index to release/list 2024-10-16 14:25:20 -04:00
019af9e703 v19.3.0 2024-10-16 18:03:21 +00:00
f213940c84 Merge pull request #2854 from balena-io/fleets-to-fleet-list
Add alias `fleet list` for `fleets` command
2024-10-16 14:02:23 -04:00
5243803342 Add alias fleet list for fleets command
Change-type: minor
2024-10-16 12:36:45 -04:00
811e009ba9 git mv fleets/index to fleet/list 2024-10-16 12:31:21 -04:00
45e0f21685 v19.2.0 2024-10-16 16:11:52 +00:00
60f5f47930 Merge pull request #2853 from balena-io/api-keys-to-list
Add alias `api-key list` for command `api-keys`
2024-10-16 12:10:48 -04:00
cad5543863 Add alias api-key list for command api-keys
Change-type: minor
2024-10-16 11:20:30 -04:00
a1e936bb3f git mv api-keys/index to api-key/list 2024-10-16 11:15:23 -04:00
49984c2366 v19.1.3 2024-10-16 14:39:29 +00:00
2a0ab6abbb Merge pull request #2852 from balena-io/remove-custom-os-command-sorting
Remove custom sorting of OS commands in docs in favor of alphabetizing
2024-10-16 14:38:33 +00:00
349bab7702 Deduplicate dependencies 2024-10-16 10:13:38 -04:00
af2c04540f Remove custom sorting of OS commands in docs in favor of alphabetizing
Change-type: patch
2024-10-16 09:58:19 -04:00
cdfabb8f92 v19.1.2 2024-10-16 13:35:41 +00:00
5e058d5158 Merge pull request #2851 from balena-io/command-to-init
Remove custom override of oclif Command class in favor of `prerun` hook
2024-10-16 09:34:36 -04:00
6a81ed2d70 Update expected warnings 2024-10-14 15:56:54 -04:00
d323c0742c Remove no longer needed dependency get-stdin
Change-type: patch
2024-10-14 15:38:21 -04:00
9cdde4f6c2 Remove custom override of oclif Command class in favor of prerun hook
Change-type: patch
2024-10-14 15:38:21 -04:00
ebe10360b3 git mv src/command.ts to src/hooks/init.ts 2024-10-14 11:25:31 -04:00
440c5ad15b v19.1.1 2024-10-14 13:06:42 +00:00
0699278220 Merge pull request #2849 from balena-io/fix-changelog
Fix changelog entry for v19.1.0
2024-10-14 13:05:49 +00:00
0eb5c78e33 Deduplicate dependencies
Change-type: patch
2024-10-14 08:35:32 -04:00
067232b5c4 Fix changelog entry for v19.1.0
Change-type: patch
2024-10-14 07:51:00 -04:00
5716ba29ad v19.1.0 2024-10-11 17:15:09 +00:00
fc2234b0dd Merge pull request #2844 from balena-io/devices-to-device-list
Devices to device list
2024-10-11 17:14:15 +00:00
12cdb14638 Docs: Show aliases for commands
Change-type: patch
2024-10-11 12:54:09 -04:00
b936c51941 Deprecate devices command in favor of device list
Change-type: minor
2024-10-11 12:54:09 -04:00
6c23b06b4c git mv devices/index to device/list 2024-10-11 12:54:09 -04:00
87c52c55ed Deduplicate dependencies
Change-type: patch
2024-10-11 12:54:09 -04:00
f792343180 v19.0.20 2024-10-11 11:48:53 +00:00
680d592af2 Merge pull request #2846 from balena-io/use-default-usage
Use oclif default usage instead of manually filling it out
2024-10-11 11:47:51 +00:00
f52e6bd8b4 Docs: Generate CLI command references from file names instead of usage
Change-type: patch
2024-10-11 07:26:12 -04:00
0847daba1b Use default oclif USAGE message for all commands
Change-type: patch
2024-10-11 07:26:12 -04:00
057b37ae38 v19.0.19 2024-10-11 11:18:26 +00:00
deb7de8951 Merge pull request #2848 from balena-io/update-release-notes-link
Fix update notification release notes link
2024-10-11 11:17:38 +00:00
55dbe42e84 Deduplicate dependencies
Change-type: patch
2024-10-10 15:32:46 -04:00
3e8bc57fdb Fix update notification release notes link
Change-type: patch
2024-10-10 14:05:10 -04:00
d206e7cd66 v19.0.18 2024-10-08 15:25:16 +00:00
7092db8ee8 Merge pull request #2845 from balena-io/contributing-plural-folders
Contributing: No longer request separate folders for plural commands
2024-10-08 15:23:41 +00:00
276d61cf6c Contributing: No longer request separate folders for plural commands
Change-type: patch
2024-10-08 10:54:06 -04:00
77ccd9c39c v19.0.17 2024-10-08 14:04:45 +00:00
9e140eff13 Merge pull request #2842 from balena-io/remove-mixpanel
Remove mixpanel
2024-10-08 10:03:55 -04:00
da95baa70c Remove dev dependency parse-link-header
Change-type: patch
2024-10-08 09:37:37 -04:00
a3ec75c2c7 Remove dev dependency @octokit/rest
Change-type: patch
2024-10-08 09:37:37 -04:00
f6f6be8ee8 Remove dev dependency @octokit/plugin-throttling
Change-type: patch
2024-10-08 09:37:37 -04:00
09e653692b Remove no longer needed references and tests for mixpanel
Change-type: patch
2024-10-08 09:37:37 -04:00
3ac89b236a Remove dev dependency @types/mixpanel
Change-type: patch
2024-10-08 09:37:37 -04:00
bd472f2380 v19.0.16 2024-10-08 13:35:05 +00:00
b5dcf45c40 Merge pull request #2839 from balena-io/compose-reduce-patched-properties
compose: Reduce the properties updated to only the necessary
2024-10-08 16:34:06 +03:00
7e2b5abe60 compose: Reduce the properties updated to only the necessary
Change-type: patch
2024-10-08 16:11:28 +03:00
7b66e0d216 v19.0.15 2024-10-08 13:11:05 +00:00
877c5031a4 Merge pull request #2838 from balena-io/remove-mockery
Remove `mockery` dev dependency
2024-10-08 13:10:17 +00:00
1245b1c99b Remove unused mockery dev dependency
Change-type: patch
2024-10-08 08:47:14 -04:00
8dbe1af551 v19.0.14 2024-10-08 12:44:20 +00:00
aae303202b Merge pull request #2841 from balena-io/temporarily-skip-broken-image-manager-tests
Temporarily skip broken image-manager tests on Windows and Mac
2024-10-08 12:43:19 +00:00
284784505d Deduplicate dependencies 2024-10-08 08:21:07 -04:00
77b9514442 Temporarily skip broken image-manager tests on Windows and Mac
Change-type: patch
2024-10-08 08:21:01 -04:00
ff4afe3ab2 v19.0.13 2024-09-23 11:35:49 +00:00
5ea246f016 Merge pull request #2837 from balena-io/adjust-changelog-message
Remove extra line from recent changelog entry
2024-09-23 11:35:03 +00:00
127bd7ec72 Remove extra line from recent changelog entry
Change-type: patch
2024-09-23 07:12:22 -04:00
fa35877137 v19.0.12 2024-09-20 17:48:43 +00:00
a402dffbc5 Merge pull request #2834 from balena-io/remove-image-manager
Embed balena-image-manager instead of having it as a dependency
2024-09-20 13:47:48 -04:00
c7441b06ac skip
Change-type: patch
2024-09-20 12:05:00 -04:00
251d64eb88 Add image-manager tests
Change-type: patch
2024-09-20 08:38:21 -04:00
ff9bb52a20 Remove balena-image-manager dependency
Change-type: patch
2024-09-20 08:38:21 -04:00
c799c3f10d Embed balena-image-manager instead of having it as a dependency
Change-type: patch
2024-09-20 08:38:21 -04:00
89efe2a2c8 Add mime dependency 2024-09-20 08:38:21 -04:00
f6ff397969 Move mkdirp from devDependency to dependency 2024-09-18 12:56:41 -04:00
aaf709a1d4 v19.0.11 2024-09-18 16:38:59 +00:00
ca6eea4371 Merge pull request #2835 from balena-io/reduce-bluebird
Remove Bluebird as a direct dependency
2024-09-18 19:38:06 +03:00
d39dc5a39a Remove Bluebird as a direct dependency
Change-type: patch
2024-09-18 18:37:39 +03:00
1699419788 v19.0.10 2024-09-12 23:00:18 +00:00
c25591cb4a Merge pull request #2828 from balena-io/remove-package-resin-valid-email
Remove package `@resin.io/valid-email`
2024-09-12 22:59:27 +00:00
a2b4f76c94 Remove package @resin.io/valid-email
Change-type: patch
2024-09-12 18:39:21 -04:00
6a1239bd52 v19.0.9 2024-09-12 16:12:12 +00:00
ddf34326a4 Merge pull request #2830 from balena-io/renovate/actions-download-artifact-4.1.x
Update actions/download-artifact action to v4.1.8
2024-09-12 16:11:15 +00:00
58f480ad7c Update actions/download-artifact action to v4.1.8
Update actions/download-artifact from 4.1.7 to 4.1.8

Change-type: patch
2024-09-12 15:48:40 +00:00
7e6589a7d7 v19.0.8 2024-09-12 15:07:56 +00:00
c699bb1dbc Merge pull request #2829 from balena-io/renovate/actions-upload-artifact-digest
Update actions/upload-artifact digest to 5076954
2024-09-12 15:07:01 +00:00
e101e0f466 Update actions/upload-artifact digest to 5076954
Update actions/upload-artifact

Change-type: patch
2024-09-12 14:47:50 +00:00
e29273142e v19.0.7 2024-09-12 14:13:22 +00:00
519395cfcd Merge pull request #2825 from balena-io/renovate/actions-setup-node-digest
Update actions/setup-node digest to 1e60f62
2024-09-12 14:12:33 +00:00
314e8800d0 Update actions/setup-node digest to 1e60f62
Update actions/setup-node

Change-type: patch
2024-09-12 13:48:25 +00:00
0bb1c892e8 v19.0.6 2024-09-12 13:47:30 +00:00
5eb79f5cf0 Merge pull request #2802 from balena-io/remove-moment-library
Remove moment and moment-duration-format in favor of native time parsing
2024-09-12 10:46:29 -03:00
707b249e97 Remove moment and moment-duration-format in favor of native time parsing
Change-type: patch
2024-09-12 10:05:13 -03:00
2a725cd1f0 v19.0.5 2024-09-10 15:13:27 +00:00
83f274cc62 Merge pull request #2789 from balena-io/renovate/apple-actions-import-codesign-certs-2.x
Update apple-actions/import-codesign-certs action to v2
2024-09-10 12:12:42 -03:00
9242a3493a Update apple-actions/import-codesign-certs action to v2
Update apple-actions/import-codesign-certs from 1 to 2

Change-type: patch
2024-09-10 14:47:56 +00:00
aa46d314b4 v19.0.4 2024-09-10 14:44:44 +00:00
58f7dfc894 Merge pull request #2824 from balena-io/bump-ts-5_6_2
Bump TypeScript to 5.6.2
2024-09-10 14:43:53 +00:00
39e1c02648 Deduplicate dependencies
Resolves: #
Change-type:
2024-09-10 11:53:09 +03:00
5f92bbc846 Update TypeScript to 5.6.2
Change-type: patch
2024-09-10 11:49:41 +03:00
2f03b24bcf v19.0.3 2024-09-05 12:34:15 +00:00
233ee990f9 Merge pull request #2823 from balena-io/reduce-require-usage
Reduce usage of not necessary CJS require()
2024-09-05 09:33:07 -03:00
facc66e9f9 Reduce use of CJS require() on automation files
Change-type: patch
2024-09-04 14:47:18 -03:00
6efd24489f Remove the use of CJS require() on test files
Change-type: patch
2024-09-04 14:33:52 -03:00
0339160a0b Remove not necessary 'import = require' syntax for js-yaml
Change-type: patch
2024-09-04 13:55:41 -03:00
0591f5edbd v19.0.2 2024-09-03 14:56:29 +00:00
c30dd323f1 Merge pull request #2821 from balena-io/bump-dev-deps
update dev dependencies
2024-09-03 14:55:19 +00:00
1640bd6457 Update devDependency patch-package to v8.0.0
Change-type: patch
2024-09-03 11:22:45 -03:00
da2ffde483 Update devDependency mkdirp to v3.0.1
Change-type: patch
2024-09-03 10:58:36 -03:00
5c9e3ad8f6 Update devDependency fs-extra(to v11) and @types/fs-extra(to v11)
Change-type: patch
2024-09-03 10:58:36 -03:00
7515d4b710 Update devDependency @types/parse-link-header to v2.0.3
Change-type: patch
2024-09-03 10:58:30 -03:00
fae5af6b75 Remove unused devDependency @types/nock
Change-type: patch
2024-09-03 10:47:23 -03:00
45aa1adacb Update devDependency klaw(to v4) and @types/klaw(to v3.0.6)
Change-type: patch
2024-09-03 10:47:23 -03:00
b34ea14413 Update husky to v9.1.5
Change-type: patch
2024-09-03 10:47:19 -03:00
90eae06017 Update devDependency @types/jsonwebtoken to v9.0.6
Change-type: patch
2024-09-03 09:35:25 -03:00
41da8f6f6f Update devDependency archiver(to v7) and @types/archiver(to v6)
Change-type: patch
2024-09-03 09:33:07 -03:00
8d706a7d81 Removes unused devDependency @types/net-keepalive
Change-type: patch
2024-09-03 09:30:33 -03:00
d67952024c Update devDependency rewire(to v7) and @types/rewire(to v2.5.30)
Change-type: patch
2024-09-03 09:28:32 -03:00
8895fc485c Update devDependency sinon(to v18) and @types/sinon(to v17)
Change-type: patch
2024-09-03 09:20:41 -03:00
c2dbcaaaf4 v19.0.1 2024-09-02 13:21:58 +00:00
52cb951e49 Merge pull request #2788 from balena-io/bump-oclif-core-v4
Bump @oclif/core from 3.27.0 to 4.0.18
2024-09-02 13:20:59 +00:00
2a357a438f Bump @oclif/core from 3.27.0 to 4.0.18
Change-type: patch
2024-09-02 09:24:08 -03:00
a9a202281d v19.0.0 2024-08-22 17:43:34 +00:00
b74979fb9e Merge pull request #2816 from balena-io/v19
v19
2024-08-22 14:42:42 -03:00
4760866c77 Update all references of lib to src
Change-type: patch
2024-08-22 13:03:37 -03:00
2b044348e0 Rename the lib folder to src
Change-type: major
2024-08-22 12:55:48 -03:00
c9fa10b9c6 Update @balena/compose to 4.0.1
Update @balena/compose from 3.2.1 to 4.0.1

Change-type: major
2024-08-22 07:44:09 -03:00
63674c8201 Use standard visuals table component for fleet/s
This effectively removes the ability to filter/sort/customize the output table.
The cli cannot properly handle this operations on all models and this one was inconsistent.
For now we recommend that users that require parsing the CLI output use the output json format and do any kind of necessary parsing on it.

Change-type: major
2024-08-07 13:14:24 -03:00
a08ac447a3 v18.2.34 2024-07-29 11:08:38 +00:00
12a338fb21 Merge pull request #2817 from balena-io/ab77/patch-1
Switch to self-hosted
2024-07-29 11:07:51 +00:00
1d70e6b4b4 Run npm dedupe commands
Change-type: patch
Signed-off-by: Kyle Harding <kyle@balena.io>
2024-07-29 07:25:13 -03:00
d3458379e6 Switch to self-hosted
change-type: patch
2024-07-23 11:10:09 -07:00
544f615ca0 v18.2.33 2024-07-17 07:46:28 +00:00
245c51d974 Merge pull request #2814 from balena-io/improve-scan-reliability
Improve discover balena os across different networks
2024-07-17 04:42:50 -03:00
03f0f11f8b Improve discover balena os across different networks
This is an improvement over the scan, join and leave commands removing flakiness when searching over different networks. In short, instead of leaving bonjour to search across all interfaces, we forcebly conduct a search on each interface, this requires mDNS binding any ipv4 interface (0.0.0.0), otherwise it would bind over the interface itself, which is not desired as it causes services to only be able to receive information over that interface, see [mafintosh/multicast-dns#53](https://github.com/mafintosh/multicast-dns/issues/53). This targeted approach enhances the reliability and accuracy of network searches, reducing instances of missed connections or network errors typically caused by flakiness when relying on bonjour's default behavior.

Change-type: patch
2024-07-16 19:01:53 -03:00
2c0c1f8fd1 v18.2.32 2024-07-16 13:10:07 +00:00
d4d7fce2c1 Merge pull request #2815 from balena-io/remove-unused-code
Remove unused code
2024-07-16 13:09:15 +00:00
0f23318367 Remove unused code
Change-type: patch
2024-07-16 07:46:18 -03:00
003d537433 v18.2.31 2024-07-15 21:17:44 +00:00
46d3497663 Merge pull request #2798 from balena-io/balena-compose-sdk-pine-instance
deploy: Use the sdk's pine instance with balena-compose
2024-07-16 00:16:55 +03:00
a39a772c9e Deduplicate dependencies 2024-07-15 18:51:16 +03:00
efa0d67f0a deploy: Use the sdk's pine instance with balena-compose
Change-type: patch
2024-07-15 18:42:51 +03:00
232b9678bc Update balena-sdk to 19.7.3
Update balena-sdk from 19.7.2 to 19.7.3

Change-type: patch
2024-07-15 16:09:51 +03:00
a8ce14b0e8 v18.2.30 2024-07-15 11:30:43 +00:00
838a36758a Merge pull request #2812 from balena-io/test-omit-escaped-chars
Omit unicode control character escapes from test logs
2024-07-15 14:29:46 +03:00
4e101e2fd9 Omit unicode control character escapes from test logs
Change-type: patch
2024-07-13 18:07:04 +03:00
9f9fd97795 Deduplicate dependencies 2024-07-13 17:44:04 +03:00
1b36dc84fc v18.2.29 2024-07-12 14:55:02 +00:00
5d6ee707ff Merge pull request #2801 from balena-io/bump-balena-preload
Update balena-preload from 15.0.5 to 15.0.6
2024-07-12 14:54:14 +00:00
3c64e13fb3 Update balena-preload from 15.0.5 to 15.0.6
Change-type: patch
2024-07-12 11:30:36 -03:00
7e41fda8d4 v18.2.28 2024-07-12 13:29:24 +00:00
5df316e9cb Merge pull request #2807 from balena-io/update-sdk-19-7-2
Update balena-sdk to 19.7.2
2024-07-12 16:28:38 +03:00
79fcd95491 Downgrade pinejs-client-request to 7.4.2 to unblock the sdk update
Change-type: patch
2024-07-12 16:02:35 +03:00
33199acbe8 Update balena-sdk to 19.7.2
Update balena-sdk from 19.5.5 to 19.7.2

Change-type: patch
2024-07-12 15:55:42 +03:00
4633c2456d v18.2.27 2024-07-12 12:45:19 +00:00
f8bc081228 Merge pull request #2804 from balena-io/update-sdk
Update balena-sdk to 19.5.5
2024-07-12 12:44:19 +00:00
1702f8ba59 Update balena-sdk to 19.5.5
Update balena-sdk from 19.4.0 to 19.5.5

Change-type: patch
2024-07-12 15:08:26 +03:00
60b0c7e346 v18.2.26 2024-07-12 12:03:32 +00:00
e95ef8b3b4 Merge pull request #2803 from balena-io/fix-dependencies
Fix dependencies
2024-07-12 12:02:39 +00:00
1bc0f7447f Drop unused dependencies
Change-type: patch
2024-07-12 08:38:49 -03:00
f65215e144 Move dependencies that should be dev only as devDependencies
Change-type: patch
2024-07-12 07:15:37 -03:00
97abc5cf1c v18.2.25 2024-07-11 10:54:49 +00:00
e64a09d2f4 Merge pull request #2800 from balena-io/bump-oclif-v4
Bump oclif v4
2024-07-11 07:54:00 -03:00
b1073ca549 Fix complete generation intermitency
Change-type: patch
2024-07-10 21:22:20 -03:00
e659e3577a Bump oclif to v4
Change-type: patch
2024-07-10 19:07:54 -03:00
f7233c5d42 v18.2.24 2024-07-10 22:06:20 +00:00
4ae2ff1740 Merge pull request #2799 from balena-io/overrides-inline-source-dev-dependency-version
Update Dependencies
2024-07-10 22:05:21 +00:00
19a60bb0ab Update mocha from 8.4.0 to 10.6.0
Change-type: patch
2024-07-10 18:25:37 -03:00
d1a6f7560c Override inline-source-cli with non-vulnerable dependency
Change-type: patch
2024-07-10 18:20:05 -03:00
4619ce7daa v18.2.23 2024-07-10 21:05:55 +00:00
7624240d5e Merge pull request #2796 from balena-io/replace-discoverable-service-for-std-bonjour-service
Replace resin-discoverable-services with bonjour-service
2024-07-10 21:04:58 +00:00
7273656d07 Replace resin-discoverable-services with bonjour-service
Instead of using the more generic resin-discoverable-services lib which is unmantained
and currently has several vulnerabilities and forks for fixing issues (that were later on fixed upstream)
we directly talk with mDNS using standard (and currently mantained) bonjour-service.

Change-type: patch
2024-07-10 16:06:19 -03:00
00bd4d5415 v18.2.22 2024-07-10 16:48:09 +00:00
c2d3c9fc71 Merge pull request #2797 from balena-io/remove-unused-depedency
Remove unused dependency minimatch
2024-07-10 16:46:45 +00:00
1749937373 Remove unused dependency minimatch
Change-type: patch
2024-07-10 12:54:52 -03:00
bcb7fb8902 v18.2.21 2024-07-09 15:10:38 +00:00
81e9601d6b Merge pull request #2794 from balena-io/bump-resin-discoverable-services
Bump resin-discoverable-services from 2.0.4 to 2.0.5
2024-07-09 15:09:34 +00:00
6c89ba4b22 Bump resin-discoverable-services from 2.0.4 to 2.0.5
Change-type: patch
2024-07-09 11:43:45 -03:00
57d3d6d537 v18.2.20 2024-07-05 21:12:48 +00:00
6330574c01 Merge pull request #2791 from balena-io/run-audit-fix
Audit fix dependencies
2024-07-05 18:11:52 -03:00
b6d1afac2d Audit fix dependencies
Change-type: patch
2024-07-05 17:41:14 -03:00
f2d0da0837 v18.2.19 2024-07-05 13:37:55 +00:00
068cd887c8 Merge pull request #2790 from balena-io/unneeded-publish-release
Remove unused package `publish-release`
2024-07-05 13:36:53 +00:00
93e597a596 Remove unused package publish-release
Change-type: patch
2024-07-05 08:56:51 -04:00
5b1d6a3190 v18.2.18 2024-07-04 21:56:19 +00:00
dba102f347 Merge pull request #2786 from balena-io/renovate/actions-setup-node-4.x
Update actions/setup-node action to v4
2024-07-04 18:55:25 -03:00
c30a1dc1ed Update actions/setup-node action to v4
Update actions/setup-node from 3 to 4

Change-type: patch
2024-07-02 13:47:56 +00:00
78368c8a51 v18.2.17 2024-07-02 13:20:43 +00:00
d7250ccc4e Merge pull request #2785 from balena-io/renovate/etcher-sdk
Update dependency etcher-sdk to v9.1.0
2024-07-02 13:19:44 +00:00
2d47eb53cd Update dependency etcher-sdk to v9.1.0
Update etcher-sdk from 9.0.11 to 9.1.0

Change-type: patch
2024-07-02 12:53:24 +00:00
b5fc97bdf9 v18.2.16 2024-07-02 12:14:25 +00:00
3472df2c04 Merge pull request #2783 from balena-io/renovate/patch-etcher-sdk
Update dependency etcher-sdk to v9.0.11
2024-07-02 12:13:18 +00:00
6b5657625a Update dependency etcher-sdk to v9.0.11
Update etcher-sdk from 9.0.8 to 9.0.11

Change-type: patch
2024-07-02 11:47:56 +00:00
dad6b23202 v18.2.15 2024-07-02 11:11:04 +00:00
6b59c06978 Merge pull request #2784 from balena-io/renovate/patch-event-stream
Update dependency event-stream to v3.3.5
2024-07-02 11:10:09 +00:00
b518067058 Update dependency event-stream to v3.3.5
Update event-stream from 3.3.4 to 3.3.5

Change-type: patch
2024-07-02 10:48:33 +00:00
bd4bdb805f v18.2.14 2024-07-02 10:14:47 +00:00
32e59eccc5 Merge pull request #2771 from balena-io/renovate/npm-jsonwebtoken-vulnerability
Update dependency jsonwebtoken to v9 [SECURITY]
2024-07-02 07:13:48 -03:00
f05e49915d Update dependency jsonwebtoken to v9 [SECURITY]
Update jsonwebtoken from 8.5.1 to 9.0.0

Change-type: patch
2024-07-02 09:48:15 +00:00
92146429c4 v18.2.13 2024-07-02 09:14:07 +00:00
40f5214317 Merge pull request #2780 from balena-io/renovate/patch-prettyjson
Update dependency @types/prettyjson to ^0.0.33
2024-07-02 09:13:04 +00:00
14e1255b5f Update dependency @types/prettyjson to ^0.0.33
Update @types/prettyjson from 0.0.30 to 0.0.33

Change-type: patch
2024-07-02 08:48:40 +00:00
15e91e95b4 v18.2.12 2024-07-02 07:50:17 +00:00
1814fe7581 Merge pull request #2782 from balena-io/npm-dd
Deduplicate dependencies
2024-07-02 10:49:11 +03:00
7325e8d9d5 Deduplicate dependencies
Change-type: patch
2024-07-01 22:51:28 +03:00
5358f92590 v18.2.11 2024-07-01 17:52:46 +00:00
fe6a7cfdba Merge pull request #2778 from balena-io/renovate/patch-fast-levenshtein
Update dependency @types/fast-levenshtein to v0.0.4
2024-07-01 17:51:45 +00:00
a29bd8d0ef Update dependency @types/fast-levenshtein to v0.0.4
Update @types/fast-levenshtein from 0.0.1 to 0.0.4

Change-type: patch
2024-06-21 20:48:02 +00:00
049e1da53e v18.2.10 2024-06-21 20:12:54 +00:00
2c0b4072ae Merge pull request #2776 from balena-io/renovate/actions-download-artifact-4.1.x
Update actions/download-artifact action to v4.1.7
2024-06-21 20:12:05 +00:00
15c0c32a01 Update actions/download-artifact action to v4.1.7
Update actions/download-artifact from 4.1.0 to 4.1.7

Change-type: patch
2024-06-21 19:48:21 +00:00
8f2c7f9dbf v18.2.9 2024-06-21 19:13:44 +00:00
90982256c7 Merge pull request #2773 from balena-io/renovate/actions-setup-python-digest
Update actions/setup-python digest to 65d7f2d
2024-06-21 19:12:42 +00:00
73220206a2 Update actions/setup-python digest to 65d7f2d
Update actions/setup-python

Change-type: patch
2024-06-21 18:48:07 +00:00
8b453aae89 v18.2.8 2024-06-21 18:13:51 +00:00
d85d5933fb Merge pull request #2775 from balena-io/renovate/actions-upload-artifact-digest
Update actions/upload-artifact digest to 6546280
2024-06-21 18:12:44 +00:00
2cd455ff81 Update actions/upload-artifact digest to 6546280
Update actions/upload-artifact

Change-type: patch
2024-06-21 17:49:06 +00:00
066cbaf35f v18.2.7 2024-06-21 17:16:21 +00:00
17fa888fea Merge pull request #2772 from balena-io/renovate/pin-dependencies
Pin dependencies
2024-06-21 17:15:25 +00:00
f50287873a Pin dependencies
Update actions/setup-node

Change-type: patch
2024-06-21 16:47:51 +00:00
edff14fa72 v18.2.6 2024-06-21 15:23:25 +00:00
9de753d9d3 Merge pull request #2770 from balena-io/bump-oclif-core
Update @oclif/core from 3.26.9 to 3.27.0
2024-06-21 15:22:19 +00:00
75d2d7d375 Update @oclif/core from 3.26.9 to 3.27.0
Change-type: patch
2024-06-21 09:49:38 -03:00
d9b193acc1 v18.2.5 2024-06-21 12:11:21 +00:00
2e42999642 Merge pull request #2769 from balena-io/bump-ts
Update TypeScript to 5.5.2
2024-06-21 12:10:18 +00:00
5a3f0ea453 Limit @oclif/core to ~3.26 so that npm dedupe doesn't auto-bump it
Change-type: patch
2024-06-21 01:37:00 +03:00
e1cd30060c Deduplicate dependencies 2024-06-21 01:31:53 +03:00
7959e23cd3 Update TypeScript to 5.5.2
Change-type: patch
2024-06-21 00:18:36 +03:00
9c4d788d6d v18.2.4 2024-05-17 12:04:11 +00:00
181f5a6a2f Merge pull request #2767 from balena-io/aethernet-patch-1
patch: fix outdated doc for "os configure"
2024-05-17 12:03:17 +00:00
163dcf596e patch: fix outdated doc for "os configure"
There were an outdated warning for `os configure` on windows.
The command actually works fine on windows.

see: https://balena.zulipchat.com/#narrow/stream/403752-channel.2Fsupport-help/topic/Cytiva.20image.20downloads/near/438786503
2024-05-17 13:39:22 +02:00
1724187466 v18.2.3 2024-05-15 13:32:53 +00:00
b27dcdd582 Merge pull request #2765 from balena-io/dfunckt-patch-1
Pluralize command categories in docs
2024-05-15 13:31:57 +00:00
c28039a3f2 Fix exitCode type 2024-05-15 16:01:38 +03:00
233bc705de Pluralize command categories in docs
Pluralize command categories, eg. "Device" -> "Devices”.

Results in much fewer categories in our docs pages and we no longer have the somewhat silly separate singular and plural categories for commands such as `devices` and `device <command>`.

Change-type: patch
2024-05-15 15:49:57 +03:00
71518678e1 v18.2.2 2024-04-30 13:57:49 +00:00
88a705c935 Merge pull request #2754 from balena-io/upgrade_dockerode
Upgrade dockerode and docker-modem dependencies
2024-04-30 13:56:52 +00:00
55d06aced2 Deduplicate npm dependencies
Signed-off-by: Ken Bannister <kb2ma@runbox.com>
2024-04-29 08:20:02 -04:00
aa9a148c46 Upgrade dockerode and docker-modem dependencies
Includes test fixes due to an interface change in docker-modem.

Change-type: patch
Signed-off-by: Ken Bannister <kb2ma@runbox.com>
2024-04-29 07:56:53 -04:00
10ca5b4f59 v18.2.1 2024-04-23 12:08:57 +00:00
47e11d5f9b Merge pull request #2758 from balena-io/kyle/actuated
Use Actuated runners for Linux test and publish
2024-04-23 12:07:47 +00:00
6fb65bcf22 Re-run npm install and npm dedupe
Signed-off-by: Kyle Harding <kyle@balena.io>
2024-04-22 17:56:20 +03:00
954de13b10 Use Actuated runners for Linux test and publish
Change-type: patch
Signed-off-by: Kyle Harding <kyle@balena.io>
2024-04-19 15:27:38 -04:00
f81a27e931 v18.2.0 2024-04-17 16:13:12 +00:00
e8815d0275 Merge pull request #2756 from balena-io/build-optional-arch
build: Auto-resolve the cpu arch when the --deviceType is provided
2024-04-17 19:12:11 +03:00
766e6d4e5e build: Auto-resolve the cpu arch when the --deviceType is provided
Change-type: minor
2024-04-17 18:10:30 +03:00
7b46f65a01 v18.1.10 2024-04-16 14:17:07 +00:00
db8df0ac35 Merge pull request #2755 from balena-io/node-20-6
Mark node 20.6.0 as the minimum working version
2024-04-16 17:16:00 +03:00
7c7f46fe2b Deduplicate dependencies 2024-04-16 16:46:25 +03:00
b29aae1821 Mark node 20.6.0 as the minimum working version
Change-type: patch
2024-04-16 15:42:41 +03:00
0b10701015 v18.1.9 2024-04-10 15:24:31 +00:00
1dbe08d7e0 Merge pull request #2748 from balena-io/kyle/renovate-npm-dedupe
Enable npm dedupe as part of Renovate postUpdateOptions
2024-04-10 18:23:33 +03:00
d01461ff3e Deduplicate dependencies 2024-04-10 17:39:18 +03:00
2a970478bd Enable npm dedupe as part of Renovate postUpdateOptions
See: https://docs.renovatebot.com/configuration-options/#postupdateoptions
Change-type: patch
Signed-off-by: Kyle Harding <kyle@balena.io>
2024-04-10 10:03:01 -04:00
ffd44d3fec v18.1.8 2024-04-09 17:29:48 +00:00
df51f87fbc Merge pull request #2752 from balena-io/shrinkwrap-v3
npm-shrinkwrap.json: Recreate with lockfileVersion 3
2024-04-09 20:28:45 +03:00
6178f34f88 Bump patch-package to 6.5.1
Change-type: patch
2024-04-09 19:25:17 +03:00
c5ecf692bb npm-shrinkwrap.json: Recreate with lockfileVersion 3
npm ci && \
  rm npm-shrinkwrap.json && \
  npm shrinkwrap

I confirmed that it generates the same
node_modules structure but cuts the
shrinkwrap file size by 43%.

Change-type: patch
See: https://docs.npmjs.com/cli/v9/configuring-npm/package-lock-json#lockfileversion
2024-04-09 19:14:11 +03:00
87f5f18721 v18.1.7 2024-04-09 16:03:36 +00:00
e33810b448 Merge pull request #2753 from balena-io/preload-drop-unused-deps
Update balena-preload to 15.0.5
2024-04-09 19:02:39 +03:00
3caf54aa16 Update balena-preload to 15.0.5
Update balena-preload from 15.0.4 to 15.0.5

Change-type: patch
2024-04-09 18:26:11 +03:00
9d3ee9eb49 v18.1.6 2024-04-09 15:04:42 +00:00
3dac94db70 Merge pull request #2751 from balena-io/drivelist-v12
Update dependencies to get node-addon-api >=7.0.0 to fix builds on node 20.12.0
2024-04-09 15:03:45 +00:00
04b4444fc2 Update expected build warning tests 2024-04-09 17:17:07 +03:00
98514cef09 Deduplicate dependencies 2024-04-09 17:17:07 +03:00
4811031172 Update @oclif/core to 3.26.2
Change-type: patch
2024-04-09 17:17:07 +03:00
be682c7426 Drop the keep-alive package in favor of node's setKeepAlive defaults
Since node 12.17.0 setKeepAlive also sets
TCP_KEEPCNT=10 (vs 5 that we had)
TCP_KEEPINTVL=1 (vs 5s that we had)

Change-type: patch
See: https://nodejs.org/docs/latest-v14.x/api/net.html#net_socket_setkeepalive_enable_initialdelay
See: https://github.com/balena-io/balena-cli/pull/1220
2024-04-09 17:17:07 +03:00
c6827ee51d Update balena-preload to v15.0.4
Change-type: patch
2024-04-09 17:17:07 +03:00
2cba3bbc22 Update resin-cli-form to v3
Change-type: patch
2024-04-09 17:17:07 +03:00
933eacf275 Update resin-cli-visuals to v2
Change-type: patch
2024-04-09 17:17:07 +03:00
e7869f4c6d Update balena-device-init to v7.0.1
Change-type: patch
2024-04-09 17:17:07 +03:00
1a246a9ba5 Update etcher-sdk to v9.0.8
Change-type: patch
2024-04-09 17:16:30 +03:00
e26895085d Mark bin/dev & bin/run as executable
Change-type: patch
2024-04-09 17:16:30 +03:00
71345a8cc1 v18.1.5 2024-03-14 15:52:40 +00:00
619f605eb2 Merge pull request #2747 from balena-io/move-claw-as-dev-dep
Move klaw library to dev dependency
2024-03-14 15:51:48 +00:00
bb4713ab9a Move klaw library to dev dependency
Change-type: patch
2024-03-14 11:41:10 -03:00
168bddf7db v18.1.4 2024-03-14 14:34:50 +00:00
24076e4f8d Merge pull request #2746 from balena-io/update-balena-lint
Update @balena/lint to 8.0.0
2024-03-14 14:33:48 +00:00
634ad156ce Update @balena/lint to 8.0.0
Change-type: patch
2024-03-14 10:00:52 -04:00
6ebeb97917 v18.1.3 2024-03-14 12:57:24 +00:00
cb444998cd Merge pull request #2742 from balena-io/adds-runjs-for-plugin-compatibility
Use standard oclif run.js & dev.js
2024-03-14 09:56:33 -03:00
742c015f21 Use standard oclif run.js & dev.js
Change-type: patch
2024-03-14 09:21:11 -03:00
556e50c87c v18.1.2 2024-03-13 13:49:11 +00:00
3294f78b00 Merge pull request #2743 from balena-io/moves-signing-to-pretarball
Move macos binary signing to oclif pretarball lifecycle
2024-03-13 10:48:14 -03:00
7f11805a7f Move macos binary signing to oclif pretarball lifecycle
Change-type: patch
2024-03-13 09:40:30 -03:00
42dd732f68 v18.1.1 2024-03-12 17:39:15 +00:00
aed50480c3 Merge pull request #2745 from balena-io/removes-tmp-workaround-for-windows-runners
Remove patching tmp for windows runners
2024-03-12 17:38:18 +00:00
6515d6ae10 Remove patching tmp for windows runners
See: https://github.com/balena-io/balena-cli/pull/1298/files#r297236577
Change-type: patch
2024-03-12 12:02:32 -03:00
7903c82821 v18.1.0 2024-03-12 14:21:30 +00:00
eee8a0ecca Merge pull request #2744 from balena-io/adds-arm64-macos-builds
Add support for macos arm64 builds
2024-03-12 11:20:36 -03:00
38a2817587 Add support for macos arm64 builds
Change-type: minor
2024-03-11 20:49:29 -03:00
2bd0641d5f v18.0.4 2024-03-11 22:19:10 +00:00
122a763f82 Merge pull request #2739 from balena-io/update-dependencies
Update dependencies
2024-03-11 22:18:03 +00:00
756f6b328b Update dependencies
Change-type: patch
2024-03-11 16:35:32 -03:00
eb9db6f7b4 v18.0.3 2024-03-11 14:25:51 +00:00
6f9e5a697c Merge pull request #2740 from balena-io/removes-signing-patches
Removes signing patches
2024-03-11 14:24:40 +00:00
f9f41eef4b Removes signing patches
Change-type: patch
2024-03-11 10:53:54 -03:00
5371fea588 v18.0.2 2024-03-07 19:40:27 +00:00
bacb55a1ea Merge pull request #2735 from balena-io/removes-patches-windows
Removes no longer needed patch
2024-03-07 19:39:38 +00:00
ecfd4a260e Remove no longer needed windows oclif patches
Change-type: patch
2024-03-07 15:51:00 -03:00
1525822239 v18.0.1 2024-03-07 16:30:17 +00:00
1614d9b2c8 Merge pull request #2733 from balena-io/fix-windows-signing
Fix windows signing
2024-03-07 16:29:07 +00:00
2e061845ae Fix windows signing
Change-type: patch
2024-03-07 13:01:08 -03:00
9e4dd3fce2 v18.0.0 2024-02-06 12:19:41 +00:00
b2590136fc Merge pull request #2720 from balena-io/bump-node-20
Update to Node 20
2024-02-06 12:18:34 +00:00
bf5e61a61c Update to Node 20
Change-type: major
2024-02-05 18:29:02 -03:00
f550d0c596 v17.5.1 2024-01-31 01:05:23 +00:00
54302669b8 Merge pull request #2725 from balena-io/livepush-fix
Fix target state construction with livepush
2024-01-30 20:04:28 -05:00
a4a4e33d7b Dedupe dependencies 2024-01-30 11:17:21 -03:00
8d6a621bfb Fix target state construction with livepush
When constructing the target state after a reported change from livepush, the
handler function would not pass all build tasks to the function that
constructs the target state, causing a TypeError when trying to obtain
the target image name for each service. This updates the handler to pass
all build tasks, ensuring the information is available to construct the
target state.

Relates-to: #2724
Change-type: patch
2024-01-30 11:03:37 -03:00
4b2602676b v17.5.0 2024-01-23 15:52:54 +00:00
b0810c0f85 Merge pull request #2722 from balena-io/draft-hup
device os-update: Enable updates to pre-release versions of higher base semver
2024-01-23 17:51:54 +02:00
97a6013537 Deduplicate dependencies 2024-01-23 16:55:36 +02:00
1ba8db1459 os versions: Add the --include-draft option
Change-type: minor
2024-01-23 16:55:36 +02:00
cdada0aec8 device os-update: Add option for including pre-release versions in the list
Change-type: minor
2024-01-23 16:55:36 +02:00
1166533482 device os-update: Enable updates to pre-release versions of higher base semver
Change-type: minor
Depends-on: https://github.com/balena-io/balena-sdk/pull/1398
See: https://balena.fibery.io/Work/Task/cli-Enable-OS-Updates-to-pre-release-OS-versions-1751
2024-01-23 16:55:36 +02:00
01538728cd Update balena-sdk to 19.4.0
Update balena-sdk from 19.0.1 to 19.4.0

Change-type: minor
2024-01-23 16:55:36 +02:00
3a7f6d78b0 v17.4.12 2024-01-18 10:55:53 +00:00
dce48c90e9 Merge pull request #2719 from balena-io/revert_dockerode
Revert upgrade to dockerode to avoid regression
2024-01-18 05:54:22 -05:00
fe70d164c1 Deduplicate dependencies 2024-01-15 22:38:12 +00:00
09e2550b32 Regression described in GitHub Issue 2715; balena push hangs in
local mode.

Change-type: patch
Signed-off-by: Ken Bannister <kb2ma@runbox.com>
2024-01-15 22:05:05 +00:00
07854c3d42 v17.4.11 2024-01-05 23:01:11 +00:00
858a455501 Merge pull request #2717 from balena-io/update-oclif-patch
Mark the oclif package patch as a dev only one
2024-01-05 23:00:17 +00:00
4e5eb4bcee Exclude the oclif package patch from the published files
Change-type: patch
2024-01-06 00:25:56 +02:00
696bad3ed6 Update the @oclif/core patch
Change-type: patch
2024-01-06 00:25:34 +02:00
9a9d0f02ef Deduplicate dependencies 2024-01-06 00:25:34 +02:00
f46d00640b v17.4.10 2024-01-02 12:41:44 +00:00
e369bd3599 Merge pull request #2716 from balena-io/normalize-v-version-prefix
Normalize v prefixes in the --version parameter of all commands
2024-01-02 14:40:45 +02:00
75b29112a7 Deduplicate dependencies 2024-01-02 13:55:40 +02:00
b7b01ecd53 Normalize v prefixes in the --version parameter of all commands
Change-type: patch
2024-01-02 13:33:38 +02:00
801a25995c v17.4.9 2023-12-19 23:02:33 +00:00
8296dea78c Merge pull request #2713 from balena-io/fix-ci
Fix publishing artifacts to gh release
2023-12-19 23:01:35 +00:00
1da5a75c14 Fix publishing artifacts to gh release
Change-type: patch
2023-12-19 19:10:06 -03:00
166de57179 v17.4.8 2023-12-19 21:59:10 +00:00
85dece9e95 Merge pull request #2714 from balena-io/kyle/patch
Remove repo config from flowzone.yml
2023-12-19 21:58:24 +00:00
bfbc71215c Remove repo config from flowzone.yml
This functionality is being deprecated in Flowzone.

See: https://github.com/product-os/flowzone/pull/833

Change-type: patch
Signed-off-by: Kyle Harding <kyle@balena.io>
2023-12-19 15:20:04 -05:00
d243c14d74 v17.4.7 2023-12-19 14:26:31 +00:00
804eb27551 Merge pull request #2712 from balena-io/add-request-rerties-to-balena-deploy
deploy: Add rate-limiting aware retries for failed requests
2023-12-19 14:25:32 +00:00
4266dc6951 deploy: Add rate-limiting aware retries for failed requests
Change-type: patch
2023-12-19 01:16:42 +02:00
0ba3522584 Update dependencies
Update @balena/compose from 3.0.5 to 3.2.0

Also updates pinejs-client-request to support
using the Retry-After header and dockerode
to 3.3.5 to be aligned with @balena/compose.

Change-type: patch
2023-12-19 01:16:42 +02:00
19b0e9489d Deduplicate node modules 2023-12-19 01:16:42 +02:00
d9fed9c34c v17.4.6 2023-12-08 15:55:53 +00:00
81ee9f397f Merge pull request #2711 from balena-io/bump-oclif-core
Bump oclif core & use default missing flag handler
2023-12-08 15:54:47 +00:00
b9722c6796 Bump oclif core & use default missing flag handler
Change-type: patch
2023-12-08 12:06:54 -03:00
29ade0f696 v17.4.5 2023-12-04 14:08:31 +00:00
d5ae612513 Merge pull request #2707 from balena-io/bump-ts
Update TypeScript to 5.3.2
2023-12-04 14:07:30 +00:00
65ba63d1a8 Stop testing dependency deduplication on the custom test runners
That's since we already run that test as part of
flowzone's default "Test npm (18.x)", and the
custom tests are using the latest node & npm
version of the selected major.

Change-type: patch
2023-12-04 15:39:10 +02:00
f5ffa7d84f Temporarily pin oclif-core to ~3.11.0 to deduplicate the dependencies
Change-type: patch
2023-12-04 15:36:43 +02:00
dac3ace61d Update TypeScript to 5.3.2
Change-type: patch
2023-11-30 00:07:17 +02:00
72459a04d1 v17.4.4 2023-11-20 17:57:23 +00:00
1e83fcf1e3 Merge pull request #2706 from balena-io/fix-balena-block-create
Fix balena block create to actually create a block
2023-11-20 17:56:32 +00:00
b8769bb9e9 Fix balena block create to actually create a block
Change-type: patch
2023-11-20 13:33:35 -03:00
9f52ee8b21 v17.4.3 2023-11-17 15:39:24 +00:00
90b65cd06b Merge pull request #2683 from balena-io/bump-oclif-core-to-v3
Bump oclif-core to v3
2023-11-17 15:38:25 +00:00
72a924f00e Bump oclif-core to v3
Change-type: patch
2023-11-16 15:06:24 -03:00
e4624eda10 v17.4.2 2023-11-15 11:02:24 +00:00
4173cd82e6 Merge pull request #2697 from balena-io/vipul/automate-capitan
Automatically generate Capitano Docs configuration
2023-11-15 11:01:38 +00:00
b393f27e1b Remove authentication directory
Signed-off-by: Vipul Gupta (@vipulgupta2048) <vipulgupta2048@gmail.com>
2023-11-15 15:55:03 +05:30
1a4a0e2439 Move auth commands into command directories
Signed-off-by: Vipul Gupta (@vipulgupta2048) <vipulgupta2048@gmail.com>
2023-11-15 15:10:22 +05:30
4cd8f4c16e Docs: Generate balena auto-completion
Signed-off-by: Vipul Gupta (@vipulgupta2048) <vipulgupta2048@gmail.com>
2023-11-15 13:08:08 +05:30
2de9d526e5 Docs: Move commands to their own directories, away from their categories
Signed-off-by: Vipul Gupta (@vipulgupta2048) <vipulgupta2048@gmail.com>
2023-11-15 13:07:34 +05:30
d9427c3c59 Docs: Generate balenaCLI with automatic configuration
Signed-off-by: Vipul Gupta (@vipulgupta2048) <vipulgupta2048@gmail.com>
2023-11-15 13:07:01 +05:30
fc0cfac475 Docs: Create version command directory
Signed-off-by: Vipul Gupta (@vipulgupta2048) <vipulgupta2048@gmail.com>
2023-11-15 13:06:45 +05:30
99094dbfda Throw error if command directory rules not followed
Signed-off-by: Vipul Gupta (@vipulgupta2048) <vipulgupta2048@gmail.com>
2023-11-15 13:06:35 +05:30
0711eefb7c Update all imports to match new command directory structure
Signed-off-by: Vipul Gupta (@vipulgupta2048) <vipulgupta2048@gmail.com>
2023-11-15 13:06:19 +05:30
dc40b0d969 Docs: Move CLI commands files to command directories
Signed-off-by: Vipul Gupta (@vipulgupta2048) <vipulgupta2048@gmail.com>
2023-11-15 13:05:58 +05:30
4b5def0a8a Docs: Automatically generate Capitano configuration
Change-type: patch
Signed-off-by: Vipul Gupta (@vipulgupta2048) <vipulgupta2048@gmail.com>
2023-11-15 13:05:39 +05:30
f44fa38113 v17.4.1 2023-11-13 19:18:47 +00:00
167dfeb269 Merge pull request #2701 from balena-io/bump-shrinkwrap
Bump shrinkwrap
2023-11-13 19:17:53 +00:00
a816548bb5 Bump shrinkwrap
Change-type: patch
2023-11-13 15:43:13 -03:00
94001efc81 v17.4.0 2023-11-10 16:28:02 +00:00
8bfafe8ecc Merge pull request #2692 from bbugh/device-json
device: Add `--json` option for JSON output
2023-11-10 13:26:59 -03:00
d78045b6ab device: Add --json option for JSON output
change-type: minor
2023-11-10 12:10:53 -03:00
11eabc4b96 v17.3.2 2023-11-10 11:03:00 +00:00
bfaa91c752 Merge pull request #2700 from balena-io/update-@balena/compose-3.0.5
Update @balena/compose to 3.0.5
2023-11-10 13:02:02 +02:00
1b615e4690 Update @balena/compose to 3.0.5
Update @balena/compose from 3.0.2 to 3.0.5

Change-type: patch
2023-11-10 11:05:42 +02:00
7954e13154 v17.3.1 2023-11-09 17:26:42 +00:00
45d8872a82 Merge pull request #2699 from balena-io/pipeline
Use `pipeline` instead of `.pipe` when downloading OS image
2023-11-09 17:25:34 +00:00
56cff46408 Use pipeline instead of .pipe when downloading OS image
Change-type: patch
2023-11-09 13:38:17 -03:00
47a1a9c6af v17.3.0 2023-11-06 20:19:10 +00:00
a434a5e657 Merge pull request #2689 from mlveggo/add_device_start_stop_service
Add device start-service and stop-service commands
2023-11-06 15:18:14 -05:00
221c213791 Add device start-service and stop-service commands
Change-type: minor
2023-11-06 16:13:51 -03:00
d2150c5cb7 v17.2.4 2023-11-06 19:12:02 +00:00
70e113152d Merge pull request #2696 from balena-io/fix-dsutils
Dedupe shrinkwrap
2023-11-06 16:11:13 -03:00
4a64102d67 Dedupe shrinkwrap
Change-type: patch
2023-11-06 14:11:38 -03:00
9bf267166e v17.2.3 2023-11-03 16:34:18 +00:00
f12249bc81 Merge pull request #2694 from balena-io/vipul/add-them-docs
Generate docs for recently supported commands
2023-11-03 16:33:14 +00:00
80d6c71b02 Update CONTRIBUTING.md with docs instructions
Signed-off-by: Vipul Gupta (@vipulgupta2048) <vipulgupta2048@gmail.com>
2023-11-03 20:39:25 +05:30
9ef4117fb8 Generate docs for recently supported commands
Added documentation for `balena fleet pin` and other recently supported commands

Change-type: patch
Signed-off-by: Vipul Gupta (@vipulgupta2048) <vipulgupta2048@gmail.com>
2023-11-03 20:28:19 +05:30
25f3bf1fbe v17.2.2 2023-10-30 12:25:19 +00:00
fe65351666 Merge pull request #2672 from balena-io/bump-eslint
Bump @balena/lint
2023-10-30 12:24:13 +00:00
7d13946c3e Bump balena-lint to 7.2.1
Change-type: patch
2023-10-30 07:45:51 -04:00
1ffa8d38f1 v17.2.1 2023-10-26 21:28:48 +00:00
6914d39370 Merge pull request #2691 from balena-io/bump-balena-sdk
Update balena-sdk and deduped dependencies
2023-10-26 21:27:22 +00:00
04db9c7a91 Update balena-sdk and deduped dependencies
Update balena-sdk from 18.0.0 to 19.0.0
Update balena-preload from 14.0.3 to 15.0.1
Update balena-image-manager from 9.0.2 to 10.0.1

Change-type: patch
2023-10-26 16:27:43 -03:00
c785d01a1c v17.2.0 2023-10-20 13:45:59 +00:00
87ba364f89 Merge pull request #2685 from bbugh/add-releases-json
Add --json option to `release` and `releases`
2023-10-20 10:44:52 -03:00
b7e5915c7a release: Add '--json' option for JSON output
change-type: minor
2023-10-20 07:42:39 -05:00
0cef6b8f87 releases: Add '--json' option for JSON output 2023-10-20 08:05:36 -03:00
71f1dbd80a v17.1.7 2023-10-20 10:49:19 +00:00
36edcf0cb8 Merge pull request #2688 from balena-io/emty-string-env-tag-values
Support empty string values for `env add` and `tag set`
2023-10-20 13:48:23 +03:00
8204dcad93 tag set: Fix using empty string as a value
Change-type: patch
2023-10-20 13:11:12 +03:00
03bcb6cff7 env add: Fix using empty string as a value
Change-type: patch
2023-10-20 13:11:12 +03:00
66b6eed57c Add tests for empty & non-provided value for the env add command
Change-type: patch
2023-10-20 13:11:12 +03:00
99b0f2c022 Add tests for the tag set command
Change-type: patch
2023-10-20 13:06:39 +03:00
947a9bade7 v17.1.6 2023-10-18 18:16:11 +00:00
15ea601d68 Merge pull request #2686 from balena-io/klutchell-patch-3
Allow custom actions for external contributors
2023-10-18 18:14:54 +00:00
ce888966dd Update npm shrinkwrap
Signed-off-by: Kyle Harding <kyle@balena.io>
2023-10-18 13:04:02 -04:00
3fc6eb7a47 Allow custom actions for external contributors
Change-type: patch
2023-10-18 12:53:43 -04:00
73aebf10bf v17.1.5 2023-10-05 10:54:36 +00:00
292c372eb4 Merge pull request #2682 from balena-io/fix-ssh-service-stdin
Fix ssh ignoreStdin device argument
2023-10-05 07:53:30 -03:00
dc3261d9c7 Fix ssh ignoreStdin device argument
Change-type: patch
2023-10-05 07:05:53 -03:00
301d0ab3a0 v17.1.4 2023-09-29 12:40:52 +00:00
efe0a018d7 Merge pull request #2679 from balena-io/bump-oclif-to-latest
Bump oclif to ^3.17.1
2023-09-29 12:39:46 +00:00
fa2a232e5f Bump oclif to ^3.17.1
Change-type: patch
2023-09-28 18:35:59 -03:00
da1f022df9 v17.1.3 2023-09-26 13:58:00 +00:00
8e6a6b81d9 Merge pull request #2671 from balena-io/stop-depending-on-old-oclif-libs
Stop depending on old oclif libs and migrate to @oclif/core directly
2023-09-26 13:56:38 +00:00
77906c4152 Move to @oclif/core v2
Change-type: patch
2023-09-26 09:50:39 -03:00
26bc68753b Remove direct dependency to @oclif/config
Change-type: patch
2023-09-26 09:48:13 -03:00
af6b263f7a v17.1.2 2023-09-26 12:14:31 +00:00
a27e216e44 Merge pull request #2678 from balena-io/fix-preload-with-commit-hash
Fix preload with commit hash
2023-09-26 12:13:24 +00:00
50e1efa448 Fix preload with commit hash
Update balena-preload from 14.0.2 to 14.0.3

Change-type: patch
2023-09-26 07:45:56 -03:00
519ac0383a v17.1.1 2023-09-05 15:06:14 +00:00
3d0ef9bc4f Merge pull request #2669 from balena-io/fixes-local-flash-on-unix
Fix local flash on unix environments
2023-09-05 15:05:16 +00:00
49e23464f9 Fix local flash on unix environments
Update etcher-sdk from 8.5.3 to 8.7.0
Change-type: patch
2023-09-05 11:26:06 -03:00
a1c9b4b80e v17.1.0 2023-09-05 13:01:03 +00:00
2b1be3e5d9 Merge pull request #2647 from balena-io/update-oclif
Update oclif, improve help command
2023-09-05 08:59:52 -04:00
e46378ec51 Update oclif, improve help command
Change-type: minor
2023-09-04 21:07:05 -03:00
27ee9c85e7 v17.0.0 2023-08-29 11:45:54 +00:00
21b6ec46e3 Merge pull request #2667 from balena-io/bump-cli-to-node-v18
Update to Node 18
2023-08-29 11:44:48 +00:00
817ce5dc96 Update to Node 18
Change-type: major
2023-08-29 07:35:53 -03:00
d9af28bca7 v16.8.0 2023-08-25 17:47:44 +00:00
8646be7979 Merge pull request #2665 from balena-io/accept-device-application-keys-as-experimental-feature
Accept device & application keys on login as experimental feature
2023-08-25 17:46:52 +00:00
14ba287e0d Accept device & application keys on login as experimental feature
Change-type: minor
2023-08-23 11:12:06 -03:00
1671e46d99 v16.7.9 2023-08-22 13:33:30 +00:00
507333c463 Merge pull request #2663 from balena-io/bumps-sdk-to-v18
Update balena-sdk to v18
2023-08-22 10:32:34 -03:00
8b320d3e9e Update balena-sdk to v18
Update balena-sdk from 17.21.1 to 18.0.0
Update balena-preload from 14.0.0 to 14.0.2
Update balena-image-manager from 9.0.0 to 9.0.2
Change-type: patch
2023-08-22 09:38:39 -03:00
e1be268749 v16.7.8 2023-08-22 11:16:38 +00:00
1a0019e6d0 Merge pull request #2662 from balena-io/otaviojacobi/bumps-to-sdk-17-12-1
Update balena-sdk to ^17.12.1
2023-08-22 11:15:33 +00:00
e79cdb671f Update balena-settings-storage to 8.1.0
Update balena-settings-storage from 7.0.0 to 8.1.0
Change-type: patch
2023-08-21 14:42:28 -03:00
f38e643cf0 env: Stop fetching unnecessary app fields
Change-type: patch
2023-08-21 14:39:16 -03:00
b8e190cd1d Remove redundant envs documentation
Change-type: patch
2023-08-21 14:39:16 -03:00
9cca654bd5 Update balena-sdk to 17.12.1
Update balena-sdk from 17.8.0 to 17.12.1
Change-type: patch
2023-08-21 14:39:16 -03:00
35177e2d2f v16.7.7 2023-08-21 16:56:33 +00:00
1a24b193e7 Merge pull request #2664 from balena-io/otavio-revert-flowzone-to-master
Revert flowzone to master
2023-08-21 16:55:31 +00:00
272915192b Revert flowzone to master
Change-type: patch
2023-08-17 20:22:53 -03:00
96774f4c52 v16.7.6 2023-07-24 13:38:06 +00:00
a034f585ba Merge pull request #2656 from balena-io/fix-app-create
app create: Fix halting with a deprecation warning
2023-07-24 13:37:00 +00:00
365d95c36b app create: Fix halting with a deprecation warning
Change-type: patch
2023-07-21 10:02:32 +03:00
c6313c08ae v16.7.5 2023-07-21 06:59:22 +00:00
f5764c4659 Merge pull request #2655 from balena-io/abstract-fleet-app-block-create
Abstract the fleet/app/block create commands
2023-07-21 09:58:36 +03:00
aff094575b Abstract the fleet/app/block create commands
Change-type: patch
2023-07-20 16:14:52 +03:00
4aaaf64f8d v16.7.4 2023-07-20 10:41:09 +00:00
7b88ce273f Merge pull request #2654 from balena-io/move-discontinued-dt
move: Include fleets of discontinued device types in the fleet selection
2023-07-20 10:40:12 +00:00
b011af89ad move: Include fleets of discontinued device types in the fleet selection
Change-type: patch
2023-07-20 13:03:54 +03:00
1bf8c1bfe7 v16.7.3 2023-07-20 08:30:09 +00:00
2b39d5d111 Merge pull request #2653 from balena-io/promote-discontinued-dt
promote: Allow joining fleets of discontinued device types
2023-07-20 08:29:20 +00:00
98663af7f6 Rerun npm-shrinkwrap.json deduplication 2023-07-19 19:44:43 +03:00
5628824bee promote: Allow joining fleets of discontinued device types
Change-type: patch
2023-07-19 19:17:27 +03:00
d12d7996bc v16.7.2 2023-07-19 01:43:55 +00:00
0dcf4cbff6 Merge pull request #2650 from balena-io/bump-balena-compose
Update balena-compose to v3.0.2
2023-07-19 01:42:56 +00:00
884e37d242 Update balena-compose to v3.0.2
Update balena-compose to v3.0.2

That release removes the use of the `cachefrom` on pull tasks, which
there is good evidence to suggest is the cause of #2165

Change-type: patch
2023-07-18 18:14:56 -04:00
f4a24e26c3 v16.7.1 2023-07-18 20:27:07 +00:00
122eccf3dc Merge pull request #2652 from balena-io/update-balena-sdk-17.8.0
Update balena-sdk to 17.8.0
2023-07-18 20:26:16 +00:00
bd598788dc Update balena-sdk to 17.8.0
Update balena-sdk from 17.0.0 to 17.8.0

Change-type: patch
2023-07-18 22:48:54 +03:00
406482b4da v16.7.0 2023-07-17 19:59:52 +00:00
a381c97ca9 Merge pull request #2649 from balena-io/preload-no-pin-device-to-release
preload: Add the --no-pin-device-to-release flag to avoid interactive questions
2023-07-17 19:59:04 +00:00
8ce78ba33c Rerun npm-shrinkwrap.json deduplication 2023-07-17 11:25:02 +03:00
f53f148c89 preload: Add the --no-pin-device-to-release flag to avoid interactive questions
Change-type: minor
See: https://balena.zulipchat.com/#narrow/stream/345746-aspect.2Fproduct/topic/Level.20-.20need.20thoughts.20on.20questions.20.26.20feature.20suggestions
2023-07-17 11:19:03 +03:00
0086feb645 v16.6.6 2023-07-10 17:16:08 +00:00
4ee55b049f Merge pull request #2646 from balena-io/reduce-lodash-usage
Reduce lodash usage in common user interaction patterns
2023-07-10 17:15:14 +00:00
90c6f121cc Rerun npm-shrinkwrap.json deduplication 2023-07-10 19:36:36 +03:00
d3c27ae859 Reduce lodash usage in common user interaction patterns
Change-type: patch
2023-07-10 17:19:01 +03:00
8f39c1de6c v16.6.5 2023-07-09 21:29:55 +00:00
4df1831187 Merge pull request #2645 from balena-io/application-create-hostApp-based-supported-DTs
fleet/block/app create: Fetch the supported device types using the hostApps
2023-07-09 21:29:02 +00:00
2bce761ace Rerun npm-shrinkwrap.json deduplication 2023-07-07 20:17:53 +03:00
d78b76aceb fleet/block/app create: Fetch the supported device types using the hostApps
Change-type: patch
See: https://balena.zulipchat.com/#narrow/stream/360838-balena-io.2Fos.2Fdevices/topic/state.20field.20in.20device-type.2Ejson
See: https://balena.fibery.io/Organisation/Improvements-849#Improvements/Stop-relying-on-device-types-v1-device-type.json-for-unrelated-things-257
2023-07-07 19:57:36 +03:00
f07f6b84d4 v16.6.4 2023-07-06 13:58:27 +00:00
d297a10570 Merge pull request #2643 from balena-io/bump-balena-compose
Bump balena-compose to v2.3.0
2023-07-06 13:57:37 +00:00
9d0b82122a Bump balena-compose to v2.3.0
This allows the the CLI to use docker registry config when querying the
images manifest.

Relates-to: balena-io-modules/balena-compose#31
Change-type: patch
2023-07-05 15:46:42 -04:00
338477463a v16.6.3 2023-06-30 17:07:34 +00:00
d1275760fa Merge pull request #2641 from balena-io/drop-toolbelt
Pin dockerode and drop docker-toolbelt
2023-06-30 20:06:46 +03:00
0f4054fa4d Remove redundant dependency on docker-toolbelt
Change-type: patch
2023-06-30 19:22:07 +03:00
7545fc5d6e Pin dockerode to v3.3.3
v3.3.4 introduces a regression that is fixed by https://github.com/apocas/dockerode/pull/695 but Dockerode has not published a version that includes the fix yet. Pin the dependency to ensure we don’t ever update to a broken version.

Change-type: patch
2023-06-30 19:19:52 +03:00
a1f25809cb v16.6.2 2023-06-29 12:27:14 +00:00
e0a3c4bd95 Merge pull request #2640 from balena-io/make-apple-notarization-team-id-public
macos notarization: Expose team ID instead of keeping it in secrets
2023-06-29 12:26:27 +00:00
d843e75512 macos notarization: Expose team ID instead of keeping it in secrets
Change-type: patch
2023-06-29 07:41:07 -04:00
72c57608d5 v16.6.1 2023-06-28 12:47:56 +00:00
d9de7636db Merge pull request #2639 from balena-io/update-electron-notarize
Drop `electron-notarize` dependency in favor of `@electron/notarize`
2023-06-28 12:47:13 +00:00
10b5af6967 Drop electron-notarize dependency in favor of @electron/notarize
Change-type: patch
2023-06-28 08:01:39 -04:00
51c050c725 v16.6.0 2023-06-26 13:05:11 +00:00
eb52c47de5 Merge pull request #2631 from balena-io/add-api-key-revoke-command
api-key: Add `revoke` command which accepts a list of API key ids
2023-06-26 09:04:21 -04:00
4b1378dfbc api-key: Add revoke command which accepts a list of API key ids
Change-type: minor
2023-06-26 08:21:23 -04:00
1a77d86347 v16.5.2 2023-06-09 16:03:10 +00:00
bd5188f4b9 Merge pull request #2637 from balena-io/klutchell-patch-2
Re-enable automatic github final releases
2023-06-09 16:02:22 +00:00
034f459bfa Update npm-shrinkwrap
Signed-off-by: Kyle Harding <kyle@balena.io>
2023-06-09 11:23:49 -04:00
bc405d997e Re-enable automatic github final releases
Change-type: patch
2023-06-09 11:05:01 -04:00
af27cf2cbe v16.5.1 2023-06-02 06:30:00 +00:00
83b9bf67c2 Merge pull request #2636 from balena-io/bump-ts
Update TypeScript to 5.1.3
2023-06-02 06:29:11 +00:00
abd73b805b Update TypeScript to 5.1.3
Change-type: patch
2023-06-01 21:58:34 +03:00
37bfd4db98 v16.5.0 2023-05-25 16:45:02 +00:00
be74143d5f Merge pull request #2633 from balena-io/add-block-create-command
Add `balena block create` command for creating Blocks
2023-05-25 16:44:19 +00:00
9975e5d9ac Add balena block create command for creating Blocks
Change-type: minor
2023-05-25 12:00:39 -04:00
1341413966 v16.4.0 2023-05-25 15:53:23 +00:00
1a5b914a6f Merge pull request #2632 from balena-io/add-app-create-command
Add `balena app create` command for creatings Apps
2023-05-25 15:52:37 +00:00
c5e8f0d6ea Add balena app create command for creatings Apps
Change-type: minor
2023-05-25 11:09:02 -04:00
3a143fe413 v16.3.0 2023-05-25 15:06:39 +00:00
3445e4a08e Merge pull request #2630 from balena-io/add-command-to-list-user-api-keys
Add `balena api-keys` command for listing user API keys
2023-05-25 15:05:38 +00:00
166130c3df Add balena api-keys command for listing user/fleet API keys
Change-type: minor
2023-05-25 09:11:36 -04:00
c3a8a905f7 v16.2.7 2023-05-24 12:04:59 +00:00
2b878e87d8 Merge pull request #2629 from balena-io/less-requests-2
Fetch the application and its devices in one request in balena devices, device init, ssh, tunnel
2023-05-24 12:04:05 +00:00
063e9d40f0 device init: Avoid extra request when not providing the --fleet option
Change-type: patch
2023-05-24 14:22:04 +03:00
2b58143164 devices: Use a single request when providing the --fleet parameter
Reduces the response time when using
--fleet from 1.5s to 1s.

Change-type: patch
2023-05-24 14:22:04 +03:00
861d4f33b7 ssh,tunnel: Fetch the fleet & devices in one request
Change-type: patch
2023-05-24 14:22:04 +03:00
81f4aae7d2 v16.2.6 2023-05-24 11:17:30 +00:00
46ab335407 Merge pull request #2626 from balena-io/less-requests
Stop fetching unnecessary fields
2023-05-24 14:16:42 +03:00
07cb0cbfcd device init: Stop fetching unnecessary app fields
Change-type: patch
2023-05-24 13:37:19 +03:00
a2392dc580 device move: Stop fetching unnecessary device & app fields
Reduces the amount of device data retrieved
by 66%.

Change-type: patch
2023-05-24 13:37:19 +03:00
8b3235ab2b device register: Stop fetching unnecessary app fields
Change-type: patch
2023-05-24 13:37:19 +03:00
15dac6f194 config generate: Stop fetching unnecessary app fields
Change-type: patch
2023-05-24 13:37:19 +03:00
3c93db8449 devices: Stop fetching unnecessary device fields
Change-type: patch
2023-05-24 13:37:19 +03:00
9d8df0b781 fleet rm,restart,rename,purge: Stop fetching unnecessary app fields
Halves the amout of application data retrieved.

Change-type: patch
2023-05-24 13:37:19 +03:00
bcadbdbed8 push: Stop unnecessarily fetching the application name
Change-type: patch
2023-05-24 13:37:19 +03:00
05a96fa60e ssh,tunnel: Reduce the amount of application fields fetched
Halves the amout of application data retrieved.

Change-type: patch
2023-05-24 13:37:19 +03:00
2e37536e7a orgs: Stop fetching unnecessary org fields
Halves the amount of org data retrieved to
show the list of orgs to select from.

Change-type: patch
2023-05-24 13:37:19 +03:00
025c4ef7f2 fleet create: Reduce the amount of org fields fetched
Halves the amount of org data retrieved to
show the list of orgs to select from.

Change-type: patch
2023-05-24 13:37:19 +03:00
ecbc660bf5 Fetch only the app slug when resolving an app by name
Affects many env & tags commands, as well
as support, releases & preload.

Change-type: patch
2023-05-24 13:37:19 +03:00
ba1f17d537 v16.2.5 2023-05-24 10:30:21 +00:00
3ab8f7500e Merge pull request #2628 from balena-io/73-fix-device-init-os-initialize
Fix device int & os initialize failing to initialize the drive list
2023-05-24 13:29:36 +03:00
0a25bec010 Fix device int & os initialize failing to initialize the drive list
Resolves: #2627
Change-type: patch
2023-05-24 12:47:06 +03:00
01e765e670 v16.2.4 2023-05-23 20:31:27 +00:00
61844f2386 Merge pull request #2625 from balena-io/app-select-reduce-requests
Remove extra request when filling the application selection list
2023-05-23 20:30:32 +00:00
46aa08c953 Remove extra request when filling the application selection list
Saves one request of about 450ms on the
init and move commands.

Change-type: patch
2023-05-23 22:47:10 +03:00
b6c7fb82c3 v16.2.3 2023-05-23 19:46:47 +00:00
fcda09009a Merge pull request #2624 from balena-io/improve-typings
Use stricter typings
2023-05-23 19:46:02 +00:00
1a6fe1f3de Use stricter typings
Change-type: patch
2023-05-23 18:57:54 +03:00
98e91c0607 v16.2.2 2023-05-23 14:02:36 +00:00
bed2387d83 Merge pull request #2623 from balena-io/fix-setting-service-env-vars-by-app-name
env add: Fix accepting fleet names when setting service vars
2023-05-23 14:01:21 +00:00
50e852acee env add: Fix accepting fleet names when setting service vars
Change-type: patch
2023-05-23 15:59:41 +03:00
da30623e4e v16.2.1 2023-05-23 12:28:25 +00:00
7a46b367a7 Merge pull request #2621 from balena-io/sdk-v17
Update balena-sdk to 17.0.0
2023-05-23 12:27:29 +00:00
d9651c7393 Update balena-settings-client to 5.0.2
Change-type: patch
2023-05-23 13:22:38 +03:00
e371b1e759 Update balena-preload & balena-image-manager
Update balena-image-manager from 8.0.1 to 9.0.0
Update balena-preload from 13.0.0 to 14.0.0

Change-type: patch
2023-05-23 13:22:38 +03:00
77cf4af166 Update balena-sdk to 17.0.0
Update balena-sdk from 16.45.1 to 17.0.0

Change-type: patch
2023-05-23 13:22:38 +03:00
9d197317ca v16.2.0 2023-05-19 18:11:57 +00:00
9a8b0b4a0d Merge pull request #2619 from balena-io/alexgg/sb
os configure, config generate: Add '--secureBoot' option to opt-in secure boot
2023-05-19 18:11:02 +00:00
0c62b9ef08 Deduplicate npm-shrinkwra.json 2023-05-19 20:28:12 +03:00
83a5e7392a secureboot: Retrieve the OS release & contract in one request
Change-type: patch
2023-05-19 19:22:23 +03:00
f0c8c37022 os configure, config generate: Add '--secureBoot' option to opt-in secure boot
Allow to generate a config file with `installer.secureboot` set so that
a secure boot and disk encrypted system can be installed.

Change-type: minor
Signed-off-by: Alex Gonzalez <alexg@balena.io>
2023-05-19 18:10:00 +02:00
ba26d3204d package.json: Update balena-sdk to 16.44.2
Update balena-sdk from 16.40.0 to 16.44.2

Change-type: patch
Signed-off-by: Alex Gonzalez <alexg@balena.io>
2023-05-19 18:10:00 +02:00
d53542975e flowzone: update custom runs to use macos-12
After the flowzone update to use zstd as compression algorithm for sources
there is an error on macos-11 as tar does not support it.

Change-type: patch
Signed-off-by: Alex Gonzalez <alexg@balena.io>
2023-05-19 11:33:31 +02:00
632296a271 v16.1.0 2023-05-16 18:26:10 +00:00
3e089fcdb2 Merge pull request #2616 from balena-io/ab77/operational
build linux/arm packages
2023-05-16 18:25:27 +00:00
d61c300750 build linux/arm packages
change-type: minor
2023-05-16 10:39:00 -07:00
a0a97c5f40 v16.0.0 2023-05-16 00:02:37 +00:00
165f3b83ca Merge pull request #2618 from balena-io/node-16
Update to Node 16
2023-05-16 00:01:48 +00:00
5bf95300ee support: Change the printed support expiry date in ISO 8601 UTC format
Change-type: major
2023-05-12 19:00:10 +03:00
adb460b270 logs: Change the timestamp format to ISO 8601 UTC
Resolves: #2608
Change-type: major
2023-05-12 19:00:10 +03:00
ca80bd52fe Pin flowzone to v4.7.1
The macos-11 runners apparently do not support zst compression format as
added in flowzone 4.7.2. While support is rolled out, we can keep
the flowzone branch to the previous working version.

Change-type: patch
2023-05-11 19:10:10 -04:00
281f8abb9a Update etcher-sdk to v8.5.3
This removes the dependency on our custom fork of [node-usb](https://github.com/balena-io-modules/node-usb)
and uses the maintained building method of the official node-usb repo

Change-type: patch
2023-05-11 18:10:52 -04:00
2cf2918d73 Update vercel/pkg to v5.8.1
This seems to be needed to build the binaries for node v16 since earlier
versions failed with

```
Error: Could not detect abi for version 16.13.0 and runtime node.  Updating "node-abi" might help solve this issue if it is a new release of node
```

Change-type: patch
2023-05-11 17:49:49 -04:00
7dfb7474f5 Update to Node 16
This also drops support for Node 14

Change-type: major
2023-05-11 17:49:37 -04:00
6ee0b48c9a v15.2.3 2023-05-03 20:03:49 +00:00
bd01fbf90c Merge pull request #2614 from balena-io/local-release-uuid
Use valid release uuid for local releases
2023-05-03 20:02:59 +00:00
cd19845b6b Use valid release uuid for local releases
On local push, the CLI uses `localrelease` as the `commit` property for
the development application. This is not a valid uuid and will not be
read properly by the supervisor, as seen in

https://github.com/balena-os/balena-supervisor/blob/master/src/compose/service.ts#L652

While this is not a problem right now, the commit is becoming the main
way to identify a service release (replacing `releaseId` and `imageId`),
and the invalid release uuid could cause update issues when pushing a
local release on when using some API endpoints.

Change-type: patch
Relates-to: balena-os/balena-supervisor#2136
2023-05-03 15:08:19 -04:00
5545883c3f v15.2.2 2023-04-28 16:16:44 +00:00
75a380b0ba Merge pull request #2615 from balena-io/remove-nvmrc
Remove nvmrc
2023-04-28 16:15:57 +00:00
35fe7c6a58 Remove nvmrc
There is not a lot of benefit to using `.nvmrc` as it still requires
`nvm use`, and not everybody uses `nvm`. The call to `npm install` will
already warn about using the wrong version.

Change-type: patch
2023-04-28 10:27:15 -04:00
69249b3139 v15.2.1 2023-04-28 09:25:50 +00:00
bf897fd56d Merge pull request #2612 from balena-io/sync-tslib
Fix tslib going out of sync causing HUP to fail
2023-04-28 09:25:01 +00:00
150c6e75f5 Fix tslib going out of sync causing HUP to fail
Change-type: patch
2023-04-27 14:07:57 +03:00
e8bc43dc64 v15.2.0 2023-04-05 13:09:24 +00:00
1213689de2 Merge pull request #2606 from balena-io/update-balena-sdk-16.40.0
Add support for device restarts in open-balena
2023-04-05 13:08:14 +00:00
c1017e8e27 Add support for device restarts in open-balena
Update balena-sdk from 16.28.2 to 16.40.0

Change-type: minor
2023-04-05 12:57:33 +03:00
7ad9e685f6 v15.1.3 2023-04-05 08:06:56 +00:00
c778aaffaf Merge pull request #2607 from balena-io/update-balena-sdk-16.28.2
devices supported: Fix showing types without a valid & finalized release
2023-04-05 08:06:05 +00:00
b98047cacf devices supported: Fix showing types without a valid & finalized release
Update balena-sdk from 16.28.0 to 16.28.2

Resolves: #2524
Change-type: patch
2023-04-05 10:19:39 +03:00
03ace6e4b2 v15.1.2 2023-03-27 15:14:47 +00:00
9b4701bcb7 Merge pull request #2601 from balena-io/use-satisfies
Improve type checking by using the satisfies operator
2023-03-27 18:13:56 +03:00
174312977a Improve type checking by using the satisfies operator
Change-type: patch
2023-03-27 16:39:09 +03:00
963d9af817 v15.1.1 2023-03-17 10:20:03 +00:00
af5ec51232 Merge pull request #2600 from balena-io/bump-ts
Update TypeScript to 5.0.2
2023-03-17 12:19:13 +02:00
1cd9fbf6a0 Update TypeScript to 5.0.2
Change-type: patch
2023-03-16 20:53:08 +02:00
72639e9e59 v15.1.0 2023-03-14 20:19:08 +00:00
447dcc1480 Merge pull request #2599 from balena-io/kyle/balena-compose-v2.2.x
Update balena-compose to v2.2.1
2023-03-14 16:18:19 -04:00
564716faa7 Update balena-compose to v2.2.1
Update balena-compose from 2.1.1 to 2.2.1

Change-type: minor
Signed-off-by: Kyle Harding <kyle@balena.io>
2023-03-14 14:59:52 -04:00
3e5b4457c2 v15.0.6 2023-03-13 14:03:48 +00:00
793e70d909 Merge pull request #2597 from balena-io/explicitly-select-devices-fields
Devices: explicitly fetches only used fields
2023-03-13 11:02:51 -03:00
5761a306be Devices: explicitly fetches only used fields
Change-type: patch
2023-03-13 09:35:43 -03:00
adff0f2a0a v15.0.5 2023-03-10 16:25:40 +00:00
4ec45a0c43 Merge pull request #2596 from balena-io/fix-is-legacy-check
Fix isLegacy check which should always relay on the slug
2023-03-10 18:24:48 +02:00
ecf4b046b5 Fix application isLegacy check for rename and deploy
Change-type: patch
2023-03-10 16:33:00 +01:00
b0cae93ac9 v15.0.4 2023-02-21 07:24:19 +00:00
53b66678d4 Merge pull request #2583 from balena-io/hraftery-patch-1-1
Clarify update rate of update-notifier info
2023-02-21 09:23:30 +02:00
0b9b65ef88 patch: Clarify update rate of update notifier info
If the cli has not been run in a while, it will show old update information. It's not obvious why, and this might lead to confusion. So this commit just adds a comment to clarify that out-of-date update notifier info is expected behaviour, and why.
2023-01-26 14:15:43 +11:00
8a84d9d792 v15.0.3 2023-01-18 16:16:39 +00:00
c535b8e1ea Merge pull request #2582 from balena-io/https-npm
Use https for the npm deprecation check, avoiding a redirect
2023-01-18 16:15:01 +00:00
234fb6cd39 Use https for the npm deprecation check, avoiding a redirect
Change-type: patch
2023-01-18 13:11:31 +00:00
8714830b48 v15.0.2 2023-01-14 07:35:13 +00:00
0e07b36691 Merge pull request #2580 from balena-io/joshbwlng/fix-typo
Fix push --nolive doc typo
2023-01-14 09:33:56 +02:00
ba80d3c38c Fix push --nolive doc typo
Change-type: patch
2023-01-13 13:36:44 +09:00
e65dc82cfe v15.0.1 2023-01-10 13:43:24 +00:00
bc727521c6 Merge pull request #2571 from balena-io/nodejs-14
Update to Node 14
2023-01-10 08:41:54 -05:00
a8c0c884d3 Extra linting 2023-01-03 16:08:10 -03:00
b11c7157d3 Update to node 14 2023-01-03 16:04:24 -03:00
578de7bcd4 Process livepush build logs inline
When using livepush, the CLI parses the build logs to obtain the stage
image ids, which are necessary for properly running livepush.

This process used to store the full log output in memory before parsing
the logs for obtaining the stage ids. We have seen this cause issues
before because of the excessive memory usage and it is one the suspects
of #2165, which is blocking the update to Node 14

Change-type: patch
2023-01-03 12:29:54 -03:00
cfc6b3ce9e v15.0.0 2023-01-02 15:21:59 +00:00
1c7a354fe7 Merge pull request #2573 from balena-io/balena-preload-13
Upgrade balena-preload to 13.0.0
2023-01-02 10:20:01 -05:00
40a0941ca3 preload: Drops ability to preload Intel Edison (EOL 2017)
Upgrade balena-preload from 12.2.0 to 13.0.0

Change-type: major
Signed-off-by: Edwin Joassart <edwin.joassart@balena.io>
2023-01-02 15:34:32 +01:00
0ab4760272 v14.5.18 2022-12-29 07:20:50 +00:00
42b2269e81 Merge pull request #2576 from balena-io/flowzone-npm-ci
Update flowzone tests to use npm ci
2022-12-29 02:19:24 -05:00
c818d846b3 Update flowzone tests to use npm ci
Will also make sure that the shrinkwrap is
matching the committed package.json.

Change-type: patch
2022-12-29 08:24:24 +02:00
3328f40416 v14.5.17 2022-12-28 23:56:12 +00:00
58d10c1908 Merge pull request #2575 from balena-io/drop-balena-sync
Stop using the deprecated balena-sync module
2022-12-29 01:54:48 +02:00
2fd0ca6a02 Stop using the deprecated balena-sync module
Change-type: patch
2022-12-29 01:05:51 +02:00
173028fd0d v14.5.16 2022-12-28 23:01:25 +00:00
62d5bf4436 Merge pull request #2574 from balena-io/align-package-json-shrinkwrap
Update the npm-shrinkwrap.json dependencies to match the package.json
2022-12-29 01:00:11 +02:00
63a0d19770 Update the npm-shrinkwrap.json dependencies to match the package.json
Change-type: patch
2022-12-28 21:22:48 +02:00
8244636bf2 v14.5.15 2022-12-12 13:41:15 +00:00
6a01fb361c Merge pull request #2570 from balena-io/aethernet-preload-12.2.0
patch: update balena-preload to 12.2.0
2022-12-12 08:39:46 -05:00
ca637b3fb6 patch: update balena-preload to 12.2.0 2022-12-12 13:16:22 +01:00
006293bd01 v14.5.14 2022-12-11 21:46:38 +00:00
338b5d79d3 Merge pull request #2535 from balena-io/multicast-dns-bump
Bump multicast-dns to rebased commit (again)
2022-12-11 16:45:14 -05:00
60dd0daae5 Bump multicast-dns to rebased commit (again)
A recent PR reverted the multicast-dns commit bump from PR #2401. This means that
under some conditions, `npm install` will fail.

See: https://github.com/balena-io-modules/multicast-dns/pull/1
See: https://github.com/balena-io/balena-cli/pull/2401

Change-type: patch
2022-12-11 12:45:49 -08:00
662b8283a6 v14.5.13 2022-12-08 14:00:28 +00:00
cfc866cf41 Merge pull request #2569 from balena-io/gh-runners
Specify gh runner versions for compatibility reasons
2022-12-08 13:58:56 +00:00
e566badfff Build on macos-11 for library compatibility reasons
Change-type: patch
2022-12-08 10:58:40 +00:00
69834c417e Build on ubuntu-20.04 for library compatibility reasons
Change-type: patch
2022-12-08 10:58:25 +00:00
8aa9c62afd v14.5.12 2022-11-21 18:46:49 +00:00
4f29e37fe7 Merge pull request #2565 from balena-io/ab77/operational
Move GH publishing to FZ core
2022-11-21 18:45:25 +00:00
99e8a36bb5 Move GH publishing to FZ core
Change-type: patch
2022-11-21 09:48:09 -08:00
669cbe227f v14.5.11 2022-11-17 18:32:48 +00:00
e9156d77f1 Merge pull request #2532 from balena-io/nvmrc
Adding .nvmrc so we can use nvm use instead of hunting for version
2022-11-17 18:31:28 +00:00
767216c842 Adding .nvmrc so we can use nvm use instead of hunting for version
Change-type: patch
2022-11-16 17:54:42 -08:00
d3018f9061 v14.5.10 2022-11-11 11:24:21 +00:00
37c6ad855b Merge pull request #2557 from balena-io/surface-sdk-incompatible-dt-errors
Surface sdk incompatible dt errors
2022-11-11 11:23:05 +00:00
ca97678358 Fix surfacing incompatible device type errors as not recognized
Change-type: patch
Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
2022-11-10 16:52:14 -08:00
3bb0036ba8 v14.5.9 2022-11-11 00:49:26 +00:00
ac9e2a9e7e Merge pull request #2562 from balena-io/ab77/operational
Prevent git from existing with 141
2022-11-11 00:47:34 +00:00
52e95e6d0a Prevent git from existing with 141
Change-type: patch
2022-11-10 15:52:13 -08:00
c5d2aa7eec v14.5.8 2022-11-10 23:32:21 +00:00
683220e303 Merge pull request #2561 from balena-io/ab77/operational
Replace missing input
2022-11-10 23:30:51 +00:00
44f09b32fa Replace missing input
Change-type: patch
2022-11-10 14:33:13 -08:00
d1a0660a3d v14.5.7 2022-11-10 22:19:22 +00:00
ee1987f188 Merge pull request #2560 from balena-io/ab77/operational
Just ignore errors during publish
2022-11-10 22:17:59 +00:00
39e9997d9e Just ignore errors during publish
Change-type: patch
2022-11-10 13:22:29 -08:00
97b8c75043 v14.5.6 2022-11-10 21:07:35 +00:00
7cb8349f29 Merge pull request #2559 from balena-io/ab77/operational
Ignore PIPE signal
2022-11-10 21:06:18 +00:00
6063f4c776 Ignore PIPE signal
Change-type: patch
2022-11-10 12:13:03 -08:00
4899d545f1 v14.5.5 2022-11-10 20:07:12 +00:00
115bf6433d Merge pull request #2558 from balena-io/ab77/operational
Don't pipefail
2022-11-10 20:05:33 +00:00
e5ce1ade89 Don't pipefail
Change-type: patch
2022-11-10 11:13:37 -08:00
9c4174ea8a v14.5.4 2022-11-10 18:31:21 +00:00
cf16957195 Merge pull request #2556 from balena-io/2537-error-on-incompatible-resolved-device-types
Error when the device type and image parameters do not match
2022-11-10 18:30:05 +00:00
4de369ff95 Error when the device type and image parameters do not match
Resolves: #2537
Change-type: patch
Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
2022-11-10 09:37:22 -08:00
ac3ebff8ee v14.5.3 2022-11-10 17:20:19 +00:00
76b01d92d3 Merge pull request #2555 from balena-io/ab77/operational
Switch to Flowzone
2022-11-10 17:18:49 +00:00
19144163ee Switch to Flowzone
Change-type: patch
2022-11-08 20:56:47 -08:00
535ffccbad v14.5.2 2022-10-21 20:15:35 +03:00
6f5ada9692 Merge pull request #2553 from balena-io/stop-waiting-for-the-analytics-response
Stop waiting for the analytics response
2022-10-21 17:09:08 +00:00
1c7d9255ae Stop waiting for the analytics response
Change-type: patch
See: https://balena.zulipchat.com/#narrow/stream/345884-aspect.2Fanalytics/topic/Balena.20CLI.20analytics-performance
Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
2022-10-21 19:07:39 +03:00
807e6ea2ad v14.5.1 2022-10-21 15:48:13 +03:00
c76f019fd0 Merge pull request #2552 from balena-io/bump-parse-link-header-2.0.0
Bump parse-link-header from 1.0.1 to 2.0.0
2022-10-21 12:45:48 +00:00
3c2c925eed Bump parse-link-header from 1.0.1 to 2.0.0
Bumps [parse-link-header](https://github.com/thlorenz/parse-link-header) from 1.0.1 to 2.0.0.
- [Release notes](https://github.com/thlorenz/parse-link-header/releases)
- [Commits](https://github.com/thlorenz/parse-link-header/compare/v1.0.1...v2.0.0)

---
updated-dependencies:
- dependency-name: parse-link-header
  dependency-type: direct:development
...

Change-type: patch
Signed-off-by: dependabot[bot] <support@github.com>
2022-10-20 20:10:53 +03:00
14b54be15e v14.5.0 2022-10-18 15:17:13 +03:00
7fb82f7447 Merge pull request #2539 from balena-io/send-tracking-to-analytics-backend
changes analytics endpoint to analytics-backend
2022-10-18 12:14:05 +00:00
4a5d44a0f1 Merge branch 'master' into send-tracking-to-analytics-backend 2022-10-18 08:15:33 -03:00
1cba0284df v14.4.4 2022-10-18 13:36:52 +03:00
6e4fe229bf Merge pull request #2546 from balena-io/update-simple-git
Update simple git
2022-10-18 10:33:17 +00:00
7033075900 Update simple-git to 3.14.1
Change-type: patch
Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
2022-10-18 09:45:24 +03:00
ded268ff3c automation/check-doc: Convert to typescript 2022-10-18 09:45:24 +03:00
a366f0b7eb automation/check-doc: Rename to .ts 2022-10-18 09:45:24 +03:00
507c8a1bfd v14.4.3 2022-10-18 00:24:29 +03:00
1fb46bfa5d Merge pull request #2545 from balena-io/config-generate-incompatible-dt-error
config generate: Fix the incompatible arch errors showing as not found
2022-10-17 21:20:21 +00:00
2e115968d5 config generate: Fix the incompatible arch errors showing as not found
Change-type: patch
Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
2022-10-17 23:44:08 +03:00
83020797b0 v14.4.2 2022-10-17 21:15:25 +03:00
0c4647e980 Merge pull request #2544 from balena-io/no-device-type-json-arch-aliases
Stop relying on device-type.json for resolving the cpu architecture
2022-10-17 18:06:05 +00:00
a20d2a04a8 Stop relying on device-type.json for resolving the device type aliases
Resolves: #2541
Change-type: patch
Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
2022-10-17 19:09:09 +03:00
57b0dccc7d Stop relying on device-type.json for resolving the cpu architecture
Resolves: #2542
Change-type: patch
Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
2022-10-17 19:09:09 +03:00
d1e3bdf29a keeps events loggiging with default message
change-type: minor
2022-10-17 10:07:51 -03:00
bdf7fedd7a uses amplitude data events format
Change-type: minor
2022-10-14 10:50:12 -03:00
c163662f4a changes analytics endpoint to analytics-backend
change-type: minor
2022-10-13 19:32:55 -03:00
a2823fd3ec v14.4.1 2022-10-12 18:19:30 +03:00
d717352b84 Merge pull request #2530 from balena-io/hraftery-patch-1
Add to description that command is device specific
2022-10-12 14:59:41 +00:00
e46902e683 balena os initialize: Clarify that the process includes flashing
Change-type: patch
2022-10-12 16:45:16 +03:00
e96ef6697e v14.4.0 2022-10-12 16:37:05 +03:00
6f54197b7b Merge pull request #2533 from balena-io/2531-device-register-dt-param
device register: Add support for the `--deviceType` option
2022-10-12 13:31:08 +00:00
34b4ac2d9f device register: Add support for the --deviceType option
Resolves: #2531
Change-type: minor
Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
2022-10-12 11:15:00 +03:00
f99244603a Update balena-sdk to 16.28.0
Update balena-sdk from 16.22.0 to 16.28.0

Change-type: patch
Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
2022-10-12 11:15:00 +03:00
523c0af0fb v14.3.1 2022-09-06 08:49:41 -04:00
2206b475c6 Merge pull request #2526 from balena-io/unified-os-release-examples
Add unified OS versions in the examples of the device & os commands
2022-09-06 12:48:06 +00:00
a117dc0382 Add unified OS versions in the examples of the device & os commands
Change-type: patch
Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
2022-09-06 13:26:26 +03:00
cf3e8ff909 v14.3.0 2022-08-17 15:26:40 +03:00
36d1af1e33 Merge pull request #2523 from balena-io/add-release-validate-and-invalidate-commands
release: Add `invalidate` and `validate` commands for invalidating and validating releases (respectively)
2022-08-17 12:24:14 +00:00
18f83092fe v14.2.0 2022-08-16 23:32:01 +03:00
ee3c796787 Merge pull request #2522 from balena-io/add-fleet-pin-and-track-latest-commands
Add fleet `pin` and `track-latest` commands
2022-08-16 20:29:51 +00:00
934c3ddf38 release: Add validate command for validating releases
Change-type: minor
Signed-off-by: Matthew Yarmolinsky <matthew-timothy@balena.io>
2022-08-15 19:44:54 +00:00
66e6daf78c release: Add invalidate command for invalidating releases
Change-type: minor
Signed-off-by: Matthew Yarmolinsky <matthew-timothy@balena.io>
2022-08-15 19:41:25 +00:00
97eb107de4 fleet: Add track-latest command for tracking the latest release
Change-type: minor
Signed-off-by: Matthew Yarmolinsky <matthew-timothy@balena.io>
2022-08-15 15:34:54 -04:00
def205f1fb fleet: Add pin command for pinning fleets to a specific release
Change-type: minor
Signed-off-by: Matthew Yarmolinsky <matthew-timothy@balena.io>
2022-08-15 15:06:10 -04:00
5c8f78678b v14.1.0 2022-08-04 17:52:53 +04:00
769f1ca5b4 Merge pull request #2493 from balena-io/add-device-track-command
Add device track command
2022-08-04 13:51:04 +00:00
cb26a736fc Add device track command for pinning a device to the latest release or a specific release
Change-type: minor
Signed-off-by: Matthew Yarmolinsky <matthew-timothy@balena.io>
2022-08-03 14:42:25 -04:00
d28847d5aa v14.0.0 2022-08-02 19:08:30 +04:00
c0902bb119 Merge pull request #2514 from balena-io/v14
Release v14
2022-08-02 15:05:58 +00:00
26aae0afab v13.10.1 2022-08-02 02:07:46 +04:00
5f3cf75c1a Merge pull request #2516 from balena-io/2515-fix-balena-deploy-jsesc-dependency
Fix balena deploy missing dependency error
2022-08-01 22:05:55 +00:00
8a7fbdb55d Drop undocumented support for numeric ids in balena device commands
Change-type: major
Signed-off-by: Matthew Yarmolinsky <matthew-timothy@balena.io>
2022-08-01 18:52:30 +00:00
b260f80bcc Drop support for the deprecated balena device public-url <enable|disable|status> <uuid> and related format
Resolves: #2501
Change-type: major
Signed-off-by: Matthew Yarmolinsky <matthew-timothy@balena.io>
2022-08-01 18:52:30 +00:00
9ec37975f3 Drop support for numeric fleet id parameters from all commands
Resolves: #2500
Change-type: major
Signed-off-by: Matthew Yarmolinsky <matthew-timothy@balena.io>
2022-08-01 18:52:25 +00:00
73c487c2f5 Fix balena deploy missing dependency error
Resolves: #2515
Change-type: patch
Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
2022-08-01 19:35:07 +03:00
3cb35ea318 fleet: Add --filter, --no-header, --no-truncate, and --sort options
Resolves: #2503
Change-type: minor
Signed-off-by: Matthew Yarmolinsky <matthew-timothy@balena.io>
2022-08-01 15:35:13 +00:00
efe6fd22ce fleet: Add --fields and --json options
Change-type: minor
Signed-off-by: Matthew Yarmolinsky <matthew-timothy@balena.io>
2022-08-01 15:35:13 +00:00
6ee8d8a899 fleet: Use the oclif output formatter
Change-type: major
Signed-off-by: Matthew Yarmolinsky <matthew-timothy@balena.io>
2022-08-01 15:35:13 +00:00
c735f13636 config: Drop optional and ignored --type flag
Change-type: patch
Signed-off-by: Matthew Yarmolinsky <matthew-timothy@balena.io>
2022-08-01 15:35:13 +00:00
edb0fdc3c1 Drop deprecated --logs flag
Resolves: #2499
Change-type: major
Signed-off-by: Matthew Yarmolinsky <matthew-timothy@balena.io>
2022-08-01 15:35:13 +00:00
14a07ac7f7 Drop support for open-balena-api < v0.131.0
Resolves: #2502
Change-type: major
Signed-off-by: Matthew Yarmolinsky <matthew-timothy@balena.io>
2022-08-01 15:35:13 +00:00
264cd94be5 v13.10.0 2022-07-20 12:25:47 +00:00
2664f4e7fb Merge pull request #2504 from balena-io/add-device-view-option
Add `--view` flag to `device` command for opening a device's dashboard page
2022-07-20 12:23:37 +00:00
3ce2653881 v13.9.0 2022-07-19 12:03:18 +03:00
719860366f Merge pull request #2476 from balena-io/switch-to-compose
Switch to balena-compose
2022-07-19 08:58:59 +00:00
21ded85c7a v13.8.0 2022-07-18 22:55:10 +03:00
c91f67d27e Merge pull request #2505 from balena-io/add-note-option-for-push-and-deploy
Add `--note` option for `push` and `deploy`
2022-07-18 18:26:43 +00:00
18eedfec7f Add --note option for push and deploy
Change-type: minor
Signed-off-by: Matthew Yarmolinsky <matthew-timothy@balena.io>
2022-07-14 15:44:55 -04:00
1fe0480a8a Add --view flag to device command for opening a device's dashboard page
Change-type: minor
Signed-off-by: Matthew Yarmolinsky <matthew-timothy@balena.io>
2022-07-14 18:56:51 +00:00
c7f56d92dd Switch to balena-compose
Removes a bunch of individual dependencies by switching to `@balena/compose` which (currently) groups and manages those dependencies together in one package.

Change-type: minor
2022-07-14 13:05:21 +00:00
a92f58134f v13.7.1 2022-07-13 10:50:45 +03:00
cc6a8ef76e Merge pull request #2498 from balena-io/2462-bump-image-manager
os download: Fix resolving to draft releases
2022-07-13 07:48:41 +00:00
88f4a3d88e os download: Fix resolving to draft releases
Resolves: #2462
Change-type: patch
Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
2022-07-13 10:14:30 +03:00
f6d668684a v13.7.0 2022-07-07 11:01:22 +03:00
be7c0dc897 Merge pull request #2496 from balena-io/add-fleet-view-command
Add `--view` flag to `fleet` command for opening a fleet's dashboard page
2022-07-07 07:58:02 +00:00
566b7f97e0 Add --view flag to fleet command for opening a fleet's dashboard page
Change-type: minor
Signed-off-by: Matthew Yarmolinsky <matthew-timothy@balena.io>
2022-07-05 13:14:18 -04:00
f55dd81a19 v13.6.1 2022-06-13 21:40:58 +03:00
dba5349390 Merge pull request #2491 from balena-io/update-balena-sdk-16.22.0
Update balena-sdk to use the native OS release phase & variant fields
2022-06-13 17:25:54 +00:00
6a8dfcc664 Update balena-sdk to use the native OS release phase & variant fields
Update balena-sdk from 16.20.4 to 16.22.0

Change-type: patch
2022-06-09 17:51:55 +03:00
59e35d866f v13.6.0 2022-06-07 17:44:48 +03:00
9235c928f1 Merge pull request #2490 from balena-io/kyle/qemu-v7.0.0
Update QEMU to v7.0.0
2022-06-07 14:38:37 +00:00
3d88f0144a Update QEMU to v7.0.0
Change-type: minor
Signed-off-by: Kyle Harding <kyle@balena.io>
2022-06-06 14:56:10 -04:00
a6b461ba91 v13.5.3 2022-05-31 13:31:31 +03:00
b96da951db Merge pull request #2485 from balena-io/drop-needspasswordreset
Drop the needsPasswordReset property from the tests
2022-05-31 10:26:22 +00:00
8235cead07 Drop the needsPasswordReset property from the tests
Change-type: patch
See: https://github.com/balena-io/balena-api/pull/3665
2022-05-31 12:46:49 +03:00
30b9d9141d v13.5.2 2022-05-31 12:34:18 +03:00
03b41d9989 Merge pull request #2486 from balena-io/npm-dd
Deduplicate npm-shrinkwrap.json
2022-05-31 09:28:29 +00:00
aab3af2153 Deduplicate npm-shrinkwrap.json
Change-type: patch
Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
2022-05-31 11:46:49 +03:00
600457de61 v13.5.1 2022-05-27 02:21:54 +03:00
17db857e10 Merge pull request #2483 from balena-io/bump-preload-to-v3
Bump balena-preload to 12.1.0
2022-05-26 23:20:10 +00:00
eb45ae2a30 preload: Fix issue where balenaOS v2.98.3+ required an Internet connection to start apps
Devices with a v13+ supervisor will fail to start preloaded apps with a
v2 target state format if connectivity is not available since migration
of apps.json is not possible without API access.

This enables support for preloading v3 target state format in
images with supervisor v13 or above.

Change-type: patch
2022-05-26 20:48:07 +00:00
2eaf70bff3 v13.5.0 2022-05-25 15:01:45 +03:00
226f45f732 Merge pull request #2482 from balena-io/key-expiry
Add provisioning key expiry date option to config generate options
2022-05-25 11:59:06 +00:00
c4990f3a26 Update balena-sdk to 16.20.4
Update balena-sdk from 16.9.0 to 16.20.4

Change-type: patch
2022-05-24 21:53:12 +05:30
0195a3b18c Add provisioning key expiry date option to config generate options
Change-Type: minor
Signed-off-by: Nitish Agarwal <1592163+nitishagar@users.noreply.github.com>
2022-05-22 21:50:48 +05:30
3d90aeb122 v13.4.3 2022-05-19 21:10:42 +03:00
0571039bfe Merge pull request #2481 from balena-io/update-docker-progress
Update docker-progress to 5.1.3
2022-05-19 17:56:34 +00:00
ee668a4c5c Update docker-progress to 5.1.3
Update docker-progress from 5.0.1 to 5.1.3

Change-type: patch
2022-05-18 15:01:27 +01:00
ead4dbfab1 v13.4.2 2022-05-10 21:02:45 +03:00
0b498d09df Merge pull request #2479 from balena-io/kyle/balena-preload
preload: Fix detection of supervisor version for balenaOS v2.93.0
2022-05-10 17:08:59 +00:00
2b2c40c22d preload: Fix detection of supervisor version for balenaOS v2.93.0
Update balena-preload from 12.0.0 to 12.0.1

Change-type: patch
Signed-off-by: Kyle Harding <kyle@balena.io>
2022-05-10 11:29:14 -04:00
ba3a3865b5 v13.4.1 2022-04-29 04:45:30 +03:00
f8402bc40c Merge pull request #2444 from balena-io/balena-leave-clearer-message
patch: Tell user that balena leave command does not remove the device…
2022-04-11 16:33:26 +00:00
c667ffa8eb leave: Update log message to advise that device still needs deleting
Change-type: patch
2022-04-11 17:04:45 +01:00
6d6065ddf5 v13.4.0 2022-04-11 17:18:27 +03:00
44f55f8e7b Merge pull request #2473 from balena-io/2337-support-all-valid-sermer-on-releases
deploy: Support all valid semver versions in balena.yml
2022-04-11 14:05:16 +00:00
d2c77760b3 deploy: Support all valid semver versions in balena.yml
Resolves: #2337
Change-type: minor
Depends-on: https://github.com/balena-io/open-balena-api/pull/982
Depends-on: https://github.com/balena-io/balena-api/pull/3584
See: https://jel.ly.fish/product-improvement-draft-releases-and-release-versioning-d0391f45-c2f9-4f4e-b964-1a7e9023a3f4
Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
2022-04-08 18:16:45 +03:00
7496710c85 v13.3.3 2022-04-08 14:39:33 +03:00
be6a468507 Merge pull request #2471 from balena-io/patches-contributing
Document the 'patches' folder in CONTRIBUTING.md
2022-04-08 11:36:49 +00:00
88835e63bd Document the 'patches' folder in CONTRIBUTING.md
Change-type: patch
2022-04-08 01:16:28 +01:00
3572cb3cd6 v13.3.2 2022-04-07 13:25:31 +03:00
7fbd1de063 Merge pull request #2470 from balena-io/2469-build-docker-tls
build: Ensure HTTPS is used with dockerPort 2376 or with ca/cert/key
2022-04-07 10:22:54 +00:00
a4ab07cd08 Skip Alpine tests until Concourse + Alpine v3.14 issues are resolved
See:
* https://github.com/concourse/concourse/issues/7905
* https://github.com/product-os/balena-concourse/issues/631
* https://github.com/product-os/ci-images/pull/116/files#r844508619

Change-type: patch
2022-04-07 00:29:55 +01:00
9185eaa2b7 build: Ensure HTTPS is used with dockerPort 2376 or with ca/cert/key
Change-type: patch
2022-04-07 00:14:03 +01:00
ff3abe1fba v13.3.1 2022-03-08 22:33:20 +02:00
1ac3b70b81 Merge pull request #2463 from balena-io/update-notifier-release-notes
Include link to Wiki release notes in version update notifications
2022-03-08 20:31:39 +00:00
e946178953 Include link to Wiki release notes in version update notifications
Change-type: patch
2022-03-08 18:25:08 +00:00
6589589bee v13.3.0 2022-03-01 00:35:10 +02:00
6ae598b55e Merge pull request #2461 from balena-io/2458-ssh-ipaddr-service
ssh: Allow ssh to service with IP address and production balenaOS image
2022-02-28 22:33:02 +00:00
915f7e3763 ssh: Allow ssh to service with IP address and production balenaOS image
Also remove 'balena ssh' dependency on the device supervisor (that may
be down because of device issues or a supervisor bug) when opening a
ssh shell on a container (#1560).

Resolves: #2458
Resolves: #1560
Change-type: minor
2022-02-28 21:39:49 +00:00
cd17d79067 ssh: Advise use of 'balena login' if root authentication fails
Change-type: patch
2022-02-24 21:48:40 +00:00
7e4f4392e9 v13.2.1 2022-02-24 23:45:39 +02:00
3c0e998616 Merge pull request #2460 from balena-io/uuid-log
Correctly use the device uuid when logging the tunnel target
2022-02-24 21:43:28 +00:00
bd1bf8153d Remove unnecessary fetch of device info in balena tunnel
Change-type: patch
2022-02-24 21:02:27 +00:00
f2528dcd18 Correctly use the device uuid when logging the tunnel target
The "vpn address" is only relevant on the device/vpn server themselves
and makes no sense from a CLI context as it uses the uuid to specify
the target

Change-type: patch
2022-02-24 21:00:58 +00:00
ec26433925 v13.2.0 2022-02-18 23:40:57 +02:00
43cddd2e5d Merge pull request #2457 from balena-io/2292-ssh-username
ssh: Attempt cloud username if 'root' authentication fails
2022-02-18 21:38:27 +00:00
eeb2be2912 ssh: Attempt cloud username if 'root' authentication fails
Also refactor several files to avoid code duplication.

Change-type: minor
2022-02-12 02:40:35 +00:00
3bf8befb1d Replace occurrence of through2 dependency with standard stream module
Change-type: patch
2022-02-11 17:04:32 +00:00
948095ce4d Refactor cached username logic from events.ts to bootstrap.ts for reuse
Change-type: patch
2022-02-11 15:23:36 +00:00
d2330f9ed1 v13.1.13 2022-02-10 14:29:18 +02:00
cc19b00998 Merge pull request #2455 from balena-io/lucianbuzzo/drop-unused-fn-awaitdevice
Drop unused awaitDevice utility function
2022-02-10 12:27:25 +00:00
ed5ac75a10 v13.1.12 2022-02-09 09:24:17 +02:00
465b8a1b5e Merge pull request #2451 from balena-io/bump-preload-v12
Update balena-preload to v12
2022-02-09 07:22:04 +00:00
eccadbdcb9 Drop unused awaitDevice utility function
Change-type: patch
Signed-off-by: Lucian Buzzo <lucian.buzzo@gmail.com>
2022-02-01 17:43:28 +00:00
31eb734af1 Update balena-preload to v12
Update balena-preload from 11.0.0 to 12.0.0

Change-type: patch
Changelog-entry: preload: Stop using the deprecated /device-types/v1 API endpoints
Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
2022-01-27 19:27:58 +02:00
fa7b59d64f v13.1.11 2022-01-20 01:55:52 +02:00
1e42bfa0d5 Merge pull request #2450 from balena-io/types-node-v12
chore: Update @types/node to v12.20.42
2022-01-19 23:53:08 +00:00
5464e550e7 chore: lib/auth/utils.ts: Replace deprecated url.resolve, use async/await
Change-type: patch
2022-01-19 22:48:46 +00:00
c0f27a663d chore: Update @types/node to v12.20.42
Change-type: patch
2022-01-19 22:48:46 +00:00
d1c61c62ab v13.1.10 2022-01-16 21:29:44 +02:00
a9691bff57 Merge pull request #2446 from balena-io/2445-min-node-version-12.8.0
Update docs and package.json re min Node.js supported version (12.8.0)
2022-01-16 19:27:33 +00:00
f5d09a43cd Update docs and package.json re min Node.js supported version (12.8.0)
Resolves: #2445
Change-type: patch
2022-01-16 18:44:45 +00:00
d11e547e11 v13.1.9 2022-01-14 03:00:53 +02:00
bd462aee02 Merge pull request #2443 from balena-io/colors-action
Update packages in response to colors package issues
2022-01-14 00:58:59 +00:00
f633c0468b Update packages in response to colors package issues
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2022-01-12 22:12:06 +01:00
e4f61a1242 v13.1.8 2022-01-11 03:28:31 +02:00
96142a002e Merge pull request #2442 from balena-io/2440-pin-docker-modem
local push: Fix "invalid character '/' looking for beginning of value"
2022-01-11 01:26:51 +00:00
6b9a5cd89c local push: Fix "invalid character '/' looking for beginning of value"
Change-type: patch
2022-01-11 00:15:10 +00:00
ba2d3d60ec Merge pull request #2441 from balena-io/v14-TypeError-type-undefined
v14 preparations: Fix TypeError produced by 'npx oclif manifest'
2022-01-08 01:55:40 +00:00
d1e66bc1a5 v14 preparations: Fix TypeError produced by 'npx oclif manifest'
Change-type: patch
2022-01-08 01:16:45 +00:00
58799915a9 v13.1.7 2022-01-06 19:29:35 +02:00
5f2d55f569 Merge pull request #2436 from balena-io/update-pkg
Update to pkg 5
2022-01-06 17:27:47 +00:00
8d6e51391c v13.1.6 2022-01-04 18:53:40 +02:00
8454b02988 Merge pull request #2435 from balena-io/enforce-js-types
Automation: enforce noImplicitAny for the type-checked javascript
2022-01-04 16:51:05 +00:00
879d98ef98 Update to pkg 5
Change-type: patch
2022-01-04 16:31:08 +00:00
c4e317a290 Automation: enforce noImplicitAny for the type-checked javascript
Change-type: patch
2022-01-04 16:27:06 +00:00
7ca4d2d720 v13.1.5 2022-01-04 17:34:55 +02:00
e1e88ec56d Merge pull request #2434 from balena-io/remove-gulp
Build: switch from using inline-source via gulp to using it directly
2022-01-04 15:33:01 +00:00
33f7fa3829 Build: switch from using inline-source via gulp to using it directly
Change-type: patch
2022-01-04 15:03:05 +00:00
3d516e7c5f v13.1.4 2022-01-04 13:25:57 +02:00
a8507508b7 Merge pull request #2428 from balena-io/update-pkg
Update pkg
2022-01-04 11:24:14 +00:00
008972b3d3 Update pkg
Change-type: patch
2022-01-03 17:35:13 +00:00
92b86330a0 v13.1.3 2022-01-03 18:52:42 +02:00
2563c07c6a Merge pull request #2433 from balena-io/ts-deploy-legacy
Convert lib/utils/deploy-legacy to typescript
2022-01-03 16:50:06 +00:00
1d4b949cf3 Convert lib/utils/deploy-legacy to typescript
Change-type: patch
2022-01-03 16:10:17 +00:00
d17e02a930 v13.1.2 2022-01-03 18:03:55 +02:00
a355cbaa79 Merge pull request #2432 from balena-io/compose-ts
Convert lib/utils/compose to typescript
2022-01-03 16:01:18 +00:00
bd021c0a2d Convert lib/utils/compose to typescript
Change-type: patch
2022-01-03 15:26:19 +00:00
a80f676804 v13.1.1 2021-12-30 15:08:14 +02:00
f723c58089 Merge pull request #2430 from balena-io/update-deps
Update dependencies
2021-12-30 13:05:58 +00:00
e27a4e2e31 Update dependencies
Update docker-progress from 5.0.0 to 5.0.1

Change-type: patch
2021-12-30 12:36:12 +00:00
b91b72c408 v13.1.0 2021-12-29 16:47:51 +02:00
5cf84d3f1d Merge pull request #2431 from balena-io/os-configure-dev-flag
os.getConfig MVP (os configure, config generate, local configure)
2021-12-29 14:45:46 +00:00
7d58b8c120 os configure, config generate: Add '--dev' option for OS developmentMode
Change-type: minor
2021-12-29 00:28:04 +00:00
851301a336 local configure: Allow configuring 'developmentMode' in config.json
Change-type: minor
2021-12-25 02:26:52 +00:00
ec6fd050f6 os build-config: Clarify command purpose in help output
Change-type: patch
2021-12-25 02:26:47 +00:00
6f81053882 device os-update: Add support for unified dev/prod balenaOS releases
Update balena-sdk from 16.8.1 to 16.9.0

Change-type: minor
2021-12-24 23:52:57 +00:00
dbd8a9a08c v13.0.2 2021-12-24 20:12:14 +02:00
256f1abf1b Merge pull request #2427 from balena-io/update-oclif
Update oclif
2021-12-24 18:10:10 +00:00
acd352cb3c Update oclif
Change-type: patch
2021-12-24 17:20:50 +00:00
31f927c27c v13.0.1 2021-12-24 18:58:28 +02:00
3d0f16168a Merge pull request #2429 from balena-io/os-versions-recommended
os versions, os download: Replace deprecated version fields
2021-12-24 16:55:58 +00:00
b2d932afab os versions, os download: Replace deprecated version fields
Replace deprecated `rawVersion` and `formattedVersion` fields and use
alternative overload of `getAvailableOsVersions`. As a result, the word
'recommended' is no longer printed next to any OS versions.

Change-type: patch
2021-12-24 16:01:51 +00:00
398175f0b3 Update balena-sdk to v16.8.1
Update balena-sdk from 16.8.0 to 16.8.1

Change-type: patch
2021-12-24 14:45:12 +00:00
2fb9c6c773 v13.0.0 2021-12-23 21:48:02 +02:00
66608b32e9 Merge pull request #2420 from balena-io/v13
Release CLI v13
2021-12-23 19:45:50 +00:00
c403683edf v13 RELEASE NOTES: see https://git.io/JDHxG
Change-type: patch
2021-12-23 18:47:34 +00:00
1e6ab46ca3 Add tips for removed commands
Signed-off-by: Scott Lowe <scott@balena.io>
2021-12-23 18:40:05 +00:00
02d3220f2d Fix some app/fleet terminology issues
Signed-off-by: Scott Lowe <scott@balena.io>
2021-12-23 18:40:05 +00:00
c86cdc8f84 balena SDK v16: Ensure all SDK calls use fleet slug rather than name
Change-type: patch
2021-12-23 18:40:05 +00:00
84f02dc063 Update balena-sdk to v16.8.0
Update balena-sdk from 15.51.1 to 16.8.0

Change-type: patch
2021-12-23 18:40:05 +00:00
9145f2fb28 device, devices: Print the fleet's slug in 'org/fleetName' format
Change-type: major
2021-12-23 15:34:09 +00:00
1164388d78 envs: Print the fleet's slug in 'org/fleetName' format
Change-type: major
2021-12-23 15:34:08 +00:00
06f6094401 os configure: Remove deprecated '--device-api-key' option
Change-type: major
2021-12-23 15:34:08 +00:00
67e11467f7 Clean up unused v13 feature switch code
Change-type: patch
2021-12-23 15:34:08 +00:00
c8dfd0ca65 config read/write/inject/reconfigure: Place '--type' option behind v14 switch
Change-type: patch
2021-12-23 15:34:08 +00:00
8b110a835a fleet create: Don't print fleet's numeric database ID in confirmation msg
Change-type: major
2021-12-23 15:34:08 +00:00
7564d95f82 devices supported: Remove deprecated '--verbose' and '--discontinued' options
Change-type: major
2021-12-23 15:34:08 +00:00
f12f2b79ef build/deploy/push: Remove deprecated '--convert-eol' option
Change-type: major
2021-12-23 15:34:08 +00:00
176d731f9e Move some v13 features behind v14 switch.
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2021-12-23 15:34:08 +00:00
1ed39d1d37 Remove deprecated '--app' and '--application' options (renamed to '--fleet')
Change-type: major
2021-12-23 15:34:08 +00:00
580ca0d584 Remove deprecated commands 'app' and 'apps' (renamed to 'fleet' and 'fleets')
Change-type: major
2021-12-23 15:34:08 +00:00
73572df7cf build/deploy/push: Remove deprecated '--[no]gitignore' option
Change-type: major
2021-12-23 15:34:08 +00:00
23b42b1a2b v13 release: Flip the v13 feature switch
Change-type: major
2021-12-23 15:34:08 +00:00
632322e3c2 v13 release: Drop support for Node.js v10 (package.json engines.node)
Change-type: major
2021-12-23 15:34:08 +00:00
4faa5d7f57 v12.55.11 2021-12-23 17:19:56 +02:00
9b967592a9 Merge pull request #2426 from balena-io/typescript-4.5
Update to typescript 4.5
2021-12-23 15:18:13 +00:00
e01483cd2b Update to typescript 4.5
Change-type: patch
2021-12-23 13:59:42 +00:00
6d89ff4bbf v12.55.10 2021-12-23 15:04:02 +02:00
126e731117 Merge pull request #2423 from balena-io/update-dev-deps
Update dev dependencies
2021-12-23 13:01:42 +00:00
32d26ad074 v12.55.9 2021-12-22 18:02:30 +02:00
2bcfec9d0f Merge pull request #2413 from balena-io/os-download-prod-suffix-revisited
os download: Future-proof unified dev/prod balenaOS versioning
2021-12-22 16:00:49 +00:00
c04e63ab7d os download: Future-proof '--version' format for unified dev/prod variants
Do not append the '.prod' suffix by default to balenaOS versions.

Change-type: patch
2021-12-22 15:37:24 +00:00
79be06820c Update dev dependencies
Change-type: patch
2021-12-21 18:24:26 +00:00
ffb94c380f v12.55.8 2021-12-21 18:59:32 +02:00
385b5e9ec6 Merge pull request #2422 from balena-io/windows-version-info
Include version info when installed on windows
2021-12-21 16:55:54 +00:00
8d3a4343cb Include version info when installed on windows
Change-type: patch
2021-12-21 16:22:21 +00:00
6eeb16245b Switch from the deprecated oclif-dev commands to the oclif commands
Change-type: patch
2021-12-21 16:21:58 +00:00
3961060f90 v12.55.7 2021-12-14 23:32:04 +02:00
a6dfc9126a Merge pull request #2412 from balena-io/pp/issue-2411
Removed hardcoded 'balenaCloud' in console message.
2021-12-14 21:30:06 +00:00
e7ddd07b7b push: Remove hardcoded 'balenaCloud' in console message
Change-type: patch
Signed-off-by: Pranav Peshwe <pranav@balena.io>
2021-12-14 19:54:30 +05:30
fea351d960 v12.55.6 2021-12-14 03:57:53 +02:00
40e0b2dbed Merge pull request #2410 from balena-io/fix-symlink-push-deploy
Fix symbolic link regression in push & deploy
2021-12-14 01:56:06 +00:00
3def4d0e4a Fix symbolic link regression in push & deploy
Change-type: patch
Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
2021-12-14 02:30:08 +02:00
aa286cc0e7 v12.55.5 2021-12-14 01:58:31 +02:00
8abeb6aed7 Merge pull request #2409 from balena-io/drop-unused-dir-traversal-list
Drop unnecessary directory list created during balena deploy & push
2021-12-13 23:56:00 +00:00
f285880135 Drop unnecessary directory list created during balena deploy & push
Change-type: patch
Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
2021-12-14 00:29:15 +02:00
2b5c387313 v12.55.4 2021-12-10 03:29:22 +02:00
8babf4c908 Merge pull request #2405 from balena-io/2386-os-download-dt-aliases
os download, os versions: Accept device type aliases
2021-12-10 01:26:38 +00:00
bfc995e948 os download, os versions: Accept device type aliases
Change-type: patch
2021-12-10 00:52:02 +00:00
c6a0bc0fba os download: Don't append '.prod' if the OS version does not match regex 2021-12-10 00:38:56 +00:00
ae69accf0f v12.55.3 2021-12-10 00:01:36 +02:00
cfcace4c99 Merge pull request #2404 from balena-io/2387-os-download-prod-suffix
os download: Assume '.prod' suffix by default for all balenaOS versions
2021-12-09 21:59:27 +00:00
6e07db0813 os download: Improve error message when not logged in (balenaOS ESR versions)
Change-type: patch
2021-12-09 18:06:26 +00:00
5c40c8d51f os download: Assume '.prod' suffix by default for all balenaOS versions
Resolves: #2387
Change-type: patch
2021-12-09 17:56:16 +00:00
d827005154 v12.55.2 2021-12-08 14:05:10 +02:00
76081343cc Merge pull request #2147 from balena-io/rework-tables
v13 preparations: Standardize command data output
2021-12-08 12:02:36 +00:00
f3fb9b6bdf v13 preparations: Standardize command data output
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2021-12-08 12:10:08 +01:00
c125e0b38d v12.55.1 2021-12-01 01:49:43 +02:00
73b2f6b4b1 Merge pull request #2401 from balena-io/klutchell-patch-2
chore: Bump multicast-dns to rebased commit
2021-11-30 23:46:39 +00:00
fdc0d08e96 chore: Bump multicast-dns to rebased commit
Otherwise npm install fails due to the missing commit in npm-shrinkwrap.json

Change-type: patch
Signed-off-by: Kyle Harding <kyle@balena.io>
See: https://github.com/balena-io-modules/multicast-dns/pull/1
2021-11-30 11:07:39 -05:00
e431a59af7 v12.55.0 2021-11-30 00:12:46 +02:00
41a2dbe60c Merge pull request #2294 from balena-io/provisioning-names-keys
Add provisioning key name option to config generate options
2021-11-29 22:11:05 +00:00
6ba67eefdb Add provisioning key name option to config generate options
Change-Type: minor
Signed-off-by: Nitish Agarwal 1592163+nitishagar@users.noreply.github.com
2021-11-29 16:15:55 +05:30
3b885ad906 v12.54.5 2021-11-27 03:45:02 +02:00
5574dc0318 Merge pull request #2398 from balena-io/reuse-getbootpartition
os configure, local configure: Reuse disk partition scanning logic
2021-11-27 01:42:53 +00:00
fcea91bfb6 os configure, local configure: Reuse disk partition scanning logic
Change-type: patch
2021-11-27 01:10:53 +00:00
7316c4e075 v12.54.4 2021-11-26 18:39:20 +02:00
389b7a1463 Merge pull request #2389 from balena-io/balena-lint-no-floating-promises
Bump 'balena-lint' and fix 'no-floating-promises' warnings
2021-11-26 16:36:16 +00:00
09d004423c Bump 'balena-lint' and fix 'no-floating-promises' warnings
Change-type: patch
2021-11-26 15:59:33 +00:00
97978ff812 v12.54.3 2021-11-26 17:38:17 +02:00
498e21f0ab Merge pull request #2376 from balena-io/lucianbuzzo/fast-scan
Improve directory scan speed prior to tarballing
2021-11-26 15:35:56 +00:00
257dd514ed Improve directory scan speed prior to tarballing
This changes improves the speed that the project is tarballed by switching from
`klaw` to `recursive-fs` and not running `lstat` on files that are ignored.
Whilst testing with the Jellyfish repository, which contains a number of
sub directories, each with their own node_modules folder, I was able to
reduce the time taken to scan and tarball the project from 70s to 11s,
which is a massive improvement.

Change-type: patch
Signed-off-by: Lucian Buzzo <lucian.buzzo@gmail.com>
2021-11-26 13:55:41 +00:00
85cbdd4947 v12.54.2 2021-11-26 14:01:22 +02:00
73625611da Merge pull request #2395 from balena-io/lucianbuzzo/2394-push-image
Set the correct target state when using Compose "image" field
2021-11-26 11:59:17 +00:00
d2a5a9ba86 Set the correct target state when using Compose "image" field
Fixes #2394

When pushing to a device in local mode, if a service is not external, and uses
an `image` field, that value should be used for tags and target state, otherwise
it won't match the image name generated on the device by balenaEngine.

Change-type: patch
Signed-off-by: Lucian Buzzo <lucian.buzzo@gmail.com>
2021-11-26 10:11:07 +00:00
1cd78215e0 v12.54.1 2021-11-26 00:59:24 +02:00
6d744d0b07 Merge pull request #2393 from balena-io/fix-config-usage
Fix mistake in `config generate` examples
2021-11-25 22:56:40 +00:00
9d312bcd12 v12.54.0 2021-11-25 23:47:55 +02:00
e22aa847e3 Merge pull request #2378 from balena-io/events-timeout
Improve UX for offline usage
2021-11-25 21:45:47 +00:00
0d1ca67d5b v12.53.2 2021-11-25 20:58:34 +02:00
c4a5a25f03 Merge pull request #2391 from balena-io/drop-custom-device-api-key-generation-code
Stop creating an extra provisioning API key in each config generation
2021-11-25 18:56:53 +00:00
b183d88400 Fix mistake in config generate examples
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2021-11-25 16:05:37 +00:00
2b6a2142eb Improve UX for offline usage
Change-type: minor
Resolves: #2372
Signed-off-by: Scott Lowe <scott@balena.io>
2021-11-25 15:14:39 +00:00
58b29bf4bb Stop creating an extra provisioning API key in each config generation
Change-type: patch
Changelog-entry: Avoid creating an extra provisioning API key in os configure & config generate
See: https://github.com/balena-io/balena-cli/pull/2294#discussion_r756499196
Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
2021-11-25 16:40:53 +02:00
fc0903a414 v12.53.1 2021-11-25 12:18:50 +02:00
cea23f5d5e Merge pull request #2388 from balena-io/docs-changes
Transitional changes to doc files for landr implementation
2021-11-25 10:15:37 +00:00
5a9b5e3b08 Transitional changes to doc files for landr implementation
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2021-11-25 10:44:38 +01:00
52138d41eb v12.53.0 2021-11-25 04:49:54 +02:00
5acdc63068 Merge pull request #2369 from balena-io/2349-config-inject-scan-partition
config read/write/inject: Avoid need for internet access
2021-11-25 02:47:56 +00:00
b546e4dd97 config read/write/inject: Avoid need for internet access
Change-type: minor
2021-11-25 02:05:40 +00:00
e4870916e2 config read: Add '--json' option for JSON output
Change-type: minor
2021-11-24 23:03:37 +00:00
3ca93448cd v12.52.2 2021-11-24 20:59:10 +02:00
f66395e2d5 Merge pull request #2390 from balena-io/device-init-docs
Delete 'doc/automated-init.md' and improve 'balena help device init'
2021-11-24 18:57:11 +00:00
952d782e90 Delete 'doc/automated-init.md' and improve 'balena help device init'
Change-type: patch
2021-11-24 18:24:14 +00:00
d53c9b3c50 v12.52.1 2021-11-22 04:25:10 +02:00
2f706c0200 Merge pull request #2384 from balena-io/2376-dockerignore-corner-cases
push/build: Add test cases for .dockerignore filtering corner cases
2021-11-22 02:23:22 +00:00
d64b6deb81 push/build: Add test cases for .dockerignore filtering corner cases
Change-type: patch
2021-11-22 01:50:27 +00:00
55fc9b2ade v12.52.0 2021-11-20 03:19:00 +02:00
6c29d0ae27 Merge pull request #2334 from balena-io/2005-os-esr-versions-hostapp
os versions, os download: Add support for balenaOS ESR versions
2021-11-20 01:17:17 +00:00
f46452f6de os download: Display OS version actually downloaded (range or 'recommended')
Change-type: patch
2021-11-20 00:43:15 +00:00
c166ec7597 os versions, os download: Add support for balenaOS ESR versions
Change-type: minor
2021-11-20 00:43:15 +00:00
7325c79888 v12.51.3 2021-11-16 19:10:36 +02:00
2a29b386eb Merge pull request #2375 from balena-io/missing-digest
deploy: Ensure the release fails if an image's digest (hash) is missing
2021-11-16 17:08:41 +00:00
23b07f8a41 deploy: Ensure the release fails if an image's digest (hash) is missing
Change-type: patch
2021-11-16 11:55:07 +00:00
6d641b4841 v12.51.2 2021-11-16 13:50:52 +02:00
7b498149b1 Merge pull request #2379 from balena-io/remove-node10-from-resinci.yml
Update balena CI configuration (remove Node v10 from npm pipeline list)
2021-11-16 11:49:36 +00:00
ae5ea0f4e8 Update balena CI configuration (remove Node v10 from npm pipeline list)
Change-type: patch
2021-11-15 23:51:15 +00:00
f635f648da v12.51.1 2021-10-25 20:54:12 +03:00
3d4e2cf823 Merge pull request #2256 from balena-io/forum-link
Fix forums support link in README.md
2021-10-25 17:52:15 +00:00
ef3b630887 v12.51.0 2021-10-22 22:13:44 +03:00
19040ccb6c Merge pull request #2367 from balena-io/support-for-fragments
Add support for YAML anchors and aliases in 'docker-compose.yml'
2021-10-22 19:11:47 +00:00
8e712ac910 Add support for YAML anchors and aliases in 'docker-compose.yml'
This allows project files to define services from generic fragments by leveraging YAML's anchors and aliases. See here for an example: 43f6537b2c/spec.md (fragments)

Removing the FAILSAFE_SCHEMA flag is not expected to break existing project files, since the default behaviour is more liberal, or cause problems down the road given we perform validation immediately after. Docs for the flag: https://github.com/nodeca/js-yaml#load-string---options-

Change-type: minor
2021-10-22 16:42:29 +03:00
c401ed35ac v12.50.3 2021-10-20 19:33:37 +03:00
94be97313b Merge pull request #2359 from balena-io/klutchell/preload-11
preload: Avoid possible ValueError when parsing storage driver
2021-10-20 16:31:34 +00:00
48053ecefc preload: Avoid possible ValueError when parsing storage driver
Update balena-preload from 10.5.0 to 11.0.0

Change-type: patch
Signed-off-by: Kyle Harding <kyle@balena.io>
2021-10-15 09:44:27 -04:00
cc60e86507 v12.50.2 2021-10-05 13:32:02 +03:00
bd774e8553 Merge pull request #2357 from balena-io/fix-fleet-rename-error-message
Error message when renaming a fleet now mentions the target name.
2021-10-05 10:27:51 +00:00
c493c33e38 Error message when renaming a fleet now mentions the target name.
Change-type: patch
Signed-off-by: Carlo Miguel F. Cruz <carloc@balena.io>
2021-10-05 17:01:07 +08:00
9487b33144 v12.50.1 2021-09-30 03:51:16 +03:00
befdae1b90 Merge pull request #2353 from balena-io/fix-help-release-finalize
Fix help output for 'release finalize' command
2021-09-30 00:49:35 +00:00
08dfc945f3 Update dependencies (@sentry/node error reporting)
Change-type: patch
2021-09-30 01:12:17 +01:00
8791c2f4e1 Replace mixpanel dependency with simple GET request
Change-type: patch
2021-09-30 01:12:17 +01:00
be306e6a20 Avoid NockMock warnings during standalone executable testing
Change-type: patch
2021-09-30 01:12:17 +01:00
6cfff72c59 Fix help output for 'release finalize' command
Change-type: patch
2021-09-30 01:12:17 +01:00
adae718c2e v12.50.0 2021-09-28 18:07:49 +03:00
132e1a63b2 Merge pull request #2345 from balena-io/add-release-handling
Add support for releases
2021-09-28 15:05:40 +00:00
a18e182ae4 Add support for releases
Signed-off-by: Paul Jonathan <pj@balena.io>
Change-type: minor
2021-09-28 14:28:43 +00:00
e098cdca17 v12.49.0 2021-09-23 23:56:47 +03:00
b42af74983 Merge pull request #2301 from balena-io/add-multiarch-handling
Add multiarch support
2021-09-23 20:54:51 +00:00
8bb211e441 build, deploy: Improve logging of image build messages
Change-type: patch
2021-09-23 16:37:45 +00:00
ffccbfba12 build, deploy: Add support for multiarch base images
Bump version of balena-multibuild to the one that supports multiarch
Remove previous hack to avoid sending platform information to multibuild

Change-type: minor
Signed-off-by: Paul Jonathan <pj@balena.io>
See: https://github.com/balena-io/balena-cli/issues/1508
2021-09-23 16:37:45 +00:00
56c1af50c0 v12.48.15 2021-09-22 17:52:15 +03:00
8b9e3ccdc8 Merge pull request #2346 from balena-io/update-sdk
Update balena-sdk to 15.51.1
2021-09-22 14:50:21 +00:00
de95262f93 Update balena-sdk to 15.51.1
Update balena-sdk from 15.48.0 to 15.51.1

Change-type: patch
2021-09-22 12:46:34 +05:30
ed49938504 v12.48.14 2021-09-22 00:37:13 +03:00
52ad0f6a57 Merge pull request #2347 from balena-io/klutchell/set-zlib-flush
os download: Avoid incomplete os downloads appearing as successful
2021-09-21 21:35:23 +00:00
7f6738c73c os download: Avoid incomplete os downloads appearing as successful
By forcing the zlib flush mode to Z_NO_FLUSH we are more likely to
see an error on image download pipelines vs silent failure and
incomplete files.

This is part of a larger investigation and may be removed in the
future when the root cause of the pipeline failures are identified.

Change-type: patch
Signed-off-by: Kyle Harding <kyle@balena.io>
2021-09-20 13:28:14 -04:00
88fc3f7714 v12.48.13 2021-09-17 17:01:55 +03:00
1afb29b923 Merge pull request #2340 from balena-io/2339-config-inject-auth
config inject: Remove requirement of being logged in
2021-09-17 13:59:18 +00:00
09a4e8db2d config inject: Remove requirement of being logged in
Change-type: patch
2021-09-16 12:15:53 +01:00
6c81440428 v12.48.12 2021-09-13 18:28:39 +03:00
3eca65ce0d Merge pull request #2333 from balena-io/klutchell/qemu-6-0-0
build/deploy: Update QEMU to 6.0.0 for emulated builds
2021-09-13 15:26:41 +00:00
6319b9dc13 v12.48.11 2021-09-11 01:38:46 +03:00
290acaecbb Merge pull request #2328 from balena-io/825-1018-fix-build-deploy-tag
build, deploy: Fix processing of '--tag' option
2021-09-10 22:36:18 +00:00
305c9045f0 build, deploy: Fix processing of '--tag' option
Change-type: patch
Resolves: #825
Resolves: #1018
2021-09-10 23:11:20 +01:00
b701151769 build/deploy: Update QEMU to 6.0.0 for emulated builds
Change-type: patch
Signed-off-by: Kyle Harding <kyle@balena.io>
2021-09-10 13:32:12 +00:00
e03bbb7275 v12.48.10 2021-09-10 14:25:45 +03:00
3fd66c39ae Merge pull request #2331 from balena-io/2330-retry-supervisor-api-request
push: Await and retry supervisor API requests to a local device
2021-09-10 11:23:59 +00:00
b30075a18b push: Await and retry supervisor API requests to a local device
Change-type: patch
2021-09-10 01:44:26 +01:00
a4fc95e99b v12.48.9 2021-09-10 03:44:17 +03:00
63d8e5e6a3 Merge pull request #2332 from balena-io/bump-net-keepalive-v3.0.0
chore: Update net-keepalive dependency (fix CLI packaging errors)
2021-09-10 00:41:55 +00:00
6244af3464 chore: Update net-keepalive dependency (fix CLI packaging errors)
Change-type: patch
2021-09-10 00:20:26 +01:00
8773927b3f v12.48.8 2021-09-09 00:27:52 +03:00
29a3fd40a2 Merge pull request #2326 from balena-io/v13-gitignore-feature-switch
v13 preparations: Add feature switch for removal of '--gitignore' (push, build)
2021-09-08 21:24:42 +00:00
d6faf060e6 v13 preparations: Add feature switch for removal of '--gitignore' (push, build)
Change-type: patch
2021-09-08 18:10:22 +01:00
352fd197b7 v13 preparations: Adjust test cases for 'balena envs'
Change-type: patch
2021-09-08 17:48:16 +01:00
afb6f938b7 v13 preparations: Adjust test cases for 'balena devices'
Change-type: patch
2021-09-08 17:47:40 +01:00
d3adbcdba9 v12.48.7 2021-09-07 18:28:57 +03:00
33fce1f24f Merge pull request #2325 from balena-io/move-reduce-device-type-json
device move: Rely on the device type model to get the compatible apps
2021-09-07 15:26:20 +00:00
ab90a5f150 v12.48.6 2021-09-07 16:55:22 +03:00
a8b2212fed Merge pull request #2324 from balena-io/reduce-device-type-json
preload: Rely on the device type model to get the compatible apps
2021-09-07 13:53:31 +00:00
6bb8df30dd preload: Rely on the device type model to get the compatible apps
Connects-to: #2318
Change-type: patch
Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
2021-09-07 14:53:17 +03:00
0327ed766d device move: Improve types & reduce the number of API requests
Change-type: patch
Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
2021-09-07 11:43:35 +00:00
1009958340 v12.48.5 2021-09-07 14:12:24 +03:00
5ce17ea70f Merge pull request #2323 from balena-io/no-my_application
preload: Replace my_application query with the SDKs application.getAll()
2021-09-07 11:10:21 +00:00
9c821511b1 device move: Rely on the device type model to get the compatible apps
Connects-to: #2318
Change-type: patch
See: https://www.flowdock.com/app/rulemotion/i-cli/threads/s6x4Z_LoH8IG4PC_YeXMC0TP6v-
Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
2021-09-07 07:53:02 +00:00
d793335287 preload: Replace my_application query with the SDKs application.getAll()
Change-type: patch
Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
2021-09-07 02:09:39 +03:00
dc59b7e4b0 v12.48.4 2021-08-31 04:34:45 +03:00
370b844538 Merge pull request #2316 from balena-io/os-download-no-device-types-v1
os download: Use the hostApps instead of the device-types/v1 endpoint
2021-08-31 01:32:58 +00:00
a8c2724929 v12.48.3 2021-08-31 04:03:14 +03:00
09dd2dd354 Merge pull request #2317 from balena-io/balena-deploy-no-device-types-v1
balena deploy: Retrieve the cpu arch as part of the device type resource
2021-08-31 01:01:30 +00:00
f3ab41841a v12.48.2 2021-08-31 02:23:23 +03:00
3dee30a0fe Merge pull request #2313 from balena-io/install-docs-20210822
Clarify installation instructions
2021-08-30 23:21:40 +00:00
d34073f695 os download: Use the hostApps instead of the device-types/v1 endpoint
Connects-to: #2318
Change-type: patch
Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
2021-08-30 22:32:11 +00:00
24fe6666e4 balena deploy: Retrieve the cpu arch as part of the device type resource
Connects-to: #2318
Change-type: patch
Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
2021-08-30 22:30:16 +00:00
3fd5981085 Clarify installation instructions
Change-type: patch
2021-08-29 02:08:53 +01:00
08ee8643cb v12.48.1 2021-08-27 03:23:23 +03:00
8db36ccec9 Merge pull request #2312 from balena-io/remove-exitWithExpectedError
build, deploy: Extend CTRL-C coverage on Windows (PowerShell, cmd.exe)
2021-08-27 00:21:24 +00:00
deb3e4c4ac Improve error handling (remove most occurrences of process.exit())
Finally delete the deprecated exitWithExpectedError() function from
'lib/errors.ts'.

Change-type: patch
2021-08-27 00:53:21 +01:00
a8ff21af69 build, deploy: Extend CTRL-C coverage on Windows (PowerShell, cmd.exe)
Before this commit, `balena build` and `balena deploy` would almost
never respect CTRL-C on Windows (PowerShell, cmd.exe). Now CTRL-C
is respected over a large extent of runtime and, if CTRL-C is hit
while images are being uploaded (`balena deploy`), the release status
is correctly set to 'failed'.

Change-type: patch
2021-08-27 00:53:21 +01:00
4c54d6c171 v12.48.0 2021-08-26 18:38:44 +03:00
83f213c007 Merge pull request #2274 from balena-io/deploy-release-versioning
Add balena.yml handling to `balena deploy` release creation
2021-08-26 15:36:59 +00:00
d0cdc900a2 Add contract contents at release creation time
Change-type: patch
2021-08-26 16:11:23 +01:00
9937b91606 Documentation update with debugging notes
Signed-off-by: Paul Jonathan <pj@balena.io>
2021-08-26 00:34:54 +00:00
972c2470c5 Fix env variable to avoid test failures
Signed-off-by: Paul Jonathan <pj@balena.io>
Change-type: patch
2021-08-25 17:01:22 +00:00
7d568a928b Add balena.yml handling and --draft to balena deploy release creation
This change allows use of a contract and release semver when doing a push,
and is part of the larger feature to use the builder as part of a CI/CD pipeline.

Change-type: minor
Signed-off-by: Paul Jonathan <pj@balena.io>
2021-08-25 17:01:17 +00:00
2331e0a3e5 v12.47.0 2021-08-20 02:15:13 +03:00
cb9b6be24b Merge pull request #2309 from balena-io/warn-deprecation-policy
Add deprecation policy checker and --unsupported global flag
2021-08-19 23:13:25 +00:00
c2d3eee7cc Add deprecation policy checker and --unsupported global flag
Change-type: minor
2021-08-19 23:17:31 +01:00
d8b08f7272 v12.46.2 2021-08-17 02:27:23 +03:00
819bdac354 Merge pull request #2308 from balena-io/bump-sdk-15.48.0
Update dependencies (balena-sdk from v15.36.0 to v15.48.0)
2021-08-16 23:25:22 +00:00
318de8f017 Update dependencies (balena-sdk from v15.36.0 to v15.48.0)
Update balena-sdk from 15.36.0 to 15.48.0

Change-type: patch
2021-08-16 23:33:44 +01:00
2b0341e12a v12.46.1 2021-08-16 18:08:37 +03:00
21f7463607 Merge pull request #2303 from balena-io/preload-custom-dind
preload: Restore support for armv7 with custom preload image
2021-08-16 15:06:32 +00:00
19fd3094d1 preload: Restore support for armv7 with custom preload image
Update balena-preload from 10.4.20 to 10.5.0

Change-type: patch
Signed-off-by: Kyle Harding <kyle@balena.io>
2021-08-16 09:29:14 -04:00
7c4974f4f5 v12.46.0 2021-08-15 20:09:40 +03:00
3b56ed278e Merge pull request #2270 from balena-io/allow-draft-releases
Add `--draft` option to `balena push`
2021-08-15 17:07:36 +00:00
254ef1c8cf Add --draft option to balena push
This change will allow to build releases as draft and have them being
set as final at a later stage. This change is part of a larger feature towards
using the builder as part of CI/CD pipelines.

Depends-on: https://github.com/balena-io/balena-builder/pull/868
Change-type: minor
2021-08-15 16:43:01 +00:00
d11f49e0f8 v12.45.2 2021-08-14 03:23:04 +03:00
48d7d0ef5e Merge pull request #2305 from balena-io/performResolution-error-handling
push, build: Improve error handling (identify which service failed)
2021-08-14 00:21:11 +00:00
c7bbbc4159 push, build: Improve error handling (identify which service failed)
Change-type: patch
2021-08-13 17:11:48 +01:00
d2fabcaf30 v12.45.1 2021-08-11 17:27:05 +03:00
e137c2aed2 Merge pull request #2307 from balena-io/2306-env-add-app-is-ambiguous
envs, env add: Fix "Application is ambiguous" when using device UUID
2021-08-11 14:25:21 +00:00
58704b08d3 envs, env add: Fix "Application is ambiguous" when using device UUID
Change-type: patch
2021-08-11 02:00:35 +01:00
485a9e944f v12.45.0 2021-08-09 19:35:52 +03:00
1d7a50f007 Merge pull request #2304 from balena-io/fleet-renamathon
Rename applications to fleets (stage 1)
2021-08-09 16:34:07 +00:00
64a44e7a5f Rename applications to fleets (stage 1). See: https://git.io/JRuZr
- Add fleet(s) commands and -f, --fleet flags as aliases to the app(s)
  commands and -a, --app, --application flags.
- Conditionally rename column/row headers and JSON object properties
  from 'application' to 'fleet', with some variations.
- Print warning messages regarding the renaming, provided that stderr
  is attached to an interactive terminal.

Change-type: minor
Resolves: #2302
2021-08-09 12:12:03 +01:00
c3406603db v12.44.29 2021-07-27 16:49:35 +03:00
f1fa187a58 Merge pull request #2300 from balena-io/preload-10-4-10
preload: Fix storage driver detection in balenaOS v2.80.9
2021-07-27 13:47:26 +00:00
6cb2893750 preload: Fix storage driver detection in balenaOS v2.80.9
Change-type: patch
Signed-off-by: Kyle Harding <kyle@balena.io>
2021-07-26 12:03:49 -04:00
216172ed4f v12.44.28 2021-07-23 17:55:35 +03:00
3717d8cc0f Merge pull request #2299 from balena-io/catch-BalenaInvalidDeviceType
os download: Improve error message for misspelled device type names
2021-07-23 14:53:22 +00:00
8338e2e933 os download: Improve error message for misspelled device type names
Change-type: patch
2021-07-23 15:10:00 +01:00
918c2e912d v12.44.27 2021-07-23 14:25:16 +03:00
be0622ec80 Merge pull request #2298 from balena-io/etimedout-troubleshooting
docs: Add entry to FAQ/Troubleshooting for ETIMEDOUT with 'balena tunnel'
2021-07-23 11:23:13 +00:00
07eef7bb49 docs: Add entry to FAQ/Troubleshooting for ETIMEDOUT with 'balena tunnel'
Change-type: patch
2021-07-23 11:54:13 +01:00
0892caa155 v12.44.26 2021-07-22 04:31:34 +03:00
fa4e8e7b55 Merge pull request #2296 from balena-io/npm-audit
chore: Update dependencies (balena-lint, oclif, "npm audit fix")
2021-07-22 01:29:20 +00:00
e624726e44 config write: Fix EBUSY error on macOS
Change-type: patch
2021-07-21 23:56:57 +01:00
f914fa2d8a chore: Remove 'umount' dependency (as advised by "npm audit")
Address security advisory https://www.npmjs.com/advisories/1512

Change-type: patch
2021-07-21 23:56:57 +01:00
c8f5542c8a chore: Update oclif
Change-type: patch
2021-07-21 23:56:46 +01:00
a2cad7bf53 chore: Update dependencies ("npm audit fix")
Change-type: patch
2021-07-21 23:56:35 +01:00
3a871a0003 chore: Update balena-lint
Change-type: patch
2021-07-20 18:02:16 +01:00
e552e36f7b v12.44.25 2021-07-20 18:56:54 +03:00
c325f1158e Merge pull request #2295 from balena-io/simplify-run-spinner
Simplify runSpinner api
2021-07-20 15:55:11 +00:00
f79ccc0c95 Simplify runSpinner api
Change-type: patch
2021-07-20 15:46:54 +01:00
1ec8d9a4ca v12.44.24 2021-07-10 00:30:25 +03:00
427b0d9b41 Merge pull request #2291 from balena-io/fix-config-write-101
config write: Fix parsing of 'key' argument with numeric components
2021-07-09 21:28:19 +00:00
cfd790a193 Update 'devDependencies' in package.json
Change-type: patch
2021-07-09 21:34:09 +01:00
36f4c1312b config write: Fix parsing of 'key' argument with numeric components
Change-type: patch
2021-07-09 17:29:21 +01:00
fe7cbf4f74 v12.44.23 2021-06-30 19:26:18 +03:00
4e8b8fe582 Merge pull request #2287 from balena-io/dfunckt-patch-1
Delete CODEOWNERS
2021-06-30 16:23:38 +00:00
2986e6cea3 Delete CODEOWNERS
Change-type: patch
2021-06-30 18:55:44 +03:00
bb6b4b255a v12.44.22 2021-06-24 19:55:41 +03:00
350c4abb96 Merge pull request #2283 from balena-io/2045-sfdisk-spinner
preload: Catch sfdisk errors that result in an endless spinner
2021-06-24 16:53:35 +00:00
fec96b41ee preload: Warn that zip files are only accepted for Intel Edison
Change-type: patch
Signed-off-by: Kyle Harding <kyle@balena.io>
2021-06-24 11:04:26 -04:00
1dba5cc7c1 preload: Catch sfdisk errors that result in an endless spinner
Change-type: patch
Changelog-entry: preload: Catch sfdisk errors that result in an endless spinner
Signed-off-by: Kyle Harding <kyle@balena.io>
2021-06-23 12:56:41 -04:00
43c6fe672f v12.44.21 2021-06-23 16:54:41 +03:00
486cae1aaa Merge pull request #2282 from balena-io/cli-author
Update author details in package.json, Windows Programs and Features
2021-06-23 13:52:55 +00:00
4d588e51a7 Update author details in package.json, Windows Programs and Features
Change-type: patch
2021-06-22 00:05:25 +01:00
0035545ce1 v12.44.20 2021-06-15 00:10:05 +03:00
d559b9a5a1 Merge pull request #2265 from balena-io/balena-sdk-15.36.0
devices supported: Use new DeviceType data model as source of truth
2021-06-14 21:08:02 +00:00
e2ffc5f068 v12.44.19 2021-05-31 11:47:23 +03:00
75b2fa0e9e Merge pull request #2273 from balena-io/fast-boot-stop
Fix fast-boot module caching with read-only installation folders
2021-05-31 08:45:29 +00:00
c619ecd41b v12.44.18 2021-05-28 16:17:00 +03:00
7ed01a925b Merge pull request #2276 from balena-io/python3-install-requirements
Update advanced installation instructions
2021-05-28 13:14:39 +00:00
460022a7cf Update advanced installation instructions
Replace 'python' with 'python3' in apt-get install command line, and
refactor for clarity.

Change-type: patch
2021-05-27 20:34:48 +01:00
d15b54cf40 Fix fast-boot module caching with read-only installation folders
* Add missing fast-boot `stop()` call on CLI exit to avoid 1s timeout.
* Move `.fast-boot.json` to `~/.balena/cli-module-cache.json` to
address scenarios where the CLI is installed to a read-only folder:
- pkg's internal 'snapshot' filesystem (standalone zip package)
- Root-owned folder without write permission to regular users,
  like `/usr[/local]/lib/balena-cli` (the case of caxa-based
  installers or the GUI installer for macOS).

Change-type: patch
2021-05-27 00:23:36 +00:00
c938df2445 v12.44.17 2021-05-24 18:17:54 +03:00
bf1df05606 Merge pull request #2272 from balena-io/rgz/deploy-doc
doc: Document the image nameing scheme used by deploy
2021-05-24 15:15:46 +00:00
e04242db64 doc: Document the image nameing scheme used by deploy
When using deploy to create a release for a multi-container project one
needs to follow this to avoid triggering a build. Relevant for CI/CD scenarios
with their own build pipeline.

Change-type: patch
Signed-off-by: Robert Günzler <robertg@balena.io>
2021-05-24 16:24:26 +02:00
9265588745 v12.44.16 2021-05-18 18:35:46 +03:00
cd8070b1a6 Merge pull request #2269 from balena-io/2231-balena-preload
preload: Update balena-preload to 10.4.7
2021-05-18 15:33:56 +00:00
b17dad8c60 preload: Update balena-preload to 10.4.7
Change-type: patch
Changelog-entry: preload: Avoid hardcoded registry2 URLs with openBalena
Signed-off-by: Kyle Harding <kyle@balena.io>
2021-05-18 11:04:58 -04:00
a254e46118 devices supported: Use new DeviceType data model as source of truth
Change-type: patch
2021-05-16 22:48:22 +00:00
6e7a0defb7 Update balena-sdk from 15.31.0 to 15.36.0
Update balena-sdk from 15.31.0 to 15.36.0

Change-type: patch
2021-05-16 19:34:40 +00:00
492dbae7f1 v12.44.15 2021-05-16 22:17:02 +03:00
ccc2c20b6d Merge pull request #2267 from Kajatin/automatic-boot-partition-number
os configure, local configure: Fix "Unsupported filesystem" error
2021-05-16 19:13:29 +00:00
501882fd26 os configure, local configure: Fix "Unsupported filesystem" error
When configuring a BalenaOS image with system connections using the CLI,
the function assumed that the boot partition was always 1. This is not
the case for every supported board. Therefore, a new function is added,
which automatically determines the boot partition number and allows
users to configure the image with system connection settings.

This change affects both the `balena local configure` and `balena os configure` commands.

Change-type: patch
2021-05-16 18:08:26 +02:00
e2ff561728 v12.44.14 2021-05-10 01:09:23 +03:00
5544f4a5dd Merge pull request #2199 from khancyr/completion
Completion
2021-05-09 22:07:13 +00:00
a3e90182bc Add completion generator from oclif.manifest.json
Change-type: patch
2021-05-09 11:05:31 +02:00
3ac85dcc5f v12.44.13 2021-05-07 20:54:53 +03:00
1ac573c659 Merge pull request #2259 from balena-io/bump-multibuild-docker-progress
Fix "Total: undefined" image pull progress report and update dependencies
2021-05-07 17:52:39 +00:00
2c922ee6d2 Update dependencies (multibuild, dockerode, docker-toolbelt, docker-progress)
Update resin-multibuild from 4.7.2 to 4.11.0

Change-type: patch
2021-05-07 00:32:15 +01:00
d9821939d9 preload: Improve error handling (stop spinning wheels)
Update balena-preload from 10.4.2 to 10.4.6

Connects-to: #2045
Change-type: patch
2021-05-07 00:00:07 +01:00
732fc2d539 build: Workaround issue with Docker v20.10 + single-arch base images
Change-type: patch
2021-05-06 23:20:06 +01:00
535a443d7c build: Fix "Total: undefined" image pull progress report
Change-type: patch
2021-05-03 15:48:16 +01:00
579d68a8f0 v12.44.12 2021-04-27 17:58:06 +03:00
ffac8cb9e5 Merge pull request #2258 from balena-io/balena-preload-10-4-2
preload: Update to Docker 20.10 with cgroups v2 support
2021-04-27 14:55:58 +00:00
0f2780744f preload: Update to Docker 20.10 with cgroups v2 support
Update balena-preload from 10.4.1 to 10.4.2.

Change-type: patch
Changelog-entry: preload: Update to Docker 20.10 with cgroups v2 support
Signed-off-by: Kyle Harding <kyle@balena.io>
2021-04-27 10:06:33 -04:00
b4495839ca v12.44.11 2021-04-21 16:46:55 +03:00
f45ac42dd3 Merge pull request #2255 from balena-io/build-args-warning
Add message regarding deprecation of --buildArg option
2021-04-21 13:44:15 +00:00
112a7b8194 Fix forums support link in README.md
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2021-04-21 06:57:28 +00:00
fa26004648 Add message regarding deprecation of --buildArg option in build/deploy commands
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2021-04-21 07:26:57 +02:00
ba1ea54d69 v12.44.10 2021-04-16 01:24:55 +03:00
9fb62d92b7 Merge pull request #2253 from balena-io/2252-fix-ssh-service-list
ssh: fix incorrect service name parsing in local mode
2021-04-15 22:21:58 +00:00
8780a24fb5 ssh: fix incorrect service name parsing in local mode
Resolves: #2252
Change-type: patch
Signed-off-by: Tomás Migone <tomas@balena.io>
2021-04-14 16:31:07 -03:00
3d3e91d49d v12.44.9 2021-04-14 04:06:00 +03:00
f6e6d9ce8b Merge pull request #2251 from balena-io/1003-config-inject-umount
config inject/read/write: Fix umount errors with OS image files
2021-04-14 01:03:53 +00:00
0f9d78ab50 config inject/read/write: Fix umount errors with OS image files
Resolves: #1003
Change-type: patch
2021-04-13 23:30:19 +01:00
06f7683837 Refactor dependency import in utils/helpers.ts for performance
Change-type: patch
2021-04-13 22:14:13 +01:00
83a23d9f30 v12.44.8 2021-04-10 02:37:53 +03:00
ffa181a2c3 Merge pull request #2248 from balena-io/2185-fix-ndjson-parsing
push, logs: Fix parsing of local mode device logs (NDJSON stream)
2021-04-09 23:35:27 +00:00
d50d18d492 push, logs: Fix parsing of local mode device logs (NDJSON stream)
Resolves: #2185
Change-type: patch
2021-04-09 23:58:04 +01:00
0b0fb94834 v12.44.7 2021-04-09 22:00:07 +03:00
c1244c0c98 Merge pull request #2247 from balena-io/osConfigureFix
lib/commands/local/configure: Fix local configure when resin-wifi is …
2021-04-09 18:56:42 +00:00
213e54feb1 lib/commands/local/configure: Fix local configure when resin-wifi is not available on the image
Resolves: #2239
Change-type: patch
Signed-off-by: Marios Balamatsias <mbalamatsias@gmail.com>
2021-04-09 21:20:47 +03:00
cc8a8513e9 v12.44.6 2021-04-07 22:44:44 +03:00
42c3236313 Merge pull request #2246 from balena-io/missing-arch-install-notes
Direct missing release installs to npm install method
2021-04-07 19:42:26 +00:00
91fd515266 Direct missing release installs to npm install method
Change-type: patch
Signed-off-by: Miguel Casqueira <miguel@balena.io>
2021-04-07 13:56:17 -04:00
57cd096612 v12.44.5 2021-04-07 19:59:18 +03:00
854501cf8d Merge pull request #2245 from balena-io/sdk-15.31.0
Update balena-sdk (15.31.0) and other dependencies
2021-04-07 16:56:55 +00:00
d44afa8c39 docs: Update install instructions re macOS installer notarization
Change-type: patch
2021-04-07 17:26:59 +01:00
b7500fc2c2 Update resin-compose-parse from 2.1.2 to 2.1.3
Change-type: patch
2021-04-07 17:26:43 +01:00
dc6c8d7472 Update balena-config-json from 4.1.0 to 4.1.1
Change-type: patch
2021-04-07 17:26:24 +01:00
5c5be8f7b7 Update etcher-sdk from 6.2.0 to 6.2.1
Change-type: patch
2021-04-07 17:14:13 +01:00
5bdd6c6034 Update balena-sdk from 15.29.0 to 15.31.0
Change-type: patch
2021-04-07 16:58:21 +01:00
a5bade99fc v12.44.4 2021-04-07 00:42:46 +03:00
9c3eb76856 Merge pull request #2186 from balena-io/notarization
Update macOS installer to avoid Apple's warning pop-up
2021-04-06 21:40:12 +00:00
973f1a9c40 Add notarization for macOS graphical installer
Change-type: patch
2021-04-06 16:56:07 -04:00
16ea0c9d6d v12.44.3 2021-04-05 01:47:08 +03:00
73bfe545e8 Merge pull request #2242 from balena-io/preload-docs
docs: Further clarify Docker requirements for preload
2021-04-04 22:45:24 +00:00
f53e658ca2 docs: Further clarify Docker requirements for preload
Change-type: patch
2021-04-04 23:02:48 +01:00
b66706e8ee v12.44.2 2021-04-02 20:25:58 +03:00
11e50466d5 Merge pull request #2240 from balena-io/remove-balenalib-images
docker: Remove balenalib images and docs
2021-04-02 17:23:50 +00:00
431c4b6e4a docker: Remove references to CLI docker images in the installation docs
Change-type: patch
2021-04-02 18:05:31 +01:00
d12490f816 docker: Remove balenalib images and docs
Change-type: patch
Signed-off-by: Kyle Harding <kyle@balena.io>
2021-04-02 07:57:52 -04:00
67b7b8b5d0 v12.44.1 2021-03-31 19:15:26 +03:00
16d1f0f06f Merge pull request #2235 from balena-io/docs-fix-broken-url
os/configure: Fix broken NetworkManager URL
2021-03-31 16:13:23 +00:00
9676ea94cb v12.44.0 2021-03-31 15:13:11 +03:00
df8ce0bbe0 Merge pull request #2168 from balena-io/node14fix
Make `os configure` and `local flash` work with Node 14
2021-03-31 12:11:13 +00:00
6437bb7511 os/configure: Fix broken NetworkManager URL
Update the broken NM URL to match the rest of the documentation.

Change-type: patch
Connects-to: balena-io/docs/#1757 balena-io/docs/#1522
Changelog-entry: os/configure: Fix broken NetworkManager URL
Signed-off-by: Mark Corbin <mark@balena.io>
2021-03-31 10:08:37 +00:00
ac96616e4e osConfigure/localFlash: Add support for Node.js v14
* Replace old resin-image-fs with newer balena-image-fs
* package.json: Remove resin-image-fs package
* package: Install dependencies that work with node14
* Remove resin-image-fs typings
* Fix etcher-sdk related types
* local/flash: Add unmountOnSuccess, write, direct properties on flash
	Taken from https://github.com/balena-io-modules/etcher-sdk/blob/master/examples/multi-destination.ts
* tests/utils/eol-conversion: Remove ext2fs sample binary
	Specifically ext2fs/build/Release/bindings.node
	I removed it because the file doesn't exist
* tests/test-data/pkg: Add new expected warnings darwin/linux/windows
* os/configure: Remove windows check
* local/flash: Check if environment is WSL and show warning message
* Get tests to pass with certain Node v14 warning messages
* INSTALL-WINDOWS: Remove os configure warning

Improve push and logs support for Node.js v14 (bump 'net-keepalive')

Resolves: #2200
Resolves: #1990
Change-type: minor
Signed-off-by: Marios Balamatsias <mbalamatsias@gmail.com>
2021-03-31 01:15:47 +03:00
2737c9c53c v12.43.2 2021-03-26 17:31:50 +02:00
3b8a46f523 Merge pull request #2229 from balena-io/catch-dind-errors
docker: Improve handling of Docker-in-Docker errors
2021-03-26 15:29:46 +00:00
3ac1994941 v12.43.1 2021-03-26 01:15:19 +02:00
b3a6c6cb0f Merge pull request #2230 from balena-io/update-install-mac-docker
Improve installation docs regarding Docker Desktop version requirements
2021-03-25 23:12:20 +00:00
6d4faa7b2c Improve installation docs regarding Docker Desktop version requirements
Connects-to: #2228
Change-type: patch
2021-03-25 16:07:09 +00:00
9036ce9af3 docker: Improve handling of Docker-in-Docker errors
The `local` logging driver captures output from container’s stdout/stderr
and writes them to an internal storage that is optimized for performance and disk use.

We also want to capture these logs on startup to wait for success/failure.

Advise the use of `--privileged` when running Docker-in-Docker to avoid
various permissions issues encountered in testing.

Change-type: patch
Changlelog-entry: docker: Improve handling of Docker-in-Docker errors
Signed-off-by: Kyle Harding <kyle@balena.io>
2021-03-25 14:02:22 +00:00
4911db640f v12.43.0 2021-03-23 03:01:51 +02:00
e7999f52a9 Merge pull request #2210 from balena-io/oclif-dev-cli-update
Add macOS uninstall script (sudo /usr/local/lib/balena-cli/bin/uninstall)
2021-03-23 00:59:30 +00:00
68b61e7424 Refactor automation scripts (reduce need for MSYS to build on Windows)
Change-type: patch
2021-03-23 00:04:43 +00:00
329b84d01e Add macOS uninstall script (sudo /usr/local/lib/balena-cli/bin/uninstall)
Change-type: minor
2021-03-23 00:04:43 +00:00
25b1dff5d8 Bump patch-package dependency and remove its own patch file
Change-type: patch
2021-03-22 16:12:44 +00:00
fb1768b4ca v12.42.2 2021-03-21 01:31:40 +02:00
cbc1e52256 Merge pull request #2227 from balena-io/2226-yaml-null-volume
push: Fix docker-compose.dev.yml serialization ("should be object,null" error)
2021-03-20 23:29:58 +00:00
37c2880996 push: Fix docker-compose.dev.yml serialization ("should be object,null" error)
Change-type: patch
2021-03-20 22:17:20 +00:00
835445be2e v12.42.1 2021-03-19 18:58:58 +02:00
52fe7481fc Merge pull request #2225 from balena-io/readme-bullet-spacing
Make README.md bullet point spacing uniform
2021-03-19 16:56:32 +00:00
88072173d0 Make README.md bullet point spacing uniform
Change-type: patch
Signed-off-by: Genadi Naydenov genadi@balena.com
2021-03-19 18:32:07 +02:00
fdc2bff063 v12.42.0 2021-03-19 15:28:52 +02:00
4f6f20f469 Merge pull request #2218 from chriswiggins/public-address
Public address
2021-03-19 13:26:48 +00:00
50af0760ce balena device: Display public IP address field
Change-type: minor
2021-03-19 14:41:21 +13:00
43906d22c8 Update balena-sdk from 15.20.0 to 15.29.0
Change-type: patch
2021-03-19 14:41:20 +13:00
43f1188f1d v12.41.3 2021-03-17 18:45:08 +02:00
2629a01c7f Merge pull request #2223 from balena-io/engines-npm-v7
Update supported npm version range in package.json (<7.0.0)
2021-03-17 16:42:55 +00:00
5fc009a6ae Update supported npm version range in package.json (<7.0.0)
Connects-to: #2221
Change-type: patch
2021-03-17 15:28:39 +00:00
480f84993b v12.41.2 2021-03-17 10:46:32 +02:00
d1fdbd927e Merge pull request #2208 from balena-io/linux-install-docs-sudo
Linux installation instructions: Add sudo configuration section
2021-03-17 08:44:22 +00:00
4bfd345b68 v12.41.1 2021-03-15 20:39:53 +02:00
d4a153d2ee Merge pull request #2212 from balena-io/klutchell/balenalib-dockerfiles
docker: Fix path to init when workdir is changed
2021-03-15 18:38:01 +00:00
3cff091e3a docker: Fix path to init when workdir is changed
Change-type: patch
Signed-off-by: Kyle Harding <kyle@balena.io>
2021-03-15 10:32:43 -04:00
b2ad9f1643 v12.41.0 2021-03-15 16:07:04 +02:00
f7623bef85 Merge pull request #2159 from balena-io/klutchell/balenalib-dockerfiles
dockerfiles: initial commit of balenalib dockerfiles
2021-03-15 14:04:52 +00:00
af63794571 docs: Add Docker to Advanced Installation instructions
Signed-off-by: Kyle Harding <kyle@balena.io>
2021-03-15 08:34:34 -04:00
65d5bdff08 docker: Add Docker images with the CLI and Docker-in-Docker
Add Dockerfiles for alpine and debian images, based on
balenalib/arch-distro-node images.

Change-type: minor
Signed-off-by: Kyle Harding <kyle@balena.io>
2021-03-15 08:34:23 -04:00
23165806aa v12.40.4 2021-03-09 19:36:10 +02:00
3649bafbb1 Merge pull request #2209 from balena-io/update-apple-certificate-name
macOS GUI installer: Update signing certificate name
2021-03-09 17:34:12 +00:00
c62445a399 macOS GUI installer: Update signing certificate name
Change-type: patch
2021-03-09 16:40:38 +00:00
b233ea3e3e Linux installation instructions: Add sudo configuration section
Change-type: patch
2021-03-07 23:31:31 +00:00
4fe660b3a5 v12.40.3 2021-03-06 18:51:02 +02:00
1f07cd1b1c Merge pull request #2207 from balena-io/fix-qemu-download-error-handling
build, deploy: Fix error handling when QEMU download fails
2021-03-06 16:48:59 +00:00
bcea5193a1 build, deploy: Fix error handling when QEMU download fails
Change-type: patch
2021-03-06 16:10:33 +00:00
8b99cd7170 v12.40.2 2021-02-24 00:45:01 +02:00
1986c9339c Merge pull request #2197 from balena-io/device-local-mode-markdown
docs: Fix missing markdown docs for device `deactivate` and `local-mode`
2021-02-23 22:43:00 +00:00
b90c9b0d7e docs: Fix missing markdown docs for device deactivate and local-mode
Change-type: patch
2021-02-23 22:10:52 +00:00
e28c3f9814 v12.40.1 2021-02-23 16:55:03 +02:00
d054ced541 Merge pull request #2194 from balena-io/klutchell/emulated-docs
docs: emphasize that push emulation is not required in most cases
2021-02-23 14:52:52 +00:00
c8e4d2c9a6 docs: emphasize that push emulation is not required in most cases
Change-type: patch
Signed-off-by: Kyle Harding <kyle@balena.io>
2021-02-23 08:55:25 -05:00
9671372b9e v12.40.0 2021-02-10 03:28:52 +02:00
2a4ff75203 Merge pull request #2177 from balena-io/livepush-compose-dev-overlay
Add support for docker-compose dev overlay
2021-02-10 01:26:52 +00:00
f3d750a024 Add support for docker-compose dev overlay in local pushes
Change-type: minor
Signed-off-by: Scott Lowe <scott@balena.io>
2021-02-09 13:06:03 +01:00
a701cd8d4d v12.39.1 2021-02-07 01:08:07 +02:00
e2c0c2f359 Merge pull request #2179 from balena-io/klutchell/qemu-v5.2.0+balena4
build/deploy: fix emulated builds to use fully static qemu binaries
2021-02-06 23:05:50 +00:00
15fc805f89 build/deploy: fix emulated builds to use fully static qemu binaries
Avoid possible situations where the local glibc may not support
the required syscalls for arm emulation during build/deploy.

Change-type: patch
Conneted-to: https://github.com/balena-io/qemu/issues/21
Signed-off-by: Kyle Harding <kyle@balena.io>
2021-02-06 09:50:46 -05:00
0a995ecc49 v12.39.0 2021-02-04 19:41:10 +02:00
1ba992ada2 Merge pull request #2176 from balena-io/device-localmode
Add command `device local-mode`
2021-02-04 17:39:05 +00:00
e47fd0c887 Add command device local-mode
Change-type: minor
Resolves: #1304
Signed-off-by: Scott Lowe <scott@balena.io>
2021-02-04 15:36:32 +00:00
af1de34840 v12.38.10 2021-02-04 17:00:43 +02:00
96fb525378 Merge pull request #2169 from balena-io/deduplicated-msg
Improve build-time checks (automation/test-lock-deduplicated.sh)
2021-02-04 14:58:27 +00:00
3d1f16c0ab v12.38.9 2021-02-04 15:59:06 +02:00
6fb58a25fc Merge pull request #2175 from balena-io/cloud-build-orgs
Modify push to pass app slug to builder
2021-02-04 13:56:31 +00:00
e6b85c9cf8 Modify push to pass app slug to builder
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2021-02-04 10:41:00 +01:00
43b93e7fd4 v12.38.8 2021-01-29 17:04:38 +02:00
a05dcf08b8 Merge pull request #2173 from balena-io/klutchell/qemu-v5.2.0
build/deploy: Update QEMU to speed up emulated builds
2021-01-29 15:02:49 +00:00
9636985ee7 build/deploy: Update QEMU to speed up emulated builds
QEMU v5 has quite a few improvements over v4, and the speed
difference when emulating arm is quite noticible.

We tested this with, and without, our single-core limitation
patch and have not been able to reproduce the stability
issues we were seeing in v4 so the patch was removed in
this release.

Change-type: patch
Connects-to: https://github.com/balena-io/balena-io/issues/2340
Signed-off-by: Kyle Harding <kyle@balena.io>
2021-01-29 09:26:34 -05:00
023fc57914 v12.38.7 2021-01-26 10:31:28 +02:00
492bdab2fe Merge pull request #2170 from balena-io/tunnel-help-openbalena
tunnel: Add note re openBalena version compatibility
2021-01-26 08:29:29 +00:00
941c365259 tunnel: Add note re openBalena version compatibility
Change-type: patch
2021-01-25 17:33:41 +00:00
fed58278c9 v12.38.6 2021-01-23 03:09:50 +02:00
d74af38bfe Merge pull request #2171 from balena-io/debug-logging
logging: note that the device supervisor version is operative
2021-01-23 01:07:30 +00:00
53926067ca logging: note that the device supervisor version is operative
Change-type: patch
Signed-off-by: Matthew McGinn <matthew@balena.io>
2021-01-22 16:53:15 -05:00
7181dc5401 v12.38.5 2021-01-22 12:59:32 +02:00
e35e13f9a7 Merge pull request #2163 from balena-io/switch-tunnel-to-tls
tls: Use TLS for tunnel connection
2021-01-22 10:57:39 +00:00
6e0638f3be Improve build-time checks (automation/test-lock-deduplicated.sh)
Change-type: patch
2021-01-21 21:29:10 +00:00
d60ec13d5c v12.38.4 2021-01-21 19:14:47 +02:00
731e50a757 Merge pull request #2166 from balena-io/engines-less-than-13
Update supported Node.js version range in package.json (<13.0.0)
2021-01-21 17:11:55 +00:00
b363d28664 Update supported Node.js version range in package.json (<13.0.0)
Change-type: patch
2021-01-21 15:58:08 +00:00
7ae83d9ce5 tls: Use TLS for tunnel connection
Switch to using the exposed tunnelUrl and TLS for making
tunnels to the device, to improve security.

Change-type: patch
Signed-off-by: Rich Bayliss <rich@balena.io>
2021-01-20 21:18:23 +00:00
31281549a6 v12.38.3 2021-01-19 19:19:10 +02:00
e86bcc438c Merge pull request #2161 from balena-io/workaround-push-public
Handle 'push' edge case with application access
2021-01-19 17:17:31 +00:00
a1cf602f6f Handle 'push' edge case with application access
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2021-01-19 13:38:22 +01:00
4cd3ef8b91 v12.38.2 2021-01-19 10:22:20 +02:00
e4eb4586f5 Merge pull request #2158 from balena-io/delete-travis-appveyor
Delete old config files for Travis and AppVeyor to avoid confusion
2021-01-19 08:20:37 +00:00
360c6e42f8 v12.38.1 2021-01-15 18:54:21 +02:00
f76702c4e0 Merge pull request #2160 from balena-io/fix-errorhandler-strings
Fix handling of thrown strings
2021-01-15 16:52:14 +00:00
d3586696b4 Fix handling of thrown strings
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2021-01-15 16:45:01 +01:00
f73e3db4de Delete old config files for Travis and AppVeyor to avoid confusion
Change-type: patch
2021-01-15 14:05:16 +00:00
1f74889386 v12.38.0 2021-01-15 01:27:04 +02:00
743de66138 Merge pull request #2154 from balena-io/add_release_tags_to_deploy
Add release-tag on deploy command
2021-01-14 23:24:51 +00:00
8d56fe9678 deploy: Add --release-tag flag
Now we can do:
`balena deploy myApp myApp/myImage --release-tag key1 value1`

Refactor and reuse the logic that parses and applies the
release tag options from the push command to the deploy
command.

Resolves: #892
Change-type: minor
Signed-off-by: Marios Balamatsias <mbalamatsias@gmail.com>
2021-01-15 00:46:39 +02:00
3d9d8bf5c8 v12.37.2 2021-01-14 16:50:48 +02:00
8c3df9ae30 Merge pull request #2153 from balena-io/america
docs: americanize the spelling of words in sourced markdown
2021-01-14 14:48:52 +00:00
e71184ed3a docs: americanize the spelling of words in sourced markdown
Change-type: patch
Signed-off-by: Matthew McGinn <matthew@balena.io>
2021-01-13 10:12:24 -05:00
caadce6c2b v12.37.1 2021-01-06 17:30:57 +02:00
f45fac6138 Merge pull request #2148 from balena-io/remove-internal-scandevices
Refactor out command internal scandevices
2021-01-06 15:29:10 +00:00
aeff5997d0 Refactor out command internal scandevices
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2021-01-06 15:00:18 +01:00
b5028c65cc v12.37.0 2020-12-29 12:58:58 +02:00
f69276e7c9 Merge pull request #2146 from balena-io/update-preload-10.4.1
Update preload 10.4.1
2020-12-29 10:56:43 +00:00
9fff9266d4 Add --additional-space flag to preload
Change-type: minor
2020-12-28 17:08:20 +01:00
0e7f953f72 Update balena-preload to 10.4.1
10.4.0 improves image size estimation
10.4.1 prevents running out of space while pulling images because of temporary files

Change-type: patch
2020-12-28 16:42:12 +01:00
61b11994b5 v12.36.1 2020-12-24 02:20:29 +02:00
1e1935cfb1 Merge pull request #2144 from balena-io/orgs-push
Update push command for organizations
2020-12-24 00:18:38 +00:00
27e2b03702 Update push command for organizations
Change-type: patch
Connects-to: #2119
Signed-off-by: Scott Lowe <scott@balena.io>
2020-12-23 16:03:52 +01:00
358acbd2c8 v12.36.0 2020-12-23 09:36:42 +02:00
b040a21268 Merge pull request #2138 from balena-io/add_tag_on_push
push: Add --release-tag flag
2020-12-23 07:35:03 +00:00
074fe010bd errors: Make all exclusive flag errors expected
eg Don't report errors if during a push --release-tag
and --detached flags are used.

Change-type: minor
Signed-off-by: Marios Balamatsias <mbalamatsias@gmail.com>
2020-12-22 17:10:10 +02:00
34557e35ee push: Add --release-tag flag
You can have 0 or multiple keys without values,
if you use values then you should have as many
values as you have keys. If you don't want to set
a value for a key set its value to "" (bash, cmd.exe)
or '""' (powershell).

Connects-to: #892
Change-type: minor
Signed-off-by: Marios Balamatsias <mbalamatsias@gmail.com>
2020-12-22 17:10:10 +02:00
3bff569758 v12.35.3 2020-12-21 13:18:38 +02:00
cf06a8dfad Merge pull request #2143 from balena-io/improve-id-disambiguation-tags
Improve id disambiguation for tag commands
2020-12-21 11:16:55 +00:00
584aa745f7 Improve id disambiguation for tag commands
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2020-12-18 12:52:18 +01:00
194d12cb3d v12.35.2 2020-12-18 11:44:48 +02:00
7739379444 Merge pull request #2137 from balena-io/fix-balenadev-sigterm
Modify handling of SIGINT in balena-dev
2020-12-18 09:42:03 +00:00
5c93df921e Modify handling of SIGINT in balena-dev
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2020-12-18 10:19:55 +01:00
da652c6bce v12.35.1 2020-12-17 17:06:38 +02:00
1cd341e6cd Merge pull request #2139 from balena-io/org-support-ssh-tunnel
Update commands ssh, tunnel to support orgs
2020-12-17 15:04:34 +00:00
9d2884aab7 Update commands ssh, tunnel to support orgs
Change-type: patch
Connects-to: #2119
Signed-off-by: Scott Lowe <scott@balena.io>
2020-12-17 13:01:53 +01:00
f128eaf389 v12.35.0 2020-12-15 17:46:38 +02:00
70b0524eb6 Merge pull request #2131 from balena-io/update-app-command-info-for-orgs
Update various commands to support organizations
2020-12-15 15:44:12 +00:00
c898747468 Update various commands to support organizations
Change-type: minor
Connects-to: #2119
Signed-off-by: Scott Lowe <scott@balena.io>
2020-12-15 16:06:25 +01:00
6fc3b0df58 v12.34.0 2020-12-15 16:47:17 +02:00
746676beb9 Merge pull request #2127 from balena-io/app-create-orgs
Add organizations support to app create command
2020-12-15 14:42:38 +00:00
611f59a0da Add organizations support to app create command
Change-type: minor
Connects-to: #2119
Signed-off-by: Scott Lowe <scott@balena.io>
2020-12-15 14:58:17 +01:00
c6430274e5 v12.33.2 2020-12-15 09:40:26 +02:00
9637f75617 Merge pull request #2050 from josecoelho/1667-permission-validation
Improve error message to access balena settings
2020-12-15 07:37:57 +00:00
439d8391ee Improve error message for issues to access balena settings
Update balena-settings-storage from 6.0.1 to 7.0.0

Resolves: #1667
Change-type: patch
2020-12-15 20:14:54 +13:00
0d3ca63f00 v12.33.1 2020-12-11 18:44:05 +02:00
1f3677bdb2 Merge pull request #2136 from balena-io/fix-preload-app-id
Fix preload command support for application IDs
2020-12-11 16:41:03 +00:00
10bca728f0 v12.33.0 2020-12-11 17:12:40 +02:00
9763a14e97 Merge pull request #2135 from balena-io/add-orgs
Add orgs command
2020-12-11 15:10:13 +00:00
fe24280adf Fix preload command support for application IDs
Change-type: patch
Resolves: #2063
Signed-off-by: Scott Lowe <scott@balena.io>
2020-12-11 13:54:31 +00:00
a11f9ec705 Add orgs command
Change-type: minor
Connects-to: #2119
Signed-off-by: Scott Lowe <scott@balena.io>
2020-12-11 12:48:44 +01:00
836ae1cf4a v12.32.2 2020-12-11 03:11:16 +02:00
b4d37e7a3a Merge pull request #2133 from balena-io/apps-column-match-not-a-function
apps: Fix "column.match is not a function" when --verbose is used
2020-12-11 01:08:46 +00:00
055ad834e7 apps: Fix "column.match is not a function" when --verbose is used
Change-type: patch
2020-12-11 00:31:59 +00:00
d2cb88dfb8 v12.32.1 2020-12-11 02:30:10 +02:00
d096743e78 Merge pull request #2130 from balena-io/ab77/onprem-refresh
Make balena-cli build on refreshed on-prem workers
2020-12-11 00:26:45 +00:00
511d0dbe26 Make balena-cli build on refreshed on-prem workers
* Fix 'balena ssh' test cases when using the Windows built-in ssh tool
* Fix Windows installer build in new balena CI workers (qqjs patch)
* Remove hardcoded path

Change-type: patch
2020-12-10 12:30:25 -08:00
6b0201866f v12.32.0 2020-12-10 18:42:18 +02:00
9e20b2b691 Merge pull request #2128 from balena-io/app-rename-orgs
Add organizations support to app rename command
2020-12-10 16:40:18 +00:00
665e0cf9d7 Add organizations support to app rename command
Change-type: minor
Connects-to: #2119
Signed-off-by: Scott Lowe <scott@balena.io>
2020-12-10 13:57:42 +01:00
b319ec7281 v12.31.0 2020-12-10 14:38:47 +02:00
ae3ccf759f Merge pull request #2113 from balena-io/1828-livepush-connection-lost
Livepush, logs: Automatically reconnect on 'Connection to device lost'
2020-12-10 12:36:45 +00:00
309b1ba6a0 v12.30.4 2020-12-10 10:20:29 +02:00
532c4a1862 Merge pull request #2125 from balena-io/fix-app-display
Fix app name output in app command
2020-12-10 08:18:28 +00:00
fc8b7c71fc Fix app name output in app command
Change-type: patch
Resolves: #2120
Signed-off-by: Scott Lowe <scott@balena.io>
2020-12-10 08:32:20 +01:00
07666e953f Livepush: Extend CTRL-C availability (don't ignore CTRL-C during image build)
Change-type: patch
2020-12-09 22:49:47 +00:00
54731c2d20 Livepush, logs: Automatically reconnect on 'Connection to device lost'
Change-type: minor
2020-12-09 20:43:14 +00:00
d00db5ea8c logs: Fix CTRL-C ignored on Windows (PowerShell, MSYS, Git for Windows)
Change-type: patch
2020-12-09 20:43:14 +00:00
5497835728 Livepush: Fix process not exiting on "Connection to device lost"
Resolves: #1828
Change-type: patch
2020-12-09 20:43:14 +00:00
5bb05f3a8c v12.30.3 2020-12-09 19:07:19 +02:00
659eda8cd1 Merge pull request #2117 from balena-io/add_device_deactivation_expected_errors
errors: Add expected errors for device deactivation
2020-12-09 17:05:41 +00:00
a19132d3bf errors: Add expected errors for device deactivation
Change-type: patch
Signed-off-by: Marios Balamatsias <mbalamatsias@gmail.com>
2020-12-09 14:52:51 +02:00
140993f554 v12.30.2 2020-12-08 13:02:07 +02:00
575eaf6de1 Merge pull request #2116 from balena-io/remove-v12
Remove remaining v12 switches
2020-12-08 11:00:07 +00:00
3edf7a038f Remove remaining v12 switches
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2020-12-08 11:00:36 +01:00
ad16c5270e v12.30.1 2020-12-07 16:14:13 +02:00
adadefdf3f Merge pull request #2115 from balena-io/fix-booleans
Standardize boolean flag typing
2020-12-07 14:12:14 +00:00
19fab40398 Standardize boolean flag typing
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2020-12-07 14:36:29 +01:00
4dc53eb056 v12.30.0 2020-12-07 14:30:09 +02:00
9c96da7515 Merge pull request #2112 from balena-io/add_deactive_cmd
device: Add deactivate command
2020-12-07 12:28:24 +00:00
8a3e386d21 packages: Bump balena-sdk and balena-errors
Update balena-sdk from 15.6.0 to 15.20.0
Update balena-errors from 4.4.1 to 4.7.1

Change-type: minor
Signed-off-by: Marios Balamatsias <mbalamatsias@gmail.com>
2020-12-07 13:19:02 +02:00
5eaa4cfb9f common-flags: Add default false on yes, force and verbose flags
Change-type: patch
Signed-off-by: Marios Balamatsias <mbalamatsias@gmail.com>
2020-12-07 13:17:51 +02:00
cb2b90732b device: Add deactivate command
Resolves: #1545
Change-type: minor
Signed-off-by: Marios Balamatsias <mbalamatsias@gmail.com>
2020-12-07 13:12:50 +02:00
090fc58d10 v12.29.1 2020-12-04 03:22:19 +02:00
3b05971098 Merge pull request #2114 from balena-io/devices-full-uuid
devices: Don't truncate device UUID to 7 chars when --json is used
2020-12-04 01:20:17 +00:00
aae6aff3e9 devices: Don't truncate device UUID to 7 chars when --json is used
Change-type: patch
2020-12-04 00:45:03 +00:00
0bae6546f2 v12.29.0 2020-12-01 16:07:38 +02:00
40ab27df26 Merge pull request #2108 from balena-io/scan_prod_devices
scan: Print production devices' info on scan
2020-12-01 14:04:58 +00:00
7d5a64f59a scan: Print production devices' info on scan
Resolves: #1713
Change-type: minor
Signed-off-by: Marios Balamatsias <mbalamatsias@gmail.com>
2020-12-01 13:31:29 +02:00
8115d156df v12.28.3 2020-11-26 16:48:38 +02:00
08fc1a3924 Merge pull request #2104 from balena-io/delay-investigation
Add ability to disable analytics for performance testing
2020-11-26 14:46:51 +00:00
950d173d27 Add ability to disable analytics for performance testing
Change-type: patch
Connects-to: #1708
Signed-off-by: Scott Lowe <scott@balena.io>
2020-11-26 13:47:48 +01:00
ac49246141 v12.28.2 2020-11-20 14:44:30 +02:00
0689074dd7 Merge pull request #2097 from balena-io/2096-login-unhandled-rejection
Fix unhandled rejection, --debug logic and add doc references to masterclasses
2020-11-20 12:42:13 +00:00
ee79c87723 v12.28.1 2020-11-20 12:57:08 +02:00
9dc9556619 Merge pull request #2099 from balena-io/2098-scan-json-spinner
scan: Prevent spinner animation output to stdout when --json is used
2020-11-20 10:55:23 +00:00
2f9212d622 scan: Prevent spinner animation output to stdout when --json is used
Change-type: patch
2020-11-20 00:23:26 +00:00
2bf59530c4 docs: Add references to the masterclasses in the CLI help and README
Change-type: patch
2020-11-19 18:13:45 +00:00
a4fd7d6118 Fix debug message logic (don't suggest --debug if it is already being used)
Change-type: patch
2020-11-19 18:13:45 +00:00
65f053dd6e Fix unhandled promise rejection when ~/.balena is not accessible
Resolves: #2096
Change-type: patch
2020-11-19 18:13:45 +00:00
8137b79078 v12.28.0 2020-11-19 20:03:53 +02:00
e9b5773bcb Merge pull request #2093 from balena-io/2091-livepush-use-dockerignore
Livepush: Ignore paths set in .dockerignore files
2020-11-19 18:00:54 +00:00
4768f76385 push: Reduce memory usage when filtering files with dockerignore
Change-type: patch
2020-11-19 14:24:54 +00:00
d6b3249274 Livepush: Refactor dockerignore filtering and add test cases
Change-type: patch
2020-11-19 14:24:54 +00:00
02a5466746 Livepush: Ignore paths set in .dockerignore files
Change-type: minor
Signed-off-by: Josh Bowling <josh@balena.io>
2020-11-19 14:24:44 +00:00
0831e5fa17 v12.27.4 2020-11-16 17:35:40 +02:00
4681d901f8 Merge pull request #2095 from balena-io/big-sur-notarization
Test code optimization: avoid running ~70 test cases twice
2020-11-16 15:32:39 +00:00
6a55613199 Test code optimization: avoid running ~70 test cases twice
Change-type: patch
2020-11-15 23:36:58 +00:00
893a39e891 docs: Add note about macOS Big Sur notarization workaround
Change-type: patch
2020-11-14 22:23:41 +00:00
fa4f91e08d v12.27.3 2020-11-11 19:25:53 +02:00
54dc37dbd3 Merge pull request #2094 from balena-io/expect-invalid-yaml
Avoid reporting balenarc parsing errors
2020-11-11 17:23:44 +00:00
1b0c14feab Avoid reporting balenarc parsing errors
Change-type: patch
Connects-to: #1100
Signed-off-by: Scott Lowe <scott@balena.io>
2020-11-11 17:04:26 +01:00
20e0810d2a v12.27.2 2020-11-09 14:41:47 +02:00
edc2e77ddd Merge pull request #2084 from balena-io/codewithcheese/append-dev
Modify `os download` help to mention `-dev` suffix
2020-11-09 12:39:51 +00:00
7da9a800cc Modify os download help to mention dev images
Change-type: patch
Signed-off-by: Thomas Manning <thomasm@balena.io>
2020-11-09 06:13:06 +00:00
2ba4405452 v12.27.1 2020-11-06 11:36:38 +02:00
e7ebf1ad12 Merge pull request #2081 from balena-io/app-disambiguation
Improve application-identifier disambiguation
2020-11-06 09:34:15 +00:00
46249e319b Improve application-identifier disambiguation
Change-type: patch
Resolves: #2077
Signed-off-by: Scott Lowe <scott@balena.io>
2020-11-06 09:39:36 +01:00
fcd0932df8 v12.27.0 2020-11-05 18:45:17 +02:00
34792ecce9 Merge pull request #2067 from balena-io/app-purge
Add command app purge
2020-11-05 16:43:14 +00:00
1e18096873 Add command app purge
Change-type: minor
Signed-off-by: Scott Lowe <scott@balena.io>
2020-11-05 17:07:06 +01:00
4da1ed3a56 v12.26.2 2020-11-05 16:03:57 +02:00
92b8741288 Merge pull request #2088 from balena-io/2087-resource-uuid
config generate + openBalena v3: Fix "Cannot read property '__id' of undefined"
2020-11-05 14:02:00 +00:00
6b4c28a026 config generate + openBalena v3: Fix "Cannot read property '__id' of undefined"
Change-type: patch
2020-11-05 13:22:15 +00:00
849fc24158 v12.26.1 2020-10-31 03:09:18 +02:00
16efb9748f Merge pull request #2074 from balena-io/devices-slug-undefined
devices: Fix "TypeError: Cannot read property 'slug' of undefined"
2020-10-31 01:07:16 +00:00
9d177609f5 devices: Fix "TypeError: Cannot read property 'slug' of undefined"
Change-type: patch
2020-10-31 00:29:50 +00:00
826b0659d6 v12.26.0 2020-10-29 12:40:24 +02:00
46d7d1d068 Merge pull request #2066 from balena-io/device-purge
Add command device purge
2020-10-29 10:38:32 +00:00
47fcffe368 Add command device purge
Change-type: minor
Resolves: #1547
Signed-off-by: Scott Lowe <scott@balena.io>
2020-10-29 11:03:37 +01:00
bb7cd7ac62 v12.25.6 2020-10-28 12:36:54 +02:00
a83f6c95df Merge pull request #2076 from balena-io/2075-ssh-service-regex
ssh: Fix "Found more than one container with a service name <name>"
2020-10-28 10:35:14 +00:00
7f000ee8c3 ssh: Fix "Found more than one container with a service name <name>"
Change-type: patch
2020-10-28 01:06:54 +00:00
e5e7bb4757 v12.25.5 2020-10-27 13:10:06 +02:00
37e6bd4b5c Merge pull request #2073 from balena-io/rm-hardcoded-command-ids
Remove need for hardcoded list of command ids
2020-10-27 11:08:27 +00:00
c48564e85a Remove need for hardcoded list of command ids
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2020-10-27 10:36:49 +01:00
8460dac066 v12.25.4 2020-10-26 08:23:55 +02:00
64ffcfdd91 Merge pull request #2072 from balena-io/1893-config-generate-application-ambiguous
config generate: Fix "Application is ambiguous" when app slug is used
2020-10-26 06:22:14 +00:00
077e25ebc4 Update Contributing document re commit messages / versionbot / changelog
Change-type: patch
2020-10-25 17:11:19 +00:00
709f009f9b config generate: Fix "Application is ambiguous" when app slug is used
Connects-to: #1893
Change-type: patch
2020-10-25 16:52:31 +00:00
116ab1fbc1 config generate: Fix device type compatibility check
Change-type: patch
2020-10-25 16:40:11 +00:00
260a30532a v12.25.3 2020-10-23 13:07:34 +03:00
7534042519 Merge pull request #2069 from balena-io/1053-buildArgs-compose
Fix `--buildArg` with compose projects; Convert `buildProject` to Typescript
2020-10-23 10:04:53 +00:00
6b208ec2ab build/deploy: Add more test cases (--buildArg option)
Change-type: patch
2020-10-21 14:25:40 +01:00
099d755900 Fix typing (don't assume that 'docker-toolbelt' uses Bluebird promises)
Change-type: patch
2020-10-21 14:25:40 +01:00
3199f15662 build/deploy: Fix --buildArg option with docker-compose.yml projects
Resolves: #1053
Change-type: patch
2020-10-21 13:02:47 +01:00
4c8dc29946 build/deploy: Fix image size notice at end of build
Change-type: patch
2020-10-21 13:02:47 +01:00
2b22fb89f1 Convert more code to Typescript (compose.js)
Change-type: patch
2020-10-21 13:02:47 +01:00
cf7d9246e5 v12.25.2 2020-10-21 15:02:26 +03:00
0d3106af0e Merge pull request #2070 from balena-io/revert-balenacli-styling
Fix preload --add-certificate, amend help for `version`, and revert `balenaCLI` styling in docs
2020-10-21 12:00:21 +00:00
478b5dd363 Revert styling of "balena CLI" as "balenaCLI"
Change-type: patch
2020-10-21 00:07:46 +01:00
0708608c7e Add help note regarding the version of Node.js printed by balena version -a
Connects-to: #2068
Change-type: patch
2020-10-21 00:07:45 +01:00
c245dc70c2 preload: Fix parsing of --add-certificate option, amend help for --app
Connects-to: #2063
Change-type: patch
2020-10-21 00:07:15 +01:00
4373ba7a5d v12.25.1 2020-10-13 11:58:10 +03:00
2cc8d15c05 Merge pull request #2054 from balena-io/ignore-unauthorized-errors
Treat authorization errors as expected
2020-10-13 08:56:13 +00:00
592efd0a2e Treat authorization errors as expected
Change-type: patch
Resolves: #2035
Signed-off-by: Scott Lowe <scott@balena.io>
2020-10-13 10:16:16 +02:00
31123d28f0 v12.25.0 2020-10-13 11:01:54 +03:00
9b6ffecaba Merge pull request #2061 from balena-io/2060-balenarc-no-sentry
Update Sentry, add BALENARC_NO_SENTRY var, refactor CLI initialization
2020-10-13 07:59:51 +00:00
d0e4fa0e59 Refactor initialization code (delete app-oclif.ts and app-common.ts)
Change-type: patch
2020-10-11 00:45:53 +01:00
cf376316bc Support BALENARC_NO_SENTRY env var to disable Sentry.io error reporting
Change-type: minor
2020-10-10 00:45:55 +01:00
8f0f3bda29 Update Sentry package (may fix "Maximum call stack size exceeded")
Change-type: patch
2020-10-09 13:03:53 +01:00
c33409adb0 v12.24.1 2020-10-07 19:28:54 +03:00
873eb1fc59 Merge pull request #2057 from balena-io/allow-alternative-signups
login: sign up at the configured balena instance
2020-10-07 16:27:08 +00:00
af70f16a9b login: sign up at the configured balena instance
Change-type: patch
Signed-off-by: Matthew McGinn <matthew@balena.io>
2020-10-07 09:20:50 -04:00
e8d757ca28 v12.24.0 2020-10-06 23:10:25 +03:00
63d3402924 Merge pull request #2056 from balena-io/scan-json
scan: Add '--json' option to help with scripting
2020-10-06 20:08:48 +00:00
8a506bc4c0 scan: Add '--json' option to help with scripting
Change-type: minor
2020-10-06 18:04:43 +01:00
a14d89fe10 v12.23.4 2020-10-06 00:48:28 +03:00
29ed0a232d Merge pull request #2053 from balena-io/fix-balenadev
Workaround balena-dev/oclif compatibility issues
2020-10-05 21:46:19 +00:00
8978221866 Update CONTRIBUTING.md re balena-dev workflow
Change-type: patch
2020-10-05 22:10:54 +01:00
2974c203b5 Add bin/balena* scripts to linter paths
Change-type: patch
2020-10-05 22:10:54 +01:00
c85acbd90b Workaround balena-dev/oclif compatibility issues
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2020-10-02 16:17:16 +02:00
8a808e25d0 v12.23.3 2020-10-02 15:22:36 +03:00
75687f51ac Merge pull request #2052 from balena-io/rename-actions
Rename actions-oclif/ to commands/
2020-10-02 12:20:57 +00:00
eddbdfe0dc Rename actions-oclif/ to commands/
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2020-10-02 13:42:23 +02:00
d8acc3f814 v12.23.2 2020-10-02 12:35:48 +03:00
fc8be3d8dc Merge pull request #2051 from balena-io/fix-push-emulated-flag
push: Fix accidental rename of `-e` (emulated) option
2020-10-02 09:33:46 +00:00
0ee02a4d73 v12.23.1 2020-10-02 11:50:46 +03:00
568fcb9759 Merge pull request #2049 from balena-io/refresh-contributing
Update the CONTRIBUTING.md document
2020-10-02 08:49:00 +00:00
6133bb2096 push: Fix accidental rename of -e (emulated) option
Accidentally renamed during oclif conversion in CLI v12.9.7.

Change-type: patch
2020-10-01 23:49:14 +00:00
48076464da Update the CONTRIBUTING.md document
Change-type: patch
2020-09-28 15:19:10 +01:00
1acf342fb0 v12.23.0 2020-09-25 18:13:07 +03:00
340ca6577b Merge pull request #2046 from balena-io/add-support
Add new command `support`
2020-09-25 15:11:05 +00:00
0a8b3ce4e4 Add new command support
Change-type: minor
Resolves: #766 #1546
Signed-off-by: Scott Lowe <scott@balena.io>
2020-09-25 16:20:45 +02:00
65c01ac172 v12.22.2 2020-09-20 03:20:05 +03:00
4c9a22aba7 Merge pull request #2041 from balena-io/2040-fix-deploy-exit
deploy: Fix unexpected exit with "Everything is up to date"
2020-09-20 00:18:08 +00:00
889fafcffc deploy: Fix unexpected exit with "Everything is up to date"
Resolves: #2040
Change-type: patch
2020-09-20 00:35:57 +01:00
719cc2e4c9 v12.22.1 2020-09-19 12:23:16 +03:00
e484701276 Merge pull request #2039 from balena-io/1760-simplify-install-docs
Reorganize and simplify installation instructions
2020-09-19 09:21:20 +00:00
b1897a512d Style "balena CLI" as "balenaCLI" and "balena cloud" as "balenaCloud"
Change-type: patch
2020-09-18 23:27:24 +01:00
f98c25eaee Reorganize and simplify installation instructions
Change-type: patch
2020-09-18 14:13:32 +01:00
b9c3b57b85 v12.22.0 2020-09-18 15:41:12 +03:00
8aff330516 Merge pull request #2038 from balena-io/add-device-restart
Add new command `device restart`
2020-09-18 12:39:09 +00:00
abdaf0043f Add new command device restart
Change-type: minor
Resolves: #1542
Signed-off-by: Scott Lowe <scott@balena.io>
2020-09-18 12:39:53 +02:00
960cb3098d v12.21.1 2020-09-17 03:48:23 +03:00
e907f12445 Merge pull request #2037 from balena-io/2036-scan-sync-standalone
scan: Fix "CLI could not be loaded" with the standalone zip installer
2020-09-17 00:46:19 +00:00
799e0f9dea scan: Fix "CLI could not be loaded" with the standalone zip installer
Change-type: patch
2020-09-17 00:38:00 +01:00
c389f41006 v12.21.0 2020-09-16 18:16:57 +03:00
74ca5207ad Merge pull request #2034 from balena-io/add-app-rename
Add new command `app rename`
2020-09-16 15:14:54 +00:00
3706db2436 Add new command app rename
Change-type: minor
Resolves: #1567
Signed-off-by: Scott Lowe <scott@balena.io>
2020-09-16 16:38:10 +02:00
6ec0b4a3bd v12.20.0 2020-09-10 21:28:04 +03:00
e65caed64e Merge pull request #2033 from balena-io/post-capitano-refactor
Improve command suggestions, add topic help
2020-09-10 18:26:29 +00:00
b180eb7b73 Minor fix to device rm
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2020-09-10 17:34:06 +02:00
9805854eab Update registry secrets example URL
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2020-09-10 17:33:57 +02:00
00c956394d Improve command suggestions, add topic help
Change-type: minor
Resolves: #2021
Signed-off-by: Scott Lowe <scott@balena.io>
2020-09-10 15:56:45 +02:00
b3510f205f v12.19.0 2020-09-10 15:09:25 +03:00
e755d9f03f Merge pull request #2032 from balena-io/misc-bugfixes
Misc bugfixes
2020-09-10 12:07:33 +00:00
f9224b05af Fix numerical id support in device rm
Change-type: patch
Resolves: #2031
Signed-off-by: Scott Lowe <scott@balena.io>
2020-09-10 12:53:02 +02:00
ece4d88bfd Fix numerical id support in device move
Change-type: patch
Resolves: #2030
Signed-off-by: Scott Lowe <scott@balena.io>
2020-09-10 12:53:02 +02:00
0dd7c33237 Fix required status of param in os versions
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2020-09-10 12:53:02 +02:00
cd20f1765e Merge pull request #2028 from balena-io/join-poll
Add ability to specify poll interval in join command
2020-09-09 13:56:12 +00:00
0ca1faba09 Add ability to specify poll interval in join command
Change-type: minor
Resolves: #1432 #1697 #1670
Signed-off-by: Scott Lowe <scott@balena.io>
2020-09-09 14:24:45 +02:00
9f8569e33f Improve error handling in internal scandevices
Change-type: patch
Connects-to: #1703
Signed-off-by: Scott Lowe <scott@balena.io>
2020-09-09 14:24:45 +02:00
d7007721a7 v12.18.0 2020-09-09 14:38:49 +03:00
f9f1863fdb Merge pull request #2027 from balena-io/1584-push-pull
push (local device): Add --pull option to force pulling base images again
2020-09-09 11:36:41 +00:00
93e18bea27 push (local device): Add --pull option to force pulling base images again
Connects-to: #1584
Change-type: minor
2020-09-09 00:16:22 +01:00
73f49765ec push: Reformat help output to fit in 80 characters
Connects-to: #1858
Change-type: patch
2020-09-09 00:16:21 +01:00
3a508dc397 v12.17.2 2020-09-08 21:16:44 +03:00
bd5bf0135a Merge pull request #2026 from balena-io/fix-device-issue
Fix error displaying info for devices without commits
2020-09-08 18:14:24 +00:00
e0c65bdef8 Fix error displaying info for devices without commits
Change-type: patch
Resolves: #2024
Signed-off-by: Scott Lowe <scott@balena.io>
2020-09-08 18:57:00 +02:00
b9d90b9e38 v12.17.1 2020-09-08 15:16:37 +03:00
d910319ba5 Merge pull request #2025 from balena-io/convert-help-fixes
Fix issues from removal of capitano
2020-09-08 12:14:34 +00:00
5e5a2c1c85 Fix usage info for env rename
Change-type: patch
Resolves: #2019
Signed-off-by: Scott Lowe <scott@balena.io>
2020-09-08 13:31:41 +02:00
238c371ade Fix typo in docs help section
Change-type: patch
Resolves: #2020
Signed-off-by: Scott Lowe <scott@balena.io>
2020-09-08 13:23:39 +02:00
504877c232 Fix issue with replaced command checks
Change-type: patch
Resolves: #2022
Signed-off-by: Scott Lowe <scott@balena.io>
2020-09-08 13:13:53 +02:00
bdcf58471f v12.17.0 2020-09-07 16:31:25 +03:00
46b9c586a6 Merge pull request #2018 from balena-io/convert-help
Convert help, remove capitano
2020-09-07 13:29:24 +00:00
273ea5ce4d Display command suggestions, when command not recognized
Change-type: minor
Signed-off-by: Scott Lowe <scott@balena.io>
2020-09-07 14:35:35 +02:00
d56fec6e36 Convert help to oclif, remove capitano
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2020-09-07 14:13:32 +02:00
cd81ff005f v12.16.0 2020-09-04 14:09:05 +03:00
dee216eeaa Merge pull request #2015 from balena-io/1584-build-pull
build, deploy: Add --pull option to force pulling base images again
2020-09-04 11:07:00 +00:00
d1539f405a build, deploy: Add --pull option to force pulling base images again
Resolves: #1584
Change-type: minor
2020-09-04 10:28:36 +01:00
d131fb4fa8 v12.15.1 2020-09-04 12:26:57 +03:00
a0380848a0 Merge pull request #2017 from balena-io/modify-undervoltage-field
Modify undervoltage status display in device command
2020-09-04 09:25:00 +00:00
ffa8e245ba Modify undervoltage status display in device command
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2020-09-04 10:32:40 +02:00
8631e22686 v12.15.0 2020-09-03 20:31:45 +03:00
f0bd3a38db Merge pull request #2014 from balena-io/new-device-fields
Add support for new device metrics to device command
2020-09-03 17:29:18 +00:00
88569066b5 Add support for new device metrics to device command
Change-type: minor
Signed-off-by: Scott Lowe <scott@balena.io>
2020-09-03 18:26:53 +02:00
c20bbe658b v12.14.18 2020-08-28 17:10:37 +03:00
ac0ce8f702 Merge pull request #2013 from balena-io/async-await-oclif
Convert oclif actions to async/await
2020-08-28 14:08:48 +00:00
42c6e1010f Convert oclif actions to async/await
Change-type: patch
2020-08-28 13:43:10 +01:00
1f4554abe8 v12.14.17 2020-08-27 17:51:29 +03:00
4e457da5a9 Merge pull request #2011 from balena-io/improve-preload-typings
preload: Improve the typings
2020-08-27 14:48:34 +00:00
2e1570149d preload: Improve the typings
Change-type: patch
Depends-on: https://github.com/balena-io/balena-sdk/pull/980
See: https://github.com/balena-io/balena-cli/pull/2007#discussion_r478330624
Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
2020-08-27 16:44:08 +03:00
c647989054 Update balena-sdk to 15.3.7
Update balena-sdk from 15.3.1 to 15.3.7

Change-type: patch
2020-08-27 12:51:13 +00:00
44bd667648 v12.14.16 2020-08-27 15:37:55 +03:00
2d042ee116 Merge pull request #2010 from balena-io/update-typescript
Update to typescript 4.0
2020-08-27 13:35:40 +01:00
787966a0b6 Update to typescript 4.0
Change-type: patch
2020-08-27 11:50:57 +01:00
a59d85e833 v12.14.15 2020-08-27 13:25:58 +03:00
d0616acf1b Merge pull request #2007 from balena-io/convert-preload
Convert command preload to oclif, typescript
2020-08-27 10:23:08 +00:00
d21a18f353 Convert command preload to oclif, typescript
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2020-08-27 10:19:54 +02:00
7d3dbc2c0b v12.14.14 2020-08-26 17:13:46 +03:00
529b98552c Merge pull request #2004 from balena-io/dont-try-to-parse-uuid-as-integer-in-tunnel
Don't try to parse deviceOrApplication as an integer in the tunnel action
2020-08-26 14:11:55 +00:00
99a478ee39 Fix device UUID parsing for 'balena tunnel'
Change-type: patch
2020-08-26 15:10:00 +02:00
fb879d3020 v12.14.13 2020-08-26 13:40:27 +03:00
4fb4cce842 Merge pull request #2006 from balena-io/1993-preload-logo
preload: Fix splash image file name for balenaOS >= 2.53.0
2020-08-26 10:38:14 +00:00
f772957d29 preload: Fix splash image file name for balenaOS >= 2.53.0
Resolves: #1993
Change-type: patch
2020-08-26 10:48:30 +01:00
fd9520224c v12.14.12 2020-08-24 13:14:10 +03:00
c1afaa6cf3 Merge pull request #2000 from balena-io/convert-deploy
Convert deploy command to oclif
2020-08-24 10:12:03 +00:00
8cb413c1c9 Convert deploy command to oclif
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2020-08-22 11:58:10 +02:00
e96fca551e v12.14.11 2020-08-21 14:28:43 +03:00
edb3ea53fb Merge pull request #2001 from balena-io/fix-template-patch
Fix help template bug affecting discrete value options
2020-08-21 11:26:26 +00:00
358a909214 Shorten env add command summary to prevent wrapping
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2020-08-21 12:43:12 +02:00
eb74ca631a Fix help template bug affecting discrete value options
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2020-08-21 12:41:35 +02:00
64ebebb121 v12.14.10 2020-08-15 01:49:55 +03:00
abc62404ab Merge pull request #1997 from balena-io/1992-fix-build-args
build: Fix --buildArg and --cache-from options (broken since v12.9.9)
2020-08-14 22:47:48 +00:00
af1c4b0d03 build: Fix --buildArg and --cache-from options (broken since v12.9.9)
Change-type: patch
2020-08-14 23:12:12 +01:00
830e1f801d v12.14.9 2020-08-14 16:49:45 +03:00
59c398fbf0 Merge pull request #1995 from balena-io/update-deps
Update dependencies
2020-08-14 13:47:42 +00:00
d7f49d2442 Update dependencies
Update balena-sdk from 15.3.0 to 15.3.1

Change-type: patch
2020-08-14 13:28:06 +01:00
34597f629d v12.14.8 2020-08-14 01:51:05 +03:00
3fa7eec8a9 Merge pull request #1996 from balena-io/fix-tar-stream
build / push: Fix sudden process crash (update tar-utils dependency)
2020-08-13 22:49:17 +00:00
1ee12b70bc build / push: Fix sudden process crash (update tar-utils dependency)
Change-type: patch
2020-08-13 23:05:11 +01:00
ca7b1ae084 v12.14.7 2020-08-13 18:03:37 +03:00
936d3cb62a Merge pull request #1994 from balena-io/update-deps
Update dependencies
2020-08-13 15:01:20 +00:00
230677e5e8 Update dependencies
Update balena-sdk from 15.2.5 to 15.3.0

Change-type: patch
2020-08-13 14:36:13 +01:00
025f817eb6 v12.14.6 2020-08-12 18:29:07 +03:00
54cceb688f Merge pull request #1982 from balena-io/allow-shrinkwrap-rebase
Allow rebasing of npm-shrinkwrap
2020-08-12 15:27:15 +00:00
648a73fd91 Tests: check shrinkwrap is deduped
Change-type: patch
2020-08-12 15:34:53 +01:00
3691ae148e Allow rebasing of npm-shrinkwrap
Change-type: patch
2020-08-12 14:46:51 +01:00
4496bc88f5 v12.14.5 2020-08-11 20:24:07 +03:00
afded27692 Merge pull request #1974 from balena-io/sdk-15
Update balena-sdk to 15.x
2020-08-11 17:21:59 +00:00
c1a5718364 Avoid trying to refresh token in tests 2020-08-11 17:54:39 +01:00
e021ad9af6 Update balena-sdk to 15.x
Update balena-config-json from 4.0.0 to 4.1.0
Update balena-image-manager from 7.0.1 to 7.0.3
Update balena-preload from 10.2.0 to 10.2.4
Update balena-sdk from 14.8.0 to 15.2.1
Update balena-sync from 11.0.0 to 11.0.2

Change-type: patch
2020-08-11 17:53:33 +01:00
5c8a5165e0 v12.14.4 2020-08-11 19:27:44 +03:00
71ff73c641 Merge pull request #1989 from balena-io/improve-tests
Improve tests
2020-08-11 16:25:57 +00:00
c35472e94d Tests: Specify es2018 as preferred, matching normal usage
Change-type: patch
2020-08-11 16:07:23 +01:00
511bb05cb9 Tests: Use a tmp data dir to avoid conflicts/overwriting existing data
Change-type: patch
2020-08-11 16:05:28 +01:00
53b2b54b23 Tests: Use a mocha file helper to always load config-tests first
Change-type: patch
2020-08-11 16:04:28 +01:00
e7f753007f Tests: Share mocha options between commands in package.json
Change-type: patch
2020-08-11 16:03:36 +01:00
0afaf8502f v12.14.3 2020-08-11 16:06:00 +03:00
3272b55dd9 Merge pull request #1988 from balena-io/avoid-unnecessary-tests
CI: Avoid unnecessary duplicate windows/mac tests
2020-08-11 13:04:02 +00:00
4c664167f6 CI: Avoid duplicate windows/mac tests
Change-type: patch
2020-08-11 12:32:36 +01:00
604c182e2c v12.14.2 2020-08-10 16:46:37 +03:00
60593a77ac Merge pull request #1987 from balena-io/lazy-load-tar-stream
Lazy load tar-stream
2020-08-10 13:44:39 +00:00
497c8cd49b Lazy load tar-stream
Change-type: patch
2020-08-10 12:01:55 +01:00
d348d9f71f v12.14.1 2020-08-08 01:23:00 +03:00
d6651fdd7e Merge pull request #1969 from balena-io/update-balena-sdk
Update balena-sdk to 14.x
2020-08-07 22:21:14 +00:00
e1c42405a1 Update balena-sdk to 14.x
Update balena-sdk from 13.6.0 to 14.8.0

Change-type: patch
2020-08-07 21:06:07 +00:00
bf22d9eaa8 v12.14.0 2020-08-07 23:58:35 +03:00
88523a2887 Merge pull request #1986 from balena-io/bump-chokidar-livepush
Live push: Accept Dockerfile ENV instructions in push to local device
2020-08-07 20:56:30 +00:00
e8eb031253 Live push: Accept Dockerfile ENV instructions in live push to local device
Update livepush, chokidar and @types/dockerode dependencies

Change-type: minor
2020-08-07 21:09:47 +01:00
120c82d657 v12.13.0 2020-08-07 18:13:27 +03:00
cb2e60d5af Merge pull request #1985 from balena-io/devices-json
devices: Add '--json' option to help with scripting
2020-08-07 15:11:32 +00:00
62dfae371c devices: Add '--json' option to help with scripting
Change-type: minor
2020-08-07 15:27:42 +01:00
eaf220b64f v12.12.2 2020-08-07 15:26:38 +03:00
9804dd3c33 Merge pull request #1983 from balena-io/pkg-warning-diff
Tests: add verification of 'pkg' warnings against saved output
2020-08-07 12:24:40 +00:00
94f3825119 Tests: add verification of 'pkg' warnings against saved output
Change-type: patch
2020-08-07 01:47:31 +01:00
abde3cf48a v12.12.1 2020-08-05 16:14:57 +03:00
efb488f81a Merge pull request #1977 from balena-io/reduce-bluebird
Reduce bluebird usage
2020-08-05 13:12:59 +00:00
6ca7c34e57 Reduce bluebird usage
Change-type: patch
2020-08-05 09:41:15 +01:00
3f084366db v12.12.0 2020-08-05 03:27:13 +03:00
9f98529e56 Merge pull request #1962 from nwneisen/1956-bulk-add-env-vars
Add ability to add env var to multiple locations in one command
2020-08-05 00:25:32 +00:00
bab98df87b env add: Add ability to add env var to multiple locations in one command
Change-type: minor
2020-08-04 17:40:26 -06:00
4d9affd030 v12.11.3 2020-08-04 22:28:57 +03:00
15b536a3b2 Merge pull request #1980 from balena-io/dont-change-preloader-config
Dont set the preloader config device type to intel-nuc
2020-08-04 19:26:42 +00:00
505acc19db Dont set the preloader config device type to intel-nuc
Change-type: patch
2020-08-04 20:12:28 +02:00
1d566a72ca v12.11.2 2020-08-04 20:23:26 +03:00
0337e284a6 Merge pull request #1978 from balena-io/1975-fix-os-build-config-undefined
os build-config: Fix output file containing 'undefined' word since v12.9.4
2020-08-04 17:21:25 +00:00
74c6f8a627 os build-config: Fix output file containing 'undefined' word since v12.9.4
Resolves: #1975
Change-type: patch
2020-08-04 17:27:20 +01:00
7aa1708f46 v12.11.1 2020-08-04 19:25:57 +03:00
32a21684e8 Merge pull request #1976 from balena-io/balena-release-v3
Update balena-release to v3
2020-08-04 16:23:50 +00:00
a52a623fdf Update balena-release to v3
Change-type: patch
Signed-off-by: Thodoris Greasidis <thodoris@balena.io>
2020-08-04 15:35:29 +00:00
b63e31e255 v12.11.0 2020-08-04 18:34:05 +03:00
fec01977c7 Merge pull request #1972 from balena-io/1773-browser-login-port-number
login: Use any free port number instead of 8989 for web authentication
2020-08-04 15:32:06 +00:00
cf894d98a5 login: Use any free port number instead of 8989 for web authentication
Change-type: minor
2020-08-03 20:26:10 +01:00
d18f25cb9c Testing: Increase mocha timeout from 6s to 12s (experimental)
Change-type: patch
2020-08-03 20:26:10 +01:00
4cdff9694e Update GitHub issue template (request openBalena vs balenaCloud info)
Change-type: patch
2020-08-03 20:26:10 +01:00
304ade9772 v12.10.2 2020-08-03 18:57:08 +03:00
0865633020 Merge pull request #1973 from balena-io/fix-per-regression
Fix performance regressions from #1967
2020-08-03 15:55:16 +00:00
ddb87f403d Fix performance regressions from #1967
Change-type: patch
2020-08-03 11:04:36 +01:00
8047779c0c v12.10.1 2020-07-31 15:00:00 +03:00
9da7f03b2a Merge pull request #1966 from balena-io/reduce-bluebird
Remove some bluebird usage
2020-07-31 11:58:03 +00:00
9aacb7ec56 Remove some bluebird usage
Change-type: patch
2020-07-31 10:33:51 +00:00
41e7ba12ff v12.10.0 2020-07-30 22:22:32 +03:00
10decc785d Merge pull request #1952 from nwneisen/1951-bulk-device-rm
Add ability to remove multiple devices in one command
2020-07-30 19:19:56 +00:00
47e9d39c6f device rm: Add ability to remove multiple devices in one command
Change-type: minor
2020-07-30 10:31:48 -06:00
0eb4e6d770 v12.9.9 2020-07-30 17:31:34 +03:00
492b877d02 Merge pull request #1967 from balena-io/convert-build
Convert command `build` to typescript, oclif, and refactor
2020-07-30 14:27:36 +00:00
09b8cc495c Convert command build to typescript, oclif, and refactor
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2020-07-30 15:53:55 +02:00
94cc84e5ce v12.9.8 2020-07-30 16:04:09 +03:00
cd3fa4521c Merge pull request #1968 from balena-io/tests-reliability
Tests: improve reliability of os/configure.spec.ts
2020-07-30 13:02:04 +00:00
5d7d687d6c Tests: improve reliability of os/configure.spec.ts
Change-type: patch
2020-07-30 13:24:41 +01:00
5b39878d54 v12.9.7 2020-07-29 16:10:35 +03:00
2c24d80492 Merge pull request #1960 from balena-io/convert-push
Convert command `push` to oclif
2020-07-29 13:08:26 +00:00
0f058a4441 Convert command push to oclif
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2020-07-29 10:53:17 +00:00
66f793e327 v12.9.6 2020-07-29 13:52:06 +03:00
60917f641b Merge pull request #1964 from balena-io/convert-config
Convert `config` commands to typescript, oclif
2020-07-29 10:50:16 +00:00
56cc70cd50 Convert config commands to typescript, oclif
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2020-07-29 12:11:18 +02:00
fd4c740d29 v12.9.5 2020-07-28 20:22:34 +03:00
644e643fab Merge pull request #1934 from balena-io/bump-preload-v10
Adjustments for balena-preload v10 (SDK v14). Improved error reporting.
2020-07-28 17:20:34 +00:00
f6529eec26 Adjustments for balena-preload v10 (SDK v14). Improved error reporting.
Change-type: patch
2020-07-28 16:12:11 +00:00
401c116820 v12.9.4 2020-07-28 19:08:34 +03:00
4e37ce14c6 Merge pull request #1953 from balena-io/convert-os-build-config
Convert `os build-config` to oclif, typescript
2020-07-28 16:06:36 +00:00
3fc25cd745 Convert os build-config to oclif, typescript
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2020-07-28 15:33:28 +00:00
598423acaa v12.9.3 2020-07-28 18:12:50 +03:00
1685ce16f4 Merge pull request #1954 from balena-io/update-net-keepalive3
Update net-keepalive to v1.3.3, reclaiming ~200MB disk space (npm install)
2020-07-28 15:10:50 +00:00
d4de25e545 Update net-keepalive to v1.3.3, reclaiming ~200MB disk space (npm install)
Change-type: patch
2020-07-28 14:38:26 +00:00
d1f46a59f7 v12.9.2 2020-07-28 17:28:54 +03:00
29854f8737 Merge pull request #1947 from balena-io/rename-devices-beta-new
Rename BETA to NEW in `devices supported -v`
2020-07-28 14:26:37 +00:00
7eb398c6ef devices supported: Rename 'BETA' to 'NEW' in verbose output
Change-type: patch
2020-07-27 20:23:51 +00:00
9ed3bb2f70 os download: Improve warning message re default balenaOS version
Change-type: patch
2020-07-27 20:23:51 +00:00
839de65df2 v12.9.1 2020-07-16 17:41:39 +03:00
b2c680e824 Merge pull request #1948 from balena-io/convert-os-initialize
Convert `os initialize` to oclif, typescript
2020-07-16 14:39:03 +00:00
b7c74598b2 Convert os initialize to oclif, typescript
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2020-07-16 16:06:41 +02:00
7b78a777ac v12.9.0 2020-07-15 21:04:53 +03:00
82026897c7 Merge pull request #1940 from balena-io/update-net-keepalive2
Update net-keepalive and pkg, Node.js >= v10.20.0 (steps towards Node.js v14)
2020-07-15 18:03:07 +00:00
0534ab1cb4 Update INSTALL.md re new minimum Node.js version of 10.20.0
Change-type: patch
2020-07-15 16:30:15 +00:00
a6a8dc822f Update net-keepalive and pkg, Node.js >= v10.20.0 (steps towards Node.js v14)
Change-type: minor
2020-07-15 16:30:15 +00:00
b0dce6b477 Add ability to conditionally apply patches per platform (Linux, Mac, Windows)
Change-type: patch
2020-07-15 16:30:15 +00:00
b9734b7b09 v12.8.0 2020-07-15 18:02:21 +03:00
24ba9da64b Merge pull request #1939 from nwneisen/323-bulk-device-move
balena device: Add ability to move multiple devices in one command
2020-07-15 15:00:33 +00:00
edaf76e329 device move: Add ability to move multiple devices in one command
Change-type: minor
2020-07-15 08:26:31 -06:00
d419ae9183 v12.7.7 2020-07-15 01:19:21 +03:00
3833dc3adc Merge pull request #1941 from balena-io/convert-os-download
Convert `os download` to oclif, typescript
2020-07-14 22:16:13 +00:00
5d3625f6ae Remove os download command dependency for device init
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2020-07-14 23:42:39 +02:00
1c17572db0 Convert os download to oclif, typescript
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2020-07-14 23:42:39 +02:00
c65dafd2ff v12.7.6 2020-07-14 18:48:43 +03:00
33fd24b981 Merge pull request #1943 from balena-io/convert-os-versions
Convert `os versions` to oclif, typescript
2020-07-14 15:46:50 +00:00
41635c746b Convert os versions to oclif, typescript
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2020-07-14 17:11:30 +02:00
8c12510f17 v12.7.5 2020-07-13 15:01:52 +03:00
50a658f2f6 Merge pull request #1937 from balena-io/convert-local-config
Convert `local configure` to oclif, typescript
2020-07-13 11:59:58 +00:00
4f831ef443 Convert local configure to oclif, typescript
Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
2020-07-13 13:10:26 +02:00
457eff1d43 v12.7.4 2020-07-13 13:42:03 +03:00
9e7a13a992 Merge pull request #1935 from nwneisen/1731-improve-ssh-error-message
Give a better error message on "balena ssh" when the keys don't match
2020-07-13 10:40:05 +00:00
d9cf95149a balena ssh: Improve error message in case of misconfigured SSH keys
Change-type: patch
2020-07-12 19:39:49 -06:00
383 changed files with 83865 additions and 40381 deletions

37
.dockerignore Normal file
View File

@ -0,0 +1,37 @@
# Reminders:
# * Matching rules are different to `.gitignore`
# * A pattern without '**' matches in the project's root directory only
# * Leading and trailing '/' are discarded (it is not possible to
# distinguish between files and directories)
# * More details: https://github.com/balena-io-modules/dockerignore
# development and testing tools or IDEs
**/*.log
**/*.pid
**/*.seed
.idea
.lock-wscript
.nvmrc
.nyc_output
.vscode
coverage
lib-cov
logs
pids
# OS cache files
**/.DS_Store
# balena CLI config and build files
**/.balenaconf
**/.fast-boot.json
**/.resinconf
balenarc.yml
build
build-bin
dist
node_modules
oclif.manifest.json
package-lock.json
resinrc.yml
tmp

9
.gitattributes vendored
View File

@ -4,12 +4,13 @@
*.* -eol
*.sh text eol=lf
.dockerignore eol=lf
Dockerfile eol=lf
Dockerfile.* eol=lf
* text=auto eol=lf
# lf for the docs as it's auto-generated and will otherwise trigger an uncommited error on windows
doc/cli.markdown text eol=lf
docs/balena-cli.md text eol=lf
# crlf for the eol conversion test files
tests/test-data/projects/docker-compose/basic/service2/file2-crlf.sh eol=crlf
tests/test-data/projects/no-docker-compose/basic/src/windows-crlf.sh eol=crlf
# Prevent auto merging of the npm-shrinkwrap.json file: see notes in CONTRIBUTING.md
/npm-shrinkwrap.json merge=binary

1
.github/CODEOWNERS vendored
View File

@ -1 +0,0 @@
* @balena-io/balena-cli

View File

@ -11,8 +11,8 @@ community can both contribute and benefit from the answers.*
*Please also check that this issue is not a duplicate. If there is another issue describing
the same problem or feature please add comments to the existing issue.*
*Thank you for your time and effort creating the issue report, and helping us improve the
balena CLI!*
*Thank you for your time and effort creating the issue report, and helping us improve
the balena CLI!*
---
@ -32,11 +32,11 @@ Please describe what actually happened instead:
Examples:
```
balena push myApp
balena push myFleet
balena push 192.168.0.12
balena deploy myApp
balena deploy myApp --build
balena build . -a myApp
balena deploy myFleet
balena deploy myFleet --build
balena build . -f myFleet
balena build . -A armv7hf -d raspberrypi3
```
@ -48,7 +48,7 @@ additional information. The `--logs` option reveals additional information for t
```
balena build . --logs
balena deploy myApp --build --logs
balena deploy myFleet --build --logs
```
# Steps to Reproduce the Problem
@ -64,6 +64,7 @@ fixed it.
# Specifications
- **balena CLI version:** e.g. 1.2.3 (output of the `"balena version -a"` command)
- **Cloud backend: openBalena or balenaCloud?** If unsure, it will be balenaCloud
- **Operating system version:** e.g. Windows 10, Ubuntu 18.04, macOS 10.14.5
- **32/64 bit OS and processor:** e.g. 32-bit Windows on 64-bit Intel processor
- **Install method:** npm or zip package or executable installer

143
.github/actions/publish/action.yml vendored Normal file
View File

@ -0,0 +1,143 @@
---
name: package and draft GitHub release
# https://github.com/product-os/flowzone/tree/master/.github/actions
inputs:
json:
description: 'JSON stringified object containing all the inputs from the calling workflow'
required: true
secrets:
description: 'JSON stringified object containing all the secrets from the calling workflow'
required: true
variables:
description: 'JSON stringified object containing all the variables from the calling workflow'
required: true
# --- custom environment
XCODE_APP_LOADER_EMAIL:
type: string
default: 'accounts+apple@balena.io'
NODE_VERSION:
type: string
default: '20.x'
VERBOSE:
type: string
default: 'true'
runs:
# https://docs.github.com/en/actions/creating-actions/creating-a-composite-action
using: 'composite'
steps:
- name: Download custom source artifact
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
with:
name: custom-${{ github.event.pull_request.head.sha || github.event.head_commit.id }}-${{ runner.os }}-${{ runner.arch }}
path: ${{ runner.temp }}
- name: Extract custom source artifact
shell: pwsh
working-directory: .
run: tar -xf ${{ runner.temp }}/custom.tgz
- name: Setup Node.js
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
with:
node-version: ${{ inputs.NODE_VERSION }}
cache: npm
- name: Set up Python 3.11
if: runner.os == 'macOS'
uses: actions/setup-python@65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236 # v4
with:
python-version: "3.11"
- name: Install additional tools
if: runner.os == 'Windows'
shell: bash
run: |
choco install yq
- name: Install additional tools
if: runner.os == 'macOS'
shell: bash
run: |
brew install coreutils
# https://www.electron.build/code-signing.html
# https://github.com/Apple-Actions/import-codesign-certs
- name: Import Apple code signing certificate
if: runner.os == 'macOS'
uses: apple-actions/import-codesign-certs@8f3fb608891dd2244cdab3d69cd68c0d37a7fe93 # v2
with:
p12-file-base64: ${{ fromJSON(inputs.secrets).APPLE_SIGNING }}
p12-password: ${{ fromJSON(inputs.secrets).APPLE_SIGNING_PASSWORD }}
- name: Import Windows code signing certificate
if: runner.os == 'Windows'
shell: powershell
run: |
Set-Content -Path ${{ runner.temp }}/certificate.base64 -Value $env:SM_CLIENT_CERT_FILE_B64
certutil -decode ${{ runner.temp }}/certificate.base64 ${{ runner.temp }}/Certificate_pkcs12.p12
Remove-Item -path ${{ runner.temp }} -include certificate.base64
env:
SM_CLIENT_CERT_FILE_B64: ${{ fromJSON(inputs.secrets).SM_CLIENT_CERT_FILE_B64 }}
# https://github.com/product-os/scripts/tree/master/shared
# https://github.com/product-os/balena-concourse/blob/master/pipelines/github-events/template.yml
- name: Package release
shell: bash
run: |
set -ea
[[ '${{ inputs.VERBOSE }}' =~ on|On|Yes|yes|true|True ]] && set -x
runner_os="$(echo "${RUNNER_OS}" | tr '[:upper:]' '[:lower:]')"
runner_arch="$(echo "${RUNNER_ARCH}" | tr '[:upper:]' '[:lower:]')"
if [[ $runner_os =~ darwin|macos|osx ]]; then
CSC_KEY_PASSWORD='${{ fromJSON(inputs.secrets).APPLE_SIGNING_PASSWORD }}'
CSC_KEYCHAIN=signing_temp
CSC_LINK=${{ fromJSON(inputs.secrets).APPLE_SIGNING }}
elif [[ $runner_os =~ windows|win ]]; then
SM_HOST=${{ fromJSON(inputs.secrets).SM_HOST }}
SM_API_KEY=${{ fromJSON(inputs.secrets).SM_API_KEY }}
SM_CLIENT_CERT_FILE='${{ runner.temp }}\Certificate_pkcs12.p12'
SM_CLIENT_CERT_PASSWORD=${{ fromJSON(inputs.secrets).SM_CLIENT_CERT_PASSWORD }}
SM_CODE_SIGNING_CERT_SHA1_HASH=${{ fromJSON(inputs.secrets).SM_CODE_SIGNING_CERT_SHA1_HASH }}
curl --silent --retry 3 --fail https://one.digicert.com/signingmanager/api-ui/v1/releases/smtools-windows-x64.msi/download \
-H "x-api-key:$SM_API_KEY" \
-o smtools-windows-x64.msi
msiexec -i smtools-windows-x64.msi -qn
PATH="/c/Program Files/DigiCert/DigiCert One Signing Manager Tools:${PATH}"
smksp_registrar.exe list
smctl.exe keypair ls
/c/Windows/System32/certutil.exe -csp "DigiCert Signing Manager KSP" -key -user
smksp_cert_sync.exe
# (signtool.exe) https://github.com/actions/runner-images/blob/main/images/win/Windows2019-Readme.md#installed-windows-sdks
PATH="/c/Program Files (x86)/Windows Kits/10/bin/${runner_arch}:${PATH}"
fi
npm run package
find dist -type f -maxdepth 1
env:
# https://github.blog/2020-08-03-github-actions-improvements-for-fork-and-pull-request-workflows/#improvements-for-public-repository-forks
# https://docs.github.com/en/actions/managing-workflow-runs/approving-workflow-runs-from-public-forks#about-workflow-runs-from-public-forks
CSC_FOR_PULL_REQUEST: true
# https://docs.digicert.com/es/software-trust-manager/ci-cd-integrations/plugins/github-custom-action-for-keypair-signing.html
TIMESTAMP_SERVER: http://timestamp.digicert.com
# Apple notarization (automation/build-bin.ts)
XCODE_APP_LOADER_EMAIL: ${{ inputs.XCODE_APP_LOADER_EMAIL }}
XCODE_APP_LOADER_PASSWORD: ${{ fromJSON(inputs.secrets).XCODE_APP_LOADER_PASSWORD }}
XCODE_APP_LOADER_TEAM_ID: ${{ inputs.XCODE_APP_LOADER_TEAM_ID }}
- name: Upload artifacts
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4
with:
name: gh-release-${{ github.event.pull_request.head.sha || github.event.head_commit.id }}-${{ strategy.job-index }}
path: dist
retention-days: 1
if-no-files-found: error

65
.github/actions/test/action.yml vendored Normal file
View File

@ -0,0 +1,65 @@
---
name: test release
# https://github.com/product-os/flowzone/tree/master/.github/actions
inputs:
json:
description: "JSON stringified object containing all the inputs from the calling workflow"
required: true
secrets:
description: "JSON stringified object containing all the secrets from the calling workflow"
required: true
variables:
description: "JSON stringified object containing all the variables from the calling workflow"
required: true
# --- custom environment
NODE_VERSION:
type: string
default: '20.x'
VERBOSE:
type: string
default: "true"
runs:
# https://docs.github.com/en/actions/creating-actions/creating-a-composite-action
using: "composite"
steps:
# https://github.com/actions/setup-node#caching-global-packages-data
- name: Setup Node.js
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
with:
node-version: ${{ inputs.NODE_VERSION }}
cache: npm
- name: Set up Python 3.11
if: runner.os == 'macOS'
uses: actions/setup-python@65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236 # v4
with:
python-version: "3.11"
- name: Test release
shell: bash
run: |
set -ea
[[ '${{ inputs.VERBOSE }}' =~ on|On|Yes|yes|true|True ]] && set -x
if [[ -e package-lock.json ]] || [[ -e npm-shrinkwrap.json ]]; then
npm ci
else
npm i
fi
npm run build
npm run test:core
- name: Compress custom source
shell: pwsh
run: tar --exclude-vcs -acf ${{ runner.temp }}/custom.tgz .
- name: Upload custom artifact
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4
with:
name: custom-${{ github.event.pull_request.head.sha || github.event.head_commit.id }}-${{ runner.os }}-${{ runner.arch }}
path: ${{ runner.temp }}/custom.tgz
retention-days: 1

4
.github/renovate.json vendored Normal file
View File

@ -0,0 +1,4 @@
{
"extends": ["github>balena-io/renovate-config"],
"postUpdateOptions": ["npmDedupe"]
}

45
.github/workflows/flowzone.yml vendored Normal file
View File

@ -0,0 +1,45 @@
name: Flowzone
on:
pull_request:
types: [opened, synchronize, closed]
branches: [main, master]
pull_request_target:
types: [opened, synchronize, closed]
branches: [main, master]
jobs:
flowzone:
name: Flowzone
uses: product-os/flowzone/.github/workflows/flowzone.yml@master
# prevent duplicate workflow executions for pull_request and pull_request_target
if: |
(
github.event.pull_request.head.repo.full_name == github.repository &&
github.event_name == 'pull_request'
) || (
github.event.pull_request.head.repo.full_name != github.repository &&
github.event_name == 'pull_request_target'
)
secrets: inherit
with:
custom_test_matrix: >
{
"os": [
["self-hosted", "X64"],
["self-hosted", "ARM64"],
["macos-13"],
["windows-2019"],
["macos-latest-xlarge"]
]
}
custom_publish_matrix: >
{
"os": [
["self-hosted", "X64"],
["self-hosted", "ARM64"],
["macos-13"],
["windows-2019"],
["macos-latest-xlarge"]
]
}
github_prerelease: false
restrict_custom_actions: false

69
.gitignore vendored
View File

@ -1,47 +1,36 @@
# Logs
logs
*.log
# Reminders:
# * A pattern without '/' matches in subdirectories as well (files and directories)
# * A leading '/' anchors matching to the directory where `.gitignore` is defined
# * A trailing '/' makes the pattern match against directories only
# More details: https://git-scm.com/docs/gitignore
# Runtime data
pids
# development and testing tools or IDEs
*.log
*.pid
*.seed
/.idea/
/.lock-wscript
/.nvmrc
/.nyc_output/
/.vscode/
/coverage/
/lib-cov/
/logs
/pids
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
.nyc_output
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directory
# Commenting this out is preferred by some people, see
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
node_modules
package-lock.json
.resinconf
.balenaconf
resinrc.yml
balenarc.yml
# OS cache files
.DS_Store
.idea
.nvmrc
.vscode
/tmp
build/
build-bin/
build-zip/
dist/
# Ignore fast-boot cache file
**/.fast-boot.json
# balena CLI config and build files
.balenaconf
.fast-boot.json
.resinconf
/balenarc.yml
/build/
/build-bin/
/dist/
/node_modules
/oclif.manifest.json
/package-lock.json
/resinrc.yml
/tmp/

1
.husky/pre-commit Normal file
View File

@ -0,0 +1 @@
node automation/check-npm-version.js && ts-node automation/check-doc.ts

6
.mocharc-standalone.js Normal file
View File

@ -0,0 +1,6 @@
const commonConfig = require('./.mocharc.js');
module.exports = {
...commonConfig,
spec: ['tests/auth/*.spec.ts', 'tests/commands/**/*.spec.ts'],
};

10
.mocharc.js Normal file
View File

@ -0,0 +1,10 @@
module.exports = {
reporter: 'spec',
require: 'ts-node/register/transpile-only',
file: './tests/config-tests',
timeout: 12000,
// To test only, say, 'push.spec.ts', do it as follows so that
// requests are authenticated:
// spec: ['tests/auth/*.spec.ts', 'tests/**/deploy.spec.ts'],
spec: 'tests/**/*.spec.ts',
};

View File

@ -1,31 +0,0 @@
---
npm:
platforms:
- name: linux
os: alpine
architecture: x86_64
node_versions:
- "10"
- name: linux
os: alpine
architecture: x86
node_versions:
- "10"
- name: darwin
os: macos
architecture: x86_64
node_versions:
- "10"
- name: windows
os: windows
architecture: x86_64
node_versions:
- "10"
- name: windows
os: windows
architecture: x86
node_versions:
- "10"
docker:
publish: false

View File

@ -1,25 +0,0 @@
language: node_js
os:
- linux
- osx
node_js:
- "10"
matrix:
exclude:
node_js: "10"
script:
- node --version
- npm --version
- npm run ci
# - npm run build:standalone
# - npm run build:installer
notifications:
email: false
deploy:
- provider: script
script: npm run release
skip_cleanup: true
on:
tags: true
condition: "$TRAVIS_TAG =~ ^v?[[:digit:]]+\\.[[:digit:]]+\\.[[:digit:]]+"
repo: balena-io/balena-cli

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2,10 +2,12 @@
The balena CLI is an open source project and your contribution is welcome!
* Install the dependencies listed in the [NPM Installation](./INSTALL.md#npm-installation)
section of the `INSTALL.md` file. Check the section [Additional
Dependencies](./INSTALL.md#additional-dependencies) too.
* Clone the `balena-cli` repository, `cd` to it and run `npm install`.
* Install the dependencies listed in the [NPM Installation
section](./INSTALL-ADVANCED.md#npm-installation) section of the installation instructions. Check
the section [Additional Dependencies](./INSTALL-ADVANCED.md#additional-dependencies) too.
* Clone the `balena-cli` repository (or a [forked
repo](https://docs.github.com/en/free-pro-team@latest/github/getting-started-with-github/fork-a-repo),
if you are not in the balena team), `cd` to it and run `npm install`.
* Build the CLI with `npm run build` or `npm test`, and execute it with `./bin/balena`
(on a Windows command prompt, you may need to run `node .\bin\balena`).
@ -19,127 +21,229 @@ Before opening a PR, test your changes with `npm test`. Keep compatibility in mi
meant to run on Linux, macOS and Windows. balena CI will run test code on all three platforms, but
this will only help if you add some test cases for your new code!
## ./bin/balena-dev and oclif
## Semantic versioning, commit messages and the ChangeLog
When using `./bin/balena-dev` with oclif-converted commands, it is currently necessary to manually
edit the `oclif` section of `package.json` to replace `./build` with `./lib` as follows:
When a pull request is merged, Balena's versionbot / Continuous Integration system takes care of
automatically creating a new CLI release on both the [npm
registry](https://www.npmjs.com/package/balena-cli) and the GitHub [releases
page](https://github.com/balena-io/balena-cli/releases). The release version numbering adheres to
the [Semantic Versioning's](http://semver.org/) concept of patch, minor and major releases.
Generally, bug fixes and documentation changes are classed as patch changes, while new features are
classed as minor changes. If a change breaks backwards compatibility, it is a major change.
Change from:
```
"oclif": {
"commands": "./build/actions-oclif",
"hooks": {
"prerun": "./build/hooks/prerun/track"
```
A new version entry is also automatically added to the
[CHANGELOG.md](https://github.com/balena-io/balena-cli/blob/master/CHANGELOG.md) file when a pull
request is merged. Each pull request corresponds to a single version / release. Each commit in the
pull request becomes a bullet point entry in the Changelog. The Changelog file should not be
manually edited.
To:
```
"oclif": {
"commands": "./lib/actions-oclif",
"hooks": {
"prerun": "./lib/hooks/prerun/track"
```
To support this automation, a commit message should be structured as follows:
And then remember to change it back before pushing the pull request. This is obviously error prone
and inconvenient, and improvement suggestions are welcome: is there a better solution than
automatically editing `package.json`? It is doable, if it is what needs to be done.
```text
The first line becomes a bullet point in the CHANGELOG file
## Semantic versioning and commit messages
Optionally, a more detailed description in one or more paragraphs.
The detailed description can be seen with `git log`, but it is not copied
to the CHANGELOG file.
The CLI version numbering adheres to [Semantic Versioning](http://semver.org/). The following
header/row is required in the body of a commit message, and will cause the CI build to fail if absent:
```
Change-type: patch|minor|major
```
Version numbers and commit messages are automatically added to the `CHANGELOG.md` file by the CI
build flow, after a pull request is merged. It should not be manually edited.
Only the first line of the commit message is copied to the Changelog file. The `Change-type` footer
must be preceded by a blank line, and indicates the commit's semver change type. When a PR consists
of multiple commits, the commits may have different change type values. As a whole, the PR will
produce a release of the "highest" change type. For example, two commits mixing patch and minor
change types will produce a minor CLI release, while two commits mixing minor and major change
types will produce a major CLI release.
## Editing documentation files (CHANGELOG, README, website...)
The commit message is parsed / checked by versionbot with the
[resin-commit-lint](https://github.com/balena-io-modules/resin-commit-lint#resin-commit-lint)
package.
The `doc/cli.markdown` file is automatically generated by running `npm run build:doc` (which also
Because of the way that the Changelog file is automatically updated from commit messages, which
become the source of "what's new" for CLI end users, we advocate "meaningful commits" and
user-focused commit messages. A meaningful commit is one that, in isolation, introduces a fix or
feature (or part of a fix or feature) that makes sense at the Changelog level, and which leaves the
CLI in a non-broken state. Sometimes, in the course of preparing a single pull request, a developer
creates several commits as a way of saving their "work in progress", which may even fail to build
(e.g. `npm run build` fails), and which is then fixed or undone by further commits in the same PR.
In this situation, the recommendation is to "squash" or "fixup" the work-in-progress commits into
fewer, meaningful commits. Interactive rebase is a good tool to achieve this:
[blog](https://thoughtbot.com/blog/git-interactive-rebase-squash-amend-rewriting-history),
[docs](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History).
Mixing multiple distinct features or bug fixes in a single commit is discouraged, because the
description will likely not fit in the single-line Changelog bullet point and also because it
makes it harder to review the pull request (especially a large one) and harder to isolate and
revert individual changes in case a bug is found later on. Create a separate commit for each
feature / bug fix, or even separate pull requests.
If you need to catch up with changes to the master branch while working on a pull request,
use rebase instead of merge: [docs](https://git-scm.com/book/en/v2/Git-Branching-Rebasing).
If `package.json` is updated for dependencies listed in the `repo.yml` file (like `balena-sdk`),
the commit message body should also include a line in the following format:
```
Update balena-sdk from 12.0.0 to 12.1.0
```
This allows versionbot to produce nested Changelog entries (with expandable arrows), pulling in
commit messages from the upstream repositories. The following npm script can be used to
automatically produce a commit with a suitable commit message:
```
npm run update balena-sdk ^12.1.0
```
The script will create a new branch (only if `master` is currently checked out), run `npm update`
with the given target version and commit the `package.json` and `npm-shrinkwrap.json` files. The
script by default will set the `Change-type` to `patch` or `minor`, depending on the semver change
of the updated dependency. A `major` change type can specified as an extra argument:
```
npm run update balena-sdk ^12.14.0 patch
npm run update balena-sdk ^13.0.0 major
```
## Editing documentation files (README, INSTALL, Reference website...)
The `docs/balena-cli.md` file is automatically generated by running `npm run build:doc` (which also
runs as part of `npm run build`). That file is then pulled by scripts in the
[balena-io/docs](https://github.com/balena-io/docs/) GitHub repo for publishing at the [CLI
Documentation page](https://www.balena.io/docs/reference/cli/).
The content sources for the auto generation of `doc/cli.markdown` are:
The content sources for the auto generation of `docs/balena-cli.md` are:
* Selected sections of the README file.
* The CLI's command documentation in source code (both Capitano and oclif commands), for example:
* `lib/actions/build.coffee`
* `lib/actions-oclif/env/add.ts`
* [Selected
sections](https://github.com/balena-io/balena-cli/blob/v12.23.0/automation/capitanodoc/capitanodoc.ts#L199-L204)
of the README file.
* The CLI's command documentation in source code (`src/commands/` folder), for example:
* `src/commands/push.ts`
* `src/commands/env/add.ts`
The README file is manually edited, but subsections are automatically extracted for inclusion in
`doc/cli.markdown` by the `getCapitanoDoc()` function in
`docs/balena-cli.md` by the `getCapitanoDoc()` function in
[`automation/capitanodoc/capitanodoc.ts`](https://github.com/balena-io/balena-cli/blob/master/automation/capitanodoc/capitanodoc.ts).
The `INSTALL.md` and `TROUBLESHOOTING.md` files are also manually edited.
**IMPORTANT**
The file [`capitanodoc.ts`](https://github.com/balena-io/balena-cli/blob/master/automation/capitanodoc/capitanodoc.ts) lists
commands to generate documentation from. At the moment, it's manually updated and maintained alphabetically.
To add a new command to be documented,
1. Find the resource which it is part of or create a new one.
2. List the location of the build file
3. Make sure to add your files in alphabetical order
Once added, run the command `npm run build` to generate the documentation
The `INSTALL*.md` and `TROUBLESHOOTING.md` files are also manually edited.
## Patches folder
The `patches` folder contains patch files created with the
[patch-package](https://www.npmjs.com/package/patch-package) tool. Small code changes to
third-party modules can be made by directly editing Javascript files under the `node_modules`
folder and then running `patch-package` to create the patch files. The patch files are then
applied immediately after `npm install`, through the `postinstall` script defined in
`package.json`.
The subfolders of the `patches` folder are documented in the
[apply-patches.js](https://github.com/balena-io/balena-cli/blob/master/patches/apply-patches.js)
script.
To make changes to the patch files under the `patches` folder, **do not edit them directly,**
not even for a "single character change" because the hash values in the patch files also need
to be recomputed by `patch-packages`. Instead, edit the relevant files under `node_modules`
directly, and then run `patch-packages` with the `--patch-dir` option to specify the subfolder
where the patch should be saved. For example, edit `node_modules/exit-hook/index.js` and then
run:
```sh
$ npx patch-package --patch-dir patches/all exit-hook
```
That said, these kinds of patches should be avoided in favour of creating pull requests
upstream. Patch files create additional maintenance work over time as the patches need to be
updated when the dependencies are updated, and they prevent the compounding community benefit
that sharing fixes upstream have on open source projects like the balena CLI. The typical
scenario where these patches are used is when the upstream maintainers are unresponsive or
unwilling to merge the required fixes, the fixes are very small and specific to the balena CLI,
and creating a fork of the upstream repo is likely to be more long-term effort than maintaining
the patches.
## Windows
Please note that `npm run build:installer` (which generates the `.exe` executable installer on
Windows) specifically requires [MSYS2](https://www.msys2.org/) to be installed. Other than that,
the standard Command Prompt or PowerShell can be used (though MSYS2 is still handy, as it provides
'git' and a number of common unix utilities). If you make changes to `package.json` scripts, check
they also run on a standard Windows Command Prompt.
Besides the regular npm installation dependencies, the `npm run build:installer` script
that produces the `.exe` graphical installer on Windows also requires
[NSIS](https://sourceforge.net/projects/nsis/) and [MSYS2](https://www.msys2.org/) to be
installed. Be sure to add `C:\Program Files (x86)\NSIS` to the PATH, so that `makensis`
is available. MSYS2 is recommended when developing the balena CLI on Windows.
If changes are made to npm scripts in `package.json`, don't assume that a Unix shell like
bash is available. For example, some Windows shells don't have the `cp` and `rm` commands,
which is why you'll often find `ncp` and `rimraf` used in `package.json` scripts.
## Updating the 'npm-shrinkwrap.json' file
The `npm-shrinkwrap.json` file is used to control package dependencies, as documented at
https://docs.npmjs.com/files/shrinkwrap.json.
While developing, the `package.json` file is often modified by, or before, running `npm install`
in order to add, remove or modify dependencies. When `npm install` is executed, it automatically
updates the `npm-shrinkwrap.json` file as well, **taking into account not only the `package.json`
file but also the current state of the `node_modules` folder in your computer.**
Changes to `npm-shrinkwrap.json` can be automatically merged by git during operations like
`rebase`, `pull` and `cherry-pick`, but in some cases this results in suboptimal dependency
resolution (the `node_modules` folder may end up larger than necessary, with consequences to CLI
load time too). For this reason, the recommended way to update `npm-shrinkwrap.json` is to run
`npm install`, possibly alongside `npm dedupe` as well. The following commands can be used to
fix shrinkwrap issues and optimize the dependencies:
Meanwhile, as a text (JSON) file, `git` is capable of merging the `npm-shrinkwrap.json` file during
operations like `rebase`, `cherry-pick` and `pull`. But git's automated merge is not the
recommended way of updating the `npm-shrinkwrap.json` file, because it does not take into account
duplicates or conflicts in the dependency tree, or indeed the state of the `package.json` file
(which may have just been merged). In extreme cases, the automated merge may actually result in a
broken installation. For these reasons, automatic merging of the `npm-shrinkwrap.json` was disabled
through the `.gitattributes` file (the "binary merge driver" allows diff'ing but prevents automatic
merging). Operations like `git rebase` may then result in an error like:
```text
$ git rebase master
warning: Cannot merge binary files: npm-shrinkwrap.json (HEAD vs. c34942b9... test)
Auto-merging npm-shrinkwrap.json
CONFLICT (content): Merge conflict in npm-shrinkwrap.json
error: Failed to merge in the changes.
```sh
git checkout master -- npm-shrinkwrap.json
rm -rf node_modules
npm install # update npm-shrinkwrap.json to satisfy changes to package.json
npm dedupe # deduplicate dependencies from npm-shrinkwrap.json
npm install # re-add optional dependencies removed by dedupe
git add npm-shrinkwrap.json # add it for committing (solve merge errors)
```
Whether or not there is a merge error, the following commands are the recommended way of updating
and committing the `npm-shrinkwrap.json` file:
Note that `npm dedupe` should always be followed by `npm install`, as shown above, even if
`npm install` had already been executed before `npm dedupe`.
```bash
$ rm -rf node_modules # Linux / Mac
$ rmdir /s node_modules # Windows Command Prompt
$ npm checkout master -- npm-shrinkwrap.json # revert it to the master branch state
$ npm install # "cleanly" update the npm-shrinkwrap.json file
$ git add npm-shrinkwrap.json # add it for committing (solve merge errors)
Optionally, these steps may be automated by installing the
[npm-merge-driver](https://www.npmjs.com/package/npm-merge-driver):
```sh
npx npm-merge-driver install -g
```
## `fast-boot` and `npm link` - modifying the `node_modules` folder
During development or debugging, it is sometimes useful to temporarily modify the `node_modules`
folder (with or without making the respective changes to the `npm-shrinkwrap.json` file),
replacing dependencies with different versions. This can be achieved with the `npm link`
command, or by manually editing or copying files to the `node_modules` folder.
Unexpected behavior may then be observed because of the CLI's use of the
[fast-boot2](https://www.npmjs.com/package/fast-boot2) package that caches module resolution.
`fast-boot2` is configured in `src/fast-boot.ts` to automatically invalidate the cache if
changes are made to the `package.json` or `npm-shrinkwrap.json` files, but the cache won't
be automatically invalidated if `npm link` is used or if manual modifications are made to the
`node_modules` folder. In this situation:
* Manually delete the module cache file (typically `~/.balena/cli-module-cache.json`), or
* Use the `bin/balena-dev` entry point (instead of `bin/balena`) as it does not activate
`fast-boot2`.
## TypeScript and oclif
The CLI currently contains a mix of plain JavaScript and
[TypeScript](https://www.typescriptlang.org/) code. The goal is to have all code written in
Typescript, in order to take advantage of static typing and formal programming interfaces.
The migration towards Typescript is taking place gradually, as part of maintenance work or
the implementation of new features. Historically, the CLI was originally written in
[CoffeeScript](https://coffeescript.org), but all CoffeeScript code was migrated to either
Javascript or Typescript.
the implementation of new features.
Similarly, [Capitano](https://github.com/balena-io/capitano) was originally adopted as the CLI's
framework, but later we decided to take advantage of [oclif](https://oclif.io/)'s features such
as native installers for Windows, macOS and Linux, and support for custom flag parsing (for
example, we're still battling with Capitano's behavior of dropping leading zeros of arguments that
look like integers, such as some abbreviated UUIDs). Again, the migration is taking place
gradually, with some CLI commands parsed by oclif and others by Capitano. A simple command line
pre-parsing takes place in `preparser.ts`, to decide whether to route full parsing to Capitano or
to oclif.
Of historical interest, the CLI was originally written in [CoffeeScript](https://coffeescript.org)
and used the [Capitano](https://github.com/balena-io/capitano) framework. All CoffeeScript code was
migrated to either Javascript or Typescript, and Capitano was replaced with oclif. A few file or
variable names still refer to this legacy, for example `automation/capitanodoc/capitanodoc.ts`.
## Programming style
@ -147,29 +251,6 @@ to oclif.
reformats the code. Beyond that, we have a preference for Javascript promises over callbacks, and for
`async/await` over `.then()`.
## Updating upstream dependencies
In order to get proper nested changelogs, when updating upstream modules that are in the repo.yml
(like the balena-sdk), the commit body has to contain a line with the following format:
```
Update balena-sdk from 12.0.0 to 12.1.0
```
Since this is error prone, it's suggested to use the following npm script:
```
npm run update balena-sdk ^12.1.0
```
This will create a new branch (only if you are currently on master), run `npm update` with the
version you provided as a target and commit the package.json & npm-shrinkwrap.json. The script by
default will set the `Change-type` to `patch` or `minor`, depending on the semver change of the
updated dependency, but if you need to use a different one (eg `major`) you can specify it as an
extra argument:
```
npm run update balena-sdk ^12.14.0 patch
npm run update balena-sdk ^13.0.0 major
```
## Common gotchas
One thing that most CLI bugs have in common is the absence of test cases exercising the broken
@ -224,3 +305,11 @@ 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'],`

169
INSTALL-ADVANCED.md Normal file
View File

@ -0,0 +1,169 @@
# balena CLI Advanced Installation Options
**These are alternative, advanced installation options. Most users would prefer the [recommended,
streamlined installation
instructions](https://github.com/balena-io/balena-cli/blob/master/INSTALL.md).**
There are 3 options to choose from to install balena's CLI:
* [Executable Installer](#executable-installer): the easiest method on Windows and macOS, using the
traditional graphical desktop application installers.
* [Standalone Zip Package](#standalone-zip-package): these are plain zip files with the balena CLI
executable in them: extract and run. Available for all platforms: Linux, Windows, macOS.
Recommended also for scripted installation in CI (continuous integration) environments.
* [NPM Installation](#npm-installation): recommended for Node.js developers who may be interested
in integrating the balena CLI in their existing projects or workflow.
Some specific CLI commands have a few extra installation steps: see section [Additional
Dependencies](#additional-dependencies).
## Executable Installer
This is the recommended installation option on macOS and Windows. Follow the specific OS
instructions:
* [Windows](./INSTALL-WINDOWS.md)
* [macOS](./INSTALL-MAC.md)
> Note regarding WSL ([Windows Subsystem for
> Linux](https://docs.microsoft.com/en-us/windows/wsl/about))
> If you would like to use WSL, follow the [installations instructions for
> Linux](./INSTALL-LINUX.md) rather than Windows, as WSL consists of a Linux environment.
If you had previously installed the CLI using a standalone zip package, it may be a good idea to
check your system's `PATH` environment variable for duplicate entries, as the terminal will use the
entry that comes first. Check the [Standalone Zip Package](#standalone-zip-package) instructions
for how to modify the PATH variable.
By default, the CLI is installed to the following folders:
OS | Folders
--- | ---
Windows: | `C:\Program Files\balena-cli\`
macOS: | `/usr/local/src/balena-cli/` <br> `/usr/local/bin/balena`
## Standalone Zip Package
1. Download the latest zip file from the [releases page](https://github.com/balena-io/balena-cli/releases).
Look for a file name that ends with the word "standalone", for example:
`balena-cli-vX.Y.Z-linux-x64-standalone.zip`_also for the Windows Subsystem for Linux_
`balena-cli-vX.Y.Z-macOS-x64-standalone.zip`
`balena-cli-vX.Y.Z-windows-x64-standalone.zip`
2. Extract the zip file contents to any folder you choose. The extracted contents will include a
`balena-cli` folder.
3. Add the `balena-cli` folder to the system's `PATH` environment variable.
See instructions for:
[Linux](https://stackoverflow.com/questions/14637979/how-to-permanently-set-path-on-linux-unix) |
[macOS](https://www.architectryan.com/2012/10/02/add-to-the-path-on-mac-os-x-mountain-lion/#.Uydjga1dXDg) |
[Windows](https://www.computerhope.com/issues/ch000549.htm)
> * If you are using macOS 10.15 or later (Catalina, Big Sur), [check this known issue and
> workaround](https://github.com/balena-io/balena-cli/issues/2244).
> * **Linux Alpine** and **Busybox:** the standalone zip package is not currently compatible with
> these "compact" Linux distributions, because of the alternative C libraries they ship with.
> For these, consider the [NPM Installation](#npm-installation) option.
> * Note that moving the `balena` executable out of the extracted `balena-cli` folder on its own
> (e.g. moving it to `/usr/local/bin/balena`) will **not** work, as it depends on the other
> folders and files also present in the `balena-cli` folder.
To update the CLI to a new version, download a new release zip file and replace the previous
installation folder. To uninstall, simply delete the folder and edit the PATH environment variable
as described above.
## NPM Installation
If you are a Node.js developer, you may wish to install the balena CLI via [npm](https://www.npmjs.com).
The npm installation involves building native (platform-specific) binary modules, which require
some development tools to be installed first, as follows.
> **The balena CLI currently requires Node.js version ^20.6.0**
> **Versions 21 and later are not yet fully supported.**
### Install development tools
#### **Linux or WSL** (Windows Subsystem for Linux)
```sh
$ sudo apt-get update && sudo apt-get -y install curl python3 git make g++
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash
$ . ~/.bashrc
$ nvm install 20
```
The `curl` command line above uses
[nvm](https://github.com/nvm-sh/nvm/blob/master/README.md#install--update-script) to install
Node.js, instead of using `apt-get`. Installing Node.js through `apt-get` is a common source of
problems from permission errors to conflict with other system packages, and therefore not
recommended.
#### **macOS**
* Download and install Apple's Command Line Tools from https://developer.apple.com/downloads/
* Install Node.js through [nvm](https://github.com/nvm-sh/nvm/blob/master/README.md#install--update-script):
```sh
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash
$ . ~/.bashrc
$ nvm install 20
```
#### **Windows** (not WSL)
Install:
* If you'd like the ability to switch between Node.js versions, install
- Node.js v20 from the [Nodejs.org releases page](https://nodejs.org/en/download/releases/).
[nvm-windows](https://github.com/coreybutler/nvm-windows#node-version-manager-nvm-for-windows)
instead.
* The [MSYS2 shell](https://www.msys2.org/), which provides `git`, `make`, `g++` and more:
* `pacman -S git gcc make openssh p7zip`
* [Set a Windows environment variable](https://www.onmsft.com/how-to/how-to-set-an-environment-variable-in-windows-10): `MSYS2_PATH_TYPE=inherit`
* Note that a bug in the MSYS2 launch script (`msys2_shell.cmd`) makes text-based
interactive CLI menus to misbehave. [Check this Github issue for a
workaround](https://github.com/msys2/MINGW-packages/issues/1633#issuecomment-240583890).
* The Windows Driver Kit (WDK), which is needed to compile some native Node modules. It is **not**
necessary to install Visual Studio, only the WDK, which is "step 2" in the following guides:
* [WDK for Windows 10](https://docs.microsoft.com/en-us/windows-hardware/drivers/download-the-wdk#download-icon-step-2-install-refreshed-wdk-for-windows-10-version-2004)
* [WDK for earlier versions of Windows](https://docs.microsoft.com/en-us/windows-hardware/drivers/other-wdk-downloads#step-2-install-the-wdk)
* The [windows-build-tools](https://www.npmjs.com/package/windows-build-tools) npm package,
by running the following command on an [administrator
console](https://www.howtogeek.com/194041/how-to-open-the-command-prompt-as-administrator-in-windows-8.1/):
`npm install --global --production windows-build-tools`
### Install the balena CLI
After installing the development tools, install the balena CLI with:
```sh
$ npm install balena-cli --global --production --unsafe-perm
```
`--unsafe-perm` is needed when `npm install` is executed as the `root` user (e.g. in a Docker
container) in order to allow npm scripts like `postinstall` to be executed.
## Additional Dependencies
The `balena device ssh`, `device detect`, `build`, `deploy` and `preload` commands may require
additional software to be installed. Check the Additional Dependencies sections for each operating
system:
* [Windows](./INSTALL-WINDOWS.md#additional-dependencies)
* [macOS](./INSTALL-MAC.md#additional-dependencies)
* [Linux](./INSTALL-LINUX.md#additional-dependencies)
Where Docker or balenaEngine are required, they may be installed on the local machine (where the
balena CLI is executed), on a remote server, or on a balenaOS device running a [balenaOS development
image](https://www.balena.io/docs/reference/OS/overview/2.x/#dev-vs-prod-images). Reasons why this
may be desirable include:
* To avoid having to install Docker on the development machine / laptop.
* To take advantage of a more powerful server (CPU, memory).
* To build or run images "natively" on an ARM device, avoiding the need for QEMU emulation.
To use a remote Docker Engine (daemon) or balenaEngine, specify the remote machine's IP address and
port number with the `--dockerHost` and `--dockerPort` command-line options. The `preload` command
has additional requirements because the bind mount feature is used. For more details, see
`balena help` for each command or the [online
reference](https://www.balena.io/docs/reference/cli/#cli-command-reference).

85
INSTALL-LINUX.md Normal file
View File

@ -0,0 +1,85 @@
# balena CLI Installation Instructions for Linux
These instructions are suitable for most Linux distributions on Intel x86, such as
Ubuntu, Debian, Fedora, Arch Linux and other glibc-based distributions.
For the ARM architecture and for Linux distributions not based on glibc, such as
Alpine Linux, follow the [NPM Installation](./INSTALL-ADVANCED.md#npm-installation)
method.
Selected operating system: **Linux**
1. Download the latest zip file from the [latest release
page](https://github.com/balena-io/balena-cli/releases/latest). Look for a file name that ends
with "-standalone.zip", for example:
`balena-cli-vX.Y.Z-linux-x64-standalone.zip`
2. Extract the zip file contents to any folder you choose, for example `/home/james`.
The extracted contents will include a `balena-cli` folder.
3. Add that folder (e.g. `/home/james/balena-cli`) to the `PATH` environment variable.
Check this [StackOverflow
post](https://stackoverflow.com/questions/14637979/how-to-permanently-set-path-on-linux-unix)
for instructions. Close and reopen the terminal window so that the changes to `PATH`
can take effect.
4. Check that the installation was successful by running the following commands on a
terminal window:
* `balena version` - should print the CLI's version
* `balena help` - should print a list of available commands
To update the balena CLI to a new version, download a new release zip file and replace the previous
installation folder. To uninstall, simply delete the folder and edit the PATH environment variable
as described above.
## sudo configuration
A few CLI commands require execution through sudo, e.g. `sudo balena device detect`.
If your Linux distribution has an `/etc/sudoers` file that defines a `secure_path`
setting, run `sudo visudo` to edit it and add the balena CLI's installation folder to
the ***pre-existing*** `secure_path` setting, for example:
```text
Defaults secure_path="/home/james/balena-cli:<pre-existing entries go here>"
```
If an `/etc/sudoers` file does not exist, or if it does not contain a pre-existing
`secure_path` setting, do not change it.
If you also have Docker installed, ensure that it can be executed ***without*** `sudo`, so that
CLI commands like `balena build` and `balena preload` can also be executed without `sudo`.
Check Docker's [post-installation
steps](https://docs.docker.com/engine/install/linux-postinstall/) on how to achieve this.
## Additional Dependencies
### build, deploy
These commands require [Docker](https://docs.docker.com/install/overview/) or
[balenaEngine](https://www.balena.io/engine/) to be available on a local or remote
machine. Most users will follow [Docker's installation
instructions](https://docs.docker.com/install/overview/) to install Docker on the same
workstation as the balena CLI. The [advanced installation
options](./INSTALL-ADVANCED.md#additional-dependencies) document describes other possibilities.
### balena device ssh
The `balena device ssh` command requires the `ssh` command-line tool to be available. Most Linux
distributions will already have it installed. Otherwise, `sudo apt-get install openssh-client`
should do the trick on Debian or Ubuntu.
The `balena device ssh` command also requires an SSH key to be added to your balena account: see [SSH
Access documentation](https://www.balena.io/docs/learn/manage/ssh-access/). The `balena key*`
command set can also be used to list and manage SSH keys: see `balena help -v`.
### balena device detect
The `balena device detect` command requires a multicast DNS (mDNS) service like
[Avahi](https://en.wikipedia.org/wiki/Avahi_(software)), which is installed by default on most
desktop Linux distributions. Otherwise, on Debian or Ubuntu, the installation command would be
`sudo apt-get install avahi-daemon`.
### balena preload
Like the `build` and `deploy` commands, the `preload` command requires Docker, with the additional
restriction that Docker must be installed on the local machine (because Docker's bind mounting
feature is used).

74
INSTALL-MAC.md Normal file
View File

@ -0,0 +1,74 @@
# balena CLI Installation Instructions for macOS
These instructions are for the recommended installation option. Advanced users may also be
interested in [advanced installation options](./INSTALL-ADVANCED.md).
Selected operating system: **macOS**
1. Download the installer from the [latest release
page](https://github.com/balena-io/balena-cli/releases/latest).
Look for a file name that ends with "-installer.pkg":
`balena-cli-vX.Y.Z-macOS-x64-installer.pkg`
2. Double click on the downloaded file to run the installer and follow the installer's
instructions.
3. Check that the installation was successful:
- [Open the Terminal
app](https://support.apple.com/en-gb/guide/terminal/apd5265185d-f365-44cb-8b09-71a064a42125/mac).
- On the terminal prompt, type `balena version` and hit Enter. It should display
the version of the balena CLI that you have installed.
No further steps are required to run most CLI commands. The `balena device ssh`, `build`, `deploy`
and `preload` commands may require additional software to be installed, as described
in the next section.
To update the balena CLI, repeat the steps above for the new version.
To uninstall it, run the following command on a terminal prompt:
```text
sudo /usr/local/src/balena-cli/bin/uninstall
```
## Additional Dependencies
### build and deploy
These commands require [Docker](https://docs.docker.com/install/overview/) or
[balenaEngine](https://www.balena.io/engine/) to be available on a local or remote
machine. Most users will follow [Docker's installation
instructions](https://docs.docker.com/install/overview/) to install Docker on the same
workstation as the balena CLI. The [advanced installation
options](./INSTALL-ADVANCED.md#additional-dependencies) document describes other possibilities.
### balena device ssh
The `balena device ssh` command requires the `ssh` command-line tool to be available. To check whether
it is already installed, run `ssh` on a Terminal window. If it is not yet installed, the options
include:
* Download the Xcode Command Line Tools from https://developer.apple.com/downloads
* Or, if you have Xcode installed, open Xcode, choose Preferences → General → Downloads →
Components → Command Line Tools → Install.
* Or, install [Homebrew](https://brew.sh/), then `brew install openssh`
The `balena device ssh` command also requires an SSH key to be added to your balena account: see [SSH
Access documentation](https://www.balena.io/docs/learn/manage/ssh-access/). The `balena key*`
command set can also be used to list and manage SSH keys: see `balena help -v`.
### balena preload
Like the `build` and `deploy` commands, the `preload` command requires Docker.
Preloading balenaOS images for some older device types (like the Raspberry
Pi 3, but not the Raspberry 4) requires Docker to support the [AUFS storage
driver](https://docs.docker.com/storage/storagedriver/aufs-driver/). Unfortunately, Docker Desktop
for Windows and macOS dropped support for the AUFS filesystem in Docker CE versions greater than
18.06.1. The present workarounds are to either:
* Install the balena CLI on Linux (e.g. Ubuntu) with a virtual machine like VirtualBox.
This works because Docker for Linux still supports AUFS. Hint: if using a virtual machine,
copy the image file over, rather than accessing it through "file sharing", to avoid errors.
* Downgrade Docker Desktop to version 18.06.1. Link: [Docker CE for
Mac](https://docs.docker.com/docker-for-mac/release-notes/#docker-community-edition-18061-ce-mac73-2018-08-29)
We are working on replacing AUFS with overlay2 in balenaOS images of the affected device types.

73
INSTALL-WINDOWS.md Normal file
View File

@ -0,0 +1,73 @@
# balena CLI Installation Instructions for Windows
These instructions are for the recommended installation option. Advanced users may also be
interested in [advanced installation options](./INSTALL-ADVANCED.md).
Selected operating system: **Windows**
1. Download the installer from the [latest release
page](https://github.com/balena-io/balena-cli/releases/latest).
Look for a file name that ends with "-installer.exe":
`balena-cli-vX.Y.Z-windows-x64-installer.exe`
2. Double click on the downloaded file to run the installer and follow the installer's
instructions.
3. Check that the installation was successful:
- Click on the Windows Start Menu, type PowerShell, and then click
on Windows PowerShell.
- On the command prompt, type `balena version` and hit Enter. It should display
the version of the balena CLI that you have installed.
No further steps are required to run most CLI commands. The `balena device ssh`, `device detect`, `build`,
`deploy` and `preload` commands may require additional software to be installed, as
described below.
## Additional Dependencies
### build and deploy
These commands require [Docker](https://docs.docker.com/install/overview/) or
[balenaEngine](https://www.balena.io/engine/) to be available on a local or remote
machine. Most users will follow [Docker's installation
instructions](https://docs.docker.com/install/overview/) to install Docker on the same
workstation as the balena CLI. The [advanced installation
options](./INSTALL-ADVANCED.md#additional-dependencies) document describes other possibilities.
### balena device ssh
The `balena device ssh` command requires the `ssh` command-line tool to be available. Microsoft started
distributing an SSH client with Windows 10, which is automatically installed through Windows
Update. To check whether it is installed, run `ssh` on a Windows Command Prompt or PowerShell. It
can also be [manually
installed](https://docs.microsoft.com/en-us/windows-server/administration/openssh/openssh_install_firstuse)
if needed. For older versions of Windows, there are several ssh/OpenSSH clients provided by 3rd
parties.
The `balena device ssh` command also requires an SSH key to be added to your balena account: see [SSH
Access documentation](https://www.balena.io/docs/learn/manage/ssh-access/). The `balena key*`
command set can also be used to list and manage SSH keys: see `balena help -v`.
### balena device detect
The `balena device detect` command requires a multicast DNS (mDNS) service like Apple's Bonjour.
Many Windows machines will already have this service installed, as it is bundled in popular
applications such as Skype (Wikipedia lists [several others](https://en.wikipedia.org/wiki/Bonjour_(software))).
Otherwise, Bonjour for Windows can be downloaded and installed from: https://support.apple.com/kb/DL999
### balena preload
Like the `build` and `deploy` commands, the `preload` command requires Docker.
Preloading balenaOS images for some older device types (like the Raspberry
Pi 3, but not the Raspberry 4) requires Docker to support the [AUFS storage
driver](https://docs.docker.com/storage/storagedriver/aufs-driver/). Unfortunately, Docker Desktop
for Windows and macOS dropped support for the AUFS filesystem in Docker CE versions greater than
18.06.1. The present workarounds are to either:
* Install the balena CLI on Linux (e.g. Ubuntu) with a virtual machine like VirtualBox.
This works because Docker for Linux still supports AUFS. Hint: if using a virtual machine,
copy the image file over, rather than accessing it through "file sharing", to avoid errors.
* Downgrade Docker Desktop to version 18.06.1. Link: [Docker CE for
Windows](https://docs.docker.com/docker-for-windows/release-notes/#docker-community-edition-18061-ce-win73-2018-08-29)
We are working on replacing AUFS with overlay2 in balenaOS images of the affected device types.

View File

@ -1,231 +1,12 @@
# balena CLI Installation Instructions
There are 3 options to choose from to install balena's CLI:
Please select your operating system:
* [Executable Installer](#executable-installer): the easiest method on Windows and macOS, using the
traditional graphical desktop application installers.
* [Standalone Zip Package](#standalone-zip-package): these are plain zip files with the balena CLI
executable in them: extract and run. Available for all platforms: Linux, Windows, macOS.
Recommended also for scripted installation in CI (continuous integration) environments.
* [NPM Installation](#npm-installation): recommended for Node.js developers who may be interested
in integrating the balena CLI in their existing projects or workflow.
* [Windows](./INSTALL-WINDOWS.md)
* [macOS](./INSTALL-MAC.md)
* [Linux](./INSTALL-LINUX.md)
Some specific CLI commands have a few extra installation steps: see section [Additional
Dependencies](#additional-dependencies).
> **Windows users:**
> * There is a [YouTube video tutorial](https://www.youtube.com/watch?v=2LApclXFqsg) for installing
> and getting started with the balena CLI on Windows. (The video uses the standalone zip package
> option.)
> * If you are using Microsoft's [Windows Subsystem for
> Linux](https://docs.microsoft.com/en-us/windows/wsl/about) (WSL), install a balena CLI release
> for Linux rather than for Windows, like the standalone zip package for Linux. An installation
> with the graphical executable installer for Windows will **not** work with WSL.
## Executable Installer
Recommended for Windows (but not Windows Subsystem for Linux) and macOS:
1. Download the latest installer from the [releases page](https://github.com/balena-io/balena-cli/releases).
Look for a file name that ends with "-installer", for example:
`balena-cli-vX.Y.Z-windows-x64-installer.exe`
`balena-cli-vX.Y.Z-macOS-x64-installer.pkg`
2. Double click the downloaded file to run the installer.
_If you are using macOS Catalina (10.15), [check this known issue and
workaround](https://github.com/balena-io/balena-cli/issues/1479)._
3. After the installation completes, close and re-open any open [command
terminal](https://www.balena.io/docs/reference/cli/#choosing-a-shell-command-promptterminal)
windows so that the changes made by the installer to the PATH environment variable can take
effect. Check that the installation was successful by running the following commands on a
command terminal:
* `balena version` - should print the installed CLI version
* `balena help` - should print the balena CLI help
> Note: If you had previously installed the CLI using a standalone zip package, it may be a good
> idea to check your system's `PATH` environment variable for duplicate entries, as the terminal
> will use the entry that comes first. Check the [Standalone Zip Package](#standalone-zip-package)
> instructions for how to modify the PATH variable.
By default, the CLI is installed to the following folders:
OS | Folders
--- | ---
Windows: | `C:\Program Files\balena-cli\`
macOS: | `/usr/local/lib/balena-cli/` <br> `/usr/local/bin/balena`
## Standalone Zip Package
1. Download the latest zip file from the [releases page](https://github.com/balena-io/balena-cli/releases).
Look for a file name that ends with the word "standalone", for example:
`balena-cli-vX.Y.Z-linux-x64-standalone.zip`_also for the Windows Subsystem for Linux_
`balena-cli-vX.Y.Z-macOS-x64-standalone.zip`
`balena-cli-vX.Y.Z-windows-x64-standalone.zip`
2. Extract the zip file contents to any folder you choose. The extracted contents will include a
`balena-cli` folder.
3. Add the `balena-cli` folder to the system's `PATH` environment variable.
See instructions for:
[Linux](https://stackoverflow.com/questions/14637979/how-to-permanently-set-path-on-linux-unix) |
[macOS](https://www.architectryan.com/2012/10/02/add-to-the-path-on-mac-os-x-mountain-lion/#.Uydjga1dXDg) |
[Windows](https://www.computerhope.com/issues/ch000549.htm)
> * If you are using macOS Catalina (10.15), [check this known issue and
> workaround](https://github.com/balena-io/balena-cli/issues/1479).
> * **Linux Alpine** and **Busybox:** the standalone zip package is not currently compatible with
> these "compact" Linux distributions, because of the alternative C libraries they ship with.
> It should however work with all "desktop" or "server" distributions, e.g. Ubuntu, Debian, Suse,
> Fedora, Arch Linux and many more.
> * Note that moving the `balena` executable out of the extracted `balena-cli` folder on its own
> (e.g. moving it to `/usr/local/bin/balena`) will **not** work, as it depends on the other
> folders and files also present in the `balena-cli` folder.
To update the CLI to a new version, download a new release zip file and replace the previous
installation folder. To uninstall, simply delete the folder and edit the PATH environment variable
as described above.
## NPM Installation
If you are a Node.js developer, you may wish to install the balena CLI via [npm](https://www.npmjs.com).
The npm installation involves building native (platform-specific) binary modules, which require
some additional development tools to be installed first:
* [Node.js](https://nodejs.org/) version 10 or 12 (version 14 is not yet fully supported)
* **Linux, macOS** and **Windows Subsystem for Linux (WSL):**
Installing Node via [nvm](https://github.com/nvm-sh/nvm/blob/master/README.md) is recommended.
When the "system" or "default" Node.js and npm packages are installed with "apt-get" in Linux
distributions like Ubuntu, users often report permission or compilation errors when running
"npm install". This [sample
Dockerfile](https://gist.github.com/pdcastro/5d4d96652181e7da685a32caf629dd44) shows the CLI
installation steps on an Ubuntu 18.04 base image.
* [Python 2.7](https://www.python.org/), [git](https://git-scm.com/), [make](https://www.gnu.org/software/make/), [g++](https://gcc.gnu.org/)
* **Linux** and **Windows Subsystem for Linux (WSL):**
`sudo apt-get install -y python git make g++`
* **macOS:** install Apple's Command Line Tools by running on a Terminal window:
`xcode-select --install`
On **Windows (not WSL),** the dependencies above and additional ones can be met by installing:
* Node.js from the [Nodejs.org download page](https://nodejs.org/en/download/).
* The [MSYS2 shell](https://www.msys2.org/), which provides `git`, `make`, `g++`, `ssh`, `rsync`
and more:
* `pacman -S git openssh rsync gcc make`
* [Set a Windows environment variable](https://www.onmsft.com/how-to/how-to-set-an-environment-variable-in-windows-10): `MSYS2_PATH_TYPE=inherit`
* Note that a bug in the MSYS2 launch script (`msys2_shell.cmd`) makes text-based
interactive CLI menus to misbehave. [Check this Github issue for a
workaround](https://github.com/msys2/MINGW-packages/issues/1633#issuecomment-240583890).
* The Windows Driver Kit (WDK), which is needed to compile some native Node modules. It is **not**
necessary to install Visual Studio, only the WDK, which is "step 2" in the following guides:
* [WDK for Windows 10](https://docs.microsoft.com/en-us/windows-hardware/drivers/download-the-wdk#download-icon-step-2-install-wdk-for-windows-10-version-1903)
* [WDK for earlier versions of Windows](https://docs.microsoft.com/en-us/windows-hardware/drivers/other-wdk-downloads#step-2-install-the-wdk)
* The [windows-build-tools](https://www.npmjs.com/package/windows-build-tools) npm package (which
provides Python 2.7 and more), by running the following command on an [administrator
console](https://www.howtogeek.com/194041/how-to-open-the-command-prompt-as-administrator-in-windows-8.1/):
`npm install -g --production windows-build-tools`
With these dependencies in place, the balena CLI installation command is:
```sh
$ npm install balena-cli -g --production --unsafe-perm
```
`--unsafe-perm` is required when `npm install` is executed as the root user, or on systems where
the global install directory is not user-writable. It allows npm install steps to download and save
prebuilt native binaries, and also allows the execution of npm scripts like `postinstall` that are
used to patch dependencies. It is usually possible to omit `--unsafe-perm` if installing under a
regular (non-root) user account, especially if using a user-managed node installation such as
[nvm](https://github.com/creationix/nvm).
## Additional Dependencies
* The `balena ssh` command requires a recent version of the `ssh` command-line tool to be available:
* macOS and Linux usually already have it installed. Otherwise, search for the available packages
on your specific Linux distribution, or for the Mac consider the [Xcode command-line
tools](https://developer.apple.com/xcode/features/) or [homebrew](https://brew.sh/).
* Microsoft started distributing an SSH client with Windows 10, which we understand is
automatically installed through Windows Update, but can be manually installed too
([more information](https://docs.microsoft.com/en-us/windows-server/administration/openssh/openssh_install_firstuse)).
For other versions of Windows, there are several ssh/OpenSSH clients provided by 3rd parties.
* The [`proxytunnel`](http://proxytunnel.sourceforge.net/) package (command-line tool) is needed
for the `balena ssh` command to work behind a proxy. It is available for Linux distributions
like Ubuntu/Debian (`apt install proxytunnel`), and for macOS through
[Homebrew](https://brew.sh/). Windows support is limited to the Windows Subsystem for Linux
(e.g., by installing Ubuntu through the Microsoft App Store). Check the
[README](https://github.com/balena-io/balena-cli/blob/master/README.md) file for proxy
configuration instructions.
* The `balena preload`, `balena build` and `balena deploy --build` commands require
[Docker](https://docs.docker.com/install/overview/) or [balenaEngine](https://www.balena.io/engine/)
to be available:
* The `balena preload` command requires the Docker Engine to support the [AUFS storage
driver](https://docs.docker.com/storage/storagedriver/aufs-driver/). Docker Desktop for Mac and
Windows dropped support for the AUFS filesystem in Docker CE versions greater than 18.06.1, so
the workaround is to downgrade to version 18.06.1 (links: [Docker CE for
Windows](https://docs.docker.com/docker-for-windows/release-notes/#docker-community-edition-18061-ce-win73-2018-08-29)
and [Docker CE for
Mac](https://docs.docker.com/docker-for-mac/release-notes/#docker-community-edition-18061-ce-mac73-2018-08-29)).
See more details in [CLI issue 1099](https://github.com/balena-io/balena-cli/issues/1099).
* Commonly, Docker is installed on the same machine where the CLI is being used, but the
`balena build` and `balena deploy` commands can also use a remote Docker Engine (daemon)
or balenaEngine (which could be a remote device running a [balenaOS development
image](https://www.balena.io/docs/reference/OS/overview/2.x/#dev-vs-prod-images)) by specifying
its IP address and port number as command-line options. Check the documentation for each
command, e.g. `balena help build`, or the [online
reference](https://www.balena.io/docs/reference/cli/#cli-command-reference).
* If you are using Microsoft's [Windows Subsystem for
Linux](https://docs.microsoft.com/en-us/windows/wsl/about) (WSL) and Docker Desktop for
Windows, check the [FAQ item "Docker seems to be
unavailable"](https://github.com/balena-io/balena-cli/blob/master/TROUBLESHOOTING.md#docker-seems-to-be-unavailable-error-when-using-windows-subsystem-for-linux-wsl).
* The `balena scan` command requires a multicast DNS (mDNS) service like Bonjour or Avahi:
* On Windows, check if 'Bonjour' is installed (Control Panel > Programs and Features).
If not, you can download Bonjour for Windows from https://support.apple.com/kb/DL999
* Most 'desktop' Linux distributions ship with [Avahi](https://en.wikipedia.org/wiki/Avahi_(software)).
Search for the installation command for your distribution. E.g. for Ubuntu:
`sudo apt-get install avahi-daemon`
* macOS comes with [Bonjour](https://en.wikipedia.org/wiki/Bonjour_(software)) built-in.
* The `balena os configure` command is currently not supported on Windows natively. Windows users are advised
to install the [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/about) (WSL)
with Ubuntu, and use the Linux release of the balena CLI.
## Configuring SSH keys
The `balena ssh` command requires an SSH key to be added to your balena account. If you had
already added a SSH key in order to [deploy with 'git push'](https://www.balena.io/docs/learn/getting-started/raspberrypi3/nodejs/#adding-an-ssh-key),
then you are probably done and may skip this section. You can check whether you already have
an SSH key in your balena account with the `balena keys` command, or by visiting the
[balena web dashboard](https://dashboard.balena-cloud.com/), clicking on your name -> Preferences
-> SSH Keys.
> Note: An "SSH key" actually consists of a public/private key pair. A typical name for the private
> key file is "id_rsa", and a typical name for the public key file is "id_rsa.pub". Both key files
> are saved to your computer (with the private key optionally protected by a password), but only
> the public key is saved to your balena account. This means that if you change computers or
> otherwise lose the private key, _you cannot recover the private key through your balena account._
> You can however add new keys, and delete the old ones.
If you don't have an SSH key in your balena account:
* If you have an existing SSH key in your computer that you would like to use, you can add it
to your balena account through the balena web dashboard (Preferences -> SSH Keys), or through
the CLI itself:
```bash
# Windows 10 (cmd.exe prompt) example:
$ balena key add MyKey %userprofile%\.ssh\id_rsa.pub
# Linux / macOS example:
$ balena key add MyKey ~/.ssh/id_rsa.pub
```
* To generate a new key, you can follow [GitHub's documentation](https://help.github.com/en/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent),
skipping the step about adding the key to your GitHub account, and instead adding the key to
your balena account as described above.
> Note regarding WSL ([Windows Subsystem for
> Linux](https://docs.microsoft.com/en-us/windows/wsl/about))
> If you would like to use WSL, follow the installations instructions for Linux
> rather than Windows, as WSL consists of a Linux environment.

111
README.md
View File

@ -1,68 +1,69 @@
# balena CLI
The official balena CLI tool.
The official balena Command Line Interface.
[![npm version](https://badge.fury.io/js/balena-cli.svg)](http://badge.fury.io/js/balena-cli)
[![dependencies](https://david-dm.org/balena-io/balena-cli.svg)](https://david-dm.org/balena-io/balena-cli)
## About
The balena CLI (Command-Line Interface) allows you to interact with the balenaCloud and the
[balena API](https://www.balena.io/docs/reference/api/overview/) through a terminal window
on Linux, macOS or Windows. You can also write shell scripts around it, or import its Node.js
modules to use it programmatically.
As an [open-source project on GitHub](https://github.com/balena-io/balena-cli/), your contribution
is also welcome!
The balena CLI is a Command Line Interface for [balenaCloud](https://www.balena.io/cloud/) or
[openBalena](https://www.balena.io/open/). It is a software tool available for Windows, macOS and
Linux, used through a command prompt / terminal window. It can be used interactively or invoked in
scripts. The balena CLI builds on the [balena API](https://www.balena.io/docs/reference/api/overview/)
and the [balena SDK](https://www.balena.io/docs/reference/sdk/node-sdk/), and can also be directly
imported in Node.js applications. The balena CLI is an [open-source project on
GitHub](https://github.com/balena-io/balena-cli/), and your contribution is also welcome!
## Installation
Check the [balena CLI installation instructions on GitHub](https://github.com/balena-io/balena-cli/blob/master/INSTALL.md).
Check the [balena CLI installation instructions on
GitHub](https://github.com/balena-io/balena-cli/blob/master/INSTALL.md).
## Getting Started
### Choosing a shell (command prompt/terminal)
## Choosing a shell (command prompt/terminal)
On **Windows,** the standard Command Prompt (`cmd.exe`) and
[PowerShell](https://docs.microsoft.com/en-us/powershell/scripting/getting-started/getting-started-with-windows-powershell?view=powershell-6)
are supported. We are aware of users also having a good experience with alternative shells,
including:
are supported. Alternative shells include:
* [MSYS2](https://www.msys2.org/):
* Install additional packages with the command:
`pacman -S git openssh rsync`
`pacman -S git gcc make openssh p7zip`
* [Set a Windows environment variable](https://www.onmsft.com/how-to/how-to-set-an-environment-variable-in-windows-10): `MSYS2_PATH_TYPE=inherit`
* Note that a bug in the MSYS2 launch script (`msys2_shell.cmd`) makes text-based interactive CLI
menus to break. [Check this Github issue for a
workaround](https://github.com/msys2/MINGW-packages/issues/1633#issuecomment-240583890).
* [MSYS](http://www.mingw.org/wiki/MSYS): select the `msys-rsync` and `msys-openssh` packages too
* [MSYS](http://www.mingw.org/wiki/MSYS)
* [Git for Windows](https://git-for-windows.github.io/)
* During the installation, you will be prompted to choose between _"Use MinTTY"_ and _"Use
Windows' default console window"._ Choose the latter, because of the same [MSYS2
bug](https://github.com/msys2/MINGW-packages/issues/1633) mentioned above (Git for Windows
actually uses MSYS2). For a screenshot, check this
[comment](https://github.com/balena-io/balena-cli/issues/598#issuecomment-556513098).
* Microsoft's [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/about)
(WSL). In this case, a Linux distribution like Ubuntu is installed via the Microsoft Store, and a
balena CLI release **for Linux** is recommended. See
[FAQ](https://github.com/balena-io/balena-cli/blob/master/TROUBLESHOOTING.md) for using balena
CLI with WSL and Docker Desktop for Windows.
balena CLI release **for Linux** should be selected. See
[FAQ](https://github.com/balena-io/balena-cli/blob/master/TROUBLESHOOTING.md) for using the
balena CLI with WSL and Docker Desktop for Windows.
On **macOS** and **Linux,** the standard terminal window is supported. _Optionally,_ `bash` command
On **macOS** and **Linux,** the standard terminal window is supported. Optionally, `bash` command
auto completion may be enabled by copying the
[balena-completion.bash](https://github.com/balena-io/balena-cli/blob/master/balena-completion.bash)
[balena_comp](https://github.com/balena-io/balena-cli/blob/master/completion/balena-completion.bash)
file to your system's `bash_completion` directory: check [Docker's command completion
guide](https://docs.docker.com/compose/completion/) for system setup instructions.
### Logging in
## Logging in
Several CLI commands require access to your balenaCloud account, for example in order to push a
new release to your application. Those commands require creating a CLI login session by running:
new release to your fleet. Those commands require creating a CLI login session by running:
```sh
$ balena login
```
### Proxy support
## Proxy support
HTTP(S) proxies can be configured through any of the following methods, in precedence order
(from higher to lower):
@ -76,7 +77,6 @@ HTTP(S) proxies can be configured through any of the following methods, in prece
file](https://www.npmjs.com/package/balena-settings-client#documentation). It may be:
* A string in URL format, e.g. `proxy: 'http://localhost:8000'`
* An object in the format:
```yaml
proxy:
protocol: 'http'
@ -88,22 +88,29 @@ HTTP(S) proxies can be configured through any of the following methods, in prece
* The `HTTPS_PROXY` and/or `HTTP_PROXY` environment variables, in the same URL format as
`BALENARC_PROXY`.
> Note: The `balena ssh` command has additional setup requirements to work behind a proxy.
> Check the [installation instructions](https://github.com/balena-io/balena-cli/blob/master/INSTALL.md),
> and ensure that the proxy server is configured to allow proxy requests to ssh port 22, using
> SSL encryption. For example, in the case of the [Squid](http://www.squid-cache.org/) proxy
> server, it should be configured with the following rules in the `squid.conf` file:
> `acl SSL_ports port 22`
> `acl Safe_ports port 22`
### Proxy setup for balena device ssh
#### Proxy exclusion
In order to work behind a proxy server, the `balena device ssh` command requires the
[`proxytunnel`](http://proxytunnel.sourceforge.net/) package (command-line tool) to be installed.
`proxytunnel` is available for Linux distributions like Ubuntu/Debian (`apt install proxytunnel`),
and for macOS through [Homebrew](https://brew.sh/). Windows support is limited to the [Windows
Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/about) (e.g., by installing
Ubuntu through the Microsoft App Store).
Ensure that the proxy server is configured to allow proxy requests to ssh port 22, using
SSL encryption. For example, in the case of the [Squid](http://www.squid-cache.org/) proxy
server, it should be configured with the following rules in the `squid.conf` file:
`acl SSL_ports port 22`
`acl Safe_ports port 22`
### Proxy exclusion
The `BALENARC_NO_PROXY` variable may be used to exclude specified destinations from proxying.
> * This feature requires balena CLI version 11.30.8 or later. In the case of the npm [installation
> * This feature requires CLI version 11.30.8 or later. In the case of the npm [installation
> option](https://github.com/balena-io/balena-cli/blob/master/INSTALL.md), it also requires
> Node.js version 10.16.0 or later.
> * To exclude a `balena ssh` target from proxying (IP address or `.local` hostname), the
> * To exclude a `balena device ssh` target from proxying (IP address or `.local` hostname), the
> `--noproxy` option should be specified in addition to the `BALENARC_NO_PROXY` variable.
By default (if `BALENARC_NO_PROXY` is not defined), all [private IPv4
@ -129,32 +136,38 @@ address like `192.168.1.2`.
## Command reference documentation
The full CLI command reference is available [on the web](https://www.balena.io/docs/reference/cli/
) or by running `balena help` and `balena help --verbose`.
) or by running `balena help --verbose`.
## Support, FAQ and troubleshooting
If you come across any problems or would like to get in touch:
To learn more, troubleshoot issues, or to contact us for support:
* Check our [FAQ / troubleshooting document](https://github.com/balena-io/balena-cli/blob/master/TROUBLESHOOTING.md).
* Ask us a question through the [balenaCloud forum](https://forums.balena.io/c/balena-cloud).
* For bug reports or feature requests,
[have a look at the GitHub issues or create a new one](https://github.com/balena-io/balena-cli/issues/).
* Check the [masterclass tutorials](https://www.balena.io/docs/learn/more/masterclasses/overview/)
* Check our [FAQ / troubleshooting document](https://github.com/balena-io/balena-cli/blob/master/TROUBLESHOOTING.md)
* Ask us a question in the [balena forums](https://forums.balena.io/c/product-support)
For CLI bug reports or feature requests, check the
[CLI GitHub issues](https://github.com/balena-io/balena-cli/issues/).
## Deprecation policy
The balena CLI uses [semver versioning](https://semver.org/), with the concepts
of major, minor and patch version releases.
The latest release of the previous major version of the balena CLI will remain
compatible with the balenaCloud backend services for one year from the date when
the next major version is released. For example, balena CLI v10.17.5, as the
latest v10 release, would remain compatible with the balenaCloud backend for one
year from the date when v11.0.0 is released.
The latest release of a major version of the balena CLI will remain compatible with
the balenaCloud backend services for at least one year from the date when the
following major version is released. For example, balena CLI v11.36.0, as the
latest v11 release, would remain compatible with the balenaCloud backend for one
year from the date when v12.0.0 was released.
At the end of this period, the older major version is considered deprecated and
some of the functionality that depends on balenaCloud services may stop working
at any time.
Users are encouraged to regularly update the balena CLI to the latest version.
Half way through to that period (6 months after the release of the next major
version), older major versions of the balena CLI will start printing a deprecation
warning message when it is used interactively (when `stderr` is attached to a TTY
device file). At the end of that period, older major versions will exit with an
error message unless the `--unsupported` flag is used. This behavior was
introduced in CLI version 12.47.0 and is also documented by `balena help`.
To take advantage of the latest backend features and ensure compatibility, users
are encouraged to regularly update the balena CLI to the latest version.
## Contributing (including editing documentation files)

View File

@ -1,8 +1,6 @@
# FAQ & Troubleshooting
# balena CLI FAQ & Troubleshooting
This document contains some common issues, questions and answers related to the balena CLI.
## Where is my configuration file?
## Where is the balena CLI's configuration file located?
The per-user configuration file lives in `$HOME/.balenarc.yml` or `%UserProfile%\_balenarc.yml`, in
Unix based operating systems and Windows respectively.
@ -10,53 +8,48 @@ Unix based operating systems and Windows respectively.
The balena CLI also attempts to read a `balenarc.yml` file in the current directory, which takes
precedence over the per-user configuration file.
## How do I point the balena CLI to staging?
## How do I point the balena CLI to the staging environment?
The easiest way is to set the `BALENARC_BALENA_URL=balena-staging.com` environment variable.
Alternatively, you can edit your configuration file and set `balenaUrl: balena-staging.com` to
persist this setting.
Set the `BALENARC_BALENA_URL=balena-staging.com` environment variable, or add
`balenaUrl: balena-staging.com` to the balena CLI's configuration file.
## How do I make the balena CLI persist data in another directory?
The balena CLI persists your session token, as well as cached images in `$HOME/.balena` or
`%UserProfile%\_balena`.
The balena CLI persists the session token, as well as cached assets, to `$HOME/.balena` or
`%UserProfile%\_balena`. This directory can be changed by setting an environment variable,
`BALENARC_DATA_DIRECTORY=/opt/balena`, or by adding `dataDirectory: /opt/balena` to the CLI's
configuration file, replacing `/opt/balena` with the desired directory.
Pointing the balena CLI to persist data in another location is necessary in certain environments,
like a server, where there is no home directory, or a device running balenaOS, which erases all
data after a restart.
## After burning to an SD card, my device doesn't boot
You can accomplish this by setting `BALENARC_DATA_DIRECTORY=/opt/balena` or adding `dataDirectory:
/opt/balena` to your configuration file, replacing `/opt/balena` with your desired directory.
Check whether the downloaded image is incomplete (download was interrupted) or corrupted.
## After burning to an sdcard, my device doesn't boot
Try clearing the cache (`%HOME/.balena/cache` or `C:\Users\<user>\_balena\cache`) and running the
command again.
- The downloaded image is not complete (download was interrupted).
## I get a permission error when burning to an SD card
Please clean the cache (`%HOME/.balena/cache` or `C:\Users\<user>\_balena\cache`) and run the command again. In the future, the CLI will check that the image is not complete and clean the cache for you.
Check whether the SD card is locked (a physical switch on the side of the card).
## I get a permission error when burning to an sdcard
## I get `connect ETIMEDOUT` with `balena device tunnel`
- The SDCard is locked.
Please update the CLI to the latest version. This issue was fixed in v12.38.5.
For more details, see: https://github.com/balena-io/balena-cli/issues/2172
### I get EINVAL errors on Cygwin
## I get EINVAL errors on Cygwin
The errors look something like this:
The errors may look something like this:
```
net.js:156
this._handle.open(options.fd);
^
Error: EINVAL, invalid argument
at new Socket (net.js:156:18)
at process.stdin (node.js:664:19)
at Object.Interface.createInterface (C:\cygwin\home\Juan Cruz Viotti\Projects\balena-cli\node_modules\inquirer\node_modules\readline2\index.js:31:43)
at PromptUI.UI (C:\cygwin\home\Juan Cruz Viotti\Projects\balena-cli\node_modules\inquirer\lib\ui\baseUI.js:23:40)
at new PromptUI (C:\cygwin\home\Juan Cruz Viotti\Projects\balena-cli\node_modules\inquirer\lib\ui\prompt.js:26:8)
at Object.promptModule [as prompt] (C:\cygwin\home\Juan Cruz Viotti\Projects\balena-cli\node_modules\inquirer\lib\inquirer.js:27:14)
```
- Some interactive widgets don't work on `Cygwin`. If you're running Windows, it's preferrable that you use `cmd.exe`, as `Cygwin` is [not official supported by Node.js](https://github.com/chjj/blessed/issues/56#issuecomment-42671945).
Some interactive widgets don't work on `Cygwin`. On Windows, PowerShell or `cmd.exe` are better
supported. Alternative shells are [listed in the README
file](./README.md#choosing-a-shell-command-promptterminal).
## I get `Invalid MBR boot signature` when configuring a device
@ -76,7 +69,9 @@ Or in Windows:
## I get `EACCES: permission denied` when logging in
The balena CLI stores the session token in `$HOME/.balena` or `C:\Users\<user>\_balena` in UNIX based operating systems and Windows respectively. This error usually indicates that the user doesn't have permissions over that directory, which can happen if you ran the balena CLI as `root`, and thus the directory got owned by him.
The balena CLI stores the session token in `$HOME/.balena` or `C:\Users\<user>\_balena` in UNIX based
operating systems and Windows respectively. This error usually indicates that the user doesn't have
permissions over that directory, which can happen if the CLI was executed as the `root` user.
Try resetting the ownership by running:
@ -84,9 +79,17 @@ Try resetting the ownership by running:
$ sudo chown -R <user> $HOME/.balena
```
## Broken line wrapping / cursor behavior with `balena ssh`
## Broken line wrapping / cursor behavior with `balena device ssh`
Users sometimes come across broken line wrapping or cursor behavior in text terminals, for example when long command lines are typed in a `balena ssh` session, or when using text editors like `vim` or `nano`. This is not something specific to the balena CLI, being also a commonly reported issue with standard remote terminal tools like `ssh` or `telnet`. It is often a remote shell configuration issue (files like `/etc/profile`, `~/.bash_profile`, `~/.bash_login`, `~/.profile` and the like), including UTF-8 misconfiguration, the use of unsupported ASCII control characters in shell prompt formatting (e.g. the `$PS1` env var) or the output of tools or log files that use colored text. The issue can sometimes be fixed by resizing the client terminal window, or by running one or more of the following commands on the shell:
Users sometimes come across broken line wrapping or cursor behavior in text terminals, for example
when long command lines are typed in a `balena device ssh` session, or when using text editors like `vim`
or `nano`. This is not something specific to the balena CLI, being also a commonly reported issue
with standard remote terminal tools like `ssh` or `telnet`. It is often a remote shell
configuration issue (files like `/etc/profile`, `~/.bash_profile`, `~/.bash_login`, `~/.profile`
and the like on the remote machine), including UTF-8 misconfiguration, the use of unsupported ASCII
control characters in shell prompt formatting (e.g. the `$PS1` env var) or the output of tools or
log files that use colored text. The issue can sometimes be fixed by simply resizing the client
terminal window, or by running one or more of the following commands on the shell:
```sh
export TERMINAL=linux
@ -112,10 +115,10 @@ If nothing seems to help, consider also using a different client-side terminal a
## "Docker seems to be unavailable" error when using Windows Subsystem for Linux (WSL)
When running on WSL, the recommendation is to install a CLI release for Linux, like the standalone
zip package for Linux. However, commands like "balena build" that contact a local Docker daemon,
like the Docker Desktop for Windows, will try to reach Docker at the Unix socket path
`/var/run/docker.sock`, while Docker Desktop for Windows uses a Windows named pipe at
`//./pipe/docker_engine` (which the Linux CLI on WSL cannot use). A solution is:
zip package for Linux. However, commands like "balena build" will, by default, attempt to reach the
Docker daemon at the Unix socket path `/var/run/docker.sock`, while Docker Desktop for Windows uses
a Windows named pipe at `//./pipe/docker_engine` (which the Linux CLI on WSL cannot use). A
solution is:
- Open the Docker Desktop for Windows settings panel and tick the checkbox _"Expose daemon on tcp://localhost:2375 without TLS"._
- On the WSL command line, set an env var:

View File

@ -1,43 +0,0 @@
# appveyor file
# http://www.appveyor.com/docs/appveyor-yml
image: Visual Studio 2017
init:
- git config --global core.autocrlf input
cache:
- C:\Users\appveyor\.node-gyp
- '%AppData%\npm-cache'
matrix:
fast_finish: true
# what combinations to test
environment:
matrix:
- nodejs_version: 10
install:
- ps: Install-Product node $env:nodejs_version x64
- set PATH=%APPDATA%\npm;%PATH%
- npm config set python 'C:\Python27\python.exe'
- npm --version
# - npm install
build: off
test: off
deploy: off
test_script:
- node --version
- npm --version
# - npm test
deploy_script:
- node --version
- npm --version
# - npm run build:standalone
# - npm run build:installer
# - IF "%APPVEYOR_REPO_TAG%" == "true" (npm run release)
# - IF NOT "%APPVEYOR_REPO_TAG%" == "true" (echo 'Not tagged, skipping deploy')

View File

@ -15,30 +15,34 @@
* limitations under the License.
*/
import type { JsonVersions } from '../lib/actions-oclif/version';
import type { JsonVersions } from '../src/commands/version/index';
import { run as oclifRun } from '@oclif/dev-cli';
import { run as oclifRun } from '@oclif/core';
import * as archiver from 'archiver';
import * as Bluebird from 'bluebird';
import { execFile } from 'child_process';
import { exec, execFile } from 'child_process';
import * as filehound from 'filehound';
import type { Stats } from 'fs';
import * as fs from 'fs-extra';
import * as _ from 'lodash';
import * as klaw from 'klaw';
import * as path from 'path';
import { exec as execPkg } from 'pkg';
import * as rimraf from 'rimraf';
import * as semver from 'semver';
import * as util from 'util';
import { promisify } from 'util';
import { notarize } from '@electron/notarize';
import { stripIndent } from '../lib/utils/lazy';
import { stripIndent } from '../build/utils/lazy';
import {
getSubprocessStdout,
diffLines,
loadPackageJson,
MSYS2_BASH,
ROOT,
StdOutTap,
whichSpawn,
} from './utils';
const execFileAsync = promisify(execFile);
const execAsync = promisify(exec);
const rimrafAsync = promisify(rimraf);
export const packageJSON = loadPackageJson();
export const version = 'v' + packageJSON.version;
const arch = process.arch;
@ -57,9 +61,13 @@ const standaloneZips: PathByPlatform = {
win32: dPath(`balena-cli-${version}-windows-${arch}-standalone.zip`),
};
const oclifInstallers: PathByPlatform = {
darwin: dPath('macos', `balena-${version}.pkg`),
win32: dPath('win', `balena-${version}-${arch}.exe`),
const getOclifInstallersOriginalNames = async (): Promise<PathByPlatform> => {
const { stdout } = await execAsync('git rev-parse --short HEAD');
const sha = stdout.trim();
return {
darwin: dPath('macos', `balena-${version}-${sha}-${arch}.pkg`),
win32: dPath('win32', `balena-${version}-${sha}-${arch}.exe`),
};
};
const renamedOclifInstallers: PathByPlatform = {
@ -73,6 +81,100 @@ export const finalReleaseAssets: { [platform: string]: string[] } = {
linux: [standaloneZips['linux']],
};
/**
* Given the output of `pkg` as a string (containing warning messages),
* diff it against previously saved output of known "safe" warnings.
* Throw an error if the diff is not empty.
*/
async function diffPkgOutput(pkgOut: string) {
const { monochrome } = await import('../tests/helpers');
const relSavedPath = path.join(
'tests',
'test-data',
'pkg',
`expected-warnings-${process.platform}-${arch}.txt`,
);
const absSavedPath = path.join(ROOT, relSavedPath);
const ignoreStartsWith = [
'> pkg@',
'> Fetching base Node.js binaries',
' fetched-',
'prebuild-install WARN install No prebuilt binaries found',
];
const modulesRE =
process.platform === 'win32'
? /(?<=[ '])([A-Z]:)?\\.+?\\node_modules(?=\\)/
: /(?<=[ '])\/.+?\/node_modules(?=\/)/;
const buildRE =
process.platform === 'win32'
? /(?<=[ '])([A-Z]:)?\\.+\\build(?=\\)/
: /(?<=[ '])\/.+\/build(?=\/)/;
const cleanLines = (chunks: string | string[]) => {
const lines = typeof chunks === 'string' ? chunks.split('\n') : chunks;
return lines
.map((line: string) => monochrome(line)) // remove ASCII colors
.filter((line: string) => !/^\s*$/.test(line)) // blank lines
.filter((line: string) =>
ignoreStartsWith.every((i) => !line.startsWith(i)),
)
.map((line: string) => {
// replace absolute paths with relative paths
let replaced = line.replace(modulesRE, 'node_modules');
if (replaced === line) {
replaced = line.replace(buildRE, 'build');
}
return replaced;
});
};
pkgOut = cleanLines(pkgOut).join('\n');
const { readFile } = (await import('fs')).promises;
const expectedOut = cleanLines(await readFile(absSavedPath, 'utf8')).join(
'\n',
);
if (expectedOut !== pkgOut) {
const sep =
'================================================================================';
const diff = diffLines(expectedOut, pkgOut);
const msg = `pkg output does not match expected output from "${relSavedPath}"
Diff:
${sep}
${diff}
${sep}
Check whether the new or changed pkg warnings are safe to ignore, then update
"${relSavedPath}"
and share the result of your investigation as comments on the pull request.
Hint: the fix is often a matter of updating the 'pkg.scripts' or 'pkg.assets'
sections in the CLI's 'package.json' file, or a matter of updating the
'buildPkg' function in 'automation/build-bin.ts'. Sometimes it requires
patching dependencies: See for example 'patches/all/open+7.0.2.patch'.
${sep}
`;
throw new Error(msg);
}
}
/**
* Call `pkg.exec` to generate the standalone zip file, capturing its warning
* messages (stdout and stderr) in order to call diffPkgOutput().
*/
async function execPkg(...args: any[]) {
const { exec: pkgExec } = await import('@yao-pkg/pkg');
const outTap = new StdOutTap(true);
try {
outTap.tap();
await (pkgExec as any)(...args);
} catch (err) {
outTap.untap();
console.log(outTap.stdoutBuf.join(''));
console.error(outTap.stderrBuf.join(''));
throw err;
}
outTap.untap();
await diffPkgOutput(outTap.allBuf.join(''));
}
/**
* Use the 'pkg' module to create a single large executable file with
* the contents of 'node_modules' and the CLI's javascript code.
@ -83,9 +185,18 @@ export const finalReleaseAssets: { [platform: string]: string[] } = {
* to be directly executed from inside another binary executable.)
*/
async function buildPkg() {
// https://github.com/vercel/pkg#targets
let targets = `linux-${arch}`;
if (process.platform === 'darwin') {
targets = `macos-${arch}`;
}
// TBC: not yet possible to build for Windows arm64 on x64 nodes
if (process.platform === 'win32') {
targets = `win-x64`;
}
const args = [
'--target',
'host',
'--targets',
targets,
'--output',
'build-bin/balena',
'package.json',
@ -100,7 +211,6 @@ async function buildPkg() {
const paths: Array<[string, string[], string[]]> = [
// [platform, [source path], [destination path]]
['*', ['open', 'xdg-open'], ['xdg-open']],
['*', ['opn', 'xdg-open'], ['xdg-open-402']],
['darwin', ['denymount', 'bin', 'denymount'], ['denymount']],
];
await Promise.all(
@ -149,7 +259,17 @@ async function testPkg() {
console.log(`Testing standalone package "${pkgBalenaPath}"...`);
// Run `balena version -j`, parse its stdout as JSON, and check that the
// reported Node.js major version matches semver.major(process.version)
const stdout = await getSubprocessStdout(pkgBalenaPath, ['version', '-j']);
let { stdout, stderr } = await execFileAsync(pkgBalenaPath, [
'version',
'-j',
]);
const { filterCliOutputForTests } = await import('../tests/helpers');
const filtered = filterCliOutputForTests({
err: stderr.split(/\r?\n/),
out: stdout.split(/\r?\n/),
});
stdout = filtered.out.join('\n');
stderr = filtered.err.join('\n');
let pkgNodeVersion = '';
let pkgNodeMajorVersion = 0;
try {
@ -166,6 +286,10 @@ async function testPkg() {
`Mismatched major version: built-in pkg Node version="${pkgNodeVersion}" vs process.version="${process.version}"`,
);
}
if (filtered.err.length > 0) {
const err = filtered.err.join('\n');
throw new Error(`"${pkgBalenaPath}": non-empty stderr "${err}"`);
}
console.log('Success! (standalone package test successful)');
}
@ -181,7 +305,7 @@ async function zipPkg() {
);
}
await fs.mkdirp(path.dirname(outputFile));
await new Promise((resolve, reject) => {
await new Promise<void>((resolve, reject) => {
console.log(`Zipping standalone package to "${outputFile}"...`);
const archive = archiver('zip', {
@ -198,24 +322,115 @@ async function zipPkg() {
archive.on('warning', console.warn);
archive.pipe(outputStream);
archive.finalize();
archive.finalize().catch(reject);
});
}
export async function signFilesForNotarization() {
console.log('Signing files for notarization');
if (process.platform !== 'darwin') {
return;
}
console.log('Deleting unneeded zip files...');
await new Promise((resolve, reject) => {
klaw('node_modules/')
.on('data', (item: { path: string; stats: Stats }) => {
if (!item.stats.isFile()) {
return;
}
if (path.basename(item.path).endsWith('.node.bak')) {
console.log('Removing pkg .node.bak file', item.path);
fs.unlinkSync(item.path);
}
if (
path.basename(item.path).endsWith('.zip') &&
path.dirname(item.path).includes('test')
) {
console.log('Removing zip', item.path);
fs.unlinkSync(item.path);
}
})
.on('end', resolve)
.on('error', reject);
});
// Sign all .node files first
console.log('Signing .node files...');
await new Promise((resolve, reject) => {
klaw('node_modules/')
.on('data', async (item: { path: string; stats: Stats }) => {
if (!item.stats.isFile()) {
return;
}
if (path.basename(item.path).endsWith('.node')) {
console.log('running command:', 'codesign', [
'-d',
'-f',
'-s',
'Developer ID Application: Balena Ltd (66H43P8FRG)',
item.path,
]);
await whichSpawn('codesign', [
'-d',
'-f',
'-s',
'Developer ID Application: Balena Ltd (66H43P8FRG)',
item.path,
]);
}
})
.on('end', resolve)
.on('error', reject);
});
console.log('Signing other binaries...');
console.log('running command:', 'codesign', [
'-d',
'-f',
'--options=runtime',
'-s',
'Developer ID Application: Balena Ltd (66H43P8FRG)',
'node_modules/denymount/bin/denymount',
]);
await whichSpawn('codesign', [
'-d',
'-f',
'--options=runtime',
'-s',
'Developer ID Application: Balena Ltd (66H43P8FRG)',
'node_modules/denymount/bin/denymount',
]);
console.log('running command:', 'codesign', [
'-d',
'-f',
'--options=runtime',
'-s',
'Developer ID Application: Balena Ltd (66H43P8FRG)',
'node_modules/macmount/bin/macmount',
]);
await whichSpawn('codesign', [
'-d',
'-f',
'--options=runtime',
'-s',
'Developer ID Application: Balena Ltd (66H43P8FRG)',
'node_modules/macmount/bin/macmount',
]);
}
export async function buildStandaloneZip() {
console.log(`Building standalone zip package for CLI ${version}`);
try {
await buildPkg();
await testPkg();
await zipPkg();
console.log(`Standalone zip package build completed`);
} catch (error) {
console.log(`Error creating or testing standalone zip package:\n ${error}`);
process.exit(1);
console.error(`Error creating or testing standalone zip package`);
throw error;
}
console.log(`Standalone zip package build completed`);
}
async function renameInstallerFiles() {
const oclifInstallers = await getOclifInstallersOriginalNames();
if (await fs.pathExists(oclifInstallers[process.platform])) {
await fs.rename(
oclifInstallers[process.platform],
@ -226,22 +441,30 @@ async function renameInstallerFiles() {
/**
* If the CSC_LINK and CSC_KEY_PASSWORD env vars are set, digitally sign the
* executable installer by running the balena-io/scripts/shared/sign-exe.sh
* script (which must be in the PATH) using a MSYS2 bash shell.
* executable installer using Microsoft SignTool.exe (Sign Tool)
* https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe
*/
async function signWindowsInstaller() {
if (process.env.CSC_LINK && process.env.CSC_KEY_PASSWORD) {
if (process.env.SM_CODE_SIGNING_CERT_SHA1_HASH) {
const exeName = renamedOclifInstallers[process.platform];
const execFileAsync = util.promisify<string, string[], void>(execFile);
console.log(`Signing installer "${exeName}"`);
await execFileAsync(MSYS2_BASH, [
'sign-exe.sh',
'-f',
exeName,
// trust ...
await execFileAsync('signtool.exe', [
'sign',
'-sha1',
process.env.SM_CODE_SIGNING_CERT_SHA1_HASH,
'-tr',
process.env.TIMESTAMP_SERVER || 'http://timestamp.comodoca.com',
'-td',
'SHA256',
'-fd',
'SHA256',
'-d',
`balena-cli ${version}`,
exeName,
]);
// ... but verify
await execFileAsync('signtool.exe', ['verify', '-pa', '-v', exeName]);
} else {
console.log(
'Skipping installer signing step because CSC_* env vars are not set',
@ -250,7 +473,27 @@ async function signWindowsInstaller() {
}
/**
* Run the `oclif-dev pack:win` or `pack:macos` command (depending on the value
* Wait for Apple Installer Notarization to continue
*/
async function notarizeMacInstaller(): Promise<void> {
const teamId = process.env.XCODE_APP_LOADER_TEAM_ID || '66H43P8FRG';
const appleId =
process.env.XCODE_APP_LOADER_EMAIL || 'accounts+apple@balena.io';
const appleIdPassword = process.env.XCODE_APP_LOADER_PASSWORD;
if (appleIdPassword && teamId) {
await notarize({
tool: 'notarytool',
teamId,
appPath: renamedOclifInstallers.darwin,
appleId,
appleIdPassword,
});
}
}
/**
* Run the `oclif pack:win` or `pack:macos` command (depending on the value
* of process.platform) to generate the native installers (which end up under
* the 'dist' folder). There are some harcoded options such as selecting only
* 64-bit binaries under Windows.
@ -260,9 +503,10 @@ export async function buildOclifInstaller() {
let packOpts = ['-r', ROOT];
if (process.platform === 'darwin') {
packOS = 'macos';
packOpts = packOpts.concat('--targets', `darwin-${arch}`);
} else if (process.platform === 'win32') {
packOS = 'win';
packOpts = packOpts.concat('-t', 'win32-x64');
packOpts = packOpts.concat('--targets', 'win32-x64');
}
if (packOS) {
console.log(`Building oclif installer for CLI ${version}`);
@ -273,13 +517,14 @@ export async function buildOclifInstaller() {
}
for (const dir of dirs) {
console.log(`rimraf(${dir})`);
await Bluebird.fromCallback((cb) => rimraf(dir, cb));
await rimrafAsync(dir);
}
console.log('=======================================================');
console.log(`oclif-dev "${packCmd}" "${packOpts.join('" "')}"`);
console.log(`oclif ${packCmd} ${packOpts.join(' ')}`);
console.log(`cwd="${process.cwd()}" ROOT="${ROOT}"`);
console.log('=======================================================');
await oclifRun([packCmd].concat(...packOpts));
const oclifPath = path.join(ROOT, 'node_modules', 'oclif');
await oclifRun([packCmd].concat(...packOpts), oclifPath);
await renameInstallerFiles();
// The Windows installer is explicitly signed here (oclif doesn't do it).
// The macOS installer is automatically signed by oclif (which runs the
@ -287,6 +532,10 @@ export async function buildOclifInstaller() {
// (`oclif.macos.sign` section).
if (process.platform === 'win32') {
await signWindowsInstaller();
} else if (process.platform === 'darwin') {
console.log('Notarizing package...');
await notarizeMacInstaller(); // Notarize
console.log('Package notarized.');
}
console.log(`oclif installer build completed`);
}
@ -315,3 +564,12 @@ export async function catchUncommitted(): Promise<void> {
]);
}
}
export async function testShrinkwrap(): Promise<void> {
if (process.env.DEBUG) {
console.error(`[debug] platform=${process.platform}`);
}
if (process.platform !== 'win32') {
await whichSpawn(path.resolve(__dirname, 'test-lock-deduplicated.sh'));
}
}

View File

@ -17,6 +17,7 @@
import * as path from 'path';
import { MarkdownFileParser } from './utils';
import { GlobSync } from 'glob';
/**
* This is the skeleton of CLI documentation/reference web page at:
@ -24,143 +25,111 @@ import { MarkdownFileParser } from './utils';
*
* The `getCapitanoDoc` function in this module parses README.md and adds
* some content to this object.
*
* IMPORTANT
*
* All commands need to be stored under a folder in src/commands to maintain uniformity
* Generating docs will error out if directive not followed
* To add a custom heading for command docs, add the heading next to the folder name
* in the `commandHeadings` dictionary.
*
* This dictionary is the source of truth that creates the docs config which is used
* to generate the CLI documentation. By default, the folder name will be used.
*
*/
const capitanoDoc = {
title: 'Balena CLI Documentation',
introduction: '',
categories: [
{
title: 'API keys',
files: ['build/actions-oclif/api-key/generate.js'],
},
{
title: 'Application',
files: [
'build/actions-oclif/apps.js',
'build/actions-oclif/app/index.js',
'build/actions-oclif/app/create.js',
'build/actions-oclif/app/rm.js',
'build/actions-oclif/app/restart.js',
],
},
{
title: 'Authentication',
files: [
'build/actions-oclif/login.js',
'build/actions-oclif/logout.js',
'build/actions-oclif/whoami.js',
],
},
{
title: 'Device',
files: [
'build/actions-oclif/device/identify.js',
'build/actions-oclif/device/init.js',
'build/actions-oclif/device/index.js',
'build/actions-oclif/device/move.js',
'build/actions-oclif/device/reboot.js',
'build/actions-oclif/device/register.js',
'build/actions-oclif/device/rename.js',
'build/actions-oclif/device/rm.js',
'build/actions-oclif/device/shutdown.js',
'build/actions-oclif/devices/index.js',
'build/actions-oclif/devices/supported.js',
'build/actions-oclif/device/os-update.js',
'build/actions-oclif/device/public-url.js',
],
},
{
title: 'Environment Variables',
files: [
'build/actions-oclif/envs.js',
'build/actions-oclif/env/add.js',
'build/actions-oclif/env/rename.js',
'build/actions-oclif/env/rm.js',
],
},
{
title: 'Tags',
files: [
'build/actions-oclif/tags.js',
'build/actions-oclif/tag/rm.js',
'build/actions-oclif/tag/set.js',
],
},
{
title: 'Help and Version',
files: ['build/actions/help.js', 'build/actions-oclif/version.js'],
},
{
title: 'Keys',
files: [
'build/actions-oclif/keys.js',
'build/actions-oclif/key/index.js',
'build/actions-oclif/key/add.js',
'build/actions-oclif/key/rm.js',
],
},
{
title: 'Logs',
files: ['build/actions-oclif/logs.js'],
},
{
title: 'Network',
files: [
'build/actions-oclif/scan.js',
'build/actions-oclif/ssh.js',
'build/actions-oclif/tunnel.js',
],
},
{
title: 'Notes',
files: ['build/actions-oclif/note.js'],
},
{
title: 'OS',
files: ['build/actions/os.js', 'build/actions-oclif/os/configure.js'],
},
{
title: 'Config',
files: ['build/actions/config.js'],
},
{
title: 'Preload',
files: ['build/actions/preload.js'],
},
{
title: 'Push',
files: ['build/actions/push.js'],
},
{
title: 'Settings',
files: ['build/actions-oclif/settings.js'],
},
{
title: 'Local',
files: [
'build/actions-oclif/local/flash.js',
'build/actions/local/index.js',
],
},
{
title: 'Deploy',
files: ['build/actions/build.js', 'build/actions/deploy.js'],
},
{
title: 'Platform',
files: ['build/actions-oclif/join.js', 'build/actions-oclif/leave.js'],
},
{
title: 'Utilities',
files: ['build/actions-oclif/util/available-drives.js'],
},
],
interface Category {
title: string;
files: string[];
}
interface Documentation {
title: string;
introduction: string;
categories: Category[];
}
// Mapping folders names to custom headings in the docs
const commandHeadings: { [key: string]: string } = {
'api-key': 'API Keys',
login: 'Authentication',
whoami: 'Authentication',
logout: 'Authentication',
env: 'Environment Variables',
help: 'Help and Version',
'ssh-key': 'SSH Keys',
organization: 'Organizations',
os: 'OS',
util: 'Utilities',
build: 'Deploy',
join: 'Platform',
leave: 'Platform',
app: 'Apps',
block: 'Blocks',
device: 'Devices',
fleet: 'Fleets',
release: 'Releases',
tag: 'Tags',
};
// Fetch all available commands
const allCommandsPaths = new GlobSync('build/commands/**/*.js', {
ignore: 'build/commands/internal/**',
}).found;
// Throw error if any commands found outside of command directories
const illegalCommandPaths = allCommandsPaths.filter((commandPath: string) =>
/^build\/commands\/[^/]+\.js$/.test(commandPath),
);
if (illegalCommandPaths.length !== 0) {
throw new Error(
`Found the following commands without a command directory: ${illegalCommandPaths}\n
To resolve this error, move the respective commands to their resource directories or create new ones.\n
Refer to the automation/capitanodoc/capitanodoc.ts file for more information.`,
);
}
// Docs config template
const capitanoDoc: Documentation = {
title: 'balena CLI Documentation',
introduction: '',
categories: [],
};
// Helper function to capitalize each word of directory name
function formatTitle(dir: string): string {
return dir.replace(/(^\w|\s\w)/g, (word) => word.toUpperCase());
}
// Create a map to track the categories for faster lookup
const categoriesMap: { [key: string]: Category } = {};
for (const commandPath of allCommandsPaths) {
const commandDir = path.basename(path.dirname(commandPath));
const heading = commandHeadings[commandDir] || formatTitle(commandDir);
if (!categoriesMap[heading]) {
categoriesMap[heading] = { title: heading, files: [] };
capitanoDoc.categories.push(categoriesMap[heading]);
}
categoriesMap[heading].files.push(commandPath);
}
// Sort Category titles alphabetically
capitanoDoc.categories = capitanoDoc.categories.sort((a, b) =>
a.title.localeCompare(b.title),
);
// Sort Category file paths alphabetically
capitanoDoc.categories.forEach((category) => {
category.files.sort((a, b) => a.localeCompare(b));
});
/**
* Modify and return the `capitanoDoc` object above in order to render the
* CLI documentation/reference web page at:
* https://www.balena.io/docs/reference/cli/
* Modify and return the `capitanoDoc` object above in order to generate the
* CLI documentation at docs/balena-cli.md
*
* This function parses the README.md file to extract relevant sections
* for the documentation web page.
@ -176,10 +145,12 @@ 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('Getting Started'),
mdParser.getSectionOfTitle('Choosing a shell (command prompt/terminal)'),
mdParser.getSectionOfTitle('Logging in'),
mdParser.getSectionOfTitle('Proxy support'),
mdParser.getSectionOfTitle('Support, FAQ and troubleshooting'),
mdParser.getSectionOfTitle('Deprecation policy'),
]);

View File

@ -14,8 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Command as OclifCommandClass } from '@oclif/command';
import { CommandDefinition as CapitanoCommand } from 'capitano';
import type { Command as OclifCommandClass } from '@oclif/core';
type OclifCommand = typeof OclifCommandClass;
@ -27,7 +26,7 @@ export interface Document {
export interface Category {
title: string;
commands: Array<CapitanoCommand | OclifCommand>;
commands: Array<OclifCommand & { name: string }>;
}
export { CapitanoCommand, OclifCommand };
export { OclifCommand };

View File

@ -14,11 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as _ from 'lodash';
import * as path from 'path';
import { getCapitanoDoc } from './capitanodoc';
import { CapitanoCommand, Category, Document, OclifCommand } from './doc-types';
import type { Category, Document, OclifCommand } from './doc-types';
import * as markdown from './markdown';
/**
@ -40,11 +38,7 @@ export async function renderMarkdown(): Promise<string> {
};
for (const jsFilename of commandCategory.files) {
category.commands.push(
...(jsFilename.includes('actions-oclif')
? importOclifCommands(jsFilename)
: importCapitanoCommands(jsFilename)),
);
category.commands.push(await importOclifCommands(jsFilename));
}
result.categories.push(category);
}
@ -52,28 +46,23 @@ export async function renderMarkdown(): Promise<string> {
return markdown.render(result);
}
function importCapitanoCommands(jsFilename: string): CapitanoCommand[] {
const actions = require(path.join(process.cwd(), jsFilename));
const commands: CapitanoCommand[] = [];
if (actions.signature) {
commands.push(_.omit(actions, 'action') as any);
} else {
for (const actionName of Object.keys(actions)) {
const actionCommand = actions[actionName];
commands.push(_.omit(actionCommand, 'action') as any);
}
}
return commands;
}
function importOclifCommands(jsFilename: string): OclifCommand[] {
// TODO: Currently oclif commands with no `usage` overridden will cause
// an error when parsed. This should be improved so that `usage` does not have
// to be overridden if not necessary.
const command: OclifCommand = require(path.join(process.cwd(), jsFilename))
async function importOclifCommands(jsFilename: string) {
const command = (await import(path.join(process.cwd(), jsFilename)))
.default as OclifCommand;
return [command];
return {
...command,
// build/commands/device/index.js -> device
// build/commands/device/list.js -> device list
name: jsFilename
.split('/')
.slice(2)
.join(' ')
.split('.')
.slice(0, 1)
.join(' ')
.split(' index')[0],
} as Category['commands'][0];
}
/**
@ -85,8 +74,9 @@ async function printMarkdown() {
console.log(await renderMarkdown());
} catch (error) {
console.error(error);
process.exit(1);
process.exitCode = 1;
}
}
// eslint-disable-next-line @typescript-eslint/no-floating-promises
printMarkdown();

View File

@ -14,39 +14,31 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { flagUsages } from '@oclif/parser';
import { Parser } from '@oclif/core';
import * as ent from 'ent';
import * as _ from 'lodash';
import { getManualSortCompareFunction } from '../../lib/utils/helpers';
import { capitanoizeOclifUsage } from '../../lib/utils/oclif-utils';
import { CapitanoCommand, Category, Document, OclifCommand } from './doc-types';
import * as utils from './utils';
import { capitanoizeOclifUsage } from '../../src/utils/oclif-utils';
import type { Category, Document } from './doc-types';
function renderCapitanoCommand(command: CapitanoCommand): string[] {
const result = [`## ${ent.encode(command.signature)}`, command.help!];
if (!_.isEmpty(command.options)) {
result.push('### Options');
for (const option of command.options!) {
if (option == null) {
throw new Error(`Undefined option in markdown generation!`);
}
if (option.description == null) {
throw new Error(`Undefined option.description in markdown generation!`);
}
result.push(
`#### ${utils.parseCapitanoOption(option)}`,
option.description,
);
}
function renderOclifCommand(command: Category['commands'][0]): string[] {
const result = [`## ${ent.encode(command.name || '')}`];
if (command.aliases?.length) {
result.push('### Aliases');
result.push(
command.aliases
.map(
(alias) =>
`- \`${alias}\`${command.deprecateAliases ? ' *(deprecated)*' : ''}`,
)
.join('\n'),
);
result.push(
`\nTo use one of the aliases, replace \`${command.name}\` with the alias.`,
);
}
return result;
}
function renderOclifCommand(command: OclifCommand): string[] {
const result = [`## ${ent.encode(command.usage)}`];
result.push('### Description');
const description = (command.description || '')
.split('\n')
.slice(1) // remove the first line, which oclif uses as help header
@ -60,8 +52,8 @@ function renderOclifCommand(command: OclifCommand): string[] {
if (!_.isEmpty(command.args)) {
result.push('### Arguments');
for (const arg of command.args!) {
result.push(`#### ${arg.name.toUpperCase()}`, arg.description || '');
for (const [name, arg] of Object.entries(command.args!)) {
result.push(`#### ${name.toUpperCase()}`, arg.description || '');
}
}
@ -72,7 +64,7 @@ function renderOclifCommand(command: OclifCommand): string[] {
continue;
}
flag.name = name;
const flagUsage = flagUsages([flag])
const flagUsage = Parser.flagUsages([flag])
.map(([usage, _description]) => usage)
.join()
.trim();
@ -86,11 +78,7 @@ function renderOclifCommand(command: OclifCommand): string[] {
function renderCategory(category: Category): string[] {
const result = [`# ${category.title}`];
for (const command of category.commands) {
result.push(
...(typeof command === 'object'
? renderCapitanoCommand(command)
: renderOclifCommand(command)),
);
result.push(...renderOclifCommand(command));
}
return result;
}
@ -107,10 +95,7 @@ function renderToc(categories: Category[]): string[] {
result.push(
category.commands
.map((command) => {
const signature =
typeof command === 'object'
? command.signature // Capitano
: capitanoizeOclifUsage(command.usage); // oclif
const signature = capitanoizeOclifUsage(command.name);
return `\t- [${ent.encode(signature)}](${getAnchor(signature)})`;
})
.join('\n'),
@ -119,35 +104,7 @@ function renderToc(categories: Category[]): string[] {
return result;
}
const manualCategorySorting: { [category: string]: string[] } = {
'Environment Variables': ['envs', 'env rm', 'env add', 'env rename'],
OS: [
'os versions',
'os download',
'os build config',
'os configure',
'os initialize',
],
};
function sortCommands(doc: Document): void {
for (const category of doc.categories) {
if (category.title in manualCategorySorting) {
category.commands = category.commands.sort(
getManualSortCompareFunction<CapitanoCommand | OclifCommand, string>(
manualCategorySorting[category.title],
(cmd: CapitanoCommand | OclifCommand, x: string) =>
typeof cmd === 'object' // Capitano vs oclif command
? cmd.signature.replace(/\W+/g, ' ').includes(x)
: (cmd.usage || '').toString().replace(/\W+/g, ' ').includes(x),
),
);
}
}
}
export function render(doc: Document) {
sortCommands(doc);
const result = [
`# ${doc.title}`,
doc.introduction,

View File

@ -15,41 +15,9 @@
* limitations under the License.
*/
import type { OptionDefinition } from 'capitano';
import * as ent from 'ent';
import * as fs from 'fs';
import * as readline from 'readline';
export function getOptionPrefix(signature: string) {
if (signature.length > 1) {
return '--';
} else {
return '-';
}
}
export function getOptionSignature(signature: string) {
return `${getOptionPrefix(signature)}${signature}`;
}
export function parseCapitanoOption(option: OptionDefinition): string {
let result = getOptionSignature(option.signature);
if (Array.isArray(option.alias)) {
for (const alias of option.alias) {
result += `, ${getOptionSignature(alias)}`;
}
} else if (typeof option.alias === 'string') {
result += `, ${getOptionSignature(option.alias)}`;
}
if (option.parameter) {
result += ` <${option.parameter}>`;
}
return ent.encode(result);
}
export class MarkdownFileParser {
constructor(public mdFilePath: string) {}

View File

@ -15,24 +15,25 @@
* limitations under the License.
*/
const stripIndent = require('common-tags/lib/stripIndent');
const _ = require('lodash');
const { promises: fs } = require('fs');
const path = require('path');
const simplegit = require('simple-git/promise');
// eslint-disable-next-line no-restricted-imports
import { stripIndent } from 'common-tags';
import * as _ from 'lodash';
import { promises as fs } from 'fs';
import * as path from 'path';
import { simpleGit } from 'simple-git';
const ROOT = path.normalize(path.join(__dirname, '..'));
/**
* Compare the timestamp of cli.markdown with the timestamp of staged files,
* issuing an error if cli.markdown is older.
* If cli.markdown does not require updating and the developer cannot run
* Compare the timestamp of balena-cli.md with the timestamp of staged files,
* issuing an error if balena-cli.md is older.
* If balena-cli.md does not require updating and the developer cannot run
* `npm run build` on their laptop, the error message suggests a workaround
* using `touch`.
*/
async function checkBuildTimestamps() {
const git = simplegit(ROOT);
const docFile = path.join(ROOT, 'doc', 'cli.markdown');
const git = simpleGit(ROOT);
const docFile = path.join(ROOT, 'docs', 'balena-cli.md');
const [docStat, gitStatus] = await Promise.all([
fs.stat(docFile),
git.status(),
@ -42,8 +43,8 @@ async function checkBuildTimestamps() {
...gitStatus.staged,
...gitStatus.renamed.map((o) => o.to),
])
// select only staged files that start with lib/ or typings/
.filter((f) => f.match(/^(lib|typings)[/\\]/))
// select only staged files that start with src/ or typings/
.filter((f) => f.match(/^(src|typings)[/\\]/))
.map((f) => path.join(ROOT, f));
const fStats = await Promise.all(stagedFiles.map((f) => fs.stat(f)));
@ -81,4 +82,5 @@ async function run() {
}
}
// eslint-disable-next-line @typescript-eslint/no-floating-promises
run();

View File

@ -6,6 +6,8 @@
*
* We don't `require('semver')` to allow this script to be run as a npm
* 'preinstall' hook, at which point no dependencies have been installed.
*
* @param {string} version
*/
function parseSemver(version) {
const match = /v?(\d+)\.(\d+).(\d+)/.exec(version);
@ -16,9 +18,13 @@ function parseSemver(version) {
return [parseInt(major, 10), parseInt(minor, 10), parseInt(patch, 10)];
}
/**
* @param {string} v1
* @param {string} v2
*/
function semverGte(v1, v2) {
let v1Array = parseSemver(v1);
let v2Array = parseSemver(v2);
const v1Array = parseSemver(v1);
const v2Array = parseSemver(v2);
for (let i = 0; i < 3; i++) {
if (v1Array[i] < v2Array[i]) {
return false;
@ -41,17 +47,25 @@ function checkNpmVersion() {
// the reason is that it would unnecessarily prevent end users from
// using npm v6.4.1 that ships with Node 8. (It is OK for the
// shrinkwrap file to get damaged if it is not going to be reused.)
console.error(`\
-------------------------------------------------------------------------------
throw new Error(`\
-----------------------------------------------------------------------------
Error: npm version '${npmVersion}' detected. Please upgrade to npm v${requiredVersion} or later
because of a bug that causes the 'npm-shrinkwrap.json' file to be damaged.
At this point, however, your 'npm-shrinkwrap.json' file has already been
damaged. Please revert it to the master branch state with a command such as:
"git checkout master -- npm-shrinkwrap.json"
Then re-run "npm install" using npm version ${requiredVersion} or later.
-------------------------------------------------------------------------------`);
process.exit(1);
-----------------------------------------------------------------------------`);
}
}
checkNpmVersion();
function main() {
try {
checkNpmVersion();
} catch (e) {
console.error(e.message || e);
process.exitCode = 1;
}
}
main();

View File

@ -1,252 +0,0 @@
/**
* @license
* Copyright 2019 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as Bluebird from 'bluebird';
import * as _ from 'lodash';
import * as semver from 'semver';
import { finalReleaseAssets, version } from './build-bin';
const { GITHUB_TOKEN } = process.env;
/**
* Create or update a release in GitHub's releases page, uploading the
* installer files (standalone zip + native oclif installers).
*/
export async function createGitHubRelease() {
console.log(`Publishing release ${version} to GitHub`);
const publishRelease = await import('publish-release');
const ghRelease = await Bluebird.fromCallback(
publishRelease.bind(null, {
token: GITHUB_TOKEN || '',
owner: 'balena-io',
repo: 'balena-cli',
tag: version,
name: `balena-CLI ${version}`,
reuseRelease: true,
assets: finalReleaseAssets[process.platform],
}),
);
console.log(`Release ${version} successful: ${ghRelease.html_url}`);
}
/**
* Top-level function to create a CLI release in GitHub's releases page:
* call zipStandaloneInstaller(), rename the files as we'd like them to
* display on the releases page, and call createGitHubRelease() to upload
* the files.
*/
export async function release() {
try {
await createGitHubRelease();
} catch (err) {
console.error('Release failed');
console.error(err);
process.exit(1);
}
}
/** Return a cached Octokit instance, creating a new one as needed. */
const getOctokit = _.once(function () {
const Octokit = (require('@octokit/rest') as typeof import('@octokit/rest')).Octokit.plugin(
(require('@octokit/plugin-throttling') as typeof import('@octokit/plugin-throttling'))
.throttling,
);
return new Octokit({
auth: GITHUB_TOKEN,
throttle: {
onRateLimit: (retryAfter: number, options: any) => {
console.warn(
`Request quota exhausted for request ${options.method} ${options.url}`,
);
// retries 3 times
if (options.request.retryCount < 3) {
console.log(`Retrying after ${retryAfter} seconds!`);
return true;
}
},
onAbuseLimit: (_retryAfter: number, options: any) => {
// does not retry, only logs a warning
console.warn(
`Abuse detected for request ${options.method} ${options.url}`,
);
},
},
});
});
/**
* Extract pagination information (current page, total pages, ordinal number)
* from the 'link' response header (example below), using the parse-link-header
* npm package:
* "link": "<https://api.github.com/repositories/187370853/releases?per_page=2&page=2>; rel=\"next\",
* <https://api.github.com/repositories/187370853/releases?per_page=2&page=3>; rel=\"last\""
*
* @param response Octokit response object (including response.headers.link)
* @param perPageDefault Default per_page pagination value if missing in URL
* @return Object where 'page' is the current page number (1-based),
* 'pages' is the total number of pages, and 'ordinal' is the ordinal number
* (3rd, 4th, 5th...) of the first item in the current page.
*/
function getPageNumbers(
response: any,
perPageDefault: number,
): { page: number; pages: number; ordinal: number } {
const res = { page: 1, pages: 1, ordinal: 1 };
if (!response.headers.link) {
return res;
}
const parse = require('parse-link-header') as typeof import('parse-link-header');
const parsed = parse(response.headers.link);
if (parsed == null) {
throw new Error(`Failed to parse link header: '${response.headers.link}'`);
}
let perPage = perPageDefault;
if (parsed.next) {
if (parsed.next.per_page) {
perPage = parseInt(parsed.next.per_page, 10);
}
res.page = parseInt(parsed.next.page, 10) - 1;
res.pages = parseInt(parsed.last.page, 10);
} else {
if (parsed.prev.per_page) {
perPage = parseInt(parsed.prev.per_page, 10);
}
res.page = res.pages = parseInt(parsed.prev.page, 10) + 1;
}
res.ordinal = (res.page - 1) * perPage + 1;
return res;
}
/**
* Iterate over every GitHub release in the given owner/repo, check whether
* its tag_name matches against the affectedVersions semver spec, and if so
* replace its release description (body) with the given newDescription value.
* @param owner GitHub repo owner, e.g. 'balena-io' or 'pdcastro'
* @param repo GitHub repo, e.g. 'balena-cli'
* @param affectedVersions Semver spec, e.g. '2.6.1 - 7.10.9 || 8.0.0'
* @param newDescription New release description (body)
* @param editID Short string present in newDescription, e.g. '[AA101]', that
* can be searched to determine whether that release has already been updated.
*/
async function updateGitHubReleaseDescriptions(
owner: string,
repo: string,
affectedVersions: string,
newDescription: string,
editID: string,
) {
const perPage = 30;
const octokit = getOctokit();
const options = await octokit.repos.listReleases.endpoint.merge({
owner,
repo,
per_page: perPage,
});
let errCount = 0;
for await (const response of octokit.paginate.iterator(options)) {
const { page: thisPage, pages: totalPages, ordinal } = getPageNumbers(
response,
perPage,
);
let i = 0;
for (const cliRelease of response.data) {
const prefix = `[#${ordinal + i++} pg ${thisPage}/${totalPages}]`;
if (!cliRelease.id) {
console.error(
`${prefix} Error: missing release ID (errCount=${++errCount})`,
);
continue;
}
const skipMsg = `${prefix} skipping release "${cliRelease.tag_name}" (${cliRelease.id})`;
if (cliRelease.draft === true) {
console.info(`${skipMsg}: draft release`);
continue;
} else if (cliRelease.body && cliRelease.body.includes(editID)) {
console.info(`${skipMsg}: already updated`);
continue;
} else if (!semver.satisfies(cliRelease.tag_name, affectedVersions)) {
console.info(`${skipMsg}: outside version range`);
continue;
} else {
const updatedRelease = {
owner,
repo,
release_id: cliRelease.id,
body: newDescription,
};
let oldBodyPreview = cliRelease.body;
if (oldBodyPreview) {
oldBodyPreview = oldBodyPreview.replace(/\s+/g, ' ').trim();
if (oldBodyPreview.length > 12) {
oldBodyPreview = oldBodyPreview.substring(0, 9) + '...';
}
}
console.info(
`${prefix} updating release "${cliRelease.tag_name}" (${cliRelease.id}) old body="${oldBodyPreview}"`,
);
try {
await octokit.repos.updateRelease(updatedRelease);
} catch (err) {
console.error(
`${skipMsg}: Error: ${err.message} (count=${++errCount})`,
);
continue;
}
}
}
}
}
/**
* Add a warning description to CLI releases affected by a mixpanel tracking
* security issue (#1359). This function can be executed "manually" with the
* following command line:
*
* npx ts-node --type-check -P automation/tsconfig.json automation/run.ts fix1359
*/
export async function updateDescriptionOfReleasesAffectedByIssue1359() {
// Run only on Linux/Node10, instead of all platform/Node combinations.
// (It could have been any other platform, as long as it only runs once.)
if (process.platform !== 'linux' || semver.major(process.version) !== 10) {
return;
}
const owner = 'balena-io';
const repo = 'balena-cli';
const affectedVersions =
'2.6.1 - 7.10.9 || 8.0.0 - 8.1.0 || 9.0.0 - 9.15.6 || 10.0.0 - 10.17.5 || 11.0.0 - 11.7.2';
const editID = '[AA100]';
let newDescription = `
Please note: the "login" command in this release is affected by a
security issue fixed in versions
[7.10.10](https://github.com/balena-io/balena-cli/releases/tag/v7.10.10),
[8.1.1](https://github.com/balena-io/balena-cli/releases/tag/v8.1.1),
[9.15.7](https://github.com/balena-io/balena-cli/releases/tag/v9.15.7),
[10.17.6](https://github.com/balena-io/balena-cli/releases/tag/v10.17.6),
[11.7.3](https://github.com/balena-io/balena-cli/releases/tag/v11.7.3)
and later. If you need to use this version, avoid passing your password,
keys or tokens as command-line arguments. ${editID}`;
// remove line breaks and collapse white space
newDescription = newDescription.replace(/\s+/g, ' ').trim();
await updateGitHubReleaseDescriptions(
owner,
repo,
affectedVersions,
newDescription,
editID,
);
}

View File

@ -21,12 +21,9 @@ import {
buildOclifInstaller,
buildStandaloneZip,
catchUncommitted,
signFilesForNotarization,
testShrinkwrap,
} from './build-bin';
import {
release,
updateDescriptionOfReleasesAffectedByIssue1359,
} from './deploy-bin';
import { fixPathForMsys, ROOT, runUnderMsys } from './utils';
// DEBUG set to falsy for negative values else is truthy
process.env.DEBUG = ['0', 'no', 'false', '', undefined].includes(
@ -35,87 +32,56 @@ process.env.DEBUG = ['0', 'no', 'false', '', undefined].includes(
? ''
: '1';
function exitWithError(error: Error | string): never {
console.error(`Error: ${error}`);
process.exit(1);
}
/**
* Trivial command-line parser. Check whether the command-line argument is one
* of the following strings, then call the appropriate functions:
* 'build:installer' (to build a native oclif installer)
* 'build:standalone' (to build a standalone pkg package)
* 'release' (to create/update a GitHub release)
*
* In the case of 'build:installer', also call runUnderMsys() to switch the
* shell from cmd.exe to MSYS2 bash.exe.
*
* @param args Arguments to parse (default is process.argv.slice(2))
*/
export async function run(args?: string[]) {
async function parse(args?: string[]) {
args = args || process.argv.slice(2);
console.log(`automation/run.ts process.argv=[${process.argv}]\n`);
console.log(`automation/run.ts args=[${args}]`);
console.error(`[debug] automation/run.ts process.argv=[${process.argv}]`);
console.error(`[debug] automation/run.ts args=[${args}]`);
if (_.isEmpty(args)) {
return exitWithError('missing command-line arguments');
throw new Error('missing command-line arguments');
}
const commands: { [cmd: string]: () => void | Promise<void> } = {
'build:installer': buildOclifInstaller,
'build:standalone': buildStandaloneZip,
'sign:binaries': signFilesForNotarization,
'catch-uncommitted': catchUncommitted,
fix1359: updateDescriptionOfReleasesAffectedByIssue1359,
release,
'test-shrinkwrap': testShrinkwrap,
};
for (const arg of args) {
if (!commands.hasOwnProperty(arg)) {
return exitWithError(`command unknown: ${arg}`);
if (!Object.hasOwn(commands, arg)) {
throw new Error(`command unknown: ${arg}`);
}
}
// If runUnderMsys() is called to re-execute this script under MSYS2,
// the current working dir becomes the MSYS2 homedir, so we change back.
process.chdir(ROOT);
// The BUILD_TMP env var is used as an alternative location for oclif
// (patched) to copy/extract the CLI files, run npm install and then
// create the NSIS executable installer for Windows. This was necessary
// to avoid issues with a 260-char limit on Windows paths (possibly a
// limitation of some library used by NSIS), as the "current working dir"
// provided by balena CI is a rather long path to start with.
if (process.platform === 'win32' && !process.env.BUILD_TMP) {
const randID = (await import('crypto'))
.randomBytes(6)
.toString('base64')
.replace(/\+/g, '-')
.replace(/\//g, '_'); // base64url (RFC 4648)
process.env.BUILD_TMP = `C:\\tmp\\${randID}`;
}
for (const arg of args) {
try {
if (arg === 'build:installer' && process.platform === 'win32') {
// ensure running under MSYS2
if (!process.env.MSYSTEM) {
process.env.MSYS2_PATH_TYPE = 'inherit';
await runUnderMsys([
fixPathForMsys(process.argv[0]),
fixPathForMsys(process.argv[1]),
arg,
]);
continue;
}
if (process.env.MSYS2_PATH_TYPE !== 'inherit') {
throw new Error(
'the MSYS2_PATH_TYPE env var must be set to "inherit"',
);
}
}
const cmdFunc = commands[arg];
await cmdFunc();
} catch (err) {
return exitWithError(`"${arg}": ${err}`);
if (typeof err === 'object') {
err.message = `"${arg}": ${err.message}`;
}
throw err;
}
}
}
/** See jsdoc for parse() function above */
export async function run(args?: string[]) {
try {
await parse(args);
} catch (e) {
console.error(e.message ? `Error: ${e.message}` : e);
process.exitCode = 1;
}
}
// eslint-disable-next-line @typescript-eslint/no-floating-promises
run();

View File

@ -0,0 +1,20 @@
#!/bin/bash
set -e
cp npm-shrinkwrap.json npm-shrinkwrap.json.old
npm i
npm dedupe
npm i
if ! diff -q npm-shrinkwrap.json npm-shrinkwrap.json.old > /dev/null; then
rm npm-shrinkwrap.json.old
echo "** npm-shrinkwrap.json was not deduplicated or not fully committed - FAIL **";
echo "** This can usually be fixed with: **";
echo "** git checkout master -- npm-shrinkwrap.json **";
echo "** rm -rf node_modules **";
echo "** npm install && npm dedupe && npm install **";
exit 1;
fi
rm npm-shrinkwrap.json.old

View File

@ -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':
@ -11,8 +11,7 @@ const validateChangeType = (maybeChangeType: string = 'minor') => {
case 'major':
return maybeChangeType;
default:
console.error(`Invalid change type: '${maybeChangeType}'`);
return process.exit(1);
throw new Error(`Invalid change type: '${maybeChangeType}'`);
}
};
@ -37,8 +36,8 @@ const run = async (cmd: string) => {
}
resolve({ stdout, stderr });
});
p.stdout.pipe(process.stdout);
p.stderr.pipe(process.stderr);
p.stdout?.pipe(process.stdout);
p.stderr?.pipe(process.stderr);
});
};
@ -58,31 +57,24 @@ const getUpstreams = async () => {
const repoYaml = fs.readFileSync(__dirname + '/../repo.yml', 'utf8');
const yaml = await import('js-yaml');
const { upstream } = yaml.safeLoad(repoYaml) as {
const { upstream } = yaml.load(repoYaml) as {
upstream: Upstream[];
};
return upstream;
};
const printUsage = (upstreams: Upstream[], upstreamName: string) => {
console.error(
`
const getUsage = (upstreams: Upstream[], upstreamName: string) => `
Usage: npm run update ${upstreamName} $version [$changeType=minor]
Upstream names: ${upstreams.map(({ repo }) => repo).join(', ')}
`,
);
return process.exit(1);
};
`;
// TODO: Drop the wrapper function once we move to TS 3.8,
// which will support top level await.
async function main() {
async function $main() {
const upstreams = await getUpstreams();
if (process.argv.length < 3) {
return printUsage(upstreams, '$upstreamName');
throw new Error(getUsage(upstreams, '$upstreamName'));
}
const upstreamName = process.argv[2];
@ -90,16 +82,15 @@ async function main() {
const upstream = upstreams.find((v) => v.repo === upstreamName);
if (!upstream) {
console.error(
throw new Error(
`Invalid upstream name '${upstreamName}', valid options: ${upstreams
.map(({ repo }) => repo)
.join(', ')}`,
);
return process.exit(1);
}
if (process.argv.length < 4) {
printUsage(upstreams, upstreamName);
throw new Error(getUsage(upstreams, upstreamName));
}
const packageName = upstream.module || upstream.repo;
@ -108,8 +99,7 @@ async function main() {
await run(`npm install ${packageName}@${process.argv[3]}`);
const newVersion = await getVersion(packageName);
if (newVersion === oldVersion) {
console.error(`Already on version '${newVersion}'`);
return process.exit(1);
throw new Error(`Already on version '${newVersion}'`);
}
console.log(`Updated ${upstreamName} from ${oldVersion} to ${newVersion}`);
@ -117,11 +107,11 @@ async function main() {
const changeType = process.argv[4]
? // if the caller specified a change type, use that one
validateChangeType(process.argv[4])
validateChangeType(process.argv[4])
: // use the same change type as in the dependency, but avoid major bumps
semverChangeType && semverChangeType !== 'major'
? semverChangeType
: 'minor';
semverChangeType && semverChangeType !== 'major'
? semverChangeType
: 'minor';
console.log(`Using Change-type: ${changeType}`);
let { stdout: currentBranch } = await run('git rev-parse --abbrev-ref HEAD');
@ -137,4 +127,13 @@ async function main() {
);
}
main();
async function main() {
try {
await $main();
} catch (e) {
console.error(e);
process.exitCode = 1;
}
}
void main();

View File

@ -16,102 +16,80 @@
*/
import { spawn } from 'child_process';
import * as _ from 'lodash';
import * as path from 'path';
import * as shellEscape from 'shell-escape';
import * as fs from 'fs';
import { diffTrimmedLines } from 'diff';
import * as whichMod from 'which';
export const MSYS2_BASH = 'C:\\msys64\\usr\\bin\\bash.exe';
export const ROOT = path.join(__dirname, '..');
/** Tap and buffer this process' stdout and stderr */
export class StdOutTap {
public stdoutBuf: string[] = [];
public stderrBuf: string[] = [];
public allBuf: string[] = []; // both stdout and stderr
protected origStdoutWrite: typeof process.stdout.write;
protected origStderrWrite: typeof process.stdout.write;
constructor(protected printDots = false) {}
tap() {
this.origStdoutWrite = process.stdout.write;
this.origStderrWrite = process.stderr.write;
process.stdout.write = (chunk: string, ...args: any[]): boolean => {
this.stdoutBuf.push(chunk);
this.allBuf.push(chunk);
const str = this.printDots ? '.' : chunk;
return this.origStdoutWrite.call(process.stdout, str, ...args);
};
process.stderr.write = (chunk: string, ...args: any[]): boolean => {
this.stderrBuf.push(chunk);
this.allBuf.push(chunk);
const str = this.printDots ? '.' : chunk;
return this.origStderrWrite.call(process.stderr, str, ...args);
};
}
untap() {
process.stdout.write = this.origStdoutWrite;
process.stderr.write = this.origStderrWrite;
if (this.printDots) {
console.error('');
}
}
}
/**
* Diff strings by line, using the 'diff' npm package:
* https://www.npmjs.com/package/diff
*/
export function diffLines(str1: string, str2: string): string {
const diffObjs = diffTrimmedLines(str1, str2);
const prefix = (chunk: string, char: string) =>
chunk
.split('\n')
.map((line: string) => `${char} ${line}`)
.join('\n');
const diffStr = diffObjs
.map((part: any) => {
return part.added
? prefix(part.value, '+')
: part.removed
? prefix(part.value, '-')
: prefix(part.value, ' ');
})
.join('\n');
return diffStr;
}
export function loadPackageJson() {
return require(path.join(ROOT, 'package.json'));
}
const packageJsonPath = path.join(ROOT, 'package.json');
/**
* Convert e.g. 'C:\myfolder' -> '/C/myfolder' so that the path can be given
* as argument to "unix tools" like 'tar' under MSYS or MSYS2 on Windows.
*/
export function fixPathForMsys(p: string): string {
return p.replace(/\\/g, '/').replace(/^([a-zA-Z]):/, '/$1');
}
/**
* Run the MSYS2 bash.exe shell in a child process (child_process.spawn()).
* The given argv arguments are escaped using the 'shell-escape' package,
* so that backslashes in Windows paths, and other bash-special characters,
* are preserved. If argv is not provided, defaults to process.argv, to the
* effect that this current (parent) process is re-executed under MSYS2 bash.
* This is useful to change the default shell from cmd.exe to MSYS2 bash on
* Windows.
* @param argv Arguments to be shell-escaped and given to MSYS2 bash.exe.
*/
export async function runUnderMsys(argv?: string[]) {
const newArgv = argv || process.argv;
await new Promise((resolve, reject) => {
const args = ['-lc', shellEscape(newArgv)];
const child = spawn(MSYS2_BASH, args, { stdio: 'inherit' });
child.on('close', (code) => {
if (code) {
console.log(`runUnderMsys: child process exited with code ${code}`);
reject(code);
} else {
resolve();
}
});
});
}
/**
* Run the executable at execPath as a child process, and resolve a promise
* to the executable's stdout output as a string. Reject the promise if
* anything is printed to stderr, or if the child process exits with a
* non-zero exit code.
* @param execPath Executable path
* @param args Command-line argument for the executable
*/
export async function getSubprocessStdout(
execPath: string,
args: string[],
): Promise<string> {
const child = spawn(execPath, args);
return new Promise((resolve, reject) => {
let stdout = '';
child.stdout.on('error', reject);
child.stderr.on('error', reject);
child.stdout.on('data', (data: Buffer) => {
try {
stdout = data.toString();
} catch (err) {
reject(err);
}
});
child.stderr.on('data', (data: Buffer) => {
try {
const stderr = data.toString();
// ignore any debug lines, but ensure that we parse
// every line provided to the stderr stream
const lines = _.filter(
stderr.trim().split(/\r?\n/),
(line) => !line.startsWith('[debug]'),
);
if (lines.length > 0) {
reject(
new Error(`"${execPath}": non-empty stderr "${lines.join('\n')}"`),
);
}
} catch (err) {
reject(err);
}
});
child.on('exit', (code: number) => {
if (code) {
reject(new Error(`"${execPath}": non-zero exit code "${code}"`));
} else {
resolve(stdout);
}
});
});
const packageJson = fs.readFileSync(packageJsonPath, 'utf8');
return JSON.parse(packageJson);
}
/**
@ -124,7 +102,6 @@ export async function getSubprocessStdout(
* @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);
@ -143,7 +120,7 @@ export async function which(program: string): Promise<string> {
*/
export async function whichSpawn(
programName: string,
args: string[],
args: string[] = [],
): Promise<void> {
const program = await which(programName);
let error: Error | undefined;
@ -155,7 +132,7 @@ export async function whichSpawn(
.on('error', reject)
.on('close', resolve);
} catch (err) {
reject(err);
reject(err as Error);
}
});
} catch (err) {

View File

@ -1,73 +0,0 @@
#!/bin/bash
_balena_complete()
{
local cur prev
# Valid top-level completions
commands="app apps build config deploy device devices env envs help key \
keys local login logout logs note os preload quickstart settings \
scan ssh util version whoami"
# Sub-completions
app_cmds="create restart rm"
config_cmds="generate inject read reconfigure write"
device_cmds="identify init move public-url reboot register rename rm \
shutdown"
device_public_url_cmds="disable enable status"
env_cmds="add rename rm"
key_cmds="add rm"
local_cmds="configure flash"
os_cmds="build-config configure download initialize versions"
util_cmds="available-drives"
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
prev=${COMP_WORDS[COMP_CWORD-1]}
if [ $COMP_CWORD -eq 1 ]
then
COMPREPLY=( $(compgen -W "${commands}" -- $cur) )
elif [ $COMP_CWORD -eq 2 ]
then
case "$prev" in
"app")
COMPREPLY=( $(compgen -W "$app_cmds" -- $cur) )
;;
"config")
COMPREPLY=( $(compgen -W "$config_cmds" -- $cur) )
;;
"device")
COMPREPLY=( $(compgen -W "$device_cmds" -- $cur) )
;;
"env")
COMPREPLY=( $(compgen -W "$env_cmds" -- $cur) )
;;
"key")
COMPREPLY=( $(compgen -W "$key_cmds" -- $cur) )
;;
"local")
COMPREPLY=( $(compgen -W "$local_cmds" -- $cur) )
;;
"os")
COMPREPLY=( $(compgen -W "$os_cmds" -- $cur) )
;;
"util")
COMPREPLY=( $(compgen -W "$util_cmds" -- $cur) )
;;
"*")
;;
esac
elif [ $COMP_CWORD -eq 3 ]
then
case "$prev" in
"public-url")
COMPREPLY=( $(compgen -W "$device_public_url_cmds" -- $cur) )
;;
"*")
;;
esac
fi
}
complete -F _balena_complete balena

View File

@ -1,20 +0,0 @@
#!/usr/bin/env node
// We boost the threadpool size as ext2fs can deadlock with some
// operations otherwise, if the pool runs out.
process.env.UV_THREADPOOL_SIZE = '64';
// Disable oclif registering ts-node
process.env.OCLIF_TS_NODE = 0;
// Use fast-boot to cache require lookups, speeding up startup
require('fast-boot2').start({
cacheScope: __dirname + '/..',
cacheFile: __dirname + '/.fast-boot.json'
});
// Set the desired es version for downstream modules that support it
require('@balena/es-version').set('es2018');
// Run the CLI
require('../build/app').run();

1
bin/balena Symbolic link
View File

@ -0,0 +1 @@
run.js

View File

@ -1,32 +0,0 @@
#!/usr/bin/env node
// ****************************************************************************
// THIS IS FOR DEV PERROSES ONLY AND WILL NOT BE PART OF THE PUBLISHED PACKAGE
// Before opening a PR you should build and test your changes using bin/balena
// ****************************************************************************
// We boost the threadpool size as ext2fs can deadlock with some
// operations otherwise, if the pool runs out.
process.env.UV_THREADPOOL_SIZE = '64';
// Use fast-boot to cache require lookups, speeding up startup
require('fast-boot2').start({
cacheScope: __dirname + '/..',
cacheFile: '.fast-boot.json',
});
// Set the desired es version for downstream modules that support it
require('@balena/es-version').set('es2018');
const path = require('path');
const rootDir = path.join(__dirname, '..');
// Note: before ts-node v6.0.0, 'transpile-only' (no type checking) was the
// default option. We upgraded ts-node and found that adding 'transpile-only'
// was necessary to avoid a mysterious 'null' error message. On the plus side,
// it is supposed to run faster. We still benefit from type checking when
// running 'npm run build'.
require('ts-node').register({
project: path.join(rootDir, 'tsconfig.json'),
transpileOnly: true,
});
require('../lib/app').run();

1
bin/balena-dev Symbolic link
View File

@ -0,0 +1 @@
dev.js

3
bin/dev.cmd Normal file
View File

@ -0,0 +1,3 @@
@echo off
node "%~dp0\run" %*

90
bin/dev.js Executable file
View File

@ -0,0 +1,90 @@
#!/usr/bin/env node
// ****************************************************************************
// THIS IS FOR DEV PURPOSES ONLY AND WILL NOT BE PART OF THE PUBLISHED PACKAGE
// Before opening a PR you should build and test your changes using bin/balena
// ****************************************************************************
// We boost the threadpool size as ext2fs can deadlock with some
// operations otherwise, if the pool runs out.
process.env.UV_THREADPOOL_SIZE = '64';
// Note on `fast-boot2`: We do not use `fast-boot2` with `balena-dev` because:
// * fast-boot2's cacheKiller option is configured to include the timestamps of
// the package.json and npm-shrinkwrap.json files, to avoid unexpected CLI
// behavior when changes are made to dependencies during development. This is
// generally a good thing, however, `balena-dev` (a few lines below) edits
// `package.json` to modify oclif paths, and this results in cache
// invalidation and a performance hit rather than speedup.
// * Even if the timestamps are removed from cacheKiller, so that there is no
// cache invalidation, fast-boot's speedup is barely noticeable when ts-node
// is used, e.g. 1.43s vs 1.4s when running `balena version`.
// * `fast-boot` causes unexpected behavior when used with `npm link` or
// when the `node_modules` folder is manually modified (affecting transitive
// dependencies) during development (e.g. bug investigations). A workaround
// is to use `balena-dev` without `fast-boot`. See also notes in
// `CONTRIBUTING.md`.
const path = require('path');
const rootDir = path.join(__dirname, '..');
// Allow balena-dev to work with oclif by temporarily
// pointing oclif config options to src/ instead of build/
modifyOclifPaths();
// Undo changes on exit
process.on('exit', function () {
modifyOclifPaths(true);
});
// Undo changes in case of ctrl-c
process.on('SIGINT', function () {
modifyOclifPaths(true);
// Note process exit here will interfere with commands that do their own SIGINT handling,
// but without it commands can not be exited.
// So currently using balena-dev does not guarantee proper exit behaviour when using ctrl-c.
// Ideally a better solution is needed.
process.exit();
});
// Set the desired es version for downstream modules that support it
require('@balena/es-version').set('es2018');
// Note: before ts-node v6.0.0, 'transpile-only' (no type checking) was the
// default option. We upgraded ts-node and found that adding 'transpile-only'
// was necessary to avoid a mysterious 'null' error message. On the plus side,
// it is supposed to run faster. We still benefit from type checking when
// running 'npm run build'.
require('ts-node').register({
project: path.join(rootDir, 'tsconfig.json'),
transpileOnly: 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) {
const fs = require('fs');
const packageJsonPath = path.join(rootDir, 'package.json');
const packageJson = fs.readFileSync(packageJsonPath, 'utf8');
const packageObj = JSON.parse(packageJson);
if (!packageObj.oclif) {
return;
}
let oclifSectionText = JSON.stringify(packageObj.oclif);
if (!revert) {
oclifSectionText = oclifSectionText.replace(/\/build\//g, '/src/');
} else {
oclifSectionText = oclifSectionText.replace(/\/src\//g, '/build/');
}
packageObj.oclif = JSON.parse(oclifSectionText);
fs.writeFileSync(
packageJsonPath,
`${JSON.stringify(packageObj, null, 2)}\n`,
'utf8',
);
}

3
bin/run.cmd Normal file
View File

@ -0,0 +1,3 @@
@echo off
node "%~dp0\run" %*

21
bin/run.js Executable file
View File

@ -0,0 +1,21 @@
#!/usr/bin/env node
// We boost the threadpool size as ext2fs can deadlock with some
// operations otherwise, if the pool runs out.
process.env.UV_THREADPOOL_SIZE = '64';
// Disable oclif registering ts-node
process.env.OCLIF_TS_NODE = '0';
async function run() {
// Use fast-boot to cache require lookups, speeding up startup
await require('../build/fast-boot').start();
// Set the desired es version for downstream modules that support it
require('@balena/es-version').set('es2018');
// Run the CLI
await require('../build/app').run(undefined, { dir: __dirname });
}
void run();

95
completion/_balena Normal file
View File

@ -0,0 +1,95 @@
#compdef balena
#autoload
#GENERATED FILE DON'T MODIFY#
_balena() {
typeset -A opt_args
local context state line curcontext="$curcontext"
# Valid top-level completions
main_commands=( api-key app block build config deploy device device-type env fleet internal join leave local login logout organization os preload push release settings ssh-key support tag util version whoami )
# Sub-completions
api_key_cmds=( generate list revoke )
app_cmds=( create )
block_cmds=( create )
config_cmds=( generate inject read reconfigure write )
device_type_cmds=( list )
device_cmds=( deactivate detect identify init list local-mode logs move note os-update pin public-url purge reboot register rename restart rm shutdown ssh start-service stop-service track-fleet tunnel )
env_cmds=( list rename rm set )
fleet_cmds=( create list pin purge rename restart rm track-latest )
internal_cmds=( osinit )
local_cmds=( configure flash )
organization_cmds=( list )
os_cmds=( build-config configure download initialize versions )
release_cmds=( finalize invalidate list validate )
ssh_key_cmds=( add list rm )
tag_cmds=( list rm set )
_arguments -C \
'(- 1 *)--version[show version and exit]' \
'(- 1 *)--help[show help options and exit]' \
'1:first command:_balena_main_cmds' \
'2:second command:_balena_sec_cmds' \
&& ret=0
}
(( $+functions[_balena_main_cmds] )) ||
_balena_main_cmds() {
_describe -t main_commands 'command' main_commands "$@" && ret=0
}
(( $+functions[_balena_sec_cmds] )) ||
_balena_sec_cmds() {
case $line[1] in
"api-key")
_describe -t api_key_cmds 'api-key_cmd' api_key_cmds "$@" && ret=0
;;
"app")
_describe -t app_cmds 'app_cmd' app_cmds "$@" && ret=0
;;
"block")
_describe -t block_cmds 'block_cmd' block_cmds "$@" && ret=0
;;
"config")
_describe -t config_cmds 'config_cmd' config_cmds "$@" && ret=0
;;
"device-type")
_describe -t device_type_cmds 'device-type_cmd' device_type_cmds "$@" && ret=0
;;
"device")
_describe -t device_cmds 'device_cmd' device_cmds "$@" && ret=0
;;
"env")
_describe -t env_cmds 'env_cmd' env_cmds "$@" && ret=0
;;
"fleet")
_describe -t fleet_cmds 'fleet_cmd' fleet_cmds "$@" && ret=0
;;
"internal")
_describe -t internal_cmds 'internal_cmd' internal_cmds "$@" && ret=0
;;
"local")
_describe -t local_cmds 'local_cmd' local_cmds "$@" && ret=0
;;
"organization")
_describe -t organization_cmds 'organization_cmd' organization_cmds "$@" && ret=0
;;
"os")
_describe -t os_cmds 'os_cmd' os_cmds "$@" && ret=0
;;
"release")
_describe -t release_cmds 'release_cmd' release_cmds "$@" && ret=0
;;
"ssh-key")
_describe -t ssh_key_cmds 'ssh-key_cmd' ssh_key_cmds "$@" && ret=0
;;
"tag")
_describe -t tag_cmds 'tag_cmd' tag_cmds "$@" && ret=0
;;
esac
}
_balena "$@"

View File

@ -0,0 +1,92 @@
#!/bin/bash
#GENERATED FILE DON'T MODIFY#
_balena_complete()
{
local cur prev
# Valid top-level completions
main_commands="api-key app block build config deploy device device-type env fleet internal join leave local login logout organization os preload push release settings ssh-key support tag util version whoami"
# Sub-completions
api_key_cmds="generate list revoke"
app_cmds="create"
block_cmds="create"
config_cmds="generate inject read reconfigure write"
device_type_cmds="list"
device_cmds="deactivate detect identify init list local-mode logs move note os-update pin public-url purge reboot register rename restart rm shutdown ssh start-service stop-service track-fleet tunnel"
env_cmds="list rename rm set"
fleet_cmds="create list pin purge rename restart rm track-latest"
internal_cmds="osinit"
local_cmds="configure flash"
organization_cmds="list"
os_cmds="build-config configure download initialize versions"
release_cmds="finalize invalidate list validate"
ssh_key_cmds="add list rm"
tag_cmds="list rm set"
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
prev=${COMP_WORDS[COMP_CWORD-1]}
if [ $COMP_CWORD -eq 1 ]
then
COMPREPLY=( $(compgen -W "${main_commands}" -- $cur) )
elif [ $COMP_CWORD -eq 2 ]
then
case "$prev" in
api-key)
COMPREPLY=( $(compgen -W "$api_key_cmds" -- $cur) )
;;
app)
COMPREPLY=( $(compgen -W "$app_cmds" -- $cur) )
;;
block)
COMPREPLY=( $(compgen -W "$block_cmds" -- $cur) )
;;
config)
COMPREPLY=( $(compgen -W "$config_cmds" -- $cur) )
;;
device-type)
COMPREPLY=( $(compgen -W "$device_type_cmds" -- $cur) )
;;
device)
COMPREPLY=( $(compgen -W "$device_cmds" -- $cur) )
;;
env)
COMPREPLY=( $(compgen -W "$env_cmds" -- $cur) )
;;
fleet)
COMPREPLY=( $(compgen -W "$fleet_cmds" -- $cur) )
;;
internal)
COMPREPLY=( $(compgen -W "$internal_cmds" -- $cur) )
;;
local)
COMPREPLY=( $(compgen -W "$local_cmds" -- $cur) )
;;
organization)
COMPREPLY=( $(compgen -W "$organization_cmds" -- $cur) )
;;
os)
COMPREPLY=( $(compgen -W "$os_cmds" -- $cur) )
;;
release)
COMPREPLY=( $(compgen -W "$release_cmds" -- $cur) )
;;
ssh-key)
COMPREPLY=( $(compgen -W "$ssh_key_cmds" -- $cur) )
;;
tag)
COMPREPLY=( $(compgen -W "$tag_cmds" -- $cur) )
;;
"*")
;;
esac
fi
}
complete -F _balena_complete balena

View File

@ -0,0 +1,175 @@
/**
* @license
* Copyright 2021 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const path = require('path');
const rootDir = path.join(__dirname, '..');
const fs = require('fs');
const manifestFile = 'oclif.manifest.json';
commandsFilePath = path.join(rootDir, manifestFile);
if (fs.existsSync(commandsFilePath)) {
console.log('Generating shell auto completion files...');
} else {
console.error(`generate-completion.js: Could not find "${manifestFile}"`);
process.exitCode = 1;
return;
}
const commandsJson = JSON.parse(fs.readFileSync(commandsFilePath, 'utf8'));
const mainCommands = [];
const additionalCommands = [];
for (const key of Object.keys(commandsJson.commands).sort()) {
const cmd = key.split(':');
if (cmd.length > 1) {
additionalCommands.push(cmd);
if (!mainCommands.includes(cmd[0])) {
mainCommands.push(cmd[0]);
}
} else {
mainCommands.push(cmd[0]);
}
}
const mainCommandsStr = mainCommands.join(' ');
// GENERATE BASH COMPLETION FILE
bashFilePathIn = path.join(__dirname, '/templates/bash.template');
bashFilePathOut = path.join(__dirname, 'balena-completion.bash');
try {
fs.unlinkSync(bashFilePathOut);
} catch (error) {
process.exitCode = 1;
return console.error(error);
}
fs.readFile(bashFilePathIn, 'utf8', function (err, data) {
if (err) {
process.exitCode = 1;
return console.error(err);
}
data = data.replace(
'#TEMPLATE FILE FOR BASH COMPLETION#',
"#GENERATED FILE DON'T MODIFY#",
);
data = data.replace(
/\$main_commands\$/g,
'main_commands="' + mainCommandsStr + '"',
);
let subCommands = [];
let prevElement = additionalCommands[0][0];
additionalCommands.forEach(function (element) {
if (element[0] === prevElement) {
subCommands.push(element[1]);
} else {
const prevElement2 = prevElement.replace(/-/g, '_') + '_cmds';
data = data.replace(
/\$sub_cmds\$/g,
' ' + prevElement2 + '="' + subCommands.join(' ') + '"\n$sub_cmds$',
);
data = data.replace(
/\$sub_cmds_prev\$/g,
' ' +
prevElement +
')\n COMPREPLY=( $(compgen -W "$' +
prevElement2 +
'" -- $cur) )\n ;;\n$sub_cmds_prev$',
);
prevElement = element[0];
subCommands = [];
subCommands.push(element[1]);
}
});
// cleanup placeholders
data = data.replace(/\$sub_cmds\$/g, '');
data = data.replace(/\$sub_cmds_prev\$/g, '');
fs.writeFile(bashFilePathOut, data, 'utf8', function (error) {
if (error) {
process.exitCode = 1;
return console.error(error);
}
});
});
// GENERATE ZSH COMPLETION FILE
zshFilePathIn = path.join(__dirname, '/templates/zsh.template');
zshFilePathOut = path.join(__dirname, '_balena');
try {
fs.unlinkSync(zshFilePathOut);
} catch (error) {
process.exitCode = 1;
return console.error(error);
}
fs.readFile(zshFilePathIn, 'utf8', function (err, data) {
if (err) {
process.exitCode = 1;
return console.error(err);
}
data = data.replace(
'#TEMPLATE FILE FOR ZSH COMPLETION#',
"#GENERATED FILE DON'T MODIFY#",
);
data = data.replace(
/\$main_commands\$/g,
'main_commands=( ' + mainCommandsStr + ' )',
);
let subCommands = [];
let prevElement = additionalCommands[0][0];
additionalCommands.forEach(function (element) {
if (element[0] === prevElement) {
subCommands.push(element[1]);
} else {
const prevElement2 = prevElement.replace(/-/g, '_') + '_cmds';
data = data.replace(
/\$sub_cmds\$/g,
' ' + prevElement2 + '=( ' + subCommands.join(' ') + ' )\n$sub_cmds$',
);
data = data.replace(
/\$sub_cmds_prev\$/g,
' "' +
prevElement +
'")\n _describe -t ' +
prevElement2 +
" '" +
prevElement +
"_cmd' " +
prevElement2 +
' "$@" && ret=0\n ;;\n$sub_cmds_prev$',
);
prevElement = element[0];
subCommands = [];
subCommands.push(element[1]);
}
});
// cleanup placeholders
data = data.replace(/\$sub_cmds\$/g, '');
data = data.replace(/\$sub_cmds_prev\$/g, '');
fs.writeFile(zshFilePathOut, data, 'utf8', function (error) {
if (error) {
process.exitCode = 1;
return console.error(error);
}
});
});

View File

@ -0,0 +1,32 @@
#!/bin/bash
#TEMPLATE FILE FOR BASH COMPLETION#
_balena_complete()
{
local cur prev
# Valid top-level completions
$main_commands$
# Sub-completions
$sub_cmds$
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
prev=${COMP_WORDS[COMP_CWORD-1]}
if [ $COMP_CWORD -eq 1 ]
then
COMPREPLY=( $(compgen -W "${main_commands}" -- $cur) )
elif [ $COMP_CWORD -eq 2 ]
then
case "$prev" in
$sub_cmds_prev$
"*")
;;
esac
fi
}
complete -F _balena_complete balena

View File

@ -0,0 +1,35 @@
#compdef balena
#autoload
#TEMPLATE FILE FOR ZSH COMPLETION#
_balena() {
typeset -A opt_args
local context state line curcontext="$curcontext"
# Valid top-level completions
$main_commands$
# Sub-completions
$sub_cmds$
_arguments -C \
'(- 1 *)--version[show version and exit]' \
'(- 1 *)--help[show help options and exit]' \
'1:first command:_balena_main_cmds' \
'2:second command:_balena_sec_cmds' \
&& ret=0
}
(( $+functions[_balena_main_cmds] )) ||
_balena_main_cmds() {
_describe -t main_commands 'command' main_commands "$@" && ret=0
}
(( $+functions[_balena_sec_cmds] )) ||
_balena_sec_cmds() {
case $line[1] in
$sub_cmds_prev$
esac
}
_balena "$@"

View File

@ -1,112 +0,0 @@
# Provisioning balena devices in automated (non-interactive) mode
This document describes how to run the `device init` command in non-interactive mode.
It requires collecting some preliminary information _once_.
The final command to provision the device looks like this:
```bash
balena device init --app APP_ID --os-version OS_VERSION --drive DRIVE --config CONFIG_FILE --yes
```
You can run this command as many times as you need, putting the new medium (SD card / USB stick) each time.
But before you can run it you need to collect the parameters and build the configuration file. Keep reading to figure out how to do it.
## Collect all the required parameters.
1. `DEVICE_TYPE`. Run
```bash
balena devices supported
```
and find the _slug_ for your target device type, like _raspberrypi3_.
1. `APP_ID`. Create an application (`balena app create APP_NAME --type DEVICE_TYPE`) or find an existing one (`balena apps`) and notice its ID.
1. `OS_VERSION`. Run
```bash
balena os versions DEVICE_TYPE
```
and pick the version that you need, like _v2.0.6+rev1.prod_.
_Note_ that even though we support _semver ranges_ it's recommended to use the exact version when doing the automated provisioning as it
guarantees full compatibility between the steps.
1. `DRIVE`. Plug in your target medium (SD card or the USB stick, depending on your device type) and run
```bash
balena util available-drives
```
and get the drive name, like _/dev/sdb_ or _/dev/mmcblk0_.
The balena CLI will not display the system drives to protect you,
but still please check very carefully that you've picked the correct drive as it will be erased during the provisioning process.
Now we have all the parameters -- time to build the config file.
## Build the config file
Interactive device provisioning process often includes collecting some extra device configuration, like the networking mode and wifi credentials.
To skip this interactive step we need to buid this configuration once and save it to the JSON file for later reuse.
Let's say we will place it into the `CONFIG_FILE` path, like _./balena-os/raspberrypi3-config.json_.
We also need to put the OS image somewhere, let's call this path `OS_IMAGE_PATH`, it can be something like _./balena-os/raspberrypi3-v2.0.6+rev1.prod.img_.
1. First we need to download the OS image once. That's needed for building the config, and will speedup the subsequent operations as the downloaded OS image is placed into the local cache.
Run:
```bash
balena os download DEVICE_TYPE --output OS_IMAGE_PATH --version OS_VERSION
```
1. Now we're ready to build the config:
```bash
balena os build-config OS_IMAGE_PATH DEVICE_TYPE --output CONFIG_FILE
```
This will run you through the interactive configuration wizard and in the end save the generated config as `CONFIG_FILE`. You can then verify it's not empty:
```bash
cat CONFIG_FILE
```
## Done
Now you're ready to run the command in the beginning of this guide.
Please note again that all of these steps only need to be done once (unless you need to change something), and once all the parameters are collected the main init command can be run unchanged.
But there are still some nuances to cover, please read below.
## Nuances
### `sudo` password on *nix systems
In order to write the image to the raw device we need the root permissions, this is unavoidable.
To improve the security we only run the minimal subcommand with `sudo`.
This means that with the default setup you're interrupted closer to the end of the device init process to enter your sudo password for this subcommand to work.
There are several ways to eliminate it and make the process fully non-interactive.
#### Option 1: make passwordless sudo.
Obviously you shouldn't do that if the machine you're working on has access to any sensitive resources or information.
But if you're using a machine dedicated to balena provisioning this can be fine, and also the simplest thing to do.
#### Option 2: `NOPASSWD` directive
You can configure the `balena` CLI command to be sudo-runnable without the password. Check [this post](https://askubuntu.com/questions/159007/how-do-i-run-specific-sudo-commands-without-a-password) for an example.
### Extra initialization config
As of June 2017 all the supported devices should not require any other interactive configuration.
But by the design of our system it is _possible_ (though it doesn't look very likely it's going to happen any time soon) that some extra initialization options may be requested for the specific device types.
If that is the case please raise the issue in the balena CLI repository and the maintainers will add the necessary options to build the similar JSON config for this step.

File diff suppressed because it is too large Load Diff

4054
docs/balena-cli.md Normal file

File diff suppressed because it is too large Load Diff

32
eslint.config.js Normal file
View 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: '^_',
}],
},
}),
];

View File

@ -1,15 +0,0 @@
const gulp = require('gulp');
const inlinesource = require('gulp-inline-source');
const OPTIONS = {
files: {
pages: 'lib/auth/pages/*.ejs',
},
};
gulp.task('pages', () =>
gulp
.src(OPTIONS.files.pages)
.pipe(inlinesource())
.pipe(gulp.dest('build/auth/pages')),
);

View File

@ -1,85 +0,0 @@
/**
* @license
* Copyright 2016-2020 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { flags } from '@oclif/command';
import Command from '../../command';
import { ExpectedError } from '../../errors';
import * as cf from '../../utils/common-flags';
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
interface FlagsDef {
help: void;
}
interface ArgsDef {
name: string;
}
export default class GenerateCmd extends Command {
public static description = stripIndent`
Generate a new balenaCloud API key.
Generate a new balenaCloud API key for the current user, with the given
name. The key will be logged to the console.
This key can be used to log into the CLI using 'balena login --token <key>',
or to authenticate requests to the API with an 'Authorization: Bearer <key>' header.
`;
public static examples = ['$ balena api-key generate "Jenkins Key"'];
public static args = [
{
name: 'name',
description: 'the API key name',
required: true,
},
];
public static usage = 'api-key generate <name>';
public static flags: flags.Input<FlagsDef> = {
help: cf.help,
};
public static authenticated = true;
public async run() {
const { args: params } = this.parse<FlagsDef, ArgsDef>(GenerateCmd);
let key;
try {
key = await getBalenaSdk().models.apiKey.create(params.name);
} catch (e) {
if (e.name === 'BalenaNotLoggedIn') {
throw new ExpectedError(stripIndent`
This command cannot be run when logged in with an API key.
Please login again with 'balena login' and select an alternative method.
`);
} else {
throw e;
}
}
console.log(stripIndent`
Registered api key '${params.name}':
${key}
This key will not be shown again, so please save it now.
`);
}
}

View File

@ -1,103 +0,0 @@
/**
* @license
* Copyright 2016-2020 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { flags } from '@oclif/command';
import Command from '../../command';
import { ExpectedError } from '../../errors';
import * as cf from '../../utils/common-flags';
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
import type * as BalenaSDK from 'balena-sdk';
interface FlagsDef {
type?: string; // application device type
help: void;
}
interface ArgsDef {
name: string;
}
export default class AppCreateCmd extends Command {
public static description = stripIndent`
Create an application.
Create a new balena application.
You can specify the application device type with the \`--type\` option.
Otherwise, an interactive dropdown will be shown for you to select from.
You can see a list of supported device types with:
$ balena devices supported
`;
public static examples = [
'$ balena app create MyApp',
'$ balena app create MyApp --type raspberry-pi',
];
public static args = [
{
name: 'name',
description: 'application name',
required: true,
},
];
public static usage = 'app create <name>';
public static flags: flags.Input<FlagsDef> = {
type: flags.string({
char: 't',
description:
'application device type (Check available types with `balena devices supported`)',
}),
help: cf.help,
};
public static authenticated = true;
public async run() {
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
AppCreateCmd,
);
const balena = getBalenaSdk();
// Create application
const deviceType =
options.type ||
(await (await import('../../utils/patterns')).selectDeviceType());
let application: BalenaSDK.Application;
try {
application = await balena.models.application.create({
name: params.name,
deviceType,
});
} catch (err) {
// BalenaRequestError: Request error: Unique key constraint violated
if ((err.message || '').toLowerCase().includes('unique')) {
throw new ExpectedError(
`Error: application "${params.name}" already exists`,
);
}
throw err;
}
console.info(
`Application created: ${application.slug} (${application.device_type}, id ${application.id})`,
);
}
}

View File

@ -1,74 +0,0 @@
/**
* @license
* Copyright 2016-2020 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { flags } from '@oclif/command';
import Command from '../../command';
import * as cf from '../../utils/common-flags';
import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy';
import { tryAsInteger } from '../../utils/validation';
interface FlagsDef {
help: void;
}
interface ArgsDef {
name: string;
}
export default class AppCmd extends Command {
public static description = stripIndent`
Display information about a single application.
Display detailed information about a single balena application.
`;
public static examples = ['$ balena app MyApp'];
public static args = [
{
name: 'name',
description: 'application name or numeric ID',
required: true,
},
];
public static usage = 'app <name>';
public static flags: flags.Input<FlagsDef> = {
help: cf.help,
};
public static authenticated = true;
public static primary = true;
public async run() {
const { args: params } = this.parse<FlagsDef, ArgsDef>(AppCmd);
const application = await getBalenaSdk().models.application.get(
tryAsInteger(params.name),
);
console.log(
getVisuals().table.vertical(application, [
`$${application.app_name}$`,
'id',
'device_type',
'slug',
'commit',
]),
);
}
}

View File

@ -1,61 +0,0 @@
/**
* @license
* Copyright 2016-2020 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { flags } from '@oclif/command';
import Command from '../../command';
import * as cf from '../../utils/common-flags';
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
import { tryAsInteger } from '../../utils/validation';
interface FlagsDef {
help: void;
}
interface ArgsDef {
name: string;
}
export default class AppRestartCmd extends Command {
public static description = stripIndent`
Restart an application.
Restart all devices that belongs to a certain application.
`;
public static examples = ['$ balena app restart MyApp'];
public static args = [
{
name: 'name',
description: 'application name or numeric ID',
required: true,
},
];
public static usage = 'app restart <name>';
public static flags: flags.Input<FlagsDef> = {
help: cf.help,
};
public static authenticated = true;
public async run() {
const { args: params } = this.parse<FlagsDef, ArgsDef>(AppRestartCmd);
await getBalenaSdk().models.application.restart(tryAsInteger(params.name));
}
}

View File

@ -1,79 +0,0 @@
/**
* @license
* Copyright 2016-2020 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { flags } from '@oclif/command';
import Command from '../../command';
import * as cf from '../../utils/common-flags';
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
import { tryAsInteger } from '../../utils/validation';
interface FlagsDef {
yes: boolean;
help: void;
}
interface ArgsDef {
name: string;
}
export default class AppRmCmd extends Command {
public static description = stripIndent`
Remove an application.
Permanently remove a balena application.
The --yes option may be used to avoid interactive confirmation.
`;
public static examples = [
'$ balena app rm MyApp',
'$ balena app rm MyApp --yes',
];
public static args = [
{
name: 'name',
description: 'application name or numeric ID',
required: true,
},
];
public static usage = 'app rm <name>';
public static flags: flags.Input<FlagsDef> = {
yes: cf.yes,
help: cf.help,
};
public static authenticated = true;
public async run() {
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
AppRmCmd,
);
const patterns = await import('../../utils/patterns');
// Confirm
await patterns.confirm(
options.yes ?? false,
`Are you sure you want to delete application ${params.name}?`,
);
// Remove
await getBalenaSdk().models.application.remove(tryAsInteger(params.name));
}
}

View File

@ -1,95 +0,0 @@
/**
* @license
* Copyright 2016-2020 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { flags } from '@oclif/command';
import type { Application } from 'balena-sdk';
import Command from '../command';
import * as cf from '../utils/common-flags';
import { getBalenaSdk, getVisuals, stripIndent } from '../utils/lazy';
import { isV12 } from '../utils/version';
interface ExtendedApplication extends Application {
device_count?: number;
online_devices?: number;
}
interface FlagsDef {
help: void;
verbose?: boolean;
}
export default class AppsCmd extends Command {
public static description = stripIndent`
List all applications.
list all your balena applications.
For detailed information on a particular application,
use \`balena app <name> instead\`.
`;
public static examples = ['$ balena apps'];
public static usage = 'apps';
public static flags: flags.Input<FlagsDef> = {
help: cf.help,
verbose: flags.boolean({
char: 'v',
description: isV12()
? 'No-op since release v12.0.0'
: 'add extra columns in the tabular output (SLUG)',
}),
};
public static authenticated = true;
public static primary = true;
public async run() {
const { flags: options } = this.parse<FlagsDef, {}>(AppsCmd);
const balena = getBalenaSdk();
// Get applications
const applications: ExtendedApplication[] = await balena.models.application.getAll(
{
$select: ['id', 'app_name', 'slug', 'device_type'],
$expand: { owns__device: { $select: 'is_online' } },
},
);
const _ = await import('lodash');
// Add extended properties
applications.forEach((application) => {
application.device_count = application.owns__device?.length ?? 0;
application.online_devices = _.sumBy(application.owns__device, (d) =>
d.is_online === true ? 1 : 0,
);
});
// Display
console.log(
getVisuals().table.horizontal(applications, [
'id',
'app_name',
options.verbose || isV12() ? 'slug' : '',
'device_type',
'online_devices',
'device_count',
]),
);
}
}

View File

@ -1,125 +0,0 @@
/**
* @license
* Copyright 2016-2020 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { flags } from '@oclif/command';
import { IArg } from '@oclif/parser/lib/args';
import Command from '../../command';
import * as cf from '../../utils/common-flags';
import { expandForAppName } from '../../utils/helpers';
import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy';
import { tryAsInteger } from '../../utils/validation';
import type { Application, Device } from 'balena-sdk';
interface ExtendedDevice extends Device {
dashboard_url?: string;
application_name?: string;
commit?: string;
last_seen?: string;
}
interface FlagsDef {
help: void;
}
interface ArgsDef {
uuid: string;
}
export default class DeviceCmd extends Command {
public static description = stripIndent`
Show info about a single device.
Show information about a single device.
`;
public static examples = ['$ balena device 7cf02a6'];
public static args: Array<IArg<any>> = [
{
name: 'uuid',
description: 'the device uuid',
parse: (dev) => tryAsInteger(dev),
required: true,
},
];
public static usage = 'device <uuid>';
public static flags: flags.Input<FlagsDef> = {
help: cf.help,
};
public static authenticated = true;
public static primary = true;
public async run() {
const { args: params } = this.parse<FlagsDef, ArgsDef>(DeviceCmd);
const balena = getBalenaSdk();
const device: ExtendedDevice = await balena.models.device.get(params.uuid, {
$select: [
'device_name',
'id',
'device_type',
'overall_status',
'is_online',
'ip_address',
'mac_address',
'last_connectivity_event',
'uuid',
'is_on__commit',
'supervisor_version',
'is_web_accessible',
'note',
'os_version',
],
...expandForAppName,
});
device.status = device.overall_status;
device.dashboard_url = balena.models.device.getDashboardUrl(device.uuid);
const belongsToApplication = device.belongs_to__application as Application[];
device.application_name = belongsToApplication?.[0]
? belongsToApplication[0].app_name
: 'N/a';
device.commit = device.is_on__commit;
device.last_seen = device.last_connectivity_event;
console.log(
getVisuals().table.vertical(device, [
`$${device.device_name}$`,
'id',
'device_type',
'status',
'is_online',
'ip_address',
'mac_address',
'application_name',
'last_seen',
'uuid',
'commit',
'supervisor_version',
'is_web_accessible',
'note',
'os_version',
'dashboard_url',
]),
);
}
}

View File

@ -1,128 +0,0 @@
/**
* @license
* Copyright 2016-2020 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { flags } from '@oclif/command';
import type { IArg } from '@oclif/parser/lib/args';
import type { Application, Device } from 'balena-sdk';
import Command from '../../command';
import * as cf from '../../utils/common-flags';
import { expandForAppName } from '../../utils/helpers';
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
import { tryAsInteger } from '../../utils/validation';
interface ExtendedDevice extends Device {
application_name?: string;
}
interface FlagsDef {
application?: string;
app?: string;
help: void;
}
interface ArgsDef {
uuid: string;
}
export default class DeviceMoveCmd extends Command {
public static description = stripIndent`
Move a device to another application.
Move a device to another application.
Note, if the application option is omitted it will be prompted
for interactively.
`;
public static examples = [
'$ balena device move 7cf02a6',
'$ balena device move 7cf02a6 --application MyNewApp',
];
public static args: Array<IArg<any>> = [
{
name: 'uuid',
description: 'the uuid of the device to move',
parse: (dev) => tryAsInteger(dev),
required: true,
},
];
public static usage = 'device move <uuid>';
public static flags: flags.Input<FlagsDef> = {
application: cf.application,
app: cf.app,
help: cf.help,
};
public static authenticated = true;
public async run() {
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
DeviceMoveCmd,
);
const balena = getBalenaSdk();
// Consolidate application options
options.application = options.application || options.app;
delete options.app;
const device: ExtendedDevice = await balena.models.device.get(
params.uuid,
expandForAppName,
);
const belongsToApplication = device.belongs_to__application as Application[];
device.application_name = belongsToApplication?.[0]
? belongsToApplication[0].app_name
: 'N/a';
// Get destination application
let application;
if (options.application) {
application = options.application;
} else {
const [deviceDeviceType, deviceTypes] = await Promise.all([
balena.models.device.getManifestBySlug(device.device_type),
balena.models.config.getDeviceTypes(),
]);
const compatibleDeviceTypes = deviceTypes.filter(
(dt) =>
balena.models.os.isArchitectureCompatibleWith(
deviceDeviceType.arch,
dt.arch,
) &&
!!dt.isDependent === !!deviceDeviceType.isDependent &&
dt.state !== 'DISCONTINUED',
);
const patterns = await import('../../utils/patterns');
application = await patterns.selectApplication(
(app: Application) =>
compatibleDeviceTypes.some((dt) => dt.slug === app.device_type) &&
// @ts-ignore using the extended device object prop
device.application_name !== app.app_name,
);
}
await balena.models.device.move(params.uuid, tryAsInteger(application));
console.info(`${params.uuid} was moved to ${application}`);
}
}

View File

@ -1,145 +0,0 @@
/**
* @license
* Copyright 2016-2020 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { flags } from '@oclif/command';
import type { IArg } from '@oclif/parser/lib/args';
import Command from '../../command';
import * as cf from '../../utils/common-flags';
import { getBalenaSdk, stripIndent, getCliForm } from '../../utils/lazy';
import { tryAsInteger } from '../../utils/validation';
import type { Device } from 'balena-sdk';
import { ExpectedError } from '../../errors';
interface FlagsDef {
version?: string;
yes: boolean;
help: void;
}
interface ArgsDef {
uuid: string;
}
export default class DeviceOsUpdateCmd extends Command {
public static description = stripIndent`
Start a Host OS update for a device.
Start a Host OS update for a device.
Note this command will ask for confirmation interactively.
This can be avoided by passing the \`--yes\` option.
Requires balenaCloud; will not work with openBalena or standalone balenaOS.
`;
public static examples = [
'$ balena device os-update 23c73a1',
'$ balena device os-update 23c73a1 --version 2.31.0+rev1.prod',
];
public static args: Array<IArg<any>> = [
{
name: 'uuid',
description: 'the uuid of the device to update',
parse: (dev) => tryAsInteger(dev),
required: true,
},
];
public static usage = 'device os-update <uuid>';
public static flags: flags.Input<FlagsDef> = {
version: flags.string({
description: 'a balenaOS version',
}),
yes: cf.yes,
help: cf.help,
};
public static authenticated = true;
public async run() {
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
DeviceOsUpdateCmd,
);
const sdk = getBalenaSdk();
// Get device info
const {
uuid,
device_type,
os_version,
os_variant,
} = await sdk.models.device.get(params.uuid, {
$select: ['uuid', 'device_type', 'os_version', 'os_variant'],
});
// Get current device OS version
const currentOsVersion = sdk.models.device.getOsVersion({
os_version,
os_variant,
} as Device);
if (!currentOsVersion) {
throw new ExpectedError(
'The current os version of the device is not available',
);
}
// Get supported OS update versions
const hupVersionInfo = await sdk.models.os.getSupportedOsUpdateVersions(
device_type,
currentOsVersion,
);
if (hupVersionInfo.versions.length === 0) {
throw new ExpectedError(
'There are no available Host OS update targets for this device',
);
}
// Get target OS version
let targetOsVersion = options.version;
if (targetOsVersion != null) {
if (!hupVersionInfo.versions.includes(targetOsVersion)) {
throw new ExpectedError(
`The provided version ${targetOsVersion} is not in the Host OS update targets for this device`,
);
}
} else {
targetOsVersion = await getCliForm().ask({
message: 'Target OS version',
type: 'list',
choices: hupVersionInfo.versions.map((version) => ({
name:
hupVersionInfo.recommended === version
? `${version} (recommended)`
: version,
value: version,
})),
});
}
const patterns = await import('../../utils/patterns');
// Confirm and start update
await patterns.confirm(
options.yes || false,
'Host OS updates require a device restart when they complete. Are you sure you want to proceed?',
);
await sdk.models.device.startOsUpdate(uuid, targetOsVersion);
await patterns.awaitDeviceOsUpdate(uuid, targetOsVersion);
}
}

View File

@ -1,82 +0,0 @@
/**
* @license
* Copyright 2016-2020 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { flags } from '@oclif/command';
import type { IArg } from '@oclif/parser/lib/args';
import Command from '../../command';
import * as cf from '../../utils/common-flags';
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
import { tryAsInteger } from '../../utils/validation';
interface FlagsDef {
uuid?: string;
help: void;
}
interface ArgsDef {
application: string;
}
export default class DeviceRegisterCmd extends Command {
public static description = stripIndent`
Register a device.
Register a device to an application.
`;
public static examples = [
'$ balena device register MyApp',
'$ balena device register MyApp --uuid <uuid>',
];
public static args: Array<IArg<any>> = [
{
name: 'application',
description: 'the name or id of application to register device with',
parse: (app) => tryAsInteger(app),
required: true,
},
];
public static usage = 'device register <application>';
public static flags: flags.Input<FlagsDef> = {
uuid: flags.string({
description: 'custom uuid',
char: 'u',
}),
help: cf.help,
};
public static authenticated = true;
public async run() {
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
DeviceRegisterCmd,
);
const balena = getBalenaSdk();
const application = await balena.models.application.get(params.application);
const uuid = options.uuid ?? balena.models.device.generateUniqueKey();
console.info(`Registering to ${application.app_name}: ${uuid}`);
const result = await balena.models.device.register(application.id, uuid);
return result && result.uuid;
}
}

View File

@ -1,111 +0,0 @@
/**
* @license
* Copyright 2016-2020 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { flags } from '@oclif/command';
import Command from '../../command';
import * as cf from '../../utils/common-flags';
import { expandForAppName } from '../../utils/helpers';
import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy';
import { tryAsInteger } from '../../utils/validation';
import type { Device, Application } from 'balena-sdk';
interface ExtendedDevice extends Device {
dashboard_url?: string;
application_name?: string;
}
interface FlagsDef {
application?: string;
app?: string;
help: void;
}
export default class DevicesCmd extends Command {
public static description = stripIndent`
List all devices.
list all devices that belong to you.
You can filter the devices by application by using the \`--application\` option.
`;
public static examples = [
'$ balena devices',
'$ balena devices --application MyApp',
'$ balena devices --app MyApp',
'$ balena devices -a MyApp',
];
public static usage = 'devices';
public static flags: flags.Input<FlagsDef> = {
application: cf.application,
app: cf.app,
help: cf.help,
};
public static primary = true;
public static authenticated = true;
public async run() {
const { flags: options } = this.parse<FlagsDef, {}>(DevicesCmd);
const balena = getBalenaSdk();
// Consolidate application options
options.application = options.application || options.app;
delete options.app;
let devices: ExtendedDevice[];
if (options.application != null) {
devices = await balena.models.device.getAllByApplication(
tryAsInteger(options.application),
expandForAppName,
);
} else {
devices = await balena.models.device.getAll(expandForAppName);
}
devices = devices.map(function (device) {
device.dashboard_url = balena.models.device.getDashboardUrl(device.uuid);
const belongsToApplication = device.belongs_to__application as Application[];
device.application_name = belongsToApplication?.[0]
? belongsToApplication[0].app_name
: 'N/a';
device.uuid = device.uuid.slice(0, 7);
return device;
});
console.log(
getVisuals().table.horizontal(devices, [
'id',
'uuid',
'device_name',
'device_type',
'application_name',
'status',
'is_online',
'supervisor_version',
'os_version',
'dashboard_url',
]),
);
}
}

View File

@ -1,116 +0,0 @@
/**
* @license
* Copyright 2016-2019 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { flags } from '@oclif/command';
import type * as SDK from 'balena-sdk';
import * as _ from 'lodash';
import Command from '../../command';
import * as cf from '../../utils/common-flags';
import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy';
import { CommandHelp } from '../../utils/oclif-utils';
import { isV12 } from '../../utils/version';
interface FlagsDef {
discontinued: boolean;
help: void;
json?: boolean;
verbose?: boolean;
}
export default class DevicesSupportedCmd extends Command {
public static description = stripIndent`
List the supported device types (like 'raspberrypi3' or 'intel-nuc').
List the supported device types (like 'raspberrypi3' or 'intel-nuc').
The --verbose option adds extra columns/fields to the output, including the
"STATE" column whose values are one of 'beta', 'released' or 'discontinued'.
However, 'discontinued' device types are only listed if the '--discontinued'
option is used.
The --json option is recommended when scripting the output of this command,
because the JSON format is less likely to change and it better represents data
types like lists and empty strings (for example, the ALIASES column contains a
list of zero or more values). The 'jq' utility may be helpful in shell scripts
(https://stedolan.github.io/jq/manual/).
`;
public static examples = [
'$ balena devices supported',
'$ balena devices supported --verbose',
'$ balena devices supported -vj',
];
public static usage = (
'devices supported ' +
new CommandHelp({ args: DevicesSupportedCmd.args }).defaultUsage()
).trim();
public static flags: flags.Input<FlagsDef> = {
discontinued: flags.boolean({
description: 'include "discontinued" device types',
}),
help: cf.help,
json: flags.boolean({
char: 'j',
description: 'produce JSON output instead of tabular output',
}),
verbose: flags.boolean({
char: 'v',
description:
'add extra columns in the tabular output (ALIASES, ARCH, STATE)',
}),
};
public async run() {
const { flags: options } = this.parse<FlagsDef, {}>(DevicesSupportedCmd);
let deviceTypes: Array<Partial<SDK.DeviceType>> = await getBalenaSdk()
.models.config.getDeviceTypes()
.map((d) => {
if (d.aliases && d.aliases.length) {
// remove aliases that are equal to the slug
d.aliases = d.aliases.filter((alias: string) => alias !== d.slug);
if (!options.json) {
// stringify the aliases array with commas and spaces
d.aliases = [d.aliases.join(', ')];
}
} else {
// ensure it is always an array (for the benefit of JSON output)
d.aliases = [];
}
return d;
});
if (!options.discontinued) {
deviceTypes = deviceTypes.filter((dt) => dt.state !== 'DISCONTINUED');
}
const fields = options.verbose
? ['slug', 'aliases', 'arch', 'state', 'name']
: isV12()
? ['slug', 'aliases', 'arch', 'name']
: ['slug', 'name'];
deviceTypes = _.sortBy(
deviceTypes.map((d) => _.pick(d, fields) as Partial<SDK.DeviceType>),
fields,
);
if (options.json) {
console.log(JSON.stringify(deviceTypes, null, 4));
} else {
const visuals = getVisuals();
const output = await visuals.table.horizontal(deviceTypes, fields);
console.log(output);
}
}
}

View File

@ -1,239 +0,0 @@
/**
* @license
* Copyright 2019 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { flags } from '@oclif/command';
import type * as BalenaSdk from 'balena-sdk';
import Command from '../../command';
import { ExpectedError } from '../../errors';
import * as cf from '../../utils/common-flags';
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
import { CommandHelp } from '../../utils/oclif-utils';
interface FlagsDef {
application?: string; // application name
device?: string; // device UUID
help: void;
quiet: boolean;
service?: string; // service name
}
interface ArgsDef {
name: string;
value?: string;
}
export default class EnvAddCmd extends Command {
public static description = stripIndent`
Add an environment or config variable to an application, device or service.
Add an environment or config variable to an application, device or service,
as selected by the respective command-line options. Either the --application
or the --device option must be provided, and either may be be used alongside
the --service option to define a service-specific variable. (A service is an
application container in a "microservices" application.) When the --service
option is used in conjunction with the --device option, the service variable
applies to the selected device only. Otherwise, it applies to all devices of
the selected application (i.e., the application's fleet). If the --service
option is omitted, the variable applies to all services.
If VALUE is omitted, the CLI will attempt to use the value of the environment
variable of same name in the CLI process' environment. In this case, a warning
message will be printed. Use \`--quiet\` to suppress it.
'BALENA_' or 'RESIN_' are reserved variable name prefixes used to identify
"configuration variables". Configuration variables control balena platform
features and are treated specially by balenaOS and the balena supervisor
running on devices. They are also stored differently in the balenaCloud API
database. Configuration variables cannot be set for specific services,
therefore the --service option cannot be used when the variable name starts
with a reserved prefix. When defining custom application variables, please
avoid the reserved prefixes.
`;
public static examples = [
'$ balena env add TERM --application MyApp',
'$ balena env add EDITOR vim --application MyApp',
'$ balena env add EDITOR vim --application MyApp --service MyService',
'$ balena env add EDITOR vim --device 7cf02a6',
'$ balena env add EDITOR vim --device 7cf02a6 --service MyService',
];
public static args = [
{
name: 'name',
required: true,
description: 'environment or config variable name',
},
{
name: 'value',
required: false,
description:
"variable value; if omitted, use value from this process' environment",
},
];
// hardcoded 'env add' to avoid oclif's 'env:add' topic syntax
public static usage =
'env add ' + new CommandHelp({ args: EnvAddCmd.args }).defaultUsage();
public static flags: flags.Input<FlagsDef> = {
application: { exclusive: ['device'], ...cf.application },
device: { exclusive: ['application'], ...cf.device },
help: cf.help,
quiet: cf.quiet,
service: cf.service,
};
public async run() {
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
EnvAddCmd,
);
const cmd = this;
if (!options.application && !options.device) {
throw new ExpectedError(
'Either the --application or the --device option must always be used',
);
}
await Command.checkLoggedIn();
if (params.value == null) {
params.value = process.env[params.name];
if (params.value == null) {
throw new ExpectedError(
`Value not found for environment variable: ${params.name}`,
);
} else if (!options.quiet) {
cmd.warn(
`Using ${params.name}=${params.value} from CLI process environment`,
);
}
}
const balena = getBalenaSdk();
const reservedPrefixes = await getReservedPrefixes(balena);
const isConfigVar = reservedPrefixes.some((prefix) =>
params.name.startsWith(prefix),
);
if (options.service) {
if (isConfigVar) {
throw new ExpectedError(stripIndent`
Configuration variables prefixed with "${reservedPrefixes.join(
'" or "',
)}" cannot be set per service.
Hint: remove the --service option or rename the variable.
`);
}
await setServiceVars(balena, params, options);
return;
}
const varType = isConfigVar ? 'configVar' : 'envVar';
if (options.application) {
await balena.models.application[varType].set(
options.application,
params.name,
params.value,
);
} else if (options.device) {
await balena.models.device[varType].set(
options.device,
params.name,
params.value,
);
}
}
}
/**
* Add service variables for a device or application.
*/
async function setServiceVars(
sdk: BalenaSdk.BalenaSDK,
params: ArgsDef,
options: FlagsDef,
) {
if (options.application) {
const serviceId = await getServiceIdForApp(
sdk,
options.application,
options.service!,
);
await sdk.models.service.var.set(serviceId, params.name, params.value!);
} else {
const { getDeviceAndAppFromUUID } = await import('../../utils/cloud');
const [device, app] = await getDeviceAndAppFromUUID(
sdk,
options.device!,
['id'],
['app_name'],
);
const serviceId = await getServiceIdForApp(
sdk,
app.app_name,
options.service!,
);
await sdk.models.device.serviceVar.set(
device.id,
serviceId,
params.name,
params.value!,
);
}
}
/**
* Return a sevice ID for the given app name and service name.
*/
async function getServiceIdForApp(
sdk: BalenaSdk.BalenaSDK,
appName: string,
serviceName: string,
): Promise<number> {
let serviceId: number | undefined;
const services = await sdk.models.service.getAllByApplication(appName, {
$filter: { service_name: serviceName },
});
if (services.length > 0) {
serviceId = services[0].id;
}
if (serviceId === undefined) {
throw new ExpectedError(
`Cannot find service ${serviceName} for application ${appName}`,
);
}
return serviceId;
}
/**
* Return an array of variable name prefixes like: [ 'RESIN_', 'BALENA_' ].
* These prefixes can be used to identify "configuration variables".
*/
async function getReservedPrefixes(
balena: BalenaSdk.BalenaSDK,
): Promise<string[]> {
const settings = await balena.settings.getAll();
const response = await balena.request.send({
baseUrl: settings.apiUrl,
url: '/config/vars',
});
return response.body.reservedNamespaces;
}

View File

@ -1,442 +0,0 @@
/**
* @license
* Copyright 2016-2019 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { flags } from '@oclif/command';
import type * as SDK from 'balena-sdk';
import * as _ from 'lodash';
import Command from '../command';
import { ExpectedError } from '../errors';
import * as cf from '../utils/common-flags';
import { getBalenaSdk, getVisuals, stripIndent } from '../utils/lazy';
import { CommandHelp } from '../utils/oclif-utils';
import { isV12 } from '../utils/version';
interface FlagsDef {
all?: boolean; // whether to include application-wide, device-wide variables //TODO: REMOVE
application?: string; // application name
config: boolean;
device?: string; // device UUID
json: boolean;
help: void;
service?: string; // service name
verbose: boolean;
}
interface EnvironmentVariableInfo extends SDK.EnvironmentVariableBase {
appName?: string | null; // application name
deviceUUID?: string; // device UUID
serviceName?: string; // service name
}
interface DeviceServiceEnvironmentVariableInfo
extends SDK.DeviceServiceEnvironmentVariable {
appName?: string; // application name
deviceUUID?: string; // device UUID
serviceName?: string; // service name
}
interface ServiceEnvironmentVariableInfo
extends SDK.ServiceEnvironmentVariable {
appName?: string; // application name
deviceUUID?: string; // device UUID
serviceName?: string; // service name
}
export default class EnvsCmd extends Command {
public static description = isV12()
? stripIndent`
List the environment or config variables of an application, device or service.
List the environment or configuration variables of an application, device or
service, as selected by the respective command-line options. (A service is
an application container in a "microservices" application.)
The results include application-wide (fleet), device-wide (multiple services on
a device) and service-specific variables that apply to the selected application,
device or service. It can be thought of as including "inherited" variables;
for example, a service inherits device-wide variables, and a device inherits
application-wide variables.
The printed output may include DEVICE and/or SERVICE columns to distinguish
between application-wide, device-specific and service-specific variables.
An asterisk in these columns indicates that the variable applies to
"all devices" or "all services".
The --config option is used to list "configuration variables" that control
balena platform features, as opposed to custom environment variables defined
by the user. The --config and the --service options are mutually exclusive
because configuration variables cannot be set for specific services.
The --json option is recommended when scripting the output of this command,
because the JSON format is less likely to change and it better represents data
types like lists and empty strings. The 'jq' utility may be helpful in shell
scripts (https://stedolan.github.io/jq/manual/). When --json is used, an empty
JSON array ([]) is printed instead of an error message when no variables exist
for the given query. When querying variables for a device, note that the
application name may be null in JSON output (or 'N/A' in tabular output) if the
application linked to the device is no longer accessible by the current user
(for example, in case the current user has been removed from the application
by its owner).
`
: stripIndent`
List the environment or config variables of an application, device or service.
List the environment or configuration variables of an application, device or
service, as selected by the respective command-line options. (A service is
an application container in a "microservices" application.)
The --config option is used to list "configuration variables" that control
balena platform features, as opposed to custom environment variables defined
by the user. The --config and the --service options are mutually exclusive
because configuration variables cannot be set for specific services.
The --all option is used to include application-wide (fleet), device-wide
(multiple services on a device) and service-specific variables that apply to
the selected application, device or service. It can be thought of as including
"inherited" variables: for example, a service inherits device-wide variables,
and a device inherits application-wide variables. Variables are still filtered
out by type with the --config option, such that configuration and non-
configuration variables are never listed together.
When the --all option is used, the printed output may include DEVICE and/or
SERVICE columns to distinguish between application-wide, device-specific and
service-specific variables. An asterisk in these columns indicates that the
variable applies to "all devices" or "all services".
The --json option is recommended when scripting the output of this command,
because the JSON format is less likely to change and it better represents data
types like lists and empty strings. The 'jq' utility may be helpful in shell
scripts (https://stedolan.github.io/jq/manual/). When --json is used, an empty
JSON array ([]) is printed instead of an error message when no variables exist
for the given query. When querying variables for a device, note that the
application name may be null in JSON output (or 'N/A' in tabular output) if the
application linked to the device is no longer accessible by the current user
(for example, in case the current user has been removed from the application
by its owner).
`;
public static examples = isV12()
? [
'$ balena envs --application MyApp',
'$ balena envs --application MyApp --json',
'$ balena envs --application MyApp --service MyService',
'$ balena envs --application MyApp --service MyService',
'$ balena envs --application MyApp --config',
'$ balena envs --device 7cf02a6',
'$ balena envs --device 7cf02a6 --json',
'$ balena envs --device 7cf02a6 --config --json',
'$ balena envs --device 7cf02a6 --service MyService',
]
: [
'$ balena envs --application MyApp',
'$ balena envs --application MyApp --all --json',
'$ balena envs --application MyApp --service MyService',
'$ balena envs --application MyApp --all --service MyService',
'$ balena envs --application MyApp --config',
'$ balena envs --device 7cf02a6',
'$ balena envs --device 7cf02a6 --all --json',
'$ balena envs --device 7cf02a6 --config --all --json',
'$ balena envs --device 7cf02a6 --all --service MyService',
];
public static usage = (
'envs ' + new CommandHelp({ args: EnvsCmd.args }).defaultUsage()
).trim();
public static flags: flags.Input<FlagsDef> = {
...(isV12()
? {
all: flags.boolean({
description: stripIndent`
No-op since balena CLI v12.0.0.`,
hidden: true,
}),
}
: {
all: flags.boolean({
description: stripIndent`
include app-wide, device-wide variables that apply to the selected device or service.
Variables are still filtered out by type with the --config option.`,
}),
}),
application: { exclusive: ['device'], ...cf.application },
config: flags.boolean({
char: 'c',
description: 'show configuration variables only',
exclusive: ['service'],
}),
device: { exclusive: ['application'], ...cf.device },
help: cf.help,
json: flags.boolean({
char: 'j',
description: 'produce JSON output instead of tabular output',
}),
verbose: cf.verbose,
service: { exclusive: ['config'], ...cf.service },
};
public async run() {
const { flags: options } = this.parse<FlagsDef, {}>(EnvsCmd);
const variables: EnvironmentVariableInfo[] = [];
options.all = options.all || isV12();
await Command.checkLoggedIn();
if (!options.application && !options.device) {
throw new ExpectedError('You must specify an application or device');
}
const balena = getBalenaSdk();
let appName = options.application;
let fullUUID: string | undefined; // as oppposed to the short, 7-char UUID
if (options.device) {
const { getDeviceAndMaybeAppFromUUID } = await import('../utils/cloud');
const [device, app] = await getDeviceAndMaybeAppFromUUID(
balena,
options.device,
['uuid'],
['app_name'],
);
fullUUID = device.uuid;
if (app) {
appName = app.app_name;
}
}
if (appName && options.service) {
await validateServiceName(balena, options.service, appName);
}
if (options.application || options.all) {
variables.push(...(await getAppVars(balena, appName, options)));
}
if (fullUUID) {
variables.push(
...(await getDeviceVars(balena, fullUUID, appName, options)),
);
}
if (!options.json && variables.length === 0) {
const target =
(options.service ? `service "${options.service}" of ` : '') +
(options.application
? `application "${options.application}"`
: `device "${options.device}"`);
throw new ExpectedError(`No environment variables found for ${target}`);
}
await this.printVariables(variables, options);
}
protected async printVariables(
varArray: EnvironmentVariableInfo[],
options: FlagsDef,
) {
const fields = ['id', 'name', 'value'];
if (options.all) {
// Replace undefined app names with 'N/A' or null
varArray = varArray.map((i: EnvironmentVariableInfo) => {
i.appName = i.appName || (options.json ? null : 'N/A');
return i;
});
fields.push(options.json ? 'appName' : 'appName => APPLICATION');
if (options.device) {
fields.push(options.json ? 'deviceUUID' : 'deviceUUID => DEVICE');
}
if (!options.config) {
fields.push(options.json ? 'serviceName' : 'serviceName => SERVICE');
}
}
if (options.json) {
this.log(
stringifyVarArray<SDK.EnvironmentVariableBase>(varArray, fields),
);
} else {
this.log(
getVisuals().table.horizontal(
_.sortBy(varArray, (v: SDK.EnvironmentVariableBase) => v.name),
fields,
),
);
}
}
}
async function validateServiceName(
sdk: SDK.BalenaSDK,
serviceName: string,
appName: string,
) {
const services = await sdk.models.service.getAllByApplication(appName, {
$filter: { service_name: serviceName },
});
if (services.length === 0) {
throw new ExpectedError(
`Service "${serviceName}" not found for application "${appName}"`,
);
}
}
/**
* Fetch application-wide config / env / service vars.
* If options.application is undefined, an attempt is made to obtain the
* application name from the device UUID (options.device). If this attempt
* fails because the device does not belong to any application, an emtpy
* array is returned.
*/
async function getAppVars(
sdk: SDK.BalenaSDK,
appName: string | undefined,
options: FlagsDef,
): Promise<EnvironmentVariableInfo[]> {
const appVars: EnvironmentVariableInfo[] = [];
if (!appName) {
return appVars;
}
if (options.config || options.all || !options.service) {
const vars = await sdk.models.application[
options.config ? 'configVar' : 'envVar'
].getAllByApplication(appName);
fillInInfoFields(vars, appName);
appVars.push(...vars);
}
if (!options.config && (options.service || options.all)) {
const pineOpts: SDK.PineOptionsFor<SDK.ServiceEnvironmentVariable> = {
$expand: {
service: {},
},
};
if (options.service) {
pineOpts.$filter = {
service: {
service_name: options.service,
},
};
}
const serviceVars = await sdk.models.service.var.getAllByApplication(
appName,
pineOpts,
);
fillInInfoFields(serviceVars, appName);
appVars.push(...serviceVars);
}
return appVars;
}
/**
* Fetch config / env / service vars when the '--device' option is provided.
* Precondition: options.device must be defined.
*/
async function getDeviceVars(
sdk: SDK.BalenaSDK,
fullUUID: string,
appName: string | undefined,
options: FlagsDef,
): Promise<EnvironmentVariableInfo[]> {
const printedUUID = options.json ? fullUUID : options.device!;
const deviceVars: EnvironmentVariableInfo[] = [];
if (options.config) {
const deviceConfigVars = await sdk.models.device.configVar.getAllByDevice(
fullUUID,
);
fillInInfoFields(deviceConfigVars, appName, printedUUID);
deviceVars.push(...deviceConfigVars);
} else {
if (options.service || options.all) {
const pineOpts: SDK.PineOptionsFor<SDK.DeviceServiceEnvironmentVariable> = {
$expand: {
service_install: {
$expand: 'installs__service',
},
},
};
if (options.service) {
pineOpts.$filter = {
service_install: {
installs__service: { service_name: options.service },
},
};
}
const deviceServiceVars = await sdk.models.device.serviceVar.getAllByDevice(
fullUUID,
pineOpts,
);
fillInInfoFields(deviceServiceVars, appName, printedUUID);
deviceVars.push(...deviceServiceVars);
}
if (!options.service || options.all) {
const deviceEnvVars = await sdk.models.device.envVar.getAllByDevice(
fullUUID,
);
fillInInfoFields(deviceEnvVars, appName, printedUUID);
deviceVars.push(...deviceEnvVars);
}
}
return deviceVars;
}
/**
* For each env var object in varArray, fill in its top-level serviceName
* and deviceUUID fields. An asterisk is used to indicate that the variable
* applies to "all services" or "all devices".
*/
function fillInInfoFields(
varArray:
| EnvironmentVariableInfo[]
| DeviceServiceEnvironmentVariableInfo[]
| ServiceEnvironmentVariableInfo[],
appName?: string,
deviceUUID?: string,
) {
for (const envVar of varArray) {
if ('service' in envVar) {
// envVar is of type ServiceEnvironmentVariableInfo
envVar.serviceName = (envVar.service as SDK.Service[])[0]?.service_name;
} else if ('service_install' in envVar) {
// envVar is of type DeviceServiceEnvironmentVariableInfo
envVar.serviceName = ((envVar.service_install as SDK.ServiceInstall[])[0]
?.installs__service as SDK.Service[])[0]?.service_name;
}
envVar.appName = appName;
envVar.serviceName = envVar.serviceName || '*';
envVar.deviceUUID = deviceUUID || '*';
}
}
/**
* Transform each object (item) of varArray to preserve only the
* fields (keys) listed in the fields argument.
*/
function stringifyVarArray<T = Dictionary<any>>(
varArray: T[],
fields: string[],
): string {
const transformed = varArray.map((o: Dictionary<any>) =>
_.transform(
o,
(result, value, key) => {
if (fields.includes(key)) {
result[key] = value;
}
},
{} as Dictionary<any>,
),
);
return JSON.stringify(transformed, null, 4);
}

View File

@ -1,46 +0,0 @@
/**
* @license
* Copyright 2016-2020 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import Command from '../../command';
import { stripIndent } from '../../utils/lazy';
// 'Internal' commands are called during the execution of other commands.
// `scandevices` is called during by `join`,`leave'.
// TODO: These should be refactored to modules/functions, and removed
// See previous `internal sudo` refactor:
// - https://github.com/balena-io/balena-cli/pull/1455/files
// - https://github.com/balena-io/balena-cli/pull/1455#discussion_r334308357
// - https://github.com/balena-io/balena-cli/pull/1455#discussion_r334308526
export default class ScandevicesCmd extends Command {
public static description = stripIndent`
Scan for local balena-enabled devices and show a picker to choose one.
Don't use this command directly!
`;
public static usage = 'internal scandevices';
public static root = true;
public static hidden = true;
public async run() {
const { forms } = await import('balena-sync');
const hostnameOrIp = await forms.selectLocalBalenaOsDevice();
return console.error(`==> Selected device: ${hostnameOrIp}`);
}
}

View File

@ -1,85 +0,0 @@
/**
* @license
* Copyright 2016-2020 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { flags } from '@oclif/command';
import Command from '../../command';
import { ExpectedError } from '../../errors';
import * as cf from '../../utils/common-flags';
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
interface FlagsDef {
help: void;
}
interface ArgsDef {
name: string;
path: string;
}
export default class KeyAddCmd extends Command {
public static description = stripIndent`
Add an SSH key to balenaCloud.
Register an SSH in balenaCloud for the logged in user.
If \`path\` is omitted, the command will attempt
to read the SSH key from stdin.
`;
public static examples = [
'$ balena key add Main ~/.ssh/id_rsa.pub',
'$ cat ~/.ssh/id_rsa.pub | balena key add Main',
];
public static args = [
{
name: 'name',
description: 'the SSH key name',
required: true,
},
{
name: `path`,
description: `the path to the public key file`,
},
];
public static usage = 'key add <name> [path]';
public static flags: flags.Input<FlagsDef> = {
help: cf.help,
};
public static authenticated = true;
public static readStdin = true;
public async run() {
const { args: params } = this.parse<FlagsDef, ArgsDef>(KeyAddCmd);
let key: string;
if (params.path != null) {
const { readFile } = (await import('fs')).promises;
key = await readFile(params.path, 'utf8');
} else if (this.stdin.length > 0) {
key = this.stdin;
} else {
throw new ExpectedError('No public key file or path provided.');
}
await getBalenaSdk().models.key.create(params.name, key);
}
}

View File

@ -1,172 +0,0 @@
/**
* @license
* Copyright 2020 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { flags } from '@oclif/command';
import type { LocalBalenaOsDevice } from 'balena-sync';
import Command from '../command';
import * as cf from '../utils/common-flags';
import { getVisuals, stripIndent } from '../utils/lazy';
interface FlagsDef {
verbose: boolean;
timeout?: number;
help: void;
}
export default class ScanCmd extends Command {
public static description = stripIndent`
Scan for balenaOS devices on your local network.
Scan for balenaOS devices on your local network.
`;
public static examples = [
'$ balena scan',
'$ balena scan --timeout 120',
'$ balena scan --verbose',
];
public static usage = 'scan';
public static flags: flags.Input<FlagsDef> = {
verbose: flags.boolean({
char: 'v',
default: false,
description: 'display full info',
}),
timeout: flags.integer({
char: 't',
description: 'scan timeout in seconds',
}),
help: cf.help,
};
public static primary = true;
public static root = true;
public async run() {
const Bluebird = await import('bluebird');
const _ = await import('lodash');
const { SpinnerPromise } = getVisuals();
const { discover } = await import('balena-sync');
const prettyjson = await import('prettyjson');
const { ExpectedError } = await import('../errors');
const { dockerPort, dockerTimeout } = await import(
'../actions/local/common'
);
const dockerUtils = await import('../utils/docker');
const { flags: options } = this.parse<FlagsDef, {}>(ScanCmd);
const discoverTimeout =
options.timeout != null ? options.timeout * 1000 : undefined;
// Find active local devices
const activeLocalDevices: LocalBalenaOsDevice[] = await new SpinnerPromise({
promise: discover.discoverLocalBalenaOsDevices(discoverTimeout),
startMessage: 'Scanning for local balenaOS devices..',
stopMessage: 'Reporting scan results',
}).filter(async ({ address }: { address: string }) => {
const docker = dockerUtils.createClient({
host: address,
port: dockerPort,
timeout: dockerTimeout,
}) as any;
try {
await docker.pingAsync();
return true;
} catch (err) {
return false;
}
});
// Exit with message if no devices found
if (_.isEmpty(activeLocalDevices)) {
// TODO: Consider whether this should really be an error
throw new ExpectedError(
process.platform === 'win32'
? ScanCmd.noDevicesFoundMessage + ScanCmd.windowsTipMessage
: ScanCmd.noDevicesFoundMessage,
);
}
// Query devices for info
const devicesInfo = await Promise.all(
activeLocalDevices.map(({ host, address }) => {
const docker = dockerUtils.createClient({
host: address,
port: dockerPort,
timeout: dockerTimeout,
}) as any;
return Bluebird.props({
host,
address,
dockerInfo: docker
.infoAsync()
.catchReturn('Could not get Docker info'),
dockerVersion: docker
.versionAsync()
.catchReturn('Could not get Docker version'),
});
}),
);
// Reduce properties if not --verbose
if (!options.verbose) {
devicesInfo.forEach((d: any) => {
d.dockerInfo = _.isObject(d.dockerInfo)
? _.pick(d.dockerInfo, ScanCmd.dockerInfoProperties)
: d.dockerInfo;
d.dockerVersion = _.isObject(d.dockerVersion)
? _.pick(d.dockerVersion, ScanCmd.dockerVersionProperties)
: d.dockerVersion;
});
}
// Output results
console.log(prettyjson.render(devicesInfo, { noColor: true }));
}
protected static dockerInfoProperties = [
'Containers',
'ContainersRunning',
'ContainersPaused',
'ContainersStopped',
'Images',
'Driver',
'SystemTime',
'KernelVersion',
'OperatingSystem',
'Architecture',
];
protected static dockerVersionProperties = ['Version', 'ApiVersion'];
protected static noDevicesFoundMessage =
'Could not find any balenaOS devices on the local network.';
protected static windowsTipMessage = `
Note for Windows users:
The 'scan' command relies on the Bonjour service. Check whether Bonjour is
installed (Control Panel > Programs and Features). If not, you can download
Bonjour for Windows (included with Bonjour Print Services) from here:
https://support.apple.com/kb/DL999
After installing Bonjour, restart your PC and run the 'balena scan' command
again.`;
}

View File

@ -1,393 +0,0 @@
/**
* @license
* Copyright 2016-2020 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { flags } from '@oclif/command';
import Command from '../command';
import * as cf from '../utils/common-flags';
import { getBalenaSdk, stripIndent } from '../utils/lazy';
import {
parseAsInteger,
validateDotLocalUrl,
validateIPAddress,
} from '../utils/validation';
import * as BalenaSdk from 'balena-sdk';
interface FlagsDef {
port?: number;
tty: boolean;
verbose: boolean;
noproxy: boolean;
help: void;
}
interface ArgsDef {
applicationOrDevice: string;
serviceName?: string;
}
export default class NoteCmd extends Command {
public static description = stripIndent`
SSH into the host or application container of a device.
Start a shell on a local or remote device. If a service name is not provided,
a shell will be opened on the host OS.
If an application name is provided, an interactive menu will be presented
for the selection of an online device. A shell will then be opened for the
host OS or service container of the chosen device.
For local devices, the IP address and .local domain name are supported.
If the device is referenced by IP or \`.local\` address, the connection
is initiated directly to balenaOS on port \`22222\` via an
openssh-compatible client. Otherwise, any connection initiated remotely
traverses the balenaCloud VPN.
Commands may be piped to the standard input for remote execution (see examples).
Note however that remote command execution on service containers (as opposed to
the host OS) is not currently possible when a device UUID is used (instead of
an IP address) because of a balenaCloud backend limitation.
Note: \`balena ssh\` requires an openssh-compatible client to be correctly
installed in your shell environment. For more information (including Windows
support) please check:
https://github.com/balena-io/balena-cli/blob/master/INSTALL.md#additional-dependencies,
`;
public static examples = [
'$ balena ssh MyApp',
'$ balena ssh f49cefd',
'$ balena ssh f49cefd my-service',
'$ balena ssh f49cefd --port <port>',
'$ balena ssh 192.168.0.1 --verbose',
'$ balena ssh f49cefd.local my-service',
'$ echo "uptime; exit;" | balena ssh f49cefd',
'$ echo "uptime; exit;" | balena ssh 192.168.0.1 myService',
];
public static args = [
{
name: 'applicationOrDevice',
description: 'application name, device uuid, or address of local device',
required: true,
},
{
name: 'serviceName',
description: 'service name, if connecting to a container',
required: false,
},
];
public static usage = 'ssh <applicationOrDevice> [serviceName]';
public static flags: flags.Input<FlagsDef> = {
port: flags.integer({
description: stripIndent`
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: (p) => parseAsInteger(p, 'port'),
}),
tty: flags.boolean({
description:
'Force pseudo-terminal allocation (bypass TTY autodetection for stdin)',
char: 't',
}),
verbose: flags.boolean({
description: 'Increase verbosity',
char: 'v',
}),
noproxy: flags.boolean({
description: 'Bypass global proxy configuration for the ssh connection',
}),
help: cf.help,
};
public static primary = true;
public async run() {
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
NoteCmd,
);
// if we're doing a direct SSH connection locally...
if (
validateDotLocalUrl(params.applicationOrDevice) ||
validateIPAddress(params.applicationOrDevice)
) {
const { performLocalDeviceSSH } = await import('../utils/device/ssh');
return await performLocalDeviceSSH({
address: params.applicationOrDevice,
port: options.port,
forceTTY: options.tty,
verbose: options.verbose,
service: params.serviceName,
});
}
const { getProxyConfig, which } = await import('../utils/helpers');
const { checkLoggedIn, getOnlineTargetUuid } = await import(
'../utils/patterns'
);
const sdk = getBalenaSdk();
const proxyConfig = getProxyConfig();
const useProxy = !!proxyConfig && !options.noproxy;
// this will be a tunnelled SSH connection...
await checkLoggedIn();
const uuid = await getOnlineTargetUuid(sdk, params.applicationOrDevice);
let version: string | undefined;
let id: number | undefined;
const device = await sdk.models.device.get(uuid, {
$select: ['id', 'supervisor_version', 'is_online'],
});
id = device.id;
version = device.supervisor_version;
const [whichProxytunnel, username, proxyUrl] = await Promise.all([
useProxy ? which('proxytunnel', false) : undefined,
sdk.auth.whoami(),
// note that `proxyUrl` refers to the balenaCloud "resin-proxy"
// service, currently "balena-devices.com", rather than some
// local proxy server URL
sdk.settings.get('proxyUrl'),
]);
const getSshProxyCommand = () => {
if (!proxyConfig) {
return;
}
if (!whichProxytunnel) {
console.warn(stripIndent`
Proxy is enabled but the \`proxytunnel\` binary cannot be found.
Please install it if you want to route the \`balena ssh\` requests through the proxy.
Alternatively you can pass \`--noproxy\` param to the \`balena ssh\` command to ignore the proxy config
for the \`ssh\` requests.
Attempting the unproxied request for now.`);
return;
}
const p = proxyConfig;
if (p.username && p.password) {
// proxytunnel understands these variables for proxy authentication.
// Setting the variables instead of command-line options avoids the
// need for shell-specific escaping of special characters like '$'.
process.env.PROXYUSER = p.username;
process.env.PROXYPASS = p.password;
}
return [
'proxytunnel',
`--proxy=${p.host}:${p.port}`,
// ssh replaces these %h:%p variables in the ProxyCommand option
// https://linux.die.net/man/5/ssh_config
'--dest=%h:%p',
...(options.verbose ? ['--verbose'] : []),
];
};
const proxyCommand = useProxy ? getSshProxyCommand() : undefined;
if (username == null) {
const { ExpectedError } = await import('../errors');
throw new ExpectedError(
`Opening an SSH connection to a remote device requires you to be logged in.`,
);
}
// At this point, we have a long uuid with a device
// that we know exists and is accessible
let containerId: string | undefined;
if (params.serviceName != null) {
containerId = await this.getContainerId(
sdk,
uuid,
params.serviceName,
{
port: options.port,
proxyCommand,
proxyUrl: proxyUrl || '',
username: username!,
},
version,
id,
);
}
let accessCommand: string;
if (containerId != null) {
accessCommand = `enter ${uuid} ${containerId}`;
} else {
accessCommand = `host ${uuid}`;
}
const command = this.generateVpnSshCommand({
uuid,
command: accessCommand,
verbose: options.verbose,
port: options.port,
proxyCommand,
proxyUrl: proxyUrl || '',
username: username!,
});
const { spawnSshAndThrowOnError } = await import('../utils/ssh');
return spawnSshAndThrowOnError(command);
}
async getContainerId(
sdk: BalenaSdk.BalenaSDK,
uuid: string,
serviceName: string,
sshOpts: {
port?: number;
proxyCommand?: string[];
proxyUrl: string;
username: string;
},
version?: string,
id?: number,
): Promise<string> {
const semver = await import('balena-semver');
if (version == null || id == null) {
const device = await sdk.models.device.get(uuid, {
$select: ['id', 'supervisor_version'],
});
version = device.supervisor_version;
id = device.id;
}
let containerId: string | undefined;
if (semver.gte(version, '8.6.0')) {
const apiUrl = await sdk.settings.get('apiUrl');
// TODO: Move this into the SDKs device model
const request = await sdk.request.send({
method: 'POST',
url: '/supervisor/v2/containerId',
baseUrl: apiUrl,
body: {
method: 'GET',
deviceId: id,
},
});
if (request.status !== 200) {
throw new Error(
`There was an error connecting to device ${uuid}, HTTP response code: ${request.status}.`,
);
}
const body = request.body;
if (body.status !== 'success') {
throw new Error(
`There was an error communicating with device ${uuid}.\n\tError: ${body.message}`,
);
}
containerId = body.services[serviceName];
} else {
console.error(stripIndent`
Using legacy method to detect container ID. This will be slow.
To speed up this process, please update your device to an OS
which has a supervisor version of at least v8.6.0.
`);
// We need to execute a balena ps command on the device,
// and parse the output, looking for a specific
// container
const childProcess = await import('child_process');
const { escapeRegExp } = await import('lodash');
const { which } = await import('../utils/helpers');
const { deviceContainerEngineBinary } = await import(
'../utils/device/ssh'
);
const sshBinary = await which('ssh');
const sshArgs = this.generateVpnSshCommand({
uuid,
verbose: false,
port: sshOpts.port,
command: `host ${uuid} "${deviceContainerEngineBinary}" ps --format "{{.ID}} {{.Names}}"`,
proxyCommand: sshOpts.proxyCommand,
proxyUrl: sshOpts.proxyUrl,
username: sshOpts.username,
});
if (process.env.DEBUG) {
console.error(`[debug] [${sshBinary}, ${sshArgs.join(', ')}]`);
}
const subProcess = childProcess.spawn(sshBinary, sshArgs, {
stdio: [null, 'pipe', null],
});
const containers = await new Promise<string>((resolve, reject) => {
const output: string[] = [];
subProcess.stdout.on('data', (chunk) => output.push(chunk.toString()));
subProcess.on('close', (code: number) => {
if (code !== 0) {
reject(
new Error(
`Non-zero error code when looking for service container: ${code}`,
),
);
} else {
resolve(output.join(''));
}
});
});
const lines = containers.split('\n');
const regex = new RegExp(`\\/?${escapeRegExp(serviceName)}_\\d+_\\d+`);
for (const container of lines) {
const [cId, name] = container.split(' ');
if (regex.test(name)) {
containerId = cId;
break;
}
}
}
if (containerId == null) {
throw new Error(
`Could not find a service ${serviceName} on device ${uuid}.`,
);
}
return containerId;
}
generateVpnSshCommand(opts: {
uuid: string;
command: string;
verbose: boolean;
port?: number;
username: string;
proxyUrl: string;
proxyCommand?: string[];
}) {
return [
...(opts.verbose ? ['-vvv'] : []),
'-t',
...['-o', 'LogLevel=ERROR'],
...['-o', 'StrictHostKeyChecking=no'],
...['-o', 'UserKnownHostsFile=/dev/null'],
...(opts.proxyCommand && opts.proxyCommand.length
? ['-o', `ProxyCommand=${opts.proxyCommand.join(' ')}`]
: []),
...(opts.port ? ['-p', opts.port.toString()] : []),
`${opts.username}@ssh.${opts.proxyUrl}`,
opts.command,
];
}
}

View File

@ -1,131 +0,0 @@
/**
* @license
* Copyright 2016-2020 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { flags } from '@oclif/command';
import Command from '../command';
import { ExpectedError } from '../errors';
import * as cf from '../utils/common-flags';
import { getBalenaSdk, getVisuals, stripIndent } from '../utils/lazy';
import { disambiguateReleaseParam } from '../utils/normalization';
import { tryAsInteger } from '../utils/validation';
import { isV12 } from '../utils/version';
interface FlagsDef {
application?: string;
device?: string;
release?: string;
help: void;
app?: string;
}
export default class TagsCmd extends Command {
public static description = stripIndent`
List all tags for an application, device or release.
List all tags and their values for a particular application,
device or release.
`;
public static examples = [
'$ balena tags --application MyApp',
'$ balena tags --device 7cf02a6',
'$ balena tags --release 1234',
'$ balena tags --release b376b0e544e9429483b656490e5b9443b4349bd6',
];
public static usage = 'tags';
public static flags: flags.Input<FlagsDef> = {
application: {
...cf.application,
exclusive: ['app', 'device', 'release'],
},
device: {
...cf.device,
exclusive: ['app', 'application', 'release'],
},
release: {
...cf.release,
exclusive: ['app', 'application', 'device'],
},
help: cf.help,
app: flags.string({
description: "same as '--application'",
exclusive: ['application', 'device', 'release'],
}),
};
public static authenticated = true;
public async run() {
const { flags: options } = this.parse<FlagsDef, {}>(TagsCmd);
// Prefer options.application over options.app
options.application = options.application || options.app;
delete options.app;
const balena = getBalenaSdk();
// Check user has specified one of application/device/release
if (!options.application && !options.device && !options.release) {
throw new ExpectedError(this.missingResourceMessage);
}
let tags;
if (options.application) {
tags = await balena.models.application.tags.getAllByApplication(
tryAsInteger(options.application),
);
}
if (options.device) {
tags = await balena.models.device.tags.getAllByDevice(
tryAsInteger(options.device),
);
}
if (options.release) {
const releaseParam = await disambiguateReleaseParam(
balena,
options.release,
);
tags = await balena.models.release.tags.getAllByRelease(releaseParam);
}
if (!tags || tags.length === 0) {
throw new ExpectedError('No tags found');
}
console.log(
isV12()
? getVisuals().table.horizontal(tags, ['tag_key', 'value'])
: getVisuals().table.horizontal(tags, ['id', 'tag_key', 'value']),
);
}
protected missingResourceMessage = stripIndent`
To list tags for a resource, you must provide exactly one of:
* An application, with --application <appname>
* A device, with --device <uuid>
* A release, with --release <id or commit>
See the help page for examples:
$ balena help tags
`;
}

View File

@ -1,206 +0,0 @@
/**
* @license
* Copyright 2016-2020 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as dockerUtils from '../utils/docker';
import * as compose from '../utils/compose';
import { dockerignoreHelp, registrySecretsHelp } from '../utils/messages';
import { getBalenaSdk } from '../utils/lazy';
/**
* Opts must be an object with the following keys:
* app: the app this build is for (optional)
* arch: the architecture to build for
* deviceType: the device type to build for
* buildEmulated
* buildOpts: arguments to forward to docker build command
*
* @param {import('docker-toolbelt')} docker
* @param {import('../utils/logger')} logger
* @param {import('../utils/compose-types').ComposeOpts} composeOpts
* @param {any} opts
*/
const buildProject = function (docker, logger, composeOpts, opts) {
const { loadProject } = require('../utils/compose_ts');
return loadProject(logger, composeOpts)
.then(function (project) {
const appType = opts.app?.application_type?.[0];
if (
appType != null &&
project.descriptors.length > 1 &&
!appType.supports_multicontainer
) {
logger.logWarn(
'Target application does not support multiple containers.\n' +
'Continuing with build, but you will not be able to deploy.',
);
}
return compose.buildProject(
docker,
logger,
project.path,
project.name,
project.composition,
opts.arch,
opts.deviceType,
opts.buildEmulated,
opts.buildOpts,
composeOpts.inlineLogs,
composeOpts.convertEol,
composeOpts.dockerfilePath,
composeOpts.nogitignore,
composeOpts.multiDockerignore,
);
})
.then(function () {
logger.outputDeferredMessages();
logger.logSuccess('Build succeeded!');
})
.catch((err) => {
logger.logError('Build failed');
throw err;
});
};
export const build = {
signature: 'build [source]',
description: 'Build a single image or a multicontainer project locally',
primary: true,
help: `\
Use this command to build an image or a complete multicontainer project with
the provided docker daemon in your development machine or balena device.
(See also the \`balena push\` command for the option of building images in the
balenaCloud build servers.)
You must provide either an application or a device-type/architecture pair to use
the balena Dockerfile pre-processor (e.g. Dockerfile.template -> Dockerfile).
This command will look into the given source directory (or the current working
directory if one isn't specified) for a docker-compose.yml file, and if found,
each service defined in the compose file will be built. If a compose file isn't
found, it will look for a Dockerfile[.template] file (or alternative Dockerfile
specified with the \`--dockerfile\` option), and if no dockerfile is found, it
will try to generate one.
${registrySecretsHelp}
${dockerignoreHelp}
Examples:
$ balena build
$ balena build ./source/
$ balena build --deviceType raspberrypi3 --arch armv7hf --emulated
$ balena build --application MyApp ./source/
$ balena build --docker /var/run/docker.sock # Linux, Mac
$ balena build --docker //./pipe/docker_engine # Windows
$ balena build --dockerHost my.docker.host --dockerPort 2376 --ca ca.pem --key key.pem --cert cert.pem\
`,
options: dockerUtils.appendOptions(
compose.appendOptions([
{
signature: 'arch',
parameter: 'arch',
description: 'The architecture to build for',
alias: 'A',
},
{
signature: 'deviceType',
parameter: 'deviceType',
description: 'The type of device this build is for',
alias: 'd',
},
{
signature: 'application',
parameter: 'application',
description: 'The target balena application this build is for',
alias: 'a',
},
]),
),
async action(params, options) {
// compositions with many services trigger misleading warnings
// @ts-ignore editing property that isn't typed but does exist
require('events').defaultMaxListeners = 1000;
const sdk = getBalenaSdk();
const { ExpectedError } = require('../errors');
const { checkLoggedIn } = require('../utils/patterns');
const { validateProjectDirectory } = require('../utils/compose_ts');
const helpers = require('../utils/helpers');
const Logger = require('../utils/logger');
const logger = Logger.getLogger();
logger.logDebug('Parsing input...');
// `build` accepts `[source]` as a parameter, but compose expects it
// as an option. swap them here
if (options.source == null) {
options.source = params.source;
}
delete params.source;
const { application, arch, deviceType } = options;
if (
(application == null && (arch == null || deviceType == null)) ||
(application != null && (arch != null || deviceType != null))
) {
throw new ExpectedError(
'You must specify either an application or an arch/deviceType pair to build for',
);
}
if (application) {
await checkLoggedIn();
}
return validateProjectDirectory(sdk, {
dockerfilePath: options.dockerfile,
noParentCheck: options['noparent-check'] || false,
projectPath: options.source || '.',
registrySecretsPath: options['registry-secrets'],
})
.then(function ({ dockerfilePath, registrySecrets }) {
options.dockerfile = dockerfilePath;
options['registry-secrets'] = registrySecrets;
if (arch != null && deviceType != null) {
return [undefined, arch, deviceType];
} else {
return helpers
.getAppWithArch(application)
.then((app) => [app, app.arch, app.device_type]);
}
})
.then(function ([app, resolvedArch, resolvedDeviceType]) {
return Promise.all([
dockerUtils.getDocker(options),
dockerUtils.generateBuildOpts(options),
compose.generateOpts(options),
]).then(([docker, buildOpts, composeOpts]) =>
buildProject(docker, logger, composeOpts, {
app,
arch: resolvedArch,
deviceType: resolvedDeviceType,
buildEmulated: !!options.emulated,
buildOpts,
}),
);
});
},
};

View File

@ -1,153 +0,0 @@
/*
Copyright 2016-2017 Balena
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
export const yes = {
signature: 'yes',
description: 'confirm non interactively',
boolean: true,
alias: 'y',
};
export interface YesOption {
yes: boolean;
}
export const optionalApplication = {
signature: 'application',
parameter: 'application',
description: 'application name',
alias: ['a', 'app'],
};
export const application = {
...optionalApplication,
required: 'You have to specify an application',
};
export const optionalRelease = {
signature: 'release',
parameter: 'release',
description: 'release id',
alias: 'r',
};
export const optionalDevice = {
signature: 'device',
parameter: 'device',
description: 'device uuid',
alias: 'd',
};
export const optionalDeviceApiKey = {
signature: 'deviceApiKey',
description:
'custom device key - note that this is only supported on balenaOS 2.0.3+',
parameter: 'device-api-key',
alias: 'k',
};
export const optionalDeviceType = {
signature: 'deviceType',
description: 'device type slug',
parameter: 'device-type',
};
export const optionalOsVersion = {
signature: 'version',
description: 'a balenaOS version',
parameter: 'version',
};
export type OptionalOsVersionOption = Partial<OsVersionOption>;
export const osVersion = {
...exports.optionalOsVersion,
required: 'You have to specify an exact os version',
};
export interface OsVersionOption {
version?: string;
}
export const booleanDevice = {
signature: 'device',
description: 'device',
boolean: true,
alias: 'd',
};
export const osVersionOrSemver = {
signature: 'version',
description: `\
exact version number, or a valid semver range,
or 'latest' (includes pre-releases),
or 'default' (excludes pre-releases if at least one stable version is available),
or 'recommended' (excludes pre-releases, will fail if only pre-release versions are available),
or 'menu' (will show the interactive menu)\
`,
parameter: 'version',
};
export const network = {
signature: 'network',
parameter: 'network',
description: 'network type',
alias: 'n',
};
export const wifiSsid = {
signature: 'ssid',
parameter: 'ssid',
description: 'wifi ssid, if network is wifi',
alias: 's',
};
export const wifiKey = {
signature: 'key',
parameter: 'key',
description: 'wifi key, if network is wifi',
alias: 'k',
};
export const forceUpdateLock = {
signature: 'force',
description: 'force action if the update lock is set',
boolean: true,
alias: 'f',
};
export const drive = {
signature: 'drive',
description: `the drive to write the image to, like \`/dev/sdb\` or \`/dev/mmcblk0\`. \
Careful with this as you can erase your hard drive. \
Check \`balena util available-drives\` for available options.`,
parameter: 'drive',
alias: 'd',
};
export const advancedConfig = {
signature: 'advanced',
description: 'show advanced configuration options',
boolean: true,
alias: 'v',
};
export const hostOSAccess = {
signature: 'host',
boolean: true,
description: 'access host OS (for devices with balenaOS >= 2.0.0+rev1)',
alias: 's',
};

View File

@ -1,408 +0,0 @@
/*
Copyright 2016-2020 Balena Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import * as commandOptions from './command-options';
import { normalizeUuidProp } from '../utils/normalization';
import { getBalenaSdk, getVisuals, getCliForm } from '../utils/lazy';
import * as _ from 'lodash';
const getUmountAsync = async () => {
const { promisify } = await import('bluebird');
const { umount } = await import('umount');
return promisify(umount);
};
export const read = {
signature: 'config read',
description: 'read a device configuration',
help: `\
Use this command to read the config.json file from the mounted filesystem (e.g. SD card) of a provisioned device"
Examples:
$ balena config read --type raspberry-pi
$ balena config read --type raspberry-pi --drive /dev/disk2\
`,
options: [
{
signature: 'type',
description:
'device type (Check available types with `balena devices supported`)',
parameter: 'type',
alias: 't',
required: 'You have to specify a device type',
},
{
signature: 'drive',
description: 'drive',
parameter: 'drive',
alias: 'd',
},
],
permission: 'user',
root: true,
async action(_params, options) {
const umountAsync = await getUmountAsync();
const drive =
options.drive || (await getVisuals().drive('Select the device drive'));
await umountAsync(drive);
const config = await import('balena-config-json');
const configJSON = await config.read(drive, options.type);
const prettyjson = await import('prettyjson');
console.info(prettyjson.render(configJSON));
},
};
export const write = {
signature: 'config write <key> <value>',
description: 'write a device configuration',
help: `\
Use this command to write the config.json file to the mounted filesystem (e.g. SD card) of a provisioned device
Examples:
$ balena config write --type raspberry-pi username johndoe
$ balena config write --type raspberry-pi --drive /dev/disk2 username johndoe
$ balena config write --type raspberry-pi files.network/settings "..."\
`,
options: [
{
signature: 'type',
description:
'device type (Check available types with `balena devices supported`)',
parameter: 'type',
alias: 't',
required: 'You have to specify a device type',
},
{
signature: 'drive',
description: 'drive',
parameter: 'drive',
alias: 'd',
},
],
permission: 'user',
root: true,
async action(params, options) {
const umountAsync = await getUmountAsync();
const drive =
options.drive || (await getVisuals().drive('Select the device drive'));
await umountAsync(drive);
const config = await import('balena-config-json');
const configJSON = await config.read(drive, options.type);
console.info(`Setting ${params.key} to ${params.value}`);
_.set(configJSON, params.key, params.value);
await umountAsync(drive);
await config.write(drive, options.type, configJSON);
console.info('Done');
},
};
export const inject = {
signature: 'config inject <file>',
description: 'inject a device configuration file',
help: `\
Use this command to inject a config.json file to the mounted filesystem
(e.g. SD card or mounted balenaOS image) of a provisioned device"
Examples:
$ balena config inject my/config.json --type raspberry-pi
$ balena config inject my/config.json --type raspberry-pi --drive /dev/disk2\
`,
options: [
{
signature: 'type',
description:
'device type (Check available types with `balena devices supported`)',
parameter: 'type',
alias: 't',
required: 'You have to specify a device type',
},
{
signature: 'drive',
description: 'drive',
parameter: 'drive',
alias: 'd',
},
],
permission: 'user',
root: true,
async action(params, options) {
const umountAsync = await getUmountAsync();
const drive =
options.drive || (await getVisuals().drive('Select the device drive'));
await umountAsync(drive);
const fs = await import('fs');
const configJSON = JSON.parse(
await fs.promises.readFile(params.file, 'utf8'),
);
const config = await import('balena-config-json');
await config.write(drive, options.type, configJSON);
console.info('Done');
},
};
export const reconfigure = {
signature: 'config reconfigure',
description: 'reconfigure a provisioned device',
help: `\
Use this command to reconfigure a provisioned device
Examples:
$ balena config reconfigure --type raspberry-pi
$ balena config reconfigure --type raspberry-pi --advanced
$ balena config reconfigure --type raspberry-pi --drive /dev/disk2\
`,
options: [
{
signature: 'type',
description:
'device type (Check available types with `balena devices supported`)',
parameter: 'type',
alias: 't',
required: 'You have to specify a device type',
},
{
signature: 'drive',
description: 'drive',
parameter: 'drive',
alias: 'd',
},
{
signature: 'advanced',
description: 'show advanced commands',
boolean: true,
alias: 'v',
},
],
permission: 'user',
root: true,
async action(_params, options) {
const umountAsync = await getUmountAsync();
const drive =
options.drive || (await getVisuals().drive('Select the device drive'));
await umountAsync(drive);
const config = await import('balena-config-json');
const { uuid } = await config.read(drive, options.type);
await umountAsync(drive);
let configureCommand = ['os', 'configure', drive, '--device', uuid];
if (options.advanced) {
configureCommand.push('--advanced');
}
const { runCommand } = await import('../utils/helpers');
await runCommand(configureCommand);
console.info('Done');
},
};
export const generate = {
signature: 'config generate',
description: 'generate a config.json file',
help: `\
Use this command to generate a config.json for a device or application.
Calling this command with the exact version number of the targeted image is required.
This is interactive by default, but you can do this automatically without interactivity
by specifying an option for each question on the command line, if you know the questions
that will be asked for the relevant device type.
In case that you want to configure an image for an application with mixed device types,
you can pass the --device-type argument along with --app to specify the target device type.
Examples:
$ balena config generate --device 7cf02a6 --version 2.12.7
$ balena config generate --device 7cf02a6 --version 2.12.7 --generate-device-api-key
$ balena config generate --device 7cf02a6 --version 2.12.7 --device-api-key <existingDeviceKey>
$ balena config generate --device 7cf02a6 --version 2.12.7 --output config.json
$ balena config generate --app MyApp --version 2.12.7
$ balena config generate --app MyApp --version 2.12.7 --device-type fincm3
$ balena config generate --app MyApp --version 2.12.7 --output config.json
$ balena config generate --app MyApp --version 2.12.7 \
--network wifi --wifiSsid mySsid --wifiKey abcdefgh --appUpdatePollInterval 1\
`,
options: [
commandOptions.osVersion,
commandOptions.optionalApplication,
commandOptions.optionalDevice,
commandOptions.optionalDeviceApiKey,
commandOptions.optionalDeviceType,
{
signature: 'generate-device-api-key',
description: 'generate a fresh device key for the device',
boolean: true,
},
{
signature: 'output',
description: 'output',
parameter: 'output',
alias: 'o',
},
// Options for non-interactive configuration
{
signature: 'network',
description: 'the network type to use: ethernet or wifi',
parameter: 'network',
},
{
signature: 'wifiSsid',
description:
'the wifi ssid to use (used only if --network is set to wifi)',
parameter: 'wifiSsid',
},
{
signature: 'wifiKey',
description:
'the wifi key to use (used only if --network is set to wifi)',
parameter: 'wifiKey',
},
{
signature: 'appUpdatePollInterval',
description:
'how frequently (in minutes) to poll for application updates',
parameter: 'appUpdatePollInterval',
},
],
permission: 'user',
action(_params, options) {
normalizeUuidProp(options, 'device');
const Bluebird = require('bluebird');
const balena = getBalenaSdk();
const prettyjson = require('prettyjson');
const {
generateDeviceConfig,
generateApplicationConfig,
} = require('../utils/config');
const helpers = require('../utils/helpers');
const { exitWithExpectedError } = require('../errors');
if (options.device == null && options.application == null) {
exitWithExpectedError(`\
You have to pass either a device or an application.
See the help page for examples:
$ balena help config generate\
`);
}
if (!options.application && options.deviceType) {
exitWithExpectedError(`\
Specifying a different device type is only supported when
generating a config for an application:
* An application, with --app <appname>
* A specific device type, with --device-type <deviceTypeSlug>
See the help page for examples:
$ balena help config generate\
`);
}
return Bluebird.try(
/** @returns {Promise<any>} */ function () {
if (options.device != null) {
return balena.models.device.get(options.device);
}
return balena.models.application.get(options.application);
},
)
.then(function (resource) {
const deviceType = options.deviceType || resource.device_type;
let manifestPromise = balena.models.device.getManifestBySlug(
deviceType,
);
if (options.application && options.deviceType) {
const app = resource;
const appManifestPromise = balena.models.device.getManifestBySlug(
app.device_type,
);
manifestPromise = manifestPromise.tap((paramDeviceType) =>
appManifestPromise.then(function (appDeviceType) {
if (
!helpers.areDeviceTypesCompatible(
appDeviceType,
paramDeviceType,
)
) {
throw new balena.errors.BalenaInvalidDeviceType(
`Device type ${options.deviceType} is incompatible with application ${options.application}`,
);
}
}),
);
}
return manifestPromise
.get('options')
.then((
formOptions, // Pass params as an override: if there is any param with exactly the same name as a
) =>
// required option, that value is used (and the corresponding question is not asked)
getCliForm().run(formOptions, { override: options }),
)
.then(function (answers) {
answers.version = options.version;
if (resource.uuid != null) {
return generateDeviceConfig(
resource,
options.deviceApiKey || options['generate-device-api-key'],
answers,
);
} else {
answers.deviceType = deviceType;
return generateApplicationConfig(resource, answers);
}
});
})
.then(function (config) {
if (options.output != null) {
return require('fs').promises.writeFile(
options.output,
JSON.stringify(config),
);
}
console.log(prettyjson.render(config));
});
},
};

View File

@ -1,318 +0,0 @@
/**
* @license
* Copyright 2016-2020 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as dockerUtils from '../utils/docker';
import * as compose from '../utils/compose';
import { dockerignoreHelp, registrySecretsHelp } from '../utils/messages';
import { ExpectedError } from '../errors';
import { getBalenaSdk, getChalk } from '../utils/lazy';
/**
* Opts must be an object with the following keys:
* app: the application instance to deploy to
* image: the image to deploy; optional
* dockerfilePath: name of an alternative Dockerfile; optional
* shouldPerformBuild
* shouldUploadLogs
* buildEmulated
* buildOpts: arguments to forward to docker build command
*
* @param {any} docker
* @param {import('../utils/logger')} logger
* @param {import('../utils/compose-types').ComposeOpts} composeOpts
* @param {any} opts
*/
const deployProject = function (docker, logger, composeOpts, opts) {
const Bluebird = require('bluebird');
const _ = require('lodash');
const doodles = require('resin-doodles');
const sdk = getBalenaSdk();
const {
deployProject: $deployProject,
loadProject,
} = require('../utils/compose_ts');
return loadProject(logger, composeOpts, opts.image)
.then(function (project) {
if (
project.descriptors.length > 1 &&
!opts.app.application_type?.[0]?.supports_multicontainer
) {
throw new ExpectedError(
'Target application does not support multiple containers. Aborting!',
);
}
// find which services use images that already exist locally
return (
Bluebird.map(project.descriptors, function (d) {
// unconditionally build (or pull) if explicitly requested
if (opts.shouldPerformBuild) {
return d;
}
return docker
.getImage(typeof d.image === 'string' ? d.image : d.image.tag)
.inspect()
.return(d.serviceName)
.catchReturn();
})
.filter((d) => !!d)
.then(function (servicesToSkip) {
// multibuild takes in a composition and always attempts to
// build or pull all services. we workaround that here by
// passing a modified composition.
const compositionToBuild = _.cloneDeep(project.composition);
compositionToBuild.services = _.omit(
compositionToBuild.services,
servicesToSkip,
);
if (_.size(compositionToBuild.services) === 0) {
logger.logInfo(
'Everything is up to date (use --build to force a rebuild)',
);
return {};
}
return compose
.buildProject(
docker,
logger,
project.path,
project.name,
compositionToBuild,
opts.app.arch,
opts.app.device_type,
opts.buildEmulated,
opts.buildOpts,
composeOpts.inlineLogs,
composeOpts.convertEol,
composeOpts.dockerfilePath,
composeOpts.nogitignore,
composeOpts.multiDockerignore,
)
.then((builtImages) => _.keyBy(builtImages, 'serviceName'));
})
.then((builtImages) =>
project.descriptors.map(
(d) =>
builtImages[d.serviceName] ?? {
serviceName: d.serviceName,
name: typeof d.image === 'string' ? d.image : d.image.tag,
logs: 'Build skipped; image for service already exists.',
props: {},
},
),
)
// @ts-ignore slightly different return types of partial vs non-partial release
.then(function (images) {
if (opts.app.application_type?.[0]?.is_legacy) {
const { deployLegacy } = require('../utils/deploy-legacy');
const msg = getChalk().yellow(
'Target application requires legacy deploy method.',
);
logger.logWarn(msg);
return Bluebird.join(
docker,
logger,
sdk.auth.getToken(),
sdk.auth.whoami(),
sdk.settings.get('balenaUrl'),
{
// opts.appName may be prefixed by 'owner/', unlike opts.app.app_name
appName: opts.appName,
imageName: images[0].name,
buildLogs: images[0].logs,
shouldUploadLogs: opts.shouldUploadLogs,
},
deployLegacy,
).then((releaseId) =>
// @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
// Promise.join typings
sdk.models.release.get(releaseId, { $select: ['commit'] }),
);
}
return Promise.all([
sdk.auth.getUserId(),
sdk.auth.getToken(),
sdk.settings.get('apiUrl'),
]).then(([userId, auth, apiEndpoint]) =>
$deployProject(
docker,
logger,
project.composition,
images,
opts.app.id,
userId,
`Bearer ${auth}`,
apiEndpoint,
!opts.shouldUploadLogs,
),
);
})
);
})
.then(function (release) {
logger.outputDeferredMessages();
logger.logSuccess('Deploy succeeded!');
logger.logSuccess(`Release: ${release.commit}`);
console.log();
console.log(doodles.getDoodle()); // Show charlie
console.log();
})
.catch((err) => {
logger.logError('Deploy failed');
throw err;
});
};
export const deploy = {
signature: 'deploy <appName> [image]',
description:
'Deploy a single image or a multicontainer project to a balena application',
help: `\
Usage: \`deploy <appName> ([image] | --build [--source build-dir])\`
Use this command to deploy an image or a complete multicontainer project to an
application, optionally building it first. The source images are searched for
(and optionally built) using the docker daemon in your development machine or
balena device. (See also the \`balena push\` command for the option of building
the image in the balenaCloud build servers.)
Unless an image is specified, this command will look into the current directory
(or the one specified by --source) for a docker-compose.yml file. If one is
found, this command will deploy each service defined in the compose file,
building it first if an image for it doesn't exist. If a compose file isn't
found, the command will look for a Dockerfile[.template] file (or alternative
Dockerfile specified with the \`-f\` option), and if yet that isn't found, it
will try to generate one.
To deploy to an app on which you're a collaborator, use
\`balena deploy <appOwnerUsername>/<appName>\`.
When --build is used, all options supported by \`balena build\` are also supported
by this command.
${registrySecretsHelp}
${dockerignoreHelp}
Examples:
$ balena deploy myApp
$ balena deploy myApp --build --source myBuildDir/
$ balena deploy myApp myApp/myImage\
`,
permission: 'user',
primary: true,
options: dockerUtils.appendOptions(
compose.appendOptions([
{
signature: 'source',
parameter: 'source',
description:
'Specify an alternate source directory; default is the working directory',
alias: 's',
},
{
signature: 'build',
boolean: true,
description: 'Force a rebuild before deploy',
alias: 'b',
},
{
signature: 'nologupload',
description:
"Don't upload build logs to the dashboard with image (if building)",
boolean: true,
},
]),
),
async action(params, options) {
// compositions with many services trigger misleading warnings
// @ts-ignore editing property that isn't typed but does exist
require('events').defaultMaxListeners = 1000;
const sdk = getBalenaSdk();
const {
getRegistrySecrets,
validateProjectDirectory,
} = require('../utils/compose_ts');
const helpers = require('../utils/helpers');
const Logger = require('../utils/logger');
const logger = Logger.getLogger();
logger.logDebug('Parsing input...');
// when Capitano converts a positional parameter (but not an option)
// to a number, the original value is preserved with the _raw suffix
let { appName, appName_raw, image } = params;
// look into "balena build" options if appName isn't given
appName = appName_raw || appName || options.application;
delete options.application;
if (appName == null) {
throw new ExpectedError(
'Please specify the name of the application to deploy',
);
}
if (image != null && options.build) {
throw new ExpectedError(
'Build option is not applicable when specifying an image',
);
}
if (image) {
const registrySecrets = await getRegistrySecrets(
sdk,
options['registry-secrets'],
);
options['registry-secrets'] = registrySecrets;
} else {
const {
dockerfilePath,
registrySecrets,
} = await validateProjectDirectory(sdk, {
dockerfilePath: options.dockerfile,
noParentCheck: options['noparent-check'] || false,
projectPath: options.source || '.',
registrySecretsPath: options['registry-secrets'],
});
options.dockerfile = dockerfilePath;
options['registry-secrets'] = registrySecrets;
}
const app = await helpers.getAppWithArch(appName);
const [docker, buildOpts, composeOpts] = await Promise.all([
dockerUtils.getDocker(options),
dockerUtils.generateBuildOpts(options),
compose.generateOpts(options),
]);
await deployProject(docker, logger, composeOpts, {
app,
appName, // may be prefixed by 'owner/', unlike app.app_name
image,
shouldPerformBuild: !!options.build,
shouldUploadLogs: !options.nologupload,
buildEmulated: !!options.emulated,
buildOpts,
});
},
};

View File

@ -1,190 +0,0 @@
/*
Copyright 2016-2020 Balena Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import * as _ from 'lodash';
import * as capitano from 'capitano';
import * as columnify from 'columnify';
import * as messages from '../utils/messages';
import { getManualSortCompareFunction } from '../utils/helpers';
import { exitWithExpectedError } from '../errors';
import { getOclifHelpLinePairs } from './help_ts';
const parse = (object) =>
_.map(object, function (item) {
// Hacky way to determine if an object is
// a function or a command
let signature;
if (item.alias != null) {
signature = item.toString();
} else {
signature = item.signature.toString();
}
return [signature, item.description];
});
const indent = function (text) {
text = _.map(text.split('\n'), (line) => ' ' + line);
return text.join('\n');
};
const print = (usageDescriptionPairs) =>
console.log(
indent(
columnify(_.fromPairs(usageDescriptionPairs), {
showHeaders: false,
minWidth: 35,
}),
),
);
const manuallySortedPrimaryCommands = [
'help',
'login',
'push',
'logs',
'ssh',
'apps',
'app',
'devices',
'device',
'tunnel',
'preload',
'build',
'deploy',
'join',
'leave',
'local scan',
];
const general = function (_params, options, done) {
console.log('Usage: balena [COMMAND] [OPTIONS]\n');
console.log('Primary commands:\n');
// We do not want the wildcard command
// to be printed in the help screen.
const commands = capitano.state.commands.filter(
(command) => !command.hidden && !command.isWildcard(),
);
const capitanoCommands = _.groupBy(commands, function (command) {
if (command.primary) {
return 'primary';
}
return 'secondary';
});
return getOclifHelpLinePairs()
.then(function (oclifHelpLinePairs) {
const primaryHelpLinePairs = parse(capitanoCommands.primary)
.concat(oclifHelpLinePairs.primary)
.sort(
getManualSortCompareFunction(manuallySortedPrimaryCommands, function (
[signature],
manualItem,
) {
return (
signature === manualItem || signature.startsWith(`${manualItem} `)
);
}),
);
const secondaryHelpLinePairs = parse(capitanoCommands.secondary)
.concat(oclifHelpLinePairs.secondary)
.sort();
print(primaryHelpLinePairs);
if (options.verbose) {
console.log('\nAdditional commands:\n');
print(secondaryHelpLinePairs);
} else {
console.log(
'\nRun `balena help --verbose` to list additional commands',
);
}
if (!_.isEmpty(capitano.state.globalOptions)) {
console.log('\nGlobal Options:\n');
print(parse(capitano.state.globalOptions).sort());
}
console.log(indent('--debug\n'));
console.log(messages.help);
return done();
})
.catch(done);
};
const commandHelp = (params, _options, done) =>
capitano.state.getMatchCommand(params.command, function (error, command) {
if (error != null) {
return done(error);
}
if (command == null || command.isWildcard()) {
exitWithExpectedError(`Command not found: ${params.command}`);
}
console.log(`Usage: ${command.signature}`);
if (command.help != null) {
console.log(`\n${command.help}`);
} else if (command.description != null) {
console.log(`\n${_.capitalize(command.description)}`);
}
if (!_.isEmpty(command.options)) {
console.log('\nOptions:\n');
print(parse(command.options).sort());
}
console.log();
return done();
});
export const help = {
signature: 'help [command...]',
description: 'show help',
help: `\
Get detailed help for an specific command.
Examples:
$ balena help apps
$ balena help os download\
`,
primary: true,
options: [
{
signature: 'verbose',
description: 'show additional commands',
boolean: true,
alias: 'v',
},
],
action(params, options, done) {
if (params.command != null) {
return commandHelp(params, options, done);
} else {
return general(params, options, done);
}
},
};

View File

@ -1,65 +0,0 @@
/**
* @license
* Copyright 2019 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as _ from 'lodash';
import * as path from 'path';
import Command from '../command';
import { capitanoizeOclifUsage } from '../utils/oclif-utils';
export async function getOclifHelpLinePairs() {
const { convertedCommands } = await import('../preparser');
const primary: Array<[string, string]> = [];
const secondary: Array<[string, string]> = [];
for (const convertedCmd of convertedCommands) {
const [topic, cmd] = convertedCmd.split(':');
const pathComponents = ['..', 'actions-oclif', topic];
if (cmd) {
pathComponents.push(cmd);
}
const cmdModule = await import(path.join(...pathComponents));
const command: typeof Command = cmdModule.default;
if (!command.hidden) {
if (command.primary) {
primary.push(getCmdUsageDescriptionLinePair(command));
} else {
secondary.push(getCmdUsageDescriptionLinePair(command));
}
}
}
return { primary, secondary };
}
function getCmdUsageDescriptionLinePair(cmd: typeof Command): [string, string] {
const usage = capitanoizeOclifUsage(cmd.usage);
let description = '';
// note: [^] matches any characters (including line breaks), achieving the
// same effect as the 's' regex flag which is only supported by Node 9+
const matches = /\s*([^]+?)\n[^]*/.exec(cmd.description || '');
if (matches && matches.length > 1) {
description = _.trimEnd(matches[1], '.');
// Only do .lowerFirst() if the second char is not uppercase (e.g. for 'SSH');
if (description[1] !== description[1]?.toUpperCase()) {
description = _.lowerFirst(description);
}
}
return [usage, description];
}

View File

@ -1,96 +0,0 @@
import * as Bluebird from 'bluebird';
import * as _ from 'lodash';
import * as dockerUtils from '../../utils/docker';
import { exitWithExpectedError } from '../../errors';
import { getChalk, getCliForm } from '../../utils/lazy';
export const dockerPort = 2375;
export const dockerTimeout = 2000;
export const filterOutSupervisorContainer = function (container) {
for (const name of container.Names) {
if (
name.includes('resin_supervisor') ||
name.includes('balena_supervisor')
) {
return false;
}
}
return true;
};
export const selectContainerFromDevice = Bluebird.method(function (
deviceIp,
filterSupervisor,
) {
if (filterSupervisor == null) {
filterSupervisor = false;
}
const docker = dockerUtils.createClient({
host: deviceIp,
port: dockerPort,
timeout: dockerTimeout,
});
// List all containers, including those not running
return docker.listContainers({ all: true }).then(function (containers) {
containers = containers.filter(function (container) {
if (!filterSupervisor) {
return true;
}
return filterOutSupervisorContainer(container);
});
if (_.isEmpty(containers)) {
exitWithExpectedError(`No containers found in ${deviceIp}`);
}
return getCliForm().ask({
message: 'Select a container',
type: 'list',
choices: _.map(containers, function (container) {
const containerName = container.Names?.[0] || 'Untitled';
const shortContainerId = ('' + container.Id).substr(0, 11);
return {
name: `${containerName} (${shortContainerId})`,
value: container.Id,
};
}),
});
});
});
export const pipeContainerStream = Bluebird.method(function ({
deviceIp,
name,
outStream,
follow,
}) {
if (follow == null) {
follow = false;
}
const docker = dockerUtils.createClient({ host: deviceIp, port: dockerPort });
const container = docker.getContainer(name);
return container
.inspect()
.then((containerInfo) => containerInfo?.State?.Running)
.then((isRunning) =>
container.attach({
logs: !follow || !isRunning,
stream: follow && isRunning,
stdout: true,
stderr: true,
}),
)
.then((containerStream) => containerStream.pipe(outStream))
.catch(function (err) {
err = '' + err.statusCode;
if (err === '404') {
return console.log(
getChalk().red.bold(`Container '${name}' not found.`),
);
}
throw err;
});
});

View File

@ -1,285 +0,0 @@
/*
Copyright 2017-2020 Balena Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const BOOT_PARTITION = 1;
const CONNECTIONS_FOLDER = '/system-connections';
const getConfigurationSchema = function (connnectionFileName) {
if (connnectionFileName == null) {
connnectionFileName = 'resin-wifi';
}
return {
mapper: [
{
template: {
persistentLogging: '{{persistentLogging}}',
},
domain: [['config_json', 'persistentLogging']],
},
{
template: {
hostname: '{{hostname}}',
},
domain: [['config_json', 'hostname']],
},
{
template: {
wifi: {
ssid: '{{networkSsid}}',
},
'wifi-security': {
psk: '{{networkKey}}',
},
},
domain: [
['system_connections', connnectionFileName, 'wifi'],
['system_connections', connnectionFileName, 'wifi-security'],
],
},
],
files: {
system_connections: {
fileset: true,
type: 'ini',
location: {
path: CONNECTIONS_FOLDER.slice(1),
// Reconfix still uses the older resin-image-fs, so still needs an
// object-based partition definition.
partition: BOOT_PARTITION,
},
},
config_json: {
type: 'json',
location: {
path: 'config.json',
partition: BOOT_PARTITION,
},
},
},
};
};
const inquirerOptions = (data) => [
{
message: 'Network SSID',
type: 'input',
name: 'networkSsid',
default: data.networkSsid,
},
{
message: 'Network Key',
type: 'input',
name: 'networkKey',
default: data.networkKey,
},
{
message: 'Do you want to set advanced settings?',
type: 'confirm',
name: 'advancedSettings',
default: false,
},
{
message: 'Device Hostname',
type: 'input',
name: 'hostname',
default: data.hostname,
when(answers) {
return answers.advancedSettings;
},
},
{
message: 'Do you want to enable persistent logging?',
type: 'confirm',
name: 'persistentLogging',
default: data.persistentLogging,
when(answers) {
return answers.advancedSettings;
},
},
];
const getConfiguration = function (data) {
const _ = require('lodash');
const inquirer = require('inquirer');
// `persistentLogging` can be `undefined`, so we want
// to make sure that case defaults to `false`
data = _.assign(data, { persistentLogging: data.persistentLogging || false });
return inquirer
.prompt(inquirerOptions(data))
.then((answers) => _.merge(data, answers));
};
// Taken from https://goo.gl/kr1kCt
const CONNECTION_FILE = `\
[connection]
id=resin-wifi
type=wifi
[wifi]
hidden=true
mode=infrastructure
ssid=My_Wifi_Ssid
[wifi-security]
auth-alg=open
key-mgmt=wpa-psk
psk=super_secret_wifi_password
[ipv4]
method=auto
[ipv6]
addr-gen-mode=stable-privacy
method=auto\
`;
/*
* if the `resin-wifi` file exists (previously configured image or downloaded from the UI) it's used and reconfigured
* if the `resin-sample.ignore` exists it's copied to `resin-wifi`
* if the `resin-sample` exists it's reconfigured (legacy mode, will be removed eventually)
* otherwise, the new file is created
*/
const prepareConnectionFile = function (target) {
const _ = require('lodash');
const imagefs = require('resin-image-fs');
return imagefs
.listDirectory({
image: target,
partition: BOOT_PARTITION,
path: CONNECTIONS_FOLDER,
})
.then(function (files) {
// The required file already exists
if (_.includes(files, 'resin-wifi')) {
return null;
}
// Fresh image, new mode, accoding to https://github.com/balena-os/meta-balena/pull/770/files
if (_.includes(files, 'resin-sample.ignore')) {
return imagefs
.copy(
{
image: target,
partition: BOOT_PARTITION,
path: `${CONNECTIONS_FOLDER}/resin-sample.ignore`,
},
{
image: target,
partition: BOOT_PARTITION,
path: `${CONNECTIONS_FOLDER}/resin-wifi`,
},
)
.thenReturn(null);
}
// Legacy mode, to be removed later
// We return the file name override from this branch
// When it is removed the following cleanup should be done:
// * delete all the null returns from this method
// * turn `getConfigurationSchema` back into the constant, with the connection filename always being `resin-wifi`
// * drop the final `then` from this method
// * adapt the code in the main listener to not receive the config from this method, and use that constant instead
if (_.includes(files, 'resin-sample')) {
return 'resin-sample';
}
// In case there's no file at all (shouldn't happen normally, but the file might have been removed)
return imagefs
.writeFile(
{
image: target,
partition: BOOT_PARTITION,
path: `${CONNECTIONS_FOLDER}/resin-wifi`,
},
CONNECTION_FILE,
)
.thenReturn(null);
})
.then((connectionFileName) => getConfigurationSchema(connectionFileName));
};
const removeHostname = function (schema) {
const _ = require('lodash');
schema.mapper = _.reject(schema.mapper, (mapper) =>
_.isEqual(Object.keys(mapper.template), ['hostname']),
);
};
export const configure = {
signature: 'local configure <target>',
description: '(Re)configure a balenaOS drive or image',
help: `\
Use this command to configure or reconfigure a balenaOS drive or image.
Examples:
$ balena local configure /dev/sdc
$ balena local configure path/to/image.img\
`,
root: true,
action(params) {
const Bluebird = require('bluebird');
const path = require('path');
const umount = require('umount');
const umountAsync = Bluebird.promisify(umount.umount);
const isMountedAsync = Bluebird.promisify(umount.isMounted);
const reconfix = require('reconfix');
const denymount = Bluebird.promisify(require('denymount'));
return prepareConnectionFile(params.target)
.tap(() =>
isMountedAsync(params.target).then(function (isMounted) {
if (!isMounted) {
return;
}
return umountAsync(params.target);
}),
)
.then(function (configurationSchema) {
const dmOpts = {};
if (process.pkg) {
// when running in a standalone pkg install, the 'denymount'
// executable is placed on the same folder as process.execPath
dmOpts.executablePath = path.join(
path.dirname(process.execPath),
'denymount',
);
}
const dmHandler = (cb) =>
reconfix
.readConfiguration(configurationSchema, params.target)
.then(getConfiguration)
.then(function (answers) {
if (!answers.hostname) {
removeHostname(configurationSchema);
}
return reconfix.writeConfiguration(
configurationSchema,
answers,
params.target,
);
})
.asCallback(cb);
return denymount(params.target, dmHandler, dmOpts);
})
.then(() => {
console.log('Done!');
});
},
};

View File

@ -1,17 +0,0 @@
/*
Copyright 2017-2020 Balena Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
export { configure } from './configure';

View File

@ -1,351 +0,0 @@
/*
Copyright 2016-2020 Balena
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import * as commandOptions from './command-options';
import * as _ from 'lodash';
import { getBalenaSdk, getVisuals, getCliForm } from '../utils/lazy';
const formatVersion = function (v, isRecommended) {
let result = `v${v}`;
if (isRecommended) {
result += ' (recommended)';
}
return result;
};
const resolveVersion = function (deviceType, version) {
if (version !== 'menu') {
if (version[0] === 'v') {
version = version.slice(1);
}
return Promise.resolve(version);
}
const balena = getBalenaSdk();
return balena.models.os
.getSupportedVersions(deviceType)
.then(function ({ versions: vs, recommended }) {
const choices = vs.map((v) => ({
value: v,
name: formatVersion(v, v === recommended),
}));
return getCliForm().ask({
message: 'Select the OS version:',
type: 'list',
choices,
default: recommended,
});
});
};
export const versions = {
signature: 'os versions <type>',
description: 'show the available balenaOS versions for the given device type',
help: `\
Use this command to show the available balenaOS versions for a certain device type.
Check available types with \`balena devices supported\`
Example:
$ balena os versions raspberrypi3\
`,
action(params) {
const balena = getBalenaSdk();
return balena.models.os
.getSupportedVersions(params.type)
.then(({ versions: vs, recommended }) => {
vs.forEach((v) => {
console.log(formatVersion(v, v === recommended));
});
});
},
};
export const download = {
signature: 'os download <type>',
description: 'download an unconfigured os image',
help: `\
Use this command to download an unconfigured os image for a certain device type.
Check available types with \`balena devices supported\`
> Note: Currently this command only works with balenaCloud, not openBalena.
> If using openBalena, please download the OS from: https://www.balena.io/os/
If version is not specified the newest stable (non-pre-release) version of OS
is downloaded if available, or the newest version otherwise (if all existing
versions for the given device type are pre-release).
You can pass \`--version menu\` to pick the OS version from the interactive menu
of all available versions.
Examples:
$ balena os download raspberrypi3 -o ../foo/bar/raspberry-pi.img
$ balena os download raspberrypi3 -o ../foo/bar/raspberry-pi.img --version 1.24.1
$ balena os download raspberrypi3 -o ../foo/bar/raspberry-pi.img --version ^1.20.0
$ balena os download raspberrypi3 -o ../foo/bar/raspberry-pi.img --version latest
$ balena os download raspberrypi3 -o ../foo/bar/raspberry-pi.img --version default
$ balena os download raspberrypi3 -o ../foo/bar/raspberry-pi.img --version menu\
`,
options: [
{
signature: 'output',
description: 'output path',
parameter: 'output',
alias: 'o',
required: 'You have to specify the output location',
},
commandOptions.osVersionOrSemver,
],
action(params, options) {
const Bluebird = require('bluebird');
const unzip = require('node-unzip-2');
const fs = require('fs');
const manager = require('balena-image-manager');
console.info(`Getting device operating system for ${params.type}`);
let displayVersion = '';
return Bluebird.try(function () {
if (!options.version) {
console.warn(`OS version is not specified, using the default version: \
the newest stable (non-pre-release) version if available, \
or the newest version otherwise (if all existing \
versions for the given device type are pre-release).`);
return 'default';
}
return resolveVersion(params.type, options.version);
})
.then(function (version) {
if (version !== 'default') {
displayVersion = ` ${version}`;
}
return manager.get(params.type, version);
})
.then(async function (stream) {
const visuals = getVisuals();
const bar = new visuals.Progress(
`Downloading Device OS${displayVersion}`,
);
const spinner = new visuals.Spinner(
`Downloading Device OS${displayVersion} (size unknown)`,
);
stream.on('progress', function (state) {
if (state != null) {
return bar.update(state);
} else {
return spinner.start();
}
});
stream.on('end', () => {
spinner.stop();
});
// We completely rely on the `mime` custom property
// to make this decision.
// The actual stream should be checked instead.
let output;
if (stream.mime === 'application/zip') {
output = unzip.Extract({ path: options.output });
} else {
output = fs.createWriteStream(options.output);
}
const streamToPromise = await import('stream-to-promise');
await streamToPromise(stream.pipe(output));
return options.output;
})
.tap(() => {
console.info('The image was downloaded successfully');
});
},
};
const buildConfigForDeviceType = function (deviceType, advanced) {
if (advanced == null) {
advanced = false;
}
const helpers = require('../utils/helpers');
let override;
const questions = deviceType.options;
if (!advanced) {
const advancedGroup = _.find(questions, {
name: 'advanced',
isGroup: true,
});
if (advancedGroup != null) {
override = helpers.getGroupDefaults(advancedGroup);
}
}
return getCliForm().run(questions, { override });
};
const $buildConfig = function (image, deviceTypeSlug, advanced) {
if (advanced == null) {
advanced = false;
}
const Bluebird = require('bluebird');
const helpers = require('../utils/helpers');
return Bluebird.resolve(
helpers.getManifest(image, deviceTypeSlug),
).then((deviceTypeManifest) =>
buildConfigForDeviceType(deviceTypeManifest, advanced),
);
};
export const buildConfig = {
signature: 'os build-config <image> <device-type>',
description: 'build the OS config and save it to the JSON file',
help: `\
Use this command to prebuild the OS config once and skip the interactive part of \`balena os configure\`.
Example:
$ balena os build-config ../path/rpi3.img raspberrypi3 --output rpi3-config.json
$ balena os configure ../path/rpi3.img --device 7cf02a6 --config rpi3-config.json\
`,
permission: 'user',
options: [
commandOptions.advancedConfig,
{
signature: 'output',
description: 'the path to the output JSON file',
alias: 'o',
required: 'the output path is required',
parameter: 'output',
},
],
action(params, options) {
return $buildConfig(
params.image,
params['device-type'],
options.advanced,
).then((answers) =>
require('fs').promises.writeFile(
options.output,
JSON.stringify(answers, null, 4),
),
);
},
};
const INIT_WARNING_MESSAGE = `\
Note: Initializing the device may ask for administrative permissions
because we need to access the raw devices directly.\
`;
export const initialize = {
signature: 'os initialize <image>',
description: 'initialize an os image',
help: `\
Use this command to initialize a device with previously configured operating system image.
${INIT_WARNING_MESSAGE}
Examples:
$ balena os initialize ../path/rpi.img --type 'raspberry-pi'\
`,
permission: 'user',
options: [
commandOptions.yes,
{
signature: 'type',
description:
'device type (Check available types with `balena devices supported`)',
parameter: 'type',
alias: 't',
required: 'You have to specify a device type',
},
commandOptions.drive,
],
action(params, options) {
const Bluebird = require('bluebird');
const umountAsync = Bluebird.promisify(require('umount').umount);
const patterns = require('../utils/patterns');
const helpers = require('../utils/helpers');
console.info(`\
Initializing device
${INIT_WARNING_MESSAGE}\
`);
return Bluebird.resolve(helpers.getManifest(params.image, options.type))
.then((manifest) =>
getCliForm().run(manifest.initialization?.options, {
override: {
drive: options.drive,
},
}),
)
.tap(function (answers) {
if (answers.drive == null) {
return;
}
return patterns
.confirm(
options.yes,
`This will erase ${answers.drive}. Are you sure?`,
`Going to erase ${answers.drive}.`,
true,
)
.then(() => umountAsync(answers.drive));
})
.tap((answers) =>
helpers.sudo([
'internal',
'osinit',
params.image,
options.type,
JSON.stringify(answers),
]),
)
.then(function (answers) {
if (answers.drive == null) {
return;
}
// TODO: balena local makes use of ejectAsync, see below
// DO we need this / should we do that here?
// getDrive = (drive) ->
// driveListAsync().then (drives) ->
// selectedDrive = _.find(drives, device: drive)
// if not selectedDrive?
// throw new Error("Drive not found: #{drive}")
// return selectedDrive
// if (os.platform() is 'win32') and selectedDrive.mountpoint?
// ejectAsync = Promise.promisify(require('removedrive').eject)
// return ejectAsync(selectedDrive.mountpoint)
return umountAsync(answers.drive).tap(() => {
console.info(`You can safely remove ${answers.drive} now`);
});
});
},
};

View File

@ -1,419 +0,0 @@
/*
Copyright 2016-2020 Balena
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import * as _ from 'lodash';
import { getBalenaSdk, getVisuals, getCliForm } from '../utils/lazy';
import * as dockerUtils from '../utils/docker';
const isCurrent = (commit) => commit === 'latest' || commit === 'current';
let allDeviceTypes;
const getDeviceTypes = function () {
const Bluebird = require('bluebird');
if (allDeviceTypes !== undefined) {
return Bluebird.resolve(allDeviceTypes);
}
const balena = getBalenaSdk();
return balena.models.config
.getDeviceTypes()
.then((deviceTypes) => _.sortBy(deviceTypes, 'name'))
.tap((dt) => {
allDeviceTypes = dt;
});
};
const getDeviceTypesWithSameArch = function (deviceTypeSlug) {
return getDeviceTypes().then(function (deviceTypes) {
const deviceType = _.find(deviceTypes, { slug: deviceTypeSlug });
return _(deviceTypes).filter({ arch: deviceType.arch }).map('slug').value();
});
};
const getApplicationsWithSuccessfulBuilds = function (deviceType) {
const balenaPreload = require('balena-preload');
const balena = getBalenaSdk();
return getDeviceTypesWithSameArch(deviceType).then((deviceTypes) => {
/** @type {import('balena-sdk').PineOptionsFor<import('balena-sdk').Application>} */
const options = {
$filter: {
device_type: {
$in: deviceTypes,
},
owns__release: {
$any: {
$alias: 'r',
$expr: {
r: {
status: 'success',
},
},
},
},
},
$expand: balenaPreload.applicationExpandOptions,
$select: [
'id',
'app_name',
'device_type',
'commit',
'should_track_latest_release',
],
$orderby: 'app_name asc',
};
return balena.pine.get({
resource: 'my_application',
options,
});
});
};
const selectApplication = function (deviceType) {
const visuals = getVisuals();
const { exitWithExpectedError } = require('../errors');
const applicationInfoSpinner = new visuals.Spinner(
'Downloading list of applications and releases.',
);
applicationInfoSpinner.start();
return getApplicationsWithSuccessfulBuilds(deviceType).then(function (
applications,
) {
applicationInfoSpinner.stop();
if (applications.length === 0) {
exitWithExpectedError(
`You have no apps with successful releases for a '${deviceType}' device type.`,
);
}
return getCliForm().ask({
message: 'Select an application',
type: 'list',
choices: applications.map((app) => ({
name: app.app_name,
value: app,
})),
});
});
};
const selectApplicationCommit = function (releases) {
const { exitWithExpectedError } = require('../errors');
if (releases.length === 0) {
exitWithExpectedError('This application has no successful releases.');
}
const DEFAULT_CHOICE = { name: 'current', value: 'current' };
const choices = [DEFAULT_CHOICE].concat(
releases.map((release) => ({
name: `${release.end_timestamp} - ${release.commit}`,
value: release.commit,
})),
);
return getCliForm().ask({
message: 'Select a release',
type: 'list',
default: 'current',
choices,
});
};
const offerToDisableAutomaticUpdates = function (
application,
commit,
pinDevice,
) {
const Bluebird = require('bluebird');
const balena = getBalenaSdk();
if (
isCurrent(commit) ||
!application.should_track_latest_release ||
pinDevice
) {
return Bluebird.resolve();
}
const message = `\
This application is set to automatically update all devices to the current version.
This might be unexpected behavior: with this enabled, the preloaded device will still
download and install the current release once it is online.
Do you want to disable automatic updates for this application?
Warning: To re-enable this requires direct api calls,
see https://balena.io/docs/reference/api/resources/device/#set-device-to-release
Alternatively you can pass the --pin-device-to-release flag to pin only this device to the selected release.\
`;
return getCliForm()
.ask({
message,
type: 'confirm',
})
.then(function (update) {
if (!update) {
return;
}
return balena.pine.patch({
resource: 'application',
id: application.id,
body: {
should_track_latest_release: false,
},
});
});
};
const preloadOptions = dockerUtils.appendConnectionOptions([
{
signature: 'app',
parameter: 'appId',
description: 'id of the application to preload',
alias: 'a',
},
{
signature: 'commit',
parameter: 'hash',
description: `\
The commit hash for a specific application release to preload, use "current" to specify the current
release (ignored if no appId is given). The current release is usually also the latest, but can be
manually pinned using https://github.com/balena-io-projects/staged-releases .\
`,
alias: 'c',
},
{
signature: 'splash-image',
parameter: 'splashImage.png',
description: 'path to a png image to replace the splash screen',
alias: 's',
},
{
signature: 'dont-check-arch',
boolean: true,
description:
'Disables check for matching architecture in image and application',
},
{
signature: 'pin-device-to-release',
boolean: true,
description:
'Pin the preloaded device to the preloaded release on provision',
alias: 'p',
},
{
signature: 'add-certificate',
parameter: 'certificate.crt',
description: `\
Add the given certificate (in PEM format) to /etc/ssl/certs in the preloading container.
The file name must end with '.crt' and must not be already contained in the preloader's
/etc/ssl/certs folder.
Can be repeated to add multiple certificates.\
`,
},
]);
// Remove dockerPort `-p` alias as it conflicts with pin-device-to-release
delete _.find(preloadOptions, { signature: 'dockerPort' }).alias;
export const preload = {
signature: 'preload <image>',
description: 'preload an app on a disk image (or Edison zip archive)',
help: `\
Preload a balena application release (app images/containers), and optionally
a balenaOS splash screen, in a previously downloaded '.img' balenaOS image file
in the local disk (a zip file is only accepted for the Intel Edison device type).
After preloading, the balenaOS image file can be flashed to a device's SD card.
When the device boots, it will not need to download the application, as it was
preloaded.
Warning: "balena preload" requires Docker to be correctly installed in
your shell environment. For more information (including Windows support)
check: https://github.com/balena-io/balena-cli/blob/master/INSTALL.md
Examples:
$ balena preload balena.img --app 1234 --commit e1f2592fc6ee949e68756d4f4a48e49bff8d72a0 --splash-image image.png
$ balena preload balena.img\
`,
permission: 'user',
primary: true,
options: preloadOptions,
action(params, options, done) {
const balena = getBalenaSdk();
const balenaPreload = require('balena-preload');
const visuals = getVisuals();
const nodeCleanup = require('node-cleanup');
const { exitWithExpectedError } = require('../errors');
const progressBars = {};
const progressHandler = function (event) {
let progressBar = progressBars[event.name];
if (!progressBar) {
progressBar = progressBars[event.name] = new visuals.Progress(
event.name,
);
}
return progressBar.update({ percentage: event.percentage });
};
const spinners = {};
const spinnerHandler = function (event) {
let spinner = spinners[event.name];
if (!spinner) {
spinner = spinners[event.name] = new visuals.Spinner(event.name);
}
if (event.action === 'start') {
return spinner.start();
} else {
console.log();
return spinner.stop();
}
};
options.commit = isCurrent(options.commit) ? 'latest' : options.commit;
options.image = params.image;
options.appId = options.app;
delete options.app;
options.splashImage = options['splash-image'];
delete options['splash-image'];
options.dontCheckArch = options['dont-check-arch'] || false;
delete options['dont-check-arch'];
if (options.dontCheckArch && !options.appId) {
exitWithExpectedError(
'You need to specify an app id if you disable the architecture check.',
);
}
options.pinDevice = options['pin-device-to-release'] || false;
delete options['pin-device-to-release'];
let certificates;
if (Array.isArray(options['add-certificate'])) {
certificates = options['add-certificate'];
} else if (options['add-certificate'] === undefined) {
certificates = [];
} else {
certificates = [options['add-certificate']];
}
for (let certificate of certificates) {
if (!certificate.endsWith('.crt')) {
exitWithExpectedError('Certificate file name must end with ".crt"');
}
}
// Get a configured dockerode instance
return dockerUtils.getDocker(options).then(function (docker) {
const preloader = new balenaPreload.Preloader(
balena,
docker,
options.appId,
options.commit,
options.image,
options.splashImage,
options.proxy,
options.dontCheckArch,
options.pinDevice,
certificates,
);
let gotSignal = false;
nodeCleanup(function (_exitCode, signal) {
if (signal) {
gotSignal = true;
nodeCleanup.uninstall(); // don't call cleanup handler again
preloader.cleanup().then(() => {
// calling process.exit() won't inform parent process of signal
process.kill(process.pid, signal);
});
return false;
}
});
if (process.env.DEBUG) {
preloader.stderr.pipe(process.stderr);
}
preloader.on('progress', progressHandler);
preloader.on('spinner', spinnerHandler);
return new Promise(function (resolve, reject) {
preloader.on('error', reject);
return preloader
.prepare()
.then(() => {
// If no appId was provided, show a list of matching apps
if (!preloader.appId) {
return selectApplication(
preloader.config.deviceType,
).then((application) => preloader.setApplication(application));
}
})
.then(() => {
// Use the commit given as --commit or show an interactive commit selection menu
if (options.commit) {
if (isCurrent(options.commit) && preloader.application.commit) {
// handle `--commit current` (and its `--commit latest` synonym)
return 'latest';
}
const release = _.find(preloader.application.owns__release, (r) =>
r.commit.startsWith(options.commit),
);
if (!release) {
exitWithExpectedError(
'There is no release matching this commit',
);
}
return release.commit;
}
return selectApplicationCommit(preloader.application.owns__release);
})
.then(function (commit) {
if (isCurrent(commit)) {
preloader.commit = preloader.application.commit;
} else {
preloader.commit = commit;
}
// Propose to disable automatic app updates if the commit is not the current release
return offerToDisableAutomaticUpdates(
preloader.application,
commit,
options.pinDevice,
);
})
.then(() =>
// All options are ready: preload the image.
preloader.preload(),
)
.catch(balena.errors.BalenaError, exitWithExpectedError)
.then(resolve)
.catch(reject);
})
.then(done)
.finally(function () {
if (!gotSignal) {
return preloader.cleanup();
}
});
});
},
};

View File

@ -1,448 +0,0 @@
/*
Copyright 2016-2020 Balena Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import type { BalenaSDK } from 'balena-sdk';
import type { CommandDefinition } from 'capitano';
import { ExpectedError } from '../errors';
import { getBalenaSdk, stripIndent } from '../utils/lazy';
import { dockerignoreHelp, registrySecretsHelp } from '../utils/messages';
import {
validateApplicationName,
validateDotLocalUrl,
validateIPAddress,
} from '../utils/validation';
import { isV12 } from '../utils/version';
enum BuildTarget {
Cloud,
Device,
}
function getBuildTarget(appOrDevice: string): BuildTarget | null {
// First try the application regex from the api
if (validateApplicationName(appOrDevice)) {
return BuildTarget.Cloud;
}
if (validateIPAddress(appOrDevice) || validateDotLocalUrl(appOrDevice)) {
return BuildTarget.Device;
}
return null;
}
async function getAppOwner(sdk: BalenaSDK, appName: string) {
const { selectFromList } = await import('../utils/patterns');
const _ = await import('lodash');
const applications = await sdk.models.application.getAll({
$expand: {
user: {
$select: ['username'],
},
},
$filter: {
$eq: [{ $tolower: { $: 'app_name' } }, appName.toLowerCase()],
},
$select: ['id'],
});
if (applications == null || applications.length === 0) {
throw new ExpectedError(
stripIndent`
No applications found with name: ${appName}.
This could mean that the application does not exist, or you do
not have the permissions required to access it.`,
);
}
if (applications.length === 1) {
return _.get(applications, '[0].user[0].username');
}
// If we got more than one application with the same name it means that the
// 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
// name (user/appname) and allows them to select
const entries = _.map(applications, (app) => {
const username = _.get(app, 'user[0].username');
return {
name: `${username}/${appName}`,
extra: username,
};
});
const selected = await selectFromList(
`${entries.length} applications found with that name, please select the application you would like to push to`,
entries,
);
return selected.extra;
}
export const push: CommandDefinition<
{
// when Capitano converts a positional parameter (but not an option)
// to a number, the original value is preserved with the _raw suffix
applicationOrDevice: string;
applicationOrDevice_raw: string;
},
{
source?: string;
emulated?: boolean;
dockerfile?: string; // DeviceDeployOptions.dockerfilePath (alternative Dockerfile)
nocache?: boolean;
'noparent-check'?: boolean;
'registry-secrets'?: string;
gitignore?: boolean;
nogitignore?: boolean;
nolive?: boolean;
detached?: boolean;
service?: string | string[];
system?: boolean;
env?: string | string[];
'convert-eol'?: boolean;
'noconvert-eol'?: boolean;
'multi-dockerignore'?: boolean;
}
> = {
signature: 'push <applicationOrDevice>',
primary: true,
description:
'Start a remote build on the balena cloud build servers or a local mode device',
help: stripIndent`
This command can be used to start a build on the remote balena cloud builders,
or a local mode balena device.
When building on the balenaCloud servers, the given source directory will be
sent to the remote server. This can be used as a drop-in replacement for the
"git push" deployment method.
When building on a local mode device, the given source directory will be
built on the device, and the resulting containers will be run on the device.
Logs will be streamed back from the device as part of the same invocation.
The web dashboard can be used to switch a device to local mode:
https://www.balena.io/docs/learn/develop/local-mode/
Note that local mode requires a supervisor version of at least v7.21.0.
The logs from only a single service can be shown with the --service flag, and
showing only the system logs can be achieved with --system. Note that these
flags can be used together.
When pushing to a local device a live session will be started.
The project source folder is watched for filesystem events, and changes
to files and folders are automatically synchronized to the running
containers. The synchronization is only in one direction, from this machine to
the device, and changes made on the device itself may be overwritten.
This feature requires a device running supervisor version v9.7.0 or greater.
${registrySecretsHelp.split('\n').join('\n\t\t')}
${dockerignoreHelp.split('\n').join('\n\t\t')}
Examples:
$ balena push myApp
$ balena push myApp --source <source directory>
$ balena push myApp -s <source directory>
$ balena push 10.0.0.1
$ balena push 10.0.0.1 --source <source directory>
$ balena push 10.0.0.1 --service my-service
$ balena push 10.0.0.1 --env MY_ENV_VAR=value --env my-service:SERVICE_VAR=value
$ balena push 10.0.0.1 --nolive
$ balena push 23c73a1.local --system
$ balena push 23c73a1.local --system --service my-service
`,
options: [
{
signature: 'source',
alias: 's',
description:
'Source directory to be sent to balenaCloud or balenaOS device (default: current working dir)',
parameter: 'source',
},
{
signature: 'emulated',
alias: 'e',
description: 'Force an emulated build to occur on the remote builder',
boolean: true,
},
{
signature: 'dockerfile',
parameter: 'Dockerfile',
description:
'Alternative Dockerfile name/path, relative to the source folder',
},
{
signature: 'nocache',
alias: 'c',
description: stripIndent`
Don't use cached layers of previously built images for this project. This ensures
that the latest base image and packages are pulled. Note that build logs may still
display the message _"Pulling previous images for caching purposes" (as the cloud
builder needs previous images to compute delta updates), but the logs will not
display the "Using cache" lines for each build step of a Dockerfile.`,
boolean: true,
},
{
signature: 'noparent-check',
description:
"Disable project validation check of 'docker-compose.yml' file in parent folder",
boolean: true,
},
{
signature: 'registry-secrets',
alias: 'R',
parameter: 'secrets.yml|.json',
description: stripIndent`
Path to a local YAML or JSON file containing Docker registry passwords used to pull base images.
Note that if registry-secrets are not provided on the command line, a secrets configuration
file from the balena directory will be used (usually $HOME/.balena/secrets.yml|.json)`,
},
{
signature: 'nolive',
boolean: true,
description: stripIndent`
Don't run a live session on this push. The filesystem will not be monitored, and changes
will not be synchronized to any running containers. Note that both this flag and --detached
and required to cause the process to end once the initial build has completed.`,
},
{
signature: 'detached',
alias: 'd',
description: stripIndent`
When pushing to the cloud, this option will cause the build to start, then return execution
back to the shell, with the status and release ID (if applicable).
When pushing to a local mode device, this option will cause the command to not tail application logs when the build
has completed.`,
boolean: true,
},
{
signature: 'service',
description: stripIndent`
Reject logs not originating from this service.
This can be used in combination with --system and other --service flags.
Only valid when pushing to a local mode device.`,
parameter: 'service',
},
{
signature: 'system',
description: stripIndent`
Only show system logs. This can be used in combination with --service.
Only valid when pushing to a local mode device.`,
boolean: true,
},
{
signature: 'env',
parameter: 'env',
description: stripIndent`
When performing a push to device, run the built containers with environment
variables provided with this argument. Environment variables can be applied
to individual services by adding their service name before the argument,
separated by a colon, e.g:
--env main:MY_ENV=value
Note that if the service name cannot be found in the composition, the entire
left hand side of the = character will be treated as the variable name.
`,
},
{
signature: 'convert-eol',
alias: 'l',
description: isV12()
? 'No-op and deprecated since balena CLI v12.0.0'
: stripIndent`
On Windows only, convert line endings from CRLF (Windows format) to LF (Unix format).
Source files are not modified.`,
boolean: true,
},
...(isV12()
? [
{
signature: 'noconvert-eol',
description:
"Don't convert line endings from CRLF (Windows format) to LF (Unix format).",
boolean: true,
},
]
: []),
{
signature: 'multi-dockerignore',
alias: 'm',
description:
'Have each service use its own .dockerignore file. See "balena help push".',
boolean: true,
},
{
signature: 'nogitignore',
alias: 'G',
description:
'No-op (default behavior) since balena CLI v12.0.0. See "balena help push".',
boolean: true,
},
{
signature: 'gitignore',
alias: 'g',
description: stripIndent`
Consider .gitignore files in addition to the .dockerignore file. This reverts
to the CLI v11 behavior/implementation (deprecated) if compatibility is required
until your project can be adapted.`,
boolean: true,
},
],
async action(params, options) {
const sdk = getBalenaSdk();
const Bluebird = await import('bluebird');
const remote = await import('../utils/remote-build');
const deviceDeploy = await import('../utils/device/deploy');
const { checkLoggedIn } = await import('../utils/patterns');
const { validateProjectDirectory } = await import('../utils/compose_ts');
const { BuildError } = await import('../utils/device/errors');
const appOrDevice: string | null =
params.applicationOrDevice_raw || params.applicationOrDevice;
if (appOrDevice == null) {
throw new ExpectedError('You must specify an application or a device');
}
if (options.gitignore && options['multi-dockerignore']) {
throw new ExpectedError(
'The --gitignore and --multi-dockerignore options cannot be used together',
);
}
const source = options.source || '.';
if (process.env.DEBUG) {
console.error(`[debug] Using ${source} as build source`);
}
const { dockerfilePath, registrySecrets } = await validateProjectDirectory(
sdk,
{
dockerfilePath: options.dockerfile,
noParentCheck: options['noparent-check'] || false,
projectPath: source,
registrySecretsPath: options['registry-secrets'],
},
);
const nogitignore = !options.gitignore;
const convertEol = isV12()
? !options['noconvert-eol']
: !!options['convert-eol'];
const buildTarget = getBuildTarget(appOrDevice);
switch (buildTarget) {
case BuildTarget.Cloud:
// Ensure that the live argument has not been passed to a cloud build
if (options.nolive != null) {
throw new ExpectedError(
'The --nolive flag is only valid when pushing to a local mode device',
);
}
if (options.service) {
throw new ExpectedError(
'The --service flag is only valid when pushing to a local mode device.',
);
}
if (options.system) {
throw new ExpectedError(
'The --system flag is only valid when pushing to a local mode device.',
);
}
if (options.env) {
throw new ExpectedError(
'The --env flag is only valid when pushing to a local mode device.',
);
}
const app = appOrDevice;
await checkLoggedIn();
const [token, baseUrl, owner] = await Promise.all([
sdk.auth.getToken(),
sdk.settings.get('balenaUrl'),
getAppOwner(sdk, app),
]);
const opts = {
dockerfilePath,
emulated: options.emulated || false,
multiDockerignore: options['multi-dockerignore'] || false,
nocache: options.nocache || false,
registrySecrets,
headless: options.detached || false,
convertEol,
};
const args = {
app,
owner,
source,
auth: token,
baseUrl,
nogitignore,
sdk,
opts,
};
await remote.startRemoteBuild(args);
break;
case BuildTarget.Device:
const device = appOrDevice;
const servicesToDisplay =
options.service != null
? Array.isArray(options.service)
? options.service
: [options.service]
: undefined;
// TODO: Support passing a different port
await Bluebird.resolve(
deviceDeploy.deployToDevice({
source,
deviceHost: device,
dockerfilePath,
registrySecrets,
multiDockerignore: options['multi-dockerignore'] || false,
nocache: options.nocache || false,
nogitignore,
noParentCheck: options['noparent-check'] || false,
nolive: options.nolive || false,
detached: options.detached || false,
services: servicesToDisplay,
system: options.system || false,
env:
typeof options.env === 'string'
? [options.env]
: options.env || [],
convertEol,
}),
).catch(BuildError, (e) => {
throw new ExpectedError(e.toString());
});
break;
default:
throw new ExpectedError(
stripIndent`
Build target not recognized. Please provide either an application name or device address.
The only supported device addresses currently are IP addresses.
If you believe your build target should have been detected, and this is an error, please
create an issue.`,
);
}
},
};

View File

@ -1,104 +0,0 @@
/*
Copyright 2016-2020 Balena
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import * as capitano from 'capitano';
import * as actions from './actions';
import * as events from './events';
import { promisify } from 'util';
capitano.permission('user', (done) =>
require('./utils/patterns').checkLoggedIn().then(done, done),
);
capitano.command({
signature: '*',
action(_params, _options, done) {
capitano.execute({ command: 'help' }, done);
process.exitCode = process.exitCode || 1;
},
});
capitano.globalOption({
signature: 'help',
boolean: true,
alias: 'h',
});
capitano.globalOption({
signature: 'version',
boolean: true,
alias: 'v',
});
// ---------- Help Module ----------
capitano.command(actions.help.help);
// ---------- OS Module ----------
capitano.command(actions.os.versions);
capitano.command(actions.os.download);
capitano.command(actions.os.buildConfig);
capitano.command(actions.os.initialize);
// ---------- Config Module ----------
capitano.command(actions.config.read);
capitano.command(actions.config.write);
capitano.command(actions.config.inject);
capitano.command(actions.config.reconfigure);
capitano.command(actions.config.generate);
// ---------- Preload Module ----------
capitano.command(actions.preload);
// ---------- Local balenaOS Module ----------
capitano.command(actions.local.configure);
// ------------ Local build and deploy -------
capitano.command(actions.build);
capitano.command(actions.deploy);
// ------------ Push/remote builds -------
capitano.command(actions.push.push);
export function run(argv: string[]) {
const cli = capitano.parse(argv.slice(2));
const runCommand = function () {
const capitanoExecuteAsync = promisify(capitano.execute);
if (cli.global?.help) {
return capitanoExecuteAsync({
command: `help ${cli.command ?? ''}`,
});
} else {
return capitanoExecuteAsync(cli);
}
};
const trackCommand = function () {
const getMatchCommandAsync = promisify(capitano.state.getMatchCommand);
return getMatchCommandAsync(cli.command).then(function (command) {
// cmdSignature is literally a string like, for example:
// "push <applicationOrDevice>"
// ("applicationOrDevice" is NOT replaced with its actual value)
// In case of failures like an nonexistent or invalid command,
// command.signature.toString() returns '*'
const cmdSignature = command.signature.toString();
return events.trackCommand(cmdSignature);
});
};
return Promise.all([trackCommand(), runCommand()]).catch(
require('./errors').handleError,
);
}

View File

@ -1,61 +0,0 @@
/**
* @license
* Copyright 2019 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Main } from '@oclif/command';
import { trackPromise } from './hooks/prerun/track';
class CustomMain extends Main {
protected _helpOverride(): boolean {
// Disable oclif's default handler for the 'version' command
if (['-v', '--version', 'version'].includes(this.argv[0])) {
return false;
} else {
return super._helpOverride();
}
}
}
import type { AppOptions } from './preparser';
/**
* oclif CLI entrypoint
*/
export async function run(command: string[], options: AppOptions) {
const runPromise = CustomMain.run(command).then(
() => {
if (!options.noFlush) {
return require('@oclif/command/flush');
}
},
(error) => {
// oclif sometimes exits with ExitError code 0 (not an error)
// (Avoid `error instanceof ExitError` here for the reasons explained
// in the CONTRIBUTING.md file regarding the `instanceof` operator.)
if (error.oclif?.exit === 0) {
return;
} else {
throw error;
}
},
);
try {
await Promise.all([trackPromise, runPromise]);
} catch (err) {
await (await import('./errors')).handleError(err);
}
}

View File

@ -1,87 +0,0 @@
/**
* @license
* Copyright 2019 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* CLI entrypoint, but see also `bin/balena` and `bin/balena-dev` which
* call this function.
*/
export async function run(
cliArgs = process.argv,
options: import('./preparser').AppOptions = {},
) {
// DEBUG set to falsy for negative values else is truthy
process.env.DEBUG = ['0', 'no', 'false', '', undefined].includes(
process.env.DEBUG?.toLowerCase(),
)
? ''
: '1';
// The 'pkgExec' special/internal command provides a Node.js interpreter
// for use of the standalone zip package. See pkgExec function.
if (cliArgs.length > 3 && cliArgs[2] === 'pkgExec') {
return pkgExec(cliArgs[3], cliArgs.slice(4));
}
const { globalInit } = await import('./app-common');
const { routeCliFramework } = await import('./preparser');
// globalInit() must be called very early on (before other imports) because
// it sets up Sentry error reporting, global HTTP proxy settings, balena-sdk
// shared options, and performs node version requirement checks.
await globalInit();
await routeCliFramework(cliArgs, options);
// Windows fix: reading from stdin prevents the process from exiting
process.stdin.pause();
}
/**
* Implements the 'pkgExec' command, used as a way to provide a Node.js
* interpreter for child_process.spawn()-like operations when the CLI is
* executing as a standalone zip package (built-in Node interpreter) and
* the system may not have a separate Node.js installation. A present use
* case is a patched version of the 'windosu' package that requires a
* Node.js interpreter to spawn a privileged child process.
*
* @param modFunc Path to a JS module that will be executed via require().
* The modFunc argument may optionally contain a function name separated
* by '::', for example '::main' in:
* 'C:\\snapshot\\balena-cli\\node_modules\\windosu\\lib\\pipe.js::main'
* in which case that function is executed in the require'd module.
* @param args Optional arguments to passed through process.argv and as
* arguments to the function specified via modFunc.
*/
async function pkgExec(modFunc: string, args: string[]) {
const [modPath, funcName] = modFunc.split('::');
let replacedModPath = modPath;
const match = modPath
.replace(/\\/g, '/')
.match(/\/snapshot\/balena-cli\/(.+)/);
if (match) {
replacedModPath = `../${match[1]}`;
}
process.argv = [process.argv[0], process.argv[1], ...args];
try {
const mod: any = await import(replacedModPath);
if (funcName) {
await mod[funcName](...args);
}
} catch (err) {
console.error(`Error executing pkgExec "${modFunc}" [${args.join()}]`);
console.error(err);
}
}

View File

@ -1,110 +0,0 @@
/*
Copyright 2016-2020 Balena
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import * as bodyParser from 'body-parser';
import * as express from 'express';
import type { Socket } from 'net';
import * as path from 'path';
import * as utils from './utils';
import { ExpectedError } from '../errors';
const serverSockets: Socket[] = [];
const createServer = ({ port }: { port: number }) => {
const app = express();
app.use(
bodyParser.urlencoded({
extended: true,
}),
);
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'pages'));
const server = app.listen(port);
server.on('connection', (socket) => serverSockets.push(socket));
return { app, server };
};
/**
* By design (more like a bug, but they won't admit it), a Node.js `http.server`
* instance prevents the process from exiting for up to 2 minutes (by default) if a
* client keeps a HTTP connection open, and regardless of whether `server.close()`
* was called: the `server.close(callback)` callback takes just as long to be called.
* Setting `server.timeout` to some value like 3 seconds works, but then the CLI
* process hangs for "only" 3 seconds (not good enough). Reducing the timeout to 1
* second may cause authentication failure if the laptop or CI server are slow for
* any reason. The only reliable way around it seems to be to explicitly unref the
* sockets, so the event loop stops waiting for it. See:
* https://github.com/nodejs/node/issues/2642
* https://github.com/nodejs/node-v0.x-archive/issues/9066
*/
export function shutdownServer() {
serverSockets.forEach((s) => s.unref());
serverSockets.splice(0);
}
/**
* @summary Await for token
* @function
* @protected
*
* @param {Object} options - options
* @param {String} options.path - callback path
* @param {Number} options.port - http port
*
* @example
* server.awaitForToken
* path: '/auth'
* port: 9001
* .then (token) ->
* console.log(token)
*/
export const awaitForToken = (options: {
path: string;
port: number;
}): Promise<string> => {
const { app, server } = createServer({ port: options.port });
return new Promise<string>((resolve, reject) => {
app.post(options.path, async (request, response) => {
server.close(); // stop listening for new connections
try {
const token = request.body.token?.trim();
if (!token) {
throw new ExpectedError('No token');
}
const loggedIn = await utils.loginIfTokenValid(token);
if (!loggedIn) {
throw new ExpectedError('Invalid token');
}
response.status(200).render('success');
resolve(token);
} catch (error) {
response.status(401).render('error');
reject(new Error(error.message));
}
});
app.use((_request, response) => {
server.close(); // stop listening for new connections
response.status(404).send('Not found');
reject(new Error('Unknown path or verb'));
});
});
};

View File

@ -1,93 +0,0 @@
/*
Copyright 2016 Balena
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import * as Bluebird from 'bluebird';
import * as _ from 'lodash';
import * as url from 'url';
import { getBalenaSdk } from '../utils/lazy';
/**
* @summary Get dashboard CLI login URL
* @function
* @protected
*
* @param {String} callbackUrl - callback url
* @fulfil {String} - dashboard login url
* @returns {Bluebird}
*
* @example
* utils.getDashboardLoginURL('http://127.0.0.1:3000').then (url) ->
* console.log(url)
*/
export const getDashboardLoginURL = (callbackUrl: string) => {
// Encode percentages signs from the escaped url
// characters to avoid angular getting confused.
callbackUrl = encodeURIComponent(callbackUrl).replace(/%/g, '%25');
return getBalenaSdk()
.settings.get('dashboardUrl')
.then((dashboardUrl) =>
url.resolve(dashboardUrl, `/login/cli/${callbackUrl}`),
);
};
/**
* @summary Log in using a token, but only if the token is valid
* @function
* @protected
*
* @description
* This function checks that the token is not only well-structured
* but that it also authenticates with the server successfully.
*
* If authenticated, the token is persisted, if not then the previous
* login state is restored.
*
* @param {String} token - session token or api key
* @fulfil {Boolean} - whether the login was successful or not
* @returns {Bluebird}
*
* utils.loginIfTokenValid('...').then (loggedIn) ->
* if loggedIn
* console.log('Token is valid!')
*/
export const loginIfTokenValid = (token: string) => {
if (_.isEmpty(token?.trim())) {
return Bluebird.resolve(false);
}
const balena = getBalenaSdk();
return balena.auth
.getToken()
.catchReturn(undefined)
.then((currentToken) =>
balena.auth
.loginWithToken(token)
.return(token)
.then(balena.auth.isLoggedIn)
.tap((isLoggedIn) => {
if (isLoggedIn) {
return;
}
if (currentToken != null) {
return balena.auth.loginWithToken(currentToken);
} else {
return balena.auth.logout();
}
}),
);
};

View File

@ -1,111 +0,0 @@
/**
* @license
* Copyright 2020 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import Command from '@oclif/command';
import { InsufficientPrivilegesError } from './errors';
export default abstract class BalenaCommand extends Command {
/**
* When set to true, command will be listed in `help`,
* otherwise listed in `help --verbose` with secondary commands.
*/
public static primary = false;
/**
* Require elevated privileges to run.
* When set to true, command will exit with an error
* if executed without root on Mac/Linux
* or if executed by non-Administrator on Windows.
*/
public static root = false;
/**
* Require authentication to run.
* When set to true, command will exit with an error
* if user is not already logged in.
*/
public static authenticated = false;
/**
* Accept piped input.
* When set to true, command will read from stdin during init
* and make contents available on member `stdin`.
*/
public static readStdin = false;
public stdin: string;
/**
* Throw InsufficientPrivilegesError if not root on Mac/Linux
* or non-Administrator on Windows.
*
* Called automatically if `root=true`.
* Can be called explicitly by command implementation, if e.g.:
* - check should only be done conditionally
* - other code needs to execute before check
*/
protected static async checkElevatedPrivileges() {
const isElevated = await (await import('is-elevated'))();
if (!isElevated) {
throw new InsufficientPrivilegesError(
'You need root/admin privileges to run this command',
);
}
}
/**
* Throw NotLoggedInError if not logged in.
*
* Called automatically if `authenticated=true`.
* Can be called explicitly by command implementation, if e.g.:
* - check should only be done conditionally
* - other code needs to execute before check
*
* Note, currently public to allow use outside of derived commands
* (as some command implementations require this. Can be made protected
* if this changes).
*/
public static async checkLoggedIn() {
await (await import('./utils/patterns')).checkLoggedIn();
}
/**
* Read stdin contents and make available to command.
*
* This approach could be improved in the future to automatically set argument
* values from stdin based in configuration, minimising command implementation.
*/
protected async getStdin() {
this.stdin = await (await import('get-stdin'))();
}
protected async init() {
const ctr = this.constructor as typeof BalenaCommand;
if (ctr.root) {
await BalenaCommand.checkElevatedPrivileges();
}
if (ctr.authenticated) {
await BalenaCommand.checkLoggedIn();
}
if (ctr.readStdin) {
await this.getStdin();
}
}
}

View File

@ -1,113 +0,0 @@
/**
* @license
* Copyright 2019-2020 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as _ from 'lodash';
import * as Mixpanel from 'mixpanel';
import * as packageJSON from '../package.json';
import { getBalenaSdk } from './utils/lazy';
const getMixpanel = _.once((balenaUrl: string) => {
return Mixpanel.init('balena-main', {
host: `api.${balenaUrl}`,
path: '/mixpanel',
protocol: 'https',
});
});
interface CachedUsername {
token: string;
username: string;
}
/**
* Mixpanel.com analytics tracking (information on balena CLI usage).
*
* @param commandSignature A string like, for example:
* "push <applicationOrDevice>"
* That's literally so: "applicationOrDevice" is NOT replaced with the actual
* application ID or device ID. The purpose is to find out the most / least
* used command verbs, so we can focus our development effort where it is most
* beneficial to end users.
*
* The username and command signature are also added as extra context
* information in Sentry.io error reporting, for CLI debugging purposes
* (mainly unexpected/unhandled exceptions -- see also `lib/errors.ts`).
*/
export async function trackCommand(commandSignature: string) {
try {
const Sentry = await import('@sentry/node');
Sentry.configureScope((scope) => {
scope.setExtra('command', commandSignature);
});
const settings = await import('balena-settings-client');
const balenaUrl = settings.get('balenaUrl') as string;
const username = await (async () => {
const getStorage = await import('balena-settings-storage');
const dataDirectory = settings.get('dataDirectory') as string;
const storage = getStorage({ dataDirectory });
let token;
try {
token = await storage.get('token');
} catch {
// If we can't get a token then we can't get a username
return;
}
try {
const result = (await storage.get('cachedUsername')) as CachedUsername;
if (result.token === token) {
return result.username;
}
} catch {
// ignore
}
try {
const balena = getBalenaSdk();
const $username = await balena.auth.whoami();
storage.set('cachedUsername', {
token,
username: $username,
} as CachedUsername);
return $username;
} catch {
return;
}
})();
const mixpanel = getMixpanel(balenaUrl);
Sentry.configureScope((scope) => {
scope.setUser({
id: username,
username,
});
});
// Don't actually call mixpanel.track() while running test cases
if (!process.env.BALENA_CLI_TEST_TYPE) {
await mixpanel.track(`[CLI] ${commandSignature}`, {
distinct_id: username,
version: packageJSON.version,
node: process.version,
arch: process.arch,
balenaUrl, // e.g. 'balena-cloud.com' or 'balena-staging.com'
platform: process.platform,
});
}
} catch {
// ignore
}
}

View File

@ -1,48 +0,0 @@
/**
* @license
* Copyright 2019-2020 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { Hook } from '@oclif/config';
let trackResolve: (result: Promise<any>) => void;
// note: trackPromise is subject to a Bluebird.timeout, defined in events.ts
export const trackPromise = new Promise((resolve) => {
trackResolve = resolve;
});
/**
* This is an oclif 'prerun' hook. This hook runs after the command line is
* parsed by oclif, but before the command's run() function is called.
* See: https://oclif.io/docs/hooks
*
* This hook is used to track CLI command signatures with mixpanel. This
* is the oclif version of what is already done for Capitano commands.
*
* A command signature is something like "env add NAME [VALUE]". That's
* literally so: 'NAME' and 'VALUE' are NOT replaced with actual values.
*/
const hook: Hook<'prerun'> = async function (options) {
const events = await import('../../events');
const usage: string | string[] | undefined = options.Command.usage;
const cmdSignature =
usage == null ? '*' : typeof usage === 'string' ? usage : usage.join(' ');
// Intentionally do not await for the track promise here, in order to
// run the command tracking and the command itself in parallel.
trackResolve(events.trackCommand(cmdSignature));
};
export default hook;

View File

@ -1,215 +0,0 @@
/**
* @license
* Copyright 2019 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { stripIndent } from './utils/lazy';
import { exitWithExpectedError } from './errors';
export interface AppOptions {
// Prevent the default behavior of flushing stdout after running a command
noFlush?: boolean;
}
/**
* Simple command-line pre-parsing to choose between oclif or Capitano.
* @param argv process.argv
*/
export async function routeCliFramework(argv: string[], options: AppOptions) {
if (process.env.DEBUG) {
console.log(
`[debug] original argv0="${process.argv0}" argv=[${argv}] length=${argv.length}`,
);
}
const cmdSlice = argv.slice(2);
// Look for commands that have been removed and if so, exit with a notice
checkDeletedCommand(cmdSlice);
if (cmdSlice.length > 0) {
// convert 'balena --version' or 'balena -v' to 'balena version'
if (['--version', '-v'].includes(cmdSlice[0])) {
cmdSlice[0] = 'version';
}
// convert 'balena --help' or 'balena -h' to 'balena help'
else if (['--help', '-h'].includes(cmdSlice[0])) {
cmdSlice[0] = 'help';
}
// convert e.g. 'balena help env add' to 'balena env add --help'
if (cmdSlice.length > 1 && cmdSlice[0] === 'help') {
cmdSlice.shift();
cmdSlice.push('--help');
}
// support global --debug flag
const debugIndex = cmdSlice.indexOf('--debug');
if (debugIndex > -1) {
process.env.DEBUG = '1';
cmdSlice.splice(debugIndex, 1);
}
}
// Enable bluebird long stack traces when in debug mode, must be set
// before the first bluebird require - done here so that it will also
// be enabled when using the `--debug` flag to enable debug mode
if (process.env.DEBUG) {
process.env.BLUEBIRD_LONG_STACK_TRACES = '1';
}
const Logger = await import('./utils/logger');
Logger.command = cmdSlice[0];
const [isOclif, isTopic] = isOclifCommand(cmdSlice);
if (isOclif) {
let oclifArgs = cmdSlice;
if (isTopic) {
// convert space-separated commands to oclif's topic:command syntax
oclifArgs = [cmdSlice[0] + ':' + cmdSlice[1], ...cmdSlice.slice(2)];
Logger.command = `${cmdSlice[0]} ${cmdSlice[1]}`;
}
if (process.env.DEBUG) {
console.log(
`[debug] new argv=[${[argv[0], argv[1], ...oclifArgs]}] length=${
oclifArgs.length + 2
}`,
);
}
await (await import('./app-oclif')).run(oclifArgs, options);
} else {
await (await import('./app-capitano')).run(argv);
}
}
/**
* Check whether the command line refers to a command that has been deprecated
* and removed and, if so, exit with an informative error message.
* @param argvSlice process.argv.slice(2)
*/
function checkDeletedCommand(argvSlice: string[]): void {
if (argvSlice[0] === 'help') {
argvSlice = argvSlice.slice(1);
}
function replaced(
oldCmd: string,
alternative: string,
version: string,
verb = 'replaced',
) {
exitWithExpectedError(stripIndent`
Note: the command "balena ${oldCmd}" was ${verb} in CLI version ${version}.
Please use "balena ${alternative}" instead.
`);
}
function removed(oldCmd: string, alternative: string, version: string) {
let msg = `Note: the command "balena ${oldCmd}" was removed in CLI version ${version}.`;
if (alternative) {
msg = [msg, alternative].join('\n');
}
exitWithExpectedError(msg);
}
const stopAlternative =
'Please use "balena ssh -s" to access the host OS, then use `balena-engine stop`.';
const cmds: { [cmd: string]: [(...args: any) => void, ...string[]] } = {
sync: [replaced, 'push', 'v11.0.0', 'removed'],
'local logs': [replaced, 'logs', 'v11.0.0'],
'local push': [replaced, 'push', 'v11.0.0'],
'local scan': [replaced, 'scan', 'v11.0.0'],
'local ssh': [replaced, 'ssh', 'v11.0.0'],
'local stop': [removed, stopAlternative, 'v11.0.0'],
};
let cmd: string | undefined;
if (argvSlice.length > 1) {
cmd = [argvSlice[0], argvSlice[1]].join(' ');
} else if (argvSlice.length > 0) {
cmd = argvSlice[0];
}
if (cmd && Object.getOwnPropertyNames(cmds).includes(cmd)) {
cmds[cmd][0](cmd, ...cmds[cmd].slice(1));
}
}
export const convertedCommands = [
'app',
'app:create',
'app:restart',
'app:rm',
'apps',
'api-key:generate',
'device',
'device:identify',
'device:init',
'device:move',
'device:os-update',
'device:public-url',
'device:reboot',
'device:register',
'device:rename',
'device:rm',
'device:shutdown',
'devices',
'devices:supported',
'envs',
'env:add',
'env:rename',
'env:rm',
'internal:scandevices',
'internal:osinit',
'join',
'keys',
'key',
'key:add',
'key:rm',
'leave',
'local:flash',
'login',
'logout',
'logs',
'note',
'os:configure',
'scan',
'settings',
'ssh',
'tags',
'tag:rm',
'tag:set',
'tunnel',
'util:available-drives',
'version',
'whoami',
];
/**
* Determine whether the CLI command has been converted from Capitano to oclif.
* Return an array of two boolean values:
* r[0] : whether the CLI command is implemented with oclif
* r[1] : if r[0] is true, whether the CLI command is implemented with
* oclif "topics" (colon-separated subcommands like `env:add`)
* @param argvSlice process.argv.slice(2)
*/
export function isOclifCommand(argvSlice: string[]): [boolean, boolean] {
// Look for commands that have been transitioned to oclif
// const { convertedCommands } = require('oclif/utils/command');
const arg0 = argvSlice.length > 0 ? argvSlice[0] : '';
const arg1 = argvSlice.length > 1 ? argvSlice[1] : '';
if (convertedCommands.includes(`${arg0}:${arg1}`)) {
return [true, true];
}
if (convertedCommands.includes(arg0)) {
return [true, false];
}
return [false, false];
}

View File

@ -1,108 +0,0 @@
/**
* @license
* Copyright 2019 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type * as SDK from 'balena-sdk';
import * as _ from 'lodash';
import { stripIndent } from './lazy';
import { ExpectedError } from '../errors';
export const serviceIdToName = _.memoize(
async (
sdk: SDK.BalenaSDK,
serviceId: number,
): Promise<string | undefined> => {
const serviceName = await sdk.pine.get<SDK.Service>({
resource: 'service',
id: serviceId,
options: {
$select: 'service_name',
},
});
if (serviceName != null) {
return serviceName.service_name;
}
return;
},
// Memoize the call based on service id
(_sdk, id) => id.toString(),
);
/**
* Return Device and Application objects for the given device UUID (short UUID
* or full UUID). An error is thrown if the application is not accessible, e.g.
* if the application owner removed the current user as a collaborator (but the
* device still belongs to the current user).
*/
export const getDeviceAndAppFromUUID = _.memoize(
async (
sdk: SDK.BalenaSDK,
deviceUUID: string,
selectDeviceFields?: Array<keyof SDK.Device>,
selectAppFields?: Array<keyof SDK.Application>,
): Promise<[SDK.Device, SDK.Application]> => {
const [device, app] = await getDeviceAndMaybeAppFromUUID(
sdk,
deviceUUID,
selectDeviceFields,
selectAppFields,
);
if (app == null) {
throw new ExpectedError(stripIndent`
Unable to access the application that device ${deviceUUID} belongs to.
Hint: check whether the application owner might have withdrawn access to it.
`);
}
return [device, app];
},
// Memoize the call based on UUID
(_sdk, deviceUUID) => deviceUUID,
);
/**
* Return a Device object and maybe an Application object for the given device
* UUID (short UUID or full UUID). The Application object may be undefined if
* the user / device lost access to the application, e.g. if the application
* owner removed the user as a collaborator (but the device still belongs to
* the current user).
*/
export const getDeviceAndMaybeAppFromUUID = _.memoize(
async (
sdk: SDK.BalenaSDK,
deviceUUID: string,
selectDeviceFields?: Array<keyof SDK.Device>,
selectAppFields?: Array<keyof SDK.Application>,
): Promise<[SDK.Device, SDK.Application | undefined]> => {
const pineOpts = {
$expand: selectAppFields
? { belongs_to__application: { $select: selectAppFields } }
: 'belongs_to__application',
} as SDK.PineOptionsFor<SDK.Device>;
if (selectDeviceFields) {
pineOpts.$select = selectDeviceFields as any;
}
const device = await sdk.models.device.get(deviceUUID, pineOpts);
const apps = device.belongs_to__application as SDK.Application[];
if (_.isEmpty(apps) || _.isEmpty(apps[0])) {
return [device, undefined];
}
return [device, apps[0]];
},
// Memoize the call based on UUID
(_sdk, deviceUUID) => deviceUUID,
);

View File

@ -1,67 +0,0 @@
/**
* @license
* Copyright 2019 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { flags } from '@oclif/command';
import type { IBooleanFlag } from '@oclif/parser/lib/flags';
export const application = flags.string({
char: 'a',
description: 'application name',
});
// TODO: Consider remove second alias 'app' when we can, to simplify.
export const app = flags.string({
description: "same as '--application'",
});
export const device = flags.string({
char: 'd',
description: 'device UUID',
});
export const help: IBooleanFlag<void> = flags.help({ char: 'h' });
export const quiet: IBooleanFlag<boolean> = flags.boolean({
char: 'q',
description: 'suppress warning messages',
default: false,
});
export const release = flags.string({
char: 'r',
description: 'release id',
});
export const service = flags.string({
char: 's',
description: 'service name',
});
export const verbose: IBooleanFlag<boolean> = flags.boolean({
char: 'v',
description: 'produce verbose output',
});
export const yes: IBooleanFlag<boolean> = flags.boolean({
char: 'y',
description: 'answer "yes" to all questions (non interactive use)',
});
export const force: IBooleanFlag<boolean> = flags.boolean({
char: 'f',
description: 'force action if the update lock is set',
});

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More