apextestlist 1.12.4 → 1.13.1

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/CHANGELOG.md CHANGED
@@ -5,6 +5,21 @@
5
5
 
6
6
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
7
7
 
8
+ ## [1.13.1](https://github.com/renatoliveira/apex-test-list/compare/v1.13.0...v1.13.1) (2025-07-12)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **deps:** bump @oclif/core from 4.3.3 to 4.4.1 ([#244](https://github.com/renatoliveira/apex-test-list/issues/244)) ([1ad9efe](https://github.com/renatoliveira/apex-test-list/commit/1ad9efef6839b055e87ae5c402f1e9ed4cbb868f))
14
+ * **deps:** bump @salesforce/source-deploy-retrieve ([#243](https://github.com/renatoliveira/apex-test-list/issues/243)) ([8b10331](https://github.com/renatoliveira/apex-test-list/commit/8b103316c48b179a5a5d55f4f144e6ea554f6e55))
15
+
16
+ ## [1.13.0](https://github.com/renatoliveira/apex-test-list/compare/v1.12.4...v1.13.0) (2025-06-19)
17
+
18
+
19
+ ### Features
20
+
21
+ * add metadata filter option via yaml ([#234](https://github.com/renatoliveira/apex-test-list/issues/234)) ([1ccaf7b](https://github.com/renatoliveira/apex-test-list/commit/1ccaf7b445feb75c20770879289d1f3d5e1a2ae6))
22
+
8
23
  ## [1.12.4](https://github.com/renatoliveira/apex-test-list/compare/v1.12.3...v1.12.4) (2025-06-14)
9
24
 
10
25
 
package/README.md CHANGED
@@ -13,6 +13,7 @@ A plugin that generates a list of tests that your automated process should run,
13
13
  - [1. `@Tests:` (Custom Comment Annotation)](#1-tests-custom-comment-annotation)
14
14
  - [2. `@TestSuites:` (Custom Comment Annotation)](#2-testsuites-custom-comment-annotation)
15
15
  - [3. `@isTest` (Apex Annotation)](#3-istest-apex-annotation)
16
+ - [4. `.test-dependencies.yml` (Centralized Metadata Filter)](#4-test-dependenciesyml-centralized-metadata-filter)
16
17
  - [Running the Tool](#running-the-tool)
17
18
  - [Handling Missing Tests](#handling-missing-tests)
18
19
  - [Handling Missing Annotations](#handling-missing-annotations)
@@ -31,7 +32,7 @@ sf plugins install apextestlist
31
32
 
32
33
  ## Usage
33
34
 
34
- This tool identifies Apex tests using three annotations:
35
+ This tool identifies Apex tests using either 3 Apex annotations or a separate metadata filter.
35
36
 
36
37
  ### 1. `@Tests:` (Custom Comment Annotation)
37
38
 
@@ -70,6 +71,35 @@ private class SampleTest {
70
71
  }
71
72
  ```
72
73
 
74
+ ### 4. `.test-dependencies.yml` (Centralized Metadata Filter)
75
+
76
+ Instead of using the Apex annotations described previously, you can use this plugin to determine Apex tests with specific Salesforce metadata.
77
+
78
+ This approach is designed to work seamlessly with the `-x`/`--manifest` flag using a manifest file generated by the [`sfdx-git-delta`](https://github.com/scolladon/sfdx-git-delta) plugin.
79
+
80
+ 1. Create a `.test-dependencies.yml` file in the root of your project.
81
+ 2. Map test classes to metadata entries (in `MetadataType:MetadataMember` format).
82
+ 1. Use wildcards (\*) to match all children under a metadata namespace (e.g., all custom fields in an object).
83
+ 2. The plugin will fail if the entries in the YAML don't match the expected format.
84
+
85
+ ```yml
86
+ MyFooTest:
87
+ - CustomField:Account__c.field__c
88
+ - Flow:OpportunityFlowX
89
+ - ValidationRule:Account.RequiredEmail
90
+ - CustomField:Opportunity__c.*
91
+
92
+ MyBarTest:
93
+ - CustomObject:Lead__c
94
+ - Flow:LeadFlowY
95
+ ```
96
+
97
+ 3. Run this plugin's command with the `filter-by-metadata`/`-m` flag **and** the `-x`/`--manifest` flag.
98
+
99
+ ```sh
100
+ sf apextests list -x package/package.xml -m
101
+ ```
102
+
73
103
  ## Running the Tool
74
104
 
75
105
  To generate a test list, run the command in any Salesforce DX project:
@@ -96,7 +126,7 @@ The final deployment command would look like:
96
126
  sf project deploy start --tests SampleTest SuperSampleTest Sample2Test SuperSample2Test SampleTriggerTest
97
127
  ```
98
128
 
99
- If no annotations are found, the command output will be empty and will present this warning:
129
+ If no test methods are found, the command output will be empty and will present this warning:
100
130
 
101
131
  ```sh
102
132
  No test methods found
@@ -104,7 +134,7 @@ No test methods found
104
134
 
105
135
  ### Handling Missing Tests
106
136
 
107
- By default, this tool does **not** verify if the tests specified in `@Tests:` or `@TestSuites:` exist in the project. To enable warnings for missing tests, use:
137
+ By default, this tool does **not** verify if the test methods found exist in the project. To enable warnings for missing tests, use:
108
138
 
109
139
  ```sh
110
140
  sf apextests list --ignore-missing-tests
@@ -130,7 +160,7 @@ sf apextests list --no-warnings
130
160
 
131
161
  ```
132
162
  USAGE
133
- $ sf apextests list -f <value> -x <value> -s -n -d <value> [--json]
163
+ $ sf apextests list -f <value> -x <value> -s -n -d <value> -m [--json]
134
164
 
135
165
  FLAGS
136
166
  -f, --format=<value> Output format. Available options:
@@ -142,6 +172,8 @@ FLAGS
142
172
  -d, --ignore-package-directory Ignore a package directory when looking for test annotations.
143
173
  Should match how they are declared in "sfdx-project.json".
144
174
  Can be declared multiple times.
175
+ -m, --filter-by-metadata [default: false] When enabled with `manifest`, test selection is based on metadata changes (e.g., Flow, CustomObject) rather than Apex annotations.
176
+
145
177
 
146
178
  GLOBAL FLAGS
147
179
  --json Format output as JSON.
@@ -10,6 +10,7 @@ export default class ApextestsList extends SfCommand<ApextestsListResult> {
10
10
  'ignore-missing-tests': import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
11
  'ignore-package-directory': import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
12
  'no-warnings': import("@oclif/core/interfaces").BooleanFlag<boolean>;
13
+ 'filter-by-metadata': import("@oclif/core/interfaces").BooleanFlag<boolean>;
13
14
  };
14
15
  run(): Promise<ApextestsListResult>;
15
16
  }
@@ -43,6 +43,13 @@ export default class ApextestsList extends SfCommand {
43
43
  required: false,
44
44
  default: false,
45
45
  }),
46
+ 'filter-by-metadata': Flags.boolean({
47
+ summary: messages.getMessage('flags.filter-by-metadata.summary'),
48
+ description: messages.getMessage('flags.filter-by-metadata.description'),
49
+ char: 'm',
50
+ required: false,
51
+ default: false,
52
+ }),
46
53
  };
47
54
  async run() {
48
55
  const { flags } = await this.parse(ApextestsList);
@@ -52,6 +59,7 @@ export default class ApextestsList extends SfCommand {
52
59
  ignoreMissingTests: flags['ignore-missing-tests'],
53
60
  ignoreDirs: flags['ignore-package-directory'],
54
61
  noWarnings: flags['no-warnings'],
62
+ filterByMetadata: flags['filter-by-metadata'],
55
63
  warn: this.warn.bind(this),
56
64
  });
57
65
  this.log(result.command);
@@ -1 +1 @@
1
- {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/commands/apextests/list.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAGpD,QAAQ,CAAC,kCAAkC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7D,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,cAAc,EAAE,gBAAgB,CAAC,CAAC;AAEzE,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,SAA8B;IAChE,MAAM,CAAU,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IACzD,MAAM,CAAU,WAAW,GAAG,QAAQ,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IACjE,MAAM,CAAU,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IAE5D,MAAM,CAAU,KAAK,GAAG;QAC7B,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC;YACnB,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,sBAAsB,CAAC;YACpD,WAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,0BAA0B,CAAC;YAC5D,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,KAAK;YACf,OAAO,EAAE,IAAI;SACd,CAAC;QACF,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC;YACrB,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,wBAAwB,CAAC;YACtD,WAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,4BAA4B,CAAC;YAC9D,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,KAAK;SAChB,CAAC;QACF,sBAAsB,EAAE,KAAK,CAAC,OAAO,CAAC;YACpC,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,oCAAoC,CAAC;YAClE,WAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,wCAAwC,CAAC;YAC1E,QAAQ,EAAE,KAAK;YACf,IAAI,EAAE,GAAG;YACT,OAAO,EAAE,KAAK;SACf,CAAC;QACF,0BAA0B,EAAE,KAAK,CAAC,SAAS,CAAC;YAC1C,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,wCAAwC,CAAC;YACtE,WAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,4CAA4C,CAAC;YAC9E,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,KAAK;YACf,QAAQ,EAAE,IAAI;SACf,CAAC;QACF,aAAa,EAAE,KAAK,CAAC,OAAO,CAAC;YAC3B,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,2BAA2B,CAAC;YACzD,WAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,+BAA+B,CAAC;YACjE,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,KAAK;YACf,OAAO,EAAE,KAAK;SACf,CAAC;KACH,CAAC;IAGK,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAElD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC;YAC7B,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,kBAAkB,EAAE,KAAK,CAAC,sBAAsB,CAAC;YACjD,UAAU,EAAE,KAAK,CAAC,0BAA0B,CAAC;YAC7C,UAAU,EAAE,KAAK,CAAC,aAAa,CAAC;YAChC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACzB,OAAO,MAAM,CAAC;IAChB,CAAC"}
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/commands/apextests/list.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,2 @@
1
1
  import { ListTestsOptions, ApextestsListResult } from '../utils/types.js';
2
- export declare function listTests({ format, manifest, ignoreMissingTests, ignoreDirs, noWarnings, warn, }: ListTestsOptions): Promise<ApextestsListResult>;
2
+ export declare function listTests({ format, manifest, ignoreMissingTests, ignoreDirs, noWarnings, filterByMetadata, warn, }: ListTestsOptions): Promise<ApextestsListResult>;
@@ -1,32 +1,43 @@
1
1
  /* eslint-disable no-await-in-loop */
2
+ import { resolve } from 'node:path';
2
3
  import { getPackageDirectories } from '../utils/getPackageDirectories.js';
3
4
  import { validateTests } from '../utils/validateTests.js';
4
5
  import { extractTypeNamesFromManifestFile } from '../parsers/manifestParser.js';
5
6
  import { formatList } from '../utils/formatters.js';
6
7
  import { searchDirectoryForTestClasses } from '../readers/directorySearcher.js';
7
8
  import { searchDirectoryForTestNamesInTestSuites } from '../readers/testSuiteSearcher.js';
8
- export async function listTests({ format = 'sf', manifest, ignoreMissingTests = false, ignoreDirs = [], noWarnings = false, warn = () => { }, }) {
9
+ import { METADATA_FILTER_CONFIG } from '../utils/constants.js';
10
+ import { loadTestMetadataDependencies, selectRelevantTests } from '../parsers/metadataFilterParser.js';
11
+ export async function listTests({ format = 'sf', manifest, ignoreMissingTests = false, ignoreDirs = [], noWarnings = false, filterByMetadata = false, warn = () => { }, }) {
9
12
  let testClassesNames = null;
10
13
  const testSuitesNames = [];
11
14
  const allTestClasses = [];
12
15
  const warnings = [];
13
- const packageDirectories = await getPackageDirectories(ignoreDirs);
16
+ const { metadataPaths: packageDirectories, repoRoot } = await getPackageDirectories(ignoreDirs);
14
17
  if (manifest) {
15
18
  const manifestMetadata = await extractTypeNamesFromManifestFile(manifest);
16
19
  testClassesNames = manifestMetadata.filter((name) => !name.endsWith('testSuite-meta.xml'));
17
- }
18
- for (const directory of packageDirectories) {
19
- const searchResult = await searchDirectoryForTestClasses(directory, testClassesNames);
20
- allTestClasses.push(...searchResult.classes);
21
- testSuitesNames.push(...searchResult.testSuites);
22
- if (searchResult.warnings?.length) {
23
- warnings.push(...searchResult.warnings);
20
+ if (filterByMetadata) {
21
+ const ymlConfigPath = resolve(repoRoot, METADATA_FILTER_CONFIG);
22
+ const testMap = await loadTestMetadataDependencies(ymlConfigPath);
23
+ const testsToRun = selectRelevantTests(testMap, manifestMetadata);
24
+ allTestClasses.push(...testsToRun);
24
25
  }
25
26
  }
26
- if (testSuitesNames.length > 0) {
27
- for (const directory of packageDirectories.filter((dir) => dir.includes('testSuites'))) {
28
- const testNames = await searchDirectoryForTestNamesInTestSuites(directory, packageDirectories);
29
- allTestClasses.push(...testNames);
27
+ if (!filterByMetadata) {
28
+ for (const directory of packageDirectories) {
29
+ const searchResult = await searchDirectoryForTestClasses(directory, testClassesNames);
30
+ allTestClasses.push(...searchResult.classes);
31
+ testSuitesNames.push(...searchResult.testSuites);
32
+ if (searchResult.warnings?.length) {
33
+ warnings.push(...searchResult.warnings);
34
+ }
35
+ }
36
+ if (testSuitesNames.length > 0) {
37
+ for (const directory of packageDirectories.filter((dir) => dir.includes('testSuites'))) {
38
+ const testNames = await searchDirectoryForTestNamesInTestSuites(directory, packageDirectories);
39
+ allTestClasses.push(...testNames);
40
+ }
30
41
  }
31
42
  }
32
43
  let finalTestMethods = Array.from(new Set(allTestClasses.map((test) => test.trim())));
@@ -34,9 +45,6 @@ export async function listTests({ format = 'sf', manifest, ignoreMissingTests =
34
45
  const { validatedTests, warnings: validationWarnings } = await validateTests(finalTestMethods, packageDirectories);
35
46
  finalTestMethods = validatedTests;
36
47
  warnings.push(...validationWarnings);
37
- if (validatedTests.length === 0) {
38
- warnings.push('No test methods declared in your annotations were found in your package directories');
39
- }
40
48
  }
41
49
  if (!noWarnings && warnings.length > 0) {
42
50
  warnings.forEach(warn);
@@ -1 +1 @@
1
- {"version":3,"file":"listTests.js","sourceRoot":"","sources":["../../src/core/listTests.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"listTests.js","sourceRoot":"","sources":["../../src/core/listTests.ts"],"names":[],"mappings":"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"}
@@ -18,9 +18,7 @@ export async function extractTypeNamesFromManifestFile(manifestFile) {
18
18
  const componentSet = await ComponentSet.fromManifest({ manifestPath: manifestFile });
19
19
  for (const component of componentSet) {
20
20
  const typeName = component.type.name;
21
- if (['ApexClass', 'ApexTrigger', 'ApexTestSuite'].includes(typeName)) {
22
- result.push(`${typeName}:${component.fullName}`);
23
- }
21
+ result.push(`${typeName}:${component.fullName}`);
24
22
  }
25
23
  return result.sort((a, b) => a.localeCompare(b));
26
24
  }
@@ -1 +1 @@
1
- {"version":3,"file":"manifestParser.js","sourceRoot":"","sources":["../../src/parsers/manifestParser.ts"],"names":[],"mappings":"AACA,YAAY,CAAC;AAEb,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,YAAY,EAAG,MAAM,oCAAoC,CAAC;AAEnE;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,gCAAgC,CAAC,YAAoB;IACzE,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,IAAI,CAAC,YAAY,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC/C,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,YAAY,GAAiB,MAAM,YAAY,CAAC,YAAY,CAAC,EAAC,YAAY,EAAE,YAAY,EAAC,CAAC,CAAC;IACjG,KAAK,MAAM,SAAS,IAAI,YAAY,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;QACrC,IAAI,CAAC,WAAW,EAAE,aAAa,EAAE,eAAe,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YACrE,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,CAAC"}
1
+ {"version":3,"file":"manifestParser.js","sourceRoot":"","sources":["../../src/parsers/manifestParser.ts"],"names":[],"mappings":"AACA,YAAY,CAAC;AAEb,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,YAAY,EAAG,MAAM,oCAAoC,CAAC;AAEnE;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,gCAAgC,CAAC,YAAoB;IACzE,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,IAAI,CAAC,YAAY,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC/C,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,YAAY,GAAiB,MAAM,YAAY,CAAC,YAAY,CAAC,EAAC,YAAY,EAAE,YAAY,EAAC,CAAC,CAAC;IACjG,KAAK,MAAM,SAAS,IAAI,YAAY,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;QACrC,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;IACnD,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { TestMetadataMap } from '../utils/types.js';
2
+ /**
3
+ * Loads the test metadata filter YAML file and confirms it matches the expected structure.
4
+ */
5
+ export declare function loadTestMetadataDependencies(configPath: string): Promise<TestMetadataMap>;
6
+ /**
7
+ * Return test classes that depend on any of the changed metadata.
8
+ */
9
+ export declare function selectRelevantTests(testMap: TestMetadataMap, changedMetadata: string[]): string[];
@@ -0,0 +1,50 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { parse } from 'yaml';
3
+ /**
4
+ * Verifies structure matches the test metadata map type.
5
+ */
6
+ function isTestMetadataMap(obj) {
7
+ if (typeof obj !== 'object' || obj === null)
8
+ return false;
9
+ return Object.entries(obj).every(([key, value]) => typeof key === 'string' &&
10
+ Array.isArray(value) &&
11
+ value.every(v => typeof v === 'string'));
12
+ }
13
+ /**
14
+ * Loads the test metadata filter YAML file and confirms it matches the expected structure.
15
+ */
16
+ export async function loadTestMetadataDependencies(configPath) {
17
+ const content = await readFile(configPath, 'utf-8');
18
+ const parsed = parse(content);
19
+ if (isTestMetadataMap(parsed)) {
20
+ return parsed;
21
+ }
22
+ throw new Error('Invalid test metadata dependencies format in YAML');
23
+ }
24
+ /**
25
+ * Compare two metadata strings like "CustomField:Account__c.Name"
26
+ * against patterns with wildcards, like "CustomField:Account__c.*"
27
+ */
28
+ function matchesDependency(dependency, changed) {
29
+ if (dependency.includes('*')) {
30
+ const pattern = dependency
31
+ .replace('.', '\\.')
32
+ .replace('*', '.*');
33
+ return new RegExp(`^${pattern}$`).test(changed);
34
+ }
35
+ return dependency === changed;
36
+ }
37
+ /**
38
+ * Return test classes that depend on any of the changed metadata.
39
+ */
40
+ export function selectRelevantTests(testMap, changedMetadata) {
41
+ const selected = [];
42
+ for (const [testClass, dependencies] of Object.entries(testMap)) {
43
+ const matches = changedMetadata.some(changed => dependencies.some(dep => matchesDependency(dep, changed)));
44
+ if (matches) {
45
+ selected.push(testClass);
46
+ }
47
+ }
48
+ return selected;
49
+ }
50
+ //# sourceMappingURL=metadataFilterParser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadataFilterParser.js","sourceRoot":"","sources":["../../src/parsers/metadataFilterParser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAI7B;;GAEG;AACH,SAAS,iBAAiB,CAAC,GAAY;IACnC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAE1D,OAAO,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAC9C,OAAO,GAAG,KAAK,QAAQ;QACvB,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACpB,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAC1C,CAAC;AACN,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAAC,UAAkB;IACjE,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACpD,MAAM,MAAM,GAAY,KAAK,CAAC,OAAO,CAAC,CAAC;IAEvC,IAAI,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5B,OAAO,MAAM,CAAC;IAClB,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;AACzE,CAAC;AAED;;;GAGG;AACH,SAAS,iBAAiB,CAAC,UAAkB,EAAE,OAAe;IAC1D,IAAI,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,UAAU;aACrB,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC;aACnB,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACxB,OAAO,IAAI,MAAM,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACpD,CAAC;IACD,OAAO,UAAU,KAAK,OAAO,CAAC;AAClC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAC/B,OAAwB,EACxB,eAAyB;IAEzB,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,KAAK,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9D,MAAM,OAAO,GAAG,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAC3C,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,iBAAiB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAC5D,CAAC;QACF,IAAI,OAAO,EAAE,CAAC;YACV,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC7B,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC;AACpB,CAAC"}
@@ -3,3 +3,4 @@ export declare const SEARCHABLE_METADATA_FOLDERS: string[];
3
3
  export declare const TEST_NAME_REGEX: RegExp;
4
4
  export declare const TEST_SUITE_NAME_REGEX: RegExp;
5
5
  export declare const TEST_CLASS_ANNOTATION_REGEX: RegExp;
6
+ export declare const METADATA_FILTER_CONFIG = ".test-dependencies.yml";
@@ -4,4 +4,5 @@ export const SEARCHABLE_METADATA_FOLDERS = ['classes', 'triggers', 'testSuites']
4
4
  export const TEST_NAME_REGEX = /@tests\s*:\s*([^/\n]+)/gi;
5
5
  export const TEST_SUITE_NAME_REGEX = /@testsuites\s*:\s*([^/\n]+)/gi;
6
6
  export const TEST_CLASS_ANNOTATION_REGEX = /@istest/gi;
7
+ export const METADATA_FILTER_CONFIG = '.test-dependencies.yml';
7
8
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/utils/constants.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AACb,MAAM,CAAC,MAAM,sBAAsB,GAAG,mBAAmB,CAAC;AAC1D,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,SAAS,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;AACjF,MAAM,CAAC,MAAM,eAAe,GAAG,0BAA0B,CAAC;AAC1D,MAAM,CAAC,MAAM,qBAAqB,GAAG,+BAA+B,CAAC;AACrE,MAAM,CAAC,MAAM,2BAA2B,GAAG,WAAW,CAAC"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/utils/constants.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AACb,MAAM,CAAC,MAAM,sBAAsB,GAAG,mBAAmB,CAAC;AAC1D,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,SAAS,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;AACjF,MAAM,CAAC,MAAM,eAAe,GAAG,0BAA0B,CAAC;AAC1D,MAAM,CAAC,MAAM,qBAAqB,GAAG,+BAA+B,CAAC;AACrE,MAAM,CAAC,MAAM,2BAA2B,GAAG,WAAW,CAAC;AACvD,MAAM,CAAC,MAAM,sBAAsB,GAAG,wBAAwB,CAAC"}
@@ -1 +1,4 @@
1
- export declare function getPackageDirectories(ignoreDirs: string[]): Promise<string[]>;
1
+ export declare function getPackageDirectories(ignoreDirs: string[]): Promise<{
2
+ metadataPaths: string[];
3
+ repoRoot: string;
4
+ }>;
@@ -15,7 +15,7 @@ export async function getPackageDirectories(ignoreDirs) {
15
15
  .map((directory) => resolve(repoRoot, directory.path))
16
16
  .filter((directory) => !ignoreDirs.includes(basename(directory)));
17
17
  const metadataPaths = (await Promise.all(packageDirectories.map((directory) => searchForSubFolders(directory, SEARCHABLE_METADATA_FOLDERS)))).flat();
18
- return metadataPaths;
18
+ return { metadataPaths, repoRoot };
19
19
  }
20
20
  async function searchForSubFolders(dxDirectory, subDirectoryNames) {
21
21
  const foundPaths = [];
@@ -1 +1 @@
1
- {"version":3,"file":"getPackageDirectories.js","sourceRoot":"","sources":["../../src/utils/getPackageDirectories.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE3D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAE7D,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,UAAoB;IAC9D,MAAM,EAAE,QAAQ,EAAE,gBAAgB,EAAE,GAAG,MAAM,WAAW,EAAE,CAAC;IAE3D,IAAI,CAAC,QAAQ,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAC;IACnF,CAAC;IAED,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACxB,MAAM,cAAc,GAAW,MAAM,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;IACzE,MAAM,WAAW,GAAgB,IAAI,CAAC,KAAK,CAAC,cAAc,CAAgB,CAAC;IAC3E,MAAM,kBAAkB,GAAG,WAAW,CAAC,kBAAkB;SACtD,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;SACrD,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAEpE,MAAM,aAAa,GAAG,CACpB,MAAM,OAAO,CAAC,GAAG,CACf,kBAAkB,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,mBAAmB,CAAC,SAAS,EAAE,2BAA2B,CAAC,CAAC,CACnG,CACF,CAAC,IAAI,EAAE,CAAC;IAET,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,KAAK,UAAU,mBAAmB,CAAC,WAAmB,EAAE,iBAA2B;IACjF,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC;IAEzC,MAAM,eAAe,GAAG,MAAM,OAAO,CAAC,GAAG,CACvC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACvB,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QACzC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC;QAEnC,IAAI,KAAK,CAAC,WAAW,EAAE,IAAI,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5D,OAAO,CAAC,QAAQ,CAAC,CAAC;QACpB,CAAC;aAAM,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YAC/B,OAAO,mBAAmB,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAAC;QAC1D,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC,CACH,CAAC;IAEF,KAAK,MAAM,KAAK,IAAI,eAAe,EAAE,CAAC;QACpC,UAAU,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC"}
1
+ {"version":3,"file":"getPackageDirectories.js","sourceRoot":"","sources":["../../src/utils/getPackageDirectories.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE3D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAE7D,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,UAAoB;IAC9D,MAAM,EAAE,QAAQ,EAAE,gBAAgB,EAAE,GAAG,MAAM,WAAW,EAAE,CAAC;IAE3D,IAAI,CAAC,QAAQ,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAC;IACnF,CAAC;IAED,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACxB,MAAM,cAAc,GAAW,MAAM,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;IACzE,MAAM,WAAW,GAAgB,IAAI,CAAC,KAAK,CAAC,cAAc,CAAgB,CAAC;IAC3E,MAAM,kBAAkB,GAAG,WAAW,CAAC,kBAAkB;SACtD,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;SACrD,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAEpE,MAAM,aAAa,GAAG,CACpB,MAAM,OAAO,CAAC,GAAG,CACf,kBAAkB,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,mBAAmB,CAAC,SAAS,EAAE,2BAA2B,CAAC,CAAC,CACnG,CACF,CAAC,IAAI,EAAE,CAAC;IAET,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC;AACrC,CAAC;AAED,KAAK,UAAU,mBAAmB,CAAC,WAAmB,EAAE,iBAA2B;IACjF,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC;IAEzC,MAAM,eAAe,GAAG,MAAM,OAAO,CAAC,GAAG,CACvC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACvB,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QACzC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC;QAEnC,IAAI,KAAK,CAAC,WAAW,EAAE,IAAI,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5D,OAAO,CAAC,QAAQ,CAAC,CAAC;QACpB,CAAC;aAAM,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YAC/B,OAAO,mBAAmB,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAAC;QAC1D,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC,CACH,CAAC;IAEF,KAAK,MAAM,KAAK,IAAI,eAAe,EAAE,CAAC;QACpC,UAAU,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC"}
@@ -18,5 +18,7 @@ export type ListTestsOptions = {
18
18
  ignoreMissingTests?: boolean;
19
19
  ignoreDirs?: string[];
20
20
  noWarnings?: boolean;
21
+ filterByMetadata?: boolean;
21
22
  warn?: (msg: string) => void;
22
23
  };
24
+ export type TestMetadataMap = Record<string, string[]>;
@@ -46,6 +46,14 @@ Do not print warnings for each Apex file missing annotations.
46
46
 
47
47
  Do not print warnings for each Apex file missing annotations.
48
48
 
49
+ # flags.filter-by-metadata.summary
50
+
51
+ Only include tests that explicitly declare metadata dependencies matching changed metadata.
52
+
53
+ # flags.filter-by-metadata.description
54
+
55
+ When enabled with `manifest`, test selection is based on metadata changes (e.g., Flow, CustomObject) rather than Apex annotations.
56
+
49
57
  # examples
50
58
 
51
59
  - <%= config.bin %> <%= command.id %> --format csv
package/oclif.lock CHANGED
@@ -1368,10 +1368,10 @@
1368
1368
  "@nodelib/fs.scandir" "2.1.5"
1369
1369
  fastq "^1.6.0"
1370
1370
 
1371
- "@oclif/core@4.3.3", "@oclif/core@^4", "@oclif/core@^4.0.27", "@oclif/core@^4.3.2":
1372
- version "4.3.3"
1373
- resolved "https://registry.yarnpkg.com/@oclif/core/-/core-4.3.3.tgz#a527536b62ef202c58d2b69ce9cd1e64eb3a94b1"
1374
- integrity sha512-A0mk4nlVE+r34fl91OdglXVPwhhfzM59IhSxnOigqMkwxFgT8z3i2WlUgzmazzvzSccs2KM4N2HkTS3NEvW96g==
1371
+ "@oclif/core@4.4.1", "@oclif/core@^4", "@oclif/core@^4.0.27", "@oclif/core@^4.3.2":
1372
+ version "4.4.1"
1373
+ resolved "https://registry.yarnpkg.com/@oclif/core/-/core-4.4.1.tgz#359d4df4f066529f3f4b44652db2d3dceb723823"
1374
+ integrity sha512-RYonV4IJZcGAoi3pdo5CPl5hVH1YdtQMEX77TLdgTPVrMmIjbiB0Borfguj/mdDF2TjLXp+Z+RbmLUejuhSYTA==
1375
1375
  dependencies:
1376
1376
  ansi-escapes "^4.3.2"
1377
1377
  ansis "^3.17.0"
@@ -1393,9 +1393,9 @@
1393
1393
  wrap-ansi "^7.0.0"
1394
1394
 
1395
1395
  "@oclif/plugin-command-snapshot@^5.2.23":
1396
- version "5.3.1"
1397
- resolved "https://registry.yarnpkg.com/@oclif/plugin-command-snapshot/-/plugin-command-snapshot-5.3.1.tgz#95fbba5980c89398dfb3ade0ae733d972f217a03"
1398
- integrity sha512-ytLavwqDuQ2+1Z4vV0lREGKf0JP6GTtVvYnrCMk9FL+C+CU6qnPyzI9fttuqwLMbfrsX8Fl8/6TT7dCWdX6HSg==
1396
+ version "5.3.2"
1397
+ resolved "https://registry.yarnpkg.com/@oclif/plugin-command-snapshot/-/plugin-command-snapshot-5.3.2.tgz#57d550b6e3f1f69ea6e4c6ec569333f9ee133711"
1398
+ integrity sha512-PdzFQ1BRbv1YqOo5+5P/FzpS3xQQs6xVUZFM+kbdhyhFf9baVGrzkyDqa+nWp9SIvBD0cMb4QrLuKMIfNG9JyA==
1399
1399
  dependencies:
1400
1400
  "@oclif/core" "^4"
1401
1401
  ansis "^3.17.0"
@@ -1480,10 +1480,10 @@
1480
1480
  strip-ansi "6.0.1"
1481
1481
  ts-retry-promise "^0.8.1"
1482
1482
 
1483
- "@salesforce/core@^8.10.3", "@salesforce/core@^8.12.0", "@salesforce/core@^8.5.1", "@salesforce/core@^8.8.0":
1484
- version "8.14.0"
1485
- resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-8.14.0.tgz#fcdd8b641221fee668b95ed2ede56b251668077c"
1486
- integrity sha512-Ta1aY15TfgxLyFNNlkw60Mm3dDtiEb50TSp3/wzrbuMgkEGvFBEZQca/ChrjANXhpw8pURDUTzL4VV/1eGCHrQ==
1483
+ "@salesforce/core@^8.12.0", "@salesforce/core@^8.14.0", "@salesforce/core@^8.5.1", "@salesforce/core@^8.8.0":
1484
+ version "8.15.0"
1485
+ resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-8.15.0.tgz#95d337a7a219c2d305117c9f5594617784a8642f"
1486
+ integrity sha512-vTobdBQ7JRlApUDezUAVlC7O7VUk1e+9AM8+TZIVnj2Glub7E5vtwTJRDT48MJ/wWjdhH+9MFfUi2GPHymHmrQ==
1487
1487
  dependencies:
1488
1488
  "@jsforce/jsforce-node" "^3.8.2"
1489
1489
  "@salesforce/kit" "^3.2.2"
@@ -1571,9 +1571,9 @@
1571
1571
  terminal-link "^3.0.0"
1572
1572
 
1573
1573
  "@salesforce/source-deploy-retrieve@^12.16.5":
1574
- version "12.19.10"
1575
- resolved "https://registry.yarnpkg.com/@salesforce/source-deploy-retrieve/-/source-deploy-retrieve-12.19.10.tgz#56818cc729bc21625b0653ad8b184c86023261b8"
1576
- integrity sha512-FfiX+Y96QnLjabpWjOxJgGq5Kh+ZQaP+RJa71DO/DtFFa0SlGW+VWqVzjSnNboHyq+nPF6DPDm1wT633zbEYvw==
1574
+ version "12.21.0"
1575
+ resolved "https://registry.yarnpkg.com/@salesforce/source-deploy-retrieve/-/source-deploy-retrieve-12.21.0.tgz#7e8dd986803ca8434882d56b8284a720d7e916a7"
1576
+ integrity sha512-dLOHm2F2maHmFHhumwigYwImh/8hWJQIOGSHYgtOMy5E0xc6Sed06QyRw1WBsoSUx7ihXvTrWpp6FhArb4OhFA==
1577
1577
  dependencies:
1578
1578
  "@salesforce/core" "^8.12.0"
1579
1579
  "@salesforce/kit" "^3.2.3"
@@ -3675,11 +3675,11 @@ eslint-plugin-jsdoc@^46.10.1:
3675
3675
  spdx-expression-parse "^4.0.0"
3676
3676
 
3677
3677
  eslint-plugin-sf-plugin@^1.20.13:
3678
- version "1.20.23"
3679
- resolved "https://registry.yarnpkg.com/eslint-plugin-sf-plugin/-/eslint-plugin-sf-plugin-1.20.23.tgz#213c514a67b734c989eac1ebbc23ff506f9ddc85"
3680
- integrity sha512-zlvxTJW4nMugGqgedymkEEeP/uiW/hgVGaaKZXEnCU+FMU7aW4kgTtLn+1JWk08mLwRlv/5NynGcABnsON21PA==
3678
+ version "1.20.26"
3679
+ resolved "https://registry.yarnpkg.com/eslint-plugin-sf-plugin/-/eslint-plugin-sf-plugin-1.20.26.tgz#3ffada40ee1aeab70384c16ed717769946b1473e"
3680
+ integrity sha512-kK1Kj+PpkVaGHWR+/FGdSW4lT7nbD+g2mSLkYFFQ4X9L9VnDSGI2mbNfByCeJ0RELC2GxM0jhw/T1pgSKc7aQw==
3681
3681
  dependencies:
3682
- "@salesforce/core" "^8.10.3"
3682
+ "@salesforce/core" "^8.14.0"
3683
3683
  "@typescript-eslint/utils" "^7.18.0"
3684
3684
 
3685
3685
  eslint-plugin-unicorn@^50.0.1:
@@ -7365,10 +7365,10 @@ yallist@^4.0.0:
7365
7365
  version "4.0.0"
7366
7366
  resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz"
7367
7367
 
7368
- yaml@^2.5.1, yaml@^2.7.1:
7369
- version "2.7.1"
7370
- resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.7.1.tgz#44a247d1b88523855679ac7fa7cda6ed7e135cf6"
7371
- integrity sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==
7368
+ yaml@^2.5.1, yaml@^2.7.1, yaml@^2.8.0:
7369
+ version "2.8.0"
7370
+ resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.0.tgz#15f8c9866211bdc2d3781a0890e44d4fa1a5fff6"
7371
+ integrity sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==
7372
7372
 
7373
7373
  yargs-parser@^18.1.2:
7374
7374
  version "18.1.3"
@@ -75,6 +75,15 @@
75
75
  "summary": "Do not print warnings for each Apex file missing annotations.",
76
76
  "allowNo": false,
77
77
  "type": "boolean"
78
+ },
79
+ "filter-by-metadata": {
80
+ "char": "m",
81
+ "description": "When enabled with `manifest`, test selection is based on metadata changes (e.g., Flow, CustomObject) rather than Apex annotations.",
82
+ "name": "filter-by-metadata",
83
+ "required": false,
84
+ "summary": "Only include tests that explicitly declare metadata dependencies matching changed metadata.",
85
+ "allowNo": false,
86
+ "type": "boolean"
78
87
  }
79
88
  },
80
89
  "hasDynamicHelp": false,
@@ -100,5 +109,5 @@
100
109
  ]
101
110
  }
102
111
  },
103
- "version": "1.12.4"
112
+ "version": "1.13.1"
104
113
  }
package/package.json CHANGED
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "apextestlist",
3
3
  "description": "A plugin that generates a list of apex test and test suite names for use in CI/CD pipelines.",
4
- "version": "1.12.4",
4
+ "version": "1.13.1",
5
5
  "dependencies": {
6
- "@oclif/core": "4.3.3",
6
+ "@oclif/core": "4.4.1",
7
7
  "@salesforce/core": "^8.8.0",
8
8
  "@salesforce/sf-plugins-core": "^11.3.12",
9
9
  "@salesforce/source-deploy-retrieve": "^12.16.5",
10
10
  "async": "^3.2.6",
11
- "xml2js": "^0.6.2"
11
+ "xml2js": "^0.6.2",
12
+ "yaml": "^2.8.0"
12
13
  },
13
14
  "devDependencies": {
14
15
  "@commitlint/cli": "^19.6.0",