Compare commits

...

2 Commits

Author SHA1 Message Date
2b76a3999f Deduplicate dependencies 2025-06-02 15:31:14 +03:00
ebbdb6f96a Update nock to 15.0.0-beta.3 to work with native fetch
Nock 15 adds support for native fetch.

Change-type: patch
See: https://github.com/nock/nock/blob/beta/migration_guides/migrating_to_15.md
2025-06-02 15:30:34 +03:00
9 changed files with 81 additions and 126 deletions

48
npm-shrinkwrap.json generated
View File

@ -151,7 +151,7 @@
"mocha": "^10.6.0", "mocha": "^10.6.0",
"mock-fs": "^5.2.0", "mock-fs": "^5.2.0",
"mock-require": "^3.0.3", "mock-require": "^3.0.3",
"nock": "^14.0.4", "nock": "^15.0.0-beta.3",
"oclif": "^4.17.0", "oclif": "^4.17.0",
"rewire": "^7.0.0", "rewire": "^7.0.0",
"simple-git": "^3.14.1", "simple-git": "^3.14.1",
@ -1566,9 +1566,9 @@
} }
}, },
"node_modules/@balena/lint/node_modules/@eslint/js": { "node_modules/@balena/lint/node_modules/@eslint/js": {
"version": "9.27.0", "version": "9.28.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.27.0.tgz", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.28.0.tgz",
"integrity": "sha512-G5JD9Tu5HJEu4z2Uo4aHY2sLV64B7CDMXxFzqzjl3NKd6RVzSXNoE80jk7Y0lJkTTkjiIhBAqmlYwjuBY3tvpA==", "integrity": "sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@ -1642,9 +1642,9 @@
} }
}, },
"node_modules/@balena/lint/node_modules/eslint": { "node_modules/@balena/lint/node_modules/eslint": {
"version": "9.27.0", "version": "9.28.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.27.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.28.0.tgz",
"integrity": "sha512-ixRawFQuMB9DZ7fjU3iGGganFDp3+45bPOdaRurcFHSXO1e/sYwUX/FtQZpLZJR6SjMoJH8hR2pPEAfDyCoU2Q==", "integrity": "sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -1654,7 +1654,7 @@
"@eslint/config-helpers": "^0.2.1", "@eslint/config-helpers": "^0.2.1",
"@eslint/core": "^0.14.0", "@eslint/core": "^0.14.0",
"@eslint/eslintrc": "^3.3.1", "@eslint/eslintrc": "^3.3.1",
"@eslint/js": "9.27.0", "@eslint/js": "9.28.0",
"@eslint/plugin-kit": "^0.3.1", "@eslint/plugin-kit": "^0.3.1",
"@humanfs/node": "^0.16.6", "@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/module-importer": "^1.0.1",
@ -2596,9 +2596,9 @@
} }
}, },
"node_modules/@inquirer/core/node_modules/@types/node": { "node_modules/@inquirer/core/node_modules/@types/node": {
"version": "22.15.27", "version": "22.15.29",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.27.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.29.tgz",
"integrity": "sha512-5fF+eu5mwihV2BeVtX5vijhdaZOfkQTATrePEaXTcKqI16LhJ7gi2/Vhd9OZM0UojcdmiOCVg5rrax+i1MdoQQ==", "integrity": "sha512-LNdjOkUDlU1RZb8e1kOIUpN1qQUlzGkEtbVNo53vbrwDg5om6oduhm4SiUaPW5ASTXhAiP0jInWG8Qx9fVlOeQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -6298,9 +6298,9 @@
} }
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "20.17.55", "version": "20.17.57",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.55.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.57.tgz",
"integrity": "sha512-ESpPDUEtW1a9nueMQtcTq/5iY/7osurPpBpFKH2VAyREKdzoFRRod6Oms0SSTfV7u52CcH7b6dFVnjfPD8fxWg==", "integrity": "sha512-f3T4y6VU4fVQDKVqJV4Uppy8c1p/sVvS3peyqxyWnzkqXFJLRU7Y1Bl7rMS1Qe9z0v4M6McY0Fp9yBsgHJUsWQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"undici-types": "~6.19.2" "undici-types": "~6.19.2"
@ -14843,15 +14843,14 @@
} }
}, },
"node_modules/nock": { "node_modules/nock": {
"version": "14.0.4", "version": "15.0.0-beta.3",
"resolved": "https://registry.npmjs.org/nock/-/nock-14.0.4.tgz", "resolved": "https://registry.npmjs.org/nock/-/nock-15.0.0-beta.3.tgz",
"integrity": "sha512-86fh+gIKH8H02+y0/HKAOZZXn6OwgzXvl6JYwfjvKkoKxUWz54wIIDU/+w24xzMvk/R8pNVXOrvTubyl+Ml6cg==", "integrity": "sha512-4q0Cr/pU11G5f3aM/V7w4u1PEeimng6MhjqGdaUEyMYp32ZbCvTuiLQknoSS9iWTbKvTCpr0Q/jN8NZpHbXfdQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@mswjs/interceptors": "^0.38.5", "@mswjs/interceptors": "^0.38.7",
"json-stringify-safe": "^5.0.1", "json-stringify-safe": "^5.0.1"
"propagate": "^2.0.0"
}, },
"engines": { "engines": {
"node": ">=18.20.0 <20 || >=20.12.1" "node": ">=18.20.0 <20 || >=20.12.1"
@ -16440,15 +16439,6 @@
"react-is": "^16.13.1" "react-is": "^16.13.1"
} }
}, },
"node_modules/propagate": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz",
"integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==",
"dev": true,
"engines": {
"node": ">= 8"
}
},
"node_modules/proto-list": { "node_modules/proto-list": {
"version": "1.2.4", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",

View File

@ -153,7 +153,7 @@
"mocha": "^10.6.0", "mocha": "^10.6.0",
"mock-fs": "^5.2.0", "mock-fs": "^5.2.0",
"mock-require": "^3.0.3", "mock-require": "^3.0.3",
"nock": "^14.0.4", "nock": "^15.0.0-beta.3",
"oclif": "^4.17.0", "oclif": "^4.17.0",
"rewire": "^7.0.0", "rewire": "^7.0.0",
"simple-git": "^3.14.1", "simple-git": "^3.14.1",

View File

@ -108,7 +108,7 @@ describe('Utils:', async function () {
}); });
}); });
return describe('given the token does authenticate with the server', function () { describe('given the token does authenticate with the server', function () {
beforeEach(function () { beforeEach(function () {
this.balenaAuthIsLoggedInStub = sinon.stub(balena.auth, 'isLoggedIn'); this.balenaAuthIsLoggedInStub = sinon.stub(balena.auth, 'isLoggedIn');
return this.balenaAuthIsLoggedInStub.resolves(true); return this.balenaAuthIsLoggedInStub.resolves(true);
@ -118,7 +118,7 @@ describe('Utils:', async function () {
return this.balenaAuthIsLoggedInStub.restore(); return this.balenaAuthIsLoggedInStub.restore();
}); });
return it('should eventually be true', function () { it('should eventually be true', function () {
const promise = utils.loginIfTokenValid(tokens.johndoe.token); const promise = utils.loginIfTokenValid(tokens.johndoe.token);
return expect(promise).to.eventually.be.true; return expect(promise).to.eventually.be.true;
}); });

View File

@ -20,7 +20,6 @@ import type { Request as ReleaseRequest } from '@balena/compose/dist/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';
import type * as nock from 'nock';
import * as path from 'path'; import * as path from 'path';
import * as sinon from 'sinon'; import * as sinon from 'sinon';
@ -181,8 +180,8 @@ describe('balena deploy', function () {
]; ];
api.expectPostRelease({ api.expectPostRelease({
inspectRequest: (_uri: string, requestBody: nock.Body) => { inspectRequest: async (request: Request) => {
const body = requestBody.valueOf() as Partial<ReleaseRequest>; const body = (await request.json()) as Partial<ReleaseRequest>;
expect(body.contract).to.deep.equal({ expect(body.contract).to.deep.equal({
name: 'testContract', name: 'testContract',
type: 'sw.application', type: 'sw.application',
@ -232,8 +231,8 @@ describe('balena deploy', function () {
]; ];
api.expectPostRelease({ api.expectPostRelease({
inspectRequest: (_uri: string, requestBody: nock.Body) => { inspectRequest: async (request: Request) => {
const body = requestBody.valueOf() as Partial<ReleaseRequest>; const body = (await request.json()) as Partial<ReleaseRequest>;
expect(body.contract).to.deep.equal({ expect(body.contract).to.deep.equal({
name: 'testContract', name: 'testContract',
type: 'sw.application', type: 'sw.application',
@ -298,21 +297,21 @@ describe('balena deploy', function () {
statusCode: 500, statusCode: 500,
// b/c failed requests are retried // b/c failed requests are retried
times: maxRequestRetries, times: maxRequestRetries,
inspectRequest: (_uri, requestBody) => { inspectRequest: async (request: Request) => {
const imageBody = requestBody as Partial< const body = (await request.json()) as Partial<
import('@balena/compose/dist/release/models').ImageModel import('@balena/compose/dist/release/models').ImageModel
>; >;
expect(imageBody.status).to.equal('success'); expect(body.status).to.equal('success');
failedImagePatchRequests++; failedImagePatchRequests++;
}, },
}); });
// Check that the CLI patches the release with status="failed" // Check that the CLI patches the release with status="failed"
api.expectPatchRelease({ api.expectPatchRelease({
inspectRequest: (_uri, requestBody) => { inspectRequest: async (request: Request) => {
const releaseBody = requestBody as Partial< const body = (await request.json()) as Partial<
import('@balena/compose/dist/release/models').ReleaseModel import('@balena/compose/dist/release/models').ReleaseModel
>; >;
expect(releaseBody.status).to.equal('failed'); expect(body.status).to.equal('failed');
}, },
}); });
api.expectPostImageLabel(); api.expectPostImageLabel();
@ -386,8 +385,8 @@ describe('balena deploy', function () {
let succesfullImagePatchRequests = 0; let succesfullImagePatchRequests = 0;
api api
.optPatch(/^\/v7\/image($|[(?])/, { times: maxRequestRetries }) .optPatch(/^\/v7\/image($|[(?])/, { times: maxRequestRetries })
.reply((_uri, requestBody) => { .reply(async (request) => {
const imageBody = requestBody as Partial< const imageBody = (await request.json()) as Partial<
import('@balena/compose/dist/release/models').ImageModel import('@balena/compose/dist/release/models').ImageModel
>; >;
expect(imageBody.status).to.equal('success'); expect(imageBody.status).to.equal('success');

View File

@ -61,12 +61,15 @@ export class BalenaAPIMock extends NockMock {
} }
public expectDownloadConfig(opts: ScopeOpts = {}) { public expectDownloadConfig(opts: ScopeOpts = {}) {
this.optPost('/download-config', opts).reply(200, (_uri, body) => { this.optPost('/download-config', opts).reply(
let deviceType = 'raspberrypi3'; 200,
if (typeof body === 'object' && 'deviceType' in body) { async (request: Request) => {
deviceType = body.deviceType; const body = await request.json();
} let deviceType = 'raspberrypi3';
return JSON.parse(`{ if (typeof body === 'object' && 'deviceType' in body) {
deviceType = body.deviceType;
}
return JSON.parse(`{
"applicationId":1301645, "applicationId":1301645,
"deviceType":"${deviceType}", "deviceType":"${deviceType}",
"userId":43699, "userId":43699,
@ -79,7 +82,8 @@ export class BalenaAPIMock extends NockMock {
"deltaEndpoint":"https://delta.balena-cloud.com", "deltaEndpoint":"https://delta.balena-cloud.com",
"apiKey":"nothingtoseehere" "apiKey":"nothingtoseehere"
}`); }`);
}); },
);
} }
public expectApplicationProvisioning(opts: ScopeOpts = {}) { public expectApplicationProvisioning(opts: ScopeOpts = {}) {
@ -284,8 +288,8 @@ export class BalenaAPIMock extends NockMock {
public expectGetAppServiceVars(opts: ScopeOpts = {}) { public expectGetAppServiceVars(opts: ScopeOpts = {}) {
this.optGet(/^\/v\d+\/service_environment_variable($|\?)/, opts).reply( this.optGet(/^\/v\d+\/service_environment_variable($|\?)/, opts).reply(
function (uri, _requestBody) { function (request) {
const match = uri.match(/service_name%20eq%20%27(.+?)%27/); const match = request.url.match(/service_name%20eq%20%27(.+?)%27/);
const serviceName = match?.[1] || undefined; const serviceName = match?.[1] || undefined;
let varArray: any[]; let varArray: any[];
if (serviceName) { if (serviceName) {
@ -332,8 +336,8 @@ export class BalenaAPIMock extends NockMock {
this.optGet( this.optGet(
/^\/v\d+\/device_service_environment_variable($|\?)/, /^\/v\d+\/device_service_environment_variable($|\?)/,
opts, opts,
).reply(function (uri, _requestBody) { ).reply(function (request) {
const match = uri.match(/service_name%20eq%20%27(.+?)%27/); const match = request.url.match(/service_name%20eq%20%27(.+?)%27/);
const serviceName = match?.[1] || undefined; const serviceName = match?.[1] || undefined;
let varArray: any[]; let varArray: any[];
if (serviceName) { if (serviceName) {

View File

@ -16,12 +16,7 @@
*/ */
import * as path from 'path'; import * as path from 'path';
import * as zlib from 'zlib';
import { NockMock } from './nock-mock'; import { NockMock } from './nock-mock';
import { promisify } from 'util';
const gunzipAsync = promisify(zlib.gunzip);
export const builderResponsePath = path.normalize( export const builderResponsePath = path.normalize(
path.join(__dirname, '..', 'test-data', 'builder-response'), path.join(__dirname, '..', 'test-data', 'builder-response'),
@ -40,25 +35,17 @@ export class BuilderMock extends NockMock {
checkURI: (uri: string) => Promise<void> | void; checkURI: (uri: string) => Promise<void> | void;
checkBuildRequestBody: (requestBody: string | Buffer) => Promise<void>; checkBuildRequestBody: (requestBody: string | Buffer) => Promise<void>;
}) { }) {
this.optPost(/^\/v3\/build($|[(?])/, opts).reply( this.optPost(/^\/v3\/build($|[(?])/, opts).reply(async function (
async function (uri, requestBody, callback) { request: Request,
let error: Error | null = null; ) {
try { await opts.checkURI(request.url);
await opts.checkURI(uri); const requestBody = await request.text();
if (typeof requestBody === 'string') { if (typeof requestBody === 'string') {
const gzipped = Buffer.from(requestBody, 'hex'); await opts.checkBuildRequestBody(requestBody);
const gunzipped = await gunzipAsync(gzipped); } else {
await opts.checkBuildRequestBody(gunzipped); throw new Error(`unexpected requestBody type "${typeof requestBody}"`);
} else { }
throw new Error( return [opts.responseCode, opts.responseBody];
`unexpected requestBody type "${typeof requestBody}"`, });
);
}
} catch (err) {
error = err;
}
callback(error, [opts.responseCode, opts.responseBody]);
},
);
} }
} }

View File

@ -81,21 +81,15 @@ export class DockerMock extends NockMock {
this.optPost( this.optPost(
new RegExp(`^/build\\?(|.+&)${qs.stringify({ t: opts.tag })}&`), new RegExp(`^/build\\?(|.+&)${qs.stringify({ t: opts.tag })}&`),
opts, opts,
).reply(async function (uri, requestBody, cb) { ).reply(async function (request) {
let error: Error | null = null; await opts.checkURI(request.url);
try { const requestBody = await request.text();
await opts.checkURI(uri); if (typeof requestBody === 'string') {
if (typeof requestBody === 'string') { await opts.checkBuildRequestBody(requestBody);
await opts.checkBuildRequestBody(requestBody); } else {
} else { throw new Error(`unexpected requestBody type "${typeof requestBody}"`);
throw new Error(
`unexpected requestBody type "${typeof requestBody}"`,
);
}
} catch (err) {
error = err;
} }
cb(error, [opts.responseCode, opts.responseBody]); return [opts.responseCode, opts.responseBody];
}); });
} }

View File

@ -100,47 +100,28 @@ export class NockMock {
return this.optMethod('post', uri, opts); return this.optMethod('post', uri, opts);
} }
protected inspectNoOp(_uri: string, _requestBody: nock.Body): void { protected inspectNoOp(_request: Request): void | Promise<void> {
return undefined; return;
} }
protected getInspectedReplyBodyFunction( protected getInspectedReplyBodyFunction(
inspectRequest: (uri: string, requestBody: nock.Body) => void, inspectRequest: (request: Request) => void | Promise<void>,
replyBody: nock.ReplyBody, replyBody: nock.ReplyBody,
) { ) {
return function ( return async function (request: Request): Promise<nock.ReplyBody> {
this: nock.ReplyFnContext, await inspectRequest(request);
uri: string, return replyBody;
requestBody: nock.Body,
cb: (err: NodeJS.ErrnoException | null, result: nock.ReplyBody) => void,
) {
try {
inspectRequest(uri, requestBody);
} catch (err) {
cb(err, '');
}
cb(null, replyBody);
}; };
} }
protected getInspectedReplyFileFunction( protected getInspectedReplyFileFunction(
inspectRequest: (uri: string, requestBody: nock.Body) => void, inspectRequest: (request: Request) => void | Promise<void>,
replyBodyFile: string, replyBodyFile: string,
) { ) {
return function ( return async function (request: Request): Promise<nock.ReplyBody> {
this: nock.ReplyFnContext, await inspectRequest(request);
uri: string,
requestBody: nock.Body,
cb: (err: NodeJS.ErrnoException | null, result: nock.ReplyBody) => void,
) {
try {
inspectRequest(uri, requestBody);
} catch (err) {
cb(err, '');
}
const replyBody = fs.readFileSync(replyBodyFile); const replyBody = fs.readFileSync(replyBodyFile);
cb(null, replyBody); return replyBody;
}; };
} }

View File

@ -48,8 +48,8 @@ export class SupervisorMock extends NockMock {
}, 10); }, 10);
}, },
}); });
this.optGet('/v2/local/logs', opts).reply((_uri, _reqBody, cb) => { this.optGet('/v2/local/logs', opts).reply(() => {
cb(null, [200, chunkedStream]); return [200, chunkedStream];
}); });
} }
} }