sf-delta-tests 0.0.27 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -146
- package/lib/commands/delta/test-classes.d.ts +12 -9
- package/lib/commands/delta/test-classes.js +63 -48
- package/lib/commands/delta/test-classes.js.map +1 -1
- package/lib/elements/object-types.js +23 -26
- package/lib/elements/object-types.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -2
- package/lib/index.js.map +1 -1
- package/lib/services/apex-class-service.js +8 -12
- package/lib/services/apex-class-service.js.map +1 -1
- package/lib/services/cli-service.js +1 -5
- package/lib/services/cli-service.js.map +1 -1
- package/lib/services/dependency-service.js +19 -22
- package/lib/services/dependency-service.js.map +1 -1
- package/lib/services/dependency-services.test.js +6 -8
- package/lib/services/dependency-services.test.js.map +1 -1
- package/lib/services/flow-service.d.ts +41 -0
- package/lib/services/flow-service.js +136 -0
- package/lib/services/flow-service.js.map +1 -0
- package/lib/services/manifest-service.d.ts +6 -2
- package/lib/services/manifest-service.js +13 -16
- package/lib/services/manifest-service.js.map +1 -1
- package/lib/services/output-service.d.ts +1 -1
- package/lib/services/output-service.js +10 -13
- package/lib/services/output-service.js.map +1 -1
- package/messages/delta.test-classes.md +28 -24
- package/oclif.manifest.json +51 -24
- package/package.json +12 -11
package/README.md
CHANGED
|
@@ -1,146 +1,79 @@
|
|
|
1
|
-
# sf-delta-tests
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
This
|
|
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
|
-
Agreement. You can do so by going to https://cla.salesforce.com/sign-cla.
|
|
81
|
-
|
|
82
|
-
### Build
|
|
83
|
-
|
|
84
|
-
To build the plugin locally, make sure to have yarn installed and run the following commands:
|
|
85
|
-
|
|
86
|
-
```bash
|
|
87
|
-
# Clone the repository
|
|
88
|
-
git clone git@github.com:salesforcecli/focus-tests
|
|
89
|
-
|
|
90
|
-
# Install the dependencies and compile
|
|
91
|
-
yarn && yarn build
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
To use your plugin, run using the local `./bin/dev` or `./bin/dev.cmd` file.
|
|
95
|
-
|
|
96
|
-
```bash
|
|
97
|
-
# Run using local run file.
|
|
98
|
-
./bin/dev hello world
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
There should be no differences when running via the Salesforce CLI or using the local run file. However, it can be useful to link the plugin to do some additional testing or run your commands from anywhere on your machine.
|
|
102
|
-
|
|
103
|
-
```bash
|
|
104
|
-
# Link your plugin to the sf cli
|
|
105
|
-
sf plugins link .
|
|
106
|
-
# To verify
|
|
107
|
-
sf plugins
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
## Commands
|
|
111
|
-
|
|
112
|
-
<!-- commands -->
|
|
113
|
-
|
|
114
|
-
- [`sf delta test-classes`](#sf-delta-test-classes)
|
|
115
|
-
|
|
116
|
-
## `sf delta test-classes`
|
|
117
|
-
|
|
118
|
-
Calculates the tests needed to be ran based on the changed metadata given using the Salesforce Dependency API
|
|
119
|
-
|
|
120
|
-
```
|
|
121
|
-
USAGE
|
|
122
|
-
$ sf delta test-classes -o <value> -c <value> [--json] [-n <value>]
|
|
123
|
-
|
|
124
|
-
FLAGS
|
|
125
|
-
-c, --changed-metadata=<value> (required) Comma seperated list of changed metadata.
|
|
126
|
-
-n, --name=<value> Description of a flag.
|
|
127
|
-
-o, --target-org=<value> (required) The org you want to check the dependencies against.
|
|
128
|
-
|
|
129
|
-
GLOBAL FLAGS
|
|
130
|
-
--json Format output as json.
|
|
131
|
-
|
|
132
|
-
DESCRIPTION
|
|
133
|
-
Calculates the tests needed to be ran based on the changed metadata given using the Salesforce Dependency API
|
|
134
|
-
|
|
135
|
-
Calculates the tests needed to be ran based on the changed metadata given using the Salesforce Dependency API
|
|
136
|
-
|
|
137
|
-
EXAMPLES
|
|
138
|
-
$ sf delta test-classes
|
|
139
|
-
|
|
140
|
-
FLAG DESCRIPTIONS
|
|
141
|
-
-n, --name=<value> Description of a flag.
|
|
142
|
-
|
|
143
|
-
More information about a flag. Don't repeat the summary.
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
<!-- commandsstop -->
|
|
1
|
+
# sf-delta-tests
|
|
2
|
+
|
|
3
|
+
Calculate dependencies and scope to relevant tests.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/sf-delta-tests) [](https://npmjs.org/package/sf-delta-tests) [](https://raw.githubusercontent.com/matthew-gladman/sf-delta-tests/main/LICENSE.txt)
|
|
6
|
+
|
|
7
|
+
This plugin is designed to optimize your Salesforce CI/CD pipeline by calculating only the relevant test classes that need to be run based on the metadata changes in your package. It uses the Salesforce Dependency API to determine these relationships.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
sf plugins install sf-delta-tests
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Build
|
|
16
|
+
|
|
17
|
+
To build the plugin locally, make sure to have yarn installed and run the following commands:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Install the dependencies and compile
|
|
21
|
+
yarn && yarn build
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
To use your plugin, run using the local `./bin/dev.js` or `./bin/dev.cmd` file.
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Run using local run file.
|
|
28
|
+
./bin/dev.js delta test-classes -o <alias name> --package-path=test/fixtures/manifest/package.xml
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
There should be no differences when running via the Salesforce CLI or using the local run file. However, it can be useful to link the plugin to do some additional testing or run your commands from anywhere on your machine.
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# Link your plugin to the sf cli
|
|
35
|
+
sf plugins link .
|
|
36
|
+
# To verify
|
|
37
|
+
sf plugins
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Commands
|
|
41
|
+
|
|
42
|
+
<!-- commands -->
|
|
43
|
+
|
|
44
|
+
- [`sf delta test-classes`](#sf-delta-test-classes)
|
|
45
|
+
|
|
46
|
+
## `sf delta test-classes`
|
|
47
|
+
|
|
48
|
+
Calculates the tests needed to be run based on the changed metadata given using the Salesforce Dependency API
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
Run only related tests
|
|
52
|
+
|
|
53
|
+
USAGE
|
|
54
|
+
$ sf delta test-classes -o <value> [--json] [--flags-dir <value>] [-p <value>] [--always-run-test <value>...] [--include-all-flows]
|
|
55
|
+
|
|
56
|
+
FLAGS
|
|
57
|
+
-o, --target-org=<value> (required) The org you want to check the dependencies against.
|
|
58
|
+
-p, --package-path=<value> [default: manifest/package.xml] Path to the package.xml that will be deployed.
|
|
59
|
+
--always-run-test=<value>... A test class to run when no tests need to be ran.
|
|
60
|
+
--[no-]include-all-flows When enabled, if any Flow is changed, include all Flows that require test coverage based on their trigger type
|
|
61
|
+
or process type. This ensures proper test coverage validation since Salesforce checks coverage for all such
|
|
62
|
+
Flows during deployment, not just the changed ones. Use --no-include-all-flows to disable.
|
|
63
|
+
|
|
64
|
+
GLOBAL FLAGS
|
|
65
|
+
--flags-dir=<value> Import flag values from a directory.
|
|
66
|
+
--json Format output as json.
|
|
67
|
+
|
|
68
|
+
DESCRIPTION
|
|
69
|
+
Run only related tests
|
|
70
|
+
|
|
71
|
+
Calculates the tests needed to be ran based on the changed metadata given using the Salesforce Dependency API
|
|
72
|
+
|
|
73
|
+
EXAMPLES
|
|
74
|
+
testCmd=$(sf delta test-classes --target-org matt@never.io.dev)
|
|
75
|
+
|
|
76
|
+
$ sf project deploy validate ${testCmd}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
<!-- commandsstop -->
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { SfCommand } from '@salesforce/sf-plugins-core';
|
|
2
2
|
import { Config } from '@oclif/core';
|
|
3
|
-
import { DependencyService } from '../../services/dependency-service';
|
|
4
|
-
import { ApexClassService } from '../../services/apex-class-service';
|
|
5
|
-
import { ManifestService } from '../../services/manifest-service';
|
|
6
|
-
import { OutputService } from '../../services/output-service';
|
|
7
|
-
import { CliService } from '../../services/cli-service';
|
|
3
|
+
import { DependencyService } from '../../services/dependency-service.js';
|
|
4
|
+
import { ApexClassService } from '../../services/apex-class-service.js';
|
|
5
|
+
import { ManifestService } from '../../services/manifest-service.js';
|
|
6
|
+
import { OutputService } from '../../services/output-service.js';
|
|
7
|
+
import { CliService } from '../../services/cli-service.js';
|
|
8
|
+
import { FlowService } from '../../services/flow-service.js';
|
|
8
9
|
export type DeltaTestClassesResult = {
|
|
9
10
|
testNames: string[];
|
|
10
11
|
cli: string;
|
|
@@ -14,15 +15,17 @@ export default class TestClasses extends SfCommand<DeltaTestClassesResult> {
|
|
|
14
15
|
static readonly description: string;
|
|
15
16
|
static readonly examples: string[];
|
|
16
17
|
static readonly flags: {
|
|
17
|
-
'target-org': import("@oclif/core/
|
|
18
|
-
'package-path': import("@oclif/core/
|
|
19
|
-
'always-run-test': import("@oclif/core/
|
|
18
|
+
'target-org': import("@oclif/core/interfaces").OptionFlag<import("@salesforce/core").Org, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
|
+
'package-path': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
|
+
'always-run-test': import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
21
|
+
'include-all-flows': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
20
22
|
};
|
|
21
23
|
private dependencyService;
|
|
22
24
|
private apexClassService;
|
|
23
25
|
private outputService;
|
|
24
26
|
private manifestService;
|
|
25
27
|
private cliService;
|
|
26
|
-
|
|
28
|
+
private flowService;
|
|
29
|
+
constructor(argv: string[], config: Config, dependencyService?: DependencyService, apexClassService?: ApexClassService, outputService?: OutputService, manifestService?: ManifestService, cliService?: CliService, flowService?: FlowService);
|
|
27
30
|
run(): Promise<DeltaTestClassesResult>;
|
|
28
31
|
}
|
|
@@ -1,23 +1,59 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
1
|
+
import { fileURLToPath } from 'node:url';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
|
|
4
|
+
import { Messages } from '@salesforce/core';
|
|
5
|
+
import lodash from 'lodash';
|
|
6
|
+
import { DependencyService } from '../../services/dependency-service.js';
|
|
7
|
+
import { ApexClassService } from '../../services/apex-class-service.js';
|
|
8
|
+
import { ManifestService } from '../../services/manifest-service.js';
|
|
9
|
+
import { OutputService } from '../../services/output-service.js';
|
|
10
|
+
import { CliService } from '../../services/cli-service.js';
|
|
11
|
+
import { FlowService } from '../../services/flow-service.js';
|
|
12
|
+
const currentFileName = fileURLToPath(import.meta.url);
|
|
13
|
+
const currentDirectory = dirname(currentFileName);
|
|
14
|
+
Messages.importMessagesDirectory(currentDirectory);
|
|
15
|
+
const messages = Messages.loadMessages('sf-delta-tests', 'delta.test-classes');
|
|
16
|
+
export default class TestClasses extends SfCommand {
|
|
17
|
+
static summary = messages.getMessage('summary');
|
|
18
|
+
static description = messages.getMessage('description');
|
|
19
|
+
static examples = messages.getMessages('examples');
|
|
20
|
+
// TODO: Add in parameters to tune the max revision depth, max changed metadata
|
|
21
|
+
// TODO: Add in parameters to allow fetching other object types for dependencies and meaningful types
|
|
22
|
+
static flags = {
|
|
23
|
+
'target-org': Flags.requiredOrg({
|
|
24
|
+
summary: messages.getMessage('flags.target-org.summary'),
|
|
25
|
+
char: 'o',
|
|
26
|
+
required: true,
|
|
27
|
+
}),
|
|
28
|
+
'package-path': Flags.directory({
|
|
29
|
+
summary: messages.getMessage('flags.package-path.summary'),
|
|
30
|
+
char: 'p',
|
|
31
|
+
default: 'manifest/package.xml',
|
|
32
|
+
}),
|
|
33
|
+
'always-run-test': Flags.string({
|
|
34
|
+
summary: messages.getMessage('flags.always-run-test.summary'),
|
|
35
|
+
multiple: true,
|
|
36
|
+
}),
|
|
37
|
+
'include-all-flows': Flags.boolean({
|
|
38
|
+
summary: messages.getMessage('flags.include-all-flows.summary'),
|
|
39
|
+
default: true,
|
|
40
|
+
allowNo: true,
|
|
41
|
+
}),
|
|
42
|
+
};
|
|
43
|
+
dependencyService;
|
|
44
|
+
apexClassService;
|
|
45
|
+
outputService;
|
|
46
|
+
manifestService;
|
|
47
|
+
cliService;
|
|
48
|
+
flowService;
|
|
49
|
+
constructor(argv, config, dependencyService = new DependencyService(), apexClassService = new ApexClassService(), outputService = new OutputService(), manifestService = new ManifestService(), cliService = new CliService(), flowService = new FlowService()) {
|
|
15
50
|
super(argv, config);
|
|
16
51
|
this.dependencyService = dependencyService;
|
|
17
52
|
this.apexClassService = apexClassService;
|
|
18
53
|
this.outputService = outputService;
|
|
19
54
|
this.manifestService = manifestService;
|
|
20
55
|
this.cliService = cliService;
|
|
56
|
+
this.flowService = flowService;
|
|
21
57
|
}
|
|
22
58
|
async run() {
|
|
23
59
|
try {
|
|
@@ -29,12 +65,20 @@ class TestClasses extends sf_plugins_core_1.SfCommand {
|
|
|
29
65
|
this.debug('Getting dependencies from SF');
|
|
30
66
|
// Download all dependencies from SF
|
|
31
67
|
const combinedApexClassData = await this.dependencyService.getDependenciesByObjects();
|
|
68
|
+
this.debug('combinedApexClassData', combinedApexClassData);
|
|
32
69
|
// Write into output folder
|
|
33
70
|
await this.outputService.dependencyData(combinedApexClassData);
|
|
34
71
|
this.debug(`Loading metadata from ${flags['package-path']}`);
|
|
35
72
|
// Get manifest data and transform that into a list of metadata
|
|
36
73
|
const manifestData = await this.manifestService.parseManifest(flags['package-path']);
|
|
37
|
-
const
|
|
74
|
+
const changedMetadataWithType = this.manifestService.extractMetadataComponentsWithType(manifestData);
|
|
75
|
+
const flowNames = await this.flowService.getFlowNames(changedMetadataWithType, flags['include-all-flows']);
|
|
76
|
+
const flowTriggerObjectNames = await this.flowService.getTriggerObjectsFromFlows(flowNames);
|
|
77
|
+
const changedMetadata = lodash.uniq([
|
|
78
|
+
...flowNames,
|
|
79
|
+
...flowTriggerObjectNames,
|
|
80
|
+
...changedMetadataWithType.map((c) => c.name),
|
|
81
|
+
]);
|
|
38
82
|
this.debug({ manifestData: manifestData.components, changedMetadata });
|
|
39
83
|
// If no meaningful changed metadata, no need to run tests (layout changes don't need tests!)
|
|
40
84
|
if (changedMetadata.length === 0) {
|
|
@@ -45,22 +89,15 @@ class TestClasses extends sf_plugins_core_1.SfCommand {
|
|
|
45
89
|
cli: this.cliService.noTests(flags['always-run-test']),
|
|
46
90
|
};
|
|
47
91
|
}
|
|
48
|
-
// Too many changes, just run all
|
|
49
|
-
if (changedMetadata.length > 40) {
|
|
50
|
-
this.debug(`Found over 40 changed metadata items (${changedMetadata.length}), running all tests`);
|
|
51
|
-
this.log(this.cliService.allTests());
|
|
52
|
-
return { testNames: [], cli: this.cliService.allTests() };
|
|
53
|
-
}
|
|
54
92
|
this.debug('Calculating the related apex classes...');
|
|
55
93
|
// The magic function. From the changed metadata get all the Apex Classes that could be connected to the changed metadata
|
|
56
94
|
const classList = this.dependencyService.getRelatedApexClasses(combinedApexClassData, changedMetadata);
|
|
57
|
-
const unknownEntities = (0, lodash_1.difference)(changedMetadata, classList);
|
|
58
95
|
this.debug({ classList });
|
|
59
|
-
this.debug({ unknownEntities });
|
|
60
96
|
this.debug('Filtering the apex classes to only tests...');
|
|
61
|
-
// Filter the total class list to only tests
|
|
62
|
-
const testNames = await this.apexClassService.filterApexTest(
|
|
63
|
-
this.
|
|
97
|
+
// Filter the total class list to only tests
|
|
98
|
+
const testNames = await this.apexClassService.filterApexTest(classList);
|
|
99
|
+
const simpleTestNames = this.apexClassService.filterApexTestSimple(classList);
|
|
100
|
+
this.debug({ testNames, simpleTestNames });
|
|
64
101
|
if (flags['always-run-test']) {
|
|
65
102
|
testNames.push(...flags['always-run-test']);
|
|
66
103
|
}
|
|
@@ -89,26 +126,4 @@ class TestClasses extends sf_plugins_core_1.SfCommand {
|
|
|
89
126
|
}
|
|
90
127
|
}
|
|
91
128
|
}
|
|
92
|
-
TestClasses.summary = messages.getMessage('summary');
|
|
93
|
-
TestClasses.description = messages.getMessage('description');
|
|
94
|
-
TestClasses.examples = messages.getMessages('examples');
|
|
95
|
-
// TODO: Add in parameters to tune the max revision depth, max changed metadata
|
|
96
|
-
// TODO: Add in parameters to allow fetching other object types for dependencies and meaningful types
|
|
97
|
-
TestClasses.flags = {
|
|
98
|
-
'target-org': sf_plugins_core_1.Flags.requiredOrg({
|
|
99
|
-
summary: messages.getMessage('flags.target-org.summary'),
|
|
100
|
-
char: 'o',
|
|
101
|
-
required: true,
|
|
102
|
-
}),
|
|
103
|
-
'package-path': sf_plugins_core_1.Flags.directory({
|
|
104
|
-
summary: messages.getMessage('flags.package-path.summary'),
|
|
105
|
-
char: 'p',
|
|
106
|
-
default: 'manifest/package.xml',
|
|
107
|
-
}),
|
|
108
|
-
'always-run-test': sf_plugins_core_1.Flags.string({
|
|
109
|
-
summary: messages.getMessage('flags.always-run-test.summary'),
|
|
110
|
-
multiple: true,
|
|
111
|
-
}),
|
|
112
|
-
};
|
|
113
|
-
exports.default = TestClasses;
|
|
114
129
|
//# sourceMappingURL=test-classes.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-classes.js","sourceRoot":"","sources":["../../../src/commands/delta/test-classes.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"test-classes.js","sourceRoot":"","sources":["../../../src/commands/delta/test-classes.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,31 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
exports.LIGHTNING_COMPONENT_BUNDLE = 'LightningComponentBundle';
|
|
9
|
-
exports.AURA_DEFINITION_BUNDLE = 'AuraDefinitionBundle';
|
|
10
|
-
exports.CUSTOM_METADATA = 'CustomMetadata';
|
|
1
|
+
export const APEX_CLASS = 'ApexClass';
|
|
2
|
+
export const APEX_TRIGGER = 'ApexTrigger';
|
|
3
|
+
export const CUSTOM_OBJECT = 'CustomObject';
|
|
4
|
+
export const FLOW = 'Flow';
|
|
5
|
+
export const LIGHTNING_COMPONENT_BUNDLE = 'LightningComponentBundle';
|
|
6
|
+
export const AURA_DEFINITION_BUNDLE = 'AuraDefinitionBundle';
|
|
7
|
+
export const CUSTOM_METADATA = 'CustomMetadata';
|
|
11
8
|
// TODO: Consider Setting
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
9
|
+
export const defaultTypesToFetchFromDependencyServer = [
|
|
10
|
+
APEX_CLASS,
|
|
11
|
+
APEX_TRIGGER,
|
|
12
|
+
CUSTOM_OBJECT,
|
|
13
|
+
FLOW,
|
|
14
|
+
LIGHTNING_COMPONENT_BUNDLE,
|
|
15
|
+
AURA_DEFINITION_BUNDLE,
|
|
16
|
+
CUSTOM_METADATA,
|
|
20
17
|
];
|
|
21
18
|
// TODO: Review
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
19
|
+
export const meaningfulMetadataChanges = [
|
|
20
|
+
APEX_CLASS,
|
|
21
|
+
APEX_TRIGGER,
|
|
22
|
+
CUSTOM_OBJECT,
|
|
23
|
+
FLOW,
|
|
24
|
+
LIGHTNING_COMPONENT_BUNDLE,
|
|
25
|
+
AURA_DEFINITION_BUNDLE,
|
|
26
|
+
CUSTOM_METADATA,
|
|
30
27
|
];
|
|
31
28
|
//# sourceMappingURL=object-types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"object-types.js","sourceRoot":"","sources":["../../src/elements/object-types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"object-types.js","sourceRoot":"","sources":["../../src/elements/object-types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,UAAU,GAAG,WAAW,CAAC;AACtC,MAAM,CAAC,MAAM,YAAY,GAAG,aAAa,CAAC;AAC1C,MAAM,CAAC,MAAM,aAAa,GAAG,cAAc,CAAC;AAC5C,MAAM,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC;AAC3B,MAAM,CAAC,MAAM,0BAA0B,GAAG,0BAA0B,CAAC;AACrE,MAAM,CAAC,MAAM,sBAAsB,GAAG,sBAAsB,CAAC;AAC7D,MAAM,CAAC,MAAM,eAAe,GAAG,gBAAgB,CAAC;AAChD,yBAAyB;AACzB,MAAM,CAAC,MAAM,uCAAuC,GAAG;IACrD,UAAU;IACV,YAAY;IACZ,aAAa;IACb,IAAI;IACJ,0BAA0B;IAC1B,sBAAsB;IACtB,eAAe;CAChB,CAAC;AAEF,eAAe;AACf,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC,UAAU;IACV,YAAY;IACZ,aAAa;IACb,IAAI;IACJ,0BAA0B;IAC1B,sBAAsB;IACtB,eAAe;CAChB,CAAC"}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
declare const _default: {};
|
|
2
|
-
export
|
|
2
|
+
export default _default;
|
package/lib/index.js
CHANGED
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAe,EAAE,CAAC"}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const promises_1 = require("fs/promises");
|
|
6
|
-
const glob_1 = require("glob");
|
|
7
|
-
class ApexClassService {
|
|
1
|
+
import { parse as parsePath, join as joinPath } from 'path';
|
|
2
|
+
import { readFile } from 'fs/promises';
|
|
3
|
+
import { glob } from 'glob';
|
|
4
|
+
export class ApexClassService {
|
|
8
5
|
// eslint-disable-next-line class-methods-use-this
|
|
9
6
|
filterApexTestSimple(classList) {
|
|
10
7
|
return classList.filter((className) => className.toLowerCase().includes('test'));
|
|
@@ -14,15 +11,15 @@ class ApexClassService {
|
|
|
14
11
|
async filterApexTest(classList, rootPath = 'force-app/main/default/classes') {
|
|
15
12
|
// Get all Apex Classes with the filenames `${className}.cls` in the root directory and all subdirectories
|
|
16
13
|
const globPattern = `**/{,${classList.join(',')}}.cls`;
|
|
17
|
-
const apexClassPaths = await
|
|
14
|
+
const apexClassPaths = await glob(globPattern, { cwd: rootPath });
|
|
18
15
|
const apexClassTests = [];
|
|
19
16
|
const regexIsTest = /@istest/i;
|
|
20
17
|
// Open each file, check to see if it is a test and add to apexClassTests
|
|
21
18
|
for (const apexClassPath of apexClassPaths) {
|
|
22
|
-
const joinedPath = (
|
|
23
|
-
const parsedPath = (
|
|
19
|
+
const joinedPath = joinPath(rootPath, apexClassPath);
|
|
20
|
+
const parsedPath = parsePath(joinedPath);
|
|
24
21
|
// eslint-disable-next-line no-await-in-loop
|
|
25
|
-
const fileContent = (await
|
|
22
|
+
const fileContent = (await readFile(joinedPath)).toString();
|
|
26
23
|
if (fileContent.search(regexIsTest) !== -1) {
|
|
27
24
|
apexClassTests.push(parsedPath.name.replace('.cls', ''));
|
|
28
25
|
}
|
|
@@ -30,5 +27,4 @@ class ApexClassService {
|
|
|
30
27
|
return apexClassTests;
|
|
31
28
|
}
|
|
32
29
|
}
|
|
33
|
-
exports.ApexClassService = ApexClassService;
|
|
34
30
|
//# sourceMappingURL=apex-class-service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apex-class-service.js","sourceRoot":"","sources":["../../src/services/apex-class-service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"apex-class-service.js","sourceRoot":"","sources":["../../src/services/apex-class-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,MAAM,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,MAAM,OAAO,gBAAgB;IAC3B,kDAAkD;IAC3C,oBAAoB,CAAC,SAAmB;QAC7C,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IACnF,CAAC;IAED,8CAA8C;IAC9C,kDAAkD;IAC3C,KAAK,CAAC,cAAc,CAAC,SAAmB,EAAE,QAAQ,GAAG,gCAAgC;QAC1F,0GAA0G;QAC1G,MAAM,WAAW,GAAG,QAAQ,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;QACvD,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;QAElE,MAAM,cAAc,GAAa,EAAE,CAAC;QACpC,MAAM,WAAW,GAAG,UAAU,CAAC;QAE/B,yEAAyE;QACzE,KAAK,MAAM,aAAa,IAAI,cAAc,EAAE,CAAC;YAC3C,MAAM,UAAU,GAAG,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;YACrD,MAAM,UAAU,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;YACzC,4CAA4C;YAC5C,MAAM,WAAW,GAAG,CAAC,MAAM,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;YAC5D,IAAI,WAAW,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;gBAC3C,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;YAC3D,CAAC;QACH,CAAC;QAED,OAAO,cAAc,CAAC;IACxB,CAAC;CACF"}
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CliService = void 0;
|
|
4
1
|
/* eslint-disable class-methods-use-this */
|
|
5
|
-
class CliService {
|
|
2
|
+
export class CliService {
|
|
6
3
|
specificTests(tests) {
|
|
7
4
|
const testList = tests.map((test) => (test.includes(' ') ? `"${test}"` : test));
|
|
8
5
|
return `--test-level=RunSpecifiedTests --tests=${testList.join(' ')}`;
|
|
@@ -15,5 +12,4 @@ class CliService {
|
|
|
15
12
|
return `--test-level=RunSpecifiedTests --tests=SFDeltaTests-NoTest ${testList.join(' ')}`.trimEnd();
|
|
16
13
|
}
|
|
17
14
|
}
|
|
18
|
-
exports.CliService = CliService;
|
|
19
15
|
//# sourceMappingURL=cli-service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-service.js","sourceRoot":"","sources":["../../src/services/cli-service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cli-service.js","sourceRoot":"","sources":["../../src/services/cli-service.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,MAAM,OAAO,UAAU;IACd,aAAa,CAAC,KAAe;QAClC,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAChF,OAAO,0CAA0C,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IACxE,CAAC;IAEM,QAAQ;QACb,OAAO,4BAA4B,CAAC;IACtC,CAAC;IAEM,OAAO,CAAC,aAAwB;QACrC,MAAM,QAAQ,GAAG,aAAa,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QAC/F,OAAO,8DAA8D,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC;IACtG,CAAC;CACF"}
|