Skip to content

Commit 755c283

Browse files
feat: make deploy zip size and zip file count available (#1403)
* feat: send zip file size in pre deploy event * feat: send zip file size in pre deploy event * feat: fire event with zip file size and file count * feat: zipSize and zipFileCount in DeployResult * fix: unit test * test: unit test updates --------- Co-authored-by: Cristian Dominguez <[email protected]>
1 parent 5f819ec commit 755c283

File tree

11 files changed

+503
-1658
lines changed

11 files changed

+503
-1658
lines changed

CHANGELOG.md

Lines changed: 438 additions & 1643 deletions
Large diffs are not rendered by default.

src/client/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export {
4343
PackageOptions,
4444
RetrieveOptions,
4545
DeployVersionData,
46+
DeployZipData,
4647
RetrieveVersionData,
4748
MetadataApiRetrieveOptions,
4849
} from './types';

src/client/metadataApiDeploy.ts

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ export class DeployResult implements MetadataTransferResult {
4343
public constructor(
4444
public readonly response: MetadataApiDeployStatus,
4545
public readonly components?: ComponentSet,
46-
public readonly replacements = new Map<string, string[]>()
46+
public readonly replacements = new Map<string, string[]>(),
47+
public readonly zipMeta?: { zipSize: number; zipFileCount?: number }
4748
) {}
4849

4950
public getFileResponses(): FileResponse[] {
@@ -97,6 +98,8 @@ export class MetadataApiDeploy extends MetadataTransfer<
9798
// from the apiOptions and we need it for telemetry.
9899
private readonly isRestDeploy: boolean;
99100
private readonly registry: RegistryAccess;
101+
private zipSize?: number;
102+
private zipFileCount?: number;
100103

101104
public constructor(options: MetadataApiDeployOptions) {
102105
super(options);
@@ -207,7 +210,10 @@ export class MetadataApiDeploy extends MetadataTransfer<
207210
})
208211
);
209212

210-
const [zipBuffer] = await Promise.all([this.getZipBuffer(), this.maybeSaveTempDirectory('metadata')]);
213+
const [{ zipBuffer, zipFileCount }] = await Promise.all([
214+
this.getZipBuffer(),
215+
this.maybeSaveTempDirectory('metadata'),
216+
]);
211217
// SDR modifies what the mdapi expects by adding a rest param
212218
const { rest, ...optionsWithoutRest } = this.options.apiOptions ?? {};
213219

@@ -217,7 +223,17 @@ export class MetadataApiDeploy extends MetadataTransfer<
217223
const manifestMsg = manifestVersion ? ` in v${manifestVersion} shape` : '';
218224
const debugMsg = format(`Deploying metadata source%s using ${webService} v${apiVersion}`, manifestMsg);
219225
this.logger.debug(debugMsg);
226+
227+
// Event and Debug output for the zip file used for deploy
228+
this.zipSize = zipBuffer.byteLength;
229+
let zipMessage = `Deployment zip file size = ${this.zipSize} Bytes`;
230+
if (zipFileCount) {
231+
this.zipFileCount = zipFileCount;
232+
zipMessage += ` containing ${zipFileCount} files`;
233+
}
234+
this.logger.debug(zipMessage);
220235
await LifecycleInstance.emit('apiVersionDeploy', { webService, manifestVersion, apiVersion });
236+
await LifecycleInstance.emit('deployZipData', { zipSize: this.zipSize, zipFileCount });
221237

222238
return this.isRestDeploy
223239
? connection.metadata.deployRest(zipBuffer, optionsWithoutRest)
@@ -266,6 +282,8 @@ export class MetadataApiDeploy extends MetadataTransfer<
266282
numberTestsTotal: result.numberTestsTotal,
267283
testsTotalTime: result.details?.runTestResult?.totalTime,
268284
filesWithReplacementsQuantity: this.replacements.size ?? 0,
285+
zipSize: this.zipSize ?? 0,
286+
zipFileCount: this.zipFileCount ?? 0,
269287
});
270288
} catch (err) {
271289
const error = err as Error;
@@ -278,7 +296,8 @@ export class MetadataApiDeploy extends MetadataTransfer<
278296
const deployResult = new DeployResult(
279297
result,
280298
this.components,
281-
new Map(Array.from(this.replacements).map(([k, v]) => [k, Array.from(v)]))
299+
new Map(Array.from(this.replacements).map(([k, v]) => [k, Array.from(v)])),
300+
{ zipSize: this.zipSize ?? 0, zipFileCount: this.zipFileCount }
282301
);
283302
// only do event hooks if source, (NOT a metadata format) deploy
284303
if (this.options.components) {
@@ -292,14 +311,17 @@ export class MetadataApiDeploy extends MetadataTransfer<
292311
return deployResult;
293312
}
294313

295-
private async getZipBuffer(): Promise<Buffer> {
314+
private async getZipBuffer(): Promise<{ zipBuffer: Buffer; zipFileCount?: number }> {
296315
const mdapiPath = this.options.mdapiPath;
316+
317+
// Zip a directory of metadata format source
297318
if (mdapiPath) {
298319
if (!fs.existsSync(mdapiPath) || !fs.lstatSync(mdapiPath).isDirectory()) {
299320
throw messages.createError('error_directory_not_found_or_not_directory', [mdapiPath]);
300321
}
301322

302323
const zip = JSZip();
324+
let zipFileCount = 0;
303325

304326
const zipDirRecursive = (dir: string): void => {
305327
const dirents = fs.readdirSync(dir, { withFileTypes: true });
@@ -313,33 +335,38 @@ export class MetadataApiDeploy extends MetadataTransfer<
313335
// Ensure only posix paths are added to zip files
314336
const relPosixPath = relPath.replace(/\\/g, '/');
315337
zip.file(relPosixPath, fs.createReadStream(fullPath));
338+
zipFileCount++;
316339
}
317340
}
318341
};
319342
this.logger.debug('Zipping directory for metadata deploy:', mdapiPath);
320343
zipDirRecursive(mdapiPath);
321344

322-
return zip.generateAsync({
323-
type: 'nodebuffer',
324-
compression: 'DEFLATE',
325-
compressionOptions: { level: 9 },
326-
});
345+
return {
346+
zipBuffer: await zip.generateAsync({
347+
type: 'nodebuffer',
348+
compression: 'DEFLATE',
349+
compressionOptions: { level: 9 },
350+
}),
351+
zipFileCount,
352+
};
327353
}
328-
// read the zip into a buffer
354+
// Read a zip of metadata format source into a buffer
329355
if (this.options.zipPath) {
330356
if (!fs.existsSync(this.options.zipPath)) {
331357
throw new SfError(messages.getMessage('error_path_not_found', [this.options.zipPath]));
332358
}
333359
// does encoding matter for zip files? I don't know
334-
return fs.promises.readFile(this.options.zipPath);
360+
return { zipBuffer: await fs.promises.readFile(this.options.zipPath) };
335361
}
362+
// Convert a ComponentSet of metadata in source format and zip
336363
if (this.options.components && this.components) {
337364
const converter = new MetadataConverter(this.registry);
338-
const { zipBuffer } = await converter.convert(this.components, 'metadata', { type: 'zip' });
365+
const { zipBuffer, zipFileCount } = await converter.convert(this.components, 'metadata', { type: 'zip' });
339366
if (!zipBuffer) {
340367
throw new SfError(messages.getMessage('zipBufferError'));
341368
}
342-
return zipBuffer;
369+
return { zipBuffer, zipFileCount };
343370
}
344371
throw new Error('Options should include components, zipPath, or mdapiPath');
345372
}

src/client/types.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,14 @@ export type DeployVersionData = {
371371
webService: 'SOAP' | 'REST';
372372
};
373373

374+
/**
375+
* Data about a deployment zip file being sent to the Metadata API.
376+
*/
377+
export type DeployZipData = {
378+
zipSize: number;
379+
zipFileCount: number;
380+
};
381+
374382
export type RetrieveVersionData = {
375383
apiVersion: string;
376384
manifestVersion: string;

src/convert/metadataConverter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ const getResult =
9191
if ('addToZip' in writer) {
9292
const buffer = writer.buffer;
9393
if (!packagePath) {
94-
return { packagePath, zipBuffer: buffer };
94+
return { packagePath, zipBuffer: buffer, zipFileCount: writer.fileCount };
9595
} else if (buffer) {
9696
await promises.writeFile(packagePath, buffer);
9797
return { packagePath };

src/convert/streams.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,10 @@ export class StandardWriter extends ComponentWriter {
191191
}
192192

193193
export class ZipWriter extends ComponentWriter {
194+
/**
195+
* Count of files (not directories) added to the zip file.
196+
*/
197+
public fileCount: number = 0;
194198
private zip = JSZip();
195199
private zipBuffer?: Buffer;
196200

@@ -244,6 +248,7 @@ export class ZipWriter extends ComponentWriter {
244248
// Ensure only posix paths are added to zip files
245249
const posixPath = path.replace(/\\/g, '/');
246250
this.zip.file(posixPath, contents);
251+
this.fileCount++;
247252
}
248253
}
249254

src/convert/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ export type ConvertResult = {
114114
* Buffer of converted package. `Undefined` if `outputDirectory` is omitted from zip output config.
115115
*/
116116
zipBuffer?: Buffer;
117+
/**
118+
* When a zip buffer is created, this is the number of files in the zip.
119+
*/
120+
zipFileCount?: number;
117121
/**
118122
* Converted source components. Not set if archiving the package.
119123
*/

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export {
4444
PackageOptions,
4545
RetrieveOptions,
4646
DeployVersionData,
47+
DeployZipData,
4748
RetrieveVersionData,
4849
} from './client';
4950
export {

test/client/metadataApiDeploy.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,8 @@ describe('MetadataApiDeploy', () => {
156156

157157
await operation.start();
158158
const result = await operation.pollStatus();
159-
const expected = new DeployResult(response, deployedComponents);
159+
const zipMeta = { zipSize: 4, zipFileCount: undefined };
160+
const expected = new DeployResult(response, deployedComponents, undefined, zipMeta);
160161

161162
expect(result).to.deep.equal(expected);
162163
});

test/convert/metadataConverter.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ describe('MetadataConverter', () => {
322322
const result = await converter.convert(components, 'metadata', { type: 'zip' });
323323

324324
expect(result.zipBuffer).to.deep.equal(testBuffer);
325+
expect(result.zipFileCount).to.equal(1);
325326
});
326327

327328
it('should return packagePath in result', async () => {

test/convert/streams.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,7 @@ describe('Streams', () => {
483483
// NOTE: Zips must only contain files with posix paths
484484
expect(jsZipFileStub.firstCall.args[0]).to.equal('classes/myComponent.cls-meta.xml');
485485
expect(jsZipFileStub.firstCall.args[1]).to.deep.equal(Buffer.from('hi'));
486+
expect(writer.fileCount).to.equal(3);
486487
});
487488

488489
it('should add entries to zip based on given write infos when zip is in-memory only', async () => {
@@ -495,6 +496,7 @@ describe('Streams', () => {
495496
});
496497
expect(jsZipFileStub.firstCall.args[0]).to.equal('classes/myComponent.cls-meta.xml');
497498
expect(jsZipFileStub.firstCall.args[1]).to.deep.equal(Buffer.from('hi'));
499+
expect(writer.fileCount).to.equal(3);
498500
});
499501

500502
it('should generateAsync zip when stream is finished', async () => {

0 commit comments

Comments
 (0)