Skip to content

Commit 1b02378

Browse files
committed
feat: initial version
1 parent e9dc10f commit 1b02378

27 files changed

+17062
-0
lines changed

.editorconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
root = true
2+
3+
[*]
4+
indent_style = space
5+
indent_size = 2
6+
charset = utf-8
7+
trim_trailing_whitespace = true
8+
insert_final_newline = true
9+
10+
[*.md]
11+
trim_trailing_whitespace = false

.github/workflows/test.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
name: Test and Release
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
workflow_dispatch:
11+
12+
jobs:
13+
test:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@v5
17+
- uses: actions/setup-node@v5
18+
with:
19+
node-version-file: .node-version
20+
- name: Install dependencies
21+
run: npm ci
22+
- name: Run tests
23+
run: npm run test
24+
release:
25+
needs: test
26+
if: ${{ github.ref == 'refs/heads/main' }}
27+
runs-on: ubuntu-latest
28+
steps:
29+
- uses: actions/checkout@v5
30+
- uses: actions/setup-node@v5
31+
with:
32+
node-version-file: .node-version
33+
- name: Install dependencies
34+
run: npm ci
35+
- name: Release package
36+
run: npx semantic-release
37+
env:
38+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
39+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

.gitignore

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Node.js
2+
/node_modules/
3+
4+
# TypeScript
5+
/lib/
6+
7+
# Testing
8+
/.nyc_output/
9+
/coverage/
10+
11+
# oclif
12+
/oclif.manifest.json
13+
14+
# Salesforce DX
15+
/.sfdx/
16+
/.sf/
17+
18+
/data/*.json

.node-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
24

CLAUDE.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Development Commands
6+
7+
```bash
8+
# Build the plugin and generate OCLIF manifest
9+
npm run build
10+
11+
# Run tests with TypeScript compilation and coverage
12+
npm run test
13+
14+
# Development usage (run plugin without installing)
15+
./bin/dev.js metadata-coverage check -h
16+
17+
# Link plugin for development with Salesforce CLI
18+
sf plugins link
19+
```
20+
21+
## Architecture
22+
23+
This is a Salesforce CLI plugin built with OCLIF that checks metadata coverage reports for Salesforce projects.
24+
25+
### Core Components
26+
27+
- **Main Command**: `src/commands/metadata-coverage/check.ts` - Primary command implementation that:
28+
- Accepts source directories, manifests, or metadata types as input
29+
- Downloads or loads cached metadata coverage reports by API version
30+
- Uses ComponentSetBuilder from `@salesforce/source-deploy-retrieve` to analyze metadata
31+
- Validates metadata types against various packaging channels (1GP, 2GP, etc.)
32+
33+
### Key Architecture Patterns
34+
35+
- **OCLIF Framework**: Extends `SfCommand` from `@salesforce/sf-plugins-core`
36+
- **Component Analysis**: Uses Salesforce's `ComponentSetBuilder` to parse metadata from source directories or manifests
37+
- **Channel Validation**: Supports validation against multiple Salesforce channels:
38+
- Classic Packaging (1GP managed/unmanaged)
39+
- Second Generation Packaging (2GP managed/unlocked)
40+
- API channels (Metadata API, Tooling API, Apex Metadata API)
41+
- Other deployment methods and tooling (changesets, source tracking)
42+
43+
### Data Flow
44+
45+
1. Parse command flags to determine metadata source and target channels
46+
2. Load/download metadata coverage report for specified API version from `data/report-{version}.json`
47+
3. Build ComponentSet from source directories, manifest, or metadata names
48+
4. Iterate through metadata types and validate against coverage report
49+
5. Output unsupported types in table format or JSON
50+
51+
### Special Metadata Handling
52+
53+
- **Settings**: Converts generic "Settings" type to specific "{Type}Settings" format
54+
- **CustomLabel**: Maps to "CustomLabels" in coverage report
55+
- **MatchingRule**: Maps to "MatchingRules" in coverage report
56+
57+
## Project Structure
58+
59+
- `src/commands/` - OCLIF command implementations
60+
- `data/` - Cached metadata coverage reports by API version
61+
- `test/` - Mocha/Chai test files
62+
- `lib/` - Compiled JavaScript output (generated by build)
63+
- `bin/` - Executable scripts for development and production

README.md

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
# sf-plugin-metadata-coverage
2+
3+
> sf plugin to check the metadata coverage report for the given source
4+
5+
[Metadata Coverage Report](https://developer.salesforce.com/docs/success/metadata-coverage-report/references/coverage-report/metadata-coverage-report.html)
6+
7+
## Installation
8+
9+
```shell
10+
sf plugins install sf-plugin-metadata-coverage
11+
```
12+
13+
## Usage
14+
15+
```sh-session
16+
$ sf metadata-coverage check --source-dir force-app --2gp-unlocked
17+
Checking 38 metadata type for unlockedPackagingWithoutNamespace using API version 64.0.
18+
All metadata types are supported.
19+
```
20+
21+
The command prints metadata types that are not supported and exits with an error code.
22+
23+
```sh-session
24+
$ sf metadata-coverage check --source-dir force-app --2gp-managed
25+
Checking 38 metadata types for managedPackaging using API version 64.0.
26+
=== Unsupported Metadata Types
27+
28+
┌───────────────────────┬───────────────────┬───────────────────────┐
29+
│ Type │ Managed Packaging │ Members │
30+
├───────────────────────┼───────────────────┼───────────────────────┤
31+
│ CustomHelpMenuSection │ false │ CustomHelpMenuSection │
32+
└───────────────────────┴───────────────────┴───────────────────────┘
33+
34+
Error (2): Some metadata types are not supported.
35+
```
36+
37+
<!-- commands -->
38+
* [`sf metadata-coverage check`](#sf-metadata-coverage-check)
39+
* [`sf metadata-coverage download`](#sf-metadata-coverage-download)
40+
41+
## `sf metadata-coverage check`
42+
43+
Check the Metadata Coverage for the given source directory, metadata type or package.xml.
44+
45+
```
46+
USAGE
47+
$ sf metadata-coverage check [--json] [--flags-dir <value>] [--api-version <value>] [-d <value>...] [-x <value>] [-m
48+
<value>...] [--1gp-managed] [--1gp-unmanaged] [--2gp-managed] [--2gp-unlocked] [--2gp-unlocked-with-namespace]
49+
[--source-tracking] [--tooling-api] [--metadata-api] [--apex-metadata-api] [--changesets]
50+
51+
FLAGS
52+
--api-version=<value> The API version of the Metadata Coverage Report to use.
53+
54+
SOURCES FLAGS
55+
-d, --source-dir=<value>... File paths for source to check.
56+
-m, --metadata=<value>... Metadata component names to check.
57+
-x, --manifest=<value> File path for the manifest (package.xml) that specifies the components to check.
58+
59+
METADATA COVERAGE CHANNELS FLAGS
60+
--1gp-managed
61+
--1gp-unmanaged
62+
--2gp-managed
63+
--2gp-unlocked
64+
--2gp-unlocked-with-namespace
65+
--apex-metadata-api
66+
--changesets
67+
--metadata-api
68+
--source-tracking
69+
--tooling-api
70+
71+
GLOBAL FLAGS
72+
--flags-dir=<value> Import flag values from a directory.
73+
--json Format output as json.
74+
75+
EXAMPLES
76+
$ sf metadata-coverage check --source-dir force-app --2gp-unlocked
77+
78+
$ sf metadata-coverage check --manifest src/package.xml --1gp-managed
79+
80+
$ sf metadata-coverage check --metadata CustomHelpMenuSection --2gp-unlocked
81+
82+
$ sf metadata-coverage check --metadata CustomHelpMenuSection --2gp-unlocked --2gp-managed
83+
84+
$ sf metadata-coverage check --metadata CustomHelpMenuSection --2gp-managed --api-version 65.0
85+
```
86+
87+
_See code: [lib/commands/metadata-coverage/check.js](https://github.com/amtrack/sf-plugin-metadata-coverage/blob/main/lib/commands/metadata-coverage/check.js)_
88+
89+
## `sf metadata-coverage download`
90+
91+
Explicitly download a Metadata Coverage Report.
92+
93+
```
94+
USAGE
95+
$ sf metadata-coverage download [--json] [--flags-dir <value>] [--api-version <value>]
96+
97+
FLAGS
98+
--api-version=<value> The API version of the Metadata Coverage Report to use.
99+
100+
GLOBAL FLAGS
101+
--flags-dir=<value> Import flag values from a directory.
102+
--json Format output as json.
103+
104+
DESCRIPTION
105+
Explicitly download a Metadata Coverage Report.
106+
107+
By default it downloads the Metadata Coverage Report for the version of the sfdx-project.json > sourceApiVersion.
108+
109+
EXAMPLES
110+
$ sf metadata-coverage download
111+
112+
$ sf metadata-coverage download --api-version 65.0
113+
```
114+
115+
_See code: [lib/commands/metadata-coverage/download.js](https://github.com/amtrack/sf-plugin-metadata-coverage/blob/main/lib/commands/metadata-coverage/download.js)_
116+
<!-- commandsstop -->
117+
118+
### Example Use Cases
119+
120+
Is the Metadata Type "CustomHelpMenuSection" supported for a 2GP Managed Package?
121+
122+
```shell
123+
sf metadata-coverage check -m CustomHelpMenuSection --2gp-managed
124+
```
125+
126+
... or maybe in the upcoming release?
127+
128+
```shell
129+
sf metadata-coverage check -m CustomHelpMenuSection --2gp-managed --api-version 65.0
130+
```
131+
132+
Can I create an Unlocked Package from my source directory?
133+
134+
```shell
135+
sf metadata-coverage check --source-dir force-app --2gp-unlocked
136+
```
137+
138+
Can I convert my 1GP Managed Package to a 2GP Managed Package?
139+
140+
```shell
141+
sf project retrieve start --package-name MyPkg --target-metadata-dir src --unzip --target-org my-pkg-org
142+
sf metadata-coverage check --manifest src/unpackaged/package.xml --2gp-managed
143+
```
144+
145+
## Development
146+
147+
After cloning this repository, install the dependencies:
148+
149+
```shell
150+
npm ci
151+
```
152+
153+
Use `bin/dev.js` to run the plugin while development
154+
155+
```shell
156+
./bin/dev.js metadata-coverage check -h
157+
```
158+
159+
or link it with sfdx
160+
161+
```shell
162+
sf plugins link
163+
sf which metadata-coverage check
164+
sf metadata-coverage check -h
165+
```
166+
167+
## Testing
168+
169+
```shell
170+
npm run test
171+
```

bin/dev.cmd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@echo off
2+
3+
node "%~dp0\dev" %*

bin/dev.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/usr/bin/env -S node --loader ts-node/esm --no-warnings=ExperimentalWarning
2+
// eslint-disable-next-line node/shebang
3+
async function main() {
4+
const { execute } = await import("@oclif/core");
5+
await execute({ development: true, dir: import.meta.url });
6+
}
7+
8+
await main();

bin/run.cmd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@echo off
2+
3+
node "%~dp0\run" %*

bin/run.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/usr/bin/env node
2+
3+
// eslint-disable-next-line node/shebang
4+
async function main() {
5+
const { execute } = await import("@oclif/core");
6+
await execute({ dir: import.meta.url });
7+
}
8+
9+
await main();

0 commit comments

Comments
 (0)