From 834292d3f91c34f6aab712821706172c9e9938fd Mon Sep 17 00:00:00 2001 From: Peter van Gulik Date: Wed, 19 Feb 2020 18:29:35 +0100 Subject: [PATCH] Reduced logging for cache decorator. Fix issue with refresh datapack command. Ensure production Salesforce metadata deployments always use checkOnly flag. --- CHANGELOG.md | 5 +++ package-lock.json | 36 +++++++++++++------ package.json | 2 +- src/services/salesforceService.ts | 43 ++++++++++++++++++----- src/services/vlocityMatchingKeyService.ts | 8 ++--- src/util/cache.ts | 6 ++-- 6 files changed, 73 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 236f0dbd..5b762846 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog Vlocity Salesforce Integration for VSCode +## [0.12.13] - 2019-02-19 + - Fix refresh datapack error + - More logging for Salesforce deployments + - Force all production deployment requests to check only + ## [0.12.12] - 2019-02-19 - Auto create and delete `-meta.xml` files for classes - Auto create boiler plate code for APEX classes and interfaces diff --git a/package-lock.json b/package-lock.json index a76619d2..647fb9a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "vlocode", - "version": "0.12.12", + "version": "0.12.13", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -811,9 +811,9 @@ } }, "@types/node": { - "version": "13.7.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.7.2.tgz", - "integrity": "sha512-uvilvAQbdJvnSBFcKJ2td4016urcGvsiR+N4dHGU87ml8O2Vl6l+ErOi9w0kXSPiwJ1AYlIW+0pDXDWWMOiWbw==", + "version": "10.17.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.15.tgz", + "integrity": "sha512-daFGV9GSs6USfPgxceDA8nlSe48XrVCJfDeYm7eokxq/ye7iuOH87hKXgMtEAVLFapkczbZsx868PMDT1Y0a6A==", "dev": true }, "@types/request": { @@ -5454,12 +5454,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5474,17 +5476,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -5601,7 +5606,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -5613,6 +5619,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5627,6 +5634,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -5634,12 +5642,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -5658,6 +5668,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -5738,7 +5749,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -5750,6 +5762,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -5871,6 +5884,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", diff --git a/package.json b/package.json index 0bb8e889..c6818d6a 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "vlocode", "displayName": "Salesforce Vlocity Integration", "description": "Salesforce and Vlocity development and deployment extension for VSCode", - "version": "0.12.12", + "version": "0.12.13", "license": "MIT", "icon": "resources/icon.png", "author": { diff --git a/src/services/salesforceService.ts b/src/services/salesforceService.ts index 39f4bc35..02feb060 100644 --- a/src/services/salesforceService.ts +++ b/src/services/salesforceService.ts @@ -392,6 +392,9 @@ export default class SalesforceService implements JsForceConnectionProvider { const packageXml = new PackageXml(manifest.apiVersion || '45.0'); const packageZip = new ZipArchive(); + // Log + this.logger.verbose(`Building metadata ZIP package API ${packageXml.version}`); + for (const [packagePath, info] of Object.entries(manifest.files)) { // Stop directly and return null if (token && token.isCancellationRequested) { @@ -424,6 +427,8 @@ export default class SalesforceService implements JsForceConnectionProvider { const mdPackage : MetadataManifest = { files: {} }; const metaFiles = await getMetaFiles(files.map(file => file.fsPath), true); + this.logger.verbose(`Building package manifest for ${files.length} selected files/folders`); + // Build zip archive for all expanded files // Note use posix path separators when building package.zip for (const metaFile of metaFiles) { @@ -594,6 +599,7 @@ export default class SalesforceService implements JsForceConnectionProvider { private async deploy(zipInput: Stream | Buffer | string | ZipArchive, options?: jsforce.DeployOptions, progress?: DeploymentProgress, token?: vscode.CancellationToken) : Promise { const startTime = new Date().getTime(); const checkInterval = 500; + const logInterval = 5000; const deploymentTypeText = options && options.checkOnly ? 'Validate' : 'Deploy'; const deploymentTask = async (progress: DeploymentProgress, cancellationToken: vscode.CancellationToken) => { @@ -608,36 +614,57 @@ export default class SalesforceService implements JsForceConnectionProvider { }); } - // Start deploy - const connection = await this.getJsForceConnection(); - const deployJob = await connection.metadata.deploy(zipInput, { + // Set deploy options passed to JSforce; options arg can override the defaults + const deployOptions = { singlePackage: true, performRetrieve: true, - ignoreWarnings: false, + ignoreWarnings: true, autoUpdatePackage: false, allowMissingFiles: false, - // We asssume we only run on developer orgs, as such set these options to true by default + // We assume we only run on developer orgs by default purgeOnDelete: true, rollbackOnError: false, ...options - }); + }; + + if (await this.isProductionOrg()) { + this.logger.warn(`Production deployment detected; running as validate/checkOnly`); + // Always check only for production + deployOptions.rollbackOnError = true; + deployOptions.purgeOnDelete = false; + deployOptions.checkOnly = true; + } + + // Start deploy + const connection = await this.getJsForceConnection(); + const deployJob = await connection.metadata.deploy(zipInput, deployOptions); // Wait for deploy + let lastConsoleLog = 0; while (await wait(checkInterval)) { if (cancellationToken && cancellationToken.isCancellationRequested) { - // Cancel deployment; we don't really care if the cancel is successfull or not + // Cancel deployment; we don't really care if the cancel is successfully or not (connection.metadata).cancelDeploy(deployJob.id); throw new Error(`${deploymentTypeText} cancelled`); } const status = await connection.metadata.checkDeployStatus(deployJob.id, true); + + if (Date.now() - lastConsoleLog > logInterval) { + // do not create seperate interval for logging but use the main status check loop + this.logger.info( + `Deployment ${status.id} - ${status.status} ` + + `(${status.numberComponentsDeployed ?? 0}/${status.numberComponentsTotal ?? 0})`); + lastConsoleLog = Date.now(); + } + if (status.done) { const details : any = status.details; if (details.componentFailures && !Array.isArray(details.componentFailures)) { details.componentFailures = [ details.componentFailures ]; } return status; - } + } } }; diff --git a/src/services/vlocityMatchingKeyService.ts b/src/services/vlocityMatchingKeyService.ts index 5aec1764..ca05b102 100644 --- a/src/services/vlocityMatchingKeyService.ts +++ b/src/services/vlocityMatchingKeyService.ts @@ -25,10 +25,10 @@ export default class VlocityMatchingKeyService { //private matchingKeys = new Lazy(() => this.loadAllMatchingKeys()); private readonly matchingKeyQuery = new QueryBuilder('vlocity_namespace__DRMatchingKey__mdt') - .select('Name', 'vlocity_namespace__MatchingKeyFields__c', 'vlocity_namespace__ObjectAPIName__c', 'vlocity_namespace__ReturnKeyField__c') + .select('Label', 'vlocity_namespace__MatchingKeyFields__c', 'vlocity_namespace__ObjectAPIName__c', 'vlocity_namespace__ReturnKeyField__c') .build(); - private readonly datapackConfigQuery = new QueryBuilder('vlocity_namespace__VlocityDataPackConfiguration_mdt') - .select('Name', 'vlocity_namespace__PrimarySObjectType__c') + private readonly datapackConfigQuery = new QueryBuilder('vlocity_namespace__VlocityDataPackConfiguration__mdt') + .select('Label', 'vlocity_namespace__PrimarySObjectType__c') .build(); constructor( @@ -145,7 +145,7 @@ export default class VlocityMatchingKeyService { const matchingKeyObjects = matchingKeyResults.map(record => { return { sobjectType: record.ObjectAPIName__c, - datapackType: this.getDatapackType(record.ObjectAPIName__c) ?? record.Name, + datapackType: this.getDatapackType(record.ObjectAPIName__c) ?? record.Label, fields: record.MatchingKeyFields__c.split(',').map(s => s.trim()), returnField: record.ReturnKeyField__c }; diff --git a/src/util/cache.ts b/src/util/cache.ts index 6b2f9778..1200632e 100644 --- a/src/util/cache.ts +++ b/src/util/cache.ts @@ -54,7 +54,7 @@ export default function cache(ttl: number = 60) { const key = args.reduce((checksum, arg) => checksum + (arg?.toString() ?? ''), name); const cachedValue = cache.get(key); if (cachedValue) { - logger().verbose(`Cache HIT -> ${name}`); + logger().debug(`Load response from cache -> ${name}`); return cachedValue; } // Exceptions cause @@ -62,12 +62,12 @@ export default function cache(ttl: number = 60) { if (ttl > 0) { setTimeout(() => cache.delete(key), ttl * 1000); } - logger().verbose(`Cache MISS -> ${name}`); + logger().debug(`Cache miss, retrieve value from source -> ${name}`); cache.set(key, newValue); if (isPromise(newValue)) { // Remove invalid results from the cache newValue.catch(err => { - logger().verbose(`Cache exception -> ${name}`); + logger().debug(`Delete cached promise on exception -> ${name}`); cache.delete(key); // Rethrow the exceptions so the original handler can handle it throw err;