apextestlist 1.14.3 → 1.15.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/CHANGELOG.md CHANGED
@@ -5,6 +5,20 @@
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.15.0](https://github.com/wisefoxme/apex-test-list/compare/v1.14.4...v1.15.0) (2026-09-16)
9
+
10
+
11
+ ### Features
12
+
13
+ * add manifest-aware --fail-on-empty flag ([#420](https://github.com/wisefoxme/apex-test-list/issues/420)) ([8fef2b5](https://github.com/wisefoxme/apex-test-list/commit/8fef2b54d169e4b474a340ea97b44642c9bd6815))
14
+
15
+ ## [1.14.4](https://github.com/wisefoxme/apex-test-list/compare/v1.14.3...v1.14.4) (2026-09-13)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * **deps:** bump @salesforce/core in the dependencies group ([#417](https://github.com/wisefoxme/apex-test-list/issues/417)) ([a6c1385](https://github.com/wisefoxme/apex-test-list/commit/a6c13857d405798831b5a626781eb97af0df4010))
21
+
8
22
  ## [1.14.3](https://github.com/wisefoxme/apex-test-list/compare/v1.14.2...v1.14.3) (2026-09-06)
9
23
 
10
24
 
package/README.md CHANGED
@@ -22,6 +22,7 @@ A plugin that generates a list of tests that your automated process should run,
22
22
  - [Running the Tool](#running-the-tool)
23
23
  - [Handling Missing Tests](#handling-missing-tests)
24
24
  - [Handling Missing Annotations](#handling-missing-annotations)
25
+ - [Failing When No Tests Are Found](#failing-when-no-tests-are-found)
25
26
  - [GitHub Action](#github-action)
26
27
  - [Command Reference](#command-reference)
27
28
  - [Issues](#issues)
@@ -162,6 +163,28 @@ To remove these warnings from the terminal, use:
162
163
  sf apextests list --no-warnings
163
164
  ```
164
165
 
166
+ ### Failing When No Tests Are Found
167
+
168
+ By default, the command exits with code `0` even when no test methods are found — it just prints an empty result and a warning. To have it fail the run instead, use:
169
+
170
+ ```sh
171
+ sf apextests list --fail-on-empty
172
+ ```
173
+
174
+ Combined with `-x`/`--manifest`, this is manifest-aware: it only fails when the manifest actually declares `ApexClass`/`ApexTrigger` members but no tests could be resolved for them. If the manifest contains no Apex at all (e.g., a delta package with only non-Apex metadata), the command still exits `0`, since there's nothing to test.
175
+
176
+ ```sh
177
+ # Exits 0: package.xml has no ApexClass/ApexTrigger members, nothing to check
178
+ sf apextests list --manifest package.xml --fail-on-empty
179
+
180
+ # Exits 1: package.xml declares Apex, but no tests were found for it
181
+ sf apextests list --manifest package.xml --fail-on-empty
182
+ ```
183
+
184
+ This is useful as a CI guardrail: skip the deploy/validate step cleanly when a manifest has no Apex changes, but fail loudly when Apex changed and no tests cover it.
185
+
186
+ The GitHub Action's `fail-on-empty` input behaves the same way — see [Inputs](#inputs).
187
+
165
188
  ## GitHub Action
166
189
 
167
190
  For GitHub Actions, this is also available as a native Action — no `sf` CLI or plugin install required:
@@ -188,7 +211,7 @@ For GitHub Actions, this is also available as a native Action — no `sf` CLI or
188
211
  | `ignore-package-directory` | Directory to ignore when searching for test annotations, one per line. | No | |
189
212
  | `no-warnings` | Do not print warnings for each Apex file missing annotations. | No | `false` |
190
213
  | `filter-by-metadata` | Only include tests that explicitly declare metadata dependencies matching changed metadata. Requires `manifest`. | No | `false` |
191
- | `fail-on-empty` | Fail the action if no test methods are found. | No | `false` |
214
+ | `fail-on-empty` | Fail the action if no test methods are found. Manifest-aware when `manifest` is set — see [Failing When No Tests Are Found](#failing-when-no-tests-are-found). | No | `false` |
192
215
 
193
216
  ### Outputs
194
217
 
@@ -203,7 +226,7 @@ For GitHub Actions, this is also available as a native Action — no `sf` CLI or
203
226
 
204
227
  ```
205
228
  USAGE
206
- $ sf apextests list -f <value> -x <value> -s -n -d <value> -m [--json]
229
+ $ sf apextests list -f <value> -x <value> -s -n -d <value> -m -e [--json]
207
230
 
208
231
  FLAGS
209
232
  -f, --format=<value> Output format. Available options:
@@ -216,7 +239,7 @@ FLAGS
216
239
  Should match how they are declared in "sfdx-project.json".
217
240
  Can be declared multiple times.
218
241
  -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.
219
-
242
+ -e, --fail-on-empty [default: false] Exit with code 1 if no test methods are found. With `--manifest`, exits 0 instead when the manifest has no ApexClass/ApexTrigger members.
220
243
 
221
244
  GLOBAL FLAGS
222
245
  --json Format output as JSON.
@@ -242,6 +265,10 @@ EXAMPLES
242
265
 
243
266
  $ sf apextests list -d "force-app"
244
267
 
268
+ Fail with exit code 1 if a manifest declares Apex but no tests are found for it (exit 0 if the manifest has no Apex at all):
269
+
270
+ $ sf apextests list --format sf --manifest package.xml --fail-on-empty
271
+
245
272
  List test annotations without printing warnings for each file missing annotations:
246
273
 
247
274
  $ sf apextests list -n
@@ -11,6 +11,7 @@ export default class ApextestsList extends SfCommand<ApextestsListResult> {
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
13
  'filter-by-metadata': import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
+ 'fail-on-empty': import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
15
  };
15
16
  run(): Promise<ApextestsListResult>;
16
17
  }
@@ -1,5 +1,5 @@
1
1
  'use strict';
2
- import { Messages } from '@salesforce/core';
2
+ import { Messages, SfError } from '@salesforce/core';
3
3
  import { Flags, SfCommand } from '@salesforce/sf-plugins-core';
4
4
  import { listTests } from '../../core/listTests.js';
5
5
  Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
@@ -50,6 +50,13 @@ export default class ApextestsList extends SfCommand {
50
50
  required: false,
51
51
  default: false,
52
52
  }),
53
+ 'fail-on-empty': Flags.boolean({
54
+ summary: messages.getMessage('flags.fail-on-empty.summary'),
55
+ description: messages.getMessage('flags.fail-on-empty.description'),
56
+ char: 'e',
57
+ required: false,
58
+ default: false,
59
+ }),
53
60
  };
54
61
  async run() {
55
62
  const { flags } = await this.parse(ApextestsList);
@@ -62,6 +69,9 @@ export default class ApextestsList extends SfCommand {
62
69
  filterByMetadata: flags['filter-by-metadata'],
63
70
  warn: this.warn.bind(this),
64
71
  });
72
+ if (flags['fail-on-empty'] && result.tests.length === 0 && (!flags.manifest || result.manifestHasApex)) {
73
+ throw new SfError(messages.getMessage('errors.noTestsFound'));
74
+ }
65
75
  this.log(result.command);
66
76
  return result;
67
77
  }
@@ -1 +1 @@
1
- {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/commands/apextests/list.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/commands/apextests/list.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAE/D,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAGpD,QAAQ,CAAC,kCAAkC,CAAC,OAAO,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,CAAmB,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IAClE,MAAM,CAAmB,WAAW,GAAG,QAAQ,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IAC1E,MAAM,CAAmB,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IAErE,MAAM,CAAmB,KAAK,GAAG;QACtC,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;QACF,oBAAoB,EAAE,KAAK,CAAC,OAAO,CAAC;YAClC,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,kCAAkC,CAAC;YAChE,WAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,sCAAsC,CAAC;YACxE,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,KAAK;YACf,OAAO,EAAE,KAAK;SACf,CAAC;QACF,eAAe,EAAE,KAAK,CAAC,OAAO,CAAC;YAC7B,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,6BAA6B,CAAC;YAC3D,WAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,iCAAiC,CAAC;YACnE,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,KAAK;YACf,OAAO,EAAE,KAAK;SACf,CAAC;KACH,CAAC;IAEK,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,gBAAgB,EAAE,KAAK,CAAC,oBAAoB,CAAC;YAC7C,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC;QAEH,IAAI,KAAK,CAAC,eAAe,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,QAAQ,IAAI,MAAM,CAAC,eAAe,CAAC,EAAE,CAAC;YACvG,MAAM,IAAI,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,qBAAqB,CAAC,CAAC,CAAC;QAChE,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACzB,OAAO,MAAM,CAAC;IAChB,CAAC;CACF"}
@@ -14,9 +14,11 @@ export async function listTests({ format = 'sf', manifest, ignoreMissingTests =
14
14
  const testSuitesNames = [];
15
15
  const allTestClasses = [];
16
16
  const warnings = [];
17
+ let manifestHasApex = false;
17
18
  const { metadataPaths: packageDirectories, repoRoot } = await getPackageDirectories(ignoreDirs);
18
19
  if (manifest) {
19
20
  const manifestMetadata = await extractTypeNamesFromManifestFile(manifest);
21
+ manifestHasApex = manifestMetadata.some((name) => name.startsWith('ApexClass:') || name.startsWith('ApexTrigger:'));
20
22
  testClassesNames = manifestMetadata.filter((name) => !name.endsWith('testSuite-meta.xml'));
21
23
  if (filterByMetadata) {
22
24
  const ymlConfigPath = resolve(repoRoot, METADATA_FILTER_CONFIG);
@@ -57,8 +59,9 @@ export async function listTests({ format = 'sf', manifest, ignoreMissingTests =
57
59
  return {
58
60
  tests: [],
59
61
  command: '',
62
+ manifestHasApex,
60
63
  };
61
64
  }
62
- return formatList(format, finalTestMethods);
65
+ return formatList(format, finalTestMethods, manifestHasApex);
63
66
  }
64
67
  //# sourceMappingURL=listTests.js.map
@@ -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":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,gCAAgC,EAAE,MAAM,8BAA8B,CAAC;AAChF,OAAO,EAAE,4BAA4B,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AACvG,OAAO,EAAE,6BAA6B,EAAE,MAAM,iCAAiC,CAAC;AAChF,OAAO,EAAE,uCAAuC,EAAE,MAAM,iCAAiC,CAAC;AAC1F,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAE1E,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE1D,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,EAC9B,MAAM,GAAG,IAAI,EACb,QAAQ,EACR,kBAAkB,GAAG,KAAK,EAC1B,UAAU,GAAG,EAAE,EACf,UAAU,GAAG,KAAK,EAClB,gBAAgB,GAAG,KAAK,EACxB,IAAI,GAAG,GAAS,EAAE;IAChB,gBAAgB;AAClB,CAAC,GACgB;IACjB,IAAI,gBAAgB,GAAoB,IAAI,CAAC;IAC7C,MAAM,eAAe,GAAa,EAAE,CAAC;IACrC,MAAM,cAAc,GAAa,EAAE,CAAC;IACpC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,eAAe,GAAG,KAAK,CAAC;IAE5B,MAAM,EAAE,aAAa,EAAE,kBAAkB,EAAE,QAAQ,EAAE,GAAG,MAAM,qBAAqB,CAAC,UAAU,CAAC,CAAC;IAEhG,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,gBAAgB,GAAG,MAAM,gCAAgC,CAAC,QAAQ,CAAC,CAAC;QAC1E,eAAe,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC,CAAC;QACpH,gBAAgB,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC,CAAC;QAC3F,IAAI,gBAAgB,EAAE,CAAC;YACrB,MAAM,aAAa,GAAG,OAAO,CAAC,QAAQ,EAAE,sBAAsB,CAAC,CAAC;YAChE,MAAM,OAAO,GAAG,MAAM,4BAA4B,CAAC,aAAa,CAAC,CAAC;YAClE,MAAM,UAAU,GAAG,mBAAmB,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;YAClE,cAAc,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAED,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,KAAK,MAAM,SAAS,IAAI,kBAAkB,EAAE,CAAC;YAC3C,MAAM,YAAY,GAAiB,MAAM,6BAA6B,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;YACpG,cAAc,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;YAC7C,eAAe,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;YACjD,IAAI,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;gBAClC,QAAQ,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC;QAED,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/B,KAAK,MAAM,SAAS,IAAI,kBAAkB,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;gBACvF,MAAM,SAAS,GAAG,MAAM,uCAAuC,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC;gBAC/F,cAAc,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC;YACpC,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,gBAAgB,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAEtF,IAAI,kBAAkB,EAAE,CAAC;QACvB,MAAM,EAAE,cAAc,EAAE,QAAQ,EAAE,kBAAkB,EAAE,GAAG,MAAM,aAAa,CAAC,gBAAgB,EAAE,kBAAkB,CAAC,CAAC;QACnH,gBAAgB,GAAG,cAAc,CAAC;QAClC,QAAQ,CAAC,IAAI,CAAC,GAAG,kBAAkB,CAAC,CAAC;IACvC,CAAC;IAED,gJAAgJ;IAChJ,IAAI,CAAC,UAAU,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAED,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IAEpD,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClC,IAAI,CAAC,uBAAuB,CAAC,CAAC;QAC9B,OAAO;YACL,KAAK,EAAE,EAAE;YACT,OAAO,EAAE,EAAE;YACX,eAAe;SAChB,CAAC;IACJ,CAAC;IAED,OAAO,UAAU,CAAC,MAAM,EAAE,gBAAgB,EAAE,eAAe,CAAC,CAAC;AAC/D,CAAC"}
@@ -1,2 +1,2 @@
1
1
  import { ApextestsListResult } from '../utils/types.js';
2
- export declare function formatList(format: string, tests: string[]): Promise<ApextestsListResult>;
2
+ export declare function formatList(format: string, tests: string[], manifestHasApex?: boolean): Promise<ApextestsListResult>;
@@ -1,21 +1,24 @@
1
1
  'use strict';
2
2
  const TESTS_FLAG = '--tests ';
3
- export async function formatList(format, tests) {
3
+ export async function formatList(format, tests, manifestHasApex = false) {
4
4
  switch (format) {
5
5
  case 'sf':
6
6
  return Promise.resolve({
7
7
  tests,
8
8
  command: TESTS_FLAG + tests.join(` ${TESTS_FLAG}`),
9
+ manifestHasApex,
9
10
  });
10
11
  case 'sfdx':
11
12
  return Promise.resolve({
12
13
  tests,
13
14
  command: TESTS_FLAG + tests.join(' '),
15
+ manifestHasApex,
14
16
  });
15
17
  case 'csv':
16
18
  return Promise.resolve({
17
19
  tests,
18
20
  command: tests.join(','),
21
+ manifestHasApex,
19
22
  });
20
23
  default:
21
24
  throw new Error('Invalid format.');
@@ -1 +1 @@
1
- {"version":3,"file":"formatters.js","sourceRoot":"","sources":["../../src/utils/formatters.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAGb,MAAM,UAAU,GAAG,UAAU,CAAC;AAE9B,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAc,EAAE,KAAe;IAC9D,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,IAAI;YACP,OAAO,OAAO,CAAC,OAAO,CAAC;gBACrB,KAAK;gBACL,OAAO,EAAE,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,UAAU,EAAE,CAAC;aACnD,CAAC,CAAC;QACL,KAAK,MAAM;YACT,OAAO,OAAO,CAAC,OAAO,CAAC;gBACrB,KAAK;gBACL,OAAO,EAAE,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;aACtC,CAAC,CAAC;QACL,KAAK,KAAK;YACR,OAAO,OAAO,CAAC,OAAO,CAAC;gBACrB,KAAK;gBACL,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;aACzB,CAAC,CAAC;QACL;YACE,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACvC,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"formatters.js","sourceRoot":"","sources":["../../src/utils/formatters.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAGb,MAAM,UAAU,GAAG,UAAU,CAAC;AAE9B,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,MAAc,EACd,KAAe,EACf,eAAe,GAAG,KAAK;IAEvB,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,IAAI;YACP,OAAO,OAAO,CAAC,OAAO,CAAC;gBACrB,KAAK;gBACL,OAAO,EAAE,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,UAAU,EAAE,CAAC;gBAClD,eAAe;aAChB,CAAC,CAAC;QACL,KAAK,MAAM;YACT,OAAO,OAAO,CAAC,OAAO,CAAC;gBACrB,KAAK;gBACL,OAAO,EAAE,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;gBACrC,eAAe;aAChB,CAAC,CAAC;QACL,KAAK,KAAK;YACR,OAAO,OAAO,CAAC,OAAO,CAAC;gBACrB,KAAK;gBACL,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;gBACxB,eAAe;aAChB,CAAC,CAAC;QACL;YACE,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACvC,CAAC;AACH,CAAC"}
@@ -11,6 +11,7 @@ export type SearchResult = {
11
11
  export type ApextestsListResult = {
12
12
  tests: string[];
13
13
  command: string;
14
+ manifestHasApex: boolean;
14
15
  };
15
16
  export type ListTestsOptions = {
16
17
  format?: string;
@@ -54,6 +54,18 @@ Only include tests that explicitly declare metadata dependencies matching change
54
54
 
55
55
  When enabled with `manifest`, test selection is based on metadata changes (e.g., Flow, CustomObject) rather than Apex annotations.
56
56
 
57
+ # flags.fail-on-empty.summary
58
+
59
+ Fail with exit code 1 if no test methods are found.
60
+
61
+ # flags.fail-on-empty.description
62
+
63
+ If provided, the command exits with code 1 when no test methods are found. When combined with `--manifest`, the command still exits with code 0 if the manifest contains no `ApexClass` or `ApexTrigger` members, since there is nothing to test in that case.
64
+
65
+ # errors.noTestsFound
66
+
67
+ No test methods found.
68
+
57
69
  # examples
58
70
 
59
71
  - <%= config.bin %> <%= command.id %> --format csv
@@ -61,3 +73,4 @@ When enabled with `manifest`, test selection is based on metadata changes (e.g.,
61
73
  - <%= config.bin %> <%= command.id %> --format sf --manifest package.xml
62
74
  - <%= config.bin %> <%= command.id %> --format sf --manifest package.xml --ignore-missing-tests
63
75
  - <%= config.bin %> <%= command.id %> --format sf --manifest package.xml -d "force-app"
76
+ - <%= config.bin %> <%= command.id %> --format sf --manifest package.xml --fail-on-empty
@@ -9,7 +9,8 @@
9
9
  "<%= config.bin %> <%= command.id %> --format sf",
10
10
  "<%= config.bin %> <%= command.id %> --format sf --manifest package.xml",
11
11
  "<%= config.bin %> <%= command.id %> --format sf --manifest package.xml --ignore-missing-tests",
12
- "<%= config.bin %> <%= command.id %> --format sf --manifest package.xml -d \"force-app\""
12
+ "<%= config.bin %> <%= command.id %> --format sf --manifest package.xml -d \"force-app\"",
13
+ "<%= config.bin %> <%= command.id %> --format sf --manifest package.xml --fail-on-empty"
13
14
  ],
14
15
  "flags": {
15
16
  "json": {
@@ -84,6 +85,15 @@
84
85
  "summary": "Only include tests that explicitly declare metadata dependencies matching changed metadata.",
85
86
  "allowNo": false,
86
87
  "type": "boolean"
88
+ },
89
+ "fail-on-empty": {
90
+ "char": "e",
91
+ "description": "If provided, the command exits with code 1 when no test methods are found. When combined with `--manifest`, the command still exits with code 0 if the manifest contains no `ApexClass` or `ApexTrigger` members, since there is nothing to test in that case.",
92
+ "name": "fail-on-empty",
93
+ "required": false,
94
+ "summary": "Fail with exit code 1 if no test methods are found.",
95
+ "allowNo": false,
96
+ "type": "boolean"
87
97
  }
88
98
  },
89
99
  "hasDynamicHelp": false,
@@ -109,5 +119,5 @@
109
119
  ]
110
120
  }
111
121
  },
112
- "version": "1.14.3"
122
+ "version": "1.15.0"
113
123
  }
package/package.json CHANGED
@@ -1,10 +1,10 @@
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.14.3",
4
+ "version": "1.15.0",
5
5
  "dependencies": {
6
6
  "@oclif/core": "5.0.0",
7
- "@salesforce/core": "9.1.9",
7
+ "@salesforce/core": "9.1.11",
8
8
  "@salesforce/sf-plugins-core": "13.0.4"
9
9
  },
10
10
  "devDependencies": {
@@ -16,20 +16,21 @@
16
16
  "@salesforce/dev-config": "4.3.3",
17
17
  "@stryker-mutator/core": "10.0.0",
18
18
  "@stryker-mutator/vitest-runner": "10.0.0",
19
- "@types/node": "26.4.1",
19
+ "@types/node": "26.5.1",
20
20
  "@vitest/coverage-v8": "5.0.0",
21
21
  "esbuild": "0.28.2",
22
22
  "husky": "9.1.7",
23
- "lint-staged": "17.4.1",
24
- "oclif": "5.0.0",
23
+ "knip": "6.35.1",
24
+ "lint-staged": "17.5.0",
25
+ "ls-engines": "0.10.1",
26
+ "oclif": "5.0.1",
25
27
  "shx": "0.4.0",
26
- "ts-node": "10.9.2",
27
28
  "typescript": "7.0.2",
28
29
  "vitest": "5.0.0",
29
30
  "wireit": "0.14.13"
30
31
  },
31
32
  "engines": {
32
- "node": ">=22 <=26"
33
+ "node": ">=22.19.0 <=26"
33
34
  },
34
35
  "files": [
35
36
  "/lib",
@@ -73,6 +74,8 @@
73
74
  "format": "wireit",
74
75
  "link-check": "wireit",
75
76
  "lint": "wireit",
77
+ "lint:dependencies": "wireit",
78
+ "lint:engine": "wireit",
76
79
  "postpack": "shx rm -f oclif.manifest.json oclif.lock",
77
80
  "prepack": "wireit",
78
81
  "prepare": "husky",
@@ -169,6 +172,27 @@
169
172
  ],
170
173
  "output": []
171
174
  },
175
+ "lint:dependencies": {
176
+ "command": "knip",
177
+ "files": [
178
+ "src/**/*.ts",
179
+ "test/**/*.ts",
180
+ "knip.config.ts",
181
+ "package.json"
182
+ ],
183
+ "output": [],
184
+ "dependencies": [
185
+ "lint"
186
+ ]
187
+ },
188
+ "lint:engine": {
189
+ "command": "ls-engines --no-current --no-dev --mode=virtual",
190
+ "files": [
191
+ "package.json",
192
+ "package-lock.json"
193
+ ],
194
+ "output": []
195
+ },
172
196
  "prepack": {
173
197
  "command": "oclif manifest && oclif readme",
174
198
  "files": [
@@ -269,5 +293,8 @@
269
293
  },
270
294
  "exports": "./lib/index.js",
271
295
  "type": "module",
272
- "author": "Renato Oliveira"
296
+ "author": "Renato Oliveira",
297
+ "allowScripts": {
298
+ "esbuild@0.28.2": true
299
+ }
273
300
  }