Compare commits

...

875 Commits

Author SHA1 Message Date
flowzone-app[bot]
42d9cbb48d
v21.1.8 2025-04-03 16:10:05 +00:00
balena-renovate[bot]
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
balena-renovate[bot]
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
flowzone-app[bot]
3f27db811b
v21.1.7 2025-04-03 15:12:16 +00:00
balena-renovate[bot]
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
balena-renovate[bot]
c8ea9cfcdb
Update actions/upload-artifact digest to ea165f8
Update actions/upload-artifact

Change-type: patch
2025-04-03 14:50:26 +00:00
flowzone-app[bot]
776115ef5d
v21.1.6 2025-04-03 14:12:08 +00:00
balena-renovate[bot]
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
balena-renovate[bot]
fe42438090
Update actions/setup-node digest to cdca736
Update actions/setup-node

Change-type: patch
2025-04-03 13:50:06 +00:00
flowzone-app[bot]
b616fbdd79
v21.1.5 2025-04-03 13:28:12 +00:00
Ken Bannister
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
Ken Bannister
663e83c3b8 Dedupe dependencies 2025-04-02 18:50:31 -04:00
Ken Bannister
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
flowzone-app[bot]
58234f17e1
v21.1.4 2025-04-02 09:16:30 +00:00
flowzone-app[bot]
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
Ken Bannister
30076fabe6 Dedupe dependencies 2025-04-01 18:25:20 -04:00
Ken Bannister
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
flowzone-app[bot]
37b3c6abe9
v21.1.3 2025-03-28 16:57:03 +00:00
flowzone-app[bot]
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
Otavio Jacobi
0d4e411777 Fix device detail for open balena
Change-type: patch
2025-03-28 13:29:52 -03:00
flowzone-app[bot]
7e6f2189e8
v21.1.2 2025-03-27 12:20:26 +00:00
Ken Bannister
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
Ken Bannister
18bc0d61e7 Dedupe dependencies 2025-03-26 22:55:54 -04:00
Ken Bannister
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
flowzone-app[bot]
813e9cb82e
v21.1.1 2025-03-26 20:34:47 +00:00
flowzone-app[bot]
3bcb3c1b2e
Merge pull request #2925 from balena-io/add-overall-status
Add overall status
2025-03-26 20:33:52 +00:00
Otavio Jacobi
20d76556c2 Add explicit read properties for device command
Change-tye: minor
2025-03-26 17:12:45 -03:00
Otavio Jacobi
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
flowzone-app[bot]
650e896f70
v21.1.0 2025-03-12 19:34:20 +00:00
flowzone-app[bot]
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
Felipe Lalanne
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
Felipe Lalanne
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
flowzone-app[bot]
ba4b9bd447
v21.0.0 2025-03-11 14:42:31 +00:00
Matthew Yarmolinsky
02c0ea5b59
Merge pull request #2921 from balena-io/major-21-second-attempt
Major 21
2025-03-11 10:41:28 -04:00
myarmolinsky
bc3558dd8e Address SDK major v21 breaking changes 2025-03-11 08:19:10 -04:00
myarmolinsky
aad62d1ccd Drop support for OS versions <2.14.0
Change-type: major
2025-03-11 08:19:10 -04:00
myarmolinsky
ecc6f80164 api-key generate: Add required argument expiryDate
Change-type: major
2025-03-11 08:19:10 -04:00
myarmolinsky
c0fd1e3886 Deduplicate dependencies 2025-03-11 08:18:56 -04:00
myarmolinsky
9d3120b144 Update balena-preload to 18.0.1
Change-type: patch
2025-03-11 08:17:27 -04:00
myarmolinsky
ed0e03ddb2 Add dependency date-fns
Change-type: patch
2025-03-11 08:16:50 -04:00
myarmolinsky
8fe6d6c026 Update balena-sdk to 21.2.1
Change-type: patch
2025-03-11 08:16:31 -04:00
flowzone-app[bot]
727033ae14
v20.2.10 2025-03-10 17:33:13 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
1a33029738 Deduplicate dependencies 2025-03-10 17:51:18 +02:00
Thodoris Greasidis
043bc48a1c Add a "deduplicate-dependencies" npm script to standardize such commits 2025-03-04 08:48:31 +02:00
Thodoris Greasidis
a10156a441 Update TypeScript to 5.8.2
Change-type: patch
2025-03-04 08:48:31 +02:00
flowzone-app[bot]
4f665f43d2
v20.2.9 2025-02-26 12:52:10 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
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
flowzone-app[bot]
666ce876e6
v20.2.8 2025-02-26 00:22:16 +00:00
Ken Bannister
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
Ken Bannister
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
flowzone-app[bot]
795259bf30
v20.2.7 2025-02-25 20:21:03 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
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
flowzone-app[bot]
72d6db796c
v20.2.6 2025-02-25 19:13:51 +00:00
balena-renovate[bot]
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
balena-renovate[bot]
6f0f7350cf
Update actions/upload-artifact digest to 4cec3d8
Update actions/upload-artifact

Change-type: patch
2025-02-25 18:51:27 +00:00
flowzone-app[bot]
07a88c700e
v20.2.5 2025-02-25 18:10:50 +00:00
balena-renovate[bot]
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
balena-renovate[bot]
cddea24cef
Update actions/setup-node digest to 1d0ff46
Update actions/setup-node

Change-type: patch
2025-02-25 17:45:52 +00:00
flowzone-app[bot]
b1c246c0b4
v20.2.4 2025-02-25 17:17:03 +00:00
Ken Bannister
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
Ken Bannister
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
flowzone-app[bot]
1352c5c823
v20.2.3 2025-01-15 18:21:09 +00:00
flowzone-app[bot]
c86eb97010
Merge pull request #2910 from balena-io/clean-eslint
Remove unused old eslint version files
2025-01-15 18:19:22 +00:00
Otavio Jacobi
53be743b9d Remove unused old eslint version files
Change-type: patch
2025-01-15 08:37:35 -03:00
flowzone-app[bot]
d9f21b4c3f
v20.2.2 2025-01-12 14:49:07 +00:00
Thodoris Greasidis
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
Thodoris Greasidis
f28a9992e4 Deduplicate dependencies 2025-01-09 23:33:54 +02:00
Thodoris Greasidis
29e7827eb1 Use the promises namespace of balena-image-fs
Change-type: patch
2025-01-09 23:33:54 +02:00
Thodoris Greasidis
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
flowzone-app[bot]
017c767f61
v20.2.1 2025-01-01 18:05:02 +00:00
Thodoris Greasidis
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
Thodoris Greasidis
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
flowzone-app[bot]
a33a794931
v20.2.0 2024-12-31 18:41:50 +00:00
Ken Bannister
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
Thodoris Greasidis
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
Thodoris Greasidis
09f80730a8 Deduplicate dependencies 2024-12-31 19:47:11 +02:00
flowzone-app[bot]
327d28c103
v20.1.6 2024-12-30 17:16:14 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
305d65d5ed Add more realistic os configure tests
Change-type: patch
2024-12-30 18:44:07 +02:00
Thodoris Greasidis
c4d3686a34 Deduplicate dependencies 2024-12-30 15:57:12 +02:00
flowzone-app[bot]
ce06854b55
v20.1.5 2024-12-20 17:55:24 +00:00
flowzone-app[bot]
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
Oskar Williams
7a22c987d2
Update shrinkwrapped express to v4.21.2
Change-type: patch
2024-12-20 17:23:28 +00:00
flowzone-app[bot]
45efbcdfe3
v20.1.4 2024-12-20 16:57:38 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
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
flowzone-app[bot]
0ffa0f85a2
v20.1.3 2024-12-20 14:33:05 +00:00
Otávio Jacobi
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
Otavio Jacobi
07365c45f2 Update oclif to 4.17.0 and @oclif/core 4.1.0
Change-type: patch
2024-12-20 11:09:29 -03:00
flowzone-app[bot]
e5076434c6
v20.1.2 2024-12-17 11:35:00 +00:00
Page-
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
Pagan Gazzard
e192767156 Remove unnecessary Promise.resolve and Promise.reject
Change-type: patch
2024-12-16 21:12:02 +00:00
flowzone-app[bot]
5a8d2fad5f
v20.1.1 2024-12-16 17:36:44 +00:00
flowzone-app[bot]
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
Otavio Jacobi
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
flowzone-app[bot]
36077cacda
v20.1.0 2024-12-12 14:17:22 +00:00
Matthew Yarmolinsky
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
myarmolinsky
703dbd01c9 device os-update: Add handling for updates that require takeover
Change-type: minor
2024-12-11 12:04:53 -05:00
myarmolinsky
602e63c8a9 Fix typings in release and release list commands 2024-12-11 12:00:08 -05:00
myarmolinsky
2ab635f49a Update expected warnings 2024-12-11 12:00:08 -05:00
myarmolinsky
322736a145 Deduplicate dependencies 2024-12-11 12:00:08 -05:00
myarmolinsky
c347b67b25 Update balena-sdk
Change-type: patch
2024-12-11 12:00:08 -05:00
myarmolinsky
4022beeb56 Update @balena/compose
Change-type: patch
2024-12-11 12:00:08 -05:00
flowzone-app[bot]
ccf97cfc9f
v20.0.9 2024-12-05 12:08:28 +00:00
flowzone-app[bot]
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
Oskar Williams
38e29251e7
Update shrinkwrapped express to v4.21.1
Change-type: patch
2024-12-05 09:59:57 +00:00
flowzone-app[bot]
bfc7a14646
v20.0.8 2024-12-04 19:37:38 +00:00
Otávio Jacobi
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
Otavio Jacobi
d1f7d6d07f Run test and publish with macos-13
Change-type: patch
2024-12-04 16:16:52 -03:00
flowzone-app[bot]
694eb78aaa
v20.0.7 2024-11-23 17:38:10 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
61d4d1f1e7 Update TypeScript to 5.7.2
Change-type: patch
2024-11-23 00:40:43 +02:00
Thodoris Greasidis
a01c85bc15 Deduplicate dependencies 2024-11-23 00:40:28 +02:00
flowzone-app[bot]
5d7b7cfc6f
v20.0.6 2024-11-08 08:10:12 +00:00
flowzone-app[bot]
92fd9e0883
Merge pull request #2887 from balena-io/refactor-build
Refactor balena build for clarity
2024-11-08 08:09:19 +00:00
Thodoris Greasidis
24273b5ac0 Deduplicate dependencies 2024-11-07 17:33:14 +02:00
Thodoris Greasidis
6155509f4c Refactor balena build for clarity
Change-type: patch
2024-11-07 16:24:10 +02:00
flowzone-app[bot]
735af9f6a9
v20.0.5 2024-11-05 10:12:26 +00:00
balena-renovate[bot]
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
balena-renovate[bot]
bcb42c8a21
Update actions/upload-artifact digest to b4b15b8
Update actions/upload-artifact

Change-type: patch
2024-11-05 09:50:56 +00:00
flowzone-app[bot]
04f5e0fa2b
v20.0.4 2024-11-05 09:13:22 +00:00
balena-renovate[bot]
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
balena-renovate[bot]
91c3fced49
Update actions/setup-node digest to 39370e3
Update actions/setup-node

Change-type: patch
2024-11-05 08:52:19 +00:00
flowzone-app[bot]
99a94eafbb
v20.0.3 2024-11-05 08:12:01 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
8577bb6281 Deduplicate dependencies 2024-11-04 20:51:28 +02:00
Thodoris Greasidis
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
flowzone-app[bot]
2887ab8200
v20.0.2 2024-10-29 12:57:11 +00:00
flowzone-app[bot]
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
myarmolinsky
6f30dc0550 Restore ability to cat key into ssh-key add
Change-type: patch
2024-10-29 07:48:42 -04:00
flowzone-app[bot]
6565ef4392
v20.0.1 2024-10-29 11:37:14 +00:00
flowzone-app[bot]
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
myarmolinsky
bb101de96e Update @oclif/core patch 2024-10-29 07:16:51 -04:00
myarmolinsky
ca6344bf4c Deduplicate dependencies 2024-10-29 07:09:06 -04:00
myarmolinsky
48596fa318 Fix sending input to some aliases not working
Change-type: patch
2024-10-29 07:05:37 -04:00
flowzone-app[bot]
7fb28ddb21
v20.0.0 2024-10-25 17:33:42 +00:00
flowzone-app[bot]
6dd6f43d64
Merge pull request #2833 from balena-io/api-v7
Api v7
2024-10-25 17:32:44 +00:00
myarmolinsky
07a7bd76fe Deduplicate dependencies 2024-10-25 12:57:41 -04:00
jaomaloy
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
myarmolinsky
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
myarmolinsky
de1821d7ac Stop checking for very old, long-removed commands
Change-type: major
2024-10-25 12:57:12 -04:00
myarmolinsky
12923c9b84 Deprecate devices supported command in favor of device-type list
Change-type: patch
2024-10-25 12:57:12 -04:00
myarmolinsky
8be069dbdb Deprecate notes command in favor of device note
Change-type: patch
2024-10-25 12:57:12 -04:00
myarmolinsky
9d3f9128a8 Deprecate tunnel command in favor of device tunnel
Change-type: patch
2024-10-25 12:57:12 -04:00
myarmolinsky
61ebf9e4fd Deprecate env add in favor of env set
Change-type: patch
2024-10-25 12:57:12 -04:00
myarmolinsky
84985022e5 Deprecate ssh command in favor of device ssh
Change-type: patch
2024-10-25 12:57:12 -04:00
myarmolinsky
c5d8f73263 Deprecate logs command in favor of device logs
Change-type: patch
2024-10-25 12:57:12 -04:00
myarmolinsky
5db0c71bb3 Deprecate scan command in favor of device detect
Change-type: patch
2024-10-25 12:57:12 -04:00
myarmolinsky
c7a06f7259 Deprecate orgs command in favor of organization list
Change-type: patch
2024-10-25 12:57:12 -04:00
myarmolinsky
bc66febc50 Deprecate tags command in favor of tag list
Change-type: patch
2024-10-25 12:57:12 -04:00
myarmolinsky
bb80311700 Deprecate envs command in favor of env list
Change-type: patch
2024-10-25 12:57:12 -04:00
myarmolinsky
3dee7bd6f6 Deprecate key commands in favor of ssh-key
Change-type: patch
2024-10-25 12:57:12 -04:00
myarmolinsky
3251f04287 Deprecate keys command in favor of key list
Change-type: patch
2024-10-25 12:57:12 -04:00
myarmolinsky
35dce4579a Deprecate releases command in favor of release list
Change-type: patch
2024-10-25 12:57:12 -04:00
myarmolinsky
71ef00534d Deprecate fleets command in favor of fleet list
Change-type: patch
2024-10-25 12:57:12 -04:00
myarmolinsky
b6f8be27ec Deprecate api-keys command in favor of api-key list
Change-type: patch
2024-10-25 12:57:12 -04:00
myarmolinsky
13110cca45 Deprecate devices command in favor of device list
Change-type: patch
2024-10-25 12:57:12 -04:00
myarmolinsky
d4b554da1b Docs: Show whether an alias is deprecated
Change-type: patch
2024-10-25 12:57:12 -04:00
myarmolinsky
1275c11573 Update balena-preload to 16.0.0
Change-type: patch
2024-10-25 12:57:10 -04:00
myarmolinsky
593233a99f Tests: Drop unused my_application resource mock
Change-type: patch
2024-10-25 12:56:48 -04:00
myarmolinsky
ec92f21b70 Drop the no longer needed __metadata property handling 2024-10-25 12:56:48 -04:00
myarmolinsky
5adc43bcbd Update image_size type from number to string 2024-10-25 12:56:48 -04:00
myarmolinsky
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
myarmolinsky
56e5dafb20 Drop the device.is_managed_by__device property from test-data 2024-10-25 12:56:48 -04:00
myarmolinsky
f0e0c0d728 Update all API queries to use the v7 model 2024-10-25 12:56:48 -04:00
myarmolinsky
afd14794f5 git mv v6 test-data api-responses to v7 2024-10-25 12:56:48 -04:00
myarmolinsky
37e08e4667 Update actor to use PineDeferred type 2024-10-25 12:56:48 -04:00
myarmolinsky
61af57acc9 Update release.contract type from string to JsonType 2024-10-25 12:56:48 -04:00
myarmolinsky
19be0fec1a Replace device should_be_running__release with is_pinned_on__release 2024-10-25 12:56:48 -04:00
myarmolinsky
2b656c23b3 Update @balena/compose to 5.0.0
Change-type: patch
2024-10-25 12:56:48 -04:00
myarmolinsky
2bf7b81645 Bump balena-sdk to 20.3.0
Change-type: patch
2024-10-25 12:56:43 -04:00
flowzone-app[bot]
746b6fa439
v19.16.0 2024-10-23 13:18:23 +00:00
Matthew Yarmolinsky
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
myarmolinsky
8655b89313 Deduplicate dependencies 2024-10-23 07:33:16 -04:00
myarmolinsky
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
myarmolinsky
e5cee648f2 Add alias device-type list for command devices supported
Change-type: minor
2024-10-23 07:23:40 -04:00
myarmolinsky
98a6b431d9 git mv devices/supported to device/list 2024-10-23 07:17:59 -04:00
flowzone-app[bot]
f305d5d9a0
v19.15.0 2024-10-23 11:01:55 +00:00
Matthew Yarmolinsky
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
myarmolinsky
3eb3b3b584 Add alias device note for command notes
Change-type: minor
2024-10-21 21:07:38 -04:00
myarmolinsky
8ee5ede34d git mv notes/index to device/note 2024-10-21 21:02:18 -04:00
flowzone-app[bot]
d6d08cc7c9
v19.14.0 2024-10-22 00:51:16 +00:00
flowzone-app[bot]
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
myarmolinsky
bff5897047 Add alias device tunnel for command tunnel
Change-type: minor
2024-10-21 20:29:20 -04:00
myarmolinsky
22c9fd399e git mv tunnel/index to device/tunnel 2024-10-21 20:29:20 -04:00
flowzone-app[bot]
65222b5fc9
v19.13.1 2024-10-21 19:13:36 +00:00
Page-
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
Self-hosted Renovate Bot
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
flowzone-app[bot]
b0d8b021d5
v19.13.0 2024-10-21 18:14:05 +00:00
Matthew Yarmolinsky
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
myarmolinsky
f1924bba6b Add alias env set for command env add
Change-type: minor
2024-10-21 12:06:17 -04:00
myarmolinsky
44082e22e4 git mv env/add to env/set 2024-10-21 12:06:17 -04:00
flowzone-app[bot]
2d15530f61
v19.12.1 2024-10-21 16:04:19 +00:00
flowzone-app[bot]
a7c612f7de
Merge pull request #2873 from balena-io/bump-oclif-core
Update `@oclif/core`
2024-10-21 16:03:04 +00:00
myarmolinsky
147ce8067a Update @oclif/core
Change-type: patch
2024-10-21 11:42:30 -04:00
flowzone-app[bot]
5e7ac09dd0
v19.12.0 2024-10-21 15:07:55 +00:00
flowzone-app[bot]
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
myarmolinsky
9b1eb57973 Update help.spec per recent help output change 2024-10-21 10:46:08 -04:00
myarmolinsky
76c08b6c13 Add alias device ssh for ssh command
Change-type: minor
2024-10-21 10:46:08 -04:00
myarmolinsky
3f82f42652 git mv ssh/index to device/ssh 2024-10-21 10:46:08 -04:00
flowzone-app[bot]
69d820878a
v19.11.1 2024-10-21 13:05:19 +00:00
Page-
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
Self-hosted Renovate Bot
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
flowzone-app[bot]
9559d5cba3
v19.11.0 2024-10-21 12:08:59 +00:00
flowzone-app[bot]
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
myarmolinsky
8e9b992a59 Deduplicate dependencies 2024-10-21 07:45:11 -04:00
myarmolinsky
b77f266bd7 Add alias device logs for logs
Change-type: minor
2024-10-21 07:35:58 -04:00
myarmolinsky
3c9ac76982 git mv logs/index to device/logs
Change-type: patch
2024-10-21 07:31:24 -04:00
flowzone-app[bot]
e483d06d2b
v19.10.0 2024-10-21 11:13:10 +00:00
Matthew Yarmolinsky
24d2d19d33
Merge pull request #2862 from balena-io/scan-to-device-detect
`scan` to `device detect`
2024-10-21 07:12:05 -04:00
myarmolinsky
ba5bb7b12c Add alias device detect for scan
Change-type: minor
2024-10-18 10:45:06 -04:00
myarmolinsky
9082e7b3f7 git mv scan/index to device/detect 2024-10-18 10:39:24 -04:00
flowzone-app[bot]
0716544042
v19.9.0 2024-10-18 14:25:43 +00:00
Matthew Yarmolinsky
e1858aa69d
Merge pull request #2861 from balena-io/orgs-to-organization-list
Orgs to organization list
2024-10-18 10:24:49 -04:00
myarmolinsky
082cce332a Add alias organization list for orgs command
Change-type: minor
2024-10-18 09:33:27 -04:00
myarmolinsky
218e0a1b6b git mv orgs/ to organization/ 2024-10-18 09:29:01 -04:00
flowzone-app[bot]
4065c5775c
v19.8.0 2024-10-18 13:25:54 +00:00
flowzone-app[bot]
fd966df1f0
Merge pull request #2860 from balena-io/tags-to-tag-list
`tags` to `tag list`
2024-10-18 13:24:59 +00:00
myarmolinsky
5eba175bf1 Add alias tag list for tags command
Change-type: minor
2024-10-18 08:49:53 -04:00
myarmolinsky
bd1b71bf2f git mv tags/index to tag/list 2024-10-18 08:40:05 -04:00
flowzone-app[bot]
bd7ea3d21a
v19.7.0 2024-10-18 12:35:38 +00:00
flowzone-app[bot]
31662d9175
Merge pull request #2859 from balena-io/envs-to-env-list
`envs` to `env list`
2024-10-18 12:34:15 +00:00
myarmolinsky
417c75484b Add alias env list for command envs
Change-type: minor
2024-10-18 07:47:46 -04:00
myarmolinsky
fcd77e97d9 git mv envs/index to env/list 2024-10-18 07:12:39 -04:00
flowzone-app[bot]
1dd819ae61
v19.6.0 2024-10-18 11:04:31 +00:00
Matthew Yarmolinsky
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
myarmolinsky
30446605e1 Deduplicate dependencies 2024-10-17 11:46:52 -04:00
myarmolinsky
e853b15f12 Add ssh-key as aliases for all key commands
Change-type: minor
2024-10-17 11:46:52 -04:00
myarmolinsky
96cf380f66 git mv key to ssh-key 2024-10-17 11:05:52 -04:00
flowzone-app[bot]
5d0d02a24d
v19.5.0 2024-10-17 14:56:42 +00:00
Matthew Yarmolinsky
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
myarmolinsky
6b5c6e072b Add key list alias for keys command
Change-type: minor
2024-10-16 15:21:44 -04:00
myarmolinsky
3615f8e525 git mv keys/index to key/list 2024-10-16 15:15:23 -04:00
flowzone-app[bot]
ec6cbd120e
v19.4.0 2024-10-16 19:12:09 +00:00
flowzone-app[bot]
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
myarmolinsky
8d1394a77d Add release list alias for releases command
Change-type: minor
2024-10-16 14:50:44 -04:00
myarmolinsky
ca0a3ee147 git mv releases/index to release/list 2024-10-16 14:25:20 -04:00
flowzone-app[bot]
019af9e703
v19.3.0 2024-10-16 18:03:21 +00:00
Matthew Yarmolinsky
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
myarmolinsky
5243803342 Add alias fleet list for fleets command
Change-type: minor
2024-10-16 12:36:45 -04:00
myarmolinsky
811e009ba9 git mv fleets/index to fleet/list 2024-10-16 12:31:21 -04:00
flowzone-app[bot]
45e0f21685
v19.2.0 2024-10-16 16:11:52 +00:00
Matthew Yarmolinsky
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
myarmolinsky
cad5543863 Add alias api-key list for command api-keys
Change-type: minor
2024-10-16 11:20:30 -04:00
myarmolinsky
a1e936bb3f git mv api-keys/index to api-key/list 2024-10-16 11:15:23 -04:00
flowzone-app[bot]
49984c2366
v19.1.3 2024-10-16 14:39:29 +00:00
flowzone-app[bot]
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
myarmolinsky
349bab7702 Deduplicate dependencies 2024-10-16 10:13:38 -04:00
myarmolinsky
af2c04540f Remove custom sorting of OS commands in docs in favor of alphabetizing
Change-type: patch
2024-10-16 09:58:19 -04:00
flowzone-app[bot]
cdfabb8f92
v19.1.2 2024-10-16 13:35:41 +00:00
Matthew Yarmolinsky
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
myarmolinsky
6a81ed2d70 Update expected warnings 2024-10-14 15:56:54 -04:00
myarmolinsky
d323c0742c Remove no longer needed dependency get-stdin
Change-type: patch
2024-10-14 15:38:21 -04:00
myarmolinsky
9cdde4f6c2 Remove custom override of oclif Command class in favor of prerun hook
Change-type: patch
2024-10-14 15:38:21 -04:00
myarmolinsky
ebe10360b3 git mv src/command.ts to src/hooks/init.ts 2024-10-14 11:25:31 -04:00
flowzone-app[bot]
440c5ad15b
v19.1.1 2024-10-14 13:06:42 +00:00
flowzone-app[bot]
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
myarmolinsky
0eb5c78e33 Deduplicate dependencies
Change-type: patch
2024-10-14 08:35:32 -04:00
myarmolinsky
067232b5c4 Fix changelog entry for v19.1.0
Change-type: patch
2024-10-14 07:51:00 -04:00
flowzone-app[bot]
5716ba29ad
v19.1.0 2024-10-11 17:15:09 +00:00
flowzone-app[bot]
fc2234b0dd
Merge pull request #2844 from balena-io/devices-to-device-list
Devices to device list
2024-10-11 17:14:15 +00:00
myarmolinsky
12cdb14638 Docs: Show aliases for commands
Change-type: patch
2024-10-11 12:54:09 -04:00
myarmolinsky
b936c51941 Deprecate devices command in favor of device list
Change-type: minor
2024-10-11 12:54:09 -04:00
myarmolinsky
6c23b06b4c git mv devices/index to device/list 2024-10-11 12:54:09 -04:00
myarmolinsky
87c52c55ed Deduplicate dependencies
Change-type: patch
2024-10-11 12:54:09 -04:00
flowzone-app[bot]
f792343180
v19.0.20 2024-10-11 11:48:53 +00:00
flowzone-app[bot]
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
myarmolinsky
f52e6bd8b4 Docs: Generate CLI command references from file names instead of usage
Change-type: patch
2024-10-11 07:26:12 -04:00
myarmolinsky
0847daba1b Use default oclif USAGE message for all commands
Change-type: patch
2024-10-11 07:26:12 -04:00
flowzone-app[bot]
057b37ae38
v19.0.19 2024-10-11 11:18:26 +00:00
flowzone-app[bot]
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
myarmolinsky
55dbe42e84 Deduplicate dependencies
Change-type: patch
2024-10-10 15:32:46 -04:00
myarmolinsky
3e8bc57fdb Fix update notification release notes link
Change-type: patch
2024-10-10 14:05:10 -04:00
flowzone-app[bot]
d206e7cd66
v19.0.18 2024-10-08 15:25:16 +00:00
flowzone-app[bot]
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
myarmolinsky
276d61cf6c Contributing: No longer request separate folders for plural commands
Change-type: patch
2024-10-08 10:54:06 -04:00
flowzone-app[bot]
77ccd9c39c
v19.0.17 2024-10-08 14:04:45 +00:00
Matthew Yarmolinsky
9e140eff13
Merge pull request #2842 from balena-io/remove-mixpanel
Remove mixpanel
2024-10-08 10:03:55 -04:00
myarmolinsky
da95baa70c Remove dev dependency parse-link-header
Change-type: patch
2024-10-08 09:37:37 -04:00
myarmolinsky
a3ec75c2c7 Remove dev dependency @octokit/rest
Change-type: patch
2024-10-08 09:37:37 -04:00
myarmolinsky
f6f6be8ee8 Remove dev dependency @octokit/plugin-throttling
Change-type: patch
2024-10-08 09:37:37 -04:00
myarmolinsky
09e653692b Remove no longer needed references and tests for mixpanel
Change-type: patch
2024-10-08 09:37:37 -04:00
myarmolinsky
3ac89b236a Remove dev dependency @types/mixpanel
Change-type: patch
2024-10-08 09:37:37 -04:00
flowzone-app[bot]
bd472f2380
v19.0.16 2024-10-08 13:35:05 +00:00
Thodoris Greasidis
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
Thodoris Greasidis
7e2b5abe60 compose: Reduce the properties updated to only the necessary
Change-type: patch
2024-10-08 16:11:28 +03:00
flowzone-app[bot]
7b66e0d216
v19.0.15 2024-10-08 13:11:05 +00:00
flowzone-app[bot]
877c5031a4
Merge pull request #2838 from balena-io/remove-mockery
Remove `mockery` dev dependency
2024-10-08 13:10:17 +00:00
myarmolinsky
1245b1c99b Remove unused mockery dev dependency
Change-type: patch
2024-10-08 08:47:14 -04:00
flowzone-app[bot]
8dbe1af551
v19.0.14 2024-10-08 12:44:20 +00:00
flowzone-app[bot]
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
myarmolinsky
284784505d Deduplicate dependencies 2024-10-08 08:21:07 -04:00
myarmolinsky
77b9514442 Temporarily skip broken image-manager tests on Windows and Mac
Change-type: patch
2024-10-08 08:21:01 -04:00
flowzone-app[bot]
ff4afe3ab2
v19.0.13 2024-09-23 11:35:49 +00:00
flowzone-app[bot]
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
myarmolinsky
127bd7ec72 Remove extra line from recent changelog entry
Change-type: patch
2024-09-23 07:12:22 -04:00
flowzone-app[bot]
fa35877137
v19.0.12 2024-09-20 17:48:43 +00:00
Matthew Yarmolinsky
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
myarmolinsky
c7441b06ac skip
Change-type: patch
2024-09-20 12:05:00 -04:00
myarmolinsky
251d64eb88 Add image-manager tests
Change-type: patch
2024-09-20 08:38:21 -04:00
myarmolinsky
ff9bb52a20 Remove balena-image-manager dependency
Change-type: patch
2024-09-20 08:38:21 -04:00
myarmolinsky
c799c3f10d Embed balena-image-manager instead of having it as a dependency
Change-type: patch
2024-09-20 08:38:21 -04:00
myarmolinsky
89efe2a2c8 Add mime dependency 2024-09-20 08:38:21 -04:00
myarmolinsky
f6ff397969 Move mkdirp from devDependency to dependency 2024-09-18 12:56:41 -04:00
flowzone-app[bot]
aaf709a1d4
v19.0.11 2024-09-18 16:38:59 +00:00
Thodoris Greasidis
ca6eea4371
Merge pull request #2835 from balena-io/reduce-bluebird
Remove Bluebird as a direct dependency
2024-09-18 19:38:06 +03:00
Thodoris Greasidis
d39dc5a39a Remove Bluebird as a direct dependency
Change-type: patch
2024-09-18 18:37:39 +03:00
flowzone-app[bot]
1699419788
v19.0.10 2024-09-12 23:00:18 +00:00
flowzone-app[bot]
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
myarmolinsky
a2b4f76c94 Remove package @resin.io/valid-email
Change-type: patch
2024-09-12 18:39:21 -04:00
flowzone-app[bot]
6a1239bd52
v19.0.9 2024-09-12 16:12:12 +00:00
balena-renovate[bot]
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
Self-hosted Renovate Bot
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
flowzone-app[bot]
7e6589a7d7
v19.0.8 2024-09-12 15:07:56 +00:00
balena-renovate[bot]
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
Self-hosted Renovate Bot
e101e0f466 Update actions/upload-artifact digest to 5076954
Update actions/upload-artifact

Change-type: patch
2024-09-12 14:47:50 +00:00
flowzone-app[bot]
e29273142e
v19.0.7 2024-09-12 14:13:22 +00:00
balena-renovate[bot]
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
Self-hosted Renovate Bot
314e8800d0 Update actions/setup-node digest to 1e60f62
Update actions/setup-node

Change-type: patch
2024-09-12 13:48:25 +00:00
flowzone-app[bot]
0bb1c892e8
v19.0.6 2024-09-12 13:47:30 +00:00
Otávio Jacobi
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
Otavio Jacobi
707b249e97 Remove moment and moment-duration-format in favor of native time parsing
Change-type: patch
2024-09-12 10:05:13 -03:00
flowzone-app[bot]
2a725cd1f0
v19.0.5 2024-09-10 15:13:27 +00:00
Otávio Jacobi
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
Self-hosted Renovate Bot
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
flowzone-app[bot]
aa46d314b4
v19.0.4 2024-09-10 14:44:44 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
39e1c02648 Deduplicate dependencies
Resolves: #
Change-type:
2024-09-10 11:53:09 +03:00
Thodoris Greasidis
5f92bbc846 Update TypeScript to 5.6.2
Change-type: patch
2024-09-10 11:49:41 +03:00
flowzone-app[bot]
2f03b24bcf
v19.0.3 2024-09-05 12:34:15 +00:00
Otávio Jacobi
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
Otavio Jacobi
facc66e9f9 Reduce use of CJS require() on automation files
Change-type: patch
2024-09-04 14:47:18 -03:00
Otavio Jacobi
6efd24489f Remove the use of CJS require() on test files
Change-type: patch
2024-09-04 14:33:52 -03:00
Otavio Jacobi
0339160a0b Remove not necessary 'import = require' syntax for js-yaml
Change-type: patch
2024-09-04 13:55:41 -03:00
flowzone-app[bot]
0591f5edbd
v19.0.2 2024-09-03 14:56:29 +00:00
flowzone-app[bot]
c30dd323f1
Merge pull request #2821 from balena-io/bump-dev-deps
update dev dependencies
2024-09-03 14:55:19 +00:00
Otavio Jacobi
1640bd6457 Update devDependency patch-package to v8.0.0
Change-type: patch
2024-09-03 11:22:45 -03:00
Otavio Jacobi
da2ffde483 Update devDependency mkdirp to v3.0.1
Change-type: patch
2024-09-03 10:58:36 -03:00
Otavio Jacobi
5c9e3ad8f6 Update devDependency fs-extra(to v11) and @types/fs-extra(to v11)
Change-type: patch
2024-09-03 10:58:36 -03:00
Otavio Jacobi
7515d4b710 Update devDependency @types/parse-link-header to v2.0.3
Change-type: patch
2024-09-03 10:58:30 -03:00
Otavio Jacobi
fae5af6b75 Remove unused devDependency @types/nock
Change-type: patch
2024-09-03 10:47:23 -03:00
Otavio Jacobi
45aa1adacb Update devDependency klaw(to v4) and @types/klaw(to v3.0.6)
Change-type: patch
2024-09-03 10:47:23 -03:00
Otavio Jacobi
b34ea14413 Update husky to v9.1.5
Change-type: patch
2024-09-03 10:47:19 -03:00
Otavio Jacobi
90eae06017 Update devDependency @types/jsonwebtoken to v9.0.6
Change-type: patch
2024-09-03 09:35:25 -03:00
Otavio Jacobi
41da8f6f6f Update devDependency archiver(to v7) and @types/archiver(to v6)
Change-type: patch
2024-09-03 09:33:07 -03:00
Otavio Jacobi
8d706a7d81 Removes unused devDependency @types/net-keepalive
Change-type: patch
2024-09-03 09:30:33 -03:00
Otavio Jacobi
d67952024c Update devDependency rewire(to v7) and @types/rewire(to v2.5.30)
Change-type: patch
2024-09-03 09:28:32 -03:00
Otavio Jacobi
8895fc485c Update devDependency sinon(to v18) and @types/sinon(to v17)
Change-type: patch
2024-09-03 09:20:41 -03:00
flowzone-app[bot]
c2dbcaaaf4
v19.0.1 2024-09-02 13:21:58 +00:00
flowzone-app[bot]
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
Otavio Jacobi
2a357a438f Bump @oclif/core from 3.27.0 to 4.0.18
Change-type: patch
2024-09-02 09:24:08 -03:00
flowzone-app[bot]
a9a202281d
v19.0.0 2024-08-22 17:43:34 +00:00
Otávio Jacobi
b74979fb9e
Merge pull request #2816 from balena-io/v19
v19
2024-08-22 14:42:42 -03:00
Otavio Jacobi
4760866c77 Update all references of lib to src
Change-type: patch
2024-08-22 13:03:37 -03:00
Otavio Jacobi
2b044348e0 Rename the lib folder to src
Change-type: major
2024-08-22 12:55:48 -03:00
Otavio Jacobi
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
Otavio Jacobi
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
flowzone-app[bot]
a08ac447a3
v18.2.34 2024-07-29 11:08:38 +00:00
flowzone-app[bot]
12a338fb21
Merge pull request #2817 from balena-io/ab77/patch-1
Switch to self-hosted
2024-07-29 11:07:51 +00:00
Kyle Harding
1d70e6b4b4 Run npm dedupe commands
Change-type: patch
Signed-off-by: Kyle Harding <kyle@balena.io>
2024-07-29 07:25:13 -03:00
Anton Belodedenko
d3458379e6
Switch to self-hosted
change-type: patch
2024-07-23 11:10:09 -07:00
flowzone-app[bot]
544f615ca0
v18.2.33 2024-07-17 07:46:28 +00:00
Otávio Jacobi
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
Otavio Jacobi
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
flowzone-app[bot]
2c0c1f8fd1
v18.2.32 2024-07-16 13:10:07 +00:00
flowzone-app[bot]
d4d7fce2c1
Merge pull request #2815 from balena-io/remove-unused-code
Remove unused code
2024-07-16 13:09:15 +00:00
Otavio Jacobi
0f23318367 Remove unused code
Change-type: patch
2024-07-16 07:46:18 -03:00
flowzone-app[bot]
003d537433
v18.2.31 2024-07-15 21:17:44 +00:00
Thodoris Greasidis
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
Thodoris Greasidis
a39a772c9e Deduplicate dependencies 2024-07-15 18:51:16 +03:00
Thodoris Greasidis
efa0d67f0a deploy: Use the sdk's pine instance with balena-compose
Change-type: patch
2024-07-15 18:42:51 +03:00
Thodoris Greasidis
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
flowzone-app[bot]
a8ce14b0e8
v18.2.30 2024-07-15 11:30:43 +00:00
Thodoris Greasidis
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
Thodoris Greasidis
4e101e2fd9 Omit unicode control character escapes from test logs
Change-type: patch
2024-07-13 18:07:04 +03:00
Thodoris Greasidis
9f9fd97795 Deduplicate dependencies 2024-07-13 17:44:04 +03:00
flowzone-app[bot]
1b36dc84fc
v18.2.29 2024-07-12 14:55:02 +00:00
flowzone-app[bot]
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
Otavio Jacobi
3c64e13fb3 Update balena-preload from 15.0.5 to 15.0.6
Change-type: patch
2024-07-12 11:30:36 -03:00
flowzone-app[bot]
7e41fda8d4
v18.2.28 2024-07-12 13:29:24 +00:00
Thodoris Greasidis
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
Thodoris Greasidis
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
Thodoris Greasidis
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
flowzone-app[bot]
4633c2456d
v18.2.27 2024-07-12 12:45:19 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
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
flowzone-app[bot]
60b0c7e346
v18.2.26 2024-07-12 12:03:32 +00:00
flowzone-app[bot]
e95ef8b3b4
Merge pull request #2803 from balena-io/fix-dependencies
Fix dependencies
2024-07-12 12:02:39 +00:00
Otavio Jacobi
1bc0f7447f Drop unused dependencies
Change-type: patch
2024-07-12 08:38:49 -03:00
Otavio Jacobi
f65215e144 Move dependencies that should be dev only as devDependencies
Change-type: patch
2024-07-12 07:15:37 -03:00
flowzone-app[bot]
97abc5cf1c
v18.2.25 2024-07-11 10:54:49 +00:00
Otávio Jacobi
e64a09d2f4
Merge pull request #2800 from balena-io/bump-oclif-v4
Bump oclif v4
2024-07-11 07:54:00 -03:00
Otavio Jacobi
b1073ca549 Fix complete generation intermitency
Change-type: patch
2024-07-10 21:22:20 -03:00
Otavio Jacobi
e659e3577a Bump oclif to v4
Change-type: patch
2024-07-10 19:07:54 -03:00
flowzone-app[bot]
f7233c5d42
v18.2.24 2024-07-10 22:06:20 +00:00
flowzone-app[bot]
4ae2ff1740
Merge pull request #2799 from balena-io/overrides-inline-source-dev-dependency-version
Update Dependencies
2024-07-10 22:05:21 +00:00
Otavio Jacobi
19a60bb0ab Update mocha from 8.4.0 to 10.6.0
Change-type: patch
2024-07-10 18:25:37 -03:00
Otavio Jacobi
d1a6f7560c Override inline-source-cli with non-vulnerable dependency
Change-type: patch
2024-07-10 18:20:05 -03:00
flowzone-app[bot]
4619ce7daa
v18.2.23 2024-07-10 21:05:55 +00:00
flowzone-app[bot]
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
Otavio Jacobi
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
flowzone-app[bot]
00bd4d5415
v18.2.22 2024-07-10 16:48:09 +00:00
flowzone-app[bot]
c2d3c9fc71
Merge pull request #2797 from balena-io/remove-unused-depedency
Remove unused dependency minimatch
2024-07-10 16:46:45 +00:00
Otavio Jacobi
1749937373 Remove unused dependency minimatch
Change-type: patch
2024-07-10 12:54:52 -03:00
flowzone-app[bot]
bcb7fb8902
v18.2.21 2024-07-09 15:10:38 +00:00
flowzone-app[bot]
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
Otavio Jacobi
6c89ba4b22 Bump resin-discoverable-services from 2.0.4 to 2.0.5
Change-type: patch
2024-07-09 11:43:45 -03:00
flowzone-app[bot]
57d3d6d537
v18.2.20 2024-07-05 21:12:48 +00:00
Otávio Jacobi
6330574c01
Merge pull request #2791 from balena-io/run-audit-fix
Audit fix dependencies
2024-07-05 18:11:52 -03:00
Otavio Jacobi
b6d1afac2d Audit fix dependencies
Change-type: patch
2024-07-05 17:41:14 -03:00
flowzone-app[bot]
f2d0da0837
v18.2.19 2024-07-05 13:37:55 +00:00
flowzone-app[bot]
068cd887c8
Merge pull request #2790 from balena-io/unneeded-publish-release
Remove unused package `publish-release`
2024-07-05 13:36:53 +00:00
myarmolinsky
93e597a596 Remove unused package publish-release
Change-type: patch
2024-07-05 08:56:51 -04:00
flowzone-app[bot]
5b1d6a3190
v18.2.18 2024-07-04 21:56:19 +00:00
Otávio Jacobi
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
Self-hosted Renovate Bot
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
flowzone-app[bot]
78368c8a51
v18.2.17 2024-07-02 13:20:43 +00:00
balena-renovate[bot]
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
Self-hosted Renovate Bot
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
flowzone-app[bot]
b5fc97bdf9
v18.2.16 2024-07-02 12:14:25 +00:00
balena-renovate[bot]
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
Self-hosted Renovate Bot
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
flowzone-app[bot]
dad6b23202
v18.2.15 2024-07-02 11:11:04 +00:00
balena-renovate[bot]
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
Self-hosted Renovate Bot
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
flowzone-app[bot]
bd4bdb805f
v18.2.14 2024-07-02 10:14:47 +00:00
Otávio Jacobi
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
Self-hosted Renovate Bot
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
flowzone-app[bot]
92146429c4
v18.2.13 2024-07-02 09:14:07 +00:00
balena-renovate[bot]
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
Self-hosted Renovate Bot
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
flowzone-app[bot]
15e91e95b4
v18.2.12 2024-07-02 07:50:17 +00:00
Thodoris Greasidis
1814fe7581
Merge pull request #2782 from balena-io/npm-dd
Deduplicate dependencies
2024-07-02 10:49:11 +03:00
Thodoris Greasidis
7325e8d9d5 Deduplicate dependencies
Change-type: patch
2024-07-01 22:51:28 +03:00
flowzone-app[bot]
5358f92590
v18.2.11 2024-07-01 17:52:46 +00:00
balena-renovate[bot]
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
Self-hosted Renovate Bot
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
flowzone-app[bot]
049e1da53e
v18.2.10 2024-06-21 20:12:54 +00:00
balena-renovate[bot]
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
Self-hosted Renovate Bot
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
flowzone-app[bot]
8f2c7f9dbf
v18.2.9 2024-06-21 19:13:44 +00:00
balena-renovate[bot]
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
Self-hosted Renovate Bot
73220206a2 Update actions/setup-python digest to 65d7f2d
Update actions/setup-python

Change-type: patch
2024-06-21 18:48:07 +00:00
flowzone-app[bot]
8b453aae89
v18.2.8 2024-06-21 18:13:51 +00:00
balena-renovate[bot]
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
Self-hosted Renovate Bot
2cd455ff81 Update actions/upload-artifact digest to 6546280
Update actions/upload-artifact

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

Change-type: patch
2024-06-21 16:47:51 +00:00
flowzone-app[bot]
edff14fa72
v18.2.6 2024-06-21 15:23:25 +00:00
flowzone-app[bot]
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
Otavio Jacobi
75d2d7d375 Update @oclif/core from 3.26.9 to 3.27.0
Change-type: patch
2024-06-21 09:49:38 -03:00
flowzone-app[bot]
d9b193acc1
v18.2.5 2024-06-21 12:11:21 +00:00
flowzone-app[bot]
2e42999642
Merge pull request #2769 from balena-io/bump-ts
Update TypeScript to 5.5.2
2024-06-21 12:10:18 +00:00
Thodoris Greasidis
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
Thodoris Greasidis
e1cd30060c Deduplicate dependencies 2024-06-21 01:31:53 +03:00
Thodoris Greasidis
7959e23cd3 Update TypeScript to 5.5.2
Change-type: patch
2024-06-21 00:18:36 +03:00
flowzone-app[bot]
9c4d788d6d
v18.2.4 2024-05-17 12:04:11 +00:00
flowzone-app[bot]
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
Edwin Joassart
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
flowzone-app[bot]
1724187466
v18.2.3 2024-05-15 13:32:53 +00:00
flowzone-app[bot]
b27dcdd582
Merge pull request #2765 from balena-io/dfunckt-patch-1
Pluralize command categories in docs
2024-05-15 13:31:57 +00:00
Akis Kesoglou
c28039a3f2 Fix exitCode type 2024-05-15 16:01:38 +03:00
dfunckt
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
flowzone-app[bot]
71518678e1
v18.2.2 2024-04-30 13:57:49 +00:00
flowzone-app[bot]
88a705c935
Merge pull request #2754 from balena-io/upgrade_dockerode
Upgrade dockerode and docker-modem dependencies
2024-04-30 13:56:52 +00:00
Ken Bannister
55d06aced2 Deduplicate npm dependencies
Signed-off-by: Ken Bannister <kb2ma@runbox.com>
2024-04-29 08:20:02 -04:00
Ken Bannister
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
flowzone-app[bot]
10ca5b4f59
v18.2.1 2024-04-23 12:08:57 +00:00
flowzone-app[bot]
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
Kyle Harding
6fb65bcf22 Re-run npm install and npm dedupe
Signed-off-by: Kyle Harding <kyle@balena.io>
2024-04-22 17:56:20 +03:00
Kyle Harding
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
flowzone-app[bot]
f81a27e931
v18.2.0 2024-04-17 16:13:12 +00:00
Thodoris Greasidis
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
Thodoris Greasidis
766e6d4e5e build: Auto-resolve the cpu arch when the --deviceType is provided
Change-type: minor
2024-04-17 18:10:30 +03:00
flowzone-app[bot]
7b46f65a01
v18.1.10 2024-04-16 14:17:07 +00:00
Thodoris Greasidis
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
Thodoris Greasidis
7c7f46fe2b Deduplicate dependencies 2024-04-16 16:46:25 +03:00
Thodoris Greasidis
b29aae1821 Mark node 20.6.0 as the minimum working version
Change-type: patch
2024-04-16 15:42:41 +03:00
flowzone-app[bot]
0b10701015
v18.1.9 2024-04-10 15:24:31 +00:00
Thodoris Greasidis
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
Thodoris Greasidis
d01461ff3e Deduplicate dependencies 2024-04-10 17:39:18 +03:00
Kyle Harding
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
flowzone-app[bot]
ffd44d3fec
v18.1.8 2024-04-09 17:29:48 +00:00
Thodoris Greasidis
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
Thodoris Greasidis
6178f34f88 Bump patch-package to 6.5.1
Change-type: patch
2024-04-09 19:25:17 +03:00
Thodoris Greasidis
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
flowzone-app[bot]
87f5f18721
v18.1.7 2024-04-09 16:03:36 +00:00
Thodoris Greasidis
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
Thodoris Greasidis
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
flowzone-app[bot]
9d3ee9eb49
v18.1.6 2024-04-09 15:04:42 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
04b4444fc2 Update expected build warning tests 2024-04-09 17:17:07 +03:00
Thodoris Greasidis
98514cef09 Deduplicate dependencies 2024-04-09 17:17:07 +03:00
Thodoris Greasidis
4811031172 Update @oclif/core to 3.26.2
Change-type: patch
2024-04-09 17:17:07 +03:00
Thodoris Greasidis
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
Thodoris Greasidis
c6827ee51d Update balena-preload to v15.0.4
Change-type: patch
2024-04-09 17:17:07 +03:00
Thodoris Greasidis
2cba3bbc22 Update resin-cli-form to v3
Change-type: patch
2024-04-09 17:17:07 +03:00
Thodoris Greasidis
933eacf275 Update resin-cli-visuals to v2
Change-type: patch
2024-04-09 17:17:07 +03:00
Thodoris Greasidis
e7869f4c6d Update balena-device-init to v7.0.1
Change-type: patch
2024-04-09 17:17:07 +03:00
Thodoris Greasidis
1a246a9ba5 Update etcher-sdk to v9.0.8
Change-type: patch
2024-04-09 17:16:30 +03:00
Thodoris Greasidis
e26895085d Mark bin/dev & bin/run as executable
Change-type: patch
2024-04-09 17:16:30 +03:00
flowzone-app[bot]
71345a8cc1
v18.1.5 2024-03-14 15:52:40 +00:00
flowzone-app[bot]
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
Otavio Jacobi
bb4713ab9a Move klaw library to dev dependency
Change-type: patch
2024-03-14 11:41:10 -03:00
flowzone-app[bot]
168bddf7db
v18.1.4 2024-03-14 14:34:50 +00:00
flowzone-app[bot]
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
myarmolinsky
634ad156ce Update @balena/lint to 8.0.0
Change-type: patch
2024-03-14 10:00:52 -04:00
flowzone-app[bot]
6ebeb97917
v18.1.3 2024-03-14 12:57:24 +00:00
Otávio Jacobi
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
Otavio Jacobi
742c015f21 Use standard oclif run.js & dev.js
Change-type: patch
2024-03-14 09:21:11 -03:00
flowzone-app[bot]
556e50c87c
v18.1.2 2024-03-13 13:49:11 +00:00
Otávio Jacobi
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
Otavio Jacobi
7f11805a7f Move macos binary signing to oclif pretarball lifecycle
Change-type: patch
2024-03-13 09:40:30 -03:00
flowzone-app[bot]
42dd732f68
v18.1.1 2024-03-12 17:39:15 +00:00
flowzone-app[bot]
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
Otavio Jacobi
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
flowzone-app[bot]
7903c82821
v18.1.0 2024-03-12 14:21:30 +00:00
Otávio Jacobi
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
Otavio Jacobi
38a2817587 Add support for macos arm64 builds
Change-type: minor
2024-03-11 20:49:29 -03:00
flowzone-app[bot]
2bd0641d5f
v18.0.4 2024-03-11 22:19:10 +00:00
flowzone-app[bot]
122a763f82
Merge pull request #2739 from balena-io/update-dependencies
Update dependencies
2024-03-11 22:18:03 +00:00
Otavio Jacobi
756f6b328b Update dependencies
Change-type: patch
2024-03-11 16:35:32 -03:00
flowzone-app[bot]
eb9db6f7b4
v18.0.3 2024-03-11 14:25:51 +00:00
flowzone-app[bot]
6f9e5a697c
Merge pull request #2740 from balena-io/removes-signing-patches
Removes signing patches
2024-03-11 14:24:40 +00:00
Otavio Jacobi
f9f41eef4b Removes signing patches
Change-type: patch
2024-03-11 10:53:54 -03:00
flowzone-app[bot]
5371fea588
v18.0.2 2024-03-07 19:40:27 +00:00
flowzone-app[bot]
bacb55a1ea
Merge pull request #2735 from balena-io/removes-patches-windows
Removes no longer needed patch
2024-03-07 19:39:38 +00:00
Otavio Jacobi
ecfd4a260e Remove no longer needed windows oclif patches
Change-type: patch
2024-03-07 15:51:00 -03:00
flowzone-app[bot]
1525822239
v18.0.1 2024-03-07 16:30:17 +00:00
flowzone-app[bot]
1614d9b2c8
Merge pull request #2733 from balena-io/fix-windows-signing
Fix windows signing
2024-03-07 16:29:07 +00:00
Otavio Jacobi
2e061845ae Fix windows signing
Change-type: patch
2024-03-07 13:01:08 -03:00
flowzone-app[bot]
9e4dd3fce2
v18.0.0 2024-02-06 12:19:41 +00:00
flowzone-app[bot]
b2590136fc
Merge pull request #2720 from balena-io/bump-node-20
Update to Node 20
2024-02-06 12:18:34 +00:00
Otávio Jacobi
bf5e61a61c Update to Node 20
Change-type: major
2024-02-05 18:29:02 -03:00
flowzone-app[bot]
f550d0c596
v17.5.1 2024-01-31 01:05:23 +00:00
Ken Bannister
54302669b8
Merge pull request #2725 from balena-io/livepush-fix
Fix target state construction with livepush
2024-01-30 20:04:28 -05:00
Felipe Lalanne
a4a4e33d7b Dedupe dependencies 2024-01-30 11:17:21 -03:00
Felipe Lalanne
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
flowzone-app[bot]
4b2602676b
v17.5.0 2024-01-23 15:52:54 +00:00
Thodoris Greasidis
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
Thodoris Greasidis
97a6013537 Deduplicate dependencies 2024-01-23 16:55:36 +02:00
Thodoris Greasidis
1ba8db1459 os versions: Add the --include-draft option
Change-type: minor
2024-01-23 16:55:36 +02:00
Thodoris Greasidis
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
Thodoris Greasidis
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
Thodoris Greasidis
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
flowzone-app[bot]
3a7f6d78b0
v17.4.12 2024-01-18 10:55:53 +00:00
Ken Bannister
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
Ken Bannister
fe70d164c1 Deduplicate dependencies 2024-01-15 22:38:12 +00:00
Ken Bannister
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
flowzone-app[bot]
07854c3d42
v17.4.11 2024-01-05 23:01:11 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
4e5eb4bcee Exclude the oclif package patch from the published files
Change-type: patch
2024-01-06 00:25:56 +02:00
Thodoris Greasidis
696bad3ed6 Update the @oclif/core patch
Change-type: patch
2024-01-06 00:25:34 +02:00
Thodoris Greasidis
9a9d0f02ef Deduplicate dependencies 2024-01-06 00:25:34 +02:00
flowzone-app[bot]
f46d00640b
v17.4.10 2024-01-02 12:41:44 +00:00
Thodoris Greasidis
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
Thodoris Greasidis
75b29112a7 Deduplicate dependencies 2024-01-02 13:55:40 +02:00
Thodoris Greasidis
b7b01ecd53 Normalize v prefixes in the --version parameter of all commands
Change-type: patch
2024-01-02 13:33:38 +02:00
flowzone-app[bot]
801a25995c
v17.4.9 2023-12-19 23:02:33 +00:00
flowzone-app[bot]
8296dea78c
Merge pull request #2713 from balena-io/fix-ci
Fix publishing artifacts to gh release
2023-12-19 23:01:35 +00:00
Otávio Jacobi
1da5a75c14 Fix publishing artifacts to gh release
Change-type: patch
2023-12-19 19:10:06 -03:00
flowzone-app[bot]
166de57179
v17.4.8 2023-12-19 21:59:10 +00:00
flowzone-app[bot]
85dece9e95
Merge pull request #2714 from balena-io/kyle/patch
Remove repo config from flowzone.yml
2023-12-19 21:58:24 +00:00
Kyle Harding
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
flowzone-app[bot]
d243c14d74
v17.4.7 2023-12-19 14:26:31 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
4266dc6951 deploy: Add rate-limiting aware retries for failed requests
Change-type: patch
2023-12-19 01:16:42 +02:00
Thodoris Greasidis
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
Thodoris Greasidis
19b0e9489d Deduplicate node modules 2023-12-19 01:16:42 +02:00
flowzone-app[bot]
d9fed9c34c
v17.4.6 2023-12-08 15:55:53 +00:00
flowzone-app[bot]
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
Otávio Jacobi
b9722c6796 Bump oclif core & use default missing flag handler
Change-type: patch
2023-12-08 12:06:54 -03:00
flowzone-app[bot]
29ade0f696
v17.4.5 2023-12-04 14:08:31 +00:00
flowzone-app[bot]
d5ae612513
Merge pull request #2707 from balena-io/bump-ts
Update TypeScript to 5.3.2
2023-12-04 14:07:30 +00:00
Thodoris Greasidis
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
Thodoris Greasidis
f5ffa7d84f Temporarily pin oclif-core to ~3.11.0 to deduplicate the dependencies
Change-type: patch
2023-12-04 15:36:43 +02:00
Thodoris Greasidis
dac3ace61d Update TypeScript to 5.3.2
Change-type: patch
2023-11-30 00:07:17 +02:00
flowzone-app[bot]
72459a04d1
v17.4.4 2023-11-20 17:57:23 +00:00
flowzone-app[bot]
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
Otávio Jacobi
b8769bb9e9 Fix balena block create to actually create a block
Change-type: patch
2023-11-20 13:33:35 -03:00
flowzone-app[bot]
9f52ee8b21
v17.4.3 2023-11-17 15:39:24 +00:00
flowzone-app[bot]
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
Otávio Jacobi
72a924f00e Bump oclif-core to v3
Change-type: patch
2023-11-16 15:06:24 -03:00
flowzone-app[bot]
e4624eda10
v17.4.2 2023-11-15 11:02:24 +00:00
flowzone-app[bot]
4173cd82e6
Merge pull request #2697 from balena-io/vipul/automate-capitan
Automatically generate Capitano Docs configuration
2023-11-15 11:01:38 +00:00
Vipul Gupta (@vipulgupta2048)
b393f27e1b
Remove authentication directory
Signed-off-by: Vipul Gupta (@vipulgupta2048) <vipulgupta2048@gmail.com>
2023-11-15 15:55:03 +05:30
Vipul Gupta (@vipulgupta2048)
1a4a0e2439
Move auth commands into command directories
Signed-off-by: Vipul Gupta (@vipulgupta2048) <vipulgupta2048@gmail.com>
2023-11-15 15:10:22 +05:30
Vipul Gupta (@vipulgupta2048)
4cd8f4c16e
Docs: Generate balena auto-completion
Signed-off-by: Vipul Gupta (@vipulgupta2048) <vipulgupta2048@gmail.com>
2023-11-15 13:08:08 +05:30
Vipul Gupta (@vipulgupta2048)
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
Vipul Gupta (@vipulgupta2048)
d9427c3c59
Docs: Generate balenaCLI with automatic configuration
Signed-off-by: Vipul Gupta (@vipulgupta2048) <vipulgupta2048@gmail.com>
2023-11-15 13:07:01 +05:30
Vipul Gupta (@vipulgupta2048)
fc0cfac475
Docs: Create version command directory
Signed-off-by: Vipul Gupta (@vipulgupta2048) <vipulgupta2048@gmail.com>
2023-11-15 13:06:45 +05:30
Vipul Gupta (@vipulgupta2048)
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
Vipul Gupta (@vipulgupta2048)
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
Vipul Gupta (@vipulgupta2048)
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
Vipul Gupta (@vipulgupta2048)
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
flowzone-app[bot]
f44fa38113
v17.4.1 2023-11-13 19:18:47 +00:00
flowzone-app[bot]
167dfeb269
Merge pull request #2701 from balena-io/bump-shrinkwrap
Bump shrinkwrap
2023-11-13 19:17:53 +00:00
Otávio Jacobi
a816548bb5 Bump shrinkwrap
Change-type: patch
2023-11-13 15:43:13 -03:00
flowzone-app[bot]
94001efc81
v17.4.0 2023-11-10 16:28:02 +00:00
Otávio Jacobi
8bfafe8ecc
Merge pull request #2692 from bbugh/device-json
device: Add `--json` option for JSON output
2023-11-10 13:26:59 -03:00
Brian Bugh
d78045b6ab device: Add --json option for JSON output
change-type: minor
2023-11-10 12:10:53 -03:00
flowzone-app[bot]
11eabc4b96
v17.3.2 2023-11-10 11:03:00 +00:00
Thodoris Greasidis
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
Thodoris Greasidis
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
flowzone-app[bot]
7954e13154
v17.3.1 2023-11-09 17:26:42 +00:00
Page-
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
Pagan Gazzard
56cff46408 Use pipeline instead of .pipe when downloading OS image
Change-type: patch
2023-11-09 13:38:17 -03:00
flowzone-app[bot]
47a1a9c6af
v17.3.0 2023-11-06 20:19:10 +00:00
Matthew Yarmolinsky
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
Morgan Larsson
221c213791 Add device start-service and stop-service commands
Change-type: minor
2023-11-06 16:13:51 -03:00
flowzone-app[bot]
d2150c5cb7
v17.2.4 2023-11-06 19:12:02 +00:00
Otávio Jacobi
70e113152d
Merge pull request #2696 from balena-io/fix-dsutils
Dedupe shrinkwrap
2023-11-06 16:11:13 -03:00
myarmolinsky
4a64102d67 Dedupe shrinkwrap
Change-type: patch
2023-11-06 14:11:38 -03:00
flowzone-app[bot]
9bf267166e
v17.2.3 2023-11-03 16:34:18 +00:00
flowzone-app[bot]
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
Vipul Gupta (@vipulgupta2048)
80d6c71b02
Update CONTRIBUTING.md with docs instructions
Signed-off-by: Vipul Gupta (@vipulgupta2048) <vipulgupta2048@gmail.com>
2023-11-03 20:39:25 +05:30
Vipul Gupta (@vipulgupta2048)
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
flowzone-app[bot]
25f3bf1fbe
v17.2.2 2023-10-30 12:25:19 +00:00
flowzone-app[bot]
fe65351666
Merge pull request #2672 from balena-io/bump-eslint
Bump @balena/lint
2023-10-30 12:24:13 +00:00
myarmolinsky
7d13946c3e Bump balena-lint to 7.2.1
Change-type: patch
2023-10-30 07:45:51 -04:00
flowzone-app[bot]
1ffa8d38f1
v17.2.1 2023-10-26 21:28:48 +00:00
flowzone-app[bot]
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
Otávio Jacobi
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
flowzone-app[bot]
c785d01a1c
v17.2.0 2023-10-20 13:45:59 +00:00
Otávio Jacobi
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
Brian Bugh
b7e5915c7a
release: Add '--json' option for JSON output
change-type: minor
2023-10-20 07:42:39 -05:00
Brian Bugh
0cef6b8f87 releases: Add '--json' option for JSON output 2023-10-20 08:05:36 -03:00
flowzone-app[bot]
71f1dbd80a
v17.1.7 2023-10-20 10:49:19 +00:00
Thodoris Greasidis
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
Thodoris Greasidis
8204dcad93 tag set: Fix using empty string as a value
Change-type: patch
2023-10-20 13:11:12 +03:00
Thodoris Greasidis
03bcb6cff7 env add: Fix using empty string as a value
Change-type: patch
2023-10-20 13:11:12 +03:00
Thodoris Greasidis
66b6eed57c Add tests for empty & non-provided value for the env add command
Change-type: patch
2023-10-20 13:11:12 +03:00
Thodoris Greasidis
99b0f2c022 Add tests for the tag set command
Change-type: patch
2023-10-20 13:06:39 +03:00
flowzone-app[bot]
947a9bade7
v17.1.6 2023-10-18 18:16:11 +00:00
flowzone-app[bot]
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
Kyle Harding
ce888966dd
Update npm shrinkwrap
Signed-off-by: Kyle Harding <kyle@balena.io>
2023-10-18 13:04:02 -04:00
Kyle Harding
3fc6eb7a47
Allow custom actions for external contributors
Change-type: patch
2023-10-18 12:53:43 -04:00
flowzone-app[bot]
73aebf10bf
v17.1.5 2023-10-05 10:54:36 +00:00
Otávio Jacobi
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
Otávio Jacobi
dc3261d9c7 Fix ssh ignoreStdin device argument
Change-type: patch
2023-10-05 07:05:53 -03:00
flowzone-app[bot]
301d0ab3a0
v17.1.4 2023-09-29 12:40:52 +00:00
flowzone-app[bot]
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
Otávio Jacobi
fa2a232e5f Bump oclif to ^3.17.1
Change-type: patch
2023-09-28 18:35:59 -03:00
flowzone-app[bot]
da1f022df9
v17.1.3 2023-09-26 13:58:00 +00:00
flowzone-app[bot]
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
Otávio Jacobi
77906c4152 Move to @oclif/core v2
Change-type: patch
2023-09-26 09:50:39 -03:00
Otávio Jacobi
26bc68753b Remove direct dependency to @oclif/config
Change-type: patch
2023-09-26 09:48:13 -03:00
flowzone-app[bot]
af6b263f7a
v17.1.2 2023-09-26 12:14:31 +00:00
flowzone-app[bot]
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
Otávio Jacobi
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
flowzone-app[bot]
519ac0383a
v17.1.1 2023-09-05 15:06:14 +00:00
flowzone-app[bot]
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
Otávio Jacobi
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
flowzone-app[bot]
a1c9b4b80e
v17.1.0 2023-09-05 13:01:03 +00:00
Matthew Yarmolinsky
2b1be3e5d9
Merge pull request #2647 from balena-io/update-oclif
Update oclif, improve help command
2023-09-05 08:59:52 -04:00
myarmolinsky
e46378ec51 Update oclif, improve help command
Change-type: minor
2023-09-04 21:07:05 -03:00
flowzone-app[bot]
27ee9c85e7
v17.0.0 2023-08-29 11:45:54 +00:00
flowzone-app[bot]
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
Otávio Jacobi
817ce5dc96 Update to Node 18
Change-type: major
2023-08-29 07:35:53 -03:00
flowzone-app[bot]
d9af28bca7
v16.8.0 2023-08-25 17:47:44 +00:00
flowzone-app[bot]
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
Otávio Jacobi
14ba287e0d Accept device & application keys on login as experimental feature
Change-type: minor
2023-08-23 11:12:06 -03:00
flowzone-app[bot]
1671e46d99
v16.7.9 2023-08-22 13:33:30 +00:00
Otávio Jacobi
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
Otávio Jacobi
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
flowzone-app[bot]
e1be268749
v16.7.8 2023-08-22 11:16:38 +00:00
flowzone-app[bot]
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
Otávio Jacobi
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
Otávio Jacobi
f38e643cf0 env: Stop fetching unnecessary app fields
Change-type: patch
2023-08-21 14:39:16 -03:00
Otávio Jacobi
b8e190cd1d Remove redundant envs documentation
Change-type: patch
2023-08-21 14:39:16 -03:00
Otávio Jacobi
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
flowzone-app[bot]
35177e2d2f
v16.7.7 2023-08-21 16:56:33 +00:00
flowzone-app[bot]
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
Otávio Jacobi
272915192b Revert flowzone to master
Change-type: patch
2023-08-17 20:22:53 -03:00
balenaCI
96774f4c52
v16.7.6 2023-07-24 13:38:06 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
365d95c36b app create: Fix halting with a deprecation warning
Change-type: patch
2023-07-21 10:02:32 +03:00
balenaCI
c6313c08ae
v16.7.5 2023-07-21 06:59:22 +00:00
Thodoris Greasidis
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
Thodoris Greasidis
aff094575b Abstract the fleet/app/block create commands
Change-type: patch
2023-07-20 16:14:52 +03:00
balenaCI
4aaaf64f8d
v16.7.4 2023-07-20 10:41:09 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
b011af89ad move: Include fleets of discontinued device types in the fleet selection
Change-type: patch
2023-07-20 13:03:54 +03:00
balenaCI
1bf8c1bfe7
v16.7.3 2023-07-20 08:30:09 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
98663af7f6 Rerun npm-shrinkwrap.json deduplication 2023-07-19 19:44:43 +03:00
Thodoris Greasidis
5628824bee promote: Allow joining fleets of discontinued device types
Change-type: patch
2023-07-19 19:17:27 +03:00
balenaCI
d12d7996bc
v16.7.2 2023-07-19 01:43:55 +00:00
flowzone-app[bot]
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
Felipe Lalanne
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
balenaCI
f4a24e26c3
v16.7.1 2023-07-18 20:27:07 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
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
balenaCI
406482b4da
v16.7.0 2023-07-17 19:59:52 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
8ce78ba33c Rerun npm-shrinkwrap.json deduplication 2023-07-17 11:25:02 +03:00
Thodoris Greasidis
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
balenaCI
0086feb645
v16.6.6 2023-07-10 17:16:08 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
90c6f121cc Rerun npm-shrinkwrap.json deduplication 2023-07-10 19:36:36 +03:00
Thodoris Greasidis
d3c27ae859 Reduce lodash usage in common user interaction patterns
Change-type: patch
2023-07-10 17:19:01 +03:00
balenaCI
8f39c1de6c
v16.6.5 2023-07-09 21:29:55 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
2bce761ace Rerun npm-shrinkwrap.json deduplication 2023-07-07 20:17:53 +03:00
Thodoris Greasidis
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
balenaCI
f07f6b84d4
v16.6.4 2023-07-06 13:58:27 +00:00
flowzone-app[bot]
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
Felipe Lalanne
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
balenaCI
338477463a
v16.6.3 2023-06-30 17:07:34 +00:00
dfunckt
d1275760fa
Merge pull request #2641 from balena-io/drop-toolbelt
Pin dockerode and drop docker-toolbelt
2023-06-30 20:06:46 +03:00
Akis Kesoglou
0f4054fa4d Remove redundant dependency on docker-toolbelt
Change-type: patch
2023-06-30 19:22:07 +03:00
Akis Kesoglou
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
balenaCI
a1f25809cb
v16.6.2 2023-06-29 12:27:14 +00:00
flowzone-app[bot]
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
myarmolinsky
d843e75512 macos notarization: Expose team ID instead of keeping it in secrets
Change-type: patch
2023-06-29 07:41:07 -04:00
balenaCI
72c57608d5
v16.6.1 2023-06-28 12:47:56 +00:00
flowzone-app[bot]
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
myarmolinsky
10b5af6967 Drop electron-notarize dependency in favor of @electron/notarize
Change-type: patch
2023-06-28 08:01:39 -04:00
balenaCI
51c050c725
v16.6.0 2023-06-26 13:05:11 +00:00
Matthew Yarmolinsky
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
myarmolinsky
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
balenaCI
1a77d86347
v16.5.2 2023-06-09 16:03:10 +00:00
flowzone-app[bot]
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
Kyle Harding
034f459bfa
Update npm-shrinkwrap
Signed-off-by: Kyle Harding <kyle@balena.io>
2023-06-09 11:23:49 -04:00
Kyle Harding
bc405d997e
Re-enable automatic github final releases
Change-type: patch
2023-06-09 11:05:01 -04:00
balenaCI
af27cf2cbe
v16.5.1 2023-06-02 06:30:00 +00:00
flowzone-app[bot]
83b9bf67c2
Merge pull request #2636 from balena-io/bump-ts
Update TypeScript to 5.1.3
2023-06-02 06:29:11 +00:00
Thodoris Greasidis
abd73b805b Update TypeScript to 5.1.3
Change-type: patch
2023-06-01 21:58:34 +03:00
balenaCI
37bfd4db98
v16.5.0 2023-05-25 16:45:02 +00:00
flowzone-app[bot]
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
myarmolinsky
9975e5d9ac Add balena block create command for creating Blocks
Change-type: minor
2023-05-25 12:00:39 -04:00
balenaCI
1341413966
v16.4.0 2023-05-25 15:53:23 +00:00
flowzone-app[bot]
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
myarmolinsky
c5e8f0d6ea Add balena app create command for creatings Apps
Change-type: minor
2023-05-25 11:09:02 -04:00
balenaCI
3a143fe413
v16.3.0 2023-05-25 15:06:39 +00:00
flowzone-app[bot]
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
myarmolinsky
166130c3df Add balena api-keys command for listing user/fleet API keys
Change-type: minor
2023-05-25 09:11:36 -04:00
balenaCI
c3a8a905f7
v16.2.7 2023-05-24 12:04:59 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
063e9d40f0 device init: Avoid extra request when not providing the --fleet option
Change-type: patch
2023-05-24 14:22:04 +03:00
Thodoris Greasidis
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
Thodoris Greasidis
861d4f33b7 ssh,tunnel: Fetch the fleet & devices in one request
Change-type: patch
2023-05-24 14:22:04 +03:00
balenaCI
81f4aae7d2
v16.2.6 2023-05-24 11:17:30 +00:00
Thodoris Greasidis
46ab335407
Merge pull request #2626 from balena-io/less-requests
Stop fetching unnecessary fields
2023-05-24 14:16:42 +03:00
Thodoris Greasidis
07cb0cbfcd device init: Stop fetching unnecessary app fields
Change-type: patch
2023-05-24 13:37:19 +03:00
Thodoris Greasidis
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
Thodoris Greasidis
8b3235ab2b device register: Stop fetching unnecessary app fields
Change-type: patch
2023-05-24 13:37:19 +03:00
Thodoris Greasidis
15dac6f194 config generate: Stop fetching unnecessary app fields
Change-type: patch
2023-05-24 13:37:19 +03:00
Thodoris Greasidis
3c93db8449 devices: Stop fetching unnecessary device fields
Change-type: patch
2023-05-24 13:37:19 +03:00
Thodoris Greasidis
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
Thodoris Greasidis
bcadbdbed8 push: Stop unnecessarily fetching the application name
Change-type: patch
2023-05-24 13:37:19 +03:00
Thodoris Greasidis
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
Thodoris Greasidis
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
Thodoris Greasidis
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
Thodoris Greasidis
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
balenaCI
ba1f17d537
v16.2.5 2023-05-24 10:30:21 +00:00
Thodoris Greasidis
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
Thodoris Greasidis
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
balenaCI
01e765e670
v16.2.4 2023-05-23 20:31:27 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
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
balenaCI
b6c7fb82c3
v16.2.3 2023-05-23 19:46:47 +00:00
flowzone-app[bot]
fcda09009a
Merge pull request #2624 from balena-io/improve-typings
Use stricter typings
2023-05-23 19:46:02 +00:00
Thodoris Greasidis
1a6fe1f3de Use stricter typings
Change-type: patch
2023-05-23 18:57:54 +03:00
balenaCI
98e91c0607
v16.2.2 2023-05-23 14:02:36 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
50e852acee env add: Fix accepting fleet names when setting service vars
Change-type: patch
2023-05-23 15:59:41 +03:00
balenaCI
da30623e4e
v16.2.1 2023-05-23 12:28:25 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
d9651c7393 Update balena-settings-client to 5.0.2
Change-type: patch
2023-05-23 13:22:38 +03:00
Thodoris Greasidis
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
Thodoris Greasidis
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
balenaCI
9d197317ca
v16.2.0 2023-05-19 18:11:57 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
0c62b9ef08 Deduplicate npm-shrinkwra.json 2023-05-19 20:28:12 +03:00
Thodoris Greasidis
83a5e7392a secureboot: Retrieve the OS release & contract in one request
Change-type: patch
2023-05-19 19:22:23 +03:00
Alex Gonzalez
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
Alex Gonzalez
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
Alex Gonzalez
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
balenaCI
632296a271
v16.1.0 2023-05-16 18:26:10 +00:00
flowzone-app[bot]
3e089fcdb2
Merge pull request #2616 from balena-io/ab77/operational
build linux/arm packages
2023-05-16 18:25:27 +00:00
balenaCI
d61c300750
build linux/arm packages
change-type: minor
2023-05-16 10:39:00 -07:00
balenaCI
a0a97c5f40
v16.0.0 2023-05-16 00:02:37 +00:00
flowzone-app[bot]
165f3b83ca
Merge pull request #2618 from balena-io/node-16
Update to Node 16
2023-05-16 00:01:48 +00:00
Thodoris Greasidis
5bf95300ee support: Change the printed support expiry date in ISO 8601 UTC format
Change-type: major
2023-05-12 19:00:10 +03:00
Thodoris Greasidis
adb460b270 logs: Change the timestamp format to ISO 8601 UTC
Resolves: #2608
Change-type: major
2023-05-12 19:00:10 +03:00
Felipe Lalanne
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
Felipe Lalanne
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
Felipe Lalanne
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
Felipe Lalanne
7dfb7474f5 Update to Node 16
This also drops support for Node 14

Change-type: major
2023-05-11 17:49:37 -04:00
balenaCI
6ee0b48c9a
v15.2.3 2023-05-03 20:03:49 +00:00
flowzone-app[bot]
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
Felipe Lalanne
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
balenaCI
5545883c3f
v15.2.2 2023-04-28 16:16:44 +00:00
flowzone-app[bot]
75a380b0ba
Merge pull request #2615 from balena-io/remove-nvmrc
Remove nvmrc
2023-04-28 16:15:57 +00:00
Felipe Lalanne
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
balenaCI
69249b3139
v15.2.1 2023-04-28 09:25:50 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
150c6e75f5 Fix tslib going out of sync causing HUP to fail
Change-type: patch
2023-04-27 14:07:57 +03:00
balenaCI
e8bc43dc64
v15.2.0 2023-04-05 13:09:24 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
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
balenaCI
7ad9e685f6
v15.1.3 2023-04-05 08:06:56 +00:00
flowzone-app[bot]
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
Thodoris Greasidis
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
balenaCI
03ace6e4b2
v15.1.2 2023-03-27 15:14:47 +00:00
Thodoris Greasidis
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
Thodoris Greasidis
174312977a Improve type checking by using the satisfies operator
Change-type: patch
2023-03-27 16:39:09 +03:00
balenaCI
963d9af817
v15.1.1 2023-03-17 10:20:03 +00:00
Thodoris Greasidis
af5ec51232
Merge pull request #2600 from balena-io/bump-ts
Update TypeScript to 5.0.2
2023-03-17 12:19:13 +02:00
Thodoris Greasidis
1cd9fbf6a0 Update TypeScript to 5.0.2
Change-type: patch
2023-03-16 20:53:08 +02:00
balenaCI
72639e9e59
v15.1.0 2023-03-14 20:19:08 +00:00
Kyle Harding
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
Kyle Harding
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
balenaCI
3e5b4457c2
v15.0.6 2023-03-13 14:03:48 +00:00
Otávio Jacobi
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
Otávio Jacobi
5761a306be Devices: explicitly fetches only used fields
Change-type: patch
2023-03-13 09:35:43 -03:00
balenaCI
adff0f2a0a
v15.0.5 2023-03-10 16:25:40 +00:00
Thodoris Greasidis
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
JSReds
ecf4b046b5 Fix application isLegacy check for rename and deploy
Change-type: patch
2023-03-10 16:33:00 +01:00
balenaCI
b0cae93ac9
v15.0.4 2023-02-21 07:24:19 +00:00
Balena CI
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
Heath Raftery
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
balenaCI
8a84d9d792
v15.0.3 2023-01-18 16:16:39 +00:00
Page-
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
Pagan Gazzard
234fb6cd39 Use https for the npm deprecation check, avoiding a redirect
Change-type: patch
2023-01-18 13:11:31 +00:00
balenaCI
8714830b48
v15.0.2 2023-01-14 07:35:13 +00:00
Balena CI
0e07b36691
Merge pull request #2580 from balena-io/joshbwlng/fix-typo
Fix push --nolive doc typo
2023-01-14 09:33:56 +02:00
Josh Bowling
ba80d3c38c Fix push --nolive doc typo
Change-type: patch
2023-01-13 13:36:44 +09:00
balenaCI
e65dc82cfe
v15.0.1 2023-01-10 13:43:24 +00:00
Felipe Lalanne
bc727521c6
Merge pull request #2571 from balena-io/nodejs-14
Update to Node 14
2023-01-10 08:41:54 -05:00
Felipe Lalanne
a8c0c884d3 Extra linting 2023-01-03 16:08:10 -03:00
Felipe Lalanne
b11c7157d3 Update to node 14 2023-01-03 16:04:24 -03:00
Felipe Lalanne
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
balenaCI
cfc6b3ce9e
v15.0.0 2023-01-02 15:21:59 +00:00
Balena CI
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
JOASSART Edwin
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
balenaCI
0ab4760272
v14.5.18 2022-12-29 07:20:50 +00:00
Balena CI
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
Thodoris Greasidis
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
balenaCI
3328f40416
v14.5.17 2022-12-28 23:56:12 +00:00
Thodoris Greasidis
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
Thodoris Greasidis
2fd0ca6a02 Stop using the deprecated balena-sync module
Change-type: patch
2022-12-29 01:05:51 +02:00
balenaCI
173028fd0d
v14.5.16 2022-12-28 23:01:25 +00:00
Thodoris Greasidis
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
Thodoris Greasidis
63a0d19770 Update the npm-shrinkwrap.json dependencies to match the package.json
Change-type: patch
2022-12-28 21:22:48 +02:00
balenaCI
8244636bf2
v14.5.15 2022-12-12 13:41:15 +00:00
Balena CI
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
Edwin Joassart
ca637b3fb6
patch: update balena-preload to 12.2.0 2022-12-12 13:16:22 +01:00
balenaCI
006293bd01
v14.5.14 2022-12-11 21:46:38 +00:00
Balena CI
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
pipex
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
balenaCI
662b8283a6
v14.5.13 2022-12-08 14:00:28 +00:00
Page-
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
Page-
e566badfff
Build on macos-11 for library compatibility reasons
Change-type: patch
2022-12-08 10:58:40 +00:00
Page-
69834c417e
Build on ubuntu-20.04 for library compatibility reasons
Change-type: patch
2022-12-08 10:58:25 +00:00
balenaCI
8aa9c62afd
v14.5.12 2022-11-21 18:46:49 +00:00
bulldozer-balena[bot]
4f29e37fe7
Merge pull request #2565 from balena-io/ab77/operational
Move GH publishing to FZ core
2022-11-21 18:45:25 +00:00
ab77
99e8a36bb5
Move GH publishing to FZ core
Change-type: patch
2022-11-21 09:48:09 -08:00
balenaCI
669cbe227f
v14.5.11 2022-11-17 18:32:48 +00:00
bulldozer-balena[bot]
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
zoobot
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
balenaCI
d3018f9061
v14.5.10 2022-11-11 11:24:21 +00:00
bulldozer-balena[bot]
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
Thodoris Greasidis
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
balenaCI
3bb0036ba8
v14.5.9 2022-11-11 00:49:26 +00:00
bulldozer-balena[bot]
ac9e2a9e7e
Merge pull request #2562 from balena-io/ab77/operational
Prevent git from existing with 141
2022-11-11 00:47:34 +00:00
ab77
52e95e6d0a
Prevent git from existing with 141
Change-type: patch
2022-11-10 15:52:13 -08:00
balenaCI
c5d2aa7eec
v14.5.8 2022-11-10 23:32:21 +00:00
bulldozer-balena[bot]
683220e303
Merge pull request #2561 from balena-io/ab77/operational
Replace missing input
2022-11-10 23:30:51 +00:00
ab77
44f09b32fa
Replace missing input
Change-type: patch
2022-11-10 14:33:13 -08:00
302 changed files with 45728 additions and 27377 deletions

4
.gitattributes vendored
View File

@ -4,6 +4,10 @@
*.* -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
docs/balena-cli.md text eol=lf

View File

@ -1,38 +0,0 @@
---
name: cleanup
# 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
# --- custom environment
VERBOSE:
type: string
default: "true"
runs:
# https://docs.github.com/en/actions/creating-actions/creating-a-composite-action
using: "composite"
steps:
# delete draft releases if the pull request is closed without merging
- name: Delete draft release
if: |
runner.os == 'Linux' &&
github.event_name == 'pull_request' &&
github.event.pull_request.merged == false &&
github.event.action == 'closed'
shell: bash
run: |
set -ea
[[ '${{ inputs.VERBOSE }}' =~ on|On|Yes|yes|true|True ]] && set -x
gh release delete --yes '${{ github.event.pull_request.head.ref }}' || true
env:
GITHUB_TOKEN: ${{ fromJSON(inputs.secrets).FLOWZONE_TOKEN }}

View File

@ -1,58 +0,0 @@
---
name: publish 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
runs:
# https://docs.github.com/en/actions/creating-actions/creating-a-composite-action
using: "composite"
steps:
- name: Get release version
if: runner.os == 'Linux'
id: get_release
shell: bash
run: |
set -ea
[[ '${{ inputs.VERBOSE }}' =~ on|On|Yes|yes|true|True ]] && set -x
echo "version=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT
# https://docs.github.com/en/rest/releases
- name: Finalize GitHub release
if: runner.os == 'Linux'
# FIXME: Process completed with exit code 141.
# https://stackoverflow.com/questions/54999974
# https://stackoverflow.com/questions/22464786
continue-on-error: true
shell: bash
run: |
set -a
[[ '${{ inputs.VERBOSE }}' =~ on|On|Yes|yes|true|True ]] && set -x
previous_tag="$(git tag --sort=-version:refname | head -n 2 | tail -n 1)"
release_notes="$(git log ${previous_tag}..HEAD --pretty=reference)"
gh release edit '${{ github.event.pull_request.head.ref }}' \
--notes "${release_notes}" \
--title 'v${{ steps.get_release.outputs.version }}' \
--tag 'v${{ steps.get_release.outputs.version }}' \
--prerelease=false \
--draft=false
release_id="$(gh api "/repos/${{ github.repository }}/releases/tags/v${{ steps.get_release.outputs.version }}" \
-H 'Accept: application/vnd.github+json' | jq -r .id)"
gh api --method PATCH "/repos/${{ github.repository }}/releases/${release_id}" \
-H 'Accept: application/vnd.github+json' \
-F make_latest="true"
env:
GITHUB_TOKEN: ${{ fromJSON(inputs.secrets).FLOWZONE_TOKEN }}

View File

@ -3,32 +3,34 @@ 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"
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"
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"
default: 'accounts+apple@balena.io'
NODE_VERSION:
type: string
# FIXME: (please) https://github.com/balena-io/balena-cli/issues/2165
default: "12.x"
default: '20.x'
VERBOSE:
type: string
default: "true"
default: 'true'
runs:
# https://docs.github.com/en/actions/creating-actions/creating-a-composite-action
using: "composite"
using: 'composite'
steps:
- name: Download custom source artifact
uses: actions/download-artifact@v3
uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # v4.1.9
with:
name: custom-${{ github.event.pull_request.head.sha || github.event.head_commit.id }}-${{ runner.os }}
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
@ -37,11 +39,17 @@ runs:
run: tar -xf ${{ runner.temp }}/custom.tgz
- name: Setup Node.js
uses: actions/setup-node@v3
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
@ -58,7 +66,7 @@ runs:
# https://github.com/Apple-Actions/import-codesign-certs
- name: Import Apple code signing certificate
if: runner.os == 'macOS'
uses: apple-actions/import-codesign-certs@v1
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 }}
@ -67,23 +75,15 @@ runs:
if: runner.os == 'Windows'
shell: powershell
run: |
Set-Content -Path ${{ runner.temp }}/certificate.base64 -Value $env:WINDOWS_CERTIFICATE
certutil -decode ${{ runner.temp }}/certificate.base64 ${{ runner.temp }}/certificate.pfx
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
Import-PfxCertificate `
-FilePath ${{ runner.temp }}/certificate.pfx `
-CertStoreLocation Cert:\CurrentUser\My `
-Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
env:
WINDOWS_CERTIFICATE: ${{ fromJSON(inputs.secrets).WINDOWS_SIGNING }}
WINDOWS_CERTIFICATE_PASSWORD: ${{ fromJSON(inputs.secrets).WINDOWS_SIGNING_PASSWORD }}
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
id: package_release
shell: bash
run: |
set -ea
@ -94,17 +94,26 @@ runs:
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_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
CSC_KEY_PASSWORD=${{ fromJSON(inputs.secrets).WINDOWS_SIGNING_PASSWORD }}
CSC_LINK='${{ runner.temp }}\certificate.pfx'
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 }}
# patches/all/oclif.patch
MSYSSHELLPATH="$(which bash)"
MSYSTEM=MSYS
curl --silent --retry 3 --fail https://one.digicert.com/signingmanager/api-ui/v1/releases/smtools-windows-x64.msi/download \
-H "x-api-key:$SM_API_KEY" \
-o smtools-windows-x64.msi
msiexec -i smtools-windows-x64.msi -qn
PATH="/c/Program Files/DigiCert/DigiCert One Signing Manager Tools:${PATH}"
smksp_registrar.exe list
smctl.exe keypair ls
/c/Windows/System32/certutil.exe -csp "DigiCert Signing Manager KSP" -key -user
smksp_cert_sync.exe
# (signtool.exe) https://github.com/actions/runner-images/blob/main/images/win/Windows2019-Readme.md#installed-windows-sdks
PATH="/c/Program Files (x86)/Windows Kits/10/bin/${runner_arch}:${PATH}"
@ -114,40 +123,21 @@ runs:
find dist -type f -maxdepth 1
echo "version=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT
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://sectigo.com/resource-library/time-stamping-server
TIMESTAMP_SERVER: http://timestamp.sectigo.com
# 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 }}
# https://github.com/softprops/action-gh-release#-customizing
- name: Create draft GitHub (pre)release
uses: softprops/action-gh-release@v1
- name: Upload artifacts
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
# use PR branch name for draft releases
name: ${{ github.event.pull_request.head.ref }}
tag_name: ${{ github.event.pull_request.head.ref }}
draft: true
prerelease: true
token: ${{ fromJSON(inputs.secrets).FLOWZONE_TOKEN }}
files: |
dist/*.pkg
dist/*.exe
dist/*.zip
- name: Compress custom source
shell: pwsh
run: tar -acf ${{ runner.temp }}/custom.tgz .
- name: Upload custom artifact
uses: actions/upload-artifact@v3
with:
name: custom-${{ github.event.pull_request.head.sha || github.event.head_commit.id }}-${{ runner.os }}
path: ${{ runner.temp }}/custom.tgz
name: gh-release-${{ github.event.pull_request.head.sha || github.event.head_commit.id }}-${{ strategy.job-index }}
path: dist
retention-days: 1
if-no-files-found: error

View File

@ -8,12 +8,14 @@ inputs:
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
# FIXME: (please) https://github.com/balena-io/balena-cli/issues/2165
default: "12.x"
default: '20.x'
VERBOSE:
type: string
default: "true"
@ -22,26 +24,19 @@ runs:
# https://docs.github.com/en/actions/creating-actions/creating-a-composite-action
using: "composite"
steps:
- name: Delete previous draft release
if: runner.os == 'Linux'
shell: bash
run: |
set -ea
[[ '${{ inputs.VERBOSE }}' =~ on|On|Yes|yes|true|True ]] && set -x
gh release delete --yes '${{ github.event.pull_request.head.ref }}' || true
env:
GITHUB_TOKEN: ${{ fromJSON(inputs.secrets).FLOWZONE_TOKEN }}
# https://github.com/actions/setup-node#caching-global-packages-data
- name: Setup Node.js
uses: actions/setup-node@v3
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: |
@ -49,22 +44,22 @@ runs:
[[ '${{ inputs.VERBOSE }}' =~ on|On|Yes|yes|true|True ]] && set -x
if [[ -e package-lock.json ]]; then
if [[ -e package-lock.json ]] || [[ -e npm-shrinkwrap.json ]]; then
npm ci
else
npm i
fi
npm run build
npm run test
npm run test:core
- name: Compress custom source
shell: pwsh
run: tar -acf ${{ runner.temp }}/custom.tgz .
run: tar --exclude-vcs -acf ${{ runner.temp }}/custom.tgz .
- name: Upload custom artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: custom-${{ github.event.pull_request.head.sha || github.event.head_commit.id }}-${{ runner.os }}
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"]
}

View File

@ -1,16 +1,45 @@
name: Flowzone
on:
pull_request:
types: [opened, synchronize, closed]
branches:
- "main"
- "master"
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:
tests_run_on: '["ubuntu-latest","macos-latest","windows-2019"]'
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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -115,14 +115,27 @@ 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
`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
@ -210,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:

View File

@ -40,7 +40,7 @@ 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
@ -78,8 +78,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 12 (min 12.8.0).**
> **Versions 13 and later are not yet fully supported.**
> **The balena CLI currently requires Node.js version ^20.6.0**
> **Versions 21 and later are not yet fully supported.**
### Install development tools
@ -89,7 +89,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 20
```
The `curl` command line above uses
@ -106,15 +106,15 @@ recommended.
```sh
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash
$ . ~/.bashrc
$ nvm install 12
$ nvm install 20
```
#### **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 v20 from the [Nodejs.org releases page](https://nodejs.org/en/download/releases/).
[nvm-windows](https://github.com/coreybutler/nvm-windows#node-version-manager-nvm-for-windows)
instead.
* The [MSYS2 shell](https://www.msys2.org/), which provides `git`, `make`, `g++` and more:
@ -145,7 +145,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

@ -33,7 +33,7 @@ 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

@ -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

@ -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

View File

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

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`

View File

@ -15,21 +15,20 @@
* limitations under the License.
*/
import type { JsonVersions } from '../lib/commands/version';
import type { JsonVersions } from '../src/commands/version/index';
import { run as oclifRun } from 'oclif';
import { run as oclifRun } from '@oclif/core';
import * as archiver from 'archiver';
import * as Bluebird from 'bluebird';
import { execFile } from 'child_process';
import { exec, execFile } from 'child_process';
import * as filehound from 'filehound';
import { Stats } from 'fs';
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 {
@ -41,6 +40,8 @@ import {
} from './utils';
const execFileAsync = promisify(execFile);
const execAsync = promisify(exec);
const rimrafAsync = promisify(rimraf);
export const packageJSON = loadPackageJson();
export const version = 'v' + packageJSON.version;
@ -60,9 +61,13 @@ const standaloneZips: PathByPlatform = {
win32: dPath(`balena-cli-${version}-windows-${arch}-standalone.zip`),
};
const oclifInstallers: PathByPlatform = {
darwin: dPath('macos', `balena-${version}.pkg`),
win32: dPath('win32', `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 = {
@ -87,7 +92,7 @@ async function diffPkgOutput(pkgOut: string) {
'tests',
'test-data',
'pkg',
`expected-warnings-${process.platform}.txt`,
`expected-warnings-${process.platform}-${arch}.txt`,
);
const absSavedPath = path.join(ROOT, relSavedPath);
const ignoreStartsWith = [
@ -155,7 +160,7 @@ ${sep}
* messages (stdout and stderr) in order to call diffPkgOutput().
*/
async function execPkg(...args: any[]) {
const { exec: pkgExec } = await import('pkg');
const { exec: pkgExec } = await import('@yao-pkg/pkg');
const outTap = new StdOutTap(true);
try {
outTap.tap();
@ -180,9 +185,18 @@ async function execPkg(...args: any[]) {
* to be directly executed from inside another binary executable.)
*/
async function buildPkg() {
// https://github.com/vercel/pkg#targets
let targets = `linux-${arch}`;
if (process.platform === 'darwin') {
targets = `macos-${arch}`;
}
// TBC: not yet possible to build for Windows arm64 on x64 nodes
if (process.platform === 'win32') {
targets = `win-x64`;
}
const args = [
'--target',
'host',
'--targets',
targets,
'--output',
'build-bin/balena',
'package.json',
@ -197,7 +211,6 @@ async function buildPkg() {
const paths: Array<[string, string[], string[]]> = [
// [platform, [source path], [destination path]]
['*', ['open', 'xdg-open'], ['xdg-open']],
['*', ['opn', 'xdg-open'], ['xdg-open-402']],
['darwin', ['denymount', 'bin', 'denymount'], ['denymount']],
];
await Promise.all(
@ -292,7 +305,7 @@ async function zipPkg() {
);
}
await fs.mkdirp(path.dirname(outputFile));
await new Promise((resolve, reject) => {
await new Promise<void>((resolve, reject) => {
console.log(`Zipping standalone package to "${outputFile}"...`);
const archive = archiver('zip', {
@ -313,7 +326,11 @@ async function zipPkg() {
});
}
async function signFilesForNotarization() {
export async function signFilesForNotarization() {
console.log('Signing files for notarization');
if (process.platform !== 'darwin') {
return;
}
console.log('Deleting unneeded zip files...');
await new Promise((resolve, reject) => {
klaw('node_modules/')
@ -413,6 +430,7 @@ export async function buildStandaloneZip() {
}
async function renameInstallerFiles() {
const oclifInstallers = await getOclifInstallersOriginalNames();
if (await fs.pathExists(oclifInstallers[process.platform])) {
await fs.rename(
oclifInstallers[process.platform],
@ -427,18 +445,20 @@ async function renameInstallerFiles() {
* https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe
*/
async function signWindowsInstaller() {
if (process.env.CSC_LINK && process.env.CSC_KEY_PASSWORD) {
if (process.env.SM_CODE_SIGNING_CERT_SHA1_HASH) {
const exeName = renamedOclifInstallers[process.platform];
console.log(`Signing installer "${exeName}"`);
// trust ...
await execFileAsync('signtool.exe', [
'sign',
'-t',
'-sha1',
process.env.SM_CODE_SIGNING_CERT_SHA1_HASH,
'-tr',
process.env.TIMESTAMP_SERVER || 'http://timestamp.comodoca.com',
'-f',
process.env.CSC_LINK,
'-p',
process.env.CSC_KEY_PASSWORD,
'-td',
'SHA256',
'-fd',
'SHA256',
'-d',
`balena-cli ${version}`,
exeName,
@ -456,16 +476,15 @@ async function signWindowsInstaller() {
* Wait for Apple Installer Notarization to continue
*/
async function notarizeMacInstaller(): Promise<void> {
const teamId = process.env.XCODE_APP_LOADER_TEAM_ID || '66H43P8FRG';
const appleId =
process.env.XCODE_APP_LOADER_EMAIL || 'accounts+apple@balena.io';
const appBundleId = packageJSON.oclif.macos.identifier || 'io.balena.cli';
const appleIdPassword = process.env.XCODE_APP_LOADER_PASSWORD;
if (appleIdPassword) {
const { notarize } = await import('electron-notarize');
// https://github.com/electron/notarize/blob/main/README.md
if (appleIdPassword && teamId) {
await notarize({
appBundleId,
tool: 'notarytool',
teamId,
appPath: renamedOclifInstallers.darwin,
appleId,
appleIdPassword,
@ -484,9 +503,10 @@ export async function buildOclifInstaller() {
let packOpts = ['-r', ROOT];
if (process.platform === 'darwin') {
packOS = 'macos';
packOpts = packOpts.concat('--targets', `darwin-${arch}`);
} else if (process.platform === 'win32') {
packOS = 'win';
packOpts = packOpts.concat('-t', 'win32-x64');
packOpts = packOpts.concat('--targets', 'win32-x64');
}
if (packOS) {
console.log(`Building oclif installer for CLI ${version}`);
@ -497,17 +517,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 "${packCmd}" "${packOpts.join('" "')}"`);
console.log(`oclif ${packCmd} ${packOpts.join(' ')}`);
console.log(`cwd="${process.cwd()}" ROOT="${ROOT}"`);
console.log('=======================================================');
await oclifRun([packCmd].concat(...packOpts));
const oclifPath = path.join(ROOT, 'node_modules', 'oclif');
await oclifRun([packCmd].concat(...packOpts), oclifPath);
await renameInstallerFiles();
// The Windows installer is explicitly signed here (oclif doesn't do it).
// The macOS installer is automatically signed by oclif (which runs the

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,173 +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/fleets.js',
'build/commands/fleet/index.js',
'build/commands/fleet/create.js',
'build/commands/fleet/purge.js',
'build/commands/fleet/rename.js',
'build/commands/fleet/restart.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: 'Releases',
files: [
'build/commands/releases.js',
'build/commands/release/index.js',
'build/commands/release/finalize.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.
@ -206,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,5 +78,5 @@ async function printMarkdown() {
}
}
// tslint:disable-next-line:no-floating-promises
// 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,7 +15,7 @@
* limitations under the License.
*/
// tslint:disable-next-line:import-blacklist
// eslint-disable-next-line no-restricted-imports
import { stripIndent } from 'common-tags';
import * as _ from 'lodash';
import { promises as fs } from 'fs';
@ -43,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)));
@ -82,5 +82,5 @@ async function run() {
}
}
// tslint:disable-next-line:no-floating-promises
// eslint-disable-next-line @typescript-eslint/no-floating-promises
run();

View File

@ -23,8 +23,8 @@ function parseSemver(version) {
* @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

@ -21,12 +21,9 @@ import {
buildOclifInstaller,
buildStandaloneZip,
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(
@ -40,7 +37,6 @@ process.env.DEBUG = ['0', 'no', 'false', '', undefined].includes(
* 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)
*
* @param args Arguments to parse (default is process.argv.slice(2))
*/
@ -54,32 +50,16 @@ async function parse(args?: string[]) {
const commands: { [cmd: string]: () => void | Promise<void> } = {
'build:installer': buildOclifInstaller,
'build:standalone': buildStandaloneZip,
'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,5 +83,5 @@ export async function run(args?: string[]) {
}
}
// tslint:disable-next-line:no-floating-promises
// 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':
@ -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,5 +136,4 @@ async function main() {
}
}
// tslint:disable-next-line:no-floating-promises
main();
void main();

View File

@ -16,8 +16,10 @@
*/
import { spawn } from 'child_process';
import * as _ from 'lodash';
import * as path from 'path';
import * as fs from 'fs';
import { diffTrimmedLines } from 'diff';
import * as whichMod from 'which';
export const ROOT = path.join(__dirname, '..');
@ -65,7 +67,6 @@ export class StdOutTap {
* 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
@ -77,15 +78,18 @@ export function diffLines(str1: string, str2: string): string {
return part.added
? prefix(part.value, '+')
: part.removed
? prefix(part.value, '-')
: prefix(part.value, ' ');
? 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 +102,6 @@ export function loadPackageJson() {
* @returns The program's full path, e.g. 'C:\WINDOWS\System32\OpenSSH\ssh.EXE'
*/
export async function which(program: string): Promise<string> {
const whichMod = await import('which');
let programPath: string;
try {
programPath = await whichMod(program);
@ -129,7 +132,7 @@ export async function whichSpawn(
.on('error', reject)
.on('close', resolve);
} catch (err) {
reject(err);
reject(err as Error);
}
});
} catch (err) {

View File

@ -1,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=( build deploy envs fleets join keys leave login logout logs note orgs preload push releases scan settings ssh support tags tunnel version whoami api-key config device device devices env fleet fleet internal key key local os release release 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 )
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 pin public-url purge reboot register rename restart rm shutdown track-fleet )
devices_cmds=( supported )
env_cmds=( add rename rm )
fleet_cmds=( create pin purge rename restart rm track-latest )
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 )
release_cmds=( finalize invalidate validate )
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
@ -43,15 +46,21 @@ _balena_sec_cmds() {
"api-key")
_describe -t api_key_cmds 'api-key_cmd' api_key_cmds "$@" && ret=0
;;
"app")
_describe -t app_cmds 'app_cmd' app_cmds "$@" && ret=0
;;
"block")
_describe -t block_cmds 'block_cmd' block_cmds "$@" && ret=0
;;
"config")
_describe -t config_cmds 'config_cmd' config_cmds "$@" && ret=0
;;
"device-type")
_describe -t device_type_cmds 'device-type_cmd' device_type_cmds "$@" && ret=0
;;
"device")
_describe -t device_cmds 'device_cmd' device_cmds "$@" && ret=0
;;
"devices")
_describe -t devices_cmds 'devices_cmd' devices_cmds "$@" && ret=0
;;
"env")
_describe -t env_cmds 'env_cmd' env_cmds "$@" && ret=0
;;
@ -61,18 +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="build deploy envs fleets join keys leave login logout logs note orgs preload push releases scan settings ssh support tags tunnel version whoami api-key config device device devices env fleet fleet internal key key local os release release 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"
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 pin public-url purge reboot register rename restart rm shutdown track-fleet"
devices_cmds="supported"
env_cmds="add rename rm"
fleet_cmds="create pin purge rename restart rm track-latest"
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"
release_cmds="finalize invalidate validate"
tag_cmds="rm set"
release_cmds="finalize invalidate list validate"
ssh_key_cmds="add list rm"
tag_cmds="list rm set"
@ -37,15 +40,21 @@ _balena_complete()
api-key)
COMPREPLY=( $(compgen -W "$api_key_cmds" -- $cur) )
;;
app)
COMPREPLY=( $(compgen -W "$app_cmds" -- $cur) )
;;
block)
COMPREPLY=( $(compgen -W "$block_cmds" -- $cur) )
;;
config)
COMPREPLY=( $(compgen -W "$config_cmds" -- $cur) )
;;
device-type)
COMPREPLY=( $(compgen -W "$device_type_cmds" -- $cur) )
;;
device)
COMPREPLY=( $(compgen -W "$device_cmds" -- $cur) )
;;
devices)
COMPREPLY=( $(compgen -W "$devices_cmds" -- $cur) )
;;
env)
COMPREPLY=( $(compgen -W "$env_cmds" -- $cur) )
;;
@ -55,18 +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

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,174 +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,
NotAvailableInOfflineModeError,
} from './errors';
import { stripIndent } from './utils/lazy';
import * as output from './framework/output';
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;
/**
* Require an internet connection to run.
* When set to true, command will exit with an error
* if user is running in offline mode (BALENARC_OFFLINE_MODE).
*/
public static offlineCompatible = 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();
}
}
/**
* Throw NotAvailableInOfflineModeError if in offline mode.
*
* Called automatically if `onlineOnly=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 {NotAvailableInOfflineModeError}
*/
public static checkNotUsingOfflineMode() {
if (process.env.BALENARC_OFFLINE_MODE) {
throw new NotAvailableInOfflineModeError(stripIndent`
This command requires an internet connection, and cannot be used in offline mode.
To leave offline mode, unset the BALENARC_OFFLINE_MODE environment variable.
`);
}
}
/**
* 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.offlineCompatible) {
BalenaCommand.checkNotUsingOfflineMode();
}
if (ctr.readStdin) {
await this.getStdin();
}
}
protected outputMessage = output.outputMessage;
protected outputData = output.outputData;
}

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,149 +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 { 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';
interface FlagsDef {
organization?: string;
type?: string; // application device type
help: void;
}
interface ArgsDef {
name: string;
}
export default 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() {
const { args: params, flags: options } = 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
console.log(
`Fleet created: slug "${application.slug}", device type "${deviceType}"`,
);
}
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);
}
}
}

View File

@ -1,94 +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 Command from '../command';
import * as cf from '../utils/common-flags';
import { getBalenaSdk, stripIndent } from '../utils/lazy';
import type { DataSetOutputOptions } from '../framework';
interface ExtendedApplication extends ApplicationWithDeviceType {
device_count: number;
online_devices: number;
device_type?: string;
}
interface FlagsDef extends DataSetOutputOptions {
help: void;
verbose?: boolean;
}
export default 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> = {
...cf.dataSetOutputFlags,
help: cf.help,
};
public static authenticated = true;
public static primary = true;
public async run() {
const { flags: options } = this.parse<FlagsDef, {}>(FleetsCmd);
const balena = getBalenaSdk();
// Get applications
const applications =
(await balena.models.application.getAllDirectlyAccessible({
$select: ['id', 'app_name', 'slug'],
$expand: {
is_for__device_type: { $select: 'slug' },
owns__device: { $select: 'is_online' },
},
})) as ExtendedApplication[];
// Add extended properties
applications.forEach((application) => {
application.device_count = application.owns__device?.length ?? 0;
application.online_devices =
application.owns__device?.filter((d) => d.is_online).length || 0;
application.device_type = application.is_for__device_type[0].slug;
});
await this.outputData(
applications,
[
'id',
'app_name',
'slug',
'device_type',
'device_count',
'online_devices',
],
options,
);
}
}

View File

@ -1,87 +0,0 @@
/**
* @license
* Copyright 2016-2020 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { flags } from '@oclif/command';
import Command from '../command';
import * as cf from '../utils/common-flags';
import { getBalenaSdk, getVisuals, stripIndent } from '../utils/lazy';
import { applicationNameNote } from '../utils/messages';
import type * as BalenaSdk from 'balena-sdk';
interface FlagsDef {
help: void;
}
interface ArgsDef {
fleet: string;
}
export default class ReleasesCmd extends Command {
public static description = stripIndent`
List all releases of a fleet.
List all releases of the given fleet.
${applicationNameNote.split('\n').join('\n\t\t')}
`;
public static examples = ['$ balena releases myorg/myfleet'];
public static usage = 'releases <fleet>';
public static flags: flags.Input<FlagsDef> = {
help: cf.help,
};
public static args = [
{
name: 'fleet',
description: 'fleet name or slug (preferred)',
required: true,
},
];
public static authenticated = true;
public async run() {
const { args: params } = this.parse<FlagsDef, ArgsDef>(ReleasesCmd);
const fields: Array<keyof BalenaSdk.Release> = [
'id',
'commit',
'created_at',
'status',
'semver',
'is_final',
];
const balena = getBalenaSdk();
const { getFleetSlug } = await import('../utils/sdk');
const releases = await balena.models.release.getAllByApplication(
await getFleetSlug(balena, params.fleet),
{ $select: fields },
);
const _ = await import('lodash');
console.log(
getVisuals().table.horizontal(
releases.map((rel) => _.mapValues(rel, (val) => val ?? 'N/a')),
fields,
),
);
}
}

View File

@ -1,19 +0,0 @@
/*
Copyright 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 { DataOutputOptions, DataSetOutputOptions } from './output';
export { DataOutputOptions, DataSetOutputOptions };

View File

@ -1,158 +0,0 @@
/*
Copyright 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 { getCliUx, getChalk } from '../utils/lazy';
export interface DataOutputOptions {
fields?: string;
json?: boolean;
}
export interface DataSetOutputOptions extends DataOutputOptions {
filter?: string;
'no-header'?: boolean;
'no-truncate'?: boolean;
sort?: string;
}
/**
* Output message to STDERR
*/
export function outputMessage(msg: string) {
// Messages go to STDERR
console.error(msg);
}
/**
* Output result data to STDOUT
* Supports:
* - arrays of items (displayed in a tabular way),
* - single items (displayed in a field per row format).
*
* @param data Array of data objects to output
* @param fields Array of fieldnames, specifying the fields and display order
* @param options Output options
*/
export async function outputData(
data: any[] | {},
fields: string[],
options: DataOutputOptions | DataSetOutputOptions,
) {
if (Array.isArray(data)) {
await outputDataSet(data, fields, options as DataSetOutputOptions);
} else {
await outputDataItem(data, fields, options as DataOutputOptions);
}
}
/**
* Wraps the cli.ux table implementation, to output tabular data
*
* @param data Array of data objects to output
* @param fields Array of fieldnames, specifying the fields and display order
* @param options Output options
*/
async function outputDataSet(
data: any[],
fields: string[],
options: DataSetOutputOptions,
) {
// Oclif expects fields to be specified in the format used in table headers (though lowercase)
// By replacing underscores with spaces here, we can support both header format and actual field name
// (e.g. as seen in json output).
options.fields = options.fields?.replace(/_/g, ' ');
options.filter = options.filter?.replace(/_/g, ' ');
options.sort = options.sort?.replace(/_/g, ' ');
getCliUx().table(
data,
// Convert fields array to column object keys
// that cli.ux expects. We can later add support
// for both formats if beneficial
fields.reduce((ac, a) => ({ ...ac, [a]: {} }), {}),
{
...options,
...(options.json
? {
output: 'json',
}
: {}),
columns: options.fields,
printLine,
},
);
}
/**
* Outputs a single data object (like `resin-cli-visuals table.vertical`),
* but supporting a subset of options from `cli-ux table` (--json and --fields)
*
* @param data Array of data objects to output
* @param fields Array of fieldnames, specifying the fields and display order
* @param options Output options
*/
async function outputDataItem(
data: any,
fields: string[],
options: DataOutputOptions,
) {
const outData: typeof data = {};
// Convert comma separated list of fields in `options.fields` to array of correct format.
// Note, user may have specified the true field name (e.g. `some_field`),
// or the format displayed in headers (e.g. `Some field`, case insensitive).
const userSelectedFields = options.fields?.split(',').map((f) => {
return f.toLowerCase().trim().replace(/ /g, '_');
});
// Order and filter the fields based on `fields` parameter and `options.fields`
(userSelectedFields || fields).forEach((fieldName) => {
if (fields.includes(fieldName)) {
outData[fieldName] = data[fieldName];
}
});
if (options.json) {
printLine(JSON.stringify(outData, undefined, 2));
} else {
const chalk = getChalk();
const { capitalize } = await import('lodash');
// Find longest key, so we can align results
const longestKeyLength = getLongestObjectKeyLength(outData);
// Output one field per line
for (const [k, v] of Object.entries(outData)) {
const shim = ' '.repeat(longestKeyLength - k.length);
const kDisplay = capitalize(k.replace(/_/g, ' '));
printLine(`${chalk.bold(kDisplay) + shim} : ${v}`);
}
}
}
function getLongestObjectKeyLength(o: any): number {
return Object.keys(o).length >= 1
? Object.keys(o).reduce((a, b) => {
return a.length > b.length ? a : b;
}).length
: 0;
}
function printLine(s: any) {
// Duplicating oclif cli-ux's default implementation here,
// but using this one explicitly for ease of testing
process.stdout.write(s + '\n');
}

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 (usage analytics).
* 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,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);
}

32258
npm-shrinkwrap.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "balena-cli",
"version": "14.5.7",
"version": "21.1.8",
"description": "The official balena Command Line Interface",
"main": "./build/app.js",
"homepage": "https://github.com/balena-io/balena-cli",
@ -14,33 +14,32 @@
"bin/",
"build/",
"doc/",
"lib/",
"src/",
"patches/",
"!patches/**/**.dev.patch",
"*.md",
"npm-shrinkwrap.json",
"oclif.manifest.json"
],
"bin": {
"balena": "./bin/balena"
"balena": "./bin/run.js"
},
"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/@balena/compose/dist/parse/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",
"node_modules/axios/**/*",
"npm-shrinkwrap.json",
"oclif.manifest.json"
]
@ -48,34 +47,37 @@
"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:pages": "mkdirp ./build/auth/pages/&& inline-source --compress ./lib/auth/pages/error.ejs ./build/auth/pages/error.ejs && inline-source --compress ./lib/auth/pages/success.ejs ./build/auth/pages/success.ejs",
"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",
"lint": "npm run lint-tsconfig && npm run lint-other",
"lint-tsconfig": "balena-lint -e ts -e js -t tsconfig.dev.json --fix automation/ lib/ tests/ typings/",
"lint-other": "balena-lint -e ts -e js --fix bin/balena bin/balena-dev completion/ .mocharc.js .mocharc-standalone.js",
"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": [
@ -90,150 +92,137 @@
"author": "Balena Inc. (https://balena.io/)",
"license": "Apache-2.0",
"engines": {
"node": ">=12 <16"
},
"husky": {
"hooks": {
"pre-commit": "node automation/check-npm-version.js && ts-node automation/check-doc.ts"
}
"node": "^20.6.0"
},
"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.2.0",
"@oclif/config": "^1.18.2",
"@oclif/parser": "^3.8.6",
"@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/archiver": "^6.0.2",
"@types/bluebird": "^3.5.36",
"@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.3.9",
"@types/diff": "^5.0.3",
"@types/dockerode": "3.3.23",
"@types/ejs": "^3.1.0",
"@types/express": "^4.17.13",
"@types/fs-extra": "^9.0.13",
"@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.8",
"@types/inquirer": "^7.3.3",
"@types/intercept-stdout": "^0.1.0",
"@types/is-root": "^2.1.2",
"@types/js-yaml": "^4.0.5",
"@types/jsonwebtoken": "^8.5.6",
"@types/klaw": "^3.0.3",
"@types/jsonwebtoken": "^9.0.6",
"@types/klaw": "^3.0.6",
"@types/lodash": "^4.14.178",
"@types/mixpanel": "^2.14.3",
"@types/mocha": "^8.2.3",
"@types/mime": "^3.0.4",
"@types/mocha": "^10.0.7",
"@types/mock-fs": "^4.13.4",
"@types/mock-require": "^2.0.1",
"@types/moment-duration-format": "^2.2.3",
"@types/ndjson": "^2.0.1",
"@types/net-keepalive": "^0.4.1",
"@types/nock": "^11.1.0",
"@types/node": "^12.20.42",
"@types/node": "^20.0.0",
"@types/node-cleanup": "^2.1.2",
"@types/parse-link-header": "^1.0.1",
"@types/prettyjson": "^0.0.30",
"@types/prettyjson": "^0.0.33",
"@types/progress-stream": "^2.0.2",
"@types/request": "^2.48.7",
"@types/rewire": "^2.5.28",
"@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.6",
"@types/sinon": "^17.0.3",
"@types/split": "^1.0.0",
"@types/stream-to-promise": "^2.2.1",
"@types/tar-stream": "^2.2.2",
"@types/through2": "^2.0.36",
"@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",
"@yao-pkg/pkg": "^5.11.1",
"archiver": "^7.0.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.5",
"fs-extra": "^9.1.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",
"mkdirp": "^1.0.4",
"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.2.1",
"parse-link-header": "^2.0.0",
"pkg": "^5.5.1",
"publish-release": "^1.6.1",
"rewire": "^5.0.0",
"oclif": "^4.17.0",
"rewire": "^7.0.0",
"simple-git": "^3.14.1",
"sinon": "^11.1.2",
"sinon": "^19.0.0",
"string-to-stream": "^3.0.1",
"ts-node": "^10.4.0",
"typescript": "^4.6.4"
"typescript": "^5.8.2"
},
"dependencies": {
"@balena/compose": "^2.1.1",
"@balena/compose": "^7.0.1",
"@balena/dockerignore": "^1.0.2",
"@balena/env-parsing": "^1.1.8",
"@balena/es-version": "^1.0.1",
"@oclif/command": "^1.8.16",
"@resin.io/valid-email": "^0.1.0",
"@oclif/core": "^4.1.0",
"@sentry/node": "^6.16.1",
"@types/fast-levenshtein": "0.0.1",
"@types/update-notifier": "^4.1.1",
"JSONStream": "^1.0.3",
"balena-config-json": "^4.2.0",
"balena-device-init": "^6.0.0",
"balena-errors": "^4.7.1",
"balena-image-fs": "^7.0.6",
"balena-image-manager": "^8.0.0",
"balena-preload": "^12.1.0",
"balena-sdk": "^16.28.0",
"balena-config-json": "^4.2.2",
"balena-device-init": "^8.1.3",
"balena-errors": "^4.7.3",
"balena-image-fs": "^7.5.0",
"balena-preload": "^18.0.1",
"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",
"balena-settings-client": "^5.0.2",
"balena-settings-storage": "^8.1.0",
"body-parser": "^1.19.1",
"chalk": "^3.0.0",
"bonjour-service": "^1.2.1",
"chalk": "^4.0.0",
"chokidar": "^3.5.2",
"cli-truncate": "^2.1.0",
"cli-ux": "^5.5.1",
"color-hash": "^1.1.1",
"columnify": "^1.5.2",
"common-tags": "^1.7.2",
"date-fns": "^4.1.0",
"denymount": "^2.3.0",
"docker-modem": "3.0.0",
"docker-modem": "^5.0.6",
"docker-progress": "^5.1.3",
"dockerode": "^3.3.1",
"dockerode": "^4.0.5",
"ejs": "^3.1.6",
"etcher-sdk": "^6.2.1",
"event-stream": "3.3.4",
"etcher-sdk": "9.1.0",
"express": "^4.17.2",
"fast-boot2": "^1.1.0",
"fast-levenshtein": "^3.0.0",
"filenamify": "^4.3.0",
"get-stdin": "^8.0.0",
"glob": "^7.2.0",
"global-agent": "^2.2.0",
"global-tunnel-ng": "^2.1.1",
@ -243,25 +232,23 @@
"is-elevated": "^3.0.0",
"is-root": "^2.1.0",
"js-yaml": "^4.1.0",
"klaw": "^3.0.0",
"JSONStream": "^1.0.3",
"jwt-decode": "^3.1.2",
"livepush": "^3.5.1",
"lodash": "^4.17.21",
"minimatch": "^3.0.4",
"moment": "^2.29.1",
"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.4",
"open": "^7.1.0",
"patch-package": "^6.4.7",
"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-cli-form": "^3.0.0",
"resin-cli-visuals": "^2.0.1",
"resin-doodles": "^0.2.0",
"resin-stream-logger": "^0.1.2",
"rimraf": "^3.0.2",
@ -283,7 +270,12 @@
"optionalDependencies": {
"windosu": "^0.3.0"
},
"overrides": {
"inline-source-cli": {
"inline-source": "^8.0.3"
}
},
"versionist": {
"publishedAt": "2022-11-10T22:19:21.757Z"
"publishedAt": "2025-04-03T16:10:03.330Z"
}
}

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,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 b3b9010..788e5c6 100644
--- a/node_modules/@oclif/plugin-help/lib/command.js
+++ b/node_modules/@oclif/plugin-help/lib/command.js
@@ -88,7 +88,7 @@ class CommandHelp {
return;
const body = list_1.renderList(args.map(a => {
var _a;
- const name = a.name.toUpperCase();
+ const name = a.required ? `<${a.name}>` : `[${a.name}]`;
let description = a.description || '';
// `a.default` is actually not always a string (typing bug), hence `toString()`
if (a.default || ((_a = a.default) === null || _a === void 0 ? void 0 : _a.toString()) === '0')
@@ -133,9 +133,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 || '';
// `flag.default` is not always a string (typing bug), hence `toString()`
diff --git a/node_modules/@oclif/plugin-help/lib/index.js b/node_modules/@oclif/plugin-help/lib/index.js
index 04d7861..c2fb591 100644
--- a/node_modules/@oclif/plugin-help/lib/index.js
+++ b/node_modules/@oclif/plugin-help/lib/index.js
@@ -98,11 +98,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

@ -1,278 +0,0 @@
diff --git a/node_modules/oclif/lib/commands/pack/macos.js b/node_modules/oclif/lib/commands/pack/macos.js
index 924f092..a69e60b 100644
--- a/node_modules/oclif/lib/commands/pack/macos.js
+++ b/node_modules/oclif/lib/commands/pack/macos.js
@@ -133,6 +133,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 pkgbuild "${args.join('" "')}"`);
await qq.x('pkgbuild', args);
}
}
diff --git a/node_modules/oclif/lib/commands/pack/win.js b/node_modules/oclif/lib/commands/pack/win.js
index bf4657e..fd58c7d 100644
--- a/node_modules/oclif/lib/commands/pack/win.js
+++ b/node_modules/oclif/lib/commands/pack/win.js
@@ -52,6 +52,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
@@ -61,6 +68,8 @@ Section "${config.name} CLI \${VERSION}"
WriteUninstaller "$INSTDIR\\Uninstall.exe"
WriteRegStr HKLM "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\${config.dirname}" \\
"DisplayName" "${config.name}"
+ WriteRegStr HKLM "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\${config.dirname}" \\
+ "DisplayVersion" "\${VERSION}"
WriteRegStr HKLM "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\${config.dirname}" \\
"UninstallString" "$\\"$INSTDIR\\uninstall.exe$\\""
WriteRegStr HKLM "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\${config.dirname}" \\
@@ -193,7 +202,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: $targets });
const { config, version, gitSha, targets, tmp } = buildConfig;
await Tarballs.build(buildConfig, { platform: 'win32', pack: false });
const arches = targets.filter(t => t.platform === 'win32').map(t => t.arch);
@@ -208,7 +218,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 templateKey = upload_util_1.templateShortKey('win32', { bin: config.bin, version: version, sha: gitSha, arch });
const o = buildConfig.dist(`win32/${templateKey}`);
// eslint-disable-next-line no-await-in-loop
@@ -255,4 +266,5 @@ PackWin.hidden = true;
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/lib/tarballs/build.js b/node_modules/oclif/lib/tarballs/build.js
index d3e8e89..a5d29e2 100644
--- a/node_modules/oclif/lib/tarballs/build.js
+++ b/node_modules/oclif/lib/tarballs/build.js
@@ -18,8 +18,9 @@ const pack = async (from, to) => {
qq.cd(prevCwd);
};
async function build(c, options = {}) {
- const { xz, config, version, s3Config, gitSha, nodeVersion, targets, updateConfig } = c;
+ const { xz, config, version, s3Config, gitSha, nodeVersion, targets, updateConfig, tmp } = c;
const prevCwd = qq.cwd();
+ console.error(`[debug] oclif 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 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 running "npm prune --production" in "${ws}"`);
+ await qq.x('npm prune --production');
+ console.error(`[debug] oclif done`);
};
const pretarball = async () => {
qq.cd(c.workspace());
@@ -99,7 +108,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/lib/tarballs/config.js b/node_modules/oclif/lib/tarballs/config.js
index 0dc3cd7..1336219 100644
--- a/node_modules/oclif/lib/tarballs/config.js
+++ b/node_modules/oclif/lib/tarballs/config.js
@@ -18,7 +18,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 tmp="${tmp}"`);
await qq.mkdirp(tmp);
return tmp;
}
@@ -43,7 +46,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('-'), upload_util_1.templateShortKey('baseDir', { bin: config.bin }));
return qq.join(base, upload_util_1.templateShortKey('baseDir', { bin: config.bin }));
diff --git a/node_modules/oclif/lib/tarballs/node.js b/node_modules/oclif/lib/tarballs/node.js
index fabe5c4..e32dd76 100644
--- a/node_modules/oclif/lib/tarballs/node.js
+++ b/node_modules/oclif/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/lib/upload-util.js b/node_modules/oclif/lib/upload-util.js
index 45392cb..3c806c7 100644
--- a/node_modules/oclif/lib/upload-util.js
+++ b/node_modules/oclif/lib/upload-util.js
@@ -28,10 +28,10 @@ function templateShortKey(type, ext, options = { root: '.' }) {
const templates = {
baseDir: '<%- bin %>',
unversioned: '<%- bin %>-<%- platform %>-<%- arch %><%- ext %>',
- versioned: '<%- bin %>-v<%- version %>-<%- sha %>-<%- platform %>-<%- arch %><%- ext %>',
- manifest: '<%- bin %>-v<%- version %>-<%- sha %>-<%- platform %>-<%- arch %>-buildmanifest',
- macos: '<%- bin %>-v<%- version %>-<%- sha %>.pkg',
- win32: '<%- bin %>-v<%- version %>-<%- sha %>-<%- arch %>.exe',
+ versioned: '<%- bin %>-v<%- version %>-<%- platform %>-<%- arch %><%- ext %>',
+ manifest: '<%- bin %>-v<%- version %>-<%- platform %>-<%- arch %>-buildmanifest',
+ macos: '<%- bin %>-v<%- version %>.pkg',
+ win32: '<%- bin %>-v<%- version %>-<%- arch %>.exe',
deb: '<%- bin %>_<%- versionShaRevision %>_<%- arch %>.deb',
};
return _.template(templates[type])(Object.assign({}, options));
diff --git a/node_modules/oclif/lib/util.js b/node_modules/oclif/lib/util.js
index 17748ad..4928fc9 100644
--- a/node_modules/oclif/lib/util.js
+++ b/node_modules/oclif/lib/util.js
@@ -67,3 +67,47 @@ exports.sortVersionsObjectByKeysDesc = (input) => {
}
return result;
};
+
+// 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 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 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 msysExec sh="${sh}" args=${JSON.stringify(args)} options=${JSON.stringify(options)}`);
+ return qq.x(sh, args, options);
+}
+exports.msysExec = msysExec;

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 +1,16 @@
diff --git a/node_modules/open/index.js b/node_modules/open/index.js
index 3bf5373..e042b64 100644
index 13147d0..ff161dd 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);
@@ -10,7 +10,10 @@ const pAccess = promisify(fs.access);
const pReadFile = promisify(fs.readFile);
// 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`
/**
Get the mount point for fixed drives in WSL.

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,8 +1,8 @@
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) {
diff --git a/node_modules/node-gyp-build/node-gyp-build.js b/node_modules/node-gyp-build/node-gyp-build.js
index 61b398e..3cc3be8 100644
--- a/node_modules/node-gyp-build/node-gyp-build.js
+++ b/node_modules/node-gyp-build/node-gyp-build.js
@@ -30,6 +30,9 @@ load.resolve = load.path = function (dir) {
if (process.env[name + '_PREBUILD']) dir = process.env[name + '_PREBUILD']
} catch (err) {}

View File

@ -6,15 +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: 'balena-compose'
- 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
@ -100,11 +101,9 @@ async function init() {
/** 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 || process.env.BALENARC_UNSUPPORTED) {
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
@ -114,10 +113,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.
@ -130,7 +135,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.
@ -145,13 +151,13 @@ 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 { setOfflineModeEnvVars, normalizeEnvVars, pkgExec } = await import(
'./utils/bootstrap'

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

View File

@ -0,0 +1,156 @@
/**
* @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 { Args, Command } from '@oclif/core';
import { ExpectedError } from '../../errors';
import { getBalenaSdk, getCliForm, stripIndent } from '../../utils/lazy';
import {
formatDuration,
intervalToDuration,
isValid,
parseISO,
} from 'date-fns';
// In days
const durations = [1, 7, 30, 90];
async function isLoggedInWithJwt() {
const balena = getBalenaSdk();
try {
const token = await balena.auth.getToken();
const { default: jwtDecode } = await import('jwt-decode');
jwtDecode(token);
return true;
} catch {
return false;
}
}
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"',
'$ balena api-key generate "Jenkins Key" 2025-10-30',
'$ balena api-key generate "Jenkins Key" never',
];
public static args = {
name: Args.string({
description: 'the API key name',
required: true,
}),
expiryDate: Args.string({
description:
'the expiry date of the API key as an ISO date string, or "never" for no expiry',
}),
};
public static authenticated = true;
public async run() {
const { args: params } = await this.parse(GenerateCmd);
let expiryDateResponse: string | number | undefined = params.expiryDate;
let key;
try {
if (!expiryDateResponse) {
expiryDateResponse = await getCliForm().ask({
message: 'Please pick an expiry date for the API key',
type: 'list',
choices: [...durations, 'custom', 'never'].map((duration) => ({
name:
duration === 'never'
? 'No expiration'
: typeof duration === 'number'
? formatDuration(
intervalToDuration({
start: 0,
end: duration * 24 * 60 * 60 * 1000,
}),
)
: 'Custom expiration',
value: duration,
})),
});
}
let expiryDate: Date | null;
if (expiryDateResponse === 'never') {
expiryDate = null;
} else if (expiryDateResponse === 'custom') {
do {
expiryDate = parseISO(
await getCliForm().ask({
message:
'Please enter an expiry date for the API key as an ISO date string',
type: 'input',
}),
);
if (!isValid(expiryDate)) {
console.error('Invalid date format');
}
} while (!isValid(expiryDate));
} else if (typeof expiryDateResponse === 'string') {
expiryDate = parseISO(expiryDateResponse);
if (!isValid(expiryDate)) {
throw new Error(
'Invalid date format, please use a valid ISO date string',
);
}
} else {
expiryDate = new Date(
Date.now() + expiryDateResponse * 24 * 60 * 60 * 1000,
);
}
key = await getBalenaSdk().models.apiKey.create({
name: params.name,
expiryDate: expiryDate === null ? null : expiryDate.toISOString(),
});
} catch (e) {
if (e.name === 'BalenaNotLoggedIn') {
if (await isLoggedInWithJwt()) {
throw new ExpectedError(stripIndent`
This command requires you to have been recently authenticated.
Please login again with 'balena login'.
In case you are using the Web authorization method, you need to logout and re-login to the dashboard first.
`);
}
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

@ -0,0 +1,82 @@
/**
* @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, Command } from '@oclif/core';
import * as cf from '../../utils/common-flags';
import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy';
export default class APIKeyListCmd extends Command {
public static aliases = ['api-keys'];
public static deprecateAliases = true;
public static description = stripIndent`
Print a list of balenaCloud API keys.
Print a list of balenaCloud API keys.
Print a list of balenaCloud API keys for the current user or for a specific fleet with the \`--fleet\` option.
`;
public static examples = ['$ balena api-key list'];
public static flags = {
user: Flags.boolean({
char: 'u',
description: 'show API keys for your user',
}),
fleet: cf.fleet,
};
public static authenticated = true;
public async run() {
const { flags: options } = await this.parse(APIKeyListCmd);
const { getApplication } = await import('../../utils/sdk');
const actorId = options.fleet
? (
await getApplication(getBalenaSdk(), options.fleet, {
$select: 'actor',
})
).actor.__id
: await getBalenaSdk().auth.getActorId();
const keys = await getBalenaSdk().pine.get({
resource: 'api_key',
options: {
$select: ['id', 'created_at', 'name', 'description', 'expiry_date'],
$filter: {
is_of__actor: actorId,
...(options.user
? {
name: {
$ne: null,
},
}
: {}),
},
$orderby: 'name asc',
},
});
const fields = ['id', 'name', 'created_at', 'description', 'expiry_date'];
const _ = await import('lodash');
console.log(
getVisuals().table.horizontal(
keys.map((key) => _.mapValues(key, (val) => val ?? 'N/a')),
fields,
),
);
}
}

View File

@ -0,0 +1,59 @@
/**
* @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 { Args, Command } from '@oclif/core';
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
export default class RevokeCmd extends Command {
public static description = stripIndent`
Revoke balenaCloud API keys.
Revoke balenaCloud API keys with the given
comma-separated list of ids.
The given balenaCloud API keys will no longer be usable.
`;
public static examples = [
'$ balena api-key revoke 123',
'$ balena api-key revoke 123,124,456',
];
public static args = {
ids: Args.string({
description: 'the API key ids',
required: true,
}),
};
public static authenticated = true;
public async run() {
const { args: params } = await this.parse(RevokeCmd);
const apiKeyIds = params.ids.split(',');
if (apiKeyIds.filter((apiKeyId) => !apiKeyId.match(/^\d+$/)).length > 0) {
console.log('API key ids must be positive integers');
return;
}
await Promise.all(
apiKeyIds.map(async (id) => {
await getBalenaSdk().models.apiKey.revoke(Number(id));
}),
);
console.log('Successfully revoked the given API keys');
}
}

View File

@ -0,0 +1,77 @@
/**
* @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, Args, Command } from '@oclif/core';
import { stripIndent } from '../../utils/lazy';
export default class AppCreateCmd extends Command {
public static description = stripIndent`
Create an app.
Create a new balena app.
You can specify the organization the app 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 organization list\` command.
The app's default device type is specified with the \`--type\` option.
The \`balena device-type list\` 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 app create MyApp',
'$ balena app create MyApp --organization mmyorg',
'$ balena app create MyApp -o myorg --type raspberry-pi',
];
public static args = {
name: Args.string({
description: 'app name',
required: true,
}),
};
public static flags = {
organization: Flags.string({
char: 'o',
description: 'handle of the organization the app should belong to',
}),
type: Flags.string({
char: 't',
description:
'app device type (Check available types with `balena device-type list`)',
}),
};
public static authenticated = true;
public async run() {
const { args: params, flags: options } = await this.parse(AppCreateCmd);
await (
await import('../../utils/application-create')
).applicationCreateBase('app', options, params);
}
}

View File

@ -0,0 +1,77 @@
/**
* @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, Args, Command } from '@oclif/core';
import { stripIndent } from '../../utils/lazy';
export default class BlockCreateCmd extends Command {
public static description = stripIndent`
Create an block.
Create a new balena block.
You can specify the organization the block 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 organization list\` command.
The block's default device type is specified with the \`--type\` option.
The \`balena device-type list\` 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 block create MyBlock',
'$ balena block create MyBlock --organization mmyorg',
'$ balena block create MyBlock -o myorg --type raspberry-pi',
];
public static args = {
name: Args.string({
description: 'block name',
required: true,
}),
};
public static flags = {
organization: Flags.string({
char: 'o',
description: 'handle of the organization the block should belong to',
}),
type: Flags.string({
char: 't',
description:
'block device type (Check available types with `balena device-type list`)',
}),
};
public static authenticated = true;
public async run() {
const { args: params, flags: options } = await this.parse(BlockCreateCmd);
await (
await import('../../utils/application-create')
).applicationCreateBase('block', options, params);
}
}

View File

@ -15,31 +15,36 @@
* limitations under the License.
*/
import { flags } from '@oclif/command';
import Command from '../command';
import { getBalenaSdk } from '../utils/lazy';
import * as cf from '../utils/common-flags';
import * as compose from '../utils/compose';
import type { Application, ApplicationType, BalenaSDK } from 'balena-sdk';
import { Args, Flags, Command } from '@oclif/core';
import { getBalenaSdk } from '../../utils/lazy';
import * as cf from '../../utils/common-flags';
import * as compose from '../../utils/compose';
import type {
ApplicationType,
BalenaSDK,
DeviceType,
PineOptions,
PineTypedResult,
} from 'balena-sdk';
import {
buildArgDeprecation,
dockerignoreHelp,
registrySecretsHelp,
} from '../utils/messages';
import type { ComposeCliFlags, ComposeOpts } from '../utils/compose-types';
import { buildProject, composeCliFlags } from '../utils/compose_ts';
import type { BuildOpts, DockerCliFlags } from '../utils/docker';
import { dockerCliFlags } from '../utils/docker';
} from '../../utils/messages';
import type { ComposeCliFlags, ComposeOpts } from '../../utils/compose-types';
import { buildProject, composeCliFlags } from '../../utils/compose_ts';
import type { BuildOpts, DockerCliFlags } from '../../utils/docker';
import { dockerCliFlags } from '../../utils/docker';
interface FlagsDef extends ComposeCliFlags, DockerCliFlags {
type ComposeGenerateOptsParam = Parameters<typeof compose.generateOpts>[0];
interface PrepareBuildOpts
extends ComposeCliFlags,
DockerCliFlags,
ComposeGenerateOptsParam {
arch?: string;
deviceType?: string;
fleet?: string;
source?: string; // Not part of command profile - source param copied here.
help: void;
}
interface ArgsDef {
source?: string;
}
@ -68,75 +73,73 @@ ${dockerignoreHelp}
public static examples = [
'$ balena build --fleet myFleet',
'$ balena build ./source/ --fleet myorg/myfleet',
'$ balena build --deviceType raspberrypi3 --emulated',
'$ balena build --deviceType raspberrypi3 --arch armv7hf --emulated',
'$ balena build --docker /var/run/docker.sock --fleet myFleet # Linux, Mac',
'$ balena build --docker //./pipe/docker_engine --fleet myFleet # Windows',
'$ balena build --dockerHost my.docker.host --dockerPort 2376 --ca ca.pem --key key.pem --cert cert.pem -f myFleet',
];
public static args = [
{
name: 'source',
description: 'path of project source directory',
},
];
public static args = {
source: Args.string({ description: 'path of project source directory' }),
};
public static usage = 'build [source]';
public static flags: flags.Input<FlagsDef> = {
arch: flags.string({
public static flags = {
arch: Flags.string({
description: 'the architecture to build for',
char: 'A',
}),
deviceType: flags.string({
deviceType: Flags.string({
description: 'the type of device this build is for',
char: 'd',
}),
fleet: cf.fleet,
...composeCliFlags,
...dockerCliFlags,
// NOTE: Not supporting -h for help, because of clash with -h in DockerCliFlags
// Revisit this in future release.
help: flags.help({}),
};
public static primary = true;
public async run() {
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
BuildCmd,
);
const { args: params, flags: options } = await this.parse(BuildCmd);
await Command.checkLoggedInIf(!!options.fleet);
const Logger = await import('../../utils/logger');
const { checkLoggedInIf } = await import('../../utils/patterns');
await checkLoggedInIf(!!options.fleet);
(await import('events')).defaultMaxListeners = 1000;
const sdk = getBalenaSdk();
const logger = await Command.getLogger();
const logger = Logger.getLogger();
logger.logDebug('Parsing input...');
// `build` accepts `source` as a parameter, but compose expects it as an option
options.source = params.source;
delete params.source;
const prepareBuildOpts = {
...options,
source: params.source,
};
await this.validateOptions(options, sdk);
await this.resolveArchFromDeviceType(sdk, prepareBuildOpts);
await this.validateOptions(prepareBuildOpts, sdk);
// Build args are under consideration for removal - warn user
if (options.buildArg) {
if (prepareBuildOpts.buildArg) {
console.log(buildArgDeprecation);
}
const app = await this.getAppAndResolveArch(options);
const app = await this.getAppAndResolveArch(prepareBuildOpts);
const { docker, buildOpts, composeOpts } = await this.prepareBuild(options);
const { docker, buildOpts, composeOpts } =
await this.prepareBuild(prepareBuildOpts);
try {
await this.buildProject(docker, logger, composeOpts, {
app,
arch: options.arch!,
deviceType: options.deviceType!,
buildEmulated: options.emulated,
appType: app?.application_type?.[0],
arch: prepareBuildOpts.arch!,
deviceType: prepareBuildOpts.deviceType!,
buildEmulated: prepareBuildOpts.emulated,
buildOpts,
});
} catch (err) {
@ -148,20 +151,20 @@ ${dockerignoreHelp}
logger.logSuccess('Build succeeded!');
}
protected async validateOptions(opts: FlagsDef, sdk: BalenaSDK) {
protected async validateOptions(opts: PrepareBuildOpts, sdk: BalenaSDK) {
// Validate option combinations
if (
(opts.fleet == null && (opts.arch == null || opts.deviceType == null)) ||
(opts.fleet != null && (opts.arch != null || opts.deviceType != null))
) {
const { ExpectedError } = await import('../errors');
const { ExpectedError } = await import('../../errors');
throw new ExpectedError(
'You must specify either a fleet (-f), or the device type (-d) and architecture (-A)',
'You must specify either a fleet (-f), or the device type (-d) and optionally the architecture (-A)',
);
}
// Validate project directory
const { validateProjectDirectory } = await import('../utils/compose_ts');
const { validateProjectDirectory } = await import('../../utils/compose_ts');
const { dockerfilePath, registrySecrets } = await validateProjectDirectory(
sdk,
{
@ -176,9 +179,45 @@ ${dockerignoreHelp}
opts['registry-secrets'] = registrySecrets;
}
protected async getAppAndResolveArch(opts: FlagsDef) {
protected async resolveArchFromDeviceType(
sdk: BalenaSDK,
opts: PrepareBuildOpts,
) {
if (opts.deviceType != null && opts.arch == null) {
try {
const deviceTypeOpts = {
$select: 'is_of__cpu_architecture',
$expand: {
is_of__cpu_architecture: {
$select: 'slug',
},
},
} satisfies PineOptions<DeviceType>;
opts.arch = (
(await sdk.models.deviceType.get(
opts.deviceType,
deviceTypeOpts,
)) as PineTypedResult<DeviceType, typeof deviceTypeOpts>
).is_of__cpu_architecture[0].slug;
} catch (err) {
const { ExpectedError } = await import('../../errors');
if (err instanceof sdk.errors.BalenaInvalidDeviceType) {
let message = err.message;
if (!(await sdk.auth.isLoggedIn())) {
message = `${message}. In case you are trying to use a private device type, please try to log in first.`;
}
throw new ExpectedError(message);
}
throw new ExpectedError(
'Failed to resolve the architecture of the provided device type. If you are in an air-gapped environment please also define the architecture (-A) parameter.',
);
}
}
}
protected async getAppAndResolveArch(opts: PrepareBuildOpts) {
if (opts.fleet) {
const { getAppWithArch } = await import('../utils/helpers');
const { getAppWithArch } = await import('../../utils/helpers');
const app = await getAppWithArch(opts.fleet);
opts.arch = app.arch;
opts.deviceType = app.is_for__device_type[0].slug;
@ -186,8 +225,8 @@ ${dockerignoreHelp}
}
}
protected async prepareBuild(options: FlagsDef) {
const { getDocker, generateBuildOpts } = await import('../utils/docker');
protected async prepareBuild(options: PrepareBuildOpts) {
const { getDocker, generateBuildOpts } = await import('../../utils/docker');
const [docker, buildOpts, composeOpts] = await Promise.all([
getDocker(options),
generateBuildOpts(options),
@ -208,24 +247,24 @@ ${dockerignoreHelp}
* buildEmulated
* buildOpts: arguments to forward to docker build command
*
* @param {DockerToolbelt} docker
* @param {Dockerode} docker
* @param {Logger} logger
* @param {ComposeOpts} composeOpts
* @param opts
*/
protected async buildProject(
docker: import('dockerode'),
logger: import('../utils/logger'),
logger: import('../../utils/logger'),
composeOpts: ComposeOpts,
opts: {
app?: Application;
appType?: Pick<ApplicationType, 'supports_multicontainer'>;
arch: string;
deviceType: string;
buildEmulated: boolean;
buildOpts: BuildOpts;
},
) {
const { loadProject } = await import('../utils/compose_ts');
const { loadProject } = await import('../../utils/compose_ts');
const project = await loadProject(
logger,
@ -234,11 +273,10 @@ ${dockerignoreHelp}
opts.buildOpts.t,
);
const appType = (opts.app?.application_type as ApplicationType[])?.[0];
if (
appType != null &&
opts.appType != null &&
project.descriptors.length > 1 &&
!appType.supports_multicontainer
!opts.appType.supports_multicontainer
) {
logger.logWarn(
'Target fleet does not support multiple containers.\n' +

View File

@ -15,31 +15,16 @@
* limitations under the License.
*/
import { flags } from '@oclif/command';
import Command from '../../command';
import { Flags, Command } from '@oclif/core';
import type { Interfaces } from '@oclif/core';
import * as cf from '../../utils/common-flags';
import { getBalenaSdk, getCliForm, stripIndent } from '../../utils/lazy';
import { applicationIdInfo, devModeInfo } from '../../utils/messages';
import type { PineDeferred } from 'balena-sdk';
interface FlagsDef {
version: string; // OS version
fleet?: string;
dev?: boolean; // balenaOS development variant
device?: string;
deviceApiKey?: string;
deviceType?: string;
'generate-device-api-key': boolean;
output?: string;
// Options for non-interactive configuration
network?: string;
wifiSsid?: string;
wifiKey?: string;
appUpdatePollInterval?: string;
'provisioning-key-name'?: string;
'provisioning-key-expiry-date'?: string;
help: void;
}
import {
applicationIdInfo,
devModeInfo,
secureBootInfo,
} from '../../utils/messages';
import type { BalenaSDK, PineDeferred } from 'balena-sdk';
export default class ConfigGenerateCmd extends Command {
public static description = stripIndent`
@ -51,6 +36,8 @@ export default class ConfigGenerateCmd extends Command {
${devModeInfo.split('\n').join('\n\t\t')}
${secureBootInfo.split('\n').join('\n\t\t')}
To configure an image for a fleet of mixed device types, use the --fleet option
alongside the --deviceType option to specify the target device type.
@ -66,20 +53,20 @@ export default class ConfigGenerateCmd extends Command {
'$ balena config generate --device 7cf02a6 --version 2.12.7 --deviceApiKey <existingDeviceKey>',
'$ balena config generate --device 7cf02a6 --version 2.12.7 --output config.json',
'$ balena config generate --fleet myorg/fleet --version 2.12.7 --dev',
'$ balena config generate --fleet myorg/fleet --version 2.12.7 --secureBoot',
'$ balena config generate --fleet myorg/fleet --version 2.12.7 --deviceType fincm3',
'$ balena config generate --fleet myorg/fleet --version 2.12.7 --output config.json',
'$ balena config generate --fleet myorg/fleet --version 2.12.7 --network wifi --wifiSsid mySsid --wifiKey abcdefgh --appUpdatePollInterval 15',
];
public static usage = 'config generate';
public static flags: flags.Input<FlagsDef> = {
version: flags.string({
public static flags = {
version: Flags.string({
description: 'a balenaOS version',
required: true,
}),
fleet: { ...cf.fleet, exclusive: ['device'] },
dev: cf.dev,
secureBoot: cf.secureBoot,
device: {
...cf.device,
exclusive: [
@ -88,64 +75,71 @@ export default class ConfigGenerateCmd extends Command {
'provisioning-key-expiry-date',
],
},
deviceApiKey: flags.string({
deviceApiKey: Flags.string({
description:
'custom device key - note that this is only supported on balenaOS 2.0.3+',
char: 'k',
}),
deviceType: flags.string({
deviceType: Flags.string({
description:
"device type slug (run 'balena devices supported' for possible values)",
"device type slug (run 'balena device-type list' for possible values)",
}),
'generate-device-api-key': flags.boolean({
'generate-device-api-key': Flags.boolean({
description: 'generate a fresh device key for the device',
}),
output: flags.string({
output: Flags.string({
description: 'path of output file',
char: 'o',
}),
// Options for non-interactive configuration
network: flags.string({
network: Flags.string({
description: 'the network type to use: ethernet or wifi',
options: ['ethernet', 'wifi'],
}),
wifiSsid: flags.string({
wifiSsid: Flags.string({
description:
'the wifi ssid to use (used only if --network is set to wifi)',
}),
wifiKey: flags.string({
wifiKey: Flags.string({
description:
'the wifi key to use (used only if --network is set to wifi)',
}),
appUpdatePollInterval: flags.string({
appUpdatePollInterval: Flags.string({
description:
'supervisor cloud polling interval in minutes (e.g. for device variables)',
}),
'provisioning-key-name': flags.string({
'provisioning-key-name': Flags.string({
description: 'custom key name assigned to generated provisioning api key',
exclusive: ['device'],
}),
'provisioning-key-expiry-date': flags.string({
'provisioning-key-expiry-date': Flags.string({
description:
'expiry date assigned to generated provisioning api key (format: YYYY-MM-DD)',
exclusive: ['device'],
}),
help: cf.help,
};
public static authenticated = true;
public async run() {
const { flags: options } = this.parse<FlagsDef, {}>(ConfigGenerateCmd);
public async getApplication(balena: BalenaSDK, fleet: string) {
const { getApplication } = await import('../../utils/sdk');
return await getApplication(balena, fleet, {
$select: 'slug',
$expand: {
is_for__device_type: { $select: 'slug' },
},
});
}
public async run() {
const { flags: options } = await this.parse(ConfigGenerateCmd);
const balena = getBalenaSdk();
await this.validateOptions(options);
let resourceDeviceType: string;
let application: ApplicationWithDeviceType | null = null;
let application: Awaited<ReturnType<typeof this.getApplication>> | null =
null;
let device:
| (DeviceWithDeviceType & { belongs_to__application: PineDeferred })
| null = null;
@ -165,11 +159,7 @@ export default class ConfigGenerateCmd extends Command {
resourceDeviceType = device.is_of__device_type[0].slug;
} else {
// Disambiguate application (if is a number, it could either be an ID or a numerical name)
application = (await getApplication(balena, options.fleet!, {
$expand: {
is_for__device_type: { $select: 'slug' },
},
})) as ApplicationWithDeviceType;
application = await this.getApplication(balena, options.fleet!);
resourceDeviceType = application.is_for__device_type[0].slug;
}
@ -191,8 +181,16 @@ export default class ConfigGenerateCmd extends Command {
}
}
const deviceManifest = await balena.models.device.getManifestBySlug(
const deviceManifest =
await balena.models.config.getDeviceTypeManifestBySlug(deviceType);
const { validateSecureBootOptionAndWarn } = await import(
'../../utils/config'
);
await validateSecureBootOptionAndWarn(
options.secureBoot,
deviceType,
options.version,
);
// Prompt for values
@ -203,6 +201,7 @@ export default class ConfigGenerateCmd extends Command {
});
answers.version = options.version;
answers.developmentMode = options.dev;
answers.secureBoot = options.secureBoot;
answers.provisioningKeyName = options['provisioning-key-name'];
answers.provisioningKeyExpiryDate = options['provisioning-key-expiry-date'];
@ -244,7 +243,9 @@ export default class ConfigGenerateCmd extends Command {
protected readonly deviceTypeNotAllowedMessage =
'The --deviceType option can only be used alongside the --fleet option';
protected async validateOptions(options: FlagsDef) {
protected async validateOptions(
options: Interfaces.InferredFlags<typeof ConfigGenerateCmd.flags>,
) {
const { ExpectedError } = await import('../../errors');
if (options.device == null && options.fleet == null) {
@ -254,6 +255,8 @@ export default class ConfigGenerateCmd extends Command {
if (!options.fleet && options.deviceType) {
throw new ExpectedError(this.deviceTypeNotAllowedMessage);
}
const { normalizeOsVersion } = await import('../../utils/normalization');
options.version = normalizeOsVersion(options.version);
const { validateDevOptionAndWarn } = await import('../../utils/config');
await validateDevOptionAndWarn(options.dev, options.version);
}

View File

@ -15,21 +15,10 @@
* limitations under the License.
*/
import { flags } from '@oclif/command';
import Command from '../../command';
import { Args, Command } from '@oclif/core';
import * as cf from '../../utils/common-flags';
import { getVisuals, stripIndent } from '../../utils/lazy';
interface FlagsDef {
type?: string;
drive?: string;
help: void;
}
interface ArgsDef {
file: string;
}
export default class ConfigInjectCmd extends Command {
public static description = stripIndent`
Inject a config.json file to a balenaOS image or attached media.
@ -46,28 +35,22 @@ export default class ConfigInjectCmd extends Command {
'$ balena config inject my/config.json --drive /dev/disk2',
];
public static args = [
{
name: 'file',
public static args = {
file: Args.string({
description: 'the path to the config.json file to inject',
required: true,
},
];
}),
};
public static usage = 'config inject <file>';
public static flags: flags.Input<FlagsDef> = {
public static flags = {
drive: cf.driveOrImg,
help: cf.help,
};
public static root = true;
public static offlineCompatible = true;
public async run() {
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
ConfigInjectCmd,
);
const { args: params, flags: options } = await this.parse(ConfigInjectCmd);
const { safeUmount } = await import('../../utils/umount');

View File

@ -15,18 +15,10 @@
* limitations under the License.
*/
import { flags } from '@oclif/command';
import Command from '../../command';
import { Command } from '@oclif/core';
import * as cf from '../../utils/common-flags';
import { getVisuals, stripIndent } from '../../utils/lazy';
interface FlagsDef {
type?: string;
drive?: string;
help: void;
json: boolean;
}
export default class ConfigReadCmd extends Command {
public static description = stripIndent`
Read the config.json file of a balenaOS image or attached media.
@ -44,11 +36,8 @@ export default class ConfigReadCmd extends Command {
'$ balena config read --drive balena.img',
];
public static usage = 'config read';
public static flags: flags.Input<FlagsDef> = {
public static flags = {
drive: cf.driveOrImg,
help: cf.help,
json: cf.json,
};
@ -56,7 +45,7 @@ export default class ConfigReadCmd extends Command {
public static offlineCompatible = true;
public async run() {
const { flags: options } = this.parse<FlagsDef, {}>(ConfigReadCmd);
const { flags: options } = await this.parse(ConfigReadCmd);
const { safeUmount } = await import('../../utils/umount');

View File

@ -15,19 +15,10 @@
* limitations under the License.
*/
import { flags } from '@oclif/command';
import Command from '../../command';
import { Flags, Command } from '@oclif/core';
import * as cf from '../../utils/common-flags';
import { getVisuals, stripIndent } from '../../utils/lazy';
interface FlagsDef {
type?: string;
drive?: string;
advanced: boolean;
help: void;
version?: string;
}
export default class ConfigReconfigureCmd extends Command {
public static description = stripIndent`
Interactively reconfigure a balenaOS image file or attached media.
@ -47,16 +38,13 @@ export default class ConfigReconfigureCmd extends Command {
'$ balena config reconfigure --drive balena.img --advanced',
];
public static usage = 'config reconfigure';
public static flags: flags.Input<FlagsDef> = {
public static flags = {
drive: cf.driveOrImg,
advanced: flags.boolean({
advanced: Flags.boolean({
description: 'show advanced commands',
char: 'v',
}),
help: cf.help,
version: flags.string({
version: Flags.string({
description: 'balenaOS version, for example "2.32.0" or "2.44.0+rev1"',
}),
};
@ -65,7 +53,7 @@ export default class ConfigReconfigureCmd extends Command {
public static root = true;
public async run() {
const { flags: options } = this.parse<FlagsDef, {}>(ConfigReconfigureCmd);
const { flags: options } = await this.parse(ConfigReconfigureCmd);
const { safeUmount } = await import('../../utils/umount');

View File

@ -15,22 +15,10 @@
* limitations under the License.
*/
import { flags } from '@oclif/command';
import Command from '../../command';
import { Args, Command } from '@oclif/core';
import * as cf from '../../utils/common-flags';
import { getVisuals, stripIndent } from '../../utils/lazy';
interface FlagsDef {
type?: string;
drive?: string;
help: void;
}
interface ArgsDef {
key: string;
value: string;
}
export default class ConfigWriteCmd extends Command {
public static description = stripIndent`
Write a key-value pair to the config.json file of an OS image or attached media.
@ -48,33 +36,26 @@ export default class ConfigWriteCmd extends Command {
'$ balena config write --drive balena.img os.network.connectivity.interval 300',
];
public static args = [
{
name: 'key',
public static args = {
key: Args.string({
description: 'the key of the config parameter to write',
required: true,
},
{
name: 'value',
}),
value: Args.string({
description: 'the value of the config parameter to write',
required: true,
},
];
}),
};
public static usage = 'config write <key> <value>';
public static flags: flags.Input<FlagsDef> = {
public static flags = {
drive: cf.driveOrImg,
help: cf.help,
};
public static root = true;
public static offlineCompatible = true;
public async run() {
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
ConfigWriteCmd,
);
const { args: params, flags: options } = await this.parse(ConfigWriteCmd);
const { denyMount, safeUmount } = await import('../../utils/umount');

View File

@ -15,45 +15,44 @@
* limitations under the License.
*/
import { flags } from '@oclif/command';
import { Args, Flags, Command } from '@oclif/core';
import type { ImageDescriptor } from '@balena/compose/dist/parse';
import Command from '../command';
import { ExpectedError } from '../errors';
import { getBalenaSdk, getChalk, stripIndent } from '../utils/lazy';
import { ExpectedError } from '../../errors';
import { getBalenaSdk, getChalk, stripIndent } from '../../utils/lazy';
import {
dockerignoreHelp,
registrySecretsHelp,
buildArgDeprecation,
} from '../utils/messages';
import * as ca from '../utils/common-args';
import * as compose from '../utils/compose';
} from '../../utils/messages';
import * as ca from '../../utils/common-args';
import * as compose from '../../utils/compose';
import type {
BuiltImage,
ComposeCliFlags,
ComposeOpts,
Release as ComposeReleaseInfo,
} from '../utils/compose-types';
import type { BuildOpts, DockerCliFlags } from '../utils/docker';
} from '../../utils/compose-types';
import type { BuildOpts, DockerCliFlags } from '../../utils/docker';
import {
applyReleaseTagKeysAndValues,
buildProject,
composeCliFlags,
isBuildConfig,
parseReleaseTagKeysAndValues,
} from '../utils/compose_ts';
import { dockerCliFlags } from '../utils/docker';
import type {
Application,
ApplicationType,
DeviceType,
Release,
} from 'balena-sdk';
} from '../../utils/compose_ts';
import { dockerCliFlags } from '../../utils/docker';
import type { ApplicationType, DeviceType, Release } from 'balena-sdk';
interface ApplicationWithArch extends Application {
interface ApplicationWithArch {
id: number;
arch: string;
is_for__device_type: [Pick<DeviceType, 'slug'>];
application_type: [Pick<ApplicationType, 'slug' | 'supports_multicontainer'>];
}
// TODO: For this special one we can't use Interfaces.InferredFlags/InferredArgs
// because of the 'registry-secrets' type which is defined in the actual code
// as a path (string | undefined) but then the cli turns it into an object
interface FlagsDef extends ComposeCliFlags, DockerCliFlags {
source?: string;
build: boolean;
@ -61,12 +60,6 @@ interface FlagsDef extends ComposeCliFlags, DockerCliFlags {
'release-tag'?: string[];
draft: boolean;
note?: string;
help: void;
}
interface ArgsDef {
fleet: string;
image?: string;
}
export default class DeployCmd extends Command {
@ -107,31 +100,26 @@ ${dockerignoreHelp}
'$ balena deploy myFleet myRepo/myImage --release-tag key1 "" key2 "value2 with spaces"',
];
public static args = [
ca.fleetRequired,
{
name: 'image',
description: 'the image to deploy',
},
];
public static args = {
fleet: ca.fleetRequired,
image: Args.string({ description: 'the image to deploy' }),
};
public static usage = 'deploy <fleet> [image]';
public static flags: flags.Input<FlagsDef> = {
source: flags.string({
public static flags = {
source: Flags.string({
description:
'specify an alternate source directory; default is the working directory',
char: 's',
}),
build: flags.boolean({
build: Flags.boolean({
description: 'force a rebuild before deploy',
char: 'b',
}),
nologupload: flags.boolean({
nologupload: Flags.boolean({
description:
"don't upload build logs to the dashboard with image (if building)",
}),
'release-tag': flags.string({
'release-tag': Flags.string({
description: stripIndent`
Set release tags if the image deployment is successful. Multiple
arguments may be provided, alternating tag keys and values (see examples).
@ -139,7 +127,7 @@ ${dockerignoreHelp}
`,
multiple: true,
}),
draft: flags.boolean({
draft: Flags.boolean({
description: stripIndent`
Deploy the release as a draft. Draft releases are ignored
by the 'track latest' release policy but can be used through release pinning.
@ -147,12 +135,9 @@ ${dockerignoreHelp}
as final by default unless this option is given.`,
default: false,
}),
note: flags.string({ description: 'The notes for this release' }),
note: Flags.string({ description: 'The notes for this release' }),
...composeCliFlags,
...dockerCliFlags,
// NOTE: Not supporting -h for help, because of clash with -h in DockerCliFlags
// Revisit this in future release.
help: flags.help({}),
};
public static authenticated = true;
@ -160,13 +145,13 @@ ${dockerignoreHelp}
public static primary = true;
public async run() {
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
DeployCmd,
);
const { args: params, flags: options } = await this.parse(DeployCmd);
(await import('events')).defaultMaxListeners = 1000;
const logger = await Command.getLogger();
const Logger = await import('../../utils/logger');
const logger = Logger.getLogger();
logger.logDebug('Parsing input...');
const { fleet, image } = params;
@ -184,7 +169,7 @@ ${dockerignoreHelp}
const sdk = getBalenaSdk();
const { getRegistrySecrets, validateProjectDirectory } = await import(
'../utils/compose_ts'
'../../utils/compose_ts'
);
const { releaseTagKeys, releaseTagValues } = parseReleaseTagKeysAndValues(
@ -192,7 +177,7 @@ ${dockerignoreHelp}
);
if (image) {
options['registry-secrets'] = await getRegistrySecrets(
(options as FlagsDef)['registry-secrets'] = await getRegistrySecrets(
sdk,
options['registry-secrets'],
);
@ -205,16 +190,16 @@ ${dockerignoreHelp}
registrySecretsPath: options['registry-secrets'],
});
options.dockerfile = dockerfilePath;
options['registry-secrets'] = registrySecrets;
(options as FlagsDef)['registry-secrets'] = registrySecrets;
}
const helpers = await import('../utils/helpers');
const helpers = await import('../../utils/helpers');
const app = await helpers.getAppWithArch(fleet);
const dockerUtils = await import('../utils/docker');
const dockerUtils = await import('../../utils/docker');
const [docker, buildOpts, composeOpts] = await Promise.all([
dockerUtils.getDocker(options),
dockerUtils.generateBuildOpts(options),
dockerUtils.generateBuildOpts(options as FlagsDef),
compose.generateOpts(options),
]);
@ -235,13 +220,13 @@ ${dockerignoreHelp}
releaseTagValues,
);
if (options.note) {
await sdk.models.release.note(release.id, options.note);
await sdk.models.release.setNote(release.id, options.note);
}
}
async deployProject(
docker: import('dockerode'),
logger: import('../utils/logger'),
logger: import('../../utils/logger'),
composeOpts: ComposeOpts,
opts: {
app: ApplicationWithArch; // the application instance to deploy to
@ -259,10 +244,10 @@ ${dockerignoreHelp}
const doodles = await import('resin-doodles');
const sdk = getBalenaSdk();
const { deployProject: $deployProject, loadProject } = await import(
'../utils/compose_ts'
'../../utils/compose_ts'
);
const appType = (opts.app?.application_type as ApplicationType[])?.[0];
const appType = opts.app.application_type[0];
try {
const project = await loadProject(
@ -319,7 +304,7 @@ ${dockerignoreHelp}
projectName: project.name,
composition: compositionToBuild,
arch: opts.app.arch,
deviceType: (opts.app?.is_for__device_type as DeviceType[])?.[0].slug,
deviceType: opts.app.is_for__device_type[0].slug,
emulated: opts.buildEmulated,
buildOpts: opts.buildOpts,
inlineLogs: composeOpts.inlineLogs,
@ -340,17 +325,17 @@ ${dockerignoreHelp}
);
let release: Release | ComposeReleaseInfo['release'];
if (appType?.is_legacy) {
const { deployLegacy } = require('../utils/deploy-legacy');
if (appType.slug === 'legacy-v1' || appType.slug === 'legacy-v2') {
const { deployLegacy } = require('../../utils/deploy-legacy');
const msg = getChalk().yellow(
'Target fleet requires legacy deploy method.',
);
logger.logWarn(msg);
const [token, username, url, options] = await Promise.all([
const [token, { username }, url, options] = await Promise.all([
sdk.auth.getToken(),
sdk.auth.whoami(),
sdk.auth.getUserInfo(),
sdk.settings.get('balenaUrl'),
{
// opts.appName may be prefixed by 'owner/', unlike opts.app.app_name
@ -373,23 +358,17 @@ ${dockerignoreHelp}
$select: ['commit'],
});
} else {
const [userId, auth, apiEndpoint] = await Promise.all([
sdk.auth.getUserId(),
sdk.auth.getToken(),
sdk.settings.get('apiUrl'),
]);
release = await $deployProject(
docker,
sdk,
logger,
project.composition,
images,
opts.app.id,
userId,
`Bearer ${auth}`,
apiEndpoint,
!opts.shouldUploadLogs,
composeOpts.projectPath,
opts.createAsDraft,
project.descriptors,
);
}

View File

@ -14,25 +14,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { flags } from '@oclif/command';
import { Flags, Command } from '@oclif/core';
import type * as BalenaSdk from 'balena-sdk';
import * as _ from 'lodash';
import Command from '../../command';
import * as cf from '../../utils/common-flags';
import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy';
import { CommandHelp } from '../../utils/oclif-utils';
interface FlagsDef {
help: void;
json?: boolean;
}
export default class DeviceTypeListCmd extends Command {
public static aliases = ['devices supported'];
public static deprecateAliases = true;
export default class DevicesSupportedCmd extends Command {
public static description = stripIndent`
List the supported device types (like 'raspberrypi3' or 'intel-nuc').
List the device types supported by balena (like 'raspberrypi3' or 'intel-nuc').
List the supported device types (like 'raspberrypi3' or 'intel-nuc').
List the device types supported by balena (like 'raspberrypi3' or 'intel-nuc').
By default, only actively supported device types are listed.
The --all option can be used to list all device types, including those that are
no longer supported by balena.
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
@ -41,38 +39,39 @@ export default class DevicesSupportedCmd extends Command {
(https://stedolan.github.io/jq/manual/).
`;
public static examples = [
'$ balena devices supported',
'$ balena devices supported --json',
'$ balena device-type list',
'$ balena device-type list --all',
'$ balena device-type list --json',
];
public static usage = (
'devices supported ' +
new CommandHelp({ args: DevicesSupportedCmd.args }).defaultUsage()
).trim();
public static flags: flags.Input<FlagsDef> = {
help: cf.help,
json: flags.boolean({
public static flags = {
json: Flags.boolean({
char: 'j',
description: 'produce JSON output instead of tabular output',
}),
all: Flags.boolean({
description: 'include device types no longer supported by balena',
default: false,
}),
};
public async run() {
const { flags: options } = this.parse<FlagsDef, {}>(DevicesSupportedCmd);
const { flags: options } = await this.parse(DeviceTypeListCmd);
const pineOptions = {
$select: (['slug', 'name'] as const).slice(),
$select: ['slug', 'name'],
$expand: {
is_of__cpu_architecture: { $select: 'slug' },
device_type_alias: {
$select: 'is_referenced_by__alias',
$orderby: 'is_referenced_by__alias asc',
$orderby: { is_referenced_by__alias: 'asc' },
},
},
} as const;
const dts = (await getBalenaSdk().models.deviceType.getAllSupported(
pineOptions,
)) as Array<
} satisfies BalenaSdk.PineOptions<BalenaSdk.DeviceType>;
const dts = (
options.all
? await getBalenaSdk().models.deviceType.getAll(pineOptions)
: await getBalenaSdk().models.deviceType.getAllSupported(pineOptions)
) as Array<
BalenaSdk.PineTypedResult<BalenaSdk.DeviceType, typeof pineOptions>
>;
interface DT {

View File

@ -15,21 +15,10 @@
* limitations under the License.
*/
import { flags } from '@oclif/command';
import type { IArg } from '@oclif/parser/lib/args';
import Command from '../../command';
import { Args, Command } from '@oclif/core';
import * as cf from '../../utils/common-flags';
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
interface FlagsDef {
yes: boolean;
help: void;
}
interface ArgsDef {
uuid: string;
}
export default class DeviceDeactivateCmd extends Command {
public static description = stripIndent`
Deactivate a device.
@ -44,27 +33,22 @@ export default class DeviceDeactivateCmd extends Command {
'$ balena device deactivate 7cf02a6 --yes',
];
public static args: Array<IArg<any>> = [
{
name: 'uuid',
public static args = {
uuid: Args.string({
description: 'the UUID of the device to be deactivated',
required: true,
},
];
}),
};
public static usage = 'device deactivate <uuid>';
public static flags: flags.Input<FlagsDef> = {
public static flags = {
yes: cf.yes,
help: cf.help,
};
public static authenticated = true;
public async run() {
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
DeviceDeactivateCmd,
);
const { args: params, flags: options } =
await this.parse(DeviceDeactivateCmd);
const balena = getBalenaSdk();
const patterns = await import('../../utils/patterns');

View File

@ -15,20 +15,13 @@
* limitations under the License.
*/
import { flags } from '@oclif/command';
import type { LocalBalenaOsDevice } from 'balena-sync';
import Command from '../command';
import * as cf from '../utils/common-flags';
import { getCliUx, stripIndent } from '../utils/lazy';
import { Flags, Command } from '@oclif/core';
import { getCliUx, stripIndent } from '../../utils/lazy';
interface FlagsDef {
json?: boolean;
verbose: boolean;
timeout?: number;
help: void;
}
export default class DeviceDetectCmd extends Command {
public static aliases = ['scan'];
public static deprecateAliases = true;
export default class ScanCmd extends Command {
public static description = stripIndent`
Scan for balenaOS devices on your local network.
@ -41,25 +34,22 @@ export default class ScanCmd extends Command {
`;
public static examples = [
'$ balena scan',
'$ balena scan --timeout 120',
'$ balena scan --verbose',
'$ balena device detect',
'$ balena device detect --timeout 120',
'$ balena device detect --verbose',
];
public static usage = 'scan';
public static flags: flags.Input<FlagsDef> = {
verbose: flags.boolean({
public static flags = {
verbose: Flags.boolean({
default: false,
char: 'v',
description: 'display full info',
}),
timeout: flags.integer({
timeout: Flags.integer({
char: 't',
description: 'scan timeout in seconds',
}),
help: cf.help,
json: flags.boolean({
json: Flags.boolean({
default: false,
char: 'j',
description: 'produce JSON output instead of tabular output',
@ -72,14 +62,16 @@ export default class ScanCmd extends Command {
public async run() {
const _ = await import('lodash');
const { discover } = await import('balena-sync');
const { discoverLocalBalenaOsDevices } = await import(
'../../utils/discover'
);
const prettyjson = await import('prettyjson');
const dockerUtils = await import('../utils/docker');
const dockerUtils = await import('../../utils/docker');
const dockerPort = 2375;
const dockerTimeout = 2000;
const { flags: options } = this.parse<FlagsDef, {}>(ScanCmd);
const { flags: options } = await this.parse(DeviceDetectCmd);
const discoverTimeout =
options.timeout != null ? options.timeout * 1000 : undefined;
@ -88,8 +80,7 @@ export default class ScanCmd extends Command {
const ux = getCliUx();
ux.action.start('Scanning for local balenaOS devices');
const localDevices: LocalBalenaOsDevice[] =
await discover.discoverLocalBalenaOsDevices(discoverTimeout);
const localDevices = await discoverLocalBalenaOsDevices(discoverTimeout);
const engineReachableDevices: boolean[] = await Promise.all(
localDevices.map(async ({ address }: { address: string }) => {
const docker = await dockerUtils.createClient({
@ -100,13 +91,13 @@ export default class ScanCmd extends Command {
try {
await docker.ping();
return true;
} catch (err) {
} catch {
return false;
}
}),
);
const developmentDevices: LocalBalenaOsDevice[] = localDevices.filter(
const developmentDevices = localDevices.filter(
(_localDevice, index) => engineReachableDevices[index],
);
@ -116,18 +107,15 @@ export default class ScanCmd extends Command {
_.isEqual,
);
const productionDevicesInfo = _.map(
productionDevices,
(device: LocalBalenaOsDevice) => {
return {
host: device.host,
address: device.address,
osVariant: 'production',
dockerInfo: undefined,
dockerVersion: undefined,
};
},
);
const productionDevicesInfo = productionDevices.map((device) => {
return {
host: device.host,
address: device.address,
osVariant: 'production',
dockerInfo: undefined,
dockerVersion: undefined,
};
});
// Query devices for info
const devicesInfo = await Promise.all(
@ -157,10 +145,10 @@ export default class ScanCmd extends Command {
if (!options.verbose) {
devicesInfo.forEach((d: any) => {
d.dockerInfo = _.isObject(d.dockerInfo)
? _.pick(d.dockerInfo, ScanCmd.dockerInfoProperties)
? _.pick(d.dockerInfo, DeviceDetectCmd.dockerInfoProperties)
: d.dockerInfo;
d.dockerVersion = _.isObject(d.dockerVersion)
? _.pick(d.dockerVersion, ScanCmd.dockerVersionProperties)
? _.pick(d.dockerVersion, DeviceDetectCmd.dockerVersionProperties)
: d.dockerVersion;
});
}
@ -177,8 +165,9 @@ export default class ScanCmd extends Command {
if (!options.json && cmdOutput.length === 0) {
console.error(
process.platform === 'win32'
? ScanCmd.noDevicesFoundMessage + ScanCmd.windowsTipMessage
: ScanCmd.noDevicesFoundMessage,
? DeviceDetectCmd.noDevicesFoundMessage +
DeviceDetectCmd.windowsTipMessage
: DeviceDetectCmd.noDevicesFoundMessage,
);
return;
}
@ -210,11 +199,11 @@ export default class ScanCmd extends Command {
protected static windowsTipMessage = `
Note for Windows users:
The 'scan' command relies on the Bonjour service. Check whether Bonjour is
The 'device detect' command relies on the Bonjour service. Check whether Bonjour is
installed (Control Panel > Programs and Features). If not, you can download
Bonjour for Windows (included with Bonjour Print Services) from here:
https://support.apple.com/kb/DL999
After installing Bonjour, restart your PC and run the 'balena scan' command
After installing Bonjour, restart your PC and run the 'balena device detect' command
again.`;
}

View File

@ -15,21 +15,10 @@
* 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 { Args, Command } from '@oclif/core';
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
import { ExpectedError } from '../../errors';
interface FlagsDef {
help: void;
}
interface ArgsDef {
uuid: string;
}
export default class DeviceIdentifyCmd extends Command {
public static description = stripIndent`
Identify a device.
@ -38,24 +27,17 @@ export default class DeviceIdentifyCmd extends Command {
`;
public static examples = ['$ balena device identify 23c73a1'];
public static args: Array<IArg<any>> = [
{
name: 'uuid',
public static args = {
uuid: Args.string({
description: 'the uuid of the device to identify',
required: true,
},
];
public static usage = 'device identify <uuid>';
public static flags: flags.Input<FlagsDef> = {
help: cf.help,
}),
};
public static authenticated = true;
public async run() {
const { args: params } = this.parse<FlagsDef, ArgsDef>(DeviceIdentifyCmd);
const { args: params } = await this.parse(DeviceIdentifyCmd);
const balena = getBalenaSdk();

View File

@ -15,12 +15,11 @@
* limitations under the License.
*/
import { flags } from '@oclif/command';
import { IArg } from '@oclif/parser/lib/args';
import Command from '../../command';
import { Flags, Args, Command } from '@oclif/core';
import * as cf from '../../utils/common-flags';
import { expandForAppName } from '../../utils/helpers';
import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy';
import { jsonInfo } from '../../utils/messages';
import type { Application, Release } from 'balena-sdk';
@ -41,39 +40,30 @@ interface ExtendedDevice extends DeviceWithDeviceType {
undervoltage_detected?: boolean;
}
interface FlagsDef {
help: void;
view: boolean;
}
interface ArgsDef {
uuid: string;
}
export default class DeviceCmd extends Command {
public static description = stripIndent`
Show info about a single device.
Show information about a single device.
${jsonInfo.split('\n').join('\n\t\t')}
`;
public static examples = [
'$ balena device 7cf02a6',
'$ balena device 7cf02a6 --view',
'$ balena device 7cf02a6 --json',
];
public static args: Array<IArg<any>> = [
{
name: 'uuid',
public static args = {
uuid: Args.string({
description: 'the device uuid',
required: true,
},
];
}),
};
public static usage = 'device <uuid>';
public static flags: flags.Input<FlagsDef> = {
help: cf.help,
view: flags.boolean({
public static flags = {
json: cf.json,
view: Flags.boolean({
default: false,
description: 'open device dashboard page',
}),
@ -83,39 +73,63 @@ export default class DeviceCmd extends Command {
public static primary = true;
public async run() {
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
DeviceCmd,
);
const { args: params, flags: options } = await this.parse(DeviceCmd);
const balena = getBalenaSdk();
const device = (await balena.models.device.get(params.uuid, {
$select: [
'device_name',
'id',
'overall_status',
'is_online',
'ip_address',
'mac_address',
'last_connectivity_event',
'uuid',
'supervisor_version',
'is_web_accessible',
'note',
'os_version',
'memory_usage',
'memory_total',
'public_address',
'storage_block_device',
'storage_usage',
'storage_total',
'cpu_usage',
'cpu_temp',
'cpu_id',
'is_undervolted',
],
...expandForAppName,
})) as ExtendedDevice;
let device: ExtendedDevice;
if (options.json) {
const [deviceBase, deviceComputed] = await Promise.all([
balena.models.device.get(params.uuid, {
$expand: {
device_tag: {
$select: ['tag_key', 'value'],
},
...expandForAppName.$expand,
},
}),
balena.models.device.get(params.uuid, {
$select: [
'overall_status',
'overall_progress',
'should_be_running__release',
],
}),
]);
device = {
...deviceBase,
...deviceComputed,
} as ExtendedDevice;
} else {
device = (await balena.models.device.get(params.uuid, {
$select: [
'device_name',
'id',
'overall_status',
'is_online',
'ip_address',
'mac_address',
'last_connectivity_event',
'uuid',
'supervisor_version',
'is_web_accessible',
'note',
'os_version',
'memory_usage',
'memory_total',
'public_address',
'storage_block_device',
'storage_usage',
'storage_total',
'cpu_usage',
'cpu_temp',
'cpu_id',
'is_undervolted',
],
...expandForAppName,
})) as ExtendedDevice;
}
if (options.view) {
const open = await import('open');
@ -179,6 +193,11 @@ export default class DeviceCmd extends Command {
);
}
if (options.json) {
console.log(JSON.stringify(device, null, 4));
return;
}
console.log(
getVisuals().table.vertical(device, [
`$${device.device_name}$`,

View File

@ -15,8 +15,7 @@
* limitations under the License.
*/
import { flags } from '@oclif/command';
import Command from '../../command';
import { Flags, Command } from '@oclif/core';
import * as cf from '../../utils/common-flags';
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
import { applicationIdInfo } from '../../utils/messages';
@ -29,7 +28,6 @@ interface FlagsDef {
'os-version'?: string;
drive?: string;
config?: string;
help: void;
'provisioning-key-name'?: string;
'provisioning-key-expiry-date'?: string;
}
@ -43,17 +41,17 @@ export default class DeviceInitCmd extends Command {
This command effectively combines several other balena CLI commands in one,
namely:
'balena device register'
'balena os download'
'balena os build-config' or 'balena config generate'
'balena os configure'
'balena device register'
'balena os download'
'balena os build-config' or 'balena config generate'
'balena os configure'
'balena os local flash'
Possible arguments for the '--fleet', '--os-version' and '--drive' options can
be listed respectively with the commands:
'balena fleets'
'balena os versions'
'balena fleet list'
'balena os versions'
'balena util available-drives'
If the '--fleet' or '--drive' options are omitted, interactive menus will be
@ -74,16 +72,14 @@ export default class DeviceInitCmd extends Command {
'$ balena device init --fleet myFleet --os-version 2.83.21+rev1.prod --drive /dev/disk5 --config config.json --yes',
];
public static usage = 'device init';
public static flags: flags.Input<FlagsDef> = {
public static flags = {
fleet: cf.fleet,
yes: cf.yes,
advanced: flags.boolean({
advanced: Flags.boolean({
char: 'v',
description: 'show advanced configuration options',
}),
'os-version': flags.string({
'os-version': Flags.string({
description: stripIndent`
exact version number, or a valid semver range,
or 'latest' (includes pre-releases),
@ -93,23 +89,22 @@ export default class DeviceInitCmd extends Command {
`,
}),
drive: cf.drive,
config: flags.string({
config: Flags.string({
description: 'path to the config JSON file, see `balena os build-config`',
}),
'provisioning-key-name': flags.string({
'provisioning-key-name': Flags.string({
description: 'custom key name assigned to generated provisioning api key',
}),
'provisioning-key-expiry-date': flags.string({
'provisioning-key-expiry-date': Flags.string({
description:
'expiry date assigned to generated provisioning api key (format: YYYY-MM-DD)',
}),
help: cf.help,
};
public static authenticated = true;
public async run() {
const { flags: options } = this.parse<FlagsDef, {}>(DeviceInitCmd);
const { flags: options } = await this.parse(DeviceInitCmd);
// Imports
const { promisify } = await import('util');
@ -119,25 +114,22 @@ export default class DeviceInitCmd extends Command {
tmp.setGracefulCleanup();
const { downloadOSImage } = await import('../../utils/cloud');
const { getApplication } = await import('../../utils/sdk');
const Logger = await import('../../utils/logger');
const logger = await Command.getLogger();
const logger = Logger.getLogger();
const balena = getBalenaSdk();
// Get application and
const application = (await getApplication(
balena,
options.fleet ||
(
await (await import('../../utils/patterns')).selectApplication()
).slug,
{
$expand: {
is_for__device_type: {
$select: 'slug',
const application = options.fleet
? await getApplication(balena, options.fleet, {
$select: ['id', 'slug'],
$expand: {
is_for__device_type: {
$select: 'slug',
},
},
},
},
)) as ApplicationWithDeviceType;
})
: await (await import('../../utils/patterns')).selectApplication();
// Register new device
const deviceUuid = balena.models.device.generateUniqueKey();
@ -163,7 +155,7 @@ export default class DeviceInitCmd extends Command {
try {
logger.logDebug(`Process failed, removing device ${device.uuid}`);
await balena.models.device.remove(device.uuid);
} catch (e) {
} catch {
// Ignore removal failures, and throw original error
}
throw e;

View File

@ -15,28 +15,30 @@
* limitations under the License.
*/
import { flags } from '@oclif/command';
import Command from '../../command';
import { Command } from '@oclif/core';
import * as cf from '../../utils/common-flags';
import { expandForAppName } from '../../utils/helpers';
import { getBalenaSdk, getVisuals, stripIndent } from '../../utils/lazy';
import { applicationIdInfo, jsonInfo } from '../../utils/messages';
import type { Application } from 'balena-sdk';
import type { Device, PineOptions } from 'balena-sdk';
interface ExtendedDevice extends DeviceWithDeviceType {
dashboard_url?: string;
fleet?: string | null; // 'org/name' slug
device_type?: string | null;
}
const devicesSelectFields = {
$select: [
'id',
'uuid',
'device_name',
'status',
'is_online',
'supervisor_version',
'os_version',
],
} satisfies PineOptions<Device>;
interface FlagsDef {
fleet?: string;
help: void;
json: boolean;
}
export default class DeviceListCmd extends Command {
public static aliases = ['devices'];
public static deprecateAliases = true;
export default class DevicesCmd extends Command {
public static description = stripIndent`
List all devices.
@ -49,17 +51,14 @@ export default class DevicesCmd extends Command {
${jsonInfo.split('\n').join('\n\t\t')}
`;
public static examples = [
'$ balena devices',
'$ balena devices --fleet MyFleet',
'$ balena devices -f myorg/myfleet',
'$ balena device list',
'$ balena device list --fleet MyFleet',
'$ balena device list -f myorg/myfleet',
];
public static usage = 'devices';
public static flags: flags.Input<FlagsDef> = {
public static flags = {
fleet: cf.fleet,
json: cf.json,
help: cf.help,
};
public static primary = true;
@ -67,39 +66,42 @@ export default class DevicesCmd extends Command {
public static authenticated = true;
public async run() {
const { flags: options } = this.parse<FlagsDef, {}>(DevicesCmd);
const { flags: options } = await this.parse(DeviceListCmd);
const balena = getBalenaSdk();
const devicesOptions = {
...devicesSelectFields,
...expandForAppName,
$orderby: { device_name: 'asc' },
} satisfies PineOptions<Device>;
let devices;
const devices = (
await (async () => {
if (options.fleet != null) {
const { getApplication } = await import('../../utils/sdk');
const application = await getApplication(balena, options.fleet, {
$select: 'slug',
$expand: {
owns__device: devicesOptions,
},
});
return application.owns__device;
}
if (options.fleet != null) {
const { getApplication } = await import('../../utils/sdk');
const application = await getApplication(balena, options.fleet);
devices = (await balena.models.device.getAllByApplication(
application.id,
expandForAppName,
)) as ExtendedDevice[];
} else {
devices = (await balena.models.device.getAll(
expandForAppName,
)) as ExtendedDevice[];
}
return await balena.pine.get({
resource: 'device',
options: devicesOptions,
});
})()
).map((device) => ({
...device,
dashboard_url: balena.models.device.getDashboardUrl(device.uuid),
fleet: device.belongs_to__application?.[0]?.slug || null,
uuid: options.json ? device.uuid : device.uuid.slice(0, 7),
device_type: device.is_of__device_type?.[0]?.slug || null,
}));
devices = devices.map(function (device) {
device.dashboard_url = balena.models.device.getDashboardUrl(device.uuid);
const belongsToApplication =
device.belongs_to__application as Application[];
device.fleet = belongsToApplication?.[0]?.slug || 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 fields = [
const fields: Array<keyof (typeof devices)[number]> = [
'id',
'uuid',
'device_name',

View File

@ -15,23 +15,9 @@
* 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 { Flags, Args, Command } from '@oclif/core';
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
interface FlagsDef {
enable: boolean;
disable: boolean;
status: boolean;
help?: void;
}
interface ArgsDef {
uuid: string | number;
}
export default class DeviceLocalModeCmd extends Command {
public static description = stripIndent`
Get or manage the local mode status for a device.
@ -47,38 +33,33 @@ export default class DeviceLocalModeCmd extends Command {
'$ balena device local-mode 23c73a1 --status',
];
public static args: Array<IArg<any>> = [
{
name: 'uuid',
public static args = {
uuid: Args.string({
description: 'the uuid of the device to manage',
required: true,
},
];
}),
};
public static usage = 'device local-mode <uuid>';
public static flags: flags.Input<FlagsDef> = {
enable: flags.boolean({
public static flags = {
enable: Flags.boolean({
description: 'enable local mode',
exclusive: ['disable', 'status'],
}),
disable: flags.boolean({
disable: Flags.boolean({
description: 'disable local mode',
exclusive: ['enable', 'status'],
}),
status: flags.boolean({
status: Flags.boolean({
description: 'output boolean indicating local mode status',
exclusive: ['enable', 'disable'],
}),
help: cf.help,
};
public static authenticated = true;
public async run() {
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
DeviceLocalModeCmd,
);
const { args: params, flags: options } =
await this.parse(DeviceLocalModeCmd);
const balena = getBalenaSdk();

View File

@ -15,28 +15,16 @@
* 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 { LogMessage } from 'balena-sdk';
import { IArg } from '@oclif/parser/lib/args';
interface FlagsDef {
'max-retry'?: number;
tail?: boolean;
service?: string[];
system?: boolean;
help: void;
}
interface ArgsDef {
device: string;
}
import { Flags, Args, Command } from '@oclif/core';
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
import type { LogMessage } from 'balena-sdk';
const MAX_RETRY = 1000;
export default class LogsCmd extends Command {
export default class DeviceLogsCmd extends Command {
public static aliases = ['logs'];
public static deprecateAliases = true;
public static description = stripIndent`
Show device logs.
@ -56,70 +44,64 @@ export default class LogsCmd extends Command {
Note: --service and --system flags must come after the device parameter, as per examples.
`;
public static examples = [
'$ balena logs 23c73a1',
'$ balena logs 23c73a1 --tail',
'$ balena device logs 23c73a1',
'$ balena device logs 23c73a1 --tail',
'',
'$ balena logs 192.168.0.31',
'$ balena logs 192.168.0.31 --service my-service',
'$ balena logs 192.168.0.31 --service my-service-1 --service my-service-2',
'$ balena device logs 192.168.0.31',
'$ balena device logs 192.168.0.31 --service my-service',
'$ balena device logs 192.168.0.31 --service my-service-1 --service my-service-2',
'',
'$ balena logs 23c73a1.local --system',
'$ balena logs 23c73a1.local --system --service my-service',
'$ balena device logs 23c73a1.local --system',
'$ balena device logs 23c73a1.local --system --service my-service',
];
public static args: Array<IArg<any>> = [
{
name: 'device',
public static args = {
device: Args.string({
description: 'device UUID, IP, or .local address',
required: true,
},
];
}),
};
public static usage = 'logs <device>';
public static flags: flags.Input<FlagsDef> = {
'max-retry': flags.integer({
public static flags = {
'max-retry': Flags.integer({
description: stripIndent`
Maximum number of reconnection attempts on "connection lost" errors
(use 0 to disable auto reconnection).`,
}),
tail: flags.boolean({
tail: Flags.boolean({
default: false,
description: 'continuously stream output',
char: 't',
}),
service: flags.string({
service: Flags.string({
description: stripIndent`
Reject logs not originating from this service.
This can be used in combination with --system or other --service flags.`,
char: 's',
multiple: true,
}),
system: flags.boolean({
system: Flags.boolean({
default: false,
description:
'Only show system logs. This can be used in combination with --service.',
char: 'S',
}),
help: cf.help,
};
public static primary = true;
public async run() {
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
LogsCmd,
);
const { args: params, flags: options } = await this.parse(DeviceLogsCmd);
const balena = getBalenaSdk();
const { serviceIdToName } = await import('../utils/cloud');
const { serviceIdToName } = await import('../../utils/cloud');
const { connectAndDisplayDeviceLogs, displayLogObject } = await import(
'../utils/device/logs'
'../../utils/device/logs'
);
const { validateIPAddress, validateDotLocalUrl } = await import(
'../utils/validation'
'../../utils/validation'
);
const Logger = await import('../utils/logger');
const Logger = await import('../../utils/logger');
const logger = Logger.getLogger();
@ -148,13 +130,13 @@ export default class LogsCmd extends Command {
validateDotLocalUrl(params.device)
) {
// Logs from local device
const { DeviceAPI } = await import('../utils/device/api');
const { DeviceAPI } = await import('../../utils/device/api');
const deviceApi = new DeviceAPI(logger, params.device);
logger.logDebug('Checking we can access device');
try {
await deviceApi.ping();
} catch (e) {
const { ExpectedError } = await import('../errors');
} catch {
const { ExpectedError } = await import('../../errors');
throw new ExpectedError(
`Cannot access device at address ${params.device}. Device may not be in local mode.`,
);
@ -169,8 +151,9 @@ export default class LogsCmd extends Command {
maxAttempts: 1 + (options['max-retry'] ?? MAX_RETRY),
});
} else {
const { checkLoggedIn } = await import('../../utils/patterns');
// Logs from cloud
await Command.checkLoggedIn();
await checkLoggedIn();
if (options.tail) {
const logStream = await balena.logs.subscribe(params.device, {
count: 100,

View File

@ -15,36 +15,18 @@
* limitations under the License.
*/
import type { flags } from '@oclif/command';
import type { IArg } from '@oclif/parser/lib/args';
import { Args, Command } from '@oclif/core';
import type {
BalenaSDK,
Device,
DeviceType,
PineOptions,
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 } from '../../utils/messages';
type ExtendedDevice = PineTypedResult<
Device,
typeof import('../../utils/helpers').expandForAppNameAndCpuArch
> & {
application_name?: string;
};
interface FlagsDef {
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.
@ -63,61 +45,63 @@ export default class DeviceMoveCmd extends Command {
'$ balena device move 7cf02a6 -f myorg/mynewfleet',
];
public static args: Array<IArg<any>> = [
{
name: 'uuid',
public static args = {
uuid: Args.string({
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> = {
public static flags = {
fleet: cf.fleet,
help: cf.help,
};
public static authenticated = true;
public async run() {
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
DeviceMoveCmd,
private async getDevices(balena: BalenaSDK, deviceUuids: string[]) {
const deviceOptions = {
$select: 'belongs_to__application',
$expand: {
is_of__device_type: {
$select: 'is_of__cpu_architecture',
$expand: {
is_of__cpu_architecture: {
$select: 'slug',
},
},
},
},
} satisfies PineOptions<Device>;
// TODO: Refacor once `device.get()` accepts an array of uuids`
const devices = await Promise.all(
deviceUuids.map(
(uuid) =>
balena.models.device.get(uuid, deviceOptions) as Promise<
PineTypedResult<Device, typeof deviceOptions>
>,
),
);
return devices;
}
public async run() {
const { args: params, flags: options } = await this.parse(DeviceMoveCmd);
const balena = getBalenaSdk();
const { expandForAppNameAndCpuArch } = await import('../../utils/helpers');
// Split uuids string into array of uuids
const deviceUuids = params.uuid.split(',');
// Get devices
const devices = await Promise.all(
deviceUuids.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';
}
const devices = await this.getDevices(balena, deviceUuids);
// Disambiguate application
const { getApplication } = await import('../../utils/sdk');
// Get destination application
const application = options.fleet
? await getApplication(balena, options.fleet)
? await getApplication(balena, options.fleet, { $select: ['id', 'slug'] })
: await this.interactivelySelectApplication(balena, devices);
// Move each device
@ -134,9 +118,8 @@ export default class DeviceMoveCmd extends Command {
async interactivelySelectApplication(
balena: BalenaSDK,
devices: ExtendedDevice[],
devices: Awaited<ReturnType<typeof this.getDevices>>,
) {
const { getExpandedProp } = await import('../../utils/pine');
// deduplicate the slugs
const deviceCpuArchs = Array.from(
new Set(
@ -146,46 +129,44 @@ export default class DeviceMoveCmd extends Command {
),
);
const deviceTypeOptions = {
$select: 'slug',
$expand: {
is_of__cpu_architecture: {
$select: 'slug',
},
const allCpuArches = await balena.pine.get({
resource: 'cpu_architecture',
options: {
$select: ['id', '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 compatibleCpuArchIds = allCpuArches
.filter((cpuArch) => {
return deviceCpuArchs.every((deviceCpuArch) =>
balena.models.os.isArchitectureCompatibleWith(
deviceCpuArch,
cpuArch.slug,
),
);
})
.map((deviceType) => deviceType.id);
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),
{
is_for__device_type: {
$any: {
$alias: 'dt',
$expr: {
dt: {
is_of__cpu_architecture: { $in: compatibleCpuArchIds },
},
},
},
},
},
true,
);
return application;
} catch (err) {
if (!compatibleDeviceTypeSlugs.size) {
if (!compatibleCpuArchIds.length) {
throw new ExpectedError(
`${err.message}\nDo all devices have a compatible architecture?`,
);

View File

@ -15,23 +15,15 @@
* limitations under the License.
*/
import { flags } from '@oclif/command';
import Command from '../command';
import { ExpectedError } from '../errors';
import * as cf from '../utils/common-flags';
import { getBalenaSdk, stripIndent } from '../utils/lazy';
import { Flags, Args, Command } from '@oclif/core';
import { ExpectedError } from '../../errors';
import * as cf from '../../utils/common-flags';
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
interface FlagsDef {
device?: string; // device UUID
dev?: string; // Alias for device.
help: void;
}
export default class DeviceNoteCmd extends Command {
public static aliases = ['notes'];
public static deprecateAliases = true;
interface ArgsDef {
note: string;
}
export default class NoteCmd extends Command {
public static description = stripIndent`
Set a device note.
@ -42,40 +34,30 @@ export default class NoteCmd extends Command {
`;
public static examples = [
'$ balena note "My useful note" --device 7cf02a6',
'$ cat note.txt | balena note --device 7cf02a6',
'$ balena device note "My useful note" --device 7cf02a6',
'$ cat note.txt | balena device note --device 7cf02a6',
];
public static args = [
{
name: 'note',
public static args = {
note: Args.string({
description: 'note content',
},
];
}),
};
public static usage = 'note <|note>';
public static flags: flags.Input<FlagsDef> = {
public static flags = {
device: { exclusive: ['dev'], ...cf.device },
dev: flags.string({
dev: Flags.string({
exclusive: ['device'],
hidden: true,
}),
help: cf.help,
};
public static authenticated = true;
public static readStdin = true;
public async run() {
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
NoteCmd,
);
const { args: params, flags: options } = await this.parse(DeviceNoteCmd);
params.note = params.note || this.stdin;
if (params.note.length === 0) {
if (params.note?.length === 0) {
throw new ExpectedError('Missing note content');
}
@ -88,6 +70,6 @@ export default class NoteCmd extends Command {
const balena = getBalenaSdk();
return balena.models.device.note(options.device!, params.note);
return balena.models.device.setNote(options.device, params.note ?? '');
}
}

View File

@ -15,23 +15,12 @@
* limitations under the License.
*/
import { flags } from '@oclif/command';
import type { IArg } from '@oclif/parser/lib/args';
import Command from '../../command';
import { Flags, Args, Command } from '@oclif/core';
import * as cf from '../../utils/common-flags';
import { getBalenaSdk, stripIndent, getCliForm } from '../../utils/lazy';
import type { Device } from 'balena-sdk';
import { ExpectedError } from '../../errors';
interface FlagsDef {
version?: string;
yes: boolean;
help: void;
}
interface ArgsDef {
uuid: string;
}
import { getExpandedProp } from '../../utils/pine';
export default class DeviceOsUpdateCmd extends Command {
public static description = stripIndent`
@ -48,32 +37,34 @@ export default class DeviceOsUpdateCmd extends Command {
'$ balena device os-update 23c73a1',
'$ balena device os-update 23c73a1 --version 2.101.7',
'$ balena device os-update 23c73a1 --version 2.31.0+rev1.prod',
'$ balena device os-update 23c73a1 --include-draft',
];
public static args: Array<IArg<any>> = [
{
name: 'uuid',
public static args = {
uuid: Args.string({
description: 'the uuid of the device to update',
required: true,
},
];
}),
};
public static usage = 'device os-update <uuid>';
public static flags: flags.Input<FlagsDef> = {
version: flags.string({
public static flags = {
version: Flags.string({
description: 'a balenaOS version',
exclusive: ['include-draft'],
}),
'include-draft': Flags.boolean({
description: 'include pre-release balenaOS versions',
default: false,
exclusive: ['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 { args: params, flags: options } =
await this.parse(DeviceOsUpdateCmd);
const sdk = getBalenaSdk();
@ -99,10 +90,25 @@ export default class DeviceOsUpdateCmd extends Command {
);
}
let includeDraft = options['include-draft'];
if (!includeDraft && options.version != null) {
const bSemver = await import('balena-semver');
const parsedVersion = bSemver.parse(options.version);
// When the user provides a draft version, we need to pass `includeDraft`
// to the os.getSupportedOsUpdateVersions() since w/o it the results
// will for sure not include the user provided version and the command
// would return a "not in the Host OS update targets" error.
includeDraft =
parsedVersion != null && parsedVersion.prerelease.length > 0;
}
// Get supported OS update versions
const hupVersionInfo = await sdk.models.os.getSupportedOsUpdateVersions(
is_of__device_type[0].slug,
currentOsVersion,
{
includeDraft,
},
);
if (hupVersionInfo.versions.length === 0) {
throw new ExpectedError(
@ -113,33 +119,72 @@ export default class DeviceOsUpdateCmd extends Command {
// Get target OS version
let targetOsVersion = options.version;
if (targetOsVersion != null) {
const { normalizeOsVersion } = await import('../../utils/normalization');
targetOsVersion = normalizeOsVersion(targetOsVersion);
if (!hupVersionInfo.versions.includes(targetOsVersion)) {
throw new ExpectedError(
`The provided version ${targetOsVersion} is not in the Host OS update targets for this device`,
);
}
} else {
const choices = await Promise.all(
hupVersionInfo.versions.map(async (version) => {
const takeoverRequired =
(await sdk.models.os.getOsUpdateType(
getExpandedProp(is_of__device_type, 'slug')!,
currentOsVersion,
version,
)) === 'takeover';
return {
name: `${version}${hupVersionInfo.recommended === version ? ' (recommended)' : ''}${takeoverRequired ? ' ADVANCED UPDATE: Requires disk re-partitioning with no rollback option' : ''}`,
value: version,
};
}),
);
targetOsVersion = await getCliForm().ask({
message: 'Target OS version',
type: 'list',
choices: hupVersionInfo.versions.map((version) => ({
name:
hupVersionInfo.recommended === version
? `${version} (recommended)`
: version,
value: version,
})),
choices,
});
}
const takeoverRequired =
(await sdk.models.os.getOsUpdateType(
getExpandedProp(is_of__device_type, 'slug')!,
currentOsVersion,
targetOsVersion,
)) === 'takeover';
const patterns = await import('../../utils/patterns');
// Warn the user if the update requires a takeover
if (takeoverRequired) {
await patterns.confirm(
options.yes || false,
stripIndent`Before you proceed, note that this update process is different from a regular HostOS Update:
DATA LOSS: This update requires disk re-partitioning, which will erase all data stored on the device.
NO ROLLBACK: Unlike our HostOS update mechanism, this process does not allow reverting to a previous version in case of failure.
Make sure to back up all important data before continuing. For more details, check our documentation: https://docs.balena.io/reference/OS/updates/update-process/
`,
);
}
// 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);
await sdk.models.device
.startOsUpdate(uuid, targetOsVersion, {
runDetached: true,
})
.then(() => {
console.log(
`The balena OS update has started. You can keep track of the progress via the dashboard.\n` +
`To open the dashboard page related to a device via the CLI, you can use \`balena device UUID --view\``,
);
})
.catch((error) => {
console.error(`Failed to start OS update for device ${uuid}:`, error);
});
}
}

View File

@ -15,22 +15,10 @@
* 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 { Args, Command } from '@oclif/core';
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
import { getExpandedProp } from '../../utils/pine';
interface FlagsDef {
help: void;
}
interface ArgsDef {
uuid: string;
releaseToPinTo?: string;
}
export default class DevicePinCmd extends Command {
public static description = stripIndent`
Pin a device to a release.
@ -44,34 +32,26 @@ export default class DevicePinCmd extends Command {
'$ balena device pin 7cf02a6 91165e5',
];
public static args: Array<IArg<any>> = [
{
name: 'uuid',
public static args = {
uuid: Args.string({
description: 'the uuid of the device to pin to a release',
required: true,
},
{
name: 'releaseToPinTo',
}),
releaseToPinTo: Args.string({
description: 'the commit of the release for the device to get pinned to',
},
];
public static usage = 'device pin <uuid> [releaseToPinTo]';
public static flags: flags.Input<FlagsDef> = {
help: cf.help,
}),
};
public static authenticated = true;
public async run() {
const { args: params } = this.parse<FlagsDef, ArgsDef>(DevicePinCmd);
const { args: params } = await this.parse(DevicePinCmd);
const balena = getBalenaSdk();
const device = await balena.models.device.get(params.uuid, {
$expand: {
should_be_running__release: {
is_pinned_on__release: {
$select: 'commit',
},
belongs_to__application: {
@ -81,7 +61,7 @@ export default class DevicePinCmd extends Command {
});
const pinnedRelease = getExpandedProp(
device.should_be_running__release,
device.is_pinned_on__release,
'commit',
);
const appSlug = getExpandedProp(device.belongs_to__application, 'slug');
@ -94,7 +74,7 @@ export default class DevicePinCmd extends Command {
pinnedRelease
? `This device is currently pinned to ${pinnedRelease}.`
: 'This device is not currently pinned to any release.'
} \n\nTo see a list of all releases this device can be pinned to, run \`balena releases ${appSlug}\`.`,
} \n\nTo see a list of all releases this device can be pinned to, run \`balena release list ${appSlug}\`.`,
);
} else {
await balena.models.device.pinToRelease(params.uuid, releaseToPinTo);

View File

@ -15,24 +15,10 @@
* limitations under the License.
*/
import { flags } from '@oclif/command';
import type { IArg } from '@oclif/parser/lib/args';
import Command from '../../command';
import { Flags, Args, Command } from '@oclif/core';
import { ExpectedError } from '../../errors';
import * as cf from '../../utils/common-flags';
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
interface FlagsDef {
enable: boolean;
disable: boolean;
status: boolean;
help?: void;
}
interface ArgsDef {
uuid: string;
}
export default class DevicePublicUrlCmd extends Command {
public static description = stripIndent`
Get or manage the public URL for a device.
@ -49,38 +35,33 @@ export default class DevicePublicUrlCmd extends Command {
'$ balena device public-url 23c73a1 --status',
];
public static args: Array<IArg<any>> = [
{
name: 'uuid',
public static args = {
uuid: Args.string({
description: 'the uuid of the device to manage',
required: true,
},
];
}),
};
public static usage = 'device public-url <uuid>';
public static flags: flags.Input<FlagsDef> = {
enable: flags.boolean({
public static flags = {
enable: Flags.boolean({
description: 'enable the public URL',
exclusive: ['disable', 'status'],
}),
disable: flags.boolean({
disable: Flags.boolean({
description: 'disable the public URL',
exclusive: ['enable', 'status'],
}),
status: flags.boolean({
status: Flags.boolean({
description: 'determine if public URL is enabled',
exclusive: ['enable', 'disable'],
}),
help: cf.help,
};
public static authenticated = true;
public async run() {
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
DevicePublicUrlCmd,
);
const { args: params, flags: options } =
await this.parse(DevicePublicUrlCmd);
const balena = getBalenaSdk();

View File

@ -15,20 +15,9 @@
* 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 { Args, Command } from '@oclif/core';
import { getBalenaSdk, getCliUx, stripIndent } from '../../utils/lazy';
interface FlagsDef {
help: void;
}
interface ArgsDef {
uuid: string;
}
export default class DevicePurgeCmd extends Command {
public static description = stripIndent`
Purge data from a device.
@ -44,24 +33,17 @@ export default class DevicePurgeCmd extends Command {
'$ balena device purge 55d43b3,23c73a1',
];
public static usage = 'device purge <uuid>';
public static args: Array<IArg<any>> = [
{
name: 'uuid',
public static args = {
uuid: Args.string({
description: 'comma-separated list (no blank spaces) of device UUIDs',
required: true,
},
];
public static flags: flags.Input<FlagsDef> = {
help: cf.help,
}),
};
public static authenticated = true;
public async run() {
const { args: params } = this.parse<FlagsDef, ArgsDef>(DevicePurgeCmd);
const { args: params } = await this.parse(DevicePurgeCmd);
const balena = getBalenaSdk();
const ux = getCliUx();

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