mirror of
https://github.com/balena-io/balena-cli.git
synced 2025-03-14 08:16:33 +00:00
Compare commits
51 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
650e896f70 | ||
|
a9042124ea | ||
|
d24d78dac7 | ||
|
42c50ef8ae | ||
|
ba4b9bd447 | ||
|
02c0ea5b59 | ||
|
bc3558dd8e | ||
|
aad62d1ccd | ||
|
ecc6f80164 | ||
|
c0fd1e3886 | ||
|
9d3120b144 | ||
|
ed0e03ddb2 | ||
|
8fe6d6c026 | ||
|
727033ae14 | ||
|
c19ce6a905 | ||
|
1a33029738 | ||
|
043bc48a1c | ||
|
a10156a441 | ||
|
4f665f43d2 | ||
|
9f097a96f5 | ||
|
64d1943804 | ||
|
666ce876e6 | ||
|
e01184080f | ||
|
93039b010d | ||
|
795259bf30 | ||
|
fa134d2d39 | ||
|
bef5221ed8 | ||
|
72d6db796c | ||
|
e848eb63ee | ||
|
6f0f7350cf | ||
|
07a88c700e | ||
|
9cae66bd92 | ||
|
cddea24cef | ||
|
b1c246c0b4 | ||
|
00b4d57a03 | ||
|
2cba82e914 | ||
|
1352c5c823 | ||
|
c86eb97010 | ||
|
53be743b9d | ||
|
d9f21b4c3f | ||
|
261ab398dd | ||
|
f28a9992e4 | ||
|
29e7827eb1 | ||
|
1d77cf3665 | ||
|
017c767f61 | ||
|
7d79c4e24b | ||
|
60bc5092e0 | ||
|
a33a794931 | ||
|
f0ede6fca2 | ||
|
dbe177e766 | ||
|
09f80730a8 |
@ -1,2 +0,0 @@
|
||||
/completion/*
|
||||
/bin/*
|
21
.eslintrc.js
21
.eslintrc.js
@ -1,21 +0,0 @@
|
||||
module.exports = {
|
||||
extends: ['./node_modules/@balena/lint/config/.eslintrc.js'],
|
||||
parserOptions: {
|
||||
project: 'tsconfig.dev.json',
|
||||
},
|
||||
root: true,
|
||||
rules: {
|
||||
ignoreDefinitionFiles: 0,
|
||||
// to avoid the `warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion`
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
'@typescript-eslint/no-shadow': 'off',
|
||||
'@typescript-eslint/no-var-requires': 'off',
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
paths: ['resin-cli-visuals', 'chalk', 'common-tags', 'resin-cli-form'],
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
|
||||
},
|
||||
};
|
6
.github/actions/publish/action.yml
vendored
6
.github/actions/publish/action.yml
vendored
@ -39,7 +39,7 @@ runs:
|
||||
run: tar -xf ${{ runner.temp }}/custom.tgz
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
|
||||
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
|
||||
with:
|
||||
node-version: ${{ inputs.NODE_VERSION }}
|
||||
cache: npm
|
||||
@ -94,7 +94,7 @@ 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 }}
|
||||
|
||||
@ -135,7 +135,7 @@ runs:
|
||||
XCODE_APP_LOADER_TEAM_ID: ${{ inputs.XCODE_APP_LOADER_TEAM_ID }}
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4
|
||||
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4
|
||||
with:
|
||||
name: gh-release-${{ github.event.pull_request.head.sha || github.event.head_commit.id }}-${{ strategy.job-index }}
|
||||
path: dist
|
||||
|
4
.github/actions/test/action.yml
vendored
4
.github/actions/test/action.yml
vendored
@ -26,7 +26,7 @@ runs:
|
||||
steps:
|
||||
# https://github.com/actions/setup-node#caching-global-packages-data
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
|
||||
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
|
||||
with:
|
||||
node-version: ${{ inputs.NODE_VERSION }}
|
||||
cache: npm
|
||||
@ -58,7 +58,7 @@ runs:
|
||||
run: tar --exclude-vcs -acf ${{ runner.temp }}/custom.tgz .
|
||||
|
||||
- name: Upload custom artifact
|
||||
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4
|
||||
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4
|
||||
with:
|
||||
name: custom-${{ github.event.pull_request.head.sha || github.event.head_commit.id }}-${{ runner.os }}-${{ runner.arch }}
|
||||
path: ${{ runner.temp }}/custom.tgz
|
||||
|
@ -1,3 +1,534 @@
|
||||
- commits:
|
||||
- subject: Add support for new requirement labels feature
|
||||
hash: 42c50ef8aed110b317a0472d928bf75e372b4c0b
|
||||
body: |
|
||||
Updates @balena/compose to v7 to include this new feature.
|
||||
footer:
|
||||
See: https://balena.fibery.io/Work/Project/Refactoring-container-contracts-1205
|
||||
see: https://balena.fibery.io/Work/Project/Refactoring-container-contracts-1205
|
||||
Depends-on: https://github.com/balena-io-modules/balena-compose/pull/64
|
||||
depends-on: https://github.com/balena-io-modules/balena-compose/pull/64
|
||||
Change-type: minor
|
||||
change-type: minor
|
||||
author: Felipe Lalanne
|
||||
nested: []
|
||||
version: 21.1.0
|
||||
title: ""
|
||||
date: 2025-03-12T19:34:17.610Z
|
||||
- commits:
|
||||
- subject: Drop support for OS versions <2.14.0
|
||||
hash: aad62d1ccd11ebb69b1035d5b95aef93d384bfd5
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: major
|
||||
change-type: major
|
||||
author: myarmolinsky
|
||||
nested: []
|
||||
- subject: "api-key generate: Add required argument `expiryDate`"
|
||||
hash: ecc6f80164fca3c0cde42b140b6d7404abe8c877
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: major
|
||||
change-type: major
|
||||
author: myarmolinsky
|
||||
nested: []
|
||||
- subject: Update `balena-preload` to 18.0.1
|
||||
hash: 9d3120b144c2c017eda55463b034f1561d264213
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: myarmolinsky
|
||||
nested: []
|
||||
- subject: Add dependency `date-fns`
|
||||
hash: ed0e03ddb274da294f719dc0e307ec37591e10d7
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: myarmolinsky
|
||||
nested: []
|
||||
- subject: Update `balena-sdk` to 21.2.1
|
||||
hash: 8fe6d6c0268f69bcf3bcac3c57470272b959e9b0
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: myarmolinsky
|
||||
nested: []
|
||||
version: 21.0.0
|
||||
title: ""
|
||||
date: 2025-03-11T14:42:28.479Z
|
||||
- commits:
|
||||
- subject: Update TypeScript to 5.8.2
|
||||
hash: a10156a441b737275cabfb03bd10bfc5aba7bc88
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: Thodoris Greasidis
|
||||
nested: []
|
||||
version: 20.2.10
|
||||
title: ""
|
||||
date: 2025-03-10T17:33:09.548Z
|
||||
- commits:
|
||||
- subject: Fix CORS issue with X-Balena-Client header
|
||||
hash: 64d19438042921e89c522f022327ead85b286e9f
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: patch
|
||||
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
|
||||
see: https://balena.fibery.io/Work/Project/Extend-the-X-Balena-Client-header-to-include-the-UI-CLI-version-as-well-1174
|
||||
author: Thodoris Greasidis
|
||||
nested: []
|
||||
version: 20.2.9
|
||||
title: ""
|
||||
date: 2025-02-26T12:52:06.672Z
|
||||
- commits:
|
||||
- subject: Update balena-config-json dependency and fix test
|
||||
hash: 93039b010db15fbf1c0d17d4ed8f0db554064de4
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
Signed-off-by: Ken Bannister <kb2ma@runbox.com>
|
||||
signed-off-by: Ken Bannister <kb2ma@runbox.com>
|
||||
author: Ken Bannister
|
||||
nested: []
|
||||
version: 20.2.8
|
||||
title: ""
|
||||
date: 2025-02-26T00:22:14.010Z
|
||||
- commits:
|
||||
- subject: Use the CLI version in the X-Balena-Client header
|
||||
hash: bef5221ed891db12a0b760f12fc9654e2f4e241b
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: patch
|
||||
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
|
||||
see: https://balena.fibery.io/Work/Project/Extend-the-X-Balena-Client-header-to-include-the-UI-CLI-version-as-well-1174
|
||||
author: Thodoris Greasidis
|
||||
nested: []
|
||||
version: 20.2.7
|
||||
title: ""
|
||||
date: 2025-02-25T20:21:00.603Z
|
||||
- commits:
|
||||
- subject: Update actions/upload-artifact digest to 4cec3d8
|
||||
hash: 6f0f7350cf65c35abd099a901266821c218478eb
|
||||
body: |
|
||||
Update actions/upload-artifact
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: balena-renovate[bot]
|
||||
nested: []
|
||||
version: 20.2.6
|
||||
title: ""
|
||||
date: 2025-02-25T19:13:48.297Z
|
||||
- commits:
|
||||
- subject: Update actions/setup-node digest to 1d0ff46
|
||||
hash: cddea24cefdfef475731e0a7d2bdec4992959a6b
|
||||
body: |
|
||||
Update actions/setup-node
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: balena-renovate[bot]
|
||||
nested: []
|
||||
version: 20.2.5
|
||||
title: ""
|
||||
date: 2025-02-25T18:10:47.617Z
|
||||
- commits:
|
||||
- subject: Pin docker-modem and dockerode to avoid regression
|
||||
hash: 2cba82e914c720e75b68bd4370a2a92b4d4a7ba0
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
Signed-off-by: Ken Bannister <kb2ma@runbox.com>
|
||||
signed-off-by: Ken Bannister <kb2ma@runbox.com>
|
||||
author: Ken Bannister
|
||||
nested: []
|
||||
version: 20.2.4
|
||||
title: ""
|
||||
date: 2025-02-25T17:17:00.607Z
|
||||
- commits:
|
||||
- subject: Remove unused old eslint version files
|
||||
hash: 53be743b9dcecbb2f0d8841b6663e7af1a9006c3
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: Otavio Jacobi
|
||||
nested: []
|
||||
version: 20.2.3
|
||||
title: ""
|
||||
date: 2025-01-15T18:21:02.810Z
|
||||
- commits:
|
||||
- subject: Use the promises namespace of balena-image-fs
|
||||
hash: 29e7827eb1dbe4b0395df51f09cea38c3b2fb2e4
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: Thodoris Greasidis
|
||||
nested: []
|
||||
- subject: Update balena-device-init to 8.1.3 & balena-image-fs to 7.3.0
|
||||
hash: 1d77cf36652eaca007a25f6ebb85c8509662d576
|
||||
body: |
|
||||
Update balena-device-init from 8.1.0 to 8.1.3
|
||||
Update balena-image-fs from 7.0.6 to 7.3.0
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: Thodoris Greasidis
|
||||
nested:
|
||||
- commits:
|
||||
- subject: Drop Bluebird from devDependencies
|
||||
hash: e4b5c71032112664ba8dac4c9edc5dad5445818d
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: Thodoris Greasidis
|
||||
nested: []
|
||||
- subject: "flowzone: Remove empty with clause"
|
||||
hash: e83b4ef55eeebffb86d0bcda78dd45ee0651c76f
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: Thodoris Greasidis
|
||||
nested: []
|
||||
- subject: Add the promises namespace as part of the exposed fs
|
||||
hash: 9b73f44020de213a682afc21092e20caf68eaff8
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: minor
|
||||
change-type: minor
|
||||
author: Thodoris Greasidis
|
||||
nested: []
|
||||
version: balena-image-fs-7.3.0
|
||||
title: ""
|
||||
date: 2025-01-06T14:31:31.244Z
|
||||
- commits:
|
||||
- subject: Update dependency @types/node to v20
|
||||
hash: 4a5f55ae8752b1b28638d3f4016910d5b2057d80
|
||||
body: |
|
||||
Update @types/node from 18.11.18 to 20.10.6
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: Self-hosted Renovate Bot
|
||||
nested: []
|
||||
version: balena-image-fs-7.2.2
|
||||
title: ""
|
||||
date: 2024-01-02T18:50:24.990Z
|
||||
- commits:
|
||||
- subject: Remove repo config from flowzone.yml
|
||||
hash: 3e0053a097a04c1d0c47139bc53787f07bfeb014
|
||||
body: |
|
||||
This functionality is being deprecated in Flowzone.
|
||||
|
||||
See: https://github.com/product-os/flowzone/pull/833
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
Signed-off-by: Kyle Harding <kyle@balena.io>
|
||||
signed-off-by: Kyle Harding <kyle@balena.io>
|
||||
author: Kyle Harding
|
||||
nested: []
|
||||
version: balena-image-fs-7.2.1
|
||||
title: ""
|
||||
date: 2023-12-19T21:54:42.129Z
|
||||
- commits:
|
||||
- subject: Add support for Node 18
|
||||
hash: 2a3bef60d9688dce26bd1c9546a28c98cf6d2566
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: minor
|
||||
change-type: minor
|
||||
author: Akis Kesoglou
|
||||
nested: []
|
||||
version: balena-image-fs-7.2.0
|
||||
title: ""
|
||||
date: 2023-01-20T14:27:37.169Z
|
||||
- commits:
|
||||
- subject: Update dependencies
|
||||
hash: 9acc4bd2e793076095880f1924f8540b4d95fa9c
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: ab77
|
||||
nested: []
|
||||
version: balena-image-fs-7.1.2
|
||||
title: ""
|
||||
date: 2023-01-05T22:29:15.022Z
|
||||
- commits:
|
||||
- subject: Update dependency jsdoc-to-markdown to 8.0.0
|
||||
hash: 5cf71efa734819263bd75c9938cb4367f90e1391
|
||||
body: |
|
||||
Update jsdoc-to-markdown to 8.0.0
|
||||
|
||||
Update jsdoc-to-markdown from 7.1.1 to 8.0.0
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: Renovate Bot
|
||||
nested: []
|
||||
version: balena-image-fs-7.1.1
|
||||
title: ""
|
||||
date: 2022-12-20T02:52:28.901Z
|
||||
- commits:
|
||||
- subject: update dependencies
|
||||
hash: 71a5bb92caa0658e45d1fb36e8652ca5ea50dee9
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: minor
|
||||
change-type: minor
|
||||
author: Zane Hitchcox
|
||||
nested: []
|
||||
version: balena-image-fs-7.1.0
|
||||
title: ""
|
||||
date: 2022-12-13T00:03:20.006Z
|
||||
- commits:
|
||||
- subject: "README: Remove the travisci badge"
|
||||
hash: 3602a9c0c503502229d12cc1ec1de5bbcbc1b13c
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: Thodoris Greasidis
|
||||
nested: []
|
||||
version: balena-device-init-8.1.3
|
||||
title: ""
|
||||
date: 2025-01-09T21:25:00.155Z
|
||||
- commits:
|
||||
- subject: Use the promises namespace of balena-image-fs
|
||||
hash: de0af086c5d9124e4bbe5d66bf9aafe0f6c5f11b
|
||||
body: |
|
||||
Update balena-image-fs from 7.0.6 to 7.3.0
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: Thodoris Greasidis
|
||||
nested:
|
||||
- commits:
|
||||
- subject: Drop Bluebird from devDependencies
|
||||
hash: e4b5c71032112664ba8dac4c9edc5dad5445818d
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: Thodoris Greasidis
|
||||
nested: []
|
||||
- subject: "flowzone: Remove empty with clause"
|
||||
hash: e83b4ef55eeebffb86d0bcda78dd45ee0651c76f
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: Thodoris Greasidis
|
||||
nested: []
|
||||
- subject: Add the promises namespace as part of the exposed fs
|
||||
hash: 9b73f44020de213a682afc21092e20caf68eaff8
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: minor
|
||||
change-type: minor
|
||||
author: Thodoris Greasidis
|
||||
nested: []
|
||||
version: balena-image-fs-7.3.0
|
||||
title: ""
|
||||
date: 2025-01-06T14:31:31.244Z
|
||||
- commits:
|
||||
- subject: Update dependency @types/node to v20
|
||||
hash: 4a5f55ae8752b1b28638d3f4016910d5b2057d80
|
||||
body: |
|
||||
Update @types/node from 18.11.18 to 20.10.6
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: Self-hosted Renovate Bot
|
||||
nested: []
|
||||
version: balena-image-fs-7.2.2
|
||||
title: ""
|
||||
date: 2024-01-02T18:50:24.990Z
|
||||
- commits:
|
||||
- subject: Remove repo config from flowzone.yml
|
||||
hash: 3e0053a097a04c1d0c47139bc53787f07bfeb014
|
||||
body: |
|
||||
This functionality is being deprecated in Flowzone.
|
||||
|
||||
See: https://github.com/product-os/flowzone/pull/833
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
Signed-off-by: Kyle Harding <kyle@balena.io>
|
||||
signed-off-by: Kyle Harding <kyle@balena.io>
|
||||
author: Kyle Harding
|
||||
nested: []
|
||||
version: balena-image-fs-7.2.1
|
||||
title: ""
|
||||
date: 2023-12-19T21:54:42.129Z
|
||||
- commits:
|
||||
- subject: Add support for Node 18
|
||||
hash: 2a3bef60d9688dce26bd1c9546a28c98cf6d2566
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: minor
|
||||
change-type: minor
|
||||
author: Akis Kesoglou
|
||||
nested: []
|
||||
version: balena-image-fs-7.2.0
|
||||
title: ""
|
||||
date: 2023-01-20T14:27:37.169Z
|
||||
- commits:
|
||||
- subject: Update dependencies
|
||||
hash: 9acc4bd2e793076095880f1924f8540b4d95fa9c
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: ab77
|
||||
nested: []
|
||||
version: balena-image-fs-7.1.2
|
||||
title: ""
|
||||
date: 2023-01-05T22:29:15.022Z
|
||||
- commits:
|
||||
- subject: Update dependency jsdoc-to-markdown to 8.0.0
|
||||
hash: 5cf71efa734819263bd75c9938cb4367f90e1391
|
||||
body: |
|
||||
Update jsdoc-to-markdown to 8.0.0
|
||||
|
||||
Update jsdoc-to-markdown from 7.1.1 to 8.0.0
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: Renovate Bot
|
||||
nested: []
|
||||
version: balena-image-fs-7.1.1
|
||||
title: ""
|
||||
date: 2022-12-20T02:52:28.901Z
|
||||
- commits:
|
||||
- subject: update dependencies
|
||||
hash: 71a5bb92caa0658e45d1fb36e8652ca5ea50dee9
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: minor
|
||||
change-type: minor
|
||||
author: Zane Hitchcox
|
||||
nested: []
|
||||
version: balena-image-fs-7.1.0
|
||||
title: ""
|
||||
date: 2022-12-13T00:03:20.006Z
|
||||
version: balena-device-init-8.1.2
|
||||
title: ""
|
||||
date: 2025-01-09T20:28:30.604Z
|
||||
- commits:
|
||||
- subject: Convert some parts to async await and simplify
|
||||
hash: eb1105cd738998bae9c3dd604a8d25f71eb38e19
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: Thodoris Greasidis
|
||||
nested: []
|
||||
- subject: Avoid unnecessary destructuring
|
||||
hash: 4cea6b650ec1c911cf2fc12a4a1dc410c0e7d075
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: Thodoris Greasidis
|
||||
nested: []
|
||||
version: balena-device-init-8.1.1
|
||||
title: ""
|
||||
date: 2025-01-06T06:37:04.147Z
|
||||
version: 20.2.2
|
||||
title: ""
|
||||
date: 2025-01-12T14:49:03.225Z
|
||||
- commits:
|
||||
- subject: Update balena-preload to 17.0.0
|
||||
hash: 60bc5092e0d6014aecf57d157cac536b3c645f0f
|
||||
body: |
|
||||
Update balena-preload from 16.0.0 to 17.0.0
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: Thodoris Greasidis
|
||||
nested:
|
||||
- commits:
|
||||
- subject: Improve typings
|
||||
hash: 67f0f3e9e3b4b37fbaeef2843dc4171a7d661c41
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: Thodoris Greasidis
|
||||
nested: []
|
||||
- subject: Stop returning Bluebird promises & drop it from the dependencies
|
||||
hash: 85375cbc1fdb0ce1ad08756f178ed55596e606d9
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: major
|
||||
change-type: major
|
||||
author: Thodoris Greasidis
|
||||
nested: []
|
||||
version: balena-preload-17.0.0
|
||||
title: ""
|
||||
date: 2024-10-21T16:20:33.486Z
|
||||
version: 20.2.1
|
||||
title: ""
|
||||
date: 2025-01-01T18:04:56.723Z
|
||||
- commits:
|
||||
- subject: "os configure: Give precedence to the boot partition located in the
|
||||
image over the device-type.json contents"
|
||||
hash: dbe177e76639040c5fac49746fbbcee2e3360d0a
|
||||
body: |
|
||||
Update balena-device-init from 8.0.0 to 8.1.0
|
||||
footer:
|
||||
Change-type: minor
|
||||
change-type: minor
|
||||
author: Thodoris Greasidis
|
||||
nested:
|
||||
- commits:
|
||||
- subject: Try to find the boot partition by inspecting the image
|
||||
hash: de53f11c56133bf2757c5361f8dbc6afa9e826fc
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: minor
|
||||
change-type: minor
|
||||
author: Thodoris Greasidis
|
||||
nested: []
|
||||
version: balena-device-init-8.1.0
|
||||
title: ""
|
||||
date: 2024-12-30T12:41:49.474Z
|
||||
- commits:
|
||||
- subject: Drop the unnecessary eslint.config.js
|
||||
hash: 91d587f34bf985bf65e6c21278e7cd70f9281656
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: Thodoris Greasidis
|
||||
nested: []
|
||||
- subject: "packacke.json: Explicitly set type commonjs"
|
||||
hash: f6a0be1d12f09d7d910e5ae35f48f1268542a74e
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: Thodoris Greasidis
|
||||
nested: []
|
||||
version: balena-device-init-8.0.1
|
||||
title: ""
|
||||
date: 2024-12-19T13:41:14.170Z
|
||||
version: 20.2.0
|
||||
title: ""
|
||||
date: 2024-12-31T18:41:45.907Z
|
||||
- commits:
|
||||
- subject: Add more realistic os configure tests
|
||||
hash: 305d65d5ed07cce767599ac4e5dd131e2a87d10d
|
||||
|
165
CHANGELOG.md
165
CHANGELOG.md
@ -4,6 +4,171 @@ All notable changes to this project will be documented in this file
|
||||
automatically by Versionist. DO NOT EDIT THIS FILE MANUALLY!
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## 21.1.0 - 2025-03-12
|
||||
|
||||
* Add support for new requirement labels feature [Felipe Lalanne]
|
||||
|
||||
## 21.0.0 - 2025-03-11
|
||||
|
||||
* Drop support for OS versions <2.14.0 [myarmolinsky]
|
||||
* api-key generate: Add required argument `expiryDate` [myarmolinsky]
|
||||
* Update `balena-preload` to 18.0.1 [myarmolinsky]
|
||||
* Add dependency `date-fns` [myarmolinsky]
|
||||
* Update `balena-sdk` to 21.2.1 [myarmolinsky]
|
||||
|
||||
## 20.2.10 - 2025-03-10
|
||||
|
||||
* Update TypeScript to 5.8.2 [Thodoris Greasidis]
|
||||
|
||||
## 20.2.9 - 2025-02-26
|
||||
|
||||
* Fix CORS issue with X-Balena-Client header [Thodoris Greasidis]
|
||||
|
||||
## 20.2.8 - 2025-02-26
|
||||
|
||||
* Update balena-config-json dependency and fix test [Ken Bannister]
|
||||
|
||||
## 20.2.7 - 2025-02-25
|
||||
|
||||
* Use the CLI version in the X-Balena-Client header [Thodoris Greasidis]
|
||||
|
||||
## 20.2.6 - 2025-02-25
|
||||
|
||||
* Update actions/upload-artifact digest to 4cec3d8 [balena-renovate[bot]]
|
||||
|
||||
## 20.2.5 - 2025-02-25
|
||||
|
||||
* Update actions/setup-node digest to 1d0ff46 [balena-renovate[bot]]
|
||||
|
||||
## 20.2.4 - 2025-02-25
|
||||
|
||||
* Pin docker-modem and dockerode to avoid regression [Ken Bannister]
|
||||
|
||||
## 20.2.3 - 2025-01-15
|
||||
|
||||
* Remove unused old eslint version files [Otavio Jacobi]
|
||||
|
||||
## 20.2.2 - 2025-01-12
|
||||
|
||||
* Use the promises namespace of balena-image-fs [Thodoris Greasidis]
|
||||
|
||||
<details>
|
||||
<summary> Update balena-device-init to 8.1.3 & balena-image-fs to 7.3.0 [Thodoris Greasidis] </summary>
|
||||
|
||||
> ### balena-image-fs-7.3.0 - 2025-01-06
|
||||
>
|
||||
> * Drop Bluebird from devDependencies [Thodoris Greasidis]
|
||||
> * flowzone: Remove empty with clause [Thodoris Greasidis]
|
||||
> * Add the promises namespace as part of the exposed fs [Thodoris Greasidis]
|
||||
>
|
||||
> ### balena-image-fs-7.2.2 - 2024-01-02
|
||||
>
|
||||
> * Update dependency @types/node to v20 [Self-hosted Renovate Bot]
|
||||
>
|
||||
> ### balena-image-fs-7.2.1 - 2023-12-19
|
||||
>
|
||||
> * Remove repo config from flowzone.yml [Kyle Harding]
|
||||
>
|
||||
> ### balena-image-fs-7.2.0 - 2023-01-20
|
||||
>
|
||||
> * Add support for Node 18 [Akis Kesoglou]
|
||||
>
|
||||
> ### balena-image-fs-7.1.2 - 2023-01-05
|
||||
>
|
||||
> * Update dependencies [ab77]
|
||||
>
|
||||
> ### balena-image-fs-7.1.1 - 2022-12-20
|
||||
>
|
||||
> * Update dependency jsdoc-to-markdown to 8.0.0 [Renovate Bot]
|
||||
>
|
||||
> ### balena-image-fs-7.1.0 - 2022-12-13
|
||||
>
|
||||
> * update dependencies [Zane Hitchcox]
|
||||
>
|
||||
> ### balena-device-init-8.1.3 - 2025-01-09
|
||||
>
|
||||
> * README: Remove the travisci badge [Thodoris Greasidis]
|
||||
>
|
||||
> ### balena-device-init-8.1.2 - 2025-01-09
|
||||
>
|
||||
>
|
||||
> <details>
|
||||
> <summary> Use the promises namespace of balena-image-fs [Thodoris Greasidis] </summary>
|
||||
>
|
||||
>> #### balena-image-fs-7.3.0 - 2025-01-06
|
||||
>>
|
||||
>> * Drop Bluebird from devDependencies [Thodoris Greasidis]
|
||||
>> * flowzone: Remove empty with clause [Thodoris Greasidis]
|
||||
>> * Add the promises namespace as part of the exposed fs [Thodoris Greasidis]
|
||||
>>
|
||||
>> #### balena-image-fs-7.2.2 - 2024-01-02
|
||||
>>
|
||||
>> * Update dependency @types/node to v20 [Self-hosted Renovate Bot]
|
||||
>>
|
||||
>> #### balena-image-fs-7.2.1 - 2023-12-19
|
||||
>>
|
||||
>> * Remove repo config from flowzone.yml [Kyle Harding]
|
||||
>>
|
||||
>> #### balena-image-fs-7.2.0 - 2023-01-20
|
||||
>>
|
||||
>> * Add support for Node 18 [Akis Kesoglou]
|
||||
>>
|
||||
>> #### balena-image-fs-7.1.2 - 2023-01-05
|
||||
>>
|
||||
>> * Update dependencies [ab77]
|
||||
>>
|
||||
>> #### balena-image-fs-7.1.1 - 2022-12-20
|
||||
>>
|
||||
>> * Update dependency jsdoc-to-markdown to 8.0.0 [Renovate Bot]
|
||||
>>
|
||||
>> #### balena-image-fs-7.1.0 - 2022-12-13
|
||||
>>
|
||||
>> * update dependencies [Zane Hitchcox]
|
||||
>>
|
||||
>
|
||||
> </details>
|
||||
>
|
||||
>
|
||||
> ### balena-device-init-8.1.1 - 2025-01-06
|
||||
>
|
||||
> * Convert some parts to async await and simplify [Thodoris Greasidis]
|
||||
> * Avoid unnecessary destructuring [Thodoris Greasidis]
|
||||
>
|
||||
|
||||
</details>
|
||||
|
||||
## 20.2.1 - 2025-01-01
|
||||
|
||||
|
||||
<details>
|
||||
<summary> Update balena-preload to 17.0.0 [Thodoris Greasidis] </summary>
|
||||
|
||||
> ### balena-preload-17.0.0 - 2024-10-21
|
||||
>
|
||||
> * Improve typings [Thodoris Greasidis]
|
||||
> * Stop returning Bluebird promises & drop it from the dependencies [Thodoris Greasidis]
|
||||
>
|
||||
|
||||
</details>
|
||||
|
||||
## 20.2.0 - 2024-12-31
|
||||
|
||||
|
||||
<details>
|
||||
<summary> os configure: Give precedence to the boot partition located in the image over the device-type.json contents [Thodoris Greasidis] </summary>
|
||||
|
||||
> ### balena-device-init-8.1.0 - Invalid date
|
||||
>
|
||||
> * Try to find the boot partition by inspecting the image [Thodoris Greasidis]
|
||||
>
|
||||
> ### balena-device-init-8.0.1 - 2024-12-19
|
||||
>
|
||||
> * Drop the unnecessary eslint.config.js [Thodoris Greasidis]
|
||||
> * packacke.json: Explicitly set type commonjs [Thodoris Greasidis]
|
||||
>
|
||||
|
||||
</details>
|
||||
|
||||
## 20.1.6 - 2024-12-30
|
||||
|
||||
* Add more realistic os configure tests [Thodoris Greasidis]
|
||||
|
@ -305,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', {
|
||||
|
@ -326,6 +326,8 @@ or to authenticate requests to the API with an 'Authorization: Bearer <key>' hea
|
||||
Examples:
|
||||
|
||||
$ balena api-key generate "Jenkins Key"
|
||||
$ balena api-key generate "Jenkins Key" 2025-10-30
|
||||
$ balena api-key generate "Jenkins Key" never
|
||||
|
||||
### Arguments
|
||||
|
||||
@ -333,6 +335,10 @@ Examples:
|
||||
|
||||
the API key name
|
||||
|
||||
#### EXPIRYDATE
|
||||
|
||||
the expiry date of the API key as an ISO date string, or "never" for no expiry
|
||||
|
||||
## api-key list
|
||||
|
||||
### Aliases
|
||||
|
1115
npm-shrinkwrap.json
generated
1115
npm-shrinkwrap.json
generated
File diff suppressed because it is too large
Load Diff
24
package.json
24
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "balena-cli",
|
||||
"version": "20.1.6",
|
||||
"version": "21.1.0",
|
||||
"description": "The official balena Command Line Interface",
|
||||
"main": "./build/app.js",
|
||||
"homepage": "https://github.com/balena-io/balena-cli",
|
||||
@ -58,6 +58,7 @@
|
||||
"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",
|
||||
"pretest": "npm run build",
|
||||
"test": "npm run test:shrinkwrap && npm run test:core",
|
||||
@ -186,21 +187,21 @@
|
||||
"sinon": "^19.0.0",
|
||||
"string-to-stream": "^3.0.1",
|
||||
"ts-node": "^10.4.0",
|
||||
"typescript": "^5.7.2"
|
||||
"typescript": "^5.8.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@balena/compose": "^6.0.0",
|
||||
"@balena/compose": "^7.0.1",
|
||||
"@balena/dockerignore": "^1.0.2",
|
||||
"@balena/env-parsing": "^1.1.8",
|
||||
"@balena/es-version": "^1.0.1",
|
||||
"@oclif/core": "^4.1.0",
|
||||
"@sentry/node": "^6.16.1",
|
||||
"balena-config-json": "^4.2.0",
|
||||
"balena-device-init": "^8.0.0",
|
||||
"balena-config-json": "^4.2.2",
|
||||
"balena-device-init": "^8.1.3",
|
||||
"balena-errors": "^4.7.3",
|
||||
"balena-image-fs": "^7.0.6",
|
||||
"balena-preload": "^16.0.0",
|
||||
"balena-sdk": "^20.8.0",
|
||||
"balena-image-fs": "^7.3.0",
|
||||
"balena-preload": "^18.0.1",
|
||||
"balena-sdk": "^21.2.1",
|
||||
"balena-semver": "^2.3.0",
|
||||
"balena-settings-client": "^5.0.2",
|
||||
"balena-settings-storage": "^8.1.0",
|
||||
@ -211,10 +212,11 @@
|
||||
"cli-truncate": "^2.1.0",
|
||||
"color-hash": "^1.1.1",
|
||||
"common-tags": "^1.7.2",
|
||||
"date-fns": "^4.1.0",
|
||||
"denymount": "^2.3.0",
|
||||
"docker-modem": "^5.0.3",
|
||||
"docker-modem": "5.0.5",
|
||||
"docker-progress": "^5.1.3",
|
||||
"dockerode": "^4.0.2",
|
||||
"dockerode": "4.0.3",
|
||||
"ejs": "^3.1.6",
|
||||
"etcher-sdk": "9.1.0",
|
||||
"express": "^4.17.2",
|
||||
@ -274,6 +276,6 @@
|
||||
}
|
||||
},
|
||||
"versionist": {
|
||||
"publishedAt": "2024-12-30T17:16:10.325Z"
|
||||
"publishedAt": "2025-03-12T19:34:18.617Z"
|
||||
}
|
||||
}
|
||||
|
2
repo.yml
2
repo.yml
@ -6,6 +6,8 @@ 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'
|
||||
|
@ -17,7 +17,16 @@
|
||||
|
||||
import { Args, Command } from '@oclif/core';
|
||||
import { ExpectedError } from '../../errors';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
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();
|
||||
@ -41,13 +50,21 @@ export default class GenerateCmd extends Command {
|
||||
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 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;
|
||||
@ -55,9 +72,61 @@ export default class GenerateCmd extends Command {
|
||||
public async run() {
|
||||
const { args: params } = await this.parse(GenerateCmd);
|
||||
|
||||
let expiryDateResponse: string | number | undefined = params.expiryDate;
|
||||
let key;
|
||||
try {
|
||||
key = await getBalenaSdk().models.apiKey.create(params.name);
|
||||
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()) {
|
||||
|
@ -368,6 +368,7 @@ ${dockerignoreHelp}
|
||||
!opts.shouldUploadLogs,
|
||||
composeOpts.projectPath,
|
||||
opts.createAsDraft,
|
||||
project.descriptors,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Args, Command } from '@oclif/core';
|
||||
import { promisify } from 'util';
|
||||
import { stripIndent } from '../../utils/lazy';
|
||||
|
||||
export default class LocalConfigureCmd extends Command {
|
||||
@ -237,7 +236,7 @@ export default class LocalConfigureCmd extends Command {
|
||||
const bootPartition = await getBootPartition(target);
|
||||
|
||||
const files = await imagefs.interact(target, bootPartition, async (_fs) => {
|
||||
return await promisify(_fs.readdir)(this.CONNECTIONS_FOLDER);
|
||||
return await _fs.promises.readdir(this.CONNECTIONS_FOLDER);
|
||||
});
|
||||
|
||||
let connectionFileName;
|
||||
@ -246,13 +245,14 @@ export default class LocalConfigureCmd extends Command {
|
||||
} else if (_.includes(files, 'resin-sample.ignore')) {
|
||||
// Fresh image, new mode, accoding to https://github.com/balena-os/meta-balena/pull/770/files
|
||||
await imagefs.interact(target, bootPartition, async (_fs) => {
|
||||
const readFileAsync = promisify(_fs.readFile);
|
||||
const writeFileAsync = promisify(_fs.writeFile);
|
||||
const contents = await readFileAsync(
|
||||
const contents = await _fs.promises.readFile(
|
||||
`${this.CONNECTIONS_FOLDER}/resin-sample.ignore`,
|
||||
{ encoding: 'utf8' },
|
||||
);
|
||||
await writeFileAsync(`${this.CONNECTIONS_FOLDER}/resin-wifi`, contents);
|
||||
await _fs.promises.writeFile(
|
||||
`${this.CONNECTIONS_FOLDER}/resin-wifi`,
|
||||
contents,
|
||||
);
|
||||
});
|
||||
} else if (_.includes(files, 'resin-sample')) {
|
||||
// Legacy mode, to be removed later
|
||||
@ -266,7 +266,7 @@ export default class LocalConfigureCmd extends Command {
|
||||
} else {
|
||||
// In case there's no file at all (shouldn't happen normally, but the file might have been removed)
|
||||
await imagefs.interact(target, bootPartition, async (_fs) => {
|
||||
await promisify(_fs.writeFile)(
|
||||
await _fs.promises.writeFile(
|
||||
`${this.CONNECTIONS_FOLDER}/resin-wifi`,
|
||||
this.CONNECTION_FILE,
|
||||
);
|
||||
|
@ -18,7 +18,6 @@
|
||||
import { Flags, Args, Command } from '@oclif/core';
|
||||
import type { Interfaces } from '@oclif/core';
|
||||
import type * as BalenaSdk from 'balena-sdk';
|
||||
import { promisify } from 'util';
|
||||
import * as _ from 'lodash';
|
||||
import { ExpectedError } from '../../errors';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
@ -292,7 +291,7 @@ export default class OsConfigureCmd extends Command {
|
||||
|
||||
for (const { name, content } of files) {
|
||||
await imagefs.interact(image, bootPartition, async (_fs) => {
|
||||
await promisify(_fs.writeFile)(
|
||||
await _fs.promises.writeFile(
|
||||
path.join(CONNECTIONS_FOLDER, name),
|
||||
content,
|
||||
);
|
||||
|
@ -295,7 +295,7 @@ Can be repeated to add multiple certificates.\
|
||||
owns__release: {
|
||||
$select: ['id', 'commit', 'end_timestamp', 'composition'],
|
||||
$expand: {
|
||||
contains__image: {
|
||||
release_image: {
|
||||
$select: ['image'],
|
||||
$expand: {
|
||||
image: {
|
||||
|
@ -128,6 +128,7 @@ export const createRelease = async function (
|
||||
draft: boolean,
|
||||
semver: string | undefined,
|
||||
contract: import('@balena/compose/dist/release/models').ReleaseModel['contract'],
|
||||
imgDescriptors: ImageDescriptor[],
|
||||
): Promise<Release> {
|
||||
const _ = require('lodash') as typeof import('lodash');
|
||||
const crypto = require('crypto') as typeof import('crypto');
|
||||
@ -167,6 +168,7 @@ export const createRelease = async function (
|
||||
semver,
|
||||
is_final: !draft,
|
||||
contract,
|
||||
imgDescriptors,
|
||||
});
|
||||
|
||||
return {
|
||||
@ -240,7 +242,7 @@ export const getPreviousRepos = (
|
||||
status: 'success',
|
||||
},
|
||||
$expand: {
|
||||
contains__image: {
|
||||
release_image: {
|
||||
$select: 'image',
|
||||
$expand: { image: { $select: 'is_stored_at__image_location' } },
|
||||
},
|
||||
@ -252,7 +254,7 @@ export const getPreviousRepos = (
|
||||
.then(function (release) {
|
||||
// grab all images from the latest release, return all image locations in the registry
|
||||
if (release.length > 0) {
|
||||
const images = release[0].contains__image as Array<{
|
||||
const images = release[0].release_image as Array<{
|
||||
image: [SDK.Image];
|
||||
}>;
|
||||
const { getRegistryAndName } =
|
||||
|
@ -1375,6 +1375,7 @@ export async function deployProject(
|
||||
skipLogUpload: boolean,
|
||||
projectPath: string,
|
||||
isDraft: boolean,
|
||||
imgDescriptors: ImageDescriptor[],
|
||||
): Promise<import('@balena/compose/dist/release/models').ReleaseModel> {
|
||||
const releaseMod = await import('@balena/compose/dist/release');
|
||||
const { createRelease, tagServiceImages } = await import('./compose');
|
||||
@ -1405,6 +1406,7 @@ export async function deployProject(
|
||||
isDraft,
|
||||
contract?.version,
|
||||
contract,
|
||||
imgDescriptors,
|
||||
),
|
||||
);
|
||||
const { client: pineClient, release, serviceImages } = $release;
|
||||
|
@ -14,7 +14,6 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
import type * as BalenaSdk from 'balena-sdk';
|
||||
import * as semver from 'balena-semver';
|
||||
import { getBalenaSdk, stripIndent } from './lazy';
|
||||
|
||||
export interface ImgConfig {
|
||||
@ -122,16 +121,10 @@ export function generateDeviceConfig(
|
||||
// os.getConfig always returns a config for an app
|
||||
delete config.apiKey;
|
||||
|
||||
if (deviceApiKey == null && semver.satisfies(options.version, '<2.0.3')) {
|
||||
config.apiKey = await sdk.models.application.generateApiKey(
|
||||
application.id,
|
||||
);
|
||||
} else {
|
||||
config.deviceApiKey =
|
||||
typeof deviceApiKey === 'string' && deviceApiKey
|
||||
? deviceApiKey
|
||||
: await sdk.models.device.generateDeviceKey(device.uuid);
|
||||
}
|
||||
config.deviceApiKey =
|
||||
typeof deviceApiKey === 'string' && deviceApiKey
|
||||
? deviceApiKey
|
||||
: await sdk.models.device.generateDeviceKey(device.uuid);
|
||||
|
||||
return config;
|
||||
})
|
||||
|
@ -110,6 +110,27 @@ export async function getManifest(
|
||||
const init = await import('balena-device-init');
|
||||
const sdk = getBalenaSdk();
|
||||
const manifest = await init.getImageManifest(image);
|
||||
if (manifest != null) {
|
||||
const config = manifest.configuration?.config;
|
||||
if (config?.partition != null) {
|
||||
const { getBootPartition } = await import('balena-config-json');
|
||||
// Find the device-type.json property that holds the boot partition number for
|
||||
// this device type (config.partition or config.partition.primary) and overwrite it
|
||||
// with the boot partition number that was found by inspecting the image.
|
||||
// since it's deprecated & no longer updated for newer releases.
|
||||
if (typeof config.partition === 'number') {
|
||||
config.partition = await getBootPartition(image);
|
||||
} else if (config.partition.primary != null) {
|
||||
config.partition.primary = await getBootPartition(image);
|
||||
}
|
||||
// TODO: Add handling for when we no longer include a `config.partition` at all.
|
||||
}
|
||||
} else {
|
||||
// TODO: Change this in the next major to throw, after confirming that this works for all supported OS versions.
|
||||
console.error(
|
||||
`[warn] Error while finding a device-type.json on the provided image path. Attempting to fetch from the API.`,
|
||||
);
|
||||
}
|
||||
if (
|
||||
manifest != null &&
|
||||
manifest.slug !== deviceType &&
|
||||
|
@ -76,38 +76,28 @@ export const getImagePath = async (deviceType: string, version?: string) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* @summary Determine if a device image is fresh
|
||||
* @summary Determine if a device image is cached
|
||||
*
|
||||
* @description
|
||||
* If the device image does not exist, return false.
|
||||
*
|
||||
* @param {String} deviceType - device type slug or alias
|
||||
* @param {String} version - the exact balenaOS version number
|
||||
* @returns {Promise<Boolean>} is image fresh
|
||||
* @returns {Promise<Boolean>} is image cached
|
||||
*
|
||||
* @example
|
||||
* isImageFresh('raspberry-pi', '1.2.3').then (isFresh) ->
|
||||
* if isFresh
|
||||
* console.log('The Raspberry Pi image v1.2.3 is fresh!')
|
||||
* isImageCached ('raspberry-pi', '1.2.3').then (isCached) ->
|
||||
* if isCached
|
||||
* console.log('The Raspberry Pi image v1.2.3 is cached!')
|
||||
*/
|
||||
export const isImageFresh = async (deviceType: string, version: string) => {
|
||||
export const isImageCached = async (deviceType: string, version: string) => {
|
||||
const imagePath = await getImagePath(deviceType, version);
|
||||
let createdDate;
|
||||
try {
|
||||
createdDate = await getFileCreatedDate(imagePath);
|
||||
const createdDate = await getFileCreatedDate(imagePath);
|
||||
return createdDate != null;
|
||||
} catch {
|
||||
// Swallow errors from getFileCreatedTime.
|
||||
}
|
||||
if (createdDate == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
const lastModifiedDate = await balena.models.os.getLastModified(
|
||||
deviceType,
|
||||
version,
|
||||
);
|
||||
return lastModifiedDate < createdDate;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -286,7 +276,7 @@ export const getStream = async (
|
||||
versionOrRange = 'latest';
|
||||
}
|
||||
const version = await resolveVersion(deviceType, versionOrRange);
|
||||
const isFresh = await isImageFresh(deviceType, version);
|
||||
const isFresh = await isImageCached(deviceType, version);
|
||||
const $stream = isFresh
|
||||
? await getImage(deviceType, version)
|
||||
: await doDownload({ ...options, deviceType, version });
|
||||
|
@ -21,6 +21,7 @@ import type { Chalk } from 'chalk';
|
||||
import type * as visuals from 'resin-cli-visuals';
|
||||
import type * as CliForm from 'resin-cli-form';
|
||||
import type { ux } from '@oclif/core';
|
||||
import { version } from '../../package.json';
|
||||
|
||||
// Equivalent of _.once but avoiding the need to import lodash for lazy deps
|
||||
const once = <T>(fn: () => T) => {
|
||||
@ -43,9 +44,26 @@ export const onceAsync = <T>(fn: () => Promise<T>) => {
|
||||
};
|
||||
};
|
||||
|
||||
export const getBalenaSdk = once(() =>
|
||||
(require('balena-sdk') as typeof BalenaSdk).fromSharedOptions(),
|
||||
);
|
||||
const cliXBalenaClientHeaderInterceptor: BalenaSdk.Interceptor = {
|
||||
request($request) {
|
||||
if ($request.headers['X-Balena-Client']) {
|
||||
// We intentionally overwrite the sdk version string from the header
|
||||
// to conserve bandwidth. We only do that when the SDK already has specified
|
||||
// the X-Balena-Client header, since that signals that this is a safe url to
|
||||
// include the extra header and will not cause CORS errors.
|
||||
$request.headers['X-Balena-Client'] = `balena-cli/${version}`;
|
||||
}
|
||||
return $request;
|
||||
},
|
||||
};
|
||||
|
||||
export const getBalenaSdk = once(() => {
|
||||
const sdk = (require('balena-sdk') as typeof BalenaSdk).fromSharedOptions();
|
||||
if (!sdk.interceptors.includes(cliXBalenaClientHeaderInterceptor)) {
|
||||
sdk.interceptors.push(cliXBalenaClientHeaderInterceptor);
|
||||
}
|
||||
return sdk;
|
||||
});
|
||||
|
||||
export const getVisuals = once(
|
||||
() => require('resin-cli-visuals') as typeof visuals,
|
||||
|
@ -50,7 +50,7 @@ export function copyQemu(context: string, arch: string) {
|
||||
.then(() => getQemuPath(arch))
|
||||
.then(
|
||||
(qemu) =>
|
||||
new Promise(function (resolve, reject) {
|
||||
new Promise<void>(function (resolve, reject) {
|
||||
const read = fs.createReadStream(qemu);
|
||||
const write = fs.createWriteStream(binPath);
|
||||
|
||||
|
@ -22,6 +22,7 @@ import { runCommand } from '../../helpers';
|
||||
import { promisify } from 'util';
|
||||
import * as tmp from 'tmp';
|
||||
import type * as $imagefs from 'balena-image-fs';
|
||||
import * as stripIndent from 'common-tags/lib/stripIndent';
|
||||
|
||||
tmp.setGracefulCleanup();
|
||||
const tmpNameAsync = promisify(tmp.tmpName);
|
||||
@ -34,6 +35,7 @@ if (process.platform !== 'win32') {
|
||||
let api: BalenaAPIMock;
|
||||
let tmpDummyPath: string;
|
||||
let tmpMatchingDtJsonPartitionPath: string;
|
||||
let tmpNonMatchingDtJsonPartitionPath: string;
|
||||
|
||||
before(async function () {
|
||||
// We conditionally import balena-image-fs, since when imported on top level then unrelated tests on win32 failed with:
|
||||
@ -47,6 +49,48 @@ if (process.platform !== 'win32') {
|
||||
'./tests/test-data/mock-jetson-nano-6.0.13.with-boot-partition-12.img',
|
||||
tmpMatchingDtJsonPartitionPath,
|
||||
);
|
||||
|
||||
tmpNonMatchingDtJsonPartitionPath = (await tmpNameAsync()) as string;
|
||||
// Create an image with a device-type.json that mentions a non matching boot partition.
|
||||
// We copy the pre-existing image and modify it, since including a separate one
|
||||
// would add 18MB more to the repository.
|
||||
await fs.copyFile(
|
||||
'./tests/test-data/mock-jetson-nano-6.0.13.with-boot-partition-12.img',
|
||||
tmpNonMatchingDtJsonPartitionPath,
|
||||
);
|
||||
await imagefs.interact(
|
||||
tmpNonMatchingDtJsonPartitionPath,
|
||||
12,
|
||||
async (_fs) => {
|
||||
const dtJson = JSON.parse(
|
||||
await _fs.promises.readFile('/device-type.json', {
|
||||
encoding: 'utf8',
|
||||
}),
|
||||
);
|
||||
expect(dtJson).to.have.nested.property(
|
||||
'configuration.config.partition',
|
||||
12,
|
||||
);
|
||||
dtJson.configuration.config.partition = 999;
|
||||
await _fs.promises.writeFile(
|
||||
'/device-type.json',
|
||||
JSON.stringify(dtJson),
|
||||
);
|
||||
|
||||
await _fs.promises.writeFile(
|
||||
'/os-release',
|
||||
stripIndent`
|
||||
ID="balena-os"
|
||||
NAME="balenaOS"
|
||||
VERSION="6.1.25"
|
||||
VERSION_ID="6.1.25"
|
||||
PRETTY_NAME="balenaOS 6.1.25"
|
||||
DISTRO_CODENAME="kirkstone"
|
||||
MACHINE="jetson-nano"
|
||||
META_BALENA_VERSION="6.1.25"`,
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
@ -61,20 +105,20 @@ if (process.platform !== 'win32') {
|
||||
after(async () => {
|
||||
await fs.unlink(tmpDummyPath);
|
||||
await fs.unlink(tmpMatchingDtJsonPartitionPath);
|
||||
await fs.unlink(tmpNonMatchingDtJsonPartitionPath);
|
||||
});
|
||||
|
||||
it('should inject a valid config.json file to an image with partition 12 as boot & matching device-type.json ', async () => {
|
||||
it('should detect the OS version and inject a valid config.json file to a 6.0.13 image with partition 12 as boot & matching device-type.json', async () => {
|
||||
api.expectGetApplication();
|
||||
api.expectGetDeviceTypes();
|
||||
// TODO: this shouldn't be necessary & the CLI should be able to find
|
||||
// It should not reach to /config or /device-types/v1 but instead find
|
||||
// everything required from the device-type.json in the image.
|
||||
api.expectGetConfigDeviceTypes();
|
||||
// api.expectGetConfigDeviceTypes();
|
||||
api.expectDownloadConfig();
|
||||
|
||||
const command: string[] = [
|
||||
`os configure ${tmpMatchingDtJsonPartitionPath}`,
|
||||
'--device-type jetson-nano',
|
||||
'--version 6.0.13',
|
||||
'--fleet testApp',
|
||||
'--config-app-update-poll-interval 10',
|
||||
'--config-network ethernet',
|
||||
@ -91,16 +135,65 @@ if (process.platform !== 'win32') {
|
||||
tmpMatchingDtJsonPartitionPath,
|
||||
12,
|
||||
async (_fs) => {
|
||||
const readFileAsync = promisify(_fs.readFile);
|
||||
const dtJson = JSON.parse(
|
||||
await readFileAsync('/device-type.json', { encoding: 'utf8' }),
|
||||
await _fs.promises.readFile('/device-type.json', {
|
||||
encoding: 'utf8',
|
||||
}),
|
||||
);
|
||||
// confirm that the device-type.json mentions the expected partition
|
||||
expect(dtJson).to.have.nested.property(
|
||||
'configuration.config.partition',
|
||||
12,
|
||||
);
|
||||
return await readFileAsync('/config.json');
|
||||
return await _fs.promises.readFile('/config.json');
|
||||
},
|
||||
);
|
||||
expect(config).to.not.be.empty;
|
||||
|
||||
// confirm the image has the correct config.json values...
|
||||
const configObj = JSON.parse(config.toString('utf8'));
|
||||
expect(configObj).to.have.property('deviceType', 'jetson-nano');
|
||||
expect(configObj).to.have.property('initialDeviceName', 'testDeviceName');
|
||||
});
|
||||
|
||||
it('should detect the OS version and inject a valid config.json file to a 6.1.25 image with partition 12 as boot & a non-matching device-type.json', async () => {
|
||||
api.expectGetApplication();
|
||||
api.expectGetDeviceTypes();
|
||||
// It should not reach to /config or /device-types/v1 but instead find
|
||||
// everything required from the device-type.json in the image.
|
||||
// api.expectGetConfigDeviceTypes();
|
||||
api.expectDownloadConfig();
|
||||
|
||||
const command: string[] = [
|
||||
`os configure ${tmpNonMatchingDtJsonPartitionPath}`,
|
||||
'--device-type jetson-nano',
|
||||
'--fleet testApp',
|
||||
'--config-app-update-poll-interval 10',
|
||||
'--config-network ethernet',
|
||||
'--initial-device-name testDeviceName',
|
||||
'--provisioning-key-name testKey',
|
||||
'--provisioning-key-expiry-date 2050-12-12',
|
||||
];
|
||||
|
||||
const { err } = await runCommand(command.join(' '));
|
||||
expect(err.join('')).to.equal('');
|
||||
|
||||
// confirm the image contains a config.json...
|
||||
const config = await imagefs.interact(
|
||||
tmpNonMatchingDtJsonPartitionPath,
|
||||
12,
|
||||
async (_fs) => {
|
||||
const dtJson = JSON.parse(
|
||||
await _fs.promises.readFile('/device-type.json', {
|
||||
encoding: 'utf8',
|
||||
}),
|
||||
);
|
||||
// confirm that the device-type.json mentions the expected partition
|
||||
expect(dtJson).to.have.nested.property(
|
||||
'configuration.config.partition',
|
||||
999,
|
||||
);
|
||||
return await _fs.promises.readFile('/config.json');
|
||||
},
|
||||
);
|
||||
expect(config).to.not.be.empty;
|
||||
@ -134,11 +227,28 @@ if (process.platform !== 'win32') {
|
||||
const { err } = await runCommand(command.join(' '));
|
||||
// Once we replace the dummy.img with one that includes a os-release & device-type.json
|
||||
// then we should be able to change this to expect no errors.
|
||||
expect(err.join('')).to.equal('');
|
||||
expect(
|
||||
err.flatMap((line) => line.split('\n')).filter((line) => line !== ''),
|
||||
).to.deep.equal(
|
||||
stripIndent`
|
||||
[warn] "${tmpDummyPath}":
|
||||
[warn] Found partition table with 1 partitions,
|
||||
[warn] but none with a name/label in ['resin-boot', 'flash-boot', 'balena-boot'].
|
||||
[warn] Will scan all partitions for contents.
|
||||
[warn] "${tmpDummyPath}":
|
||||
[warn] 1 partition(s) found, but none containing file "/device-type.json".
|
||||
[warn] Assuming default boot partition number '1'.
|
||||
[warn] "${tmpDummyPath}":
|
||||
[warn] Could not find a previous "/config.json" file in partition '1'.
|
||||
[warn] Proceeding anyway, but this is unexpected.
|
||||
[warn] Error while finding a device-type.json on the provided image path. Attempting to fetch from the API.`.split(
|
||||
'\n',
|
||||
),
|
||||
);
|
||||
|
||||
// confirm the image contains a config.json...
|
||||
const config = await imagefs.interact(tmpDummyPath, 1, async (_fs) => {
|
||||
return await promisify(_fs.readFile)('/config.json');
|
||||
return await _fs.promises.readFile('/config.json');
|
||||
});
|
||||
expect(config).to.not.be.empty;
|
||||
|
||||
|
@ -82,7 +82,7 @@ describe('balena release', function () {
|
||||
expect(err).to.be.empty;
|
||||
const json = JSON.parse(out.join(''));
|
||||
expect(json[0].commit).to.equal('90247b54de4fa7a0a3cbc85e73c68039');
|
||||
expect(json[0].contains__image[0].image[0].start_timestamp).to.equal(
|
||||
expect(json[0].release_image[0].image[0].start_timestamp).to.equal(
|
||||
'2020-01-04T01:13:08.583Z',
|
||||
);
|
||||
});
|
||||
|
@ -10,7 +10,7 @@
|
||||
"build_log": null,
|
||||
"start_timestamp": "2021-08-25T22:18:33.624Z",
|
||||
"end_timestamp": "2021-08-25T22:18:48.820Z",
|
||||
"contains__image": [
|
||||
"release_image": [
|
||||
{
|
||||
"image": [
|
||||
{
|
||||
|
@ -42,7 +42,7 @@ describe('image-manager', function () {
|
||||
|
||||
describe('given the image is fresh', function () {
|
||||
beforeEach(function () {
|
||||
this.cacheIsImageFresh = stub(imageManager, 'isImageFresh');
|
||||
this.cacheIsImageFresh = stub(imageManager, 'isImageCached');
|
||||
return this.cacheIsImageFresh.resolves(true);
|
||||
});
|
||||
|
||||
@ -56,7 +56,7 @@ describe('image-manager', function () {
|
||||
void imageManager.getStream('raspberry-pi').then(function (stream) {
|
||||
let result = '';
|
||||
|
||||
stream.on('data', (chunk) => (result += chunk.toString()));
|
||||
stream.on('data', (chunk: string) => (result += chunk.toString()));
|
||||
|
||||
return stream.on('end', function () {
|
||||
expect(result).to.equal('Cache image');
|
||||
@ -68,7 +68,7 @@ describe('image-manager', function () {
|
||||
|
||||
describe('given the image is not fresh', function () {
|
||||
beforeEach(function () {
|
||||
this.cacheIsImageFresh = stub(imageManager, 'isImageFresh');
|
||||
this.cacheIsImageFresh = stub(imageManager, 'isImageCached');
|
||||
return this.cacheIsImageFresh.resolves(false);
|
||||
});
|
||||
|
||||
@ -91,7 +91,7 @@ describe('image-manager', function () {
|
||||
void imageManager.getStream('raspberry-pi').then((stream) => {
|
||||
let result = '';
|
||||
|
||||
stream.on('data', (chunk) => (result += chunk));
|
||||
stream.on('data', (chunk: string) => (result += chunk));
|
||||
|
||||
stream.on('end', async () => {
|
||||
expect(result).to.equal('Download image');
|
||||
@ -280,7 +280,7 @@ describe('image-manager', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('.isImageFresh()', () => {
|
||||
describe('.isImageCached()', () => {
|
||||
describe('given the raspberry-pi manifest', function () {
|
||||
beforeEach(function () {
|
||||
this.getDeviceTypeManifestBySlugStub = stub(
|
||||
@ -314,78 +314,8 @@ describe('image-manager', function () {
|
||||
});
|
||||
|
||||
it('should return false', async function () {
|
||||
expect(await imageManager.isImageFresh('raspberry-pi', '1.2.3')).to.be
|
||||
.false;
|
||||
});
|
||||
});
|
||||
|
||||
describe('given a fixed created time', function () {
|
||||
beforeEach(function () {
|
||||
this.utilsGetFileCreatedDate = stub(
|
||||
imageManager,
|
||||
'getFileCreatedDate',
|
||||
);
|
||||
this.utilsGetFileCreatedDate.resolves(
|
||||
new Date('2014-01-01T00:00:00.000Z'),
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.utilsGetFileCreatedDate.restore();
|
||||
});
|
||||
|
||||
describe('given the file was created before the os last modified time', function () {
|
||||
beforeEach(function () {
|
||||
this.osGetLastModified = stub(balena.models.os, 'getLastModified');
|
||||
this.osGetLastModified.resolves(
|
||||
new Date('2014-02-01T00:00:00.000Z'),
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.osGetLastModified.restore();
|
||||
});
|
||||
|
||||
it('should return false', function () {
|
||||
const promise = imageManager.isImageFresh('raspberry-pi', '1.2.3');
|
||||
return expect(promise).to.eventually.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
describe('given the file was created after the os last modified time', function () {
|
||||
beforeEach(function () {
|
||||
this.osGetLastModified = stub(balena.models.os, 'getLastModified');
|
||||
this.osGetLastModified.resolves(
|
||||
new Date('2013-01-01T00:00:00.000Z'),
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.osGetLastModified.restore();
|
||||
});
|
||||
|
||||
it('should return true', function () {
|
||||
const promise = imageManager.isImageFresh('raspberry-pi', '1.2.3');
|
||||
return expect(promise).to.eventually.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
describe('given the file was created just at the os last modified time', function () {
|
||||
beforeEach(function () {
|
||||
this.osGetLastModified = stub(balena.models.os, 'getLastModified');
|
||||
this.osGetLastModified.resolves(
|
||||
new Date('2014-00-01T00:00:00.000Z'),
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.osGetLastModified.restore();
|
||||
});
|
||||
|
||||
it('should return false', function () {
|
||||
const promise = imageManager.isImageFresh('raspberry-pi', '1.2.3');
|
||||
return expect(promise).to.eventually.be.false;
|
||||
});
|
||||
expect(await imageManager.isImageCached('raspberry-pi', '1.2.3')).to
|
||||
.be.false;
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -412,7 +342,7 @@ describe('image-manager', function () {
|
||||
.then(function (stream) {
|
||||
let result = '';
|
||||
|
||||
stream.on('data', (chunk: string) => (result += chunk));
|
||||
stream.on('data', (chunk) => (result += chunk as string));
|
||||
|
||||
stream.on('end', function () {
|
||||
expect(result).to.equal('Lorem ipsum dolor sit amet');
|
||||
|
Loading…
x
Reference in New Issue
Block a user