mirror of
https://github.com/balena-io/balena-cli.git
synced 2024-12-19 21:57:51 +00:00
Add support for releases
Signed-off-by: Paul Jonathan <pj@balena.io> Change-type: minor
This commit is contained in:
parent
e098cdca17
commit
a18e182ae4
@ -8,7 +8,7 @@ _balena() {
|
||||
local context state line curcontext="$curcontext"
|
||||
|
||||
# Valid top-level completions
|
||||
main_commands=( apps build deploy envs fleets join keys leave login logout logs note orgs preload push scan settings ssh support tags tunnel version whoami api-key app app config device device devices env fleet fleet internal key key local os tag util )
|
||||
main_commands=( apps 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 app app config device device devices env fleet fleet internal key key local os release release tag util )
|
||||
# Sub-completions
|
||||
api_key_cmds=( generate )
|
||||
app_cmds=( create purge rename restart rm )
|
||||
@ -21,6 +21,7 @@ _balena() {
|
||||
key_cmds=( add rm )
|
||||
local_cmds=( configure flash )
|
||||
os_cmds=( build-config configure download initialize versions )
|
||||
release_cmds=( finalize )
|
||||
tag_cmds=( rm set )
|
||||
|
||||
|
||||
@ -73,6 +74,9 @@ _balena_sec_cmds() {
|
||||
"os")
|
||||
_describe -t os_cmds 'os_cmd' os_cmds "$@" && ret=0
|
||||
;;
|
||||
"release")
|
||||
_describe -t release_cmds 'release_cmd' release_cmds "$@" && ret=0
|
||||
;;
|
||||
"tag")
|
||||
_describe -t tag_cmds 'tag_cmd' tag_cmds "$@" && ret=0
|
||||
;;
|
||||
|
@ -7,7 +7,7 @@ _balena_complete()
|
||||
local cur prev
|
||||
|
||||
# Valid top-level completions
|
||||
main_commands="apps build deploy envs fleets join keys leave login logout logs note orgs preload push scan settings ssh support tags tunnel version whoami api-key app app config device device devices env fleet fleet internal key key local os tag util"
|
||||
main_commands="apps 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 app app config device device devices env fleet fleet internal key key local os release release tag util"
|
||||
# Sub-completions
|
||||
api_key_cmds="generate"
|
||||
app_cmds="create purge rename restart rm"
|
||||
@ -20,6 +20,7 @@ _balena_complete()
|
||||
key_cmds="add rm"
|
||||
local_cmds="configure flash"
|
||||
os_cmds="build-config configure download initialize versions"
|
||||
release_cmds="finalize"
|
||||
tag_cmds="rm set"
|
||||
|
||||
|
||||
@ -67,6 +68,9 @@ _balena_complete()
|
||||
os)
|
||||
COMPREPLY=( $(compgen -W "$os_cmds" -- $cur) )
|
||||
;;
|
||||
release)
|
||||
COMPREPLY=( $(compgen -W "$release_cmds" -- $cur) )
|
||||
;;
|
||||
tag)
|
||||
COMPREPLY=( $(compgen -W "$tag_cmds" -- $cur) )
|
||||
;;
|
||||
|
86
lib/commands/release/finalize.ts
Normal file
86
lib/commands/release/finalize.ts
Normal file
@ -0,0 +1,86 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2016-2020 Balena Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { flags } from '@oclif/command';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { tryAsInteger } from '../../utils/validation';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
commitOrId: string | number;
|
||||
}
|
||||
|
||||
export default class ReleaseFinalizeCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Finalize a release.
|
||||
|
||||
Finalize a release. Releases can be "draft" or "final", and this command
|
||||
changes a draft release into a final release. Draft releases can be created
|
||||
with the \`--draft\` option of the \`balena build\` or \`balena deploy\`
|
||||
commands.
|
||||
|
||||
Draft releases are not automatically deployed to devices tracking the latest application
|
||||
release. For a draft release to be deployed to a device, the device should be
|
||||
explicity pinned to that release. Conversely, final releases may trigger immediate
|
||||
deployment to unpinned devices (subject to a device's polling period) and, for
|
||||
this reason, final releases cannot be changed back to draft status.
|
||||
`;
|
||||
public static examples = [
|
||||
'$ balena release finalize a777f7345fe3d655c1c981aa642e5555',
|
||||
'$ balena release finalize 1234567',
|
||||
];
|
||||
|
||||
public static usage = 'finalize <commitOrId>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'commitOrId',
|
||||
description: 'the commit or ID of the release to finalize',
|
||||
required: true,
|
||||
parse: (commitOrId: string) => tryAsInteger(commitOrId),
|
||||
},
|
||||
];
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params } = this.parse<FlagsDef, ArgsDef>(ReleaseFinalizeCmd);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
const release = await balena.models.release.get(params.commitOrId, {
|
||||
$select: ['id', 'is_final'],
|
||||
});
|
||||
|
||||
if (release.is_final) {
|
||||
console.log(`Release ${params.commitOrId} is already finalized!`);
|
||||
return;
|
||||
}
|
||||
|
||||
await balena.models.release.finalize(release.id);
|
||||
console.log(`Release ${params.commitOrId} finalized`);
|
||||
}
|
||||
}
|
128
lib/commands/release/index.ts
Normal file
128
lib/commands/release/index.ts
Normal file
@ -0,0 +1,128 @@
|
||||
/**
|
||||
* @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 type * as BalenaSdk from 'balena-sdk';
|
||||
import jsyaml = require('js-yaml');
|
||||
import { tryAsInteger } from '../../utils/validation';
|
||||
|
||||
interface FlagsDef {
|
||||
help: void;
|
||||
composition?: boolean;
|
||||
}
|
||||
|
||||
interface ArgsDef {
|
||||
commitOrId: string | number;
|
||||
}
|
||||
|
||||
export default class ReleaseCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Get info for a release.
|
||||
`;
|
||||
public static examples = [
|
||||
'$ balena release a777f7345fe3d655c1c981aa642e5555',
|
||||
'$ balena release 1234567',
|
||||
];
|
||||
|
||||
public static usage = 'release <commitOrId>';
|
||||
|
||||
public static flags: flags.Input<FlagsDef> = {
|
||||
help: cf.help,
|
||||
composition: flags.boolean({
|
||||
default: false,
|
||||
char: 'c',
|
||||
description: 'Return the release composition',
|
||||
}),
|
||||
};
|
||||
|
||||
public static args = [
|
||||
{
|
||||
name: 'commitOrId',
|
||||
description: 'the commit or ID of the release to get information',
|
||||
required: true,
|
||||
parse: (commitOrId: string) => tryAsInteger(commitOrId),
|
||||
},
|
||||
];
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
ReleaseCmd,
|
||||
);
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
if (options.composition) {
|
||||
await this.showComposition(params.commitOrId, balena);
|
||||
} else {
|
||||
await this.showReleaseInfo(params.commitOrId, balena);
|
||||
}
|
||||
}
|
||||
|
||||
async showComposition(
|
||||
commitOrId: string | number,
|
||||
balena: BalenaSdk.BalenaSDK,
|
||||
) {
|
||||
const release = await balena.models.release.get(commitOrId, {
|
||||
$select: 'composition',
|
||||
});
|
||||
|
||||
console.log(jsyaml.dump(release.composition));
|
||||
}
|
||||
|
||||
async showReleaseInfo(
|
||||
commitOrId: string | number,
|
||||
balena: BalenaSdk.BalenaSDK,
|
||||
) {
|
||||
const fields: Array<keyof BalenaSdk.Release> = [
|
||||
'id',
|
||||
'commit',
|
||||
'created_at',
|
||||
'status',
|
||||
'semver',
|
||||
'is_final',
|
||||
'build_log',
|
||||
'start_timestamp',
|
||||
'end_timestamp',
|
||||
];
|
||||
|
||||
const release = await balena.models.release.get(commitOrId, {
|
||||
$select: fields,
|
||||
$expand: {
|
||||
release_tag: {
|
||||
$select: ['tag_key', 'value'],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const tagStr = release
|
||||
.release_tag!.map((t) => `${t.tag_key}=${t.value}`)
|
||||
.join('\n');
|
||||
|
||||
const _ = await import('lodash');
|
||||
const values = _.mapValues(
|
||||
release,
|
||||
(val) => val ?? 'N/a',
|
||||
) as Dictionary<string>;
|
||||
values['tags'] = tagStr;
|
||||
|
||||
console.log(getVisuals().table.vertical(values, [...fields, 'tags']));
|
||||
}
|
||||
}
|
86
lib/commands/releases.ts
Normal file
86
lib/commands/releases.ts
Normal file
@ -0,0 +1,86 @@
|
||||
/**
|
||||
* @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',
|
||||
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 releases = await balena.models.release.getAllByApplication(
|
||||
params.fleet,
|
||||
{ $select: fields },
|
||||
);
|
||||
|
||||
const _ = await import('lodash');
|
||||
console.log(
|
||||
getVisuals().table.horizontal(
|
||||
releases.map((rel) => _.mapValues(rel, (val) => val ?? 'N/a')),
|
||||
fields,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -208,6 +208,16 @@ environments). Numeric fleet IDs are deprecated because they consist of an
|
||||
implementation detail of the balena backend. We intend to remove support for
|
||||
numeric IDs at some point in the future.`;
|
||||
|
||||
export const applicationNameNote = `\
|
||||
Fleets may be specified by fleet name or slug. Slugs are recommended because
|
||||
they are unique and unambiguous. Slugs can be listed with the \`balena fleets\`
|
||||
command. Note that slugs may change if the fleet is renamed. Fleet names are
|
||||
not unique and may result in "Fleet is ambiguous" errors at any time (even if
|
||||
"it used to work in the past"), for example if the name clashes with a newly
|
||||
created public/open fleet, or with fleets from other balena accounts that you
|
||||
may be invited to join under any role. For this reason, fleet names are
|
||||
especially discouraged in scripts (e.g. CI environments).`;
|
||||
|
||||
export const jsonInfo = `\
|
||||
The --json option is recommended when scripting the output of this command,
|
||||
because field names are less likely to change in JSON format and because it
|
||||
|
68
tests/commands/release.spec.ts
Normal file
68
tests/commands/release.spec.ts
Normal file
@ -0,0 +1,68 @@
|
||||
/**
|
||||
* @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 { expect } from 'chai';
|
||||
|
||||
import { BalenaAPIMock } from '../nock/balena-api-mock';
|
||||
import { cleanOutput, runCommand } from '../helpers';
|
||||
|
||||
describe('balena release', function () {
|
||||
let api: BalenaAPIMock;
|
||||
|
||||
beforeEach(() => {
|
||||
api = new BalenaAPIMock();
|
||||
api.expectGetWhoAmI({ optional: true, persist: true });
|
||||
api.expectGetMixpanel({ optional: true });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Check all expected api calls have been made and clean up.
|
||||
api.done();
|
||||
});
|
||||
|
||||
it('should show release details', async () => {
|
||||
api.expectGetRelease();
|
||||
const { out } = await runCommand('release 27fda508c');
|
||||
const lines = cleanOutput(out);
|
||||
expect(lines[0]).to.contain('ID: ');
|
||||
expect(lines[0]).to.contain(' 142334');
|
||||
expect(lines[1]).to.contain('COMMIT: ');
|
||||
expect(lines[1]).to.contain(' 90247b54de4fa7a0a3cbc85e73c68039');
|
||||
});
|
||||
|
||||
it('should return release composition', async () => {
|
||||
api.expectGetRelease();
|
||||
const { out } = await runCommand('release 27fda508c --composition');
|
||||
const lines = cleanOutput(out);
|
||||
expect(lines[0]).to.be.equal("version: '2.1'");
|
||||
expect(lines[1]).to.be.equal('networks: {}');
|
||||
expect(lines[2]).to.be.equal('volumes:');
|
||||
expect(lines[3]).to.be.equal('resin-data: {}');
|
||||
expect(lines[4]).to.be.equal('services:');
|
||||
expect(lines[5]).to.be.equal('main:');
|
||||
});
|
||||
|
||||
it('should list releases', async () => {
|
||||
api.expectGetRelease();
|
||||
api.expectGetApplication();
|
||||
const { out } = await runCommand('releases someapp');
|
||||
const lines = cleanOutput(out);
|
||||
expect(lines.length).to.be.equal(2);
|
||||
expect(lines[1]).to.contain('142334');
|
||||
expect(lines[1]).to.contain('90247b54de4fa7a0a3cbc85e73c68039');
|
||||
});
|
||||
});
|
@ -101,12 +101,27 @@ export class BalenaAPIMock extends NockMock {
|
||||
});
|
||||
}
|
||||
|
||||
public expectGetRelease(opts: ScopeOpts = {}) {
|
||||
this.optGet(/^\/v6\/release($|[(?])/, opts).replyWithFile(
|
||||
200,
|
||||
path.join(apiResponsePath, 'release-GET-v6.json'),
|
||||
jHeader,
|
||||
);
|
||||
public expectGetRelease({
|
||||
notFound = false,
|
||||
optional = false,
|
||||
persist = false,
|
||||
} = {}) {
|
||||
const interceptor = this.optGet(/^\/v6\/release($|[(?])/, {
|
||||
persist,
|
||||
optional,
|
||||
});
|
||||
if (notFound) {
|
||||
interceptor.reply(200, { d: [] });
|
||||
} else {
|
||||
this.optGet(/^\/v6\/release($|[(?])/, {
|
||||
persist,
|
||||
optional,
|
||||
}).replyWithFile(
|
||||
200,
|
||||
path.join(apiResponsePath, 'release-GET-v6.json'),
|
||||
jHeader,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,52 +1,95 @@
|
||||
{
|
||||
"d": [
|
||||
{
|
||||
"contains__image": [
|
||||
{
|
||||
"image": [
|
||||
{
|
||||
"id": 1820810,
|
||||
"created_at": "2020-01-04T01:13:08.805Z",
|
||||
"start_timestamp": "2020-01-04T01:13:08.583Z",
|
||||
"end_timestamp": "2020-01-04T01:13:11.920Z",
|
||||
"dockerfile": "# FROM busybox\n# FROM arm32v7/busybox\n# FROM arm32v7/alpine\n# FROM eu.gcr.io/buoyant-idea-226013/arm32v7/busybox\n# FROM eu.gcr.io/buoyant-idea-226013/amd64/busybox\n# FROM balenalib/raspberrypi3-debian:jessie-build\nFROM balenalib/raspberrypi3:stretch\nENV UDEV=1\n\n# FROM sander85/rpi-busybox # armv6\n# FROM balenalib/raspberrypi3-alpine\n\n# COPY start.sh /\n# COPY /src/start.sh /src/start.sh\n# COPY /src/hello.txt /\n# COPY src/hi.txt /\n\n# RUN cat /hello.txt\n# RUN cat /hi.txt\n# RUN cat /run/secrets/my-secret.txt\n# EXPOSE 80\nRUN uname -a\n\n# FROM alpine\n# RUN apk update && apk add bash\n# SHELL [\"/bin/bash\", \"-c\"]\n# CMD for ((i=1; i > 0; i++)); do echo \"(Plain Dockerfile 34-$i) $(uname -a)\"; sleep ${INTERVAL=5}; done\n\n# CMD i=1; while :; do echo \"Plain Dockerfile 36 ($i) $(uname -a)\"; sleep 10; i=$((i+1)); done\n# ENTRYPOINT [\"/usr/bin/entry.sh\"]\nCMD [\"/bin/bash\"]\n",
|
||||
"is_a_build_of__service": {
|
||||
"__deferred": {
|
||||
"uri": "/resin/service(233455)"
|
||||
},
|
||||
"__id": 233455
|
||||
},
|
||||
"image_size": 134320410,
|
||||
"is_stored_at__image_location": "registry2.balena-cloud.com/v2/9c00c9413942cd15cfc9189c5dac359d",
|
||||
"project_type": "Standard Dockerfile",
|
||||
"error_message": null,
|
||||
"build_log": "Step 1/4 : FROM balenalib/raspberrypi3:stretch\n ---> 8a75ea61d9c0\nStep 2/4 : ENV UDEV=1\n\u001b[42m\u001b[30mUsing cache\u001b[39m\u001b[49m\n ---> 159206067c8a\nStep 3/4 : RUN uname -a\n\u001b[42m\u001b[30mUsing cache\u001b[39m\u001b[49m\n ---> dd1b3d9c334b\nStep 4/4 : CMD [\"/bin/bash\"]\n\u001b[42m\u001b[30mUsing cache\u001b[39m\u001b[49m\n ---> 5211b6f4bb72\nSuccessfully built 5211b6f4bb72\n",
|
||||
"push_timestamp": "2020-01-04T01:13:14.415Z",
|
||||
"status": "success",
|
||||
"content_hash": "sha256:6b5471aae43ae81e8f69e10d1a516cb412569a6d5020a57eae311f8fa16d688a",
|
||||
"contract": null,
|
||||
"__metadata": {
|
||||
"uri": "/resin/image(@id)?@id=1820810"
|
||||
}
|
||||
}
|
||||
],
|
||||
"id": 1738663,
|
||||
"created_at": "2020-01-04T01:13:14.646Z",
|
||||
"is_part_of__release": {
|
||||
"__deferred": {
|
||||
"uri": "/resin/release(1203844)"
|
||||
},
|
||||
"__id": 1203844
|
||||
},
|
||||
"__metadata": {
|
||||
"uri": "/resin/image__is_part_of__release(@id)?@id=1738663"
|
||||
}
|
||||
{
|
||||
"id": 142334,
|
||||
"commit": "90247b54de4fa7a0a3cbc85e73c68039",
|
||||
"created_at": "2021-08-25T22:18:34.014Z",
|
||||
"status": "success",
|
||||
"semver": "0.0.0",
|
||||
"is_final": false,
|
||||
"build_log": null,
|
||||
"start_timestamp": "2021-08-25T22:18:33.624Z",
|
||||
"end_timestamp": "2021-08-25T22:18:48.820Z",
|
||||
"__metadata": {
|
||||
"uri": "/resin/release(@id)?@id=142334"
|
||||
},
|
||||
"contains__image": [
|
||||
{
|
||||
"image": [
|
||||
{
|
||||
"id": 1820810,
|
||||
"created_at": "2020-01-04T01:13:08.805Z",
|
||||
"start_timestamp": "2020-01-04T01:13:08.583Z",
|
||||
"end_timestamp": "2020-01-04T01:13:11.920Z",
|
||||
"dockerfile": "# FROM busybox\n# FROM arm32v7/busybox\n# FROM arm32v7/alpine\n# FROM eu.gcr.io/buoyant-idea-226013/arm32v7/busybox\n# FROM eu.gcr.io/buoyant-idea-226013/amd64/busybox\n# FROM balenalib/raspberrypi3-debian:jessie-build\nFROM balenalib/raspberrypi3:stretch\nENV UDEV=1\n\n# FROM sander85/rpi-busybox # armv6\n# FROM balenalib/raspberrypi3-alpine\n\n# COPY start.sh /\n# COPY /src/start.sh /src/start.sh\n# COPY /src/hello.txt /\n# COPY src/hi.txt /\n\n# RUN cat /hello.txt\n# RUN cat /hi.txt\n# RUN cat /run/secrets/my-secret.txt\n# EXPOSE 80\nRUN uname -a\n\n# FROM alpine\n# RUN apk update && apk add bash\n# SHELL [\"/bin/bash\", \"-c\"]\n# CMD for ((i=1; i > 0; i++)); do echo \"(Plain Dockerfile 34-$i) $(uname -a)\"; sleep ${INTERVAL=5}; done\n\n# CMD i=1; while :; do echo \"Plain Dockerfile 36 ($i) $(uname -a)\"; sleep 10; i=$((i+1)); done\n# ENTRYPOINT [\"/usr/bin/entry.sh\"]\nCMD [\"/bin/bash\"]\n",
|
||||
"is_a_build_of__service": {
|
||||
"__deferred": {
|
||||
"uri": "/resin/service(233455)"
|
||||
},
|
||||
"__id": 233455
|
||||
},
|
||||
"image_size": 134320410,
|
||||
"is_stored_at__image_location": "registry2.balena-cloud.com/v2/9c00c9413942cd15cfc9189c5dac359d",
|
||||
"project_type": "Standard Dockerfile",
|
||||
"error_message": null,
|
||||
"build_log": "Step 1/4 : FROM balenalib/raspberrypi3:stretch\n ---> 8a75ea61d9c0\nStep 2/4 : ENV UDEV=1\n\u001b[42m\u001b[30mUsing cache\u001b[39m\u001b[49m\n ---> 159206067c8a\nStep 3/4 : RUN uname -a\n\u001b[42m\u001b[30mUsing cache\u001b[39m\u001b[49m\n ---> dd1b3d9c334b\nStep 4/4 : CMD [\"/bin/bash\"]\n\u001b[42m\u001b[30mUsing cache\u001b[39m\u001b[49m\n ---> 5211b6f4bb72\nSuccessfully built 5211b6f4bb72\n",
|
||||
"push_timestamp": "2020-01-04T01:13:14.415Z",
|
||||
"status": "success",
|
||||
"content_hash": "sha256:6b5471aae43ae81e8f69e10d1a516cb412569a6d5020a57eae311f8fa16d688a",
|
||||
"contract": null,
|
||||
"__metadata": {
|
||||
"uri": "/resin/image(@id)?@id=1820810"
|
||||
}
|
||||
}
|
||||
],
|
||||
"id": 1203844,
|
||||
"id": 1738663,
|
||||
"created_at": "2020-01-04T01:13:14.646Z",
|
||||
"is_part_of__release": {
|
||||
"__deferred": {
|
||||
"uri": "/resin/release(1203844)"
|
||||
},
|
||||
"__id": 1203844
|
||||
},
|
||||
"__metadata": {
|
||||
"uri": "/resin/release(@id)?@id=1203844"
|
||||
"uri": "/resin/image__is_part_of__release(@id)?@id=1738663"
|
||||
}
|
||||
}
|
||||
],
|
||||
"release_tag": [
|
||||
{
|
||||
"tag_key": "testtag1",
|
||||
"value": "val1",
|
||||
"__metadata": {}
|
||||
}
|
||||
],
|
||||
"composition": {
|
||||
"version": "2.1",
|
||||
"networks": {},
|
||||
"volumes": {
|
||||
"resin-data": {}
|
||||
},
|
||||
"services": {
|
||||
"main": {
|
||||
"build": {
|
||||
"context": "."
|
||||
},
|
||||
"privileged": true,
|
||||
"tty": true,
|
||||
"restart": "always",
|
||||
"network_mode": "host",
|
||||
"volumes": [
|
||||
"resin-data:/data"
|
||||
],
|
||||
"labels": {
|
||||
"io.resin.features.kernel-modules": "1",
|
||||
"io.resin.features.firmware": "1",
|
||||
"io.resin.features.dbus": "1",
|
||||
"io.resin.features.supervisor-api": "1",
|
||||
"io.resin.features.resin-api": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user