apextestlist 1.14.4 → 1.15.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,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.1](https://github.com/wisefoxme/apex-test-list/compare/v1.15.0...v1.15.1) (2026-09-28)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **deps:** bump @salesforce/core in the dependencies group ([#426](https://github.com/wisefoxme/apex-test-list/issues/426)) ([f98d484](https://github.com/wisefoxme/apex-test-list/commit/f98d48450fa7d2f54e8b6ec8cb075c5709e39144))
14
+
15
+ ## [1.15.0](https://github.com/wisefoxme/apex-test-list/compare/v1.14.4...v1.15.0) (2026-09-16)
16
+
17
+
18
+ ### Features
19
+
20
+ * 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))
21
+
8
22
  ## [1.14.4](https://github.com/wisefoxme/apex-test-list/compare/v1.14.3...v1.14.4) (2026-09-13)
9
23
 
10
24
 
package/README.md CHANGED
@@ -20,8 +20,10 @@ A plugin that generates a list of tests that your automated process should run,
20
20
  - [3. `@isTest` (Apex Annotation)](#3-istest-apex-annotation)
21
21
  - [4. `.test-dependencies.yml` (Centralized Metadata Filter)](#4-test-dependenciesyml-centralized-metadata-filter)
22
22
  - [Running the Tool](#running-the-tool)
23
+ - [Explicit Test Level for Deploy and Validate](#explicit-test-level-for-deploy-and-validate)
23
24
  - [Handling Missing Tests](#handling-missing-tests)
24
25
  - [Handling Missing Annotations](#handling-missing-annotations)
26
+ - [Failing When No Tests Are Found](#failing-when-no-tests-are-found)
25
27
  - [GitHub Action](#github-action)
26
28
  - [Command Reference](#command-reference)
27
29
  - [Issues](#issues)
@@ -123,13 +125,29 @@ Example output:
123
125
  This command is useful in CI/CD pipelines, dynamically generating the test list for deployments:
124
126
 
125
127
  ```sh
126
- sf project deploy start $(sf apextests list)
128
+ sf project deploy start --test-level RunSpecifiedTests $(sf apextests list)
127
129
  ```
128
130
 
129
131
  The final deployment command would look like:
130
132
 
131
133
  ```sh
132
- sf project deploy start --tests SampleTest SuperSampleTest Sample2Test SuperSample2Test SampleTriggerTest
134
+ sf project deploy start --test-level RunSpecifiedTests --tests SampleTest SuperSampleTest Sample2Test SuperSample2Test SampleTriggerTest
135
+ ```
136
+
137
+ ### Explicit Test Level for Deploy and Validate
138
+
139
+ When you append `sf apextests list` output (or the GitHub Action `command` output) to `sf project deploy start` or `sf project deploy validate`, explicitly pass `--test-level RunSpecifiedTests`. Without it, the deploy or validation can fail immediately with:
140
+
141
+ ```text
142
+ Error (1): INVALID_OPERATION: runTests can only be used with a testLevel of RunSpecifiedTests
143
+ ```
144
+
145
+ Salesforce CLI documentation suggests that providing `--tests` should infer `RunSpecifiedTests`, but behavior differs between deploy subcommands. In practice, `sf project deploy validate` does not set the level implicitly (a fix is tracked in [salesforcecli/plugin-deploy-retrieve#1650](https://github.com/salesforcecli/plugin-deploy-retrieve/pull/1650)). Using an explicit test level works for both start and validate.
146
+
147
+ With a manifest:
148
+
149
+ ```sh
150
+ sf project deploy start -x package/package.xml --test-level RunSpecifiedTests $(sf apextests list -x package/package.xml)
133
151
  ```
134
152
 
135
153
  If no test methods are found, the command output will be empty and will present this warning:
@@ -162,6 +180,28 @@ To remove these warnings from the terminal, use:
162
180
  sf apextests list --no-warnings
163
181
  ```
164
182
 
183
+ ### Failing When No Tests Are Found
184
+
185
+ 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:
186
+
187
+ ```sh
188
+ sf apextests list --fail-on-empty
189
+ ```
190
+
191
+ 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.
192
+
193
+ ```sh
194
+ # Exits 0: package.xml has no ApexClass/ApexTrigger members, nothing to check
195
+ sf apextests list --manifest package.xml --fail-on-empty
196
+
197
+ # Exits 1: package.xml declares Apex, but no tests were found for it
198
+ sf apextests list --manifest package.xml --fail-on-empty
199
+ ```
200
+
201
+ 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.
202
+
203
+ The GitHub Action's `fail-on-empty` input behaves the same way — see [Inputs](#inputs).
204
+
165
205
  ## GitHub Action
166
206
 
167
207
  For GitHub Actions, this is also available as a native Action — no `sf` CLI or plugin install required:
@@ -175,7 +215,7 @@ For GitHub Actions, this is also available as a native Action — no `sf` CLI or
175
215
  ignore-missing-tests: 'true'
176
216
 
177
217
  - name: Deploy with the specified tests
178
- run: sf project deploy start -x package.xml ${{ steps.list.outputs.command }}
218
+ run: sf project deploy start -x package.xml --test-level RunSpecifiedTests ${{ steps.list.outputs.command }}
179
219
  ```
180
220
 
181
221
  ### Inputs
@@ -188,7 +228,7 @@ For GitHub Actions, this is also available as a native Action — no `sf` CLI or
188
228
  | `ignore-package-directory` | Directory to ignore when searching for test annotations, one per line. | No | |
189
229
  | `no-warnings` | Do not print warnings for each Apex file missing annotations. | No | `false` |
190
230
  | `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` |
231
+ | `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
232
 
193
233
  ### Outputs
194
234
 
@@ -203,7 +243,7 @@ For GitHub Actions, this is also available as a native Action — no `sf` CLI or
203
243
 
204
244
  ```
205
245
  USAGE
206
- $ sf apextests list -f <value> -x <value> -s -n -d <value> -m [--json]
246
+ $ sf apextests list -f <value> -x <value> -s -n -d <value> -m -e [--json]
207
247
 
208
248
  FLAGS
209
249
  -f, --format=<value> Output format. Available options:
@@ -216,7 +256,7 @@ FLAGS
216
256
  Should match how they are declared in "sfdx-project.json".
217
257
  Can be declared multiple times.
218
258
  -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
-
259
+ -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
260
 
221
261
  GLOBAL FLAGS
222
262
  --json Format output as JSON.
@@ -242,6 +282,10 @@ EXAMPLES
242
282
 
243
283
  $ sf apextests list -d "force-app"
244
284
 
285
+ 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):
286
+
287
+ $ sf apextests list --format sf --manifest package.xml --fail-on-empty
288
+
245
289
  List test annotations without printing warnings for each file missing annotations:
246
290
 
247
291
  $ 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":"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"}
@@ -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.4"
122
+ "version": "1.15.1"
113
123
  }
package/package.json CHANGED
@@ -1,32 +1,32 @@
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.4",
4
+ "version": "1.15.1",
5
5
  "dependencies": {
6
6
  "@oclif/core": "5.0.0",
7
- "@salesforce/core": "9.1.11",
7
+ "@salesforce/core": "9.2.0",
8
8
  "@salesforce/sf-plugins-core": "13.0.4"
9
9
  },
10
10
  "devDependencies": {
11
11
  "@actions/core": "3.0.1",
12
- "@biomejs/biome": "2.5.12",
13
- "@commitlint/cli": "21.2.2",
14
- "@commitlint/config-conventional": "21.2.2",
12
+ "@biomejs/biome": "2.5.14",
13
+ "@commitlint/cli": "21.2.3",
14
+ "@commitlint/config-conventional": "21.2.3",
15
15
  "@salesforce/cli-plugins-testkit": "5.3.66",
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.5.1",
20
- "@vitest/coverage-v8": "5.0.0",
19
+ "@types/node": "26.6.2",
20
+ "@vitest/coverage-v8": "5.0.1",
21
21
  "esbuild": "0.28.2",
22
22
  "husky": "9.1.7",
23
- "knip": "6.35.1",
24
- "lint-staged": "17.5.0",
23
+ "knip": "6.38.0",
24
+ "lint-staged": "17.5.1",
25
25
  "ls-engines": "0.10.1",
26
- "oclif": "5.0.1",
26
+ "oclif": "6.0.1",
27
27
  "shx": "0.4.0",
28
28
  "typescript": "7.0.2",
29
- "vitest": "5.0.0",
29
+ "vitest": "5.0.1",
30
30
  "wireit": "0.14.13"
31
31
  },
32
32
  "engines": {