Skip to content

Commit

Permalink
Adds commands for exporting and importing app/fleet releases.
Browse files Browse the repository at this point in the history
Change-type: minor
Signed-off-by: Carlo Miguel F. Cruz <[email protected]>
  • Loading branch information
cmfcruz committed Aug 2, 2024
1 parent a08ac44 commit 58ad003
Show file tree
Hide file tree
Showing 7 changed files with 323 additions and 26 deletions.
2 changes: 1 addition & 1 deletion completion/_balena
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ _balena() {
key_cmds=( add rm )
local_cmds=( configure flash )
os_cmds=( build-config configure download initialize versions )
release_cmds=( finalize invalidate validate )
release_cmds=( export finalize import invalidate validate )
tag_cmds=( rm set )


Expand Down
2 changes: 1 addition & 1 deletion completion/balena-completion.bash
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ _balena_complete()
key_cmds="add rm"
local_cmds="configure flash"
os_cmds="build-config configure download initialize versions"
release_cmds="finalize invalidate validate"
release_cmds="export finalize import invalidate validate"
tag_cmds="rm set"


Expand Down
52 changes: 52 additions & 0 deletions docs/balena-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,9 @@ are encouraged to regularly update the balena CLI to the latest version.

- Releases

- [release export &#60;commitorid&#62;](#release-export-commitorid)
- [release finalize &#60;commitorid&#62;](#release-finalize-commitorid)
- [release import &#60;bundlefile&#62;](#release-import-bundlefile)
- [release &#60;commitorid&#62;](#release-commitorid)
- [release invalidate &#60;commitorid&#62;](#release-invalidate-commitorid)
- [release validate &#60;commitorid&#62;](#release-validate-commitorid)
Expand Down Expand Up @@ -3369,6 +3371,29 @@ The notes for this release

# Releases

## release export &#60;commitOrId&#62;

Exports a successful release to a release bundle file that can be used
to import the release to another application or fleet.

Examples:

$ balena release export a777f7345fe3d655c1c981aa642e5555 -o ../path/to/release.tar
$ balena release export 1234567 -o ../path/to/release.tar
$ balena release export myOrg/myFleet:1.2.3 -o ../path/to/release.tar

### Arguments

#### COMMITORID

commit, ID, or tag of the release to export

### Options

#### -o, --output OUTPUT

output path

## release finalize &#60;commitOrId&#62;

Finalize a release. Releases can be "draft" or "final", and this command
Expand All @@ -3395,6 +3420,33 @@ the commit or ID of the release to finalize

### Options

## release import &#60;bundleFile&#62;



Examples:

$ balena release import ../path/to/release.tar -f 1234567
$ balena release import ../path/to/release.tar -f myFleet
$ balena release import ../path/to/release.tar -f myOrg/myFleet
$ balena release import ../path/to/release.tar -f myOrg/myFleet -O 1.2.3

### Arguments

#### BUNDLE

path to a release bundle file, e.g. "release.tar"

### Options

#### -f, --fleet FLEET

fleet name or slug (preferred)

#### -O, --override-version OVERRIDE-VERSION

Overrides the version of the release bundle

## release &#60;commitOrId&#62;

The --json option is recommended when scripting the output of this command,
Expand Down
98 changes: 98 additions & 0 deletions lib/commands/release/export.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/**
* @license
* Copyright 2016-2024 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 { commitOrIdArg } from '.';
import { Flags } from '@oclif/core';
import Command from '../../command';
import * as cf from '../../utils/common-flags';
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
import { create } from '@balena/release-bundle';
import * as fs from 'fs/promises';

export default class ReleaseExportCmd extends Command {
public static description = stripIndent`
Exports a release to a release bundle file.
Exports a successful release to a release bundle file that can be used
to import the release to another application or fleet.
`;
public static examples = [
'$ balena release export a777f7345fe3d655c1c981aa642e5555 -o ../path/to/release.tar',
'$ balena release export 1234567 -o ../path/to/release.tar',
'$ balena release export myOrg/myFleet:1.2.3 -o ../path/to/release.tar',
];

public static usage = 'release export <commitOrId>';

public static flags = {
output: Flags.string({
description: 'output path',
char: 'o',
required: true,
}),
help: cf.help,
};

public static args = {
commitOrId: commitOrIdArg({
description: 'commit, ID, or tag of the release to export',
required: true,
}),
};

public static authenticated = true;

public async run() {
const { args: params, flags: options } = await this.parse(ReleaseExportCmd);

const balena = getBalenaSdk();

let release: balenaSdk.Release;
if (
typeof params.commitOrId === 'string' &&
params.commitOrId.includes(':')
) {
const fleet = params.commitOrId.split(':')[0];
const rawVersion = params.commitOrId.split(':')[1];
release = await balena.models.release.get(
{ application: fleet, rawVersion: rawVersion },
{ $select: ['id'], $top: 1 },
);
} else {
release = await balena.models.release.get(params.commitOrId, {
$select: ['id'],
$top: 1,
});
}

try {
const releaseBundle = await create({
sdk: balena,
releaseId: release.id,
});
await fs.writeFile(options.output, releaseBundle);
} catch (error) {
console.log(
`Release ${params.commitOrId} could not be exported. ${error.message}`,
);
}

console.log(
`Release ${params.commitOrId} has been exported to ${options.output}.`,
);
}
}
92 changes: 92 additions & 0 deletions lib/commands/release/import.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/**
* @license
* Copyright 2016-2024 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 } from '@oclif/core';
import Command from '../../command';
import * as cf from '../../utils/common-flags';
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
import { apply } from '@balena/release-bundle';
import { createReadStream } from 'fs';

export default class ReleaseImportCmd extends Command {
public static description = stripIndent`
Imports a release from a release bundle file to an application or fleet.
`;
public static examples = [
'$ balena release import ../path/to/release.tar -f 1234567',
'$ balena release import ../path/to/release.tar -f myFleet',
'$ balena release import ../path/to/release.tar -f myOrg/myFleet',
'$ balena release import ../path/to/release.tar -f myOrg/myFleet -O 1.2.3',
];

public static usage = 'release import <bundleFile>';

public static flags = {
fleet: { ...cf.fleet, exclusive: ['device'] },
'override-version': Flags.string({
description: 'Overrides the version of the release bundle',
char: 'O',
required: true,
}),
help: cf.help,
};

public static args = {
bundle: Args.string({
required: true,
description: 'path to a release bundle file, e.g. "release.tar"',
}),
};

public static authenticated = true;

public async run() {
const { args: params, flags: options } = await this.parse(ReleaseImportCmd);

const balena = getBalenaSdk();

const bundle = createReadStream(params.bundle);

try {
if (
typeof options.fleet !== 'number' &&
typeof options.fleet !== 'string'
) {
throw new Error('Fleet must be a number or slug.');
}

// TODO: validate if the path to the release bundle exists

const application = await balena.models.application.get(options.fleet, {
$select: ['id'],
});
await apply({
sdk: balena,
application: application.id,
stream: bundle,
version: options['override-version'],
});
console.log(
`Release bundle ${params.bundle} has been applied to ${options.fleet}.`,
);
} catch (error) {
console.log(
`Could not apply release bundle to fleet ${options.fleet}. ${error.message}`,
);
}
}
}
Loading

0 comments on commit 58ad003

Please sign in to comment.