balena-cli 23.2.14 → 23.2.15-build-update-compose-7-3-0-97bf26975807627a264274621ffcf8380aea838e-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -1
- package/build/commands/os/configure.js.map +1 -1
- package/build/commands/release/list.js +4 -4
- package/build/commands/release/list.js.map +1 -1
- package/build/utils/compose.d.ts +2 -2
- package/build/utils/compose.js +3 -3
- package/build/utils/compose.js.map +1 -1
- package/build/utils/compose_ts.d.ts +2 -2
- package/build/utils/compose_ts.js +8 -7
- package/build/utils/compose_ts.js.map +1 -1
- package/npm-shrinkwrap.json +38 -94
- package/oclif.manifest.json +772 -772
- package/package.json +3 -3
- package/src/commands/os/configure.ts +4 -4
- package/src/commands/release/list.ts +4 -4
- package/src/utils/compose-types.d.ts +32 -19
- package/src/utils/compose.ts +8 -5
- package/src/utils/compose_ts.ts +13 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "balena-cli",
|
|
3
|
-
"version": "23.2.
|
|
3
|
+
"version": "23.2.15-build-update-compose-7-3-0-97bf26975807627a264274621ffcf8380aea838e-1",
|
|
4
4
|
"description": "The official balena Command Line Interface",
|
|
5
5
|
"main": "./build/app.js",
|
|
6
6
|
"homepage": "https://github.com/balena-io/balena-cli",
|
|
@@ -176,7 +176,7 @@
|
|
|
176
176
|
"typescript": "^5.9.2"
|
|
177
177
|
},
|
|
178
178
|
"dependencies": {
|
|
179
|
-
"@balena/compose": "^7.0
|
|
179
|
+
"@balena/compose": "^7.3.0",
|
|
180
180
|
"@balena/dockerignore": "^1.0.2",
|
|
181
181
|
"@balena/env-parsing": "^1.1.8",
|
|
182
182
|
"@balena/es-version": "^1.0.1",
|
|
@@ -262,6 +262,6 @@
|
|
|
262
262
|
"balena-request": "14.0.6"
|
|
263
263
|
},
|
|
264
264
|
"versionist": {
|
|
265
|
-
"publishedAt": "
|
|
265
|
+
"publishedAt": "2026-01-05T23:04:56.483Z"
|
|
266
266
|
}
|
|
267
267
|
}
|
|
@@ -208,7 +208,7 @@ export default class OsConfigureCmd extends Command {
|
|
|
208
208
|
})) as DeviceWithDeviceType & {
|
|
209
209
|
belongs_to__application: BalenaSdk.PineDeferred;
|
|
210
210
|
};
|
|
211
|
-
deviceTypeSlug = device.is_of__device_type[0].slug
|
|
211
|
+
deviceTypeSlug = device.is_of__device_type[0].slug!;
|
|
212
212
|
} else if (fleetSlugOrId != null) {
|
|
213
213
|
app = await getApplication(balena, fleetSlugOrId, {
|
|
214
214
|
$select: 'slug',
|
|
@@ -226,7 +226,7 @@ export default class OsConfigureCmd extends Command {
|
|
|
226
226
|
|
|
227
227
|
const deviceTypeManifest = await helpers.getManifest(
|
|
228
228
|
params.image,
|
|
229
|
-
deviceTypeSlug
|
|
229
|
+
deviceTypeSlug!,
|
|
230
230
|
);
|
|
231
231
|
|
|
232
232
|
const { normalizeOsVersion } = await import('../../utils/normalization');
|
|
@@ -242,7 +242,7 @@ export default class OsConfigureCmd extends Command {
|
|
|
242
242
|
);
|
|
243
243
|
await validateSecureBootOptionAndWarn(
|
|
244
244
|
secureBoot,
|
|
245
|
-
deviceTypeSlug
|
|
245
|
+
deviceTypeSlug!,
|
|
246
246
|
osVersion,
|
|
247
247
|
);
|
|
248
248
|
|
|
@@ -258,7 +258,7 @@ export default class OsConfigureCmd extends Command {
|
|
|
258
258
|
};
|
|
259
259
|
const answers: AugmentedAnswers = {
|
|
260
260
|
...baseAnswers,
|
|
261
|
-
deviceType: deviceTypeSlug
|
|
261
|
+
deviceType: deviceTypeSlug!,
|
|
262
262
|
version: osVersion,
|
|
263
263
|
developmentMode: developmentMode,
|
|
264
264
|
secureBoot: secureBoot,
|
|
@@ -89,10 +89,10 @@ export default class ReleaseListCmd extends Command {
|
|
|
89
89
|
(r) => r.id,
|
|
90
90
|
);
|
|
91
91
|
|
|
92
|
-
const augmentedReleases = releases.map((release) =>
|
|
93
|
-
|
|
94
|
-
...
|
|
95
|
-
})
|
|
92
|
+
const augmentedReleases = releases.map((release) => {
|
|
93
|
+
const extra = releasesWithExplicitReadFieldsById[release.id];
|
|
94
|
+
return typeof extra === 'object' ? { ...release, ...extra } : release;
|
|
95
|
+
});
|
|
96
96
|
|
|
97
97
|
await pipeline(
|
|
98
98
|
Readable.from(augmentedReleases),
|
|
@@ -15,10 +15,7 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import type {
|
|
19
|
-
ImageModel,
|
|
20
|
-
ReleaseModel,
|
|
21
|
-
} from '@balena/compose/dist/release/models';
|
|
18
|
+
import type { BalenaModel } from 'balena-sdk';
|
|
22
19
|
import type { Composition, ImageDescriptor } from '@balena/compose/dist/parse';
|
|
23
20
|
import type { Pack } from 'tar-stream';
|
|
24
21
|
|
|
@@ -27,25 +24,32 @@ interface Image {
|
|
|
27
24
|
tag: string;
|
|
28
25
|
}
|
|
29
26
|
|
|
27
|
+
interface ImageProperties {
|
|
28
|
+
dockerfile?: string;
|
|
29
|
+
projectType?: string;
|
|
30
|
+
size?: number;
|
|
31
|
+
startTime?: Date;
|
|
32
|
+
endTime?: Date;
|
|
33
|
+
}
|
|
34
|
+
|
|
30
35
|
export interface BuiltImage {
|
|
31
36
|
logs: string;
|
|
32
37
|
name: string;
|
|
33
|
-
props:
|
|
34
|
-
dockerfile?: string;
|
|
35
|
-
projectType?: string;
|
|
36
|
-
size?: number;
|
|
37
|
-
startTime?: Date;
|
|
38
|
-
endTime?: Date;
|
|
39
|
-
};
|
|
38
|
+
props: ImageProperties;
|
|
40
39
|
serviceName: string;
|
|
41
40
|
}
|
|
42
41
|
|
|
42
|
+
type ServiceImage = Omit<
|
|
43
|
+
BalenaModel['image']['Read'],
|
|
44
|
+
'created_at' | 'is_a_build_of__service'
|
|
45
|
+
>;
|
|
46
|
+
|
|
43
47
|
export interface TaggedImage {
|
|
44
48
|
localImage: import('dockerode').Image;
|
|
45
|
-
serviceImage:
|
|
49
|
+
serviceImage: ServiceImage;
|
|
46
50
|
serviceName: string;
|
|
47
51
|
logs: string;
|
|
48
|
-
props:
|
|
52
|
+
props: ImageProperties;
|
|
49
53
|
registry: string;
|
|
50
54
|
repo: string;
|
|
51
55
|
}
|
|
@@ -82,23 +86,32 @@ export interface ComposeProject {
|
|
|
82
86
|
export interface Release {
|
|
83
87
|
client: import('@balena/compose').release.Request['client'];
|
|
84
88
|
release: Pick<
|
|
85
|
-
|
|
89
|
+
BalenaModel['release']['Read'],
|
|
86
90
|
| 'id'
|
|
87
91
|
| 'status'
|
|
88
92
|
| 'commit'
|
|
89
93
|
| 'composition'
|
|
90
94
|
| 'source'
|
|
91
95
|
| 'is_final'
|
|
92
|
-
| 'contract'
|
|
93
96
|
| 'semver'
|
|
94
97
|
| 'start_timestamp'
|
|
95
98
|
| 'end_timestamp'
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
>;
|
|
99
|
+
> & {
|
|
100
|
+
contract: Contract | null;
|
|
101
|
+
};
|
|
102
|
+
serviceImages: Dictionary<ServiceImage>;
|
|
100
103
|
}
|
|
101
104
|
|
|
105
|
+
// TODO: The balena contract model for release.contract is `{ [key: string]: JSON } | JSON[] | null`
|
|
106
|
+
// which appears to be incorrect, as a contract is represented as `{ [key: string]: any }`
|
|
107
|
+
// (more specifically, `{ type: string, [key: string]: any }`) when querying a release for its contract.
|
|
108
|
+
// @balena/contrato also defines a ContractObject as the type below, see:
|
|
109
|
+
// https://github.com/balena-io/contrato/blob/543e891249431aa98474e17fecc66617ab9ca8f3/lib/types.ts#L15-L17
|
|
110
|
+
export type Contract = {
|
|
111
|
+
type: string;
|
|
112
|
+
[key: string]: any;
|
|
113
|
+
};
|
|
114
|
+
|
|
102
115
|
interface TarDirectoryOptions {
|
|
103
116
|
composition?: Composition;
|
|
104
117
|
convertEol?: boolean;
|
package/src/utils/compose.ts
CHANGED
|
@@ -26,6 +26,7 @@ import type {
|
|
|
26
26
|
ComposeOpts,
|
|
27
27
|
ComposeProject,
|
|
28
28
|
Release,
|
|
29
|
+
Contract,
|
|
29
30
|
TaggedImage,
|
|
30
31
|
} from './compose-types';
|
|
31
32
|
import Logger = require('./logger');
|
|
@@ -128,7 +129,7 @@ export const createRelease = async function (
|
|
|
128
129
|
composition: Composition,
|
|
129
130
|
draft: boolean,
|
|
130
131
|
semver: string | undefined,
|
|
131
|
-
contract:
|
|
132
|
+
contract: Contract | undefined,
|
|
132
133
|
imgDescriptors: ImageDescriptor[],
|
|
133
134
|
): Promise<Release> {
|
|
134
135
|
const crypto = require('crypto') as typeof import('crypto');
|
|
@@ -165,16 +166,18 @@ export const createRelease = async function (
|
|
|
165
166
|
commit: crypto.pseudoRandomBytes(16).toString('hex').toLowerCase(),
|
|
166
167
|
semver,
|
|
167
168
|
is_final: !draft,
|
|
168
|
-
contract,
|
|
169
|
+
contract: contract ?? undefined,
|
|
169
170
|
imgDescriptors,
|
|
170
171
|
});
|
|
171
172
|
|
|
172
173
|
for (const serviceImage of Object.values(serviceImages)) {
|
|
173
174
|
if ('created_at' in serviceImage) {
|
|
174
|
-
delete
|
|
175
|
+
// created_at is not an optional field in the SDK, but we need to delete it
|
|
176
|
+
serviceImage.created_at = undefined as any;
|
|
175
177
|
}
|
|
176
178
|
if ('is_a_build_of__service' in serviceImage) {
|
|
177
|
-
delete
|
|
179
|
+
// is_a_build_of__service is not an optional field in the SDK, but we need to delete it
|
|
180
|
+
serviceImage.is_a_build_of__service = undefined as any;
|
|
178
181
|
}
|
|
179
182
|
}
|
|
180
183
|
|
|
@@ -191,7 +194,7 @@ export const createRelease = async function (
|
|
|
191
194
|
'semver',
|
|
192
195
|
'start_timestamp',
|
|
193
196
|
'end_timestamp',
|
|
194
|
-
]),
|
|
197
|
+
]) as Release['release'],
|
|
195
198
|
serviceImages,
|
|
196
199
|
};
|
|
197
200
|
};
|
package/src/utils/compose_ts.ts
CHANGED
|
@@ -39,6 +39,8 @@ import type {
|
|
|
39
39
|
ComposeProject,
|
|
40
40
|
TaggedImage,
|
|
41
41
|
TarDirectoryOptions,
|
|
42
|
+
Release,
|
|
43
|
+
Contract,
|
|
42
44
|
} from './compose-types';
|
|
43
45
|
import type { DeviceInfo } from './device/api';
|
|
44
46
|
import { getBalenaSdk, getCliUx, stripIndent } from './lazy';
|
|
@@ -1274,7 +1276,7 @@ async function pushAndUpdateServiceImages(
|
|
|
1274
1276
|
token: string,
|
|
1275
1277
|
images: TaggedImage[],
|
|
1276
1278
|
afterEach: (
|
|
1277
|
-
serviceImage:
|
|
1279
|
+
serviceImage: TaggedImage['serviceImage'],
|
|
1278
1280
|
props: object,
|
|
1279
1281
|
) => Promise<void>,
|
|
1280
1282
|
) {
|
|
@@ -1330,15 +1332,15 @@ async function pushAndUpdateServiceImages(
|
|
|
1330
1332
|
serviceImage.image_size = `${imgInfo.Size}`;
|
|
1331
1333
|
serviceImage.content_hash = imgDigest;
|
|
1332
1334
|
serviceImage.build_log = logs;
|
|
1333
|
-
serviceImage.dockerfile = props.dockerfile;
|
|
1334
|
-
serviceImage.project_type = props.projectType;
|
|
1335
|
+
serviceImage.dockerfile = props.dockerfile ?? null;
|
|
1336
|
+
serviceImage.project_type = props.projectType ?? null;
|
|
1335
1337
|
if (props.startTime) {
|
|
1336
|
-
serviceImage.start_timestamp = props.startTime;
|
|
1338
|
+
serviceImage.start_timestamp = props.startTime.toISOString();
|
|
1337
1339
|
}
|
|
1338
1340
|
if (props.endTime) {
|
|
1339
|
-
serviceImage.end_timestamp = props.endTime;
|
|
1341
|
+
serviceImage.end_timestamp = props.endTime.toISOString();
|
|
1340
1342
|
}
|
|
1341
|
-
serviceImage.push_timestamp = new Date();
|
|
1343
|
+
serviceImage.push_timestamp = new Date().toISOString();
|
|
1342
1344
|
serviceImage.status = 'success';
|
|
1343
1345
|
} catch (error) {
|
|
1344
1346
|
serviceImage.error_message = '' + error;
|
|
@@ -1379,7 +1381,7 @@ async function pushServiceImages(
|
|
|
1379
1381
|
`Saving image ${serviceImage.is_stored_at__image_location}`,
|
|
1380
1382
|
);
|
|
1381
1383
|
if (skipLogUpload) {
|
|
1382
|
-
|
|
1384
|
+
serviceImage.build_log = null;
|
|
1383
1385
|
}
|
|
1384
1386
|
|
|
1385
1387
|
// These are the only update-able image fields in bC atm, and passing
|
|
@@ -1425,7 +1427,7 @@ export async function deployProject(
|
|
|
1425
1427
|
projectPath: string,
|
|
1426
1428
|
isDraft: boolean,
|
|
1427
1429
|
imgDescriptors: ImageDescriptor[],
|
|
1428
|
-
): Promise<
|
|
1430
|
+
): Promise<Release['release']> {
|
|
1429
1431
|
const releaseMod = await import('@balena/compose/dist/release');
|
|
1430
1432
|
const { createRelease, tagServiceImages } = await import('./compose');
|
|
1431
1433
|
const tty = (await import('./tty'))(process.stdout);
|
|
@@ -1496,7 +1498,7 @@ export async function deployProject(
|
|
|
1496
1498
|
}
|
|
1497
1499
|
} finally {
|
|
1498
1500
|
await runSpinner(tty, spinner, `${prefix}Saving release...`, async () => {
|
|
1499
|
-
release.end_timestamp = new Date();
|
|
1501
|
+
release.end_timestamp = new Date().toISOString();
|
|
1500
1502
|
if (release.id != null) {
|
|
1501
1503
|
await releaseMod.updateRelease(pineClient, release.id, {
|
|
1502
1504
|
status: release.status,
|
|
@@ -1552,9 +1554,7 @@ export function createRunLoop(tick: (...args: any[]) => void) {
|
|
|
1552
1554
|
|
|
1553
1555
|
async function getContractContent(
|
|
1554
1556
|
filePath: string,
|
|
1555
|
-
): Promise<
|
|
1556
|
-
import('@balena/compose/dist/release/models').ReleaseModel['contract']
|
|
1557
|
-
> {
|
|
1557
|
+
): Promise<Contract | undefined> {
|
|
1558
1558
|
let fileContentAsString;
|
|
1559
1559
|
try {
|
|
1560
1560
|
fileContentAsString = await fs.readFile(filePath, 'utf8');
|
|
@@ -1584,7 +1584,7 @@ async function getContractContent(
|
|
|
1584
1584
|
return asJson;
|
|
1585
1585
|
}
|
|
1586
1586
|
|
|
1587
|
-
function isContract(obj: any): obj is
|
|
1587
|
+
function isContract(obj: any): obj is Contract {
|
|
1588
1588
|
return obj?.type && allowedContractTypes.includes(obj.type);
|
|
1589
1589
|
}
|
|
1590
1590
|
|