Skip to main content

validate-app

Run comprehensive pre-submission validation on commerce app packages. Use IMMEDIATELY when users mention "validate", "check", "verify", or "ready to submit". REQUIRED before calling submit-app - trigger proactively to catch errors early. Validates directory structure, manifest format, SHA256 hashes, impex XML, security issues, and runs complete CONTRIBUTING.md checklist. Also use when debugging validation failures or import errors to identify root cause quickly.

Datos de origen

Repositorio
SalesforceCommerceCloud/commerce-apps
Última actividad en el origen
9 de septiembre de 2026 a las 22:39
Idioma detectado de SKILL.md
inglés
Estrellas
12
Forks
9

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Explorador de archivos
5 archivos

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
validate-app
description
Run comprehensive pre-submission validation on commerce app packages. Use IMMEDIATELY when users mention "validate", "check", "verify", or "ready to submit". REQUIRED before calling submit-app - trigger proactively to catch errors early. Validates directory structure, manifest format, SHA256 hashes, impex XML, security issues, and runs complete CONTRIBUTING.md checklist. Also use when debugging validation failures or import errors to identify root cause quickly.
# Validate Commerce App Package Run comprehensive validation checks on a commerce app before submitting a PR. > **Cross-tool note:** References to `/skill-name` (e.g., `/submit-app`) are Claude Code invocation syntax. If using another assistant, read and follow the corresponding `.claude/skills/<skill-name>/SKILL.md` file instead. ## Step 1: Identify app and resolve input Gather: - Domain (e.g., `tax`, `payment`, `shipping`) - App name (e.g., `avalara-tax`) - Version (or use latest ZIP) **Structure:** Apps must be at `{domain}/{appName}/` where `{appName}` matches the "id" field. See `references/folder-structure.md`. The skill accepts **either** a packaged `.zip` **or** an already-extracted CAP root directory (e.g., `commerce-<appName>-app-v<version>/`). Set both variables once; later steps branch on `INPUT_KIND`: ```bash # Resolve the input: a .zip path OR an extracted CAP root directory. INPUT="<path-to-zip-or-extracted-cap-root>" if [[ -f "$INPUT" && "$INPUT" == *.zip ]]; then INPUT_KIND=zip ZIP="$INPUT" EXTRACT_DIR="$(mktemp -d)" unzip -q "$ZIP" -d "$EXTRACT_DIR" CAP_ROOT="$EXTRACT_DIR/commerce-<appName>-app-v<version>" elif [[ -d "$INPUT" ]]; then INPUT_KIND=dir CAP_ROOT="$INPUT" ZIP="" # no zip available — Step 3 will be skipped EXTRACT_DIR="" # nothing to clean up in Step 14 else echo "Input must be a .zip file or extracted CAP root directory" >&2; exit 2 fi ``` ## Step 2: Verify input exists ```bash if [[ "$INPUT_KIND" == "zip" ]]; then ls -lh "$ZIP"; else ls -ld "$CAP_ROOT"; fi ``` ## Step 3: Validate SHA256 **Skip if `INPUT_KIND=dir`** — the manifest pins a hash of the `.zip` artifact, which can't be reproduced from extracted files. Note this gap in the report and re-run Step 3 once the ZIP is built. ```bash if [[ "$INPUT_KIND" == "zip" ]]; then shasum -a 256 "$ZIP" jq '[.[] | select(type=="array")] | flatten | .[] | select(.id == "<appName>") | .sha256' \ commerce-apps-manifest/manifest.json else echo "(skipped — no ZIP available; SHA256 must be re-checked against the built ZIP)" fi ``` Hashes must match exactly. ## Step 4: Validate manifest entry Check `commerce-apps-manifest/manifest.json` has all required fields: - `id` - matches app name - `name` - display name - `description` - `iconName` - matches icon in ZIP `icons/` directory - `domain` - valid domain (hyphen-case) - `type` - must be `"app"` - `provider` - must be `"thirdParty"` - `version` - semantic versioning - `zip` - matches actual filename - `sha256` - matches computed hash Optional fields (validate if present): - `storefrontSupport.sfnext.minVersion` - valid semver (`X.Y.Z` or `X.Y.Z-prerelease`) - `storefrontSupport.sfnext.maxVersion` - valid semver, optional (`X.Y.Z` or `X.Y.Z-prerelease`) - `storefrontSupport.sfra.minVersion` - valid semver (`X.Y.Z` or `X.Y.Z-prerelease`) - `storefrontSupport.sfra.maxVersion` - valid semver, optional (`X.Y.Z` or `X.Y.Z-prerelease`) - Only `sfnext` and `sfra` keys allowed inside `storefrontSupport`; only `minVersion` and `maxVersion` allowed inside each - If `storefrontSupport.sfra` is present, `storefrontSupport.sfnext` must also be present (with a valid `minVersion`). Fail validation on SFRA-only declarations. - `storefrontSupport` must be present in **both** the root manifest and `commerce-app.json` with matching values ## Step 5: Validate package contents ```bash if [[ "$INPUT_KIND" == "zip" ]]; then unzip -l "$ZIP" | head -30 unzip -l "$ZIP" | grep -E "\.DS_Store|__MACOSX" || echo " ✓ no junk files" else ls -la "$CAP_ROOT" | head -30 find "$CAP_ROOT" \( -name '.DS_Store' -o -name '__MACOSX' \) -print | head \ || echo " ✓ no junk files" fi # Required files (works for both inputs) for f in commerce-app.json README.md app-configuration/tasksList.json; do [[ -e "$CAP_ROOT/$f" ]] && echo " ✓ $f" || echo " ✗ MISSING: $f" done ``` Check: - Single root: `commerce-<appName>-app-v<version>/` (ZIP only — for `INPUT_KIND=dir`, the directory IS the root) - No junk hidden files (`.DS_Store`, `__MACOSX`, `.env`, secrets) — **except** `.project`, which every cartridge root MUST include (see Step 6b) - No registry paths (`tax/`, `domain/`) at the ZIP root (ZIP only) - Required: `commerce-app.json`, `README.md`, `app-configuration/tasksList.json` ## Step 6: Detect architecture ```bash HAS_UI=$([[ -d "$CAP_ROOT/storefront-next" ]] && echo 1 || echo 0) HAS_BACKEND=$([[ -d "$CAP_ROOT/cartridges" ]] && echo 1 || echo 0) ``` Determine: - **UI-only:** Has `storefront-next/`, NO `cartridges/` - **Backend-only:** Has `cartridges/`, NO `storefront-next/` - **Fullstack:** Has both ## Step 6b: Validate cartridge `.project` files (Backend-only/Fullstack) **Skip if UI-only** (`HAS_BACKEND=0`). Every immediate child directory of `cartridges/site_cartridges/` and `cartridges/bm_cartridges/` must contain a `.project` file. It may be empty (auto-created by scaffolding/packaging) or a real, non-empty Eclipse `.project` file — both PASS. Missing is a FAIL. ```bash bash .github/scripts/validate-cartridge-project.sh "$CAP_ROOT" ``` ## Step 7: Validate commerce-app.json ```bash jq . "$CAP_ROOT/commerce-app.json" ``` Required fields: - `id`, `name`, `description`, `domain`, `version` - `publisher.name`, `publisher.url`, `publisher.support` Version must match root manifest version. Optional fields (validate if present): - `storefrontSupport.sfnext.minVersion` - valid semver (`X.Y.Z` or `X.Y.Z-prerelease`) - `storefrontSupport.sfnext.maxVersion` - valid semver, optional (`X.Y.Z` or `X.Y.Z-prerelease`) - `storefrontSupport.sfra.minVersion` - valid semver (`X.Y.Z` or `X.Y.Z-prerelease`) - `storefrontSupport.sfra.maxVersion` - valid semver, optional (`X.Y.Z` or `X.Y.Z-prerelease`) - If `storefrontSupport.sfra` is present, `storefrontSupport.sfnext` must also be present (with a valid `minVersion`). Fail validation on SFRA-only declarations. - Values must match the corresponding fields in the root manifest entry ## Step 8: Validate storefront files (UI-only/Fullstack) **Skip if Backend-only.** Required: - `storefront-next/src/extensions/<appName>/target-config.json` — entry point; declares `components[]`, `actionHooks[]`, etc., each pointing at a `path` under the extension directory. For each entry referenced from `target-config.json`, verify the file exists: ```bash TC="$CAP_ROOT/storefront-next/src/extensions/<appName>/target-config.json" jq -r '[.components[]?.path, .actionHooks[]?.handler, .routes[]?.handler] | .[] | select(.)' "$TC" \ | while read -r p; do [[ -f "$CAP_ROOT/storefront-next/src/$p" ]] \ && echo " ✓ $p" \ || echo " ✗ MISSING: $p" done ``` If the extension ships translations, they live under `storefront-next/src/extensions/<appName>/locales/<locale>/translations.json`. Locale set is app-specific — not a fixed allowlist. ## Step 9: Validate impex (Backend-only/Fullstack) **Skip if UI-only.** ```bash find "$CAP_ROOT/impex/" -name "*.xml" -exec xmllint --noout {} \; ``` See `references/impex-validation.md` for detailed rules: - Services use dotted notation - Install/uninstall pairs match - Uninstall `services.xml` uses credential → profile → service order with `mode="delete"` (same XSD sequence as install; BM UI service-first delete does not apply to IMPEX) - Attribute IDs use camelCase with app prefix - SITEID placeholder (not actual site ID) - No hardcoded credentials ## Step 10: Verify catalog.json - **Existing app:** catalog.json exists, unchanged in PR - **New app:** catalog.json has INIT values: ```json { "latest": {"version": "INIT", "tag": "INIT"}, "versions": [] } ``` ## Step 10b: Validate app-configuration/ JSON via CI scripts Run the same scripts CI runs against `$CAP_ROOT` (already set in Step 1). Each is the source of truth for its schema; scripts print errors to stderr and exit non-zero on failure. ```bash # tasksList.json schema (required file) bash .github/scripts/validate-tasks-list.sh "$CAP_ROOT/app-configuration/tasksList.json" # adminComponents.json schema (optional file) [[ -f "$CAP_ROOT/app-configuration/adminComponents.json" ]] && \ bash .github/scripts/validate-admin-components.sh "$CAP_ROOT/app-configuration/adminComponents.json" # app-shipped translations (optional directory; cross-references the two files above) bash .github/scripts/validate-translations.sh "$CAP_ROOT" ``` Each script prints schema details and exits non-zero with errors on stderr. See the script header comments for the schema contract. ## Step 11: Validate manifest-level translations The CAP-internal translations live under `app-configuration/translations/` (validated in Step 10b). The **manifest-level** `commerce-apps-manifest/translations/en-US.json` holds the marketplace `name` / `description` shown on the app card: ```bash jq '."<appName>"' commerce-apps-manifest/translations/en-US.json ``` Check: - Entry exists in `en-US.json` (minimum) - Has `name` and `description` fields - Valid JSON structure ## Step 12: Validate icon ```bash ICON_NAME=$(jq -r '[.[] | select(type=="array")] | flatten | .[] | select(.id == "<appName>") | .iconName' \ commerce-apps-manifest/manifest.json) [[ -f "$CAP_ROOT/icons/$ICON_NAME" ]] && echo " ✓ icon in package" || echo " - not in package" [[ -f "commerce-apps-manifest/icons/$ICON_NAME" ]] && echo " ✓ icon in registry" || echo " ✗ MISSING in registry" ``` Icon filename must match `iconName` field exactly. CI extracts automatically. ## Step 13: Security scan ```bash bash .github/scripts/security-scan.sh "$CAP_ROOT/" ``` **If blocking findings (exit 1):** FAIL - fix issues first. **If warnings only:** Continue with warnings for review. See `references/security-scan.md` for details. ## Step 14: Clean up Only remove the temp dir if Step 1 created one (`INPUT_KIND=zip`). When the user passed an extracted CAP root, leave it alone. ```bash [[ -n "$EXTRACT_DIR" ]] && rm -rf "$EXTRACT_DIR" ``` ## Report results - **✅ PASS** - All validations passed, ready for `/submit-app` - **❌ FAIL** - List specific issues with file paths and line numbers Provide fix recommendations for each issue.
Ver en GitHub