sf-decomposer 7.2.0 → 7.3.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,13 @@
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
+ ## [7.3.0](https://github.com/mcarvin8/sf-decomposer/compare/v7.2.0...v7.3.0) (2026-08-24)
9
+
10
+
11
+ ### Features
12
+
13
+ * **action:** add a GitHub Action wrapping decompose/recompose/verify ([#572](https://github.com/mcarvin8/sf-decomposer/issues/572)) ([b32391d](https://github.com/mcarvin8/sf-decomposer/commit/b32391dff7dd2d77868b4a67cc70f7563dd1e55b))
14
+
8
15
  ## [7.2.0](https://github.com/mcarvin8/sf-decomposer/compare/v7.1.1...v7.2.0) (2026-08-24)
9
16
 
10
17
 
package/README.md CHANGED
@@ -8,7 +8,10 @@
8
8
  [![Mutation testing badge](https://img.shields.io/endpoint?style=flat&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fmcarvin8%2Fsf-decomposer%2Fmain)](https://dashboard.stryker-mutator.io/reports/github.com/mcarvin8/sf-decomposer/main)
9
9
  [![Performance](https://img.shields.io/badge/Performance-Dashboard-58a6ff)](https://mcarvin8.github.io/sf-decomposer/dev/bench/runtime/)
10
10
 
11
- A Salesforce CLI plugin that **decomposes** large metadata XML files into smaller, version-control–friendly files (XML, JSON, YAML, JSON5), and **recomposes** them back into deployment-ready metadata.
11
+ **Decomposes** large Salesforce metadata XML files into smaller, version-control–friendly files (XML, JSON, YAML, JSON5), and **recomposes** them back into deployment-ready metadata — as a Salesforce CLI plugin, or as a GitHub Action that needs neither the CLI nor a plugin install.
12
+
13
+ - Using the Salesforce CLI? Start at [Setup](#setup).
14
+ - Running this in CI without the CLI? Skip straight to [GitHub Action](#github-action).
12
15
 
13
16
  <!-- TABLE OF CONTENTS -->
14
17
  <details>
@@ -21,6 +24,7 @@ A Salesforce CLI plugin that **decomposes** large metadata XML files into smalle
21
24
  - [4. Configure Hooks](#4-configure-hooks-recommended)
22
25
  - [Daily Workflow](#daily-workflow)
23
26
  - [Commands](#commands)
27
+ - [GitHub Action](#github-action)
24
28
  - [Reference](#reference)
25
29
  - [Decompose Strategies](#decompose-strategies)
26
30
  - [Supported Metadata](#supported-metadata)
@@ -215,7 +219,7 @@ EXAMPLES
215
219
  `sf decomposer decompose -x "manifest/package.xml" -m "flow"`
216
220
  ```
217
221
 
218
- _See code: [src/commands/decomposer/decompose.ts](https://github.com/mcarvin8/sf-decomposer/blob/v7.2.0/src/commands/decomposer/decompose.ts)_
222
+ _See code: [src/commands/decomposer/decompose.ts](https://github.com/mcarvin8/sf-decomposer/blob/v7.3.0/src/commands/decomposer/decompose.ts)_
219
223
 
220
224
  ## `sf decomposer recompose`
221
225
 
@@ -261,7 +265,7 @@ EXAMPLES
261
265
  `sf decomposer recompose -x "manifest/package.xml" -m "flow"`
262
266
  ```
263
267
 
264
- _See code: [src/commands/decomposer/recompose.ts](https://github.com/mcarvin8/sf-decomposer/blob/v7.2.0/src/commands/decomposer/recompose.ts)_
268
+ _See code: [src/commands/decomposer/recompose.ts](https://github.com/mcarvin8/sf-decomposer/blob/v7.3.0/src/commands/decomposer/recompose.ts)_
265
269
 
266
270
  ## `sf decomposer verify`
267
271
 
@@ -325,11 +329,59 @@ EXAMPLES
325
329
  `sf decomposer verify -x "manifest/package.xml" --config`
326
330
  ```
327
331
 
328
- _See code: [src/commands/decomposer/verify.ts](https://github.com/mcarvin8/sf-decomposer/blob/v7.2.0/src/commands/decomposer/verify.ts)_
332
+ _See code: [src/commands/decomposer/verify.ts](https://github.com/mcarvin8/sf-decomposer/blob/v7.3.0/src/commands/decomposer/verify.ts)_
329
333
  <!-- commandsstop -->
330
334
 
331
335
  ---
332
336
 
337
+ ## GitHub Action
338
+
339
+ `decompose`, `recompose`, and `verify` are also available as a GitHub Action — a container action, so it needs **no Salesforce CLI and no `sf-decomposer` plugin install**. One action, dispatched by a `mode` input, mirrors the three CLI commands one-for-one: same flags (as inputs), same `.sfdecomposer.config.json` support via `config: true`.
340
+
341
+ ```yaml
342
+ - uses: actions/checkout@v7
343
+
344
+ - name: Decompose retrieved metadata
345
+ uses: mcarvin8/sf-decomposer@v7
346
+ with:
347
+ mode: decompose
348
+ metadata-type: |
349
+ permissionset
350
+ flow
351
+ postpurge: 'true'
352
+
353
+ - name: Verify the round trip before merging
354
+ uses: mcarvin8/sf-decomposer@v7
355
+ with:
356
+ mode: verify
357
+ config: 'true'
358
+ ```
359
+
360
+ Or point it at an existing `.sfdecomposer.config.json` for either step instead of listing flags: `with: { mode: decompose, config: 'true' }`.
361
+
362
+ **Inputs** (all optional except `mode`; multi-value inputs are newline-separated, matching `actions/checkout`'s own multiline convention):
363
+
364
+ | Input | Used by | Description |
365
+ |--------------------------------|----------------------|-----------------------------------------------------------------------------------|
366
+ | `mode` | all | `decompose`, `recompose`, or `verify`. |
367
+ | `metadata-type` | all | Metadata suffix(es) to process, one per line. |
368
+ | `manifest` | all | Path to a package.xml manifest to scope the run to. |
369
+ | `ignore-package-directory` | all | Package director(y/ies) to skip, one per line. |
370
+ | `config` | all | Read settings from `.sfdecomposer.config.json`, same as the CLI's `--config`. |
371
+ | `format` | decompose, verify | `xml`, `json`, `json5`, or `yaml`. Default `xml`. |
372
+ | `strategy` | decompose, verify | `unique-id` or `grouped-by-tag`. Default `unique-id`. |
373
+ | `decompose-nested-permissions` | decompose, verify | With `grouped-by-tag`, further decompose permission set object/field permissions. |
374
+ | `prepurge` | decompose | Remove existing decomposed files before decomposing. |
375
+ | `postpurge` | decompose, recompose | After decompose, remove originals; after recompose, remove decomposed files. |
376
+ | `update-forceignore` | decompose | Append decomposed file patterns to `.forceignore`. |
377
+ | `update-gitattributes` | decompose | Mark decomposed files as generated in `.gitattributes`. |
378
+
379
+ **Outputs:** `metadata` (newline-separated list of processed suffixes), `types-count`; `verify` additionally sets `drift-count` and `reordered-count`, and fails the step when `drift-count` is greater than 0.
380
+
381
+ See [`action.yml`](action.yml) for the full input/output reference.
382
+
383
+ ---
384
+
333
385
  ## Reference
334
386
 
335
387
  ### Decompose Strategies
@@ -0,0 +1 @@
1
+ export declare function runDecompose(): Promise<void>;
@@ -0,0 +1,57 @@
1
+ 'use strict';
2
+ import * as core from '@actions/core';
3
+ import { decomposeMetadataTypes } from '../core/decomposeMetadataTypes.js';
4
+ import { loadConfigFile, parseConfigSuffixes, resolveDefaultConfigPath, validateConfigManifest, } from '../helpers/configOverrides.js';
5
+ import { multilineInput, optionalInput, requireMetadataTypesOrManifest } from './inputs.js';
6
+ export async function runDecompose() {
7
+ let metadataTypes = multilineInput('metadata-type');
8
+ let manifest = optionalInput('manifest');
9
+ let ignoreDirs = multilineInput('ignore-package-directory');
10
+ let format = optionalInput('format') ?? 'xml';
11
+ let strategy = optionalInput('strategy') ?? 'unique-id';
12
+ let prepurge = core.getBooleanInput('prepurge');
13
+ let postpurge = core.getBooleanInput('postpurge');
14
+ let decomposeNestedPerms = core.getBooleanInput('decompose-nested-permissions');
15
+ let updateForceignore = core.getBooleanInput('update-forceignore');
16
+ let updateGitattributes = core.getBooleanInput('update-gitattributes');
17
+ let overrides;
18
+ if (core.getBooleanInput('config')) {
19
+ const config = await loadConfigFile(await resolveDefaultConfigPath());
20
+ metadataTypes ??= parseConfigSuffixes(config.metadataSuffixes);
21
+ const configManifest = !manifest ? config.manifest : undefined;
22
+ manifest ??= config.manifest;
23
+ ignoreDirs ??= parseConfigSuffixes(config.ignorePackageDirectories);
24
+ format = optionalInput('format') ?? config.decomposedFormat ?? 'xml';
25
+ strategy = optionalInput('strategy') ?? config.strategy ?? 'unique-id';
26
+ prepurge = prepurge || (config.prePurge ?? false);
27
+ postpurge = postpurge || (config.postPurge ?? false);
28
+ decomposeNestedPerms = decomposeNestedPerms || (config.decomposeNestedPermissions ?? false);
29
+ updateForceignore = updateForceignore || (config.updateForceignore ?? false);
30
+ updateGitattributes = updateGitattributes || (config.updateGitattributes ?? false);
31
+ overrides = config.overrides;
32
+ manifest = await validateConfigManifest({
33
+ configManifest,
34
+ metadataTypes,
35
+ manifest,
36
+ warn: (msg) => core.warning(msg),
37
+ });
38
+ }
39
+ requireMetadataTypesOrManifest(metadataTypes, manifest);
40
+ const result = await decomposeMetadataTypes({
41
+ metadataTypes,
42
+ prepurge,
43
+ postpurge,
44
+ format,
45
+ ignoreDirs,
46
+ strategy,
47
+ decomposeNestedPerms,
48
+ manifest,
49
+ overrides,
50
+ updateForceignore,
51
+ updateGitattributes,
52
+ log: (msg) => core.info(msg),
53
+ });
54
+ core.setOutput('metadata', result.metadata.join('\n'));
55
+ core.setOutput('types-count', result.metadata.length);
56
+ }
57
+ //# sourceMappingURL=decompose.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decompose.js","sourceRoot":"","sources":["../../src/action/decompose.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ 'use strict';
2
+ import { run } from './main.js';
3
+ void run();
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/action/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAEhC,KAAK,GAAG,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function multilineInput(name: string): string[] | undefined;
2
+ export declare function optionalInput(name: string): string | undefined;
3
+ export declare function requireMetadataTypesOrManifest(metadataTypes: string[] | undefined, manifest: string | undefined): void;
@@ -0,0 +1,19 @@
1
+ 'use strict';
2
+ import * as core from '@actions/core';
3
+ export function multilineInput(name) {
4
+ const values = core
5
+ .getMultilineInput(name)
6
+ .map((line) => line.trim())
7
+ .filter((line) => line.length > 0);
8
+ return values.length > 0 ? values : undefined;
9
+ }
10
+ export function optionalInput(name) {
11
+ const value = core.getInput(name);
12
+ return value === '' ? undefined : value;
13
+ }
14
+ export function requireMetadataTypesOrManifest(metadataTypes, manifest) {
15
+ if (!metadataTypes?.length && !manifest) {
16
+ throw new Error("Either the 'metadata-type' or 'manifest' input must be set, or 'config' must be true with a config file that specifies metadataSuffixes or manifest.");
17
+ }
18
+ }
19
+ //# sourceMappingURL=inputs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inputs.js","sourceRoot":"","sources":["../../src/action/inputs.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,KAAK,IAAI,MAAM,eAAe,CAAC;AAEtC,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,MAAM,GAAG,IAAI;SAChB,iBAAiB,CAAC,IAAI,CAAC;SACvB,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACrC,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAClC,OAAO,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,8BAA8B,CAC5C,aAAmC,EACnC,QAA4B;IAE5B,IAAI,CAAC,aAAa,EAAE,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CACb,sJAAsJ,CACvJ,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function run(): Promise<void>;
@@ -0,0 +1,26 @@
1
+ 'use strict';
2
+ import * as core from '@actions/core';
3
+ import { runDecompose } from './decompose.js';
4
+ import { runRecompose } from './recompose.js';
5
+ import { runVerify } from './verify.js';
6
+ export async function run() {
7
+ try {
8
+ const mode = core.getInput('mode', { required: true });
9
+ if (mode === 'decompose') {
10
+ await runDecompose();
11
+ }
12
+ else if (mode === 'recompose') {
13
+ await runRecompose();
14
+ }
15
+ else if (mode === 'verify') {
16
+ await runVerify();
17
+ }
18
+ else {
19
+ core.setFailed(`Invalid mode "${mode}". Expected "decompose", "recompose", or "verify".`);
20
+ }
21
+ }
22
+ catch (error) {
23
+ core.setFailed(error instanceof Error ? error.message : String(error));
24
+ }
25
+ }
26
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/action/main.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,KAAK,IAAI,MAAM,eAAe,CAAC;AAEtC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,MAAM,CAAC,KAAK,UAAU,GAAG;IACvB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAEvD,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;YACzB,MAAM,YAAY,EAAE,CAAC;QACvB,CAAC;aAAM,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;YAChC,MAAM,YAAY,EAAE,CAAC;QACvB,CAAC;aAAM,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7B,MAAM,SAAS,EAAE,CAAC;QACpB,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,SAAS,CAAC,iBAAiB,IAAI,oDAAoD,CAAC,CAAC;QAC5F,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,SAAS,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACzE,CAAC;AACH,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function runRecompose(): Promise<void>;
@@ -0,0 +1,36 @@
1
+ 'use strict';
2
+ import * as core from '@actions/core';
3
+ import { recomposeMetadataTypes } from '../core/recomposeMetadataTypes.js';
4
+ import { loadConfigFile, parseConfigSuffixes, resolveDefaultConfigPath, validateConfigManifest, } from '../helpers/configOverrides.js';
5
+ import { multilineInput, optionalInput, requireMetadataTypesOrManifest } from './inputs.js';
6
+ export async function runRecompose() {
7
+ let metadataTypes = multilineInput('metadata-type');
8
+ let manifest = optionalInput('manifest');
9
+ let ignoreDirs = multilineInput('ignore-package-directory');
10
+ let postpurge = core.getBooleanInput('postpurge');
11
+ if (core.getBooleanInput('config')) {
12
+ const config = await loadConfigFile(await resolveDefaultConfigPath());
13
+ metadataTypes ??= parseConfigSuffixes(config.metadataSuffixes);
14
+ const configManifest = !manifest ? config.manifest : undefined;
15
+ manifest ??= config.manifest;
16
+ ignoreDirs ??= parseConfigSuffixes(config.ignorePackageDirectories);
17
+ postpurge = postpurge || (config.postPurge ?? false);
18
+ manifest = await validateConfigManifest({
19
+ configManifest,
20
+ metadataTypes,
21
+ manifest,
22
+ warn: (msg) => core.warning(msg),
23
+ });
24
+ }
25
+ requireMetadataTypesOrManifest(metadataTypes, manifest);
26
+ const result = await recomposeMetadataTypes({
27
+ metadataTypes,
28
+ postpurge,
29
+ ignoreDirs,
30
+ manifest,
31
+ log: (msg) => core.info(msg),
32
+ });
33
+ core.setOutput('metadata', result.metadata.join('\n'));
34
+ core.setOutput('types-count', result.metadata.length);
35
+ }
36
+ //# sourceMappingURL=recompose.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recompose.js","sourceRoot":"","sources":["../../src/action/recompose.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,KAAK,IAAI,MAAM,eAAe,CAAC;AAEtC,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAC3E,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,8BAA8B,EAAE,MAAM,aAAa,CAAC;AAE5F,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,IAAI,aAAa,GAAG,cAAc,CAAC,eAAe,CAAC,CAAC;IACpD,IAAI,QAAQ,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;IACzC,IAAI,UAAU,GAAG,cAAc,CAAC,0BAA0B,CAAC,CAAC;IAC5D,IAAI,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC;IAElD,IAAI,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC;QACnC,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,wBAAwB,EAAE,CAAC,CAAC;QACtE,aAAa,KAAK,mBAAmB,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;QAC/D,MAAM,cAAc,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;QAC/D,QAAQ,KAAK,MAAM,CAAC,QAAQ,CAAC;QAC7B,UAAU,KAAK,mBAAmB,CAAC,MAAM,CAAC,wBAAwB,CAAC,CAAC;QACpE,SAAS,GAAG,SAAS,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,KAAK,CAAC,CAAC;QAErD,QAAQ,GAAG,MAAM,sBAAsB,CAAC;YACtC,cAAc;YACd,aAAa;YACb,QAAQ;YACR,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC;SACjC,CAAC,CAAC;IACL,CAAC;IAED,8BAA8B,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;IAExD,MAAM,MAAM,GAAG,MAAM,sBAAsB,CAAC;QAC1C,aAAa;QACb,SAAS;QACT,UAAU;QACV,QAAQ;QACR,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;KAC7B,CAAC,CAAC;IAEH,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACvD,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AACxD,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function runVerify(): Promise<void>;
@@ -0,0 +1,53 @@
1
+ 'use strict';
2
+ import * as core from '@actions/core';
3
+ import { verifyMetadataTypes } from '../core/verifyMetadataTypes.js';
4
+ import { loadConfigFile, parseConfigSuffixes, resolveDefaultConfigPath, validateConfigManifest, } from '../helpers/configOverrides.js';
5
+ import { multilineInput, optionalInput, requireMetadataTypesOrManifest } from './inputs.js';
6
+ export async function runVerify() {
7
+ let metadataTypes = multilineInput('metadata-type');
8
+ let manifest = optionalInput('manifest');
9
+ let ignoreDirs = multilineInput('ignore-package-directory');
10
+ let format = optionalInput('format') ?? 'xml';
11
+ let strategy = optionalInput('strategy') ?? 'unique-id';
12
+ let decomposeNestedPerms = core.getBooleanInput('decompose-nested-permissions');
13
+ let overrides;
14
+ if (core.getBooleanInput('config')) {
15
+ const config = await loadConfigFile(await resolveDefaultConfigPath());
16
+ metadataTypes ??= parseConfigSuffixes(config.metadataSuffixes);
17
+ const configManifest = !manifest ? config.manifest : undefined;
18
+ manifest ??= config.manifest;
19
+ ignoreDirs ??= parseConfigSuffixes(config.ignorePackageDirectories);
20
+ format = optionalInput('format') ?? config.decomposedFormat ?? 'xml';
21
+ strategy = optionalInput('strategy') ?? config.strategy ?? 'unique-id';
22
+ decomposeNestedPerms = decomposeNestedPerms || (config.decomposeNestedPermissions ?? false);
23
+ overrides = config.overrides;
24
+ manifest = await validateConfigManifest({
25
+ configManifest,
26
+ metadataTypes,
27
+ manifest,
28
+ warn: (msg) => core.warning(msg),
29
+ });
30
+ }
31
+ requireMetadataTypesOrManifest(metadataTypes, manifest);
32
+ const result = await verifyMetadataTypes({
33
+ metadataTypes,
34
+ format,
35
+ ignoreDirs,
36
+ strategy,
37
+ decomposeNestedPerms,
38
+ manifest,
39
+ overrides,
40
+ log: (msg) => core.info(msg),
41
+ });
42
+ core.setOutput('metadata', result.metadata.join('\n'));
43
+ core.setOutput('types-count', result.metadata.length);
44
+ core.setOutput('drift-count', result.drift.length);
45
+ core.setOutput('reordered-count', result.reordered.length);
46
+ if (result.drift.length > 0) {
47
+ for (const { path, reason } of result.drift) {
48
+ core.error(`${path}: ${reason}`);
49
+ }
50
+ core.setFailed(`Round-trip verify failed: ${result.drift.length} file(s) drifted between the original tree and the round-tripped output. See the log above for the offending paths.`);
51
+ }
52
+ }
53
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/action/verify.ts"],"names":[],"mappings":"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"}
@@ -364,5 +364,5 @@
364
364
  ]
365
365
  }
366
366
  },
367
- "version": "7.2.0"
367
+ "version": "7.3.0"
368
368
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sf-decomposer",
3
3
  "description": "Decompose Salesforce metadata into granular, VCS-friendly files; recompose for deployment.",
4
- "version": "7.2.0",
4
+ "version": "7.3.0",
5
5
  "dependencies": {
6
6
  "@oclif/core": "4.13.5",
7
7
  "@salesforce/core": "9.1.2",
@@ -9,6 +9,7 @@
9
9
  "config-disassembler": "3.3.0"
10
10
  },
11
11
  "devDependencies": {
12
+ "@actions/core": "3.0.1",
12
13
  "@biomejs/biome": "2.5.9",
13
14
  "@commitlint/cli": "21.2.2",
14
15
  "@commitlint/config-conventional": "21.2.2",