Compare commits

...

1262 Commits

Author SHA1 Message Date
40a980929a Update dependency @types/dockerode to v3.3.41
Update @types/dockerode from 3.3.23 to 3.3.41

Change-type: patch
2025-06-19 19:33:54 +00:00
3f9288e9d3 v22.1.1 2025-06-19 09:32:56 +00:00
0efa745628 Merge pull request #2957 from balena-io/truncate-error-message
Deploy: Limit the submitted error_message of images that fail to build to 300K characters
2025-06-19 09:31:58 +00:00
bddad252f7 Deploy: Limit the submitted error_message of images that fail to build to 1000 characters
Change-type: patch
See: https://balena.fibery.io/Work/Project/re-pitching-API-Limit-size-of-large-fields-975
2025-06-19 11:28:38 +03:00
a1a0e4f028 Deduplicate dependencies 2025-06-17 23:47:57 +03:00
de74baa2ff v22.1.0 2025-06-09 20:05:12 +00:00
6c12f755c5 Merge pull request #2955 from balena-io/node-22
Node 22
2025-06-09 17:04:26 -03:00
f80b8e63b1 Add support for node 22
Change-type: minor
2025-06-07 11:14:48 -03:00
b32514f5af Bump etcher-sdk to v10.0.0
Update balena-device-init from 8.1.3 to 8.1.1
Update etcher-sdk from 9.1.4 to 10.0.0
Update resin-cli-form from 3.0.0 to 4.0.0
Update resin-cli-visuals from 2.0.1 to 3.0.0

Change-type: patch
2025-06-07 11:13:55 -03:00
935f8d2549 v22.0.6 2025-06-02 12:27:13 +00:00
b2de857ef1 Merge pull request #2952 from balena-io/remove-request
Remove request
2025-06-02 08:26:26 -04:00
78f1471bf4 Deduplicate dependencies 2025-05-30 08:23:23 -04:00
d47abf072d Remove request dependency
Change-type: patch
2025-05-30 08:16:08 -04:00
8502c4db4b Replace request usage with got
Change-type: patch
2025-05-30 08:16:08 -04:00
dd2c5c40d7 v22.0.5 2025-05-29 15:47:35 +00:00
d23b253ac5 Merge pull request #2951 from balena-io/bump-etcher-sdk
Bump etcher-sdk to v9.1.4
2025-05-29 12:46:43 -03:00
0b0e24c9b2 Bump etcher-sdk to v9.1.4
Update etcher-sdk from 9.1.0 to 9.1.4

Change-type: patch
2025-05-29 10:54:45 -03:00
f9656cbe91 v22.0.4 2025-05-29 13:19:04 +00:00
e174f7db4c Merge pull request #2949 from balena-io/use-got-instead-of-request-legacy-deploy
Use got instead of request legacy deploy
2025-05-29 13:18:10 +00:00
a7a408a5c7 tests: Replace request with got
Change-type: patch
2025-05-29 09:35:57 -03:00
e5877c7de9 deploy-legacy: Replace request with got
Change-type: patch
2025-05-29 09:35:57 -03:00
ecb8b3ae6b v22.0.3 2025-05-29 12:09:59 +00:00
fd20516f69 Merge pull request #2950 from balena-io/bump-sentry-v9
Bump sentry to v9
2025-05-29 12:09:11 +00:00
5ccee0e4f1 Bump sentry to v9
Change-type: patch
2025-05-28 20:29:40 -03:00
7bb13a551c v22.0.2 2025-05-28 19:32:18 +00:00
19d287aefc Merge pull request #2948 from balena-io/build-nologs
fix: allow balena build to work with --nologs
2025-05-28 16:31:28 -03:00
8d10c1af2a Fix balena build to work with --nologs
Change-type: patch
2025-05-28 15:36:56 -03:00
ebfabdba6a v22.0.1 2025-05-28 17:00:48 +00:00
b0cbe43708 Merge pull request #2947 from balena-io/nock-14
Update `nock` to 14.0.4 & Move DeviceAPI off `request`
2025-05-28 13:59:58 -03:00
b7f1469912 Deduplicate dependencies 2025-05-28 12:08:37 -04:00
3396ba5a97 DeviceAPI: Move away from request in favor of BalenaSdk request
Change-type: patch
2025-05-28 12:08:37 -04:00
78ffff83bc Update nock to 14.0.4
Change-type: patch
2025-05-28 08:35:40 -04:00
ae13d584a3 v22.0.0 2025-05-26 13:53:39 +00:00
14f12d17eb Merge pull request #2912 from balena-io/native-build-2
Build standalone without pkg
2025-05-26 10:52:55 -03:00
45eb0ad4b1 Add migration guide to v22
Change-type: patch
2025-05-24 08:17:07 -03:00
21fd8a3307 Build standalone without pkg
Change-type: major
2025-05-23 18:52:51 -03:00
b545bd00ad v21.1.14 2025-05-21 15:39:23 +00:00
3eda7938f9 Merge pull request #2946 from balena-io/bump-balena-preload-2
Bump balena-preload to 18.0.4
2025-05-21 12:38:05 -03:00
2bccabfc38 Bump balena-preload to 18.0.4
Update balena-preload from 18.0.3 to 18.0.4

Change-type: patch
2025-05-21 11:41:07 -03:00
1b42d08567 v21.1.13 2025-05-21 13:46:34 +00:00
55b69be987 Merge pull request #2944 from balena-io/bump-balena-preload
Bump balena-preload to 18.0.3
2025-05-21 13:45:38 +00:00
7c8ce1b1a9 Bump balena-preload to 18.0.3
Update balena-preload from 18.0.1 to 18.0.3

Change-type: patch
2025-05-21 09:58:51 -03:00
31ddacec4c v21.1.12 2025-05-16 18:54:51 +00:00
dad26328b9 Merge pull request #2935 from balena-io/fix-build-secrets-serialization
Fix build secrets serialization
2025-05-16 14:54:04 -04:00
98197eef47 Dedupe dependencies 2025-05-15 19:13:36 -04:00
0f8ce47ec6 Update @balena/compose dependency to fix error with build secrets.
See https://github.com/balena-io-modules/balena-compose/pull/79

Change-type: patch
Signed-off-by: Ken Bannister <kb2ma@runbox.com>
2025-05-15 19:03:04 -04:00
33d3be326a v21.1.11 2025-05-06 15:25:00 +00:00
3eb397de1b Merge pull request #2611 from balena-io/lmb/fix-typos
Fix typos in the help messages
2025-05-06 15:24:01 +00:00
457b81a597 Deduplicate dependencies 2025-05-06 10:57:39 -04:00
8eb1777437 Fix typos in os configure and config generate help messages
Change-type: patch
2025-05-06 09:08:01 -04:00
bbc08dcfc5 v21.1.10 2025-05-05 17:13:26 +00:00
48cee061f4 Merge pull request #2937 from balena-io/fix-windows-signing
patch: fix windows signing
2025-05-05 17:12:40 +00:00
37e96e5d67 patch: fix windows signing 2025-05-05 13:38:05 -03:00
a5c865b7f9 v21.1.9 2025-04-07 12:53:22 +00:00
3fb3dd5819 Merge pull request #2929 from balena-io/update-balena-config-json
Update balena-config-json to rely on the balena-image-fs helpers
2025-04-07 15:52:21 +03:00
daf5c518fb Deduplicate dependencies 2025-04-04 10:38:24 +03:00
4fcedd0607 Update balena-config-json to rely on the balena-image-fs helpers
Update balena-config-json from 4.2.2 to 4.2.7
Update balena-image-fs from 7.5.0 to 7.5.2

Change-type: patch
2025-04-04 10:23:39 +03:00
42d9cbb48d v21.1.8 2025-04-03 16:10:05 +00:00
408efa91c1 Merge pull request #2933 from balena-io/renovate/actions-download-artifact-4.1.x
Update actions/download-artifact action to v4.1.9
2025-04-03 16:09:08 +00:00
a2209ffe56 Update actions/download-artifact action to v4.1.9
Update actions/download-artifact from 4.1.8 to 4.1.9

Change-type: patch
2025-04-03 15:50:05 +00:00
3f27db811b v21.1.7 2025-04-03 15:12:16 +00:00
839a3050fb Merge pull request #2932 from balena-io/renovate/actions-upload-artifact-digest
Update actions/upload-artifact digest to ea165f8
2025-04-03 15:11:18 +00:00
c8ea9cfcdb Update actions/upload-artifact digest to ea165f8
Update actions/upload-artifact

Change-type: patch
2025-04-03 14:50:26 +00:00
776115ef5d v21.1.6 2025-04-03 14:12:08 +00:00
f031ec1dea Merge pull request #2931 from balena-io/renovate/actions-setup-node-digest
Update actions/setup-node digest to cdca736
2025-04-03 14:11:10 +00:00
fe42438090 Update actions/setup-node digest to cdca736
Update actions/setup-node

Change-type: patch
2025-04-03 13:50:06 +00:00
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
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
336 changed files with 57878 additions and 35564 deletions

6
.gitattributes vendored
View File

@ -4,9 +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

View File

@ -67,7 +67,7 @@ fixed it.
- **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
- **Install method:** npm or standalone package or executable installer
- **If npm install, Node.js and npm version:** e.g. Node v8.16.0 and npm v6.4.1
# Additional References

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

@ -0,0 +1,145 @@
---
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: '22.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@cc203385981b70ca67e1cc392babf9cc229d5806 # v4.1.9
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@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # 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
smctl.exe windows certsync
/c/Windows/System32/certutil.exe -csp "DigiCert Signing Manager KSP" -key -user
# (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@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: gh-release-${{ github.event.pull_request.head.sha || github.event.head_commit.id }}-${{ strategy.job-index }}
path: |
dist
!dist/balena
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: '22.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@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # 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@ea165f8d65b6e75b540449e92b4886f43607fa02 # 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

1
.husky/pre-commit Normal file
View File

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

View File

@ -2,6 +2,9 @@ module.exports = {
reporter: 'spec',
require: 'ts-node/register/transpile-only',
file: './tests/config-tests',
timeout: 12000,
timeout: 48000,
// 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,17 +0,0 @@
---
npm:
platforms:
- name: linux
os: ubuntu
architecture: x86_64
node_versions:
- "10"
- "12"
- "14"
- name: linux
os: alpine
architecture: x86_64
node_versions:
- "10"
- "12"
- "14"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,7 @@ The balena CLI is an open source project and your contribution is welcome!
In order to ease development:
* `npm run build:fast` skips some of the build steps for interactive testing, or
* `npm run test:source` skips testing the standalone zip packages (which is rather slow)
* `npm run test:source` skips testing the standalone packages (which is rather slow)
* `./bin/balena-dev` uses `ts-node/register` to transpile on the fly.
Before opening a PR, test your changes with `npm test`. Keep compatibility in mind, as the CLI is
@ -105,26 +105,72 @@ npm run update balena-sdk ^13.0.0 major
## Editing documentation files (README, INSTALL, Reference website...)
The `doc/cli.markdown` file is automatically generated by running `npm run build:doc` (which also
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](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 (`lib/commands/` folder), for example:
* `lib/commands/push.ts`
* `lib/commands/env/add.ts`
* 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).
**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
Besides the regular npm installation dependencies, the `npm run build:installer` script
@ -177,7 +223,7 @@ 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 `lib/fast-boot.ts` to automatically invalidate the cache if
`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:
@ -267,4 +313,3 @@ gotchas to bear in mind:
replace: `spec: 'tests/**/*.spec.ts',`
with: `spec: ['tests/auth/*.spec.ts', 'tests/**/deploy.spec.ts'],`

View File

@ -8,8 +8,8 @@ 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.
* [Standalone tar.gz Package](#standalone-targz-package): these are plain tar.gz files with the balena CLI
bundled within. 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.
@ -30,9 +30,9 @@ instructions:
> 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
If you had previously installed the CLI using a standalone tar 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
entry that comes first. Check the [Standalone tar.gz Package](#standalone-targz-package) instructions
for how to modify the PATH variable.
By default, the CLI is installed to the following folders:
@ -40,20 +40,19 @@ 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`
macOS: | `/usr/local/src/balena-cli/` <br> `/usr/local/bin/balena`
## Standalone Zip Package
## Standalone tar.gz Package
1. Download the latest zip file from the [releases page](https://github.com/balena-io/balena-cli/releases).
1. Download the latest tar.gz 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`
`balena-cli-vX.Y.Z-linux-x64-standalone.tar.gz`_also for the Windows Subsystem for Linux_
`balena-cli-vX.Y.Z-macOS-x64-standalone.tar.gz`
`balena-cli-vX.Y.Z-windows-x64-standalone.tar.gz`
2. Extract the zip file contents to any folder you choose. The extracted contents will include a
`balena-cli` folder.
2. Extract the tar.gz file contents to any folder you choose. The extracted contents will be a `balena` folder containing a `bin` subdirectory.
3. Add the `balena-cli` folder to the system's `PATH` environment variable.
3. Add the `balena/bin` 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) |
@ -61,14 +60,14 @@ macOS: | `/usr/local/lib/balena-cli/` <br> `/usr/local/bin/balena`
> * 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
> * **Linux Alpine** and **Busybox:** the standalone tar.gz 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
> * Note that moving the `balena/bin/balena` executable out of the extracted `balena` 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.
> folders and files also present in the `balena` folder.
To update the CLI to a new version, download a new release zip file and replace the previous
To update the CLI to a new version, download a new release tar.gz file and replace the previous
installation folder. To uninstall, simply delete the folder and edit the PATH environment variable
as described above.
@ -78,8 +77,8 @@ If you are a Node.js developer, you may wish to install the balena CLI via [npm]
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 10 (min 10.20.0) or 12.**
> **Versions 13 and later are not yet fully supported.**
> **The balena CLI currently requires Node.js version >=20.6.0**
> **Versions 23 and later are not yet fully supported.**
### Install development tools
@ -89,7 +88,7 @@ some development tools to be installed first, as follows.
$ 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 12
$ nvm install 22
```
The `curl` command line above uses
@ -106,15 +105,15 @@ recommended.
```sh
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash
$ . ~/.bashrc
$ nvm install 12
$ nvm install 22
```
#### **Windows** (not WSL)
Install:
* Node.js v12 from the [Nodejs.org releases page](https://nodejs.org/en/download/releases/).
* If you'd like the ability to switch between Node.js versions, install
- Node.js v22 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:
@ -145,7 +144,7 @@ container) in order to allow npm scripts like `postinstall` to be executed.
## Additional Dependencies
The `balena ssh`, `scan`, `build`, `deploy` and `preload` commands may require
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:

View File

@ -8,15 +8,15 @@ method.
Selected operating system: **Linux**
1. Download the latest zip file from the [latest release
1. Download the latest tar.gz 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`
with "-standalone.tar.gz", for example:
`balena-cli-vX.Y.Z-linux-x64-standalone.tar.gz`
2. Extract the zip file contents to any folder you choose, for example `/home/james`.
The extracted contents will include a `balena-cli` folder.
2. Extract the tar.gz file contents to any folder you choose, for example `/home/james`.
The extracted contents will include a `balena/bin` folder.
3. Add that folder (e.g. `/home/james/balena-cli`) to the `PATH` environment variable.
3. Add that folder (e.g. `/home/james/balena/bin`) 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`
@ -27,13 +27,13 @@ Selected operating system: **Linux**
* `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
To update the balena CLI to a new version, download a new release tar.gz 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 scan`.
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:
@ -61,19 +61,19 @@ instructions](https://docs.docker.com/install/overview/) to install Docker on th
workstation as the balena CLI. The [advanced installation
options](./INSTALL-ADVANCED.md#additional-dependencies) document describes other possibilities.
### balena ssh
### balena device ssh
The `balena ssh` command requires the `ssh` command-line tool to be available. Most Linux
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 ssh` command also requires an SSH key to be added to your balena account: see [SSH
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 scan
### balena device detect
The `balena scan` command requires a multicast DNS (mDNS) service like
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`.

View File

@ -7,8 +7,8 @@ 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`
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.
@ -19,7 +19,7 @@ Selected operating system: **macOS**
- 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 ssh`, `build`, `deploy`
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.
@ -27,7 +27,7 @@ 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/lib/balena-cli/bin/uninstall
sudo /usr/local/src/balena-cli/bin/uninstall
```
## Additional Dependencies
@ -41,9 +41,9 @@ instructions](https://docs.docker.com/install/overview/) to install Docker on th
workstation as the balena CLI. The [advanced installation
options](./INSTALL-ADVANCED.md#additional-dependencies) document describes other possibilities.
### balena ssh
### balena device ssh
The `balena ssh` command requires the `ssh` command-line tool to be available. To check whether
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:
@ -52,7 +52,7 @@ include:
Components → Command Line Tools → Install.
* Or, install [Homebrew](https://brew.sh/), then `brew install openssh`
The `balena ssh` command also requires an SSH key to be added to your balena account: see [SSH
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`.

View File

@ -8,7 +8,7 @@ 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`
`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.
@ -19,7 +19,7 @@ Selected operating system: **Windows**
- 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 ssh`, `scan`, `build`,
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.
@ -34,9 +34,9 @@ instructions](https://docs.docker.com/install/overview/) to install Docker on th
workstation as the balena CLI. The [advanced installation
options](./INSTALL-ADVANCED.md#additional-dependencies) document describes other possibilities.
### balena ssh
### balena device ssh
The `balena ssh` command requires the `ssh` command-line tool to be available. Microsoft started
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
@ -44,13 +44,13 @@ installed](https://docs.microsoft.com/en-us/windows-server/administration/openss
if needed. For older versions of Windows, there are several ssh/OpenSSH clients provided by 3rd
parties.
The `balena ssh` command also requires an SSH key to be added to your balena account: see [SSH
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 scan
### balena device detect
The `balena scan` command requires a multicast DNS (mDNS) service like Apple's Bonjour.
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

45
MIGRATIONS.md Normal file
View File

@ -0,0 +1,45 @@
## Migrating to balena CLI v22
This guide outlines the changes introduced in balena CLI v22 and provides instructions for when and how to migrate.
---
### For Installer Users (Windows .exe, macOS .pkg)
If you are using the Windows executable (.exe) or macOS package (.pkg) installers, **no changes** are required for this update. You can continue to use the installers as before.
---
### For npm Installation Users
If you installed balena CLI via npm, **no changes** are required for this update. Your existing installation and update process remains the same.
---
### For Standalone Installation Users
Users of the standalone balena CLI will need to make the following adjustments:
1. **Archive Format Change**: The distribution archive format has changed from `.zip` to `.tar.gz`. You will need to use the `tar` command instead of `unzip` to extract the CLI.
* **Previous command (v21.x.x and older):**
```bash
unzip balena-cli-v21.1.12-linux-x64-standalone.zip
```
* **New command (v22.0.0 and newer):**
```bash
tar -xzf balena-cli-v22.0.0-linux-x64-standalone.tar.gz
```
2. **Executable Path Change**: The path to the balena CLI executable within the extracted folder has been updated.
* **Previous path (v21.x.x and older):**
```
balena-cli/balena
```
* **New path (v22.0.0 and newer):**
```
balena/bin/balena
```
Please update your scripts and any aliases to reflect these changes if you are using the standalone version.

View File

@ -20,6 +20,8 @@ GitHub](https://github.com/balena-io/balena-cli/), and your contribution is also
Check the [balena CLI installation instructions on
GitHub](https://github.com/balena-io/balena-cli/blob/master/INSTALL.md).
Note for v22 Migration: If you are upgrading to balena CLI v22 from a previous standalone installation, please [see the v22 Migration Guide](https://github.com/balena-io/balena-cli/blob/master/MIGRATIONS.md) for installation changes.
## Choosing a shell (command prompt/terminal)
On **Windows,** the standard Command Prompt (`cmd.exe`) and
@ -88,9 +90,9 @@ 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`.
### Proxy setup for balena ssh
### Proxy setup for balena device ssh
In order to work behind a proxy server, the `balena ssh` command requires the
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
@ -110,7 +112,7 @@ The `BALENARC_NO_PROXY` variable may be used to exclude specified destinations f
> * 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
@ -144,7 +146,7 @@ To learn more, troubleshoot issues, or to contact us for support:
* 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 through the [balenaCloud forum](https://forums.balena.io/c/balena-cloud)
* 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/).

View File

@ -31,7 +31,7 @@ command again.
Check whether the SD card is locked (a physical switch on the side of the card).
## I get `connect ETIMEDOUT` with `balena tunnel`
## I get `connect ETIMEDOUT` with `balena device tunnel`
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
@ -79,10 +79,10 @@ 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`
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`
@ -115,7 +115,7 @@ 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" will, by default, attempt to reach the
tar.gz 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:

View File

@ -15,38 +15,25 @@
* limitations under the License.
*/
import type { JsonVersions } from '../lib/commands/version';
import { run as oclifRun } from '@oclif/dev-cli';
import * as archiver from 'archiver';
import * as Bluebird from 'bluebird';
import { execFile } from 'child_process';
import * as filehound from 'filehound';
import { Stats } from 'fs';
import { run as oclifRun } from '@oclif/core';
import { exec, execFile } from 'child_process';
import type { Stats } from 'fs';
import * as fs from 'fs-extra';
import * as klaw from 'klaw';
import * as _ from 'lodash';
import * as path from 'path';
import * as rimraf from 'rimraf';
import * as semver from 'semver';
import { promisify } from 'util';
import { notarize } from '@electron/notarize';
import { stripIndent } from '../build/utils/lazy';
import {
diffLines,
loadPackageJson,
ROOT,
StdOutTap,
whichSpawn,
} from './utils';
import { loadPackageJson, ROOT, 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;
const MSYS2_BASH =
process.env.MSYSSHELLPATH || 'C:\\msys64\\usr\\bin\\bash.exe';
function dPath(...paths: string[]) {
return path.join(ROOT, 'dist', ...paths);
@ -56,15 +43,13 @@ interface PathByPlatform {
[platform: string]: string;
}
const standaloneZips: PathByPlatform = {
linux: dPath(`balena-cli-${version}-linux-${arch}-standalone.zip`),
darwin: dPath(`balena-cli-${version}-macOS-${arch}-standalone.zip`),
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 = {
@ -72,249 +57,30 @@ const renamedOclifInstallers: PathByPlatform = {
win32: dPath(`balena-cli-${version}-windows-${arch}-installer.exe`),
};
export const finalReleaseAssets: { [platform: string]: string[] } = {
win32: [standaloneZips['win32'], renamedOclifInstallers['win32']],
darwin: [standaloneZips['darwin'], renamedOclifInstallers['darwin']],
linux: [standaloneZips['linux']],
const getOclifStandaloneOriginalNames = async (): Promise<PathByPlatform> => {
const { stdout } = await execAsync('git rev-parse --short HEAD');
const sha = stdout.trim();
return {
linux: dPath(`balena-${version}-${sha}-linux-${arch}.tar.gz`),
darwin: dPath(`balena-${version}-${sha}-darwin-${arch}.tar.gz`),
win32: dPath(`balena-${version}-${sha}-win32-${arch}.tar.gz`),
};
};
/**
* 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}.txt`,
);
const absSavedPath = path.join(ROOT, relSavedPath);
const ignoreStartsWith = [
'> pkg@',
'> Fetching base Node.js binaries',
' fetched-',
];
const modulesRE =
process.platform === 'win32'
? /(?<=[ '])([A-Z]:)?\\.+?\\node_modules(?=\\)/
: /(?<=[ '])\/.+?\/node_modules(?=\/)/;
const buildRE =
process.platform === 'win32'
? /(?<=[ '])([A-Z]:)?\\.+\\build(?=\\)/
: /(?<=[ '])\/.+\/build(?=\/)/;
const renamedOclifStandalone: PathByPlatform = {
linux: dPath(`balena-cli-${version}-linux-${arch}-standalone.tar.gz`),
darwin: dPath(`balena-cli-${version}-macOS-${arch}-standalone.tar.gz`),
win32: dPath(`balena-cli-${version}-windows-${arch}-standalone.tar.gz`),
};
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);
export async function signFilesForNotarization() {
console.log('Signing files for notarization');
// If signFilesForNotarization is called on the test CI environment (which will not set CSC_LINK)
// then we skip the signing process.
if (process.platform !== 'darwin' || !process.env.CSC_LINK) {
console.log('Skipping signing for notarization');
return;
}
}
/**
* 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('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.
* Also copy a number of native modules (binary '.node' files) that are
* compiled during 'npm install' to the 'build-bin' folder, alongside
* the single large executable file created by pkg. (This is necessary
* because of a pkg limitation that does not allow binary executables
* to be directly executed from inside another binary executable.)
*/
async function buildPkg() {
const args = [
'--target',
'host',
'--output',
'build-bin/balena',
'package.json',
];
console.log('=======================================================');
console.log(`execPkg ${args.join(' ')}`);
console.log(`cwd="${process.cwd()}" ROOT="${ROOT}"`);
console.log('=======================================================');
await execPkg(args);
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(
paths.map(([platform, source, dest]) => {
if (platform === '*' || platform === process.platform) {
// eg copy from node_modules/open/xdg-open to build-bin/xdg-open
return fs.copy(
path.join(ROOT, 'node_modules', ...source),
path.join(ROOT, 'build-bin', ...dest),
);
}
}),
);
const nativeExtensionPaths: string[] = await filehound
.create()
.paths(path.join(ROOT, 'node_modules'))
.ext(['node', 'dll'])
.find();
console.log(`\nCopying to build-bin:\n${nativeExtensionPaths.join('\n')}`);
await Promise.all(
nativeExtensionPaths.map((extPath) =>
fs.copy(
extPath,
extPath.replace(
path.join(ROOT, 'node_modules'),
path.join(ROOT, 'build-bin'),
),
),
),
);
}
/**
* Run some basic tests on the built pkg executable.
* TODO: test more than just `balena version -j`; integrate with the
* existing mocha/chai CLI command testing.
*/
async function testPkg() {
const pkgBalenaPath = path.join(
ROOT,
'build-bin',
process.platform === 'win32' ? 'balena.exe' : 'balena',
);
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)
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 {
const balenaVersions: JsonVersions = JSON.parse(stdout);
pkgNodeVersion = balenaVersions['Node.js'];
pkgNodeMajorVersion = semver.major(pkgNodeVersion);
} catch (err) {
throw new Error(stripIndent`
Error parsing JSON output of "balena version -j": ${err}
Original output: "${stdout}"`);
}
if (semver.major(process.version) !== pkgNodeMajorVersion) {
throw new Error(
`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)');
}
/**
* Create the zip file for the standalone 'pkg' bundle previously created
* by the buildPkg() function in 'build-bin.ts'.
*/
async function zipPkg() {
const outputFile = standaloneZips[process.platform];
if (!outputFile) {
throw new Error(
`Standalone installer unavailable for platform "${process.platform}"`,
);
}
await fs.mkdirp(path.dirname(outputFile));
await new Promise((resolve, reject) => {
console.log(`Zipping standalone package to "${outputFile}"...`);
const archive = archiver('zip', {
zlib: { level: 7 },
});
archive.directory(path.join(ROOT, 'build-bin'), 'balena-cli');
const outputStream = fs.createWriteStream(outputFile);
outputStream.on('close', resolve);
outputStream.on('error', reject);
archive.on('error', reject);
archive.on('warning', console.warn);
archive.pipe(outputStream);
archive.finalize();
});
}
async function signFilesForNotarization() {
console.log('Deleting unneeded zip files...');
await new Promise((resolve, reject) => {
klaw('node_modules/')
@ -322,6 +88,10 @@ async function signFilesForNotarization() {
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')
@ -396,20 +166,40 @@ async function signFilesForNotarization() {
]);
}
export async function buildStandaloneZip() {
console.log(`Building standalone zip package for CLI ${version}`);
export async function buildStandalone() {
console.log(`Building standalone tarball for CLI ${version}`);
fs.rmSync('./tmp', { recursive: true, force: true });
fs.rmSync('./dist', { recursive: true, force: true });
fs.mkdirSync('./dist');
try {
await buildPkg();
await testPkg();
await zipPkg();
console.log(`Standalone zip package build completed`);
let packOpts = ['-r', ROOT, '--no-xz'];
if (process.platform === 'darwin') {
packOpts = packOpts.concat('--targets', `darwin-${arch}`);
} else if (process.platform === 'win32') {
packOpts = packOpts.concat('--targets', 'win32-x64');
} else if (process.platform === 'linux') {
packOpts = packOpts.concat('--targets', `linux-${arch}`);
}
console.log(`Building oclif installer for CLI ${version}`);
const packCmd = `pack:tarballs`;
console.log('=======================================================');
console.log(`oclif ${packCmd} ${packOpts.join(' ')}`);
console.log(`cwd="${process.cwd()}" ROOT="${ROOT}"`);
console.log('=======================================================');
const oclifPath = path.join(ROOT, 'node_modules', 'oclif');
await oclifRun([packCmd].concat(...packOpts), oclifPath);
await renameStandalone();
console.log(`Standalone tarball package build completed`);
} catch (error) {
console.error(`Error creating or testing standalone zip package`);
console.error(`Error creating or testing standalone tarball package`);
throw error;
}
}
async function renameInstallerFiles() {
async function renameInstallers() {
const oclifInstallers = await getOclifInstallersOriginalNames();
if (await fs.pathExists(oclifInstallers[process.platform])) {
await fs.rename(
oclifInstallers[process.platform],
@ -418,22 +208,42 @@ async function renameInstallerFiles() {
}
}
async function renameStandalone() {
const oclifStandalone = await getOclifStandaloneOriginalNames();
if (await fs.pathExists(oclifStandalone[process.platform])) {
await fs.rename(
oclifStandalone[process.platform],
renamedOclifStandalone[process.platform],
);
}
}
/**
* 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) {
const exeName = renamedOclifInstallers[process.platform];
if (process.env.SM_CODE_SIGNING_CERT_SHA1_HASH) {
const exeName = (await getOclifInstallersOriginalNames())[process.platform];
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',
@ -445,18 +255,26 @@ async function signWindowsInstaller() {
* Wait for Apple Installer Notarization to continue
*/
async function notarizeMacInstaller(): Promise<void> {
const appleId = 'accounts+apple@balena.io';
const { notarize } = await import('electron-notarize');
await notarize({
appBundleId: 'io.balena.etcher',
appPath: renamedOclifInstallers.darwin,
appleId,
appleIdPassword: '@keychain:CLI_PASSWORD',
});
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;
const appPath = (await getOclifInstallersOriginalNames())[process.platform];
console.log(`Notarizing file "${appPath}"`);
if (appleIdPassword && teamId) {
await notarize({
tool: 'notarytool',
teamId,
appPath,
appleId,
appleIdPassword,
});
}
}
/**
* Run the `oclif-dev pack:win` or `pack:macos` command (depending on the value
* 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.
@ -466,9 +284,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}`);
@ -479,18 +298,14 @@ export async function buildOclifInstaller() {
}
for (const dir of dirs) {
console.log(`rimraf(${dir})`);
await Bluebird.fromCallback((cb) => rimraf(dir, cb));
}
if (process.platform === 'darwin') {
console.log('Signing files for notarization...');
await signFilesForNotarization();
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));
await renameInstallerFiles();
const oclifPath = path.join(ROOT, 'node_modules', 'oclif');
await oclifRun([packCmd].concat(...packOpts), oclifPath);
// The Windows installer is explicitly signed here (oclif doesn't do it).
// The macOS installer is automatically signed by oclif (which runs the
// `pkgbuild` tool), using the certificate name given in package.json
@ -502,6 +317,7 @@ export async function buildOclifInstaller() {
await notarizeMacInstaller(); // Notarize
console.log('Package notarized.');
}
await renameInstallers();
console.log(`oclif installer build completed`);
}
}
@ -537,4 +353,5 @@ export async function testShrinkwrap(): Promise<void> {
if (process.platform !== 'win32') {
await whichSpawn(path.resolve(__dirname, 'test-lock-deduplicated.sh'));
}
await Promise.resolve();
}

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,172 +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/commands/api-key/generate.js'],
},
{
title: 'Fleet',
files: [
'build/commands/apps.js',
'build/commands/fleets.js',
'build/commands/app/index.js',
'build/commands/fleet/index.js',
'build/commands/app/create.js',
'build/commands/fleet/create.js',
'build/commands/app/purge.js',
'build/commands/fleet/purge.js',
'build/commands/app/rename.js',
'build/commands/fleet/rename.js',
'build/commands/app/restart.js',
'build/commands/fleet/restart.js',
'build/commands/app/rm.js',
'build/commands/fleet/rm.js',
],
},
{
title: 'Authentication',
files: [
'build/commands/login.js',
'build/commands/logout.js',
'build/commands/whoami.js',
],
},
{
title: 'Device',
files: [
'build/commands/devices/index.js',
'build/commands/devices/supported.js',
'build/commands/device/index.js',
'build/commands/device/deactivate.js',
'build/commands/device/identify.js',
'build/commands/device/init.js',
'build/commands/device/local-mode.js',
'build/commands/device/move.js',
'build/commands/device/os-update.js',
'build/commands/device/public-url.js',
'build/commands/device/purge.js',
'build/commands/device/reboot.js',
'build/commands/device/register.js',
'build/commands/device/rename.js',
'build/commands/device/restart.js',
'build/commands/device/rm.js',
'build/commands/device/shutdown.js',
],
},
{
title: 'Environment Variables',
files: [
'build/commands/envs.js',
'build/commands/env/add.js',
'build/commands/env/rename.js',
'build/commands/env/rm.js',
],
},
{
title: 'Tags',
files: [
'build/commands/tags.js',
'build/commands/tag/rm.js',
'build/commands/tag/set.js',
],
},
{
title: 'Help and Version',
files: ['help', 'build/commands/version.js'],
},
{
title: 'Keys',
files: [
'build/commands/keys.js',
'build/commands/key/index.js',
'build/commands/key/add.js',
'build/commands/key/rm.js',
],
},
{
title: 'Logs',
files: ['build/commands/logs.js'],
},
{
title: 'Network',
files: [
'build/commands/scan.js',
'build/commands/ssh.js',
'build/commands/tunnel.js',
],
},
{
title: 'Notes',
files: ['build/commands/note.js'],
},
{
title: 'OS',
files: [
'build/commands/os/build-config.js',
'build/commands/os/configure.js',
'build/commands/os/versions.js',
'build/commands/os/download.js',
'build/commands/os/initialize.js',
],
},
{
title: 'Config',
files: [
'build/commands/config/generate.js',
'build/commands/config/inject.js',
'build/commands/config/read.js',
'build/commands/config/reconfigure.js',
'build/commands/config/write.js',
],
},
{
title: 'Preload',
files: ['build/commands/preload.js'],
},
{
title: 'Push',
files: ['build/commands/push.js'],
},
{
title: 'Settings',
files: ['build/commands/settings.js'],
},
{
title: 'Local',
files: [
'build/commands/local/configure.js',
'build/commands/local/flash.js',
],
},
{
title: 'Deploy',
files: ['build/commands/build.js', 'build/commands/deploy.js'],
},
{
title: 'Platform',
files: ['build/commands/join.js', 'build/commands/leave.js'],
},
{
title: 'Utilities',
files: ['build/commands/util/available-drives.js'],
},
{
title: 'Support',
files: ['build/commands/support.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.
@ -205,7 +145,7 @@ export async function getCapitanoDoc(): Promise<typeof capitanoDoc> {
throw new Error(`Error parsing section title`);
}
// match[1] has the title, match[2] has the rest
return match && match[2];
return match?.[2];
}),
mdParser.getSectionOfTitle('Installation'),
mdParser.getSectionOfTitle('Choosing a shell (command prompt/terminal)'),

View File

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

View File

@ -16,9 +16,8 @@
*/
import * as path from 'path';
import { getCapitanoDoc } from './capitanodoc';
import { Category, Document, OclifCommand } from './doc-types';
import type { Category, Document, OclifCommand } from './doc-types';
import * as markdown from './markdown';
import { stripIndent } from '../../lib/utils/lazy';
/**
* Generates the markdown document (as a string) for the CLI documentation
@ -39,7 +38,7 @@ export async function renderMarkdown(): Promise<string> {
};
for (const jsFilename of commandCategory.files) {
category.commands.push(...importOclifCommands(jsFilename));
category.commands.push(await importOclifCommands(jsFilename));
}
result.categories.push(category);
}
@ -47,49 +46,23 @@ export async function renderMarkdown(): Promise<string> {
return markdown.render(result);
}
// Help is now managed via a plugin
// This fake command allows capitanodoc to include help in docs
class FakeHelpCommand {
description = stripIndent`
List balena commands, or get detailed help for a specific command.
async function importOclifCommands(jsFilename: string) {
const command = (await import(path.join(process.cwd(), jsFilename)))
.default as OclifCommand;
List balena commands, or get detailed help for a specific command.
`;
examples = [
'$ balena help',
'$ balena help login',
'$ balena help os download',
];
args = [
{
name: 'command',
description: 'command to show help for',
},
];
usage = 'help [command]';
flags = {
verbose: {
description: 'show additional commands',
char: '-v',
},
};
}
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 =
jsFilename === 'help'
? (new FakeHelpCommand() as unknown as OclifCommand)
: (require(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];
}
/**
@ -105,4 +78,5 @@ async function printMarkdown() {
}
}
// eslint-disable-next-line @typescript-eslint/no-floating-promises
printMarkdown();

View File

@ -14,16 +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 { Category, Document, OclifCommand } from './doc-types';
import { capitanoizeOclifUsage } from '../../src/utils/oclif-utils';
import type { Category, Document } from './doc-types';
function renderOclifCommand(command: OclifCommand): string[] {
const result = [`## ${ent.encode(command.usage || '')}`];
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.`,
);
}
result.push('### Description');
const description = (command.description || '')
.split('\n')
.slice(1) // remove the first line, which oclif uses as help header
@ -37,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 || '');
}
}
@ -49,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();
@ -80,7 +95,7 @@ function renderToc(categories: Category[]): string[] {
result.push(
category.commands
.map((command) => {
const signature = capitanoizeOclifUsage(command.usage);
const signature = capitanoizeOclifUsage(command.name);
return `\t- [${ent.encode(signature)}](${getAnchor(signature)})`;
})
.join('\n'),
@ -89,33 +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<OclifCommand, string>(
manualCategorySorting[category.title],
(cmd: OclifCommand, x: string) =>
(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;

View File

@ -1,257 +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) {
throw new Error(`Error creating GitHub release:\n${err}`);
}
}
/** 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;
type Release =
import('@octokit/rest').RestEndpointMethodTypes['repos']['listReleases']['response']['data'][0];
for await (const response of octokit.paginate.iterator<Release>(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

@ -19,14 +19,11 @@ import * as _ from 'lodash';
import {
buildOclifInstaller,
buildStandaloneZip,
buildStandalone,
catchUncommitted,
signFilesForNotarization,
testShrinkwrap,
} from './build-bin';
import {
release,
updateDescriptionOfReleasesAffectedByIssue1359,
} from './deploy-bin';
// DEBUG set to falsy for negative values else is truthy
process.env.DEBUG = ['0', 'no', 'false', '', undefined].includes(
@ -39,8 +36,7 @@ process.env.DEBUG = ['0', 'no', 'false', '', undefined].includes(
* 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)
* 'build:standalone' (to build a standalone package)
*
* @param args Arguments to parse (default is process.argv.slice(2))
*/
@ -53,33 +49,17 @@ async function parse(args?: string[]) {
}
const commands: { [cmd: string]: () => void | Promise<void> } = {
'build:installer': buildOclifInstaller,
'build:standalone': buildStandaloneZip,
'build:standalone': buildStandalone,
'sign:binaries': signFilesForNotarization,
'catch-uncommitted': catchUncommitted,
'test-shrinkwrap': testShrinkwrap,
fix1359: updateDescriptionOfReleasesAffectedByIssue1359,
release,
};
for (const arg of args) {
if (!commands.hasOwnProperty(arg)) {
if (!Object.hasOwn(commands, arg)) {
throw new Error(`command unknown: ${arg}`);
}
}
// 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 {
const cmdFunc = commands[arg];
@ -103,4 +83,5 @@ export async function run(args?: string[]) {
}
}
// eslint-disable-next-line @typescript-eslint/no-floating-promises
run();

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':
@ -36,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);
});
};
@ -107,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');
@ -136,4 +136,4 @@ async function main() {
}
}
main();
void main();

View File

@ -16,76 +16,17 @@
*/
import { spawn } from 'child_process';
import * as _ from 'lodash';
import * as path from 'path';
import * as fs from 'fs';
import * as whichMod from 'which';
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 { diffTrimmedLines } = require('diff');
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');
const packageJson = fs.readFileSync(packageJsonPath, 'utf8');
return JSON.parse(packageJson);
}
/**
@ -98,7 +39,6 @@ export function loadPackageJson() {
* @returns The program's full path, e.g. 'C:\WINDOWS\System32\OpenSSH\ssh.EXE'
*/
export async function which(program: string): Promise<string> {
const whichMod = await import('which');
let programPath: string;
try {
programPath = await whichMod(program);
@ -117,7 +57,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;
@ -129,7 +69,7 @@ export async function whichSpawn(
.on('error', reject)
.on('close', resolve);
} catch (err) {
reject(err);
reject(err as Error);
}
});
} catch (err) {

View File

@ -1,23 +0,0 @@
#!/usr/bin/env node
// tslint:disable:no-var-requires
// 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();
}
run();

1
bin/balena Symbolic link
View File

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

View File

@ -1,89 +0,0 @@
#!/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
// ****************************************************************************
// tslint:disable:no-var-requires
// 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 lib/ 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,
});
require('../lib/app').run();
// Modify package.json oclif paths from build/ -> lib/, 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, '/lib/');
} else {
oclifSectionText = oclifSectionText.replace(/\/lib\//g, '/build/');
}
packageObj.oclif = JSON.parse(oclifSectionText);
fs.writeFileSync(
packageJsonPath,
`${JSON.stringify(packageObj, null, 2)}\n`,
'utf8',
);
}

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();

View File

@ -8,25 +8,28 @@ _balena() {
local context state line curcontext="$curcontext"
# Valid top-level completions
main_commands=( apps build deploy envs fleets join keys leave login logout logs note orgs preload push scan settings ssh support tags tunnel version whoami api-key app app config device device devices env fleet fleet internal key key local os tag util )
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 )
app_cmds=( create purge rename restart rm )
api_key_cmds=( generate list revoke )
app_cmds=( create )
block_cmds=( create )
config_cmds=( generate inject read reconfigure write )
device_cmds=( deactivate identify init local-mode move os-update public-url purge reboot register rename restart rm shutdown )
devices_cmds=( supported )
env_cmds=( add rename rm )
fleet_cmds=( create purge rename restart rm )
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 )
key_cmds=( add rm )
local_cmds=( configure flash )
organization_cmds=( list )
os_cmds=( build-config configure download initialize versions )
tag_cmds=( rm set )
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 *)'{-h,--help}'[show help options and exit]' \
'(- 1 *)--help[show help options and exit]' \
'1:first command:_balena_main_cmds' \
'2:second command:_balena_sec_cmds' \
&& ret=0
@ -46,15 +49,18 @@ _balena_sec_cmds() {
"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
;;
"devices")
_describe -t devices_cmds 'devices_cmd' devices_cmds "$@" && ret=0
;;
"env")
_describe -t env_cmds 'env_cmd' env_cmds "$@" && ret=0
;;
@ -64,15 +70,21 @@ _balena_sec_cmds() {
"internal")
_describe -t internal_cmds 'internal_cmd' internal_cmds "$@" && ret=0
;;
"key")
_describe -t key_cmds 'key_cmd' key_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
;;

View File

@ -7,20 +7,23 @@ _balena_complete()
local cur prev
# Valid top-level completions
main_commands="apps build deploy envs fleets join keys leave login logout logs note orgs preload push scan settings ssh support tags tunnel version whoami api-key app app config device device devices env fleet fleet internal key key local os tag util"
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"
app_cmds="create purge rename restart rm"
api_key_cmds="generate list revoke"
app_cmds="create"
block_cmds="create"
config_cmds="generate inject read reconfigure write"
device_cmds="deactivate identify init local-mode move os-update public-url purge reboot register rename restart rm shutdown"
devices_cmds="supported"
env_cmds="add rename rm"
fleet_cmds="create purge rename restart rm"
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"
key_cmds="add rm"
local_cmds="configure flash"
organization_cmds="list"
os_cmds="build-config configure download initialize versions"
tag_cmds="rm set"
release_cmds="finalize invalidate list validate"
ssh_key_cmds="add list rm"
tag_cmds="list rm set"
@ -40,15 +43,18 @@ _balena_complete()
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) )
;;
devices)
COMPREPLY=( $(compgen -W "$devices_cmds" -- $cur) )
;;
env)
COMPREPLY=( $(compgen -W "$env_cmds" -- $cur) )
;;
@ -58,15 +64,21 @@ _balena_complete()
internal)
COMPREPLY=( $(compgen -W "$internal_cmds" -- $cur) )
;;
key)
COMPREPLY=( $(compgen -W "$key_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) )
;;

View File

@ -31,9 +31,9 @@ if (fs.existsSync(commandsFilePath)) {
const commandsJson = JSON.parse(fs.readFileSync(commandsFilePath, 'utf8'));
var mainCommands = [];
var additionalCommands = [];
for (const key of Object.keys(commandsJson.commands)) {
const mainCommands = [];
const additionalCommands = [];
for (const key of Object.keys(commandsJson.commands).sort()) {
const cmd = key.split(':');
if (cmd.length > 1) {
additionalCommands.push(cmd);
@ -72,8 +72,8 @@ fs.readFile(bashFilePathIn, 'utf8', function (err, data) {
/\$main_commands\$/g,
'main_commands="' + mainCommandsStr + '"',
);
var subCommands = [];
var prevElement = additionalCommands[0][0];
let subCommands = [];
let prevElement = additionalCommands[0][0];
additionalCommands.forEach(function (element) {
if (element[0] === prevElement) {
subCommands.push(element[1]);
@ -134,8 +134,8 @@ fs.readFile(zshFilePathIn, 'utf8', function (err, data) {
/\$main_commands\$/g,
'main_commands=( ' + mainCommandsStr + ' )',
);
var subCommands = [];
var prevElement = additionalCommands[0][0];
let subCommands = [];
let prevElement = additionalCommands[0][0];
additionalCommands.forEach(function (element) {
if (element[0] === prevElement) {
subCommands.push(element[1]);

View File

@ -14,7 +14,7 @@ $sub_cmds$
_arguments -C \
'(- 1 *)--version[show version and exit]' \
'(- 1 *)'{-h,--help}'[show help options and exit]' \
'(- 1 *)--help[show help options and exit]' \
'1:first command:_balena_main_cmds' \
'2:second command:_balena_sec_cmds' \
&& ret=0

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 --fleet FLEET_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. `FLEET_ID`. Create a fleet (`balena fleet create FLEET_NAME --type DEVICE_TYPE`) or find an existing one (`balena fleets`) 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

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,132 +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).
*
* @throws {NotLoggedInError}
*/
public static async checkLoggedIn() {
await (await import('./utils/patterns')).checkLoggedIn();
}
/**
* Throw NotLoggedInError if not logged in when condition true.
*
* @param {boolean} doCheck - will check if true.
* @throws {NotLoggedInError}
*/
public static async checkLoggedInIf(doCheck: boolean) {
if (doCheck) {
await this.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'))();
}
/**
* Get a logger instance.
*/
protected static async getLogger() {
return (await import('./utils/logger')).getLogger();
}
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,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,181 +0,0 @@
/**
* @license
* Copyright 2016-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.
*/
import { flags } from '@oclif/command';
import type { Output as ParserOutput } from '@oclif/parser';
import type { Application } 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 { appToFleetCmdMsg, warnify } from '../../utils/messages';
interface FlagsDef {
organization?: string;
type?: string; // application device type
help: void;
}
interface ArgsDef {
name: string;
}
export class FleetCreateCmd extends Command {
public static description = stripIndent`
Create a fleet.
Create a new balena fleet.
You can specify the organization the fleet should belong to using
the \`--organization\` option. The organization's handle, not its name,
should be provided. Organization handles can be listed with the
\`balena orgs\` command.
The fleet's default device type is specified with the \`--type\` option.
The \`balena devices supported\` command can be used to list the available
device types.
Interactive dropdowns will be shown for selection if no device type or
organization is specified and there are multiple options to choose from.
If there is a single option to choose from, it will be chosen automatically.
This interactive behavior can be disabled by explicitly specifying a device
type and organization.
`;
public static examples = [
'$ balena fleet create MyFleet',
'$ balena fleet create MyFleet --organization mmyorg',
'$ balena fleet create MyFleet -o myorg --type raspberry-pi',
];
public static args = [
{
name: 'name',
description: 'fleet name',
required: true,
},
];
public static usage = 'fleet create <name>';
public static flags: flags.Input<FlagsDef> = {
organization: flags.string({
char: 'o',
description: 'handle of the organization the fleet should belong to',
}),
type: flags.string({
char: 't',
description:
'fleet device type (Check available types with `balena devices supported`)',
}),
help: cf.help,
};
public static authenticated = true;
public async run(parserOutput?: ParserOutput<FlagsDef, ArgsDef>) {
const { args: params, flags: options } =
parserOutput || this.parse<FlagsDef, ArgsDef>(FleetCreateCmd);
// Ascertain device type
const deviceType =
options.type ||
(await (await import('../../utils/patterns')).selectDeviceType());
// Ascertain organization
const organization =
options.organization?.toLowerCase() || (await this.getOrganization());
// Create application
let application: Application;
try {
application = await getBalenaSdk().models.application.create({
name: params.name,
deviceType,
organization,
});
} catch (err) {
if ((err.message || '').toLowerCase().includes('unique')) {
// BalenaRequestError: Request error: "organization" and "app_name" must be unique.
throw new ExpectedError(
`Error: fleet "${params.name}" already exists in organization "${organization}".`,
);
} else if ((err.message || '').toLowerCase().includes('unauthorized')) {
// BalenaRequestError: Request error: Unauthorized
throw new ExpectedError(
`Error: You are not authorized to create fleets in organization "${organization}".`,
);
}
throw err;
}
// Output
const { isV13 } = await import('../../utils/version');
console.log(
isV13()
? `Fleet created: slug "${application.slug}", device type "${deviceType}"`
: `Fleet created: ${application.slug} (${deviceType}, id ${application.id})`,
);
}
async getOrganization() {
const { getOwnOrganizations } = await import('../../utils/sdk');
const organizations = await getOwnOrganizations(getBalenaSdk());
if (organizations.length === 0) {
// User is not a member of any organizations (should not happen).
throw new Error('This account is not a member of any organizations');
} else if (organizations.length === 1) {
// User is a member of only one organization - use this.
return organizations[0].handle;
} else {
// User is a member of multiple organizations -
const { selectOrganization } = await import('../../utils/patterns');
return selectOrganization(organizations);
}
}
}
export default class AppCreateCmd extends FleetCreateCmd {
public static description = stripIndent`
DEPRECATED alias for the 'fleet create' command
${appToFleetCmdMsg
.split('\n')
.map((l) => `\t\t${l}`)
.join('\n')}
For command usage, see 'balena help fleet create'
`;
public static examples = [];
public static usage = 'app create <name>';
public static args = FleetCreateCmd.args;
public static flags = FleetCreateCmd.flags;
public static authenticated = FleetCreateCmd.authenticated;
public static primary = FleetCreateCmd.primary;
public async run() {
// call this.parse() before deprecation message to parse '-h'
const parserOutput = this.parse<FlagsDef, ArgsDef>(AppCreateCmd);
if (process.stderr.isTTY) {
console.error(warnify(appToFleetCmdMsg));
}
await super.run(parserOutput);
}
}

View File

@ -1,124 +0,0 @@
/**
* @license
* Copyright 2016-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.
*/
import type { flags } from '@oclif/command';
import type { Output as ParserOutput } from '@oclif/parser';
import type { Release } from 'balena-sdk';
import Command from '../../command';
import * as cf from '../../utils/common-flags';
import * as ca from '../../utils/common-args';
import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy';
import {
applicationIdInfo,
appToFleetCmdMsg,
warnify,
} from '../../utils/messages';
interface FlagsDef {
help: void;
}
interface ArgsDef {
fleet: string;
}
export class FleetCmd extends Command {
public static description = stripIndent`
Display information about a single fleet.
Display detailed information about a single fleet.
${applicationIdInfo.split('\n').join('\n\t\t')}
`;
public static examples = [
'$ balena fleet MyFleet',
'$ balena fleet myorg/myfleet',
];
public static args = [ca.fleetRequired];
public static usage = 'fleet <fleet>';
public static flags: flags.Input<FlagsDef> = {
help: cf.help,
};
public static authenticated = true;
public static primary = true;
public async run(parserOutput?: ParserOutput<FlagsDef, ArgsDef>) {
const { args: params } =
parserOutput || this.parse<FlagsDef, ArgsDef>(FleetCmd);
const { getApplication } = await import('../../utils/sdk');
const application = (await getApplication(getBalenaSdk(), params.fleet, {
$expand: {
is_for__device_type: { $select: 'slug' },
should_be_running__release: { $select: 'commit' },
},
})) as ApplicationWithDeviceType & {
should_be_running__release: [Release?];
// For display purposes:
device_type: string;
commit?: string;
};
application.device_type = application.is_for__device_type[0].slug;
application.commit = application.should_be_running__release[0]?.commit;
// Emulate table.vertical title output, but avoid uppercasing and inserting spaces
console.log(`== ${application.app_name}`);
console.log(
getVisuals().table.vertical(application, [
'id',
'device_type',
'slug',
'commit',
]),
);
}
}
export default class AppCmd extends FleetCmd {
public static description = stripIndent`
DEPRECATED alias for the 'fleet' command
${appToFleetCmdMsg
.split('\n')
.map((l) => `\t\t${l}`)
.join('\n')}
For command usage, see 'balena help fleet'
`;
public static examples = [];
public static usage = 'app <fleet>';
public static args = FleetCmd.args;
public static flags = FleetCmd.flags;
public static authenticated = FleetCmd.authenticated;
public static primary = FleetCmd.primary;
public async run() {
// call this.parse() before deprecation message to parse '-h'
const parserOutput = this.parse<FlagsDef, ArgsDef>(AppCmd);
if (process.stderr.isTTY) {
console.error(warnify(appToFleetCmdMsg));
}
await super.run(parserOutput);
}
}

View File

@ -1,104 +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 type { flags } from '@oclif/command';
import type { Output as ParserOutput } from '@oclif/parser';
import Command from '../../command';
import * as cf from '../../utils/common-flags';
import * as ca from '../../utils/common-args';
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
import {
applicationIdInfo,
appToFleetCmdMsg,
warnify,
} from '../../utils/messages';
interface FlagsDef {
help: void;
}
interface ArgsDef {
fleet: string;
}
export class FleetRestartCmd extends Command {
public static description = stripIndent`
Restart a fleet.
Restart all devices belonging to a fleet.
${applicationIdInfo.split('\n').join('\n\t\t')}
`;
public static examples = [
'$ balena fleet restart MyFleet',
'$ balena fleet restart myorg/myfleet',
];
public static args = [ca.fleetRequired];
public static usage = 'fleet restart <fleet>';
public static flags: flags.Input<FlagsDef> = {
help: cf.help,
};
public static authenticated = true;
public async run(parserOutput?: ParserOutput<FlagsDef, ArgsDef>) {
const { args: params } =
parserOutput || this.parse<FlagsDef, ArgsDef>(FleetRestartCmd);
const { getApplication } = await import('../../utils/sdk');
const balena = getBalenaSdk();
// Disambiguate application (if is a number, it could either be an ID or a numerical name)
const application = await getApplication(balena, params.fleet);
await balena.models.application.restart(application.id);
}
}
export default class AppRestartCmd extends FleetRestartCmd {
public static description = stripIndent`
DEPRECATED alias for the 'fleet restart' command
${appToFleetCmdMsg
.split('\n')
.map((l) => `\t\t${l}`)
.join('\n')}
For command usage, see 'balena help fleet restart'
`;
public static examples = [];
public static usage = 'app restart <fleet>';
public static args = FleetRestartCmd.args;
public static flags = FleetRestartCmd.flags;
public static authenticated = FleetRestartCmd.authenticated;
public static primary = FleetRestartCmd.primary;
public async run() {
// call this.parse() before deprecation message to parse '-h'
const parserOutput = this.parse<FlagsDef, ArgsDef>(AppRestartCmd);
if (process.stderr.isTTY) {
console.error(warnify(appToFleetCmdMsg));
}
await super.run(parserOutput);
}
}

View File

@ -1,134 +0,0 @@
/**
* @license
* Copyright 2016-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.
*/
import { flags } from '@oclif/command';
import type { Output as ParserOutput } from '@oclif/parser';
import Command from '../command';
import * as cf from '../utils/common-flags';
import { getBalenaSdk, getVisuals, stripIndent } from '../utils/lazy';
import { appToFleetCmdMsg, warnify } from '../utils/messages';
interface ExtendedApplication extends ApplicationWithDeviceType {
device_count?: number;
online_devices?: number;
}
interface FlagsDef {
help: void;
verbose?: boolean;
}
export class FleetsCmd extends Command {
public static description = stripIndent`
List all fleets.
List all your balena fleets.
For detailed information on a particular fleet, use
\`balena fleet <fleet>\`
`;
public static examples = ['$ balena fleets'];
public static usage = 'fleets';
public static flags: flags.Input<FlagsDef> = {
help: cf.help,
verbose: flags.boolean({
default: false,
char: 'v',
description: 'No-op since release v12.0.0',
}),
};
public static authenticated = true;
public static primary = true;
protected useAppWord = false;
public async run(_parserOutput?: ParserOutput<FlagsDef, {}>) {
_parserOutput ||= this.parse<FlagsDef, {}>(FleetsCmd);
const balena = getBalenaSdk();
// Get applications
const applications = (await balena.models.application.getAll({
$select: ['id', 'app_name', 'slug'],
$expand: {
is_for__device_type: { $select: 'slug' },
owns__device: { $select: 'is_online' },
},
})) as ExtendedApplication[];
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,
);
// @ts-expect-error
application.device_type = application.is_for__device_type[0].slug;
});
// Display
console.log(
getVisuals().table.horizontal(applications, [
'id',
this.useAppWord ? 'app_name' : 'app_name => NAME',
'slug',
'device_type',
'online_devices',
'device_count',
]),
);
}
}
const appsToFleetsRenameMsg = appToFleetCmdMsg
.replace(/'app'/g, "'apps'")
.replace(/'fleet'/g, "'fleets'");
export default class AppsCmd extends FleetsCmd {
public static description = stripIndent`
DEPRECATED alias for the 'fleets' command
${appsToFleetsRenameMsg
.split('\n')
.map((l) => `\t\t${l}`)
.join('\n')}
For command usage, see 'balena help fleets'
`;
public static examples = [];
public static usage = 'apps';
public static args = FleetsCmd.args;
public static flags = FleetsCmd.flags;
public static authenticated = FleetsCmd.authenticated;
public static primary = FleetsCmd.primary;
public async run() {
// call this.parse() before deprecation message to parse '-h'
const parserOutput = this.parse<FlagsDef, {}>(AppsCmd);
if (process.stderr.isTTY) {
console.error(warnify(appsToFleetsRenameMsg));
}
this.useAppWord = true;
await super.run(parserOutput);
}
}

View File

@ -1,212 +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 type { flags } from '@oclif/command';
import type { IArg } from '@oclif/parser/lib/args';
import type {
BalenaSDK,
Device,
DeviceType,
PineTypedResult,
} from 'balena-sdk';
import Command from '../../command';
import * as cf from '../../utils/common-flags';
import { ExpectedError } from '../../errors';
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
import {
applicationIdInfo,
appToFleetFlagMsg,
warnify,
} from '../../utils/messages';
import { isV13 } from '../../utils/version';
type ExtendedDevice = PineTypedResult<
Device,
typeof import('../../utils/helpers').expandForAppNameAndCpuArch
> & {
application_name?: string;
};
interface FlagsDef {
application?: string;
app?: string;
fleet?: string;
help: void;
}
interface ArgsDef {
uuid: string;
}
export default class DeviceMoveCmd extends Command {
public static description = stripIndent`
Move one or more devices to another fleet.
Move one or more devices to another fleet.
If --fleet is omitted, the fleet will be prompted for interactively.
${applicationIdInfo.split('\n').join('\n\t\t')}
`;
public static examples = [
'$ balena device move 7cf02a6',
'$ balena device move 7cf02a6,dc39e52',
'$ balena device move 7cf02a6 --fleet MyNewFleet',
'$ balena device move 7cf02a6 -f myorg/mynewfleet',
];
public static args: Array<IArg<any>> = [
{
name: 'uuid',
description:
'comma-separated list (no blank spaces) of device UUIDs to be moved',
required: true,
},
];
public static usage = 'device move <uuid(s)>';
public static flags: flags.Input<FlagsDef> = {
...(isV13() ? {} : { app: cf.app, application: cf.application }),
fleet: cf.fleet,
help: cf.help,
};
public static authenticated = true;
public async run() {
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
DeviceMoveCmd,
);
if ((options.application || options.app) && process.stderr.isTTY) {
console.error(warnify(appToFleetFlagMsg));
}
options.application ||= options.app || options.fleet;
const balena = getBalenaSdk();
const { tryAsInteger } = await import('../../utils/validation');
const { expandForAppNameAndCpuArch } = await import('../../utils/helpers');
// Parse ids string into array of correct types
const deviceIds: Array<string | number> = params.uuid
.split(',')
.map((id) => tryAsInteger(id));
// Get devices
const devices = await Promise.all(
deviceIds.map(
(uuid) =>
balena.models.device.get(
uuid,
expandForAppNameAndCpuArch,
) as Promise<ExtendedDevice>,
),
);
// Map application name for each device
for (const device of devices) {
const belongsToApplication = device.belongs_to__application;
device.application_name = belongsToApplication?.[0]
? belongsToApplication[0].app_name
: 'N/a';
}
// Disambiguate application (if is a number, it could either be an ID or a numerical name)
const { getApplication } = await import('../../utils/sdk');
// Get destination application
const application = options.application
? await getApplication(balena, options.application)
: await this.interactivelySelectApplication(balena, devices);
// Move each device
for (const uuid of deviceIds) {
try {
await balena.models.device.move(uuid, application.id);
console.info(`Device ${uuid} was moved to fleet ${application.slug}`);
} catch (err) {
console.info(`${err.message}, uuid: ${uuid}`);
process.exitCode = 1;
}
}
}
async interactivelySelectApplication(
balena: BalenaSDK,
devices: ExtendedDevice[],
) {
const { getExpandedProp } = await import('../../utils/pine');
// deduplicate the slugs
const deviceCpuArchs = Array.from(
new Set(
devices.map(
(d) => d.is_of__device_type[0].is_of__cpu_architecture[0].slug,
),
),
);
const deviceTypeOptions = {
$select: 'slug',
$expand: {
is_of__cpu_architecture: {
$select: 'slug',
},
},
} as const;
const deviceTypes = (await balena.models.deviceType.getAllSupported(
deviceTypeOptions,
)) as Array<PineTypedResult<DeviceType, typeof deviceTypeOptions>>;
const compatibleDeviceTypeSlugs = new Set(
deviceTypes
.filter((deviceType) => {
const deviceTypeArch = getExpandedProp(
deviceType.is_of__cpu_architecture,
'slug',
)!;
return deviceCpuArchs.every((deviceCpuArch) =>
balena.models.os.isArchitectureCompatibleWith(
deviceCpuArch,
deviceTypeArch,
),
);
})
.map((deviceType) => deviceType.slug),
);
const patterns = await import('../../utils/patterns');
try {
const application = await patterns.selectApplication(
(app) =>
compatibleDeviceTypeSlugs.has(app.is_for__device_type[0].slug) &&
devices.some((device) => device.application_name !== app.app_name),
true,
);
return application;
} catch (err) {
if (!compatibleDeviceTypeSlugs.size) {
throw new ExpectedError(
`${err.message}\nDo all devices have a compatible architecture?`,
);
}
throw err;
}
}
}

View File

@ -1,146 +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, is_of__device_type, os_version, os_variant } =
(await sdk.models.device.get(params.uuid, {
$select: ['uuid', 'os_version', 'os_variant'],
$expand: {
is_of__device_type: {
$select: 'slug',
},
},
})) as DeviceWithDeviceType;
// 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(
is_of__device_type[0].slug,
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,171 +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 {
applicationIdInfo,
appToFleetFlagMsg,
appToFleetOutputMsg,
jsonInfo,
warnify,
} from '../../utils/messages';
import { isV13 } from '../../utils/version';
import type { Application } from 'balena-sdk';
interface ExtendedDevice extends DeviceWithDeviceType {
dashboard_url?: string;
application_name?: string | null;
device_type?: string | null;
}
interface FlagsDef {
application?: string;
app?: string;
fleet?: string;
help: void;
json: boolean;
v13: boolean;
}
export default class DevicesCmd extends Command {
public static description = stripIndent`
List all devices.
List all of your devices.
Devices can be filtered by fleet with the \`--fleet\` option.
${applicationIdInfo.split('\n').join('\n\t\t')}
${jsonInfo.split('\n').join('\n\t\t')}
`;
public static examples = [
'$ balena devices',
'$ balena devices --fleet MyFleet',
'$ balena devices -f myorg/myfleet',
];
public static usage = 'devices';
public static flags: flags.Input<FlagsDef> = {
...(isV13()
? {}
: {
application: {
...cf.application,
exclusive: ['app', 'fleet', 'v13'],
},
app: { ...cf.app, exclusive: ['application', 'fleet', 'v13'] },
}),
fleet: { ...cf.fleet, exclusive: ['app', 'application'] },
json: cf.json,
help: cf.help,
v13: cf.v13,
};
public static primary = true;
public static authenticated = true;
protected useAppWord = false;
protected hasWarned = false;
public async run() {
const { flags: options } = this.parse<FlagsDef, {}>(DevicesCmd);
this.useAppWord = !options.fleet && !options.v13 && !isV13();
const balena = getBalenaSdk();
if (
(options.application || options.app) &&
!options.json &&
process.stderr.isTTY
) {
this.hasWarned = true;
console.error(warnify(appToFleetFlagMsg));
}
// Consolidate application options
options.application ||= options.app || options.fleet;
let devices;
if (options.application != null) {
const { getApplication } = await import('../../utils/sdk');
const application = await getApplication(balena, options.application);
devices = (await balena.models.device.getAllByApplication(
application.id,
expandForAppName,
)) as ExtendedDevice[];
} else {
devices = (await balena.models.device.getAll(
expandForAppName,
)) as ExtendedDevice[];
}
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]?.app_name || null;
device.uuid = options.json ? device.uuid : device.uuid.slice(0, 7);
device.device_type = device.is_of__device_type?.[0]?.slug || null;
return device;
});
const jName = this.useAppWord ? 'application_name' : 'fleet_name';
const tName = this.useAppWord ? 'APPLICATION NAME' : 'FLEET';
const fields = [
'id',
'uuid',
'device_name',
'device_type',
options.json
? `application_name => ${jName}`
: `application_name => ${tName}`,
'status',
'is_online',
'supervisor_version',
'os_version',
'dashboard_url',
];
if (options.json) {
const { pickAndRename } = await import('../../utils/helpers');
const mapped = devices.map((device) => pickAndRename(device, fields));
console.log(JSON.stringify(mapped, null, 4));
} else {
if (!this.hasWarned && this.useAppWord && process.stderr.isTTY) {
console.error(warnify(appToFleetOutputMsg));
}
const _ = await import('lodash');
console.log(
getVisuals().table.horizontal(
devices.map((dev) => _.mapValues(dev, (val) => val ?? 'N/a')),
fields,
),
);
}
}
}

View File

@ -1,154 +0,0 @@
/**
* @license
* Copyright 2016-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.
*/
import { flags } from '@oclif/command';
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 { isV13 } from '../../utils/version';
interface FlagsDef {
discontinued: boolean;
help: void;
json?: boolean;
verbose?: boolean;
}
const deprecatedInfo = isV13()
? ''
: `
The --verbose option may add extra columns/fields to the output. Currently
this includes the "STATE" column which is DEPRECATED and whose values are one
of 'new', 'released' or 'discontinued'. However, 'discontinued' device types
are only listed if the '--discontinued' option is also used, and this option
is also DEPRECATED.
`
.split('\n')
.join(`\n\t\t`);
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').
${deprecatedInfo}
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: isV13()
? 'No effect (DEPRECATED)'
: 'include "discontinued" device types (DEPRECATED)',
}),
help: cf.help,
json: flags.boolean({
char: 'j',
description: 'produce JSON output instead of tabular output',
}),
verbose: flags.boolean({
char: 'v',
description: isV13()
? 'No effect (DEPRECATED)'
: 'add extra columns in the tabular output (DEPRECATED)',
}),
};
public async run() {
const { flags: options } = this.parse<FlagsDef, {}>(DevicesSupportedCmd);
const [dts, configDTs] = await Promise.all([
getBalenaSdk().models.deviceType.getAllSupported({
$expand: { is_of__cpu_architecture: { $select: 'slug' } },
$select: ['slug', 'name'],
}),
getBalenaSdk().models.config.getDeviceTypes(),
]);
const dtsBySlug = _.keyBy(dts, (dt) => dt.slug);
const configDTsBySlug = _.keyBy(configDTs, (dt) => dt.slug);
const discontinuedDTs = isV13()
? []
: configDTs.filter((dt) => dt.state === 'DISCONTINUED');
const discontinuedDTsBySlug = _.keyBy(discontinuedDTs, (dt) => dt.slug);
// set of slugs from models.deviceType.getAllSupported() plus slugs of
// discontinued device types as per models.config.getDeviceTypes()
const slugsOfInterest = new Set([
...Object.keys(dtsBySlug),
...Object.keys(discontinuedDTsBySlug),
]);
interface DT {
slug: string;
aliases: string[];
arch: string;
state?: string; // to be removed in CLI v13
name: string;
}
let deviceTypes: DT[] = [];
for (const slug of slugsOfInterest) {
const configDT: Partial<typeof configDTs[0]> =
configDTsBySlug[slug] || {};
if (configDT.state === 'DISCONTINUED' && !options.discontinued) {
continue;
}
const dt: Partial<typeof dts[0]> = dtsBySlug[slug] || {};
const aliases = (configDT.aliases || []).filter(
(alias) => alias !== slug,
);
deviceTypes.push({
slug,
aliases: options.json ? aliases : [aliases.join(', ')],
arch:
(dt.is_of__cpu_architecture as any)?.[0]?.slug ||
configDT.arch ||
'n/a',
// 'BETA' renamed to 'NEW'
// https://www.flowdock.com/app/rulemotion/i-cli/threads/1svvyaf8FAZeSdG4dPJc4kHOvJU
state: isV13()
? undefined
: (configDT.state || 'NEW').replace('BETA', 'NEW'),
name: dt.name || configDT.name || 'N/A',
});
}
const fields =
options.verbose && !isV13()
? ['slug', 'aliases', 'arch', 'state', 'name']
: ['slug', 'aliases', 'arch', 'name'];
deviceTypes = _.sortBy(deviceTypes, 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,20 +0,0 @@
/**
* @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.
*/
import { FleetCreateCmd } from '../app/create';
export default FleetCreateCmd;

View File

@ -1,20 +0,0 @@
/**
* @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.
*/
import { FleetCmd } from '../app';
export default FleetCmd;

View File

@ -1,20 +0,0 @@
/**
* @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.
*/
import { FleetPurgeCmd } from '../app/purge';
export default FleetPurgeCmd;

View File

@ -1,20 +0,0 @@
/**
* @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.
*/
import { FleetRenameCmd } from '../app/rename';
export default FleetRenameCmd;

View File

@ -1,20 +0,0 @@
/**
* @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.
*/
import { FleetRestartCmd } from '../app/restart';
export default FleetRestartCmd;

View File

@ -1,20 +0,0 @@
/**
* @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.
*/
import { FleetRmCmd } from '../app/rm';
export default FleetRmCmd;

View File

@ -1,20 +0,0 @@
/**
* @license
* Copyright 2016-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.
*/
import { FleetsCmd } from './apps';
export default FleetsCmd;

View File

@ -1,105 +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 { stripIndent } from '../../utils/lazy';
interface FlagsDef {
output: string;
version?: string;
help: void;
}
interface ArgsDef {
type: string;
}
export default class OsDownloadCmd extends Command {
public static description = stripIndent`
Download an unconfigured OS image.
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), otherwise the newest version (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.
To download a development image append \`.dev\` to the version or select from
the interactive menu.
`;
public static examples = [
'$ balena os download raspberrypi3 -o ../foo/bar/raspberry-pi.img',
'$ balena os download raspberrypi3 -o ../foo/bar/raspberry-pi.img --version 2.60.1+rev1',
'$ balena os download raspberrypi3 -o ../foo/bar/raspberry-pi.img --version 2.60.1+rev1.dev',
'$ balena os download raspberrypi3 -o ../foo/bar/raspberry-pi.img --version ^2.60.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',
];
public static args = [
{
name: 'type',
description: 'the device type',
required: true,
},
];
public static usage = 'os download <type>';
public static flags: flags.Input<FlagsDef> = {
output: flags.string({
description: 'output path',
char: 'o',
required: true,
}),
version: flags.string({
description: stripIndent`
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)
`,
}),
help: cf.help,
};
public async run() {
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
OsDownloadCmd,
);
const { downloadOSImage } = await import('../../utils/cloud');
try {
await downloadOSImage(params.type, options.output, options.version);
} catch (e) {
e.deviceTypeSlug = params.type;
throw e;
}
}
}

View File

@ -1,65 +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';
interface FlagsDef {
help: void;
}
interface ArgsDef {
type: string;
}
export default class OsVersionsCmd extends Command {
public static description = stripIndent`
Show available balenaOS versions for the given device type.
Show the available balenaOS versions for the given device type.
Check available types with \`balena devices supported\`.
`;
public static examples = ['$ balena os versions raspberrypi3'];
public static args = [
{
name: 'type',
description: 'device type',
required: true,
},
];
public static usage = 'os versions <type>';
public static flags: flags.Input<FlagsDef> = {
help: cf.help,
};
public async run() {
const { args: params } = this.parse<FlagsDef, ArgsDef>(OsVersionsCmd);
const { versions: vs, recommended } =
await getBalenaSdk().models.os.getSupportedVersions(params.type);
vs.forEach((v) => {
console.log(`v${v}` + (v === recommended ? ' (recommended)' : ''));
});
}
}

View File

@ -1,385 +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, validateLocalHostnameOrIp } from '../utils/validation';
import * as BalenaSdk from 'balena-sdk';
interface FlagsDef {
port?: number;
tty: boolean;
verbose: boolean;
noproxy: boolean;
help: void;
}
interface ArgsDef {
fleetOrDevice: string;
service?: string;
}
export default class SshCmd extends Command {
public static description = stripIndent`
Open a SSH prompt on a device's host OS or service container.
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 a fleet 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 MyFleet',
'$ 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: 'fleetOrDevice',
description:
'fleet name/slug/id, device uuid, or address of local device',
required: true,
},
{
name: 'service',
description: 'service name, if connecting to a container',
required: false,
},
];
public static usage = 'ssh <fleetOrDevice> [service]';
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({
default: false,
description:
'force pseudo-terminal allocation (bypass TTY autodetection for stdin)',
char: 't',
}),
verbose: flags.boolean({
default: false,
description: 'increase verbosity',
char: 'v',
}),
noproxy: flags.boolean({
default: false,
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>(
SshCmd,
);
// Local connection
if (validateLocalHostnameOrIp(params.fleetOrDevice)) {
const { performLocalDeviceSSH } = await import('../utils/device/ssh');
return await performLocalDeviceSSH({
address: params.fleetOrDevice,
port: options.port,
forceTTY: options.tty,
verbose: options.verbose,
service: params.service,
});
}
// Remote connection
const { getProxyConfig } = await import('../utils/helpers');
const { getOnlineTargetDeviceUuid } = await import('../utils/patterns');
const sdk = getBalenaSdk();
const proxyConfig = getProxyConfig();
const useProxy = !!proxyConfig && !options.noproxy;
// this will be a tunnelled SSH connection...
await Command.checkLoggedIn();
const deviceUuid = await getOnlineTargetDeviceUuid(
sdk,
params.fleetOrDevice,
);
const device = await sdk.models.device.get(deviceUuid, {
$select: ['id', 'supervisor_version', 'is_online'],
});
const deviceId = device.id;
const supervisorVersion = device.supervisor_version;
const { which } = await import('../utils/which');
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;
// At this point, we have a long uuid of a device
// that we know exists and is accessible
let containerId: string | undefined;
if (params.service != null) {
containerId = await this.getContainerId(
sdk,
deviceUuid,
params.service,
{
port: options.port,
proxyCommand,
proxyUrl: proxyUrl || '',
username: username!,
},
supervisorVersion,
deviceId,
);
}
let accessCommand: string;
if (containerId != null) {
accessCommand = `enter ${deviceUuid} ${containerId}`;
} else {
accessCommand = `host ${deviceUuid}`;
}
const command = this.generateVpnSshCommand({
uuid: deviceUuid,
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/which');
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,124 +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 <fleetOrDevice>"
* That's literally so: "fleetOrDevice" is NOT replaced with the actual
* fleet 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`).
*
* For more details on the data collected by balena generally, check this page:
* https://www.balena.io/docs/learn/more/collected-data/
*/
export async function trackCommand(commandSignature: string) {
try {
let Sentry: typeof import('@sentry/node');
if (!process.env.BALENARC_NO_SENTRY) {
Sentry = await import('@sentry/node');
Sentry.configureScope((scope) => {
scope.setExtra('command', commandSignature);
});
}
const settings = await import('balena-settings-client');
const balenaUrl = settings.get<string>('balenaUrl');
const username = await (async () => {
const getStorage = await import('balena-settings-storage');
const dataDirectory = settings.get<string>('dataDirectory');
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();
await storage.set('cachedUsername', {
token,
username: $username,
} as CachedUsername);
return $username;
} catch {
return;
}
})();
const mixpanel = getMixpanel(balenaUrl);
if (!process.env.BALENARC_NO_SENTRY) {
Sentry!.configureScope((scope) => {
scope.setUser({
id: username,
username,
});
});
}
// Don't actually call mixpanel.track() while running test cases, or if suppressed
if (
!process.env.BALENA_CLI_TEST_TYPE &&
!process.env.BALENARC_NO_ANALYTICS
) {
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,46 +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.
* 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,104 +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.
*/
/*
* THIS MODULE SHOULD NOT IMPORT / REQUIRE ANYTHING AT THE GLOBAL LEVEL.
* It is meant to contain elementary helper functions or classes that
* can be used very early on during CLI startup, before anything else
* like Sentry error reporting, preparser, oclif parser and the like.
*/
export class CliSettings {
public readonly settings: any;
constructor() {
this.settings =
require('balena-settings-client') as typeof import('balena-settings-client');
}
public get<T>(name: string): T {
return this.settings.get(name);
}
/**
* Like settings.get(), but return `undefined` instead of throwing an
* error if the setting is not found / not defined.
*/
public getCatch<T>(name: string): T | undefined {
try {
return this.settings.get(name);
} catch (err) {
if (!/Setting not found/i.test(err.message)) {
throw err;
}
}
}
}
export function parseBoolEnvVar(varName: string): boolean {
return !['0', 'no', 'false', '', undefined].includes(
process.env[varName]?.toLowerCase(),
);
}
export function normalizeEnvVar(varName: string) {
process.env[varName] = parseBoolEnvVar(varName) ? '1' : '';
}
const bootstrapVars = ['DEBUG', 'BALENARC_NO_SENTRY'];
export function normalizeEnvVars(varNames: string[] = bootstrapVars) {
for (const varName of varNames) {
normalizeEnvVar(varName);
}
}
/**
* 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.
*/
export 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,710 +0,0 @@
/**
* @license
* Copyright 2017-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.
*/
import * as path from 'path';
import { ExpectedError } from '../errors';
import { getChalk } from './lazy';
import { isV13 } from './version';
/**
* @returns Promise<{import('./compose-types').ComposeOpts}>
*/
export function generateOpts(options) {
const { promises: fs } = require('fs');
if (!isV13() && options.gitignore && options['multi-dockerignore']) {
throw new ExpectedError(
'The --gitignore and --multi-dockerignore options cannot be used together',
);
}
return fs.realpath(options.source || '.').then((projectPath) => ({
projectName: options.projectName,
projectPath,
inlineLogs: !options.nologs,
convertEol: !options['noconvert-eol'],
dockerfilePath: options.dockerfile,
multiDockerignore: !!options['multi-dockerignore'],
nogitignore: !options.gitignore, // v13: delete this line
noParentCheck: options['noparent-check'],
}));
}
// Parse the given composition and return a structure with info. Input is:
// - composePath: the *absolute* path to the directory containing the compose file
// - composeStr: the contents of the compose file, as a string
/**
* @param {string} composePath
* @param {string} composeStr
* @param {string | undefined} projectName The --projectName flag (build, deploy)
* @param {string | undefined} imageTag The --tag flag (build, deploy)
* @returns {import('./compose-types').ComposeProject}
*/
export function createProject(
composePath,
composeStr,
projectName = '',
imageTag = '',
) {
const yml = require('js-yaml');
const compose = require('resin-compose-parse');
// both methods below may throw.
const rawComposition = yml.load(composeStr, {
schema: yml.FAILSAFE_SCHEMA,
});
const composition = compose.normalize(rawComposition);
projectName ||= path.basename(composePath);
const descriptors = compose.parse(composition).map(function (descr) {
// generate an image name based on the project and service names
// if one is not given and the service requires a build
if (
typeof descr.image !== 'string' &&
descr.image.context != null &&
descr.image.tag == null
) {
const { makeImageName } = require('./compose_ts');
descr.image.tag = makeImageName(projectName, descr.serviceName, imageTag);
}
return descr;
});
return {
path: composePath,
name: projectName,
composition,
descriptors,
};
}
/**
* This is the CLI v10 / v11 "original" tarDirectory function. It is still
* around for the benefit of the `--gitignore` option, but is expected to be
* deleted in CLI v13.
* @param {string} dir Source directory
* @param {import('./compose-types').TarDirectoryOptions} param
* @returns {Promise<import('stream').Readable>}
*
* v13: delete this function
*/
export async function originalTarDirectory(dir, param) {
let {
preFinalizeCallback = null,
convertEol = false,
nogitignore = false,
} = param;
if (convertEol == null) {
convertEol = false;
}
const Bluebird = require('bluebird');
const tar = require('tar-stream');
const klaw = require('klaw');
const { promises: fs } = require('fs');
const streamToPromise = require('stream-to-promise');
const { printGitignoreWarn } = require('./compose_ts');
const { FileIgnorer, IgnoreFileType } = require('./ignore');
const { toPosixPath } = require('resin-multibuild').PathUtils;
let readFile;
if (process.platform === 'win32') {
const { readFileWithEolConversion } = require('./eol-conversion');
readFile = (file) => readFileWithEolConversion(file, convertEol);
} else {
({ readFile } = fs);
}
const getFiles = () =>
Bluebird.resolve(streamToPromise(klaw(dir)))
// @ts-ignore
.filter((item) => !item.stats.isDirectory())
// @ts-ignore
.map((item) => item.path);
const ignore = new FileIgnorer(dir);
const pack = tar.pack();
const ignoreFiles = {};
return getFiles()
.each(function (file) {
const type = ignore.getIgnoreFileType(path.relative(dir, file));
if (type != null) {
ignoreFiles[type] = ignoreFiles[type] || [];
ignoreFiles[type].push(path.resolve(dir, file));
return ignore.addIgnoreFile(file, type);
}
})
.tap(() => {
if (!nogitignore) {
printGitignoreWarn(
(ignoreFiles[IgnoreFileType.DockerIgnore] || [])[0] || '',
ignoreFiles[IgnoreFileType.GitIgnore] || [],
);
}
})
.filter(ignore.filter)
.map(function (file) {
const relPath = path.relative(path.resolve(dir), file);
return Promise.all([relPath, fs.stat(file), readFile(file)]).then(
([filename, stats, data]) =>
pack.entry(
{
name: toPosixPath(filename),
mtime: stats.mtime,
size: stats.size,
mode: stats.mode,
},
data,
),
);
})
.then(() => preFinalizeCallback?.(pack))
.then(function () {
pack.finalize();
return pack;
});
}
/**
* @param {string} apiEndpoint
* @param {string} auth
* @param {number} userId
* @param {number} appId
* @param {import('resin-compose-parse').Composition} composition
* @param {boolean} draft
* @param {string|undefined} semver
* @param {string|undefined} contract
* @returns {Promise<import('./compose-types').Release>}
*/
export const createRelease = async function (
apiEndpoint,
auth,
userId,
appId,
composition,
draft,
semver,
contract,
) {
const _ = require('lodash');
const crypto = require('crypto');
const releaseMod = require('balena-release');
const client = releaseMod.createClient({ apiEndpoint, auth });
const { release, serviceImages } = await releaseMod.create({
client,
user: userId,
application: appId,
composition,
source: 'local',
commit: crypto.pseudoRandomBytes(16).toString('hex').toLowerCase(),
semver,
is_final: !draft,
contract,
});
return {
client,
release: _.pick(release, [
'id',
'status',
'commit',
'composition',
'source',
'is_final',
'contract',
'semver',
'start_timestamp',
'end_timestamp',
]),
serviceImages: _.mapValues(serviceImages, (serviceImage) =>
_.omit(serviceImage, [
'created_at',
'is_a_build_of__service',
'__metadata',
]),
),
};
};
/**
*
* @param {import('dockerode')} docker
* @param {Array<import('./compose-types').BuiltImage>} images
* @param {Partial<import('balena-release/build/models').ImageModel>} serviceImages
* @returns {Promise<Array<import('./compose-types').TaggedImage>>}
*/
export const tagServiceImages = (docker, images, serviceImages) =>
Promise.all(
images.map(function (d) {
const serviceImage = serviceImages[d.serviceName];
const imageName = serviceImage.is_stored_at__image_location;
const match = /(.*?)\/(.*?)(?::([^/]*))?$/.exec(imageName);
if (match == null) {
throw new Error(`Could not parse imageName: '${imageName}'`);
}
const [, registry, repo, tag = 'latest'] = match;
const name = `${registry}/${repo}`;
return docker
.getImage(d.name)
.tag({ repo: name, tag, force: true })
.then(() => docker.getImage(`${name}:${tag}`))
.then((localImage) => ({
serviceName: d.serviceName,
serviceImage,
localImage,
registry,
repo,
logs: d.logs,
props: d.props,
}));
}),
);
/**
* @param {*} sdk
* @param {import('./logger')} logger
* @param {number} appID
* @returns {Promise<string[]>}
*/
export const getPreviousRepos = (sdk, logger, appID) =>
sdk.pine
.get({
resource: 'release',
options: {
$filter: {
belongs_to__application: appID,
status: 'success',
},
$select: ['id'],
$expand: {
contains__image: {
$expand: 'image',
},
},
$orderby: 'id desc',
$top: 1,
},
})
.then(function (release) {
// grab all images from the latest release, return all image locations in the registry
if (release.length > 0) {
const images = release[0].contains__image;
const { getRegistryAndName } = require('resin-multibuild');
return Promise.all(
images.map(function (d) {
const imageName = d.image[0].is_stored_at__image_location || '';
const registry = getRegistryAndName(imageName);
logger.logDebug(
`Requesting access to previously pushed image repo (${registry.imageName})`,
);
return registry.imageName;
}),
);
} else {
return [];
}
})
.catch((e) => {
logger.logDebug(`Failed to access previously pushed image repo: ${e}`);
return [];
});
/**
* @param {*} sdk
* @param {string} tokenAuthEndpoint
* @param {string} registry
* @param {string[]} images
* @param {string[]} previousRepos
* @returns {Promise<string>}
*/
export const authorizePush = function (
sdk,
tokenAuthEndpoint,
registry,
images,
previousRepos,
) {
if (!Array.isArray(images)) {
images = [images];
}
images.push(...previousRepos);
return sdk.request
.send({
baseUrl: tokenAuthEndpoint,
url: '/auth/v1/token',
qs: {
service: registry,
scope: images.map((repo) => `repository:${repo}:pull,push`),
},
})
.then(({ body }) => body.token)
.catch(() => '');
};
/**
* @param {import('dockerode')} docker
* @param {string} token
* @param {Array<import('./compose-types').TaggedImage>} images
* @param {(serviceImage: import('balena-release/build/models').ImageModel, props: object) => void} afterEach
*/
export const pushAndUpdateServiceImages = function (
docker,
token,
images,
afterEach,
) {
const { DockerProgress } = require('docker-progress');
const { retry } = require('./helpers');
const tty = require('./tty')(process.stdout);
const Bluebird = require('bluebird');
const opts = { authconfig: { registrytoken: token } };
const progress = new DockerProgress({ docker });
const renderer = pushProgressRenderer(
tty,
getChalk().blue('[Push]') + ' ',
);
const reporters = progress.aggregateProgress(images.length, renderer);
return Bluebird.using(tty.cursorHidden(), () =>
Promise.all(
images.map(({ serviceImage, localImage, props, logs }, index) =>
Promise.all([
localImage.inspect().then((img) => img.Size),
retry({
// @ts-ignore
func: () => progress.push(localImage.name, reporters[index], opts),
maxAttempts: 3, // try calling func 3 times (max)
// @ts-ignore
label: localImage.name, // label for retry log messages
initialDelayMs: 2000, // wait 2 seconds before the 1st retry
backoffScaler: 1.4, // wait multiplier for each retry
}).finally(renderer.end),
])
.then(
/** @type {([number, string]) => void} */
function ([size, digest]) {
serviceImage.image_size = size;
serviceImage.content_hash = digest;
serviceImage.build_log = logs;
serviceImage.dockerfile = props.dockerfile;
serviceImage.project_type = props.projectType;
if (props.startTime) {
serviceImage.start_timestamp = props.startTime;
}
if (props.endTime) {
serviceImage.end_timestamp = props.endTime;
}
serviceImage.push_timestamp = new Date();
serviceImage.status = 'success';
},
)
.catch(function (e) {
serviceImage.error_message = '' + e;
serviceImage.status = 'failed';
throw e;
})
.finally(() => afterEach?.(serviceImage, props)),
),
),
);
};
// utilities
const renderProgressBar = function (percentage, stepCount) {
const _ = require('lodash');
percentage = _.clamp(percentage, 0, 100);
const barCount = Math.floor((stepCount * percentage) / 100);
const spaceCount = stepCount - barCount;
const bar = `[${_.repeat('=', barCount)}>${_.repeat(' ', spaceCount)}]`;
return `${bar} ${_.padStart(percentage, 3)}%`;
};
var pushProgressRenderer = function (tty, prefix) {
const fn = function (e) {
const { error, percentage } = e;
if (error != null) {
throw new Error(error);
}
const bar = renderProgressBar(percentage, 40);
return tty.replaceLine(`${prefix}${bar}\r`);
};
fn.end = () => {
tty.clearLine();
};
return fn;
};
export class BuildProgressUI {
constructor(tty, descriptors) {
this._handleEvent = this._handleEvent.bind(this);
this.start = this.start.bind(this);
this.end = this.end.bind(this);
this._display = this._display.bind(this);
const _ = require('lodash');
const through = require('through2');
const eventHandler = this._handleEvent;
const services = _.map(descriptors, 'serviceName');
const streams = _(services)
.map(function (service) {
const stream = through.obj(function (event, _enc, cb) {
eventHandler(service, event);
return cb();
});
stream.pipe(tty.stream, { end: false });
return [service, stream];
})
.fromPairs()
.value();
this._tty = tty;
this._serviceToDataMap = {};
this._services = services;
// Logger magically prefixes the log line with [Build] etc., but it doesn't
// work well with the spinner we're also showing. Manually build the prefix
// here and bypass the logger.
const prefix = getChalk().blue('[Build]') + ' ';
const offset = 10; // account for escape sequences inserted for colouring
this._prefixWidth =
offset + prefix.length + _.max(_.map(services, 'length'));
this._prefix = prefix;
// these are to handle window wrapping
this._maxLineWidth = null;
this._lineWidths = [];
this._startTime = null;
this._ended = false;
this._cancelled = false;
this._spinner = require('./compose_ts').createSpinner();
this.streams = streams;
}
_handleEvent(service, event) {
this._serviceToDataMap[service] = event;
}
start() {
this._tty.hideCursor();
this._services.forEach((service) => {
this.streams[service].write({ status: 'Preparing...' });
});
this._runloop = require('./compose_ts').createRunLoop(this._display);
this._startTime = Date.now();
}
end(summary = null) {
if (this._ended) {
return;
}
this._ended = true;
this._runloop?.end();
this._runloop = null;
this._clear();
this._renderStatus(true);
this._renderSummary(summary ?? this._getServiceSummary());
this._tty.showCursor();
}
_display() {
this._clear();
this._renderStatus();
this._renderSummary(this._getServiceSummary());
this._tty.cursorUp(this._services.length + 1); // for status line
}
_clear() {
this._tty.deleteToEnd();
this._maxLineWidth = this._tty.currentWindowSize().width;
}
_getServiceSummary() {
const _ = require('lodash');
const services = this._services;
const serviceToDataMap = this._serviceToDataMap;
return _(services)
.map(function (service) {
const { status, progress, error } = serviceToDataMap[service] ?? {};
if (error) {
return `${error}`;
} else if (progress) {
const bar = renderProgressBar(progress, 20);
if (status) {
return `${bar} ${status}`;
}
return `${bar}`;
} else if (status) {
return `${status}`;
} else {
return 'Waiting...';
}
})
.map((data, index) => [services[index], data])
.fromPairs()
.value();
}
_renderStatus(end) {
end ??= false;
const moment = require('moment');
require('moment-duration-format')(moment);
this._tty.clearLine();
this._tty.write(this._prefix);
if (end && this._cancelled) {
this._tty.writeLine('Build cancelled');
} else if (end) {
const serviceCount = this._services.length;
const serviceStr =
serviceCount === 1 ? '1 service' : `${serviceCount} services`;
const durationStr =
this._startTime == null
? 'unknown time'
: moment
.duration(
Math.floor((Date.now() - this._startTime) / 1000),
'seconds',
)
.format();
this._tty.writeLine(`Built ${serviceStr} in ${durationStr}`);
} else {
this._tty.writeLine(`Building services... ${this._spinner()}`);
}
}
_renderSummary(serviceToStrMap) {
const _ = require('lodash');
const chalk = getChalk();
const truncate = require('cli-truncate');
const strlen = require('string-width');
this._services.forEach((service, index) => {
let str = _.padEnd(this._prefix + chalk.bold(service), this._prefixWidth);
str += serviceToStrMap[service];
if (this._maxLineWidth != null) {
str = truncate(str, this._maxLineWidth);
}
this._lineWidths[index] = strlen(str);
this._tty.clearLine();
this._tty.writeLine(str);
});
}
}
export class BuildProgressInline {
constructor(outStream, descriptors) {
this.start = this.start.bind(this);
this.end = this.end.bind(this);
this._renderEvent = this._renderEvent.bind(this);
const _ = require('lodash');
const through = require('through2');
const services = _.map(descriptors, 'serviceName');
const eventHandler = this._renderEvent;
const streams = _(services)
.map(function (service) {
const stream = through.obj(function (event, _enc, cb) {
eventHandler(service, event);
return cb();
});
stream.pipe(outStream, { end: false });
return [service, stream];
})
.fromPairs()
.value();
const offset = 10; // account for escape sequences inserted for colouring
this._prefixWidth = offset + _.max(_.map(services, 'length'));
this._outStream = outStream;
this._services = services;
this._startTime = null;
this._ended = false;
this.streams = streams;
}
start() {
this._outStream.write('Building services...\n');
this._services.forEach((service) => {
this.streams[service].write({ status: 'Preparing...' });
});
this._startTime = Date.now();
}
end(summary = null) {
const moment = require('moment');
require('moment-duration-format')(moment);
if (this._ended) {
return;
}
this._ended = true;
if (summary != null) {
this._services.forEach((service) => {
this._renderEvent(service, { status: summary[service] });
});
}
const serviceCount = this._services.length;
const serviceStr =
serviceCount === 1 ? '1 service' : `${serviceCount} services`;
const durationStr =
this._startTime == null
? 'unknown time'
: moment
.duration(
Math.floor((Date.now() - this._startTime) / 1000),
'seconds',
)
.format();
this._outStream.write(`Built ${serviceStr} in ${durationStr}\n`);
}
_renderEvent(service, event) {
const _ = require('lodash');
const str = (function () {
const { status, error } = event;
if (error) {
return `${error}`;
} else if (status) {
return `${status}`;
} else {
return 'Waiting...';
}
})();
const prefix = _.padEnd(getChalk().bold(service), this._prefixWidth);
this._outStream.write(prefix);
this._outStream.write(str);
this._outStream.write('\n');
}
}

View File

@ -1,173 +0,0 @@
/*
Copyright 2016-2019 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 type * as BalenaSdk from 'balena-sdk';
import * as semver from 'balena-semver';
import { getBalenaSdk } from './lazy';
export interface ImgConfig {
applicationName: string;
applicationId: number;
deviceType: string;
userId: number;
username: string;
appUpdatePollInterval: number;
listenPort: number;
vpnPort: number;
apiEndpoint: string;
vpnEndpoint: string;
registryEndpoint: string;
deltaEndpoint: string;
mixpanelToken: string;
wifiSsid?: string;
wifiKey?: string;
initialDeviceName?: string;
// props for older OS versions
connectivity?: string;
files?: {
[filepath: string]: string;
};
// device specific config props
deviceId?: number;
uuid?: string;
registered_at?: number;
os?: {
sshKeys?: string[];
};
}
export async function generateBaseConfig(
application: BalenaSdk.Application,
options: {
version: string;
appUpdatePollInterval?: number;
deviceType?: string;
os?: {
sshKeys?: string[];
};
},
): Promise<ImgConfig> {
options = {
...options,
appUpdatePollInterval: options.appUpdatePollInterval || 10,
};
const config = (await getBalenaSdk().models.os.getConfig(
application.slug,
options,
)) as ImgConfig & { apiKey?: string };
// os.getConfig always returns a config for an app
delete config.apiKey;
// merge sshKeys to config, when they have been specified
if (options.os && options.os.sshKeys) {
// Create config.os object if it does not exist
config.os = config.os ? config.os : {};
config.os.sshKeys = config.os.sshKeys
? [...config.os.sshKeys, ...options.os.sshKeys]
: options.os.sshKeys;
}
return config;
}
export async function generateApplicationConfig(
application: BalenaSdk.Application,
options: {
version: string;
deviceType?: string;
appUpdatePollInterval?: number;
},
) {
const config = await generateBaseConfig(application, options);
if (semver.satisfies(options.version, '<2.7.8')) {
await addApplicationKey(config, application.id);
} else {
await addProvisioningKey(config, application.id);
}
return config;
}
export function generateDeviceConfig(
device: DeviceWithDeviceType & {
belongs_to__application: BalenaSdk.PineDeferred;
},
deviceApiKey: string | true | undefined,
options: { version: string },
) {
return getBalenaSdk()
.models.application.get(device.belongs_to__application.__id)
.then(async (application) => {
const baseConfigOpts = {
...options,
deviceType: device.is_of__device_type[0].slug,
};
const config = await generateBaseConfig(application, baseConfigOpts);
if (deviceApiKey == null && semver.satisfies(options.version, '<2.0.3')) {
await addApplicationKey(config, application.id);
} else {
await addDeviceKey(config, device.uuid, deviceApiKey || true);
}
return config;
})
.then((config) => {
// Associate a device, to prevent the supervisor
// from creating another one on its own.
config.registered_at = Math.floor(Date.now() / 1000);
config.deviceId = device.id;
config.uuid = device.uuid;
return config;
});
}
function addApplicationKey(config: any, applicationNameOrId: string | number) {
return getBalenaSdk()
.models.application.generateApiKey(applicationNameOrId)
.then((apiKey) => {
config.apiKey = apiKey;
return apiKey;
});
}
function addProvisioningKey(config: any, applicationNameOrId: string | number) {
return getBalenaSdk()
.models.application.generateProvisioningKey(applicationNameOrId)
.then((apiKey) => {
config.apiKey = apiKey;
return apiKey;
});
}
async function addDeviceKey(
config: any,
uuid: string,
customDeviceApiKey: string | true,
) {
if (customDeviceApiKey === true) {
config.deviceApiKey = await getBalenaSdk().models.device.generateDeviceKey(
uuid,
);
} else {
config.deviceApiKey = customDeviceApiKey;
}
}

View File

@ -1,119 +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 type { ContainerInfo } from 'dockerode';
import { stripIndent } from '../lazy';
export interface DeviceSSHOpts {
address: string;
port?: number;
forceTTY?: boolean;
verbose: boolean;
service?: string;
}
export const deviceContainerEngineBinary = `$(if [ -f /usr/bin/balena ]; then echo "balena"; else echo "docker"; fi)`;
export async function performLocalDeviceSSH(
opts: DeviceSSHOpts,
): Promise<void> {
const { escapeRegExp, reduce } = await import('lodash');
const { spawnSshAndThrowOnError } = await import('../ssh');
const { ExpectedError } = await import('../../errors');
let command = '';
if (opts.service != null) {
// Get the containers which are on-device. Currently we
// are single application, which means we can assume any
// container which fulfills the form of
// $serviceName_$appId_$releaseId is what we want. Once
// we have multi-app, we should show a dialog which
// allows the user to choose the correct container
const Docker = await import('dockerode');
const docker = new Docker({
host: opts.address,
port: 2375,
});
const regex = new RegExp(`(^|\\/)${escapeRegExp(opts.service)}_\\d+_\\d+`);
const nameRegex = /\/?([a-zA-Z0-9_-]+)_\d+_\d+/;
let allContainers: ContainerInfo[];
try {
allContainers = await docker.listContainers();
} catch (_e) {
throw new ExpectedError(stripIndent`
Could not access docker daemon on device ${opts.address}.
Please ensure the device is in local mode.`);
}
const serviceNames: string[] = [];
const containers: Array<{ id: string; name: string }> = [];
for (const container of allContainers) {
for (const name of container.Names) {
if (regex.test(name)) {
containers.push({ id: container.Id, name });
break;
}
const match = name.match(nameRegex);
if (match) {
serviceNames.push(match[1]);
}
}
}
if (containers.length === 0) {
throw new ExpectedError(
`Could not find a service on device with name ${opts.service}. ${
serviceNames.length > 0
? `Available services:\n${reduce(
serviceNames,
(str, name) => `${str}\t${name}\n`,
'',
)}`
: ''
}`,
);
}
if (containers.length > 1) {
throw new ExpectedError(stripIndent`
Found more than one container matching service name "${opts.service}":
${containers.map((container) => container.name).join(', ')}
Use different service names to avoid ambiguity.
`);
}
const containerId = containers[0].id;
const shellCmd = `/bin/sh -c "if [ -e /bin/bash ]; then exec /bin/bash; else exec /bin/sh; fi"`;
// stdin (fd=0) is not a tty when data is piped in, for example
// echo 'ls -la; exit;' | balena ssh 192.168.0.20 service1
// See https://www.balena.io/blog/balena-monthly-roundup-january-2020/#charliestipsntricks
// https://assets.balena.io/newsletter/2020-01/pipe.png
const isTTY = !!opts.forceTTY || (await import('tty')).isatty(0);
const ttyFlag = isTTY ? '-t' : '';
command = `${deviceContainerEngineBinary} exec -i ${ttyFlag} ${containerId} ${shellCmd}`;
}
return spawnSshAndThrowOnError([
...(opts.verbose ? ['-vvv'] : []),
'-t',
...['-p', opts.port ? opts.port.toString() : '22222'],
...['-o', 'LogLevel=ERROR'],
...['-o', 'StrictHostKeyChecking=no'],
...['-o', 'UserKnownHostsFile=/dev/null'],
`root@${opts.address}`,
...(command ? [command] : []),
]);
}

View File

@ -1,85 +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 type * as Config from '@oclif/config';
/**
* This class is a partial copy-and-paste of
* @oclif/plugin-help/command/CommandHelp, which is used to generate oclif's
* command help output.
*/
export class CommandHelp {
constructor(public command: { args?: any[] }) {}
protected arg(arg: Config.Command['args'][0]): string {
const name = arg.name.toUpperCase();
if (arg.required) {
return `${name}`;
}
return `[${name}]`;
}
public defaultUsage(): string {
return CommandHelp.compact([
// this.command.id,
(this.command.args || [])
.filter((a) => !a.hidden)
.map((a) => this.arg(a))
.join(' '),
]).join(' ');
}
public static compact<T>(array: Array<T | undefined>): T[] {
return array.filter((a): a is T => !!a);
}
}
export 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();
}
}
}
/** Convert e.g. 'env add NAME [VALUE]' to 'env add <name> [value]' */
export function capitanoizeOclifUsage(
oclifUsage: string | string[] | undefined,
): string {
return (oclifUsage || '')
.toString()
.replace(/(?<=\s)[A-Z]+(?=(\s|$))/g, (match) => `<${match}>`)
.toLowerCase();
}
export async function getCommandsFromManifest() {
const manifest = require('../../oclif.manifest.json');
if (manifest.commands == null) {
throw new Error('Commands section not found in manifest.');
}
return manifest.commands;
}
export async function getCommandIdsFromManifest() {
const commands = await getCommandsFromManifest();
return Object.keys(commands);
}

View File

@ -1,417 +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 * as BalenaSdk from 'balena-sdk';
import _ = require('lodash');
import { instanceOf, NotLoggedInError, ExpectedError } from '../errors';
import { getBalenaSdk, getVisuals, stripIndent, getCliForm } from './lazy';
import validation = require('./validation');
import { delay } from './helpers';
import { isV13 } from './version';
import type { Application, Device, Organization } from 'balena-sdk';
export function authenticate(options: {}): Promise<void> {
const balena = getBalenaSdk();
return getCliForm()
.run(
[
{
message: 'Email:',
name: 'email',
type: 'input',
validate: validation.validateEmail,
},
{
message: 'Password:',
name: 'password',
type: 'password',
},
],
{ override: options },
)
.then(balena.auth.login)
.then(balena.auth.twoFactor.isPassed)
.then((isTwoFactorAuthPassed: boolean) => {
if (isTwoFactorAuthPassed) {
return;
}
return getCliForm()
.ask({
message: 'Two factor auth challenge:',
name: 'code',
type: 'input',
})
.then(balena.auth.twoFactor.challenge)
.catch((error: any) => {
return balena.auth.logout().then(() => {
if (
error.name === 'BalenaRequestError' &&
error.statusCode === 401
) {
throw new ExpectedError('Invalid two factor authentication code');
}
throw error;
});
});
});
}
/**
* Check if logged in, and throw `NotLoggedInError` if not.
* Note: `NotLoggedInError` is an `ExpectedError`.
*/
export async function checkLoggedIn(): Promise<void> {
const balena = getBalenaSdk();
if (!(await balena.auth.isLoggedIn())) {
throw new NotLoggedInError(stripIndent`
Login required: use the “balena login” command to log in.
`);
}
}
export function askLoginType() {
return getCliForm().ask<'web' | 'credentials' | 'token' | 'register'>({
message: 'How would you like to login?',
name: 'loginType',
type: 'list',
choices: [
{
name: 'Web authorization (recommended)',
value: 'web',
},
{
name: 'Credentials',
value: 'credentials',
},
{
name: 'Authentication token',
value: 'token',
},
{
name: "I don't have a balena account!",
value: 'register',
},
],
});
}
export function selectDeviceType() {
return getBalenaSdk()
.models.config.getDeviceTypes()
.then((deviceTypes) => {
deviceTypes = _.sortBy(deviceTypes, 'name').filter(
(dt) => dt.state !== 'DISCONTINUED',
);
return getCliForm().ask({
message: 'Device Type',
type: 'list',
choices: _.map(deviceTypes, ({ slug: value, name }) => ({
name,
value,
})),
});
});
}
/**
* Display interactive confirmation prompt.
* Throw ExpectedError if the user declines.
* @param yesOption - automatically confirm if true
* @param message - message to display with prompt
* @param yesMessage - message to display if automatically confirming
*/
export async function confirm(
yesOption: boolean,
message: string,
yesMessage?: string,
defaultValue = false,
) {
if (yesOption) {
if (yesMessage) {
if (isV13()) {
console.error(yesMessage);
} else {
console.log(yesMessage);
}
}
return;
}
const confirmed = await getCliForm().ask<boolean>({
message,
type: 'confirm',
default: defaultValue,
});
if (!confirmed) {
throw new ExpectedError('Aborted');
}
}
export function selectApplication(
filter?: (app: ApplicationWithDeviceType) => boolean,
errorOnEmptySelection = false,
) {
const balena = getBalenaSdk();
return balena.models.application
.hasAny()
.then(async (hasAnyApplications) => {
if (!hasAnyApplications) {
throw new ExpectedError('No fleets found');
}
const apps = (await balena.models.application.getAll({
$expand: {
is_for__device_type: {
$select: 'slug',
},
},
})) as ApplicationWithDeviceType[];
return apps.filter(filter || _.constant(true));
})
.then((applications) => {
if (errorOnEmptySelection && applications.length === 0) {
throw new ExpectedError('No suitable fleets found for selection');
}
return getCliForm().ask({
message: 'Select an application',
type: 'list',
choices: _.map(applications, (application) => ({
name: `${application.app_name} (${application.slug}) [${application.is_for__device_type[0].slug}]`,
value: application,
})),
});
});
}
export async function selectOrganization(organizations?: Organization[]) {
// Use either provided orgs (if e.g. already loaded) or load from cloud
organizations =
organizations || (await getBalenaSdk().models.organization.getAll());
return getCliForm().ask({
message: 'Select an organization',
type: 'list',
choices: organizations.map((org) => ({
name: `${org.name} (${org.handle})`,
value: org.handle,
})),
});
}
export async function awaitDevice(uuid: string) {
const balena = getBalenaSdk();
const deviceName = await balena.models.device.getName(uuid);
const visuals = getVisuals();
const spinner = new visuals.Spinner(
`Waiting for ${deviceName} to come online`,
);
const poll = async (): Promise<void> => {
const isOnline = await balena.models.device.isOnline(uuid);
if (isOnline) {
spinner.stop();
console.info(`The device **${deviceName}** is online!`);
return;
} else {
// Spinner implementation is smart enough to
// not start again if it was already started
spinner.start();
await delay(3000);
await poll();
}
};
console.info(`Waiting for ${deviceName} to connect to balena...`);
await poll();
return uuid;
}
export async function awaitDeviceOsUpdate(
uuid: string,
targetOsVersion: string,
) {
const balena = getBalenaSdk();
const deviceName = await balena.models.device.getName(uuid);
const visuals = getVisuals();
const progressBar = new visuals.Progress(
`Updating the OS of ${deviceName} to v${targetOsVersion}`,
);
progressBar.update({ percentage: 0 });
const poll = async (): Promise<void> => {
const [osUpdateStatus, { overall_progress: osUpdateProgress }] =
await Promise.all([
balena.models.device.getOsUpdateStatus(uuid),
balena.models.device.get(uuid, { $select: 'overall_progress' }),
]);
if (osUpdateStatus.status === 'done') {
console.info(
`The device ${deviceName} has been updated to v${targetOsVersion} and will restart shortly!`,
);
return;
}
if (osUpdateStatus.error) {
throw new ExpectedError(
`Failed to complete Host OS update on device ${deviceName}\n${osUpdateStatus.error}`,
);
}
if (osUpdateProgress !== null) {
// Avoid resetting to 0% at end of process when device goes offline.
progressBar.update({ percentage: osUpdateProgress });
}
await delay(3000);
await poll();
};
await poll();
return uuid;
}
export function inferOrSelectDevice(preferredUuid: string) {
const balena = getBalenaSdk();
return balena.models.device.getAll().then((devices) => {
const onlineDevices = devices.filter((device) => device.is_online);
if (_.isEmpty(onlineDevices)) {
throw new ExpectedError("You don't have any devices online");
}
const defaultUuid = _(onlineDevices).map('uuid').includes(preferredUuid)
? preferredUuid
: onlineDevices[0].uuid;
return getCliForm().ask({
message: 'Select a device',
type: 'list',
default: defaultUuid,
choices: _.map(onlineDevices, (device) => ({
name: `${device.device_name || 'Untitled'} (${device.uuid.slice(
0,
7,
)})`,
value: device.uuid,
})),
});
});
}
/*
* Given applicationOrDevice, which may be
* - an application name
* - an application slug
* - an application id (integer)
* - a device uuid
* Either:
* - in case of device uuid, return uuid of device after verifying that it exists and is online.
* - in case of application, return uuid of device user selects from list of online devices.
*
* TODO: Modify this when app IDs dropped.
*/
export async function getOnlineTargetDeviceUuid(
sdk: BalenaSdk.BalenaSDK,
applicationOrDevice: string,
) {
const logger = (await import('../utils/logger')).getLogger();
// If looks like UUID, probably device
if (validation.validateUuid(applicationOrDevice)) {
let device: Device;
try {
logger.logDebug(
`Trying to fetch device by UUID ${applicationOrDevice} (${typeof applicationOrDevice})`,
);
device = await sdk.models.device.get(applicationOrDevice, {
$select: ['uuid', 'is_online'],
});
if (!device.is_online) {
throw new ExpectedError(
`Device with UUID ${applicationOrDevice} is offline`,
);
}
return device.uuid;
} catch (err) {
const { BalenaDeviceNotFound } = await import('balena-errors');
if (instanceOf(err, BalenaDeviceNotFound)) {
logger.logDebug(`Device with UUID ${applicationOrDevice} not found`);
// Now try app
} else {
throw err;
}
}
}
// Not a device UUID, try app
let app: Application;
try {
logger.logDebug(`Fetching fleet ${applicationOrDevice}`);
const { getApplication } = await import('./sdk');
app = await getApplication(sdk, applicationOrDevice);
} catch (err) {
const { BalenaApplicationNotFound } = await import('balena-errors');
if (instanceOf(err, BalenaApplicationNotFound)) {
throw new ExpectedError(
`Fleet or Device not found: ${applicationOrDevice}`,
);
} else {
throw err;
}
}
// App found, load its devices
const devices = await sdk.models.device.getAllByApplication(app.id, {
$select: ['device_name', 'uuid'],
$filter: { is_online: true },
});
// Throw if no devices online
if (_.isEmpty(devices)) {
throw new ExpectedError(
`Fleet ${app.slug} found, but has no devices online.`,
);
}
// Ask user to select from online devices for application
return getCliForm().ask({
message: `Select a device on fleet ${app.slug}`,
type: 'list',
default: devices[0].uuid,
choices: _.map(devices, (device) => ({
name: `${device.device_name || 'Untitled'} (${device.uuid.slice(0, 7)})`,
value: device.uuid,
})),
});
}
export function selectFromList<T>(
message: string,
choices: Array<T & { name: string }>,
): Promise<T> {
return getCliForm().ask<T>({
message,
type: 'list',
choices: _.map(choices, (s) => ({
name: s.name,
value: s,
})),
});
}

View File

@ -1,114 +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 type {
Application,
BalenaSDK,
Organization,
PineOptions,
} from 'balena-sdk';
/**
* Wraps the sdk application.get method,
* adding disambiguation in cases where the provided
* identifier could be interpreted in multiple valid ways.
*/
export async function getApplication(
sdk: BalenaSDK,
nameOrSlugOrId: string | number,
options?: PineOptions<Application>,
): Promise<Application> {
const { looksLikeInteger } = await import('./validation');
if (looksLikeInteger(nameOrSlugOrId as string)) {
try {
// Test for existence of app with this numerical ID
return await sdk.models.application.get(Number(nameOrSlugOrId), options);
} catch (e) {
const { instanceOf } = await import('../errors');
const { BalenaApplicationNotFound } = await import('balena-errors');
if (!instanceOf(e, BalenaApplicationNotFound)) {
throw e;
}
// App with this numerical ID not found, but there may be an app with this numerical name.
}
}
return sdk.models.application.get(nameOrSlugOrId, options);
}
/**
* Given an string representation of an application identifier,
* which could be one of:
* - name (including numeric names)
* - slug
* - numerical id
* disambiguate and return a properly typed identifier.
*
* Attempts to minimise the number of API calls required.
* TODO: Remove this once support for numeric App IDs is removed.
*/
export async function getTypedApplicationIdentifier(
sdk: BalenaSDK,
nameOrSlugOrId: string,
) {
const { looksLikeInteger } = await import('./validation');
// If there's no possible ambiguity,
// return the passed identifier unchanged
if (!looksLikeInteger(nameOrSlugOrId)) {
return nameOrSlugOrId;
}
// Resolve ambiguity
try {
// Test for existence of app with this numerical ID,
// and return typed id if found
return (await sdk.models.application.get(Number(nameOrSlugOrId))).id;
} catch (e) {
const { instanceOf } = await import('../errors');
const { BalenaApplicationNotFound } = await import('balena-errors');
if (!instanceOf(e, BalenaApplicationNotFound)) {
throw e;
}
}
// App with this numerical id not found
// return the passed identifier unchanged
return nameOrSlugOrId;
}
/**
* Wraps the sdk organization.getAll method,
* restricting to those orgs user is a member of
*/
export async function getOwnOrganizations(
sdk: BalenaSDK,
): Promise<Organization[]> {
return await sdk.models.organization.getAll({
$filter: {
organization_membership: {
$any: {
$alias: 'orm',
$expr: {
orm: {
user: await sdk.auth.getUserId(),
},
},
},
},
},
$orderby: 'name asc',
});
}

View File

@ -1,169 +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 { spawn, StdioOptions } from 'child_process';
import * as _ from 'lodash';
import { TypedError } from 'typed-error';
import { ExpectedError } from '../errors';
export class ExecError extends TypedError {
public cmd: string;
public exitCode: number;
constructor(cmd: string, exitCode: number) {
super(`Command '${cmd}' failed with error: ${exitCode}`);
this.cmd = cmd;
this.exitCode = exitCode;
}
}
export async function exec(
deviceIp: string,
cmd: string,
stdout?: NodeJS.WritableStream,
): Promise<void> {
const { which } = await import('./which');
const program = await which('ssh');
const args = [
'-n',
'-t',
'-p',
'22222',
'-o',
'LogLevel=ERROR',
'-o',
'StrictHostKeyChecking=no',
'-o',
'UserKnownHostsFile=/dev/null',
`root@${deviceIp}`,
cmd,
];
if (process.env.DEBUG) {
const logger = (await import('./logger')).getLogger();
logger.logDebug(`Executing [${program},${args}]`);
}
// Note: stdin must be 'inherit' to workaround a bug in older versions of
// the built-in Windows 10 ssh client that otherwise prints the following
// to stderr and hangs: "GetConsoleMode on STD_INPUT_HANDLE failed with 6"
// They fixed the bug in newer versions of the ssh client:
// https://github.com/PowerShell/Win32-OpenSSH/issues/856
// but users whould have to manually download and install a new client.
// Note that "ssh -n" does not solve the problem, but should in theory
// prevent the ssh client from using the CLI process stdin, even if it
// is connected with 'inherit'.
const stdio: StdioOptions = [
'inherit',
stdout ? 'pipe' : 'inherit',
'inherit',
];
const exitCode = await new Promise<number>((resolve, reject) => {
const ps = spawn(program, args, { stdio })
.on('error', reject)
.on('close', resolve);
if (stdout) {
ps.stdout.pipe(stdout);
}
});
if (exitCode !== 0) {
throw new ExecError(cmd, exitCode);
}
}
export async function execBuffered(
deviceIp: string,
cmd: string,
enc?: string,
): Promise<string> {
const through = await import('through2');
const buffer: string[] = [];
await exec(
deviceIp,
cmd,
through(function (data, _enc, cb) {
buffer.push(data.toString(enc));
cb();
}),
);
return buffer.join('');
}
/**
* Return a device's balenaOS release by executing 'cat /etc/os-release'
* over ssh to the given deviceIp address. The result is cached with
* lodash's memoize.
*/
export const getDeviceOsRelease = _.memoize(async (deviceIp: string) =>
execBuffered(deviceIp, 'cat /etc/os-release'),
);
// TODO: consolidate the various forms of executing ssh child processes
// in the CLI, like exec and spawn, starting with the files:
// lib/actions/ssh.ts
// lib/utils/ssh.ts
// lib/utils/device/ssh.ts
/**
* Obtain the full path for ssh using which, then spawn a child process.
* - If the child process returns error code 0, return the function normally
* (do not throw an error).
* - If the child process returns a non-zero error code, set process.exitCode
* to that error code, and throw ExpectedError with a warning message.
* - If the child process is terminated by a process signal, set
* process.exitCode = 1, and throw ExpectedError with a warning message.
*/
export async function spawnSshAndThrowOnError(
args: string[],
options?: import('child_process').SpawnOptions,
) {
const { whichSpawn } = await import('./which');
const [exitCode, exitSignal] = await whichSpawn(
'ssh',
args,
options,
true, // returnExitCodeOrSignal
);
if (exitCode || exitSignal) {
// ssh returns a wide range of exit codes, including return codes of
// interactive shells. For example, if the user types CTRL-C on an
// interactive shell and then `exit`, ssh returns error code 130.
// Another example, typing "exit 1" on an interactive shell causes ssh
// to return exit code 1. In these cases, print a short one-line warning
// message, and exits the CLI process with the same error code.
process.exitCode = exitCode;
throw new ExpectedError(sshErrorMessage(exitSignal, exitCode));
}
}
function sshErrorMessage(exitSignal?: string, exitCode?: number) {
const msg: string[] = [];
if (exitSignal) {
msg.push(`Warning: ssh process was terminated with signal "${exitSignal}"`);
} else {
msg.push(`Warning: ssh process exited with non-zero code "${exitCode}"`);
switch (exitCode) {
case 255:
msg.push(`
Are the SSH keys correctly configured in balenaCloud? See:
https://www.balena.io/docs/learn/manage/ssh-access/#add-an-ssh-key-to-balenacloud`);
msg.push('Are you accidentally using `sudo`?');
}
}
return msg.join('\n');
}

View File

@ -1,53 +0,0 @@
/*
Copyright 2016-2019 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 isRoot = require('is-root');
import * as UpdateNotifier from 'update-notifier';
import packageJSON = require('../../package.json');
// Check for an update once a day. 1 day granularity should be
// enough, rather than every run.
const balenaUpdateInterval = 1000 * 60 * 60 * 24 * 1;
let notifier: UpdateNotifier.UpdateNotifier;
export function notify() {
if (!notifier) {
// `update-notifier` creates files to make the next
// running time ask for updated, however this can lead
// to ugly EPERM issues if those files are created as root.
if (isRoot()) {
return;
} else {
notifier = UpdateNotifier({
pkg: packageJSON,
updateCheckInterval: balenaUpdateInterval,
});
}
}
const up = notifier.update;
if (
up &&
(require('semver') as typeof import('semver')).lt(up.current, up.latest)
) {
notifier.notify({
defer: false,
message: `Update available ${up.current}${up.latest}\n
https://github.com/balena-io/balena-cli/blob/master/INSTALL.md`,
});
}
}

33848
npm-shrinkwrap.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "balena-cli",
"version": "12.48.14",
"version": "22.1.1",
"description": "The official balena Command Line Interface",
"main": "./build/app.js",
"homepage": "https://github.com/balena-io/balena-cli",
@ -14,65 +14,50 @@
"bin/",
"build/",
"doc/",
"lib/",
"src/",
"patches/",
"!patches/**/**.dev.patch",
"*.md",
"npm-shrinkwrap.json",
"oclif.manifest.json"
],
"bin": {
"balena": "./bin/balena"
},
"pkg": {
"scripts": [
"build/**/*.js",
"node_modules/balena-sdk/es2018/index.js",
"node_modules/balena-sync/build/**/*.js",
"node_modules/pinejs-client-request/node_modules/pinejs-client-core/es2018/index.js",
"node_modules/resin-compose-parse/build/schemas/*.json"
],
"assets": [
"build/auth/pages/*.ejs",
"node_modules/resin-discoverable-services/services/**/*",
"node_modules/balena-sdk/node_modules/balena-pine/**/*",
"node_modules/balena-pine/**/*",
"node_modules/pinejs-client-core/**/*",
"node_modules/opn/xdg-open",
"node_modules/open/xdg-open",
"node_modules/windosu/*.bat",
"node_modules/windosu/*.cmd",
"npm-shrinkwrap.json",
"oclif.manifest.json"
]
"balena": "./bin/run.js"
},
"scripts": {
"postinstall": "node patches/apply-patches.js",
"prebuild": "rimraf build/ build-bin/",
"pretarball": "ts-node --transpile-only ../../automation/run.ts sign:binaries",
"build": "npm run build:src && npm run catch-uncommitted",
"build:t": "npm run lint && npm run build:fast && npm run build:test",
"build:src": "npm run lint && npm run build:fast && npm run build:test && npm run build:doc && npm run build:completion",
"build:fast": "gulp pages && tsc && npx oclif-dev manifest",
"build:test": "tsc -P ./tsconfig.dev.json --noEmit && tsc -P ./tsconfig.js.json --noEmit",
"build:doc": "ts-node --transpile-only automation/capitanodoc/index.ts > doc/cli.markdown",
"build:pages": "mkdirp ./build/auth/pages/&& inline-source --compress ./src/auth/pages/error.ejs ./build/auth/pages/error.ejs && inline-source --compress ./src/auth/pages/success.ejs ./build/auth/pages/success.ejs",
"build:fast": "npm run build:pages && tsc && npx oclif manifest",
"build:test": "tsc -P ./tsconfig.dev.json --noEmit",
"build:doc": "ts-node --transpile-only automation/capitanodoc/index.ts > docs/balena-cli.md",
"build:completion": "node completion/generate-completion.js",
"build:standalone": "ts-node --transpile-only automation/run.ts build:standalone",
"build:installer": "ts-node --transpile-only automation/run.ts build:installer",
"deduplicate-dependencies": "npm dd && git add npm-shrinkwrap.json && git commit --message \"Deduplicate dependencies\"",
"package": "npm run build:fast && npm run build:standalone && npm run build:installer",
"release": "ts-node --transpile-only automation/run.ts release",
"pretest": "npm run build",
"test": "npm run test:shrinkwrap && npm run test:source && npm run test:standalone",
"test": "npm run test:shrinkwrap && npm run test:core",
"test:core": "npm run test:source && npm run test:standalone",
"test:shrinkwrap": "ts-node --transpile-only automation/run.ts test-shrinkwrap",
"test:source": "cross-env BALENA_CLI_TEST_TYPE=source mocha",
"test:standalone": "npm run build:standalone && npm run test:standalone:fast",
"test:standalone:fast": "cross-env BALENA_CLI_TEST_TYPE=standalone mocha --config .mocharc-standalone.js",
"test:fast": "npm run build:fast && npm run test:source",
"test:fast-profile": "npm run test:fast -- -- --inspect-brk=0.0.0.0",
"test:debug": "cross-env BALENA_CLI_TEST_TYPE=source mocha --inspect-brk=0.0.0.0",
"test:only": "npm run build:fast && cross-env BALENA_CLI_TEST_TYPE=source mocha \"tests/**/${npm_config_test}.spec.ts\"",
"catch-uncommitted": "ts-node --transpile-only automation/run.ts catch-uncommitted",
"ci": "npm run test && npm run catch-uncommitted",
"watch": "gulp watch",
"lint": "balena-lint -e ts -e js --fix automation/ completion/ lib/ typings/ tests/ bin/balena bin/balena-dev gulpfile.js .mocharc.js .mocharc-standalone.js",
"lint": "npm run lint-tsconfig && npm run lint-other",
"lint-tsconfig": "balena-lint -e ts -e js -t tsconfig.dev.json --fix automation/ src/ tests/ typings/",
"lint-other": "balena-lint -e ts -e js --fix bin/run.js bin/dev.js completion/ .mocharc.js .mocharc-standalone.js",
"update": "ts-node --transpile-only ./automation/update-module.ts",
"prepare": "echo {} > bin/.fast-boot.json",
"prepare": "echo {} > bin/.fast-boot.json && husky",
"prepublishOnly": "npm run build"
},
"keywords": [
@ -87,208 +72,182 @@
"author": "Balena Inc. (https://balena.io/)",
"license": "Apache-2.0",
"engines": {
"node": ">=10.20.0 <13.0.0",
"npm": "<7.0.0"
},
"husky": {
"hooks": {
"pre-commit": "node automation/check-npm-version.js && node automation/check-doc.js"
}
"node": ">=20.6.0 <23"
},
"oclif": {
"bin": "balena",
"commands": "./build/commands",
"helpClass": "./build/help",
"topicSeparator": " ",
"hooks": {
"prerun": "./build/hooks/prerun/track",
"prerun": "./build/hooks/prerun",
"command_not_found": "./build/hooks/command-not-found/suggest"
},
"additionalHelpFlags": [
"help"
],
"macos": {
"identifier": "io.balena.cli",
"sign": "Developer ID Installer: Balena Ltd (66H43P8FRG)"
},
"plugins": [
"@oclif/plugin-help"
]
"sign": "\"Developer ID Installer: Balena Ltd (66H43P8FRG)\""
}
},
"devDependencies": {
"@balena/lint": "^6.1.1",
"@oclif/config": "^1.17.0",
"@oclif/dev-cli": "^1.26.0",
"@oclif/parser": "^3.8.5",
"@octokit/plugin-throttling": "^3.5.1",
"@octokit/rest": "^18.6.7",
"@types/archiver": "^5.1.1",
"@balena/lint": "^9.1.3",
"@electron/notarize": "^2.0.0",
"@types/bluebird": "^3.5.36",
"@types/body-parser": "^1.19.1",
"@types/chai": "^4.2.21",
"@types/body-parser": "^1.19.2",
"@types/chai": "^4.3.0",
"@types/chai-as-promised": "^7.1.4",
"@types/cli-truncate": "^2.0.0",
"@types/common-tags": "^1.8.1",
"@types/dockerode": "^3.2.4",
"@types/ejs": "^3.0.7",
"@types/dockerode": "3.3.41",
"@types/ejs": "^3.1.0",
"@types/express": "^4.17.13",
"@types/fs-extra": "^9.0.12",
"@types/fast-levenshtein": "^0.0.4",
"@types/fs-extra": "^11.0.4",
"@types/global-agent": "^2.1.1",
"@types/global-tunnel-ng": "^2.1.1",
"@types/http-proxy": "^1.17.7",
"@types/http-proxy": "^1.17.8",
"@types/inquirer": "^7.3.3",
"@types/intercept-stdout": "^0.1.0",
"@types/is-root": "^2.1.2",
"@types/js-yaml": "^4.0.2",
"@types/jsonwebtoken": "^8.5.4",
"@types/klaw": "^3.0.2",
"@types/lodash": "^4.14.171",
"@types/mixpanel": "^2.14.3",
"@types/mocha": "^8.2.3",
"@types/mock-require": "^2.0.0",
"@types/moment-duration-format": "^2.2.3",
"@types/js-yaml": "^4.0.5",
"@types/jsonwebtoken": "^9.0.6",
"@types/klaw": "^3.0.6",
"@types/lodash": "^4.14.178",
"@types/mime": "^3.0.4",
"@types/mocha": "^10.0.7",
"@types/mock-fs": "^4.13.4",
"@types/mock-require": "^2.0.1",
"@types/ndjson": "^2.0.1",
"@types/net-keepalive": "^0.4.1",
"@types/nock": "^11.1.0",
"@types/node": "^10.17.60",
"@types/node-cleanup": "^2.1.1",
"@types/parse-link-header": "^1.0.0",
"@types/prettyjson": "^0.0.30",
"@types/node": "^20.0.0",
"@types/node-cleanup": "^2.1.2",
"@types/prettyjson": "^0.0.33",
"@types/progress-stream": "^2.0.2",
"@types/request": "^2.48.6",
"@types/rewire": "^2.5.28",
"@types/rimraf": "^3.0.1",
"@types/rewire": "^2.5.30",
"@types/rimraf": "^3.0.2",
"@types/semver": "^7.3.9",
"@types/shell-escape": "^0.2.0",
"@types/sinon": "^10.0.2",
"@types/sinon": "^17.0.3",
"@types/split": "^1.0.0",
"@types/stream-to-promise": "^2.2.1",
"@types/tar-stream": "^2.2.1",
"@types/tar-stream": "^2.2.2",
"@types/through2": "^2.0.36",
"@types/tmp": "^0.2.1",
"@types/tmp": "^0.2.3",
"@types/update-notifier": "^4.1.1",
"@types/which": "^2.0.1",
"archiver": "^5.3.0",
"@types/window-size": "^1.1.1",
"catch-uncommitted": "^2.0.0",
"chai": "^4.3.4",
"chai-as-promised": "^7.1.1",
"cross-env": "^7.0.3",
"deep-object-diff": "^1.1.0",
"diff": "^5.0.0",
"electron-notarize": "^1.0.0",
"ent": "^2.2.0",
"filehound": "^1.17.4",
"fs-extra": "^9.1.0",
"gulp": "^4.0.2",
"gulp-inline-source": "^4.0.0",
"fs-extra": "^11.2.0",
"http-proxy": "^1.18.1",
"husky": "^4.3.8",
"husky": "^9.1.5",
"inline-source-cli": "^2.0.0",
"intercept-stdout": "^0.1.2",
"jsonwebtoken": "^8.5.1",
"mocha": "^8.4.0",
"jsonwebtoken": "^9.0.0",
"klaw": "^4.1.0",
"mocha": "^10.6.0",
"mock-fs": "^5.2.0",
"mock-require": "^3.0.3",
"nock": "^13.1.1",
"parse-link-header": "^1.0.1",
"pkg": "^4.4.9",
"publish-release": "^1.6.1",
"rewire": "^5.0.0",
"simple-git": "^2.40.0",
"sinon": "^11.1.2",
"ts-node": "^10.0.0",
"typescript": "^4.3.5"
"nock": "^14.0.4",
"oclif": "^4.17.0",
"rewire": "^7.0.0",
"simple-git": "^3.14.1",
"sinon": "^19.0.0",
"string-to-stream": "^3.0.1",
"ts-node": "^10.4.0",
"typescript": "^5.8.2"
},
"dependencies": {
"@balena/compose": "^7.0.9",
"@balena/dockerignore": "^1.0.2",
"@balena/es-version": "^1.0.0",
"@oclif/command": "^1.8.0",
"@resin.io/valid-email": "^0.1.0",
"@sentry/node": "^5.25.0",
"@types/fast-levenshtein": "0.0.1",
"@types/update-notifier": "^4.1.1",
"@zeit/dockerignore": "0.0.3",
"JSONStream": "^1.0.3",
"balena-config-json": "^4.1.1",
"balena-device-init": "^6.0.0",
"balena-errors": "^4.7.1",
"balena-image-fs": "^7.0.6",
"balena-image-manager": "^7.0.3",
"balena-preload": "^10.5.0",
"balena-release": "^3.2.0",
"balena-sdk": "^15.48.0",
"@balena/env-parsing": "^1.1.8",
"@balena/es-version": "^1.0.1",
"@oclif/core": "^4.1.0",
"@sentry/node": "^9.0.0",
"balena-config-json": "^4.2.7",
"balena-device-init": "^8.1.11",
"balena-errors": "^4.7.3",
"balena-image-fs": "^7.5.2",
"balena-preload": "^18.0.4",
"balena-sdk": "^21.3.0",
"balena-semver": "^2.3.0",
"balena-settings-client": "^4.0.7",
"balena-settings-storage": "^7.0.0",
"balena-sync": "^11.0.2",
"bluebird": "^3.7.2",
"body-parser": "^1.19.0",
"chalk": "^3.0.0",
"chokidar": "^3.4.3",
"balena-settings-client": "^5.0.2",
"balena-settings-storage": "^8.1.0",
"body-parser": "^1.19.1",
"bonjour-service": "^1.2.1",
"chalk": "^4.0.0",
"chokidar": "^3.5.2",
"cli-truncate": "^2.1.0",
"color-hash": "^1.0.3",
"columnify": "^1.5.2",
"color-hash": "^1.1.1",
"common-tags": "^1.7.2",
"date-fns": "^4.1.0",
"denymount": "^2.3.0",
"docker-modem": "^3.0.0",
"docker-progress": "^5.0.0",
"docker-qemu-transpose": "^1.1.1",
"dockerode": "^3.3.0",
"ejs": "^3.1.3",
"etcher-sdk": "^6.2.1",
"event-stream": "3.3.4",
"express": "^4.13.3",
"docker-modem": "^5.0.6",
"docker-progress": "^5.1.3",
"dockerode": "^4.0.5",
"ejs": "^3.1.6",
"etcher-sdk": "^10.0.0",
"express": "^4.17.2",
"fast-boot2": "^1.1.0",
"fast-levenshtein": "^3.0.0",
"file-disk": "^8.0.1",
"filenamify": "^4.3.0",
"get-stdin": "^8.0.0",
"glob": "^7.1.7",
"global-agent": "^2.1.12",
"glob": "^7.2.0",
"global-agent": "^2.2.0",
"global-tunnel-ng": "^2.1.1",
"got": "^11.8.2",
"got": "^11.8.3",
"humanize": "0.0.9",
"ignore": "^5.1.8",
"inquirer": "^7.3.3",
"is-elevated": "^3.0.0",
"is-root": "^2.1.0",
"js-yaml": "^4.0.0",
"klaw": "^3.0.0",
"livepush": "^3.5.0",
"js-yaml": "^4.1.0",
"JSONStream": "^1.0.3",
"jwt-decode": "^3.1.2",
"livepush": "^3.5.1",
"lodash": "^4.17.21",
"minimatch": "^3.0.4",
"mixpanel": "^0.10.3",
"moment": "^2.27.0",
"moment-duration-format": "^2.3.2",
"mime": "^2.4.6",
"mkdirp": "^3.0.1",
"ndjson": "^2.0.0",
"net-keepalive": "^3.0.0",
"node-cleanup": "^2.1.2",
"node-unzip-2": "^0.2.8",
"oclif": "^1.18.1",
"open": "^7.1.0",
"partitioninfo": "^6.0.2",
"patch-package": "^6.4.7",
"prettyjson": "^1.1.3",
"patch-package": "^8.0.0",
"prettyjson": "^1.2.5",
"progress-stream": "^2.0.0",
"reconfix": "^1.0.0-v0-1-0-fork-46760acff4d165f5238bfac5e464256ef1944476",
"request": "^2.88.2",
"resin-cli-form": "^2.0.2",
"resin-cli-visuals": "^1.8.0",
"resin-compose-parse": "^2.1.3",
"resin-doodles": "^0.1.1",
"resin-multibuild": "^4.11.0",
"resin-cli-form": "^4.0.0",
"resin-cli-visuals": "^3.0.0",
"resin-doodles": "^0.2.0",
"resin-stream-logger": "^0.1.2",
"rimraf": "^3.0.2",
"semver": "^7.3.2",
"semver": "^7.3.5",
"shell-escape": "^0.2.0",
"split": "^1.0.1",
"stream-to-promise": "^2.2.0",
"string-width": "^4.2.0",
"string-width": "^4.2.3",
"strip-ansi-stream": "^1.0.0",
"tar-stream": "^2.1.3",
"tar-utils": "^2.1.1",
"through2": "^2.0.3",
"tmp": "^0.2.1",
"typed-error": "^3.2.1",
"update-notifier": "^4.1.0",
"update-notifier": "^5.1.0",
"which": "^2.0.2",
"window-size": "^1.1.0"
},
"optionalDependencies": {
"windosu": "^0.3.0"
},
"overrides": {
"inline-source-cli": {
"inline-source": "^8.0.3"
}
},
"versionist": {
"publishedAt": "2021-09-20T17:38:23.634Z"
"publishedAt": "2025-06-19T09:32:53.877Z"
}
}

View File

@ -1,15 +0,0 @@
diff --git a/node_modules/@oclif/config/lib/config.js b/node_modules/@oclif/config/lib/config.js
index aba1da9..830f800 100644
--- a/node_modules/@oclif/config/lib/config.js
+++ b/node_modules/@oclif/config/lib/config.js
@@ -165,7 +165,9 @@ class Config {
debug('runCommand %s %o', id, argv);
const c = this.findCommand(id);
if (!c) {
- await this.runHook('command_not_found', { id });
+ // argv added to command_not_found hook
+ // We should try to upstream this change
+ await this.runHook('command_not_found', { id, argv });
throw new errors_1.CLIError(`command ${id} not found`);
}
const command = c.load();

View File

@ -0,0 +1,79 @@
diff --git a/node_modules/@oclif/core/lib/help/command.js b/node_modules/@oclif/core/lib/help/command.js
index 33105a0..0436982 100644
--- a/node_modules/@oclif/core/lib/help/command.js
+++ b/node_modules/@oclif/core/lib/help/command.js
@@ -58,7 +58,8 @@ class CommandHelp extends formatter_1.HelpFormatter {
return;
return args.map((a) => {
// Add ellipsis to indicate that the argument takes multiple values if strict is false
- const name = this.command.strict === false ? `${a.name.toUpperCase()}...` : a.name.toUpperCase();
+ let name = this.command.strict === false ? `${a.name.toUpperCase()}...` : a.name.toUpperCase();
+ name = a.required ? `<${name}>` : `[${name}]`;
let description = a.description || '';
if (a.default)
description = `${(0, theme_1.colorize)(this.config?.theme?.flagDefaultValue, `[default: ${a.default}]`)} ${description}`;
diff --git a/node_modules/@oclif/core/lib/help/index.js b/node_modules/@oclif/core/lib/help/index.js
index 0b48c0e..ff4fed4 100644
--- a/node_modules/@oclif/core/lib/help/index.js
+++ b/node_modules/@oclif/core/lib/help/index.js
@@ -173,11 +173,12 @@ class Help extends HelpBase {
}
this.log(this.formatCommand(command));
this.log('');
- if (subTopics.length > 0) {
+ const SUPPRESS_SUBTOPICS = true;
+ if (subTopics.length > 0 && !SUPPRESS_SUBTOPICS) {
this.log(this.formatTopics(subTopics));
this.log('');
}
- if (subCommands.length > 0) {
+ if (subCommands.length > 0 && !SUPPRESS_SUBTOPICS) {
const aliases = [];
const uniqueSubCommands = subCommands.filter((p) => {
aliases.push(...p.aliases);
diff --git a/node_modules/@oclif/core/lib/parser/errors.js b/node_modules/@oclif/core/lib/parser/errors.js
index 168da99..538a880 100644
--- a/node_modules/@oclif/core/lib/parser/errors.js
+++ b/node_modules/@oclif/core/lib/parser/errors.js
@@ -15,7 +15,8 @@ class CLIParseError extends errors_1.CLIError {
parse;
showHelp = false;
constructor(options) {
- options.message += '\nSee more help with --help';
+ const help = options.command ? `\`${options.command} --help\`` : '--help';
+ options.message += `\nSee more help with ${help}`;
super(options.message, { exit: options.exit });
this.parse = options.parse;
}
@@ -38,7 +39,8 @@ exports.InvalidArgsSpecError = InvalidArgsSpecError;
class RequiredArgsError extends CLIParseError {
args;
constructor({ args, exit, flagsWithMultiple, parse, }) {
- let message = `Missing ${args.length} required arg${args.length === 1 ? '' : 's'}`;
+ const command = 'balena ' + parse.input.context.id.replace(/:/g, ' ');
+ let message = `Missing ${args.length} required argument${args.length === 1 ? '' : 's'}`;
const namedArgs = args.filter((a) => a.name);
if (namedArgs.length > 0) {
const list = (0, list_1.default)(namedArgs.map((a) => {
@@ -52,7 +54,7 @@ class RequiredArgsError extends CLIParseError {
message += `\n\nNote: ${flags} allow${flagsWithMultiple.length === 1 ? 's' : ''} multiple values. Because of this you need to provide all arguments before providing ${flagsWithMultiple.length === 1 ? 'that flag' : 'those flags'}.`;
message += '\nAlternatively, you can use "--" to signify the end of the flags and the beginning of arguments.';
}
- super({ exit: cache_1.default.getInstance().get('exitCodes')?.requiredArgs ?? exit, message, parse });
+ super({ exit: cache_1.default.getInstance().get('exitCodes')?.requiredArgs ?? exit, message, parse, command });
this.args = args;
this.showHelp = true;
}
diff --git a/node_modules/@oclif/core/lib/ux/list.js b/node_modules/@oclif/core/lib/ux/list.js
index 954954c..0e507c7 100644
--- a/node_modules/@oclif/core/lib/ux/list.js
+++ b/node_modules/@oclif/core/lib/ux/list.js
@@ -22,7 +22,7 @@ function renderList(items) {
}
left = left.padEnd(maxLength);
right = linewrap(maxLength + 2, right);
- return `${left} ${right}`;
+ return `${left} : ${right}`;
});
return lines.join('\n');
}

View File

@ -1,250 +0,0 @@
diff --git a/node_modules/@oclif/dev-cli/lib/commands/pack/macos.js b/node_modules/@oclif/dev-cli/lib/commands/pack/macos.js
index e0abbbe..debf799 100644
--- a/node_modules/@oclif/dev-cli/lib/commands/pack/macos.js
+++ b/node_modules/@oclif/dev-cli/lib/commands/pack/macos.js
@@ -128,6 +128,7 @@ class PackMacos extends command_1.Command {
if (process.env.OSX_KEYCHAIN)
args.push('--keychain', process.env.OSX_KEYCHAIN);
args.push(dist);
+ console.error(`[debug] @oclif/dev-cli pkgbuild "${args.join('" "')}"`);
await qq.x('pkgbuild', args);
}
}
diff --git a/node_modules/@oclif/dev-cli/lib/commands/pack/win.js b/node_modules/@oclif/dev-cli/lib/commands/pack/win.js
index a313991..6681892 100644
--- a/node_modules/@oclif/dev-cli/lib/commands/pack/win.js
+++ b/node_modules/@oclif/dev-cli/lib/commands/pack/win.js
@@ -51,6 +51,13 @@ VIAddVersionKey /LANG=\${LANG_ENGLISH} "ProductVersion" "\${VERSION}.0"
InstallDir "\$PROGRAMFILES${arch === 'x64' ? '64' : ''}\\${config.dirname}"
Section "${config.name} CLI \${VERSION}"
+ ; First remove any old client files.
+ ; (Remnants of old versions were causing CLI errors)
+ ; Initially tried running the Uninstall.exe, but was
+ ; unable to make script wait for completion (despite using _?)
+ DetailPrint "Removing files from previous version."
+ RMDir /r "$INSTDIR\\client"
+
SetOutPath $INSTDIR
File /r bin
File /r client
@@ -192,7 +199,8 @@ class PackWin extends command_1.Command {
async run() {
await this.checkForNSIS();
const { flags } = this.parse(PackWin);
- const buildConfig = await Tarballs.buildConfig(flags.root);
+ const targets = flags.targets ? flags.targets.split(',') : undefined;
+ const buildConfig = await Tarballs.buildConfig(flags.root, { targets });
const { config } = buildConfig;
await Tarballs.build(buildConfig, { platform: 'win32', pack: false });
const arches = buildConfig.targets.filter(t => t.platform === 'win32').map(t => t.arch);
@@ -207,7 +215,8 @@ class PackWin extends command_1.Command {
// eslint-disable-next-line no-await-in-loop
await qq.mv(buildConfig.workspace({ platform: 'win32', arch }), [installerBase, 'client']);
// eslint-disable-next-line no-await-in-loop
- await qq.x(`makensis ${installerBase}/${config.bin}.nsi | grep -v "\\[compress\\]" | grep -v "^File: Descending to"`);
+ const { msysExec, toMsysPath } = require("../../util");
+ await msysExec(`makensis ${toMsysPath(installerBase)}/${config.bin}.nsi | grep -v "\\[compress\\]" | grep -v "^File: Descending to"`);
const o = buildConfig.dist(`win/${config.bin}-v${buildConfig.version}-${arch}.exe`);
// eslint-disable-next-line no-await-in-loop
await qq.mv([installerBase, 'installer.exe'], o);
@@ -232,4 +241,5 @@ exports.default = PackWin;
PackWin.description = 'create windows installer from oclif CLI';
PackWin.flags = {
root: command_1.flags.string({ char: 'r', description: 'path to oclif CLI root', default: '.', required: true }),
+ targets: command_1.flags.string({char: 't', description: 'comma-separated targets to pack (e.g.: win32-x86,win32-x64)'}),
};
diff --git a/node_modules/@oclif/dev-cli/lib/tarballs/build.js b/node_modules/@oclif/dev-cli/lib/tarballs/build.js
index c6bd245..baa7f6f 100644
--- a/node_modules/@oclif/dev-cli/lib/tarballs/build.js
+++ b/node_modules/@oclif/dev-cli/lib/tarballs/build.js
@@ -18,8 +18,9 @@ const pack = async (from, to) => {
qq.cd(prevCwd);
};
async function build(c, options = {}) {
- const { xz, config } = c;
+ const { xz, config, tmp } = c;
const prevCwd = qq.cwd();
+ console.error(`[debug] @oclif/dev-cli cwd="${prevCwd}"\n c.root="${c.root}" c.workspace()="${c.workspace()}"`);
const packCLI = async () => {
const stdout = await qq.x.stdout('npm', ['pack', '--unsafe-perm'], { cwd: c.root });
return path.join(c.root, stdout.split('\n').pop());
@@ -30,11 +31,19 @@ async function build(c, options = {}) {
tarball = path.basename(tarball);
tarball = qq.join([c.workspace(), tarball]);
qq.cd(c.workspace());
- await qq.x(`tar -xzf ${tarball}`);
+ const { msysExec, toMsysPath } = require("../util");
+ await msysExec(`tar -xzf ${toMsysPath(tarball)}`);
// eslint-disable-next-line no-await-in-loop
for (const f of await qq.ls('package', { fullpath: true }))
await qq.mv(f, '.');
await qq.rm('package', tarball, 'bin/run.cmd');
+ // rename the original balena-cli ./bin/balena entry point for oclif compatibility
+ await qq.mv('bin/balena', 'bin/run');
+ // The oclif installers are a production installation, while the source
+ // `bin` folder may contain a `.fast-boot.json` file of a dev installation.
+ // This has previously led to issues preventing the CLI from starting, so
+ // delete `.fast-boot.json` (if any) from the destination folder.
+ await qq.rm('bin/.fast-boot.json');
};
const updatePJSON = async () => {
qq.cd(c.workspace());
@@ -46,21 +55,21 @@ async function build(c, options = {}) {
await qq.writeJSON('package.json', pjson);
};
const addDependencies = async () => {
- qq.cd(c.workspace());
- const yarnRoot = findYarnWorkspaceRoot(c.root) || c.root;
- const yarn = await qq.exists([yarnRoot, 'yarn.lock']);
- if (yarn) {
- await qq.cp([yarnRoot, 'yarn.lock'], '.');
- await qq.x('yarn --no-progress --production --non-interactive');
- }
- else {
- let lockpath = qq.join(c.root, 'package-lock.json');
- if (!await qq.exists(lockpath)) {
- lockpath = qq.join(c.root, 'npm-shrinkwrap.json');
- }
- await qq.cp(lockpath, '.');
- await qq.x('npm install --production');
+ const ws = c.workspace();
+ qq.cd(ws);
+ console.error(`[debug] @oclif/dev-cli copying node_modules to "${ws}"`)
+ const source = path.join(c.root, 'node_modules');
+ if (process.platform === 'win32') {
+ // xcopy is much faster than `qq.cp(source, ws)`
+ await qq.x(`xcopy "${source}" "${ws}\\node_modules" /S /E /B /I /K /Q /Y`);
+ } else {
+ // use the shell's `cp` on macOS in order to preserve extended
+ // file attributes containing `codesign` digital signatures
+ await qq.x(`cp -pR "${source}" "${ws}"`);
}
+ console.error(`[debug] @oclif/dev-cli running "npm prune --production" in "${ws}"`);
+ await qq.x('npm prune --production');
+ console.error(`[debug] @oclif/dev-cli done`);
};
const buildTarget = async (target) => {
const workspace = c.workspace(target);
@@ -74,7 +83,8 @@ async function build(c, options = {}) {
output: path.join(workspace, 'bin', 'node'),
platform: target.platform,
arch: target.arch,
- tmp: qq.join(config.root, 'tmp'),
+ tmp,
+ projectRootPath: c.root,
});
if (options.pack === false)
return;
diff --git a/node_modules/@oclif/dev-cli/lib/tarballs/config.js b/node_modules/@oclif/dev-cli/lib/tarballs/config.js
index 9754a6b..68ef6b7 100644
--- a/node_modules/@oclif/dev-cli/lib/tarballs/config.js
+++ b/node_modules/@oclif/dev-cli/lib/tarballs/config.js
@@ -17,7 +17,10 @@ function gitSha(cwd, options = {}) {
}
exports.gitSha = gitSha;
async function Tmp(config) {
- const tmp = path.join(config.root, 'tmp');
+ const tmp = process.env.BUILD_TMP
+ ? path.join(process.env.BUILD_TMP, 'oclif')
+ : path.join(config.root, 'tmp');
+ console.error(`[debug] @oclif/dev-cli tmp="${tmp}"`);
await qq.mkdirp(tmp);
return tmp;
}
@@ -44,7 +47,7 @@ async function buildConfig(root, options = {}) {
s3Config: updateConfig.s3,
nodeVersion: updateConfig.node.version || process.versions.node,
workspace(target) {
- const base = qq.join(config.root, 'tmp');
+ const base = tmp;
if (target && target.platform)
return qq.join(base, [target.platform, target.arch].join('-'), config.s3Key('baseDir', target));
return qq.join(base, config.s3Key('baseDir', target));
diff --git a/node_modules/@oclif/dev-cli/lib/tarballs/node.js b/node_modules/@oclif/dev-cli/lib/tarballs/node.js
index fabe5c4..e32dd76 100644
--- a/node_modules/@oclif/dev-cli/lib/tarballs/node.js
+++ b/node_modules/@oclif/dev-cli/lib/tarballs/node.js
@@ -4,9 +4,10 @@ const errors_1 = require("@oclif/errors");
const path = require("path");
const qq = require("qqjs");
const log_1 = require("../log");
+const { isMSYS2, msysExec, toMsysPath } = require("../util");
async function checkFor7Zip() {
try {
- await qq.x('7z', { stdio: [0, null, 2] });
+ await msysExec('7z', { stdio: [0, null, 2] });
}
catch (error) {
if (error.code === 127)
@@ -41,7 +42,8 @@ async function fetchNodeBinary({ nodeVersion, output, platform, arch, tmp }) {
const basedir = path.dirname(tarball);
await qq.mkdirp(basedir);
await qq.download(url, tarball);
- await qq.x(`grep ${path.basename(tarball)} ${shasums} | shasum -a 256 -c -`, { cwd: basedir });
+ const shaCmd = isMSYS2 ? 'sha256sum -c -' : 'shasum -a 256 -c -';
+ await msysExec(`grep ${path.basename(tarball)} ${toMsysPath(shasums)} | ${shaCmd}`, { cwd: basedir });
};
const extract = async () => {
log_1.log(`extracting ${nodeBase}`);
@@ -51,7 +53,7 @@ async function fetchNodeBinary({ nodeVersion, output, platform, arch, tmp }) {
await qq.mkdirp(path.dirname(cache));
if (platform === 'win32') {
qq.pushd(nodeTmp);
- await qq.x(`7z x -bd -y ${tarball} > /dev/null`);
+ await msysExec(`7z x -bd -y ${toMsysPath(tarball)} > /dev/null`);
await qq.mv([nodeBase, 'node.exe'], cache);
qq.popd();
}
diff --git a/node_modules/@oclif/dev-cli/lib/util.js b/node_modules/@oclif/dev-cli/lib/util.js
index b3d48b7..540bbe6 100644
--- a/node_modules/@oclif/dev-cli/lib/util.js
+++ b/node_modules/@oclif/dev-cli/lib/util.js
@@ -40,3 +40,47 @@ function sortBy(arr, fn) {
}
exports.sortBy = sortBy;
exports.template = (context) => (t) => _.template(t || '')(context);
+
+// OSTYPE is 'msys' for MSYS 1.0 and for MSYS2, or 'cygwin' for Cygwin
+// but note that OSTYPE is not "exported" by default, so run: export OSTYPE=$OSTYPE
+// MSYSTEM is 'MINGW32' for MSYS 1.0, 'MSYS' for MSYS2, and undefined for Cygwin
+const isCygwin = process.env.OSTYPE === 'cygwin';
+const isMinGW = process.env.MSYSTEM && process.env.MSYSTEM.startsWith('MINGW');
+const isMSYS2 = process.env.MSYSTEM && process.env.MSYSTEM.startsWith('MSYS');
+const MSYSSHELLPATH = process.env.MSYSSHELLPATH ||
+ (isMSYS2 ? 'C:\\msys64\\usr\\bin\\bash.exe' :
+ (isMinGW ? 'C:\\MinGW\\msys\\1.0\\bin\\bash.exe' :
+ (isCygwin ? 'C:\\cygwin64\\bin\\bash.exe' : '/bin/sh')));
+
+exports.isCygwin = isCygwin;
+exports.isMinGW = isMinGW;
+exports.isMSYS2 = isMSYS2;
+console.error(`[debug] @oclif/dev-cli MSYSSHELLPATH=${MSYSSHELLPATH} MSYSTEM=${process.env.MSYSTEM} OSTYPE=${process.env.OSTYPE} isMSYS2=${isMSYS2} isMingGW=${isMinGW} isCygwin=${isCygwin}`);
+
+const qq = require("qqjs");
+
+/* Convert a Windows path like 'C:\tmp' to a MSYS path like '/c/tmp' */
+function toMsysPath(windowsPath) {
+ // 'c:\myfolder' -> '/c/myfolder' or '/cygdrive/c/myfolder'
+ let msysPath = windowsPath.replace(/\\/g, '/');
+ if (isMSYS2 || isMinGW) {
+ msysPath = msysPath.replace(/^([a-zA-Z]):/, '/$1');
+ } else if (isCygwin) {
+ msysPath = msysPath.replace(/^([a-zA-Z]):/, '/cygdrive/$1');
+ }
+ console.error(`[debug] @oclif/dev-cli toMsysPath before="${windowsPath}" after="${msysPath}"`);
+ return msysPath;
+}
+exports.toMsysPath = toMsysPath;
+
+/* Like qqjs qq.x(), but using MSYS bash on Windows instead of cmd.exe */
+async function msysExec(cmd, options = {}) {
+ if (process.platform !== 'win32') {
+ return qq.x(cmd, options);
+ }
+ const sh = MSYSSHELLPATH;
+ const args = ['-c', cmd];
+ console.error(`[debug] @oclif/dev-cli msysExec sh="${sh}" args=${JSON.stringify(args)} options=${JSON.stringify(options)}`);
+ return qq.x(sh, args, options);
+}
+exports.msysExec = msysExec;

View File

@ -1,55 +0,0 @@
diff --git a/node_modules/@oclif/parser/lib/errors.js b/node_modules/@oclif/parser/lib/errors.js
index 0c93a81..95d06be 100644
--- a/node_modules/@oclif/parser/lib/errors.js
+++ b/node_modules/@oclif/parser/lib/errors.js
@@ -13,7 +13,8 @@ const m = deps_1.default()
.add('list', () => require('./list'));
class CLIParseError extends errors_1.CLIError {
constructor(options) {
- options.message += '\nSee more help with --help';
+ const help = options.command ? `\`${options.command} --help\`` : '--help';
+ options.message += `\nSee more help with ${help}`;
super(options.message);
this.parse = options.parse;
}
@@ -34,22 +35,24 @@ class InvalidArgsSpecError extends CLIParseError {
exports.InvalidArgsSpecError = InvalidArgsSpecError;
class RequiredArgsError extends CLIParseError {
constructor({ args, parse }) {
- let message = `Missing ${args.length} required arg${args.length === 1 ? '' : 's'}`;
+ const command = 'balena ' + parse.input.context.id.replace(/:/g, ' ');
+ let message = `Missing ${args.length} required argument${args.length === 1 ? '' : 's'}`;
const namedArgs = args.filter(a => a.name);
if (namedArgs.length > 0) {
const list = m.list.renderList(namedArgs.map(a => [a.name, a.description]));
message += `:\n${list}`;
}
- super({ parse, message });
+ super({ parse, message, command });
this.args = args;
}
}
exports.RequiredArgsError = RequiredArgsError;
class RequiredFlagError extends CLIParseError {
constructor({ flag, parse }) {
+ const command = 'balena ' + parse.input.context.id.replace(/:/g, ' ');
const usage = m.list.renderList(m.help.flagUsages([flag], { displayRequired: false }));
const message = `Missing required flag:\n${usage}`;
- super({ parse, message });
+ super({ parse, message, command });
this.flag = flag;
}
}
diff --git a/node_modules/@oclif/parser/lib/list.js b/node_modules/@oclif/parser/lib/list.js
index 3907cc0..b689ca1 100644
--- a/node_modules/@oclif/parser/lib/list.js
+++ b/node_modules/@oclif/parser/lib/list.js
@@ -21,7 +21,7 @@ function renderList(items) {
}
left = left.padEnd(maxLength);
right = linewrap(maxLength + 2, right);
- return `${left} ${right}`;
+ return `${left} : ${right}`;
});
return lines.join('\n');
}

View File

@ -1,43 +0,0 @@
diff --git a/node_modules/@oclif/plugin-help/lib/command.js b/node_modules/@oclif/plugin-help/lib/command.js
index 1caa65b..e205faf 100644
--- a/node_modules/@oclif/plugin-help/lib/command.js
+++ b/node_modules/@oclif/plugin-help/lib/command.js
@@ -87,7 +87,7 @@ class CommandHelp {
if (args.filter(a => a.description).length === 0)
return;
const body = list_1.renderList(args.map(a => {
- const name = a.name.toUpperCase();
+ const name = a.required ? `<${a.name}>` : `[${a.name}]`;
let description = a.description || '';
if (a.default)
description = `[default: ${a.default}] ${description}`;
@@ -130,9 +130,7 @@ class CommandHelp {
if (!flag.helpValue && flag.options) {
value = flag.options.join('|');
}
- if (!value.includes('|'))
- value = underline(value);
- left += `=${value}`;
+ left += ` <${value}>`;
}
let right = flag.description || '';
if (flag.type === 'option' && flag.default) {
diff --git a/node_modules/@oclif/plugin-help/lib/index.js b/node_modules/@oclif/plugin-help/lib/index.js
index 02646b6..525e19f 100644
--- a/node_modules/@oclif/plugin-help/lib/index.js
+++ b/node_modules/@oclif/plugin-help/lib/index.js
@@ -95,11 +95,12 @@ class Help extends HelpBase {
console.log(title + '\n');
console.log(this.formatCommand(command));
console.log('');
- if (subTopics.length > 0) {
+ const SUPPRESS_SUBTOPICS = true;
+ if (subTopics.length > 0 && !SUPPRESS_SUBTOPICS) {
console.log(this.formatTopics(subTopics));
console.log('');
}
- if (subCommands.length > 0) {
+ if (subCommands.length > 0 && !SUPPRESS_SUBTOPICS) {
console.log(this.formatCommands(subCommands));
console.log('');
}

View File

@ -0,0 +1,33 @@
diff --git a/node_modules/oclif/lib/commands/pack/win.js b/node_modules/oclif/lib/commands/pack/win.js
index bfe9205..482519e 100644
--- a/node_modules/oclif/lib/commands/pack/win.js
+++ b/node_modules/oclif/lib/commands/pack/win.js
@@ -86,6 +86,12 @@ InstallDir "\$PROGRAMFILES${arch === 'x64' ? '64' : ''}\\${config.dirname}"
${customization}
Section "${config.name} CLI \${VERSION}"
+ ; First remove any old client files.
+ ; (Remnants of old versions were causing CLI errors)
+ ; Initially tried running the Uninstall.exe, but was
+ ; unable to make script wait for completion (despite using _?)
+ DetailPrint "Removing files from previous version."
+ RMDir /r "$INSTDIR\\client"
SetOutPath $INSTDIR
File /r bin
File /r client
diff --git a/node_modules/oclif/lib/tarballs/build.js b/node_modules/oclif/lib/tarballs/build.js
index f0c8d95..a72400e 100644
--- a/node_modules/oclif/lib/tarballs/build.js
+++ b/node_modules/oclif/lib/tarballs/build.js
@@ -218,6 +218,11 @@ const extractCLI = async (tarball, c) => {
(0, promises_1.rm)(path.join(workspace, path.basename(tarball)), { recursive: true }),
(0, fs_extra_1.remove)(path.join(workspace, 'bin', 'run.cmd')),
]);
+ // The oclif installers are a production installation, while the source
+ // `bin` folder may contain a `.fast-boot.json` file of a dev installation.
+ // This has previously led to issues preventing the CLI from starting, so
+ // delete `.fast-boot.json` (if any) from the destination folder.
+ await (0, fs_extra_1.remove)(path.join(workspace, 'bin', '.fast-boot.json'));
};
const buildTarget = async (target, c, options) => {
if (target.platform === 'win32' && target.arch === 'arm64' && (0, semver_1.lt)(c.nodeVersion, '20.0.0')) {

View File

@ -1,15 +0,0 @@
diff --git a/node_modules/open/index.js b/node_modules/open/index.js
index 3bf5373..e042b64 100644
--- a/node_modules/open/index.js
+++ b/node_modules/open/index.js
@@ -11,7 +11,9 @@ const pAccess = promisify(fs.access);
const pExecFile = promisify(childProcess.execFile);
// Path to included `xdg-open`.
-const localXdgOpenPath = path.join(__dirname, 'xdg-open');
+const localXdgOpenPath = process.pkg
+ ? path.join(path.dirname(process.execPath), 'xdg-open')
+ : path.join(__dirname, 'xdg-open');
// Convert a path from WSL format to Windows format:
// `/mnt/c/Program Files/Example/MyApp.exe` → `C:\Program Files\Example\MyApp.exe`

View File

@ -1,15 +0,0 @@
diff --git a/node_modules/opn/index.js b/node_modules/opn/index.js
index 13dcb66..0f0c1df 100644
--- a/node_modules/opn/index.js
+++ b/node_modules/opn/index.js
@@ -51,7 +51,9 @@ module.exports = function (target, opts) {
if (opts.app) {
cmd = opts.app;
} else {
- cmd = path.join(__dirname, 'xdg-open');
+ cmd = process.pkg
+ ? path.join(path.dirname(process.execPath), 'xdg-open-402')
+ : path.join(__dirname, 'xdg-open');
}
if (appArgs.length > 0) {

View File

@ -1,37 +0,0 @@
diff --git a/node_modules/pkg/lib-es5/packer.js b/node_modules/pkg/lib-es5/packer.js
index 7295bb6..76805a3 100644
--- a/node_modules/pkg/lib-es5/packer.js
+++ b/node_modules/pkg/lib-es5/packer.js
@@ -128,6 +128,7 @@ function _default({
const newStat = Object.assign({}, value);
newStat.isFileValue = value.isFile();
newStat.isDirectoryValue = value.isDirectory();
+ newStat.isSocketValue = value.isSocket();
const buffer = Buffer.from(JSON.stringify(newStat));
stripes.push({
snap,
diff --git a/node_modules/pkg/prelude/bootstrap.js b/node_modules/pkg/prelude/bootstrap.js
index 0d19f1d..db69015 100644
--- a/node_modules/pkg/prelude/bootstrap.js
+++ b/node_modules/pkg/prelude/bootstrap.js
@@ -925,8 +925,10 @@ function payloadFileSync (pointer) {
var isFileValue = s.isFileValue;
var isDirectoryValue = s.isDirectoryValue;
+ var isSocketValue = s.isSocketValue;
delete s.isFileValue;
delete s.isDirectoryValue;
+ delete s.isSocketValue;
s.isFile = function () {
return isFileValue;
@@ -934,6 +936,9 @@ function payloadFileSync (pointer) {
s.isDirectory = function () {
return isDirectoryValue;
};
+ s.isSocket = function () {
+ return isSocketValue;
+ };
s.isSymbolicLink = function () {
return false;
};

View File

@ -24,7 +24,10 @@ const { promisify } = require('util');
const execFileAsync = promisify(execFile);
const patchesDir = 'patches';
/** Run the patch-package tool in a child process and wait for it to finish */
/**
* Run the patch-package tool in a child process and wait for it to finish
* @param {string} patchDir
*/
async function patchPackage(patchDir) {
// Equivalent to: `npx patch-package --patch-dir $patchDir`
const result = await execFileAsync('node', [

View File

@ -1,14 +0,0 @@
diff --git a/node_modules/node-gyp-build/index.js b/node_modules/node-gyp-build/index.js
index b5096ed..7cd451a 100644
--- a/node_modules/node-gyp-build/index.js
+++ b/node_modules/node-gyp-build/index.js
@@ -29,6 +29,9 @@ load.path = function (dir) {
if (process.env[name + '_PREBUILD']) dir = process.env[name + '_PREBUILD']
} catch (err) {}
+ // pkg fix: native node modules are located externally to the pkg executable
+ dir = dir.replace(/^\/snapshot\/.+?\/node_modules\//, path.dirname(process.execPath) + path.sep)
+
if (!prebuildsOnly) {
var release = getFirst(path.join(dir, 'build/Release'), matchBuild)
if (release) return release

View File

@ -1,38 +0,0 @@
diff --git a/node_modules/windosu/lib/pipe.js b/node_modules/windosu/lib/pipe.js
index dc81fa5..a381cc7 100644
--- a/node_modules/windosu/lib/pipe.js
+++ b/node_modules/windosu/lib/pipe.js
@@ -42,7 +42,8 @@ function pipe(path, options) {
return d.promise;
}
module.exports = pipe;
-if (module === require.main) {
+
+function main() {
if (!process.argv[4]) {
console.error('Incorrect arguments!');
process.exit(-1);
@@ -52,3 +53,8 @@ if (module === require.main) {
serve: process.argv[3] == 'server'
});
}
+module.exports.main = main;
+
+if (module === require.main) {
+ main();
+}
diff --git a/node_modules/windosu/lib/windosu.js b/node_modules/windosu/lib/windosu.js
index 6502812..dd0391a 100644
--- a/node_modules/windosu/lib/windosu.js
+++ b/node_modules/windosu/lib/windosu.js
@@ -16,7 +16,9 @@ module.exports.exec = function (command, options, callback) {
temp: temp,
command: command,
cliWidth: cliWidth(),
- pipe: '"' + process.execPath + '" "' + path.join(__dirname, 'pipe.js') + '"',
+ pipe: process.pkg
+ ? '"' + process.execPath + '" pkgExec "' + path.join(__dirname, 'pipe.js') + '::main"'
+ : '"' + process.execPath + '" "' + path.join(__dirname, 'pipe.js') + '"',
input: inputName = id + '-in',
output: outputName = id + '-out',
stderr_redir: process.stdout.isTTY ? '2>&1' : '2> %ERROR%'

View File

@ -6,13 +6,17 @@ upstream:
url: 'https://github.com/balena-io/balena-sdk'
- repo: 'balena-config-json'
url: 'https://github.com/balena-io-modules/balena-config-json'
- repo: 'balena-image-fs'
url: 'https://github.com/balena-io-modules/balena-image-fs'
- repo: 'balena-device-init'
url: 'https://github.com/balena-io-modules/balena-device-init'
- repo: 'balena-image-manager'
url: 'https://github.com/balena-io-modules/balena-image-manager'
- repo: 'balena-preload'
url: 'https://github.com/balena-io-modules/balena-preload'
- repo: 'balena-sync'
url: 'https://github.com/balena-io-modules/balena-sync'
- repo: 'etcher-sdk'
url: 'https://github.com/balena-io-modules/etcher-sdk/'
- repo: 'resin-compose-parse'
url: 'https://github.com/balena-io-modules/resin-compose-parse'
- repo: '@balena/compose'
url: 'https://github.com/balena-io-modules/balena-compose'
- repo: 'docker-progress'
url: 'https://github.com/balena-io-modules/docker-progress'

View File

@ -16,14 +16,15 @@
*/
import * as packageJSON from '../package.json';
import type { AppOptions } from './preparser';
import {
AppOptions,
checkDeletedCommand,
preparseArgs,
unsupportedFlag,
} from './preparser';
import { CliSettings } from './utils/bootstrap';
import { onceAsync } from './utils/lazy';
import { run as mainRun, settings } from '@oclif/core';
/**
* Sentry.io setup
@ -36,14 +37,11 @@ export const setupSentry = onceAsync(async () => {
dsn: config.sentryDsn,
release: packageJSON.version,
});
Sentry.configureScope((scope) => {
scope.setExtras({
is_pkg: !!(process as any).pkg,
node_version: process.version,
platform: process.platform,
});
Sentry.getCurrentScope().setExtras({
is_pkg: !!(process as any).pkg,
node_version: process.version,
platform: process.platform,
});
return Sentry.getCurrentHub();
});
async function checkNodeVersion() {
@ -76,11 +74,13 @@ export function setMaxListeners(maxListeners: number) {
/** Selected CLI initialization steps */
async function init() {
if (process.env.BALENARC_NO_SENTRY) {
console.error(`WARN: disabling Sentry.io error reporting`);
if (process.env.DEBUG) {
console.error(`WARN: disabling Sentry.io error reporting`);
}
} else {
await setupSentry();
}
checkNodeVersion();
await checkNodeVersion();
const settings = new CliSettings();
@ -90,16 +90,16 @@ async function init() {
setupBalenaSdkSharedOptions(settings);
// check for CLI updates once a day
(await import('./utils/update')).notify();
if (!process.env.BALENARC_OFFLINE_MODE) {
(await import('./utils/update')).notify();
}
}
/** Execute the oclif parser and the CLI command. */
async function oclifRun(command: string[], options: AppOptions) {
let deprecationPromise: Promise<void>;
let deprecationPromise: Promise<void> | undefined;
// check and enforce the CLI's deprecation policy
if (unsupportedFlag) {
deprecationPromise = Promise.resolve();
} else {
if (!(unsupportedFlag || process.env.BALENARC_UNSUPPORTED)) {
const { DeprecationChecker } = await import('./deprecation');
const deprecationChecker = new DeprecationChecker(packageJSON.version);
// warnAndAbortIfDeprecated uses previously cached data only
@ -109,10 +109,16 @@ async function oclifRun(command: string[], options: AppOptions) {
}
const runPromise = (async function (shouldFlush: boolean) {
const { CustomMain } = await import('./utils/oclif-utils');
let isEEXIT = false;
try {
await CustomMain.run(command);
if (options.development) {
// In dev mode -> use ts-node and dev plugins
process.env.NODE_ENV = 'development';
settings.debug = true;
}
// For posteriority: We can't use default oclif 'execute' as
// We customize error handling and flushing
await mainRun(command, options.loadOptions ?? options.dir);
} catch (error) {
// oclif sometimes exits with ExitError code EEXIT 0 (not an error),
// for example the `balena help` command.
@ -125,7 +131,8 @@ async function oclifRun(command: string[], options: AppOptions) {
}
}
if (shouldFlush) {
await import('@oclif/command/flush');
const { flush } = await import('@oclif/core');
await flush();
}
// TODO: figure out why we need to call fast-boot stop() here, in
// addition to calling it in the main `run()` function in this file.
@ -140,23 +147,20 @@ async function oclifRun(command: string[], options: AppOptions) {
}
})(!options.noFlush);
const { trackPromise } = await import('./hooks/prerun/track');
const { trackPromise } = await import('./hooks/prerun');
await Promise.all([trackPromise, deprecationPromise, runPromise]);
}
/** CLI entrypoint. Called by the `bin/balena` and `bin/balena-dev` scripts. */
export async function run(cliArgs = process.argv, options: AppOptions = {}) {
/** CLI entrypoint. Called by the `bin/run.js` and `bin/dev.js` scripts. */
export async function run(cliArgs = process.argv, options: AppOptions) {
try {
const { normalizeEnvVars, pkgExec } = await import('./utils/bootstrap');
const { setOfflineModeEnvVars, normalizeEnvVars } = await import(
'./utils/bootstrap'
);
setOfflineModeEnvVars();
normalizeEnvVars();
// 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));
}
await init();
// Look for commands that have been removed and if so, exit with a notice

View File

@ -56,7 +56,7 @@ export async function login({ host = '127.0.0.1', port = 0 }) {
console.info(`Opening web browser for URL:\n${loginUrl}`);
const open = await import('open');
open(loginUrl, { wait: false });
await open(loginUrl, { wait: false });
const balena = getBalenaSdk();
const token = await loginServer.awaitForToken();

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

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