diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..5be1e84 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,2 @@ +# oclif message files use parser-specific Markdown; preserve command examples. +messages/** diff --git a/.sfdevrc.json b/.sfdevrc.json index 66121e1..87e01b2 100644 --- a/.sfdevrc.json +++ b/.sfdevrc.json @@ -5,6 +5,31 @@ "wireit": { "test": { "dependencies": ["test:compile", "test:only", "lint"] + }, + "test:only": { + "command": "nyc mocha \"test/**/*.test.ts\"", + "env": { + "FORCE_COLOR": "2" + }, + "files": [ + "test/**/*.ts", + "test/**/*.mjs", + "src/**/*.ts", + "**/tsconfig.json", + ".mocha*", + "!*.nut.ts", + ".nycrc", + "package.json", + "yarn.lock" + ], + "output": [], + "dependencies": ["compile"] + }, + "compile": { + "command": "tsc -p . --pretty --incremental", + "files": ["src/**/*.ts", "**/tsconfig.json", "messages/**", "package.json", "yarn.lock"], + "output": ["lib/**", "*.tsbuildinfo"], + "clean": "if-file-deleted" } } } diff --git a/FLOW_DEPENDENCIES.md b/FLOW_DEPENDENCIES.md new file mode 100644 index 0000000..bfccc3f --- /dev/null +++ b/FLOW_DEPENDENCIES.md @@ -0,0 +1,21 @@ +# Flow dependency analysis + +`flow dependencies` reads direct relationships for a selected Flow and an explicit scan scope. Run it from the plugin-flow checkout after compiling: + +```bash +node bin/run.js flow dependencies \ + --target-org my-org \ + --flow-name Account_Onboarding \ + --scan-flow FirstCaller \ + --scan-flow SecondCaller +``` + +Names, definition IDs and version IDs are resolved from the authenticated org. `--scan-flow` is optional and repeatable; it selects candidate caller Flows whose metadata will be inspected. It does not request an automatic org-wide scan. The root and explicit caller list are capped at 20 Flow definitions. + +The command reads selected Flow metadata and queries the dependency API for incoming/outgoing records. API-reported Apex callers can be displayed without supplying an Apex class name. A relationship to a Flow definition does not establish a dependency on a particular inactive version and is not a deletion assessment. + +Use `--version-policy latest` (the default) or `--version-policy active`. Active requires an active version for every explicitly selected Flow and does not silently fall back. Flow names are DeveloperName values; `--namespace` applies to the root and explicit scan Flows. + +Console output includes the root identity and incoming/outgoing evidence. `--json` also returns scan scope, provider status and coverage warnings. Empty or limited dependency-API results do not prove that no relationship exists. + +This command is read-only. Its supported scope is direct relationships: no recursive traversal, complete caller enumeration, Apex source parser, arbitrary runtime reference discovery, manifest generation or delete eligibility is claimed. Use version-management assessment for normal-delete eligibility. diff --git a/FLOW_VERSION_MANAGEMENT.md b/FLOW_VERSION_MANAGEMENT.md new file mode 100644 index 0000000..41f7f34 --- /dev/null +++ b/FLOW_VERSION_MANAGEMENT.md @@ -0,0 +1,102 @@ +# Flow version management + +Run these commands from the plugin-flow checkout after installing dependencies and compiling the plugin. Build and link the Flow Node library using the repository development setup first. The commands use the existing Salesforce CLI org authorization and accept any authenticated org alias and Flow API name. + +## Backend compatibility + +Version management requires API 67.0 or later and these authenticated server operations: + +| Command path | Required operation | +| -------------------------- | -------------------------------------------------------------- | +| List and retention catalog | `POST /connect/interaction/flow-versions/list` | +| Normal deletion preview | `POST /connect/interaction/flow-versions/deletion-assessment` | +| Normal deletion | `DELETE /tooling/sobjects/Flow/{versionId}` | +| Force preview | `POST /connect/interaction/flow-versions/force-delete/preview` | +| Force execution | `POST /connect/interaction/flow-versions/force-delete` | + +The API version prefix is selected from the authenticated Connection. Availability of the CLI package does not establish that these server operations are installed in an org. Authentication, request failures and malformed responses are reported as errors; the client does not substitute inferred eligibility or counts. + +The production integration delegates inventory, eligibility and retention selection to shared B services, and force deletion to the D API. Those service bindings are still being finalized. The currently supported wire contracts and interim retention behavior below remain explicit until that integration is available. + +## List versions + +Choose exactly one scope: `--flow ` or `--all`. Use a qualified API name for a namespaced Flow. + +```bash +node bin/run.js flow version list --target-org my-org --api-version 67.0 --flow Account_Onboarding +node bin/run.js flow version list --target-org my-org --api-version 67.0 --all --json +node bin/run.js flow version list --target-org my-org --all --status Obsolete --older-than 90d --min-percent 80 --deletable +``` + +The server supplies version metadata, actual org version limit, counts and normal deletion eligibility. The client follows pagination and retains completeness information. Null values remain unavailable; they are never replaced by zero. `PASS` displays Yes, `BLOCKED` displays No with its reason, and `ERROR` means the row was not fully assessed. + +The current list contract derives age from Created Date. Production B1 specifies Last Modified Date. The backend and client must adopt the same age basis when the shared B1 contract is bound; the client does not silently reinterpret server age values. + +## Preview and delete explicit versions + +Version lists and inclusive ranges are supported, with up to 200 distinct numbers. Selection is resolved to exact definition/version identities; Active or latest versions are never substituted for missing numbers. + +```bash +node bin/run.js flow version delete \ + --target-org my-org \ + --api-version 67.0 \ + --flow Account_Onboarding \ + --versions 1,2,4-6 \ + --dry-run +``` + +The same command works on one line. Existing bare value syntax is also accepted; Boolean options retain their dashes: + +```bash +node bin/run.js flow version delete target-org my-org flow Account_Onboarding versions 1,2,4-6 --dry-run +``` + +Omit `--dry-run` to display the assessed plan and request confirmation. The default is No; timeout or cancellation closes the prompt without deleting. Explicit `--yes` is required for normal noninteractive or JSON execution. + +Every exact target is rechecked after confirmation. A blocked or known-failed version does not prevent eligible siblings from being processed. Normal deletion does not abandon interviews or remove references. A lost or inconclusive mutation response remains `UNKNOWN` and stops subsequent mutations; it is not automatically retried. + +The client currently preserves the last remaining version with a separately labeled client policy. This is not a claimed server restriction. The product decision about deleting the empty definition remains open; managed-package restrictions remain server-owned. + +## Retention cleanup + +Preview is the default: + +```bash +node bin/run.js flow version prune --target-org my-org --flow Account_Onboarding --keep-latest 5 --older-than 90d +node bin/run.js flow version prune --target-org my-org --all --keep-latest 5 --older-than 90d --dry-run --json +``` + +`--execute` requests interactive confirmation. `--yes` is the explicit noninteractive execution option. Both are mutually exclusive with `--dry-run`. Force deletion is never used by retention cleanup. + +The current client reads the complete unfiltered catalog, keeps Active and the latest N, and adds an interim rollback safeguard based on the newest Obsolete `statusChangeDate`. It keeps all newest ties, or all Obsolete versions when their timestamps are all null. Packaging can change that timestamp, so it is not proof of previous activation. Missing required metadata or an incomplete catalog prevents selection. + +Only remaining inactive versions old enough according to server `ageDays` and marked `PASS`/deletable become candidates. Fresh identity, eligibility and retention checks precede each deletion; confirmation cannot add or substitute targets. + +Production B1 protects Active and the latest N and uses Last Modified Date. Shared candidate selection will replace the interim client rule after its request/response contract is agreed. The current command does not claim B1 parity. + +## Force-delete one version + +Force deletion is manual, requires interactive terminals and accepts exactly one positive version number. It uses dedicated preview/execute operations; no force flag is added to Tooling DELETE. + +```bash +node bin/run.js flow version delete --target-org my-org --flow Account_Onboarding --versions 2 --force --dry-run +node bin/run.js flow version delete --target-org my-org --flow Account_Onboarding --versions 2 --force +``` + +The CLI displays actual server impact and eligibility, then requires the exact Flow API name and version number. `--yes` cannot approve force execution. Tokens and typed answers are omitted from reports, console output and JSON. Force execution with JSON still requires interactive input/output and sends human prompts to stderr. + +Force execution requires a backend that enforces the opt-in Force Delete Flow Versions permission, org-level disable, impact-bound token authorization, interview/registration cleanup, orchestration handling and audit. These are server responsibilities. Unsupported impact data remains unavailable, and an ineligible preview never executes. Backend production readiness must be established independently of client tests. + +## Reports and scripting + +JSON schemas are checked in under `schemas/flow-version-{list,delete,prune,force-delete}.json`. Normal deletion uses report contract 2; list, retention and force reports use contract 1. Reports preserve exact identities, backend reasons and confirmed versus uncertain mutation outcomes. + +| Result | Exit | +| ------------------------------------------------------- | ---- | +| Completed preview, cancellation, or successful deletion | 0 | +| Deletion blocked without another failure | 1 | +| Failed, unassessed, uncertain, or unattempted execution | 2 | + +List exits 1 for truncation or an assessment error, and 0 for a complete result that may include blocked rows. Invalid input, authentication and whole-request failures return command errors. The product wording about failed dry-run requests remains open; a completed preview retains its per-version blockers/errors and exits 0. + +Client tests use isolated providers, native Connection mocks and terminal fixtures. They do not establish live server authorization, audit, abandonment or rollback behavior. diff --git a/README.md b/README.md index 24efabf..cc92901 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Salesforce Flow Test Plugin +# Salesforce Flow CLI Plugin ![npm (scoped)](https://img.shields.io/npm/v/@salesforce/plugin-flow) [![License](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](https://opensource.org/license/apache-2-0) @@ -6,7 +6,9 @@ ## Introduction -This is an oclif plugin that supports the Salesforce Flow Test commands. +This oclif plugin provides Salesforce Flow test commands, dependency analysis, and version management. Flow tests use `@salesforce/apex-node`; version-management commands use `@salesforce/flow-node` from the [flows repository](https://github.com/forcedotcom/flows). + +See [Flow version management](FLOW_VERSION_MANAGEMENT.md) and [Flow dependency analysis](FLOW_DEPENDENCIES.md) for command examples and backend compatibility. ### Building the Plugin @@ -43,6 +45,25 @@ $ bin/dev.js flow run test -o myOrg@example.com
+### Developing with Flow Node + +Clone `forcedotcom/flows` beside this checkout. The development dependency is pinned to a Flow Node Git commit until its first npm release and requires access to the private `forcedotcom/flows` repository. A public plugin release must first use a published Flow Node npm version. To use your local library while developing: + +```bash +cd ../flows +yarn install --frozen-lockfile +yarn build +yarn link --link-folder .yarn-links + +cd ../plugin-flow +yarn install --frozen-lockfile +yarn link --link-folder ../flows/.yarn-links @salesforce/flow-node +yarn compile +node bin/run.js flow version list --help +``` + +Rebuild Flow Node after library changes. The local link uses the same public package entry point as the installed dependency. If Yarn is not on your PATH, use `corepack yarn`. + ### Running the Test Suite Test the test suite locally by building the project first and then running the tests. @@ -58,8 +79,77 @@ $ yarn test +- [`sf flow dependencies`](#sf-flow-dependencies) - [`sf flow get test`](#sf-flow-get-test) - [`sf flow run test`](#sf-flow-run-test) +- [`sf flow version delete`](#sf-flow-version-delete) +- [`sf flow version list`](#sf-flow-version-list) +- [`sf flow version prune`](#sf-flow-version-prune) + +## `sf flow dependencies` + +Inspect direct Flow dependencies and references in a target org. + +``` +USAGE + $ sf flow dependencies -o -f [--json] [--flags-dir ] [--api-version ] [--namespace + ] [--scan-flow ...] [--version-policy latest|active] + +FLAGS + -f, --flow-name= (required) API DeveloperName of the root Flow (without a namespace prefix). + -o, --target-org= (required) Username or alias of the target org. Not required if the `target-org` + configuration variable is already set. + --api-version= Override the api version used for api requests made by this command + --namespace= Namespace of the root and scanned Flows; omit for unmanaged Flows. + --scan-flow=... Additional caller Flow DeveloperName to inspect; repeat for more Flows (20 total + including the root). + --version-policy=