Add contract contents at release creation time

Change-type: patch
This commit is contained in:
Paulo Castro 2021-08-26 15:05:50 +01:00
parent 9937b91606
commit d0cdc900a2
9 changed files with 27 additions and 45 deletions

View File

@ -3373,7 +3373,7 @@ Hint: Empty values may be specified with "" (bash, cmd.exe) or '""' (PowerShell)
Deploy the release as a draft. Draft releases are ignored Deploy the release as a draft. Draft releases are ignored
by the 'track latest' release policy but can be used through release pinning. by the 'track latest' release policy but can be used through release pinning.
Draft releases can be marked as final through the API. Releases as created Draft releases can be marked as final through the API. Releases are created
as final by default unless this option is given. as final by default unless this option is given.
#### -e, --emulated #### -e, --emulated

View File

@ -141,7 +141,7 @@ ${dockerignoreHelp}
description: stripIndent` description: stripIndent`
Deploy the release as a draft. Draft releases are ignored Deploy the release as a draft. Draft releases are ignored
by the 'track latest' release policy but can be used through release pinning. by the 'track latest' release policy but can be used through release pinning.
Draft releases can be marked as final through the API. Releases as created Draft releases can be marked as final through the API. Releases are created
as final by default unless this option is given.`, as final by default unless this option is given.`,
default: false, default: false,
}), }),

View File

@ -177,6 +177,7 @@ export async function originalTarDirectory(dir, param) {
* @param {import('resin-compose-parse').Composition} composition * @param {import('resin-compose-parse').Composition} composition
* @param {boolean} draft * @param {boolean} draft
* @param {string|undefined} semver * @param {string|undefined} semver
* @param {string|undefined} contract
* @returns {Promise<import('./compose-types').Release>} * @returns {Promise<import('./compose-types').Release>}
*/ */
export const createRelease = async function ( export const createRelease = async function (
@ -187,6 +188,7 @@ export const createRelease = async function (
composition, composition,
draft, draft,
semver, semver,
contract,
) { ) {
const _ = require('lodash'); const _ = require('lodash');
const crypto = require('crypto'); const crypto = require('crypto');
@ -203,6 +205,7 @@ export const createRelease = async function (
commit: crypto.pseudoRandomBytes(16).toString('hex').toLowerCase(), commit: crypto.pseudoRandomBytes(16).toString('hex').toLowerCase(),
semver, semver,
is_final: !draft, is_final: !draft,
contract,
}); });
return { return {

View File

@ -1314,18 +1314,12 @@ export async function deployProject(
const prefix = getChalk().cyan('[Info]') + ' '; const prefix = getChalk().cyan('[Info]') + ' ';
const spinner = createSpinner(); const spinner = createSpinner();
const contract = await getContractContent( const contractPath = path.join(projectPath, 'balena.yml');
path.join(projectPath, 'balena.yml'), const contract = await getContractContent(contractPath);
);
if (contract?.version && !PLAIN_SEMVER_REGEX.test(contract?.version)) { if (contract?.version && !PLAIN_SEMVER_REGEX.test(contract?.version)) {
throw new ExpectedError( throw new ExpectedError(stripIndent`\
stripIndent`Error: expected the version field in ${path.join( Error: expected the version field in "${contractPath}"
projectPath, to be a basic semver in the format '1.2.3'. Got '${contract.version}' instead`);
'balena.yml',
)} to be a basic semver in the format '1.2.3'. Got '${
contract.version
}' instead`,
);
} }
const $release = await runSpinner( const $release = await runSpinner(
@ -1341,6 +1335,7 @@ export async function deployProject(
composition, composition,
isDraft, isDraft,
contract?.version, contract?.version,
contract ? JSON.stringify(contract) : undefined,
), ),
); );
const { client: pineClient, release, serviceImages } = $release; const { client: pineClient, release, serviceImages } = $release;
@ -1376,11 +1371,6 @@ export async function deployProject(
} finally { } finally {
await runSpinner(tty, spinner, `${prefix}Saving release...`, async () => { await runSpinner(tty, spinner, `${prefix}Saving release...`, async () => {
release.end_timestamp = new Date(); release.end_timestamp = new Date();
// Add contract contents to the release
if (contract) {
release.contract = JSON.stringify(contract);
}
if (release.id != null) { if (release.id != null) {
await releaseMod.updateRelease(pineClient, release.id, release); await releaseMod.updateRelease(pineClient, release.id, release);
} }

6
npm-shrinkwrap.json generated
View File

@ -3969,9 +3969,9 @@
} }
}, },
"balena-release": { "balena-release": {
"version": "3.1.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/balena-release/-/balena-release-3.1.0.tgz", "resolved": "https://registry.npmjs.org/balena-release/-/balena-release-3.2.0.tgz",
"integrity": "sha512-FEbu6mdRUXgqZM0UTEz80zS5fLJDPPJ1ztF0+kmFR4VQ1Cr/s1Xn3m35GCREZlq5quOWLQnWr5Xe2TESH7IdIA==", "integrity": "sha512-jwmAjIZCJ5I46/yQNN+dA73RWlre0+jBVmo2QeJl1pK83obTLyifJeWNVf5irzP8KFE7WQzo9ICK1cCpLtygFA==",
"requires": { "requires": {
"@types/bluebird": "^3.5.18", "@types/bluebird": "^3.5.18",
"@types/node": "^8.0.55", "@types/node": "^8.0.55",

View File

@ -206,7 +206,7 @@
"balena-image-fs": "^7.0.6", "balena-image-fs": "^7.0.6",
"balena-image-manager": "^7.0.3", "balena-image-manager": "^7.0.3",
"balena-preload": "^10.5.0", "balena-preload": "^10.5.0",
"balena-release": "^3.1.0", "balena-release": "^3.2.0",
"balena-sdk": "^15.48.0", "balena-sdk": "^15.48.0",
"balena-semver": "^2.3.0", "balena-semver": "^2.3.0",
"balena-settings-client": "^4.0.7", "balena-settings-client": "^4.0.7",

View File

@ -15,6 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import type { Request as ReleaseRequest } from 'balena-release';
import { expect } from 'chai'; import { expect } from 'chai';
import { promises as fs } from 'fs'; import { promises as fs } from 'fs';
import * as _ from 'lodash'; import * as _ from 'lodash';
@ -162,10 +163,9 @@ describe('balena deploy', function () {
'with-contract', 'with-contract',
); );
const expectedFiles: ExpectedTarStreamFiles = { const expectedFiles: ExpectedTarStreamFiles = {
'src/.dockerignore': { fileSize: 16, type: 'file' },
'src/start.sh': { fileSize: 30, type: 'file' }, 'src/start.sh': { fileSize: 30, type: 'file' },
Dockerfile: { fileSize: 88, type: 'file' }, Dockerfile: { fileSize: 88, type: 'file' },
'balena.yml': { fileSize: 58, type: 'file' }, 'balena.yml': { fileSize: 55, type: 'file' },
}; };
const responseFilename = 'build-POST.json'; const responseFilename = 'build-POST.json';
const responseBody = await fs.readFile( const responseBody = await fs.readFile(
@ -176,19 +176,14 @@ describe('balena deploy', function () {
...commonResponseLines[responseFilename], ...commonResponseLines[responseFilename],
`[Info] No "docker-compose.yml" file found at "${projectPath}"`, `[Info] No "docker-compose.yml" file found at "${projectPath}"`,
`[Info] Creating default composition with source: "${projectPath}"`, `[Info] Creating default composition with source: "${projectPath}"`,
...getDockerignoreWarn1(
[path.join(projectPath, 'src', '.dockerignore')],
'deploy',
),
]; ];
api.expectPostRelease({ api.expectPostRelease({
inspectRequest: (_uri: string, requestBody: nock.Body) => { inspectRequest: (_uri: string, requestBody: nock.Body) => {
const body = requestBody.valueOf() as { const body = requestBody.valueOf() as Partial<ReleaseRequest>;
semver: string; expect(body.contract).to.be.equal(
is_final: boolean; '{"name":"testContract","type":"sw.application","version":"1.5.2"}',
}; );
expect(body.semver).to.be.equal('1.5.2');
expect(body.is_final).to.be.true; expect(body.is_final).to.be.true;
}, },
}); });
@ -216,10 +211,9 @@ describe('balena deploy', function () {
'with-contract', 'with-contract',
); );
const expectedFiles: ExpectedTarStreamFiles = { const expectedFiles: ExpectedTarStreamFiles = {
'src/.dockerignore': { fileSize: 16, type: 'file' },
'src/start.sh': { fileSize: 30, type: 'file' }, 'src/start.sh': { fileSize: 30, type: 'file' },
Dockerfile: { fileSize: 88, type: 'file' }, Dockerfile: { fileSize: 88, type: 'file' },
'balena.yml': { fileSize: 58, type: 'file' }, 'balena.yml': { fileSize: 55, type: 'file' },
}; };
const responseFilename = 'build-POST.json'; const responseFilename = 'build-POST.json';
const responseBody = await fs.readFile( const responseBody = await fs.readFile(
@ -230,18 +224,14 @@ describe('balena deploy', function () {
...commonResponseLines[responseFilename], ...commonResponseLines[responseFilename],
`[Info] No "docker-compose.yml" file found at "${projectPath}"`, `[Info] No "docker-compose.yml" file found at "${projectPath}"`,
`[Info] Creating default composition with source: "${projectPath}"`, `[Info] Creating default composition with source: "${projectPath}"`,
...getDockerignoreWarn1(
[path.join(projectPath, 'src', '.dockerignore')],
'deploy',
),
]; ];
api.expectPostRelease({ api.expectPostRelease({
inspectRequest: (_uri: string, requestBody: nock.Body) => { inspectRequest: (_uri: string, requestBody: nock.Body) => {
const body = requestBody.valueOf() as { const body = requestBody.valueOf() as Partial<ReleaseRequest>;
semver: string; expect(body.contract).to.be.equal(
is_final: boolean; '{"name":"testContract","type":"sw.application","version":"1.5.2"}',
}; );
expect(body.semver).to.be.equal('1.5.2'); expect(body.semver).to.be.equal('1.5.2');
expect(body.is_final).to.be.false; expect(body.is_final).to.be.false;
}, },

View File

@ -1,3 +1,3 @@
name: testymctestface name: testContract
type: sw.application type: sw.application
version: 1.5.2 version: 1.5.2