-
Notifications
You must be signed in to change notification settings - Fork 35
Expand file tree
/
Copy pathdiagnostics.ts
More file actions
153 lines (136 loc) · 6.56 KB
/
Copy pathdiagnostics.ts
File metadata and controls
153 lines (136 loc) · 6.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
* Copyright 2026, Salesforce, Inc.
*
* 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 { ConfigAggregator, Lifecycle, Logger, Messages, SfProject, OrgConfigProperties, Org } from '@salesforce/core';
import { SfDoctor } from '@salesforce/plugin-info';
type HookFunction = (options: { doctor: SfDoctor }) => Promise<[void]>;
let logger: Logger;
const getLogger = (): Logger => {
if (!logger) {
logger = Logger.childFromRoot('plugin-deploy-retrieve-diagnostics');
}
return logger;
};
const pluginName = '@salesforce/plugin-deploy-retrieve';
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
const messages = Messages.loadMessages(pluginName, 'diagnostics');
export const hook: HookFunction = async (options) => {
getLogger().debug(`Running SfDoctor diagnostics for ${pluginName}`);
return Promise.all([apiVersionTest(options.doctor)]);
};
// ============================
// *** DIAGNOSTIC TESTS ***
// ============================
// Gathers and compares the following API versions:
// 1. apiVersion (if set) from the sfdx config, including environment variable
// 2. sourceApiVersion (if set) from sfdx-project.json
// 3. max apiVersion of the default target dev hub org (if set)
// 4. max apiVersion of the default target org (if set)
//
// Warns if:
// 1. apiVersion and sourceApiVersion are set but not equal
// 2. apiVersion and sourceApiVersion are both not set
// 3. default devhub target org and default target org have different max apiVersions
// 4. sourceApiVersion is set and does not match max apiVersion of default target org
// 5. apiVersion is set and does not match max apiVersion of default target org
const apiVersionTest = async (doctor: SfDoctor): Promise<void> => {
getLogger().debug('Running API Version tests');
// check org-api-version from ConfigAggregator
const aggregator = await ConfigAggregator.create();
const apiVersion = aggregator.getPropertyValue<string>(OrgConfigProperties.ORG_API_VERSION);
const sourceApiVersion = await getSourceApiVersion();
const targetDevHub = aggregator.getPropertyValue<string>(OrgConfigProperties.TARGET_DEV_HUB);
const targetOrg = aggregator.getPropertyValue<string>(OrgConfigProperties.TARGET_ORG);
const targetDevHubApiVersion = targetDevHub && (await getMaxApiVersion(aggregator, targetDevHub));
const targetOrgApiVersion = targetOrg && (await getMaxApiVersion(aggregator, targetOrg));
doctor.addPluginData(pluginName, {
apiVersion,
sourceApiVersion,
targetDevHubApiVersion,
targetOrgApiVersion,
});
const testName1 = `[${pluginName}] sourceApiVersion matches apiVersion`;
let status1 = 'pass';
if (diff(sourceApiVersion, apiVersion)) {
status1 = 'warn';
doctor.addSuggestion(messages.getMessage('apiVersionMismatch'));
}
if (sourceApiVersion === undefined && apiVersion === undefined) {
status1 = 'warn';
doctor.addSuggestion(messages.getMessage('apiVersionUnset'));
}
void Lifecycle.getInstance().emit('Doctor:diagnostic', { testName: testName1, status: status1 });
if (targetDevHubApiVersion && targetOrgApiVersion) {
const testName2 = `[${pluginName}] default target DevHub max apiVersion matches default target org max apiVersion`;
let status2 = 'pass';
if (diff(targetDevHubApiVersion, targetOrgApiVersion)) {
status2 = 'warn';
doctor.addSuggestion(messages.getMessage('maxApiVersionMismatch'));
}
void Lifecycle.getInstance().emit('Doctor:diagnostic', { testName: testName2, status: status2 });
}
// Only run this test if both sourceApiVersion and the default target org max version are set.
if (sourceApiVersion?.length && targetOrgApiVersion?.length) {
const testName3 = `[${pluginName}] sourceApiVersion matches default target org max apiVersion`;
let status3 = 'pass';
if (diff(sourceApiVersion, targetOrgApiVersion)) {
status3 = 'warn';
doctor.addSuggestion(messages.getMessage('sourceApiVersionMaxMismatch', [targetOrgApiVersion]));
}
void Lifecycle.getInstance().emit('Doctor:diagnostic', { testName: testName3, status: status3 });
}
// Only run this test if both apiVersion and the default target org max version are set.
if (apiVersion?.length && targetOrgApiVersion?.length) {
const testName4 = `[${pluginName}] apiVersion matches default target org max apiVersion`;
let status4 = 'pass';
if (diff(apiVersion, targetOrgApiVersion)) {
status4 = 'warn';
doctor.addSuggestion(messages.getMessage('apiVersionMaxMismatch', [targetOrgApiVersion]));
}
void Lifecycle.getInstance().emit('Doctor:diagnostic', { testName: testName4, status: status4 });
}
};
// check sfdx-project.json for sourceApiVersion
const getSourceApiVersion = async (): Promise<string | undefined> => {
try {
const project = SfProject.getInstance();
const projectJson = await project.resolveProjectConfig();
return projectJson.sourceApiVersion as string | undefined;
} catch (error) {
const errMsg = (error as Error).message;
getLogger().debug(`Cannot determine sourceApiVersion due to: ${errMsg}`);
}
};
// check max API version for default orgs
const getMaxApiVersion = async (aggregator: ConfigAggregator, aliasOrUsername: string): Promise<string | undefined> => {
try {
const org = await Org.create({ aliasOrUsername, aggregator });
return await org.retrieveMaxApiVersion();
} catch (error) {
const errMsg = (error as Error).message;
getLogger().debug(`Cannot determine the max ApiVersion for org: [${aliasOrUsername}] due to: ${errMsg}`);
}
};
// Compare 2 API versions that have values and return if they are different.
// E.g.,
// Comparing undefined with 56.0 would return false.
// Comparing undefined with undefined would return false.
// Comparing 55.0 with 55.0 would return false.
// Comparing 55.0 with 56.0 would return true.
const diff = (version1: string | undefined, version2: string | undefined): boolean => {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
getLogger().debug(`Comparing API versions: [${version1},${version2}]`);
return !!version1?.length && !!version2?.length && version1 !== version2;
};