mcp-server-sfmc 0.2.1 → 0.4.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/README.md +6 -1
- package/ci-templates/Jenkinsfile +71 -0
- package/ci-templates/README.md +36 -0
- package/ci-templates/azure-pipelines.yml +64 -0
- package/ci-templates/bitbucket-pipelines.yml +57 -0
- package/ci-templates/eslint.config.mjs +25 -0
- package/ci-templates/github-action.yml +109 -0
- package/ci-templates/github-copilot-review-instructions.md +72 -0
- package/ci-templates/gitlab-ci.yml +49 -0
- package/ci-templates/gitlab-duo-review-instructions.md +36 -0
- package/dist/cli/reviewDiff.d.ts +22 -0
- package/dist/cli/reviewDiff.d.ts.map +1 -0
- package/dist/cli/reviewDiff.js +226 -0
- package/dist/cli/reviewDiff.js.map +1 -0
- package/dist/index.js +226 -85
- package/dist/index.js.map +1 -1
- package/dist/mce-help-search.d.ts +3 -0
- package/dist/mce-help-search.d.ts.map +1 -1
- package/dist/mce-help-search.js +3 -0
- package/dist/mce-help-search.js.map +1 -1
- package/package.json +25 -6
package/README.md
CHANGED
|
@@ -29,9 +29,14 @@ You **do not** have to install the VS Code extension. Pick one way to run the se
|
|
|
29
29
|
| **`npx` (no install)** | Default in the examples below. Runs the latest published version from npm on demand; first run may download the package. **Requires Node.js and npm** (which provides `npx`). |
|
|
30
30
|
| **`npm install -g mcp-server-sfmc`** | Same CLI as `npx`, but the package stays on disk so **startup is faster** and you can set `"command": "mcp-server-sfmc"` with empty `args` in your MCP config. |
|
|
31
31
|
| **`npm install mcp-server-sfmc` in a project** | Keeps a **pinned version** in that folder’s `node_modules` — point your MCP config at `npx mcp-server-sfmc` with `cwd` set to the project, or run `./node_modules/.bin/mcp-server-sfmc` directly. |
|
|
32
|
+
| **`sfmc-review-diff` (bundled CLI)** | For **CI**: spawns this MCP server, calls `review_change` on a unified diff (stdin or file), exits non-zero on `ERROR` by default. Install the package in the job, then e.g. `git diff base...HEAD \| npx sfmc-review-diff`. |
|
|
32
33
|
|
|
33
34
|
None of these replace the VS Code extension for **editing** (syntax, LSP, snippets); they only expose the **MCP server** to tools that speak the Model Context Protocol.
|
|
34
35
|
|
|
36
|
+
## CI templates and `sfmc-review-diff`
|
|
37
|
+
|
|
38
|
+
Ready-to-copy workflows (GitHub Actions, GitLab CI, Jenkins, Azure Pipelines, Bitbucket Pipelines) live under **[`ci-templates/`](./ci-templates/)**. They run **`eslint-plugin-sfmc`** on changed files and **`sfmc-review-diff`** on the PR/MR unified diff. See **[`ci-templates/README.md`](./ci-templates/README.md)** for what each file does and how the two checks differ.
|
|
39
|
+
|
|
35
40
|
## What it gives your AI assistant
|
|
36
41
|
|
|
37
42
|
| Feature | Details |
|
|
@@ -45,7 +50,7 @@ None of these replace the VS Code extension for **editing** (syntax, LSP, snippe
|
|
|
45
50
|
| **Resources** | Full function catalogs, keyword list, unsupported ES6+ syntax list |
|
|
46
51
|
| **MCE help search** | Bundled excerpts from mirrored Salesforce Help (MCE vs Next scoped) |
|
|
47
52
|
|
|
48
|
-
##
|
|
53
|
+
## Connecting AI clients
|
|
49
54
|
|
|
50
55
|
### VS Code (1.99+) + GitHub Copilot — manual `mcp.json`
|
|
51
56
|
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Jenkins pipeline — SFMC Code Quality
|
|
2
|
+
// Runs eslint-plugin-sfmc on changed AMPscript and SSJS files in a pull request.
|
|
3
|
+
//
|
|
4
|
+
// Prerequisites:
|
|
5
|
+
// - Node.js 20+ installed on the agent (or use the 'nodejs' tool in Jenkins config)
|
|
6
|
+
// - "GitHub Pull Request Builder" or "Bitbucket Branch Source" plugin for PR detection
|
|
7
|
+
|
|
8
|
+
pipeline {
|
|
9
|
+
agent any
|
|
10
|
+
|
|
11
|
+
tools {
|
|
12
|
+
nodejs 'node-20' // matches the name in Manage Jenkins > Global Tool Configuration
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
triggers {
|
|
16
|
+
// GitHub Pull Request Builder plugin trigger (adjust as needed for your SCM)
|
|
17
|
+
githubPush()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
stages {
|
|
21
|
+
stage('Lint SFMC') {
|
|
22
|
+
when {
|
|
23
|
+
changeRequest() // only run on PRs/MRs
|
|
24
|
+
}
|
|
25
|
+
steps {
|
|
26
|
+
script {
|
|
27
|
+
// Install linter
|
|
28
|
+
sh 'npm install --no-save eslint eslint-plugin-sfmc'
|
|
29
|
+
|
|
30
|
+
// Write minimal config
|
|
31
|
+
writeFile file: 'eslint.config.mjs', text: '''
|
|
32
|
+
import sfmc from 'eslint-plugin-sfmc';
|
|
33
|
+
export default [...sfmc.configs.recommended];
|
|
34
|
+
'''
|
|
35
|
+
|
|
36
|
+
// Determine changed files (adjust base-branch detection as needed)
|
|
37
|
+
def changedFiles = sh(
|
|
38
|
+
script: "git diff --name-only origin/${env.CHANGE_TARGET}...HEAD | grep -E '\\.(amp|ampscript|ssjs|html)$' || true",
|
|
39
|
+
returnStdout: true
|
|
40
|
+
).trim()
|
|
41
|
+
|
|
42
|
+
if (changedFiles) {
|
|
43
|
+
echo "Linting SFMC files:\n${changedFiles}"
|
|
44
|
+
sh "npx eslint --format stylish ${changedFiles}"
|
|
45
|
+
} else {
|
|
46
|
+
echo "No SFMC files changed — skipping lint."
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
post {
|
|
51
|
+
failure {
|
|
52
|
+
// Optionally post a comment using the GitHub plugin
|
|
53
|
+
echo 'SFMC lint failed. See build log for details.'
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
stage('MCP diff review') {
|
|
59
|
+
when {
|
|
60
|
+
changeRequest()
|
|
61
|
+
}
|
|
62
|
+
steps {
|
|
63
|
+
script {
|
|
64
|
+
sh 'npm install --no-save mcp-server-sfmc@latest'
|
|
65
|
+
sh 'git fetch origin +refs/heads/$CHANGE_TARGET:refs/remotes/origin/$CHANGE_TARGET --depth=500 || true'
|
|
66
|
+
sh 'git diff origin/$CHANGE_TARGET...HEAD | npx sfmc-review-diff'
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# CI templates for SFMC projects
|
|
2
|
+
|
|
3
|
+
Copy these files into your own repository and adjust branch names, Node version, or path filters as needed.
|
|
4
|
+
|
|
5
|
+
## Two complementary checks
|
|
6
|
+
|
|
7
|
+
| Mechanism | What it does |
|
|
8
|
+
|-----------|----------------|
|
|
9
|
+
| **ESLint** (`eslint-plugin-sfmc`) | Lints **changed files** matching `*.amp`, `*.ssjs`, `*.html` (and embedded rules for HTML). File-level rules (unknown functions, arity, ES6 in SSJS, etc.). |
|
|
10
|
+
| **`sfmc-review-diff`** (this package, CLI) | Pipes a **unified `git diff`** into the MCP tool `review_change`, which validates **only added lines** using the same language catalog as the MCP server. Fails the job on `ERROR` diagnostics by default (`--fail-on` can include warnings or infos). |
|
|
11
|
+
|
|
12
|
+
You can keep **both** jobs in CI, or drop one if you only want file-based linting or only diff-based review.
|
|
13
|
+
|
|
14
|
+
**Git history:** shallow clones often lack the merge base. Prefer `fetch-depth: 0` (GitHub Actions), `GIT_DEPTH: "0"` (GitLab merge request pipelines), or enough depth that your diff command’s base ref/SHA exists.
|
|
15
|
+
|
|
16
|
+
## Files in this folder
|
|
17
|
+
|
|
18
|
+
| File | Platform | ESLint | `sfmc-review-diff` |
|
|
19
|
+
|------|----------|--------|----------------------|
|
|
20
|
+
| [github-action.yml](./github-action.yml) | GitHub Actions | yes | yes |
|
|
21
|
+
| [gitlab-ci.yml](./gitlab-ci.yml) | GitLab CI | yes | yes |
|
|
22
|
+
| [Jenkinsfile](./Jenkinsfile) | Jenkins | yes | yes |
|
|
23
|
+
| [azure-pipelines.yml](./azure-pipelines.yml) | Azure Pipelines | yes | yes |
|
|
24
|
+
| [bitbucket-pipelines.yml](./bitbucket-pipelines.yml) | Bitbucket Pipelines | yes | yes |
|
|
25
|
+
| [eslint.config.mjs](./eslint.config.mjs) | (reference) | shared flat config | — |
|
|
26
|
+
|
|
27
|
+
## AI review instructions (not CI)
|
|
28
|
+
|
|
29
|
+
These files guide **GitLab Duo** / **GitHub Copilot** style review text; they do **not** run `sfmc-review-diff`:
|
|
30
|
+
|
|
31
|
+
- [gitlab-duo-review-instructions.md](./gitlab-duo-review-instructions.md) — place content in `.gitlab/duo/mr-review-instructions.yaml` per GitLab docs (YAML format), not as a raw paste of this file.
|
|
32
|
+
- [github-copilot-review-instructions.md](./github-copilot-review-instructions.md) — Copilot / agent instructions; MCP blocks belong in client config, not in Actions YAML.
|
|
33
|
+
|
|
34
|
+
## Installing the CLI in CI
|
|
35
|
+
|
|
36
|
+
Templates use `npm install --no-save mcp-server-sfmc@latest` so the `sfmc-review-diff` binary is available. Pin a semver range in your project if you need reproducible builds.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Azure DevOps Pipelines — SFMC Code Quality
|
|
2
|
+
# Runs eslint-plugin-sfmc on changed AMPscript and SSJS files in pull requests.
|
|
3
|
+
#
|
|
4
|
+
# Add to your repository as azure-pipelines.yml and enable in Azure DevOps Pipelines.
|
|
5
|
+
|
|
6
|
+
trigger: none # only run on PRs, not pushes
|
|
7
|
+
|
|
8
|
+
pr:
|
|
9
|
+
branches:
|
|
10
|
+
include:
|
|
11
|
+
- main
|
|
12
|
+
- master
|
|
13
|
+
- develop
|
|
14
|
+
paths:
|
|
15
|
+
include:
|
|
16
|
+
- "**/*.amp"
|
|
17
|
+
- "**/*.ampscript"
|
|
18
|
+
- "**/*.ssjs"
|
|
19
|
+
- "**/*.html"
|
|
20
|
+
|
|
21
|
+
pool:
|
|
22
|
+
vmImage: "ubuntu-latest"
|
|
23
|
+
|
|
24
|
+
steps:
|
|
25
|
+
- task: NodeTool@0
|
|
26
|
+
inputs:
|
|
27
|
+
versionSpec: "20.x"
|
|
28
|
+
displayName: "Install Node.js 20"
|
|
29
|
+
|
|
30
|
+
- script: npm install --no-save eslint eslint-plugin-sfmc
|
|
31
|
+
displayName: "Install eslint-plugin-sfmc"
|
|
32
|
+
|
|
33
|
+
- script: |
|
|
34
|
+
cat > eslint.config.mjs << 'EOF'
|
|
35
|
+
import sfmc from 'eslint-plugin-sfmc';
|
|
36
|
+
export default [...sfmc.configs.recommended];
|
|
37
|
+
EOF
|
|
38
|
+
displayName: "Create ESLint config"
|
|
39
|
+
|
|
40
|
+
- script: |
|
|
41
|
+
git fetch origin $(System.PullRequest.TargetBranch) --depth=1
|
|
42
|
+
CHANGED=$(git diff --name-only origin/$(System.PullRequest.TargetBranch)...HEAD \
|
|
43
|
+
| grep -E '\.(amp|ampscript|ssjs|html)$' || true)
|
|
44
|
+
|
|
45
|
+
if [ -z "$CHANGED" ]; then
|
|
46
|
+
echo "No SFMC files changed — skipping lint."
|
|
47
|
+
exit 0
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
echo "Linting SFMC files:"
|
|
51
|
+
echo "$CHANGED"
|
|
52
|
+
npx eslint --format stylish $CHANGED
|
|
53
|
+
displayName: "Run SFMC lint"
|
|
54
|
+
failOnStderr: false
|
|
55
|
+
|
|
56
|
+
- script: npm install --no-save mcp-server-sfmc@latest
|
|
57
|
+
displayName: "Install mcp-server-sfmc (sfmc-review-diff)"
|
|
58
|
+
|
|
59
|
+
- script: |
|
|
60
|
+
set -e
|
|
61
|
+
git fetch origin "$(System.PullRequest.TargetBranch)" --unshallow 2>/dev/null || git fetch origin "$(System.PullRequest.TargetBranch)" --depth=500
|
|
62
|
+
git diff "origin/$(System.PullRequest.TargetBranch)...HEAD" | npx sfmc-review-diff
|
|
63
|
+
displayName: "MCP diff review (sfmc-review-diff)"
|
|
64
|
+
failOnStderr: false
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Bitbucket Pipelines — SFMC Code Quality
|
|
2
|
+
# Runs eslint-plugin-sfmc on changed AMPscript and SSJS files in pull requests.
|
|
3
|
+
#
|
|
4
|
+
# Add to your repository as bitbucket-pipelines.yml (or merge into your existing one).
|
|
5
|
+
|
|
6
|
+
image: node:20-alpine
|
|
7
|
+
|
|
8
|
+
definitions:
|
|
9
|
+
steps:
|
|
10
|
+
- step: &sfmc-lint
|
|
11
|
+
name: Lint AMPscript & SSJS
|
|
12
|
+
script:
|
|
13
|
+
- npm install --no-save eslint eslint-plugin-sfmc
|
|
14
|
+
- |
|
|
15
|
+
cat > eslint.config.mjs << 'EOF'
|
|
16
|
+
import sfmc from 'eslint-plugin-sfmc';
|
|
17
|
+
export default [...sfmc.configs.recommended];
|
|
18
|
+
EOF
|
|
19
|
+
- |
|
|
20
|
+
# Bitbucket provides BITBUCKET_PR_DESTINATION_BRANCH for PR builds
|
|
21
|
+
if [ -n "$BITBUCKET_PR_DESTINATION_BRANCH" ]; then
|
|
22
|
+
git fetch origin "$BITBUCKET_PR_DESTINATION_BRANCH" --depth=1
|
|
23
|
+
CHANGED=$(git diff --name-only "origin/$BITBUCKET_PR_DESTINATION_BRANCH"...HEAD \
|
|
24
|
+
| grep -E '\.(amp|ampscript|ssjs|html)$' || true)
|
|
25
|
+
else
|
|
26
|
+
# Fallback: lint all SFMC files
|
|
27
|
+
CHANGED=$(find . -type f \( -name '*.amp' -o -name '*.ampscript' -o -name '*.ssjs' \) | head -50)
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
if [ -z "$CHANGED" ]; then
|
|
31
|
+
echo "No SFMC files to lint."
|
|
32
|
+
exit 0
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
echo "Linting:"
|
|
36
|
+
echo "$CHANGED"
|
|
37
|
+
npx eslint --format stylish $CHANGED
|
|
38
|
+
|
|
39
|
+
- step: &sfmc-review-diff
|
|
40
|
+
name: MCP diff review (sfmc-review-diff)
|
|
41
|
+
script:
|
|
42
|
+
- npm install --no-save mcp-server-sfmc@latest
|
|
43
|
+
- |
|
|
44
|
+
if [ -n "$BITBUCKET_PR_DESTINATION_BRANCH" ]; then
|
|
45
|
+
git fetch origin "$BITBUCKET_PR_DESTINATION_BRANCH" --depth=500
|
|
46
|
+
git diff "origin/$BITBUCKET_PR_DESTINATION_BRANCH"...HEAD | npx sfmc-review-diff
|
|
47
|
+
else
|
|
48
|
+
echo "Not a PR build — skipping sfmc-review-diff."
|
|
49
|
+
exit 0
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
pipelines:
|
|
53
|
+
pull-requests:
|
|
54
|
+
"**":
|
|
55
|
+
- parallel:
|
|
56
|
+
- step: *sfmc-lint
|
|
57
|
+
- step: *sfmc-review-diff
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* eslint.config.mjs — SFMC project ESLint configuration
|
|
3
|
+
*
|
|
4
|
+
* Copy this file to your project root to enable eslint-plugin-sfmc rules
|
|
5
|
+
* for AMPscript (.amp, .ampscript) and SSJS (.ssjs) files.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* npm install --save-dev eslint eslint-plugin-sfmc
|
|
9
|
+
* npx eslint .
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import sfmc from 'eslint-plugin-sfmc';
|
|
13
|
+
|
|
14
|
+
export default [
|
|
15
|
+
// eslint-plugin-sfmc recommended rules for .amp, .ampscript, .ssjs, and .html files
|
|
16
|
+
...sfmc.configs.recommended,
|
|
17
|
+
|
|
18
|
+
// Optional: customise rules for your project
|
|
19
|
+
{
|
|
20
|
+
rules: {
|
|
21
|
+
// Increase the maximum number of problems reported per file
|
|
22
|
+
// 'sfmc/max-problems': ['warn', { max: 200 }],
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
];
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# place this file in .github/workflows
|
|
2
|
+
name: SFMC Code Quality
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
pull_request:
|
|
6
|
+
paths:
|
|
7
|
+
- "**/*.amp"
|
|
8
|
+
- "**/*.ampscript"
|
|
9
|
+
- "**/*.ssjs"
|
|
10
|
+
- "**/*.html"
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
lint-sfmc:
|
|
14
|
+
name: Lint AMPscript & SSJS
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
permissions:
|
|
17
|
+
contents: read
|
|
18
|
+
pull-requests: write
|
|
19
|
+
|
|
20
|
+
steps:
|
|
21
|
+
- name: Checkout
|
|
22
|
+
uses: actions/checkout@v4
|
|
23
|
+
|
|
24
|
+
- name: Set up Node.js
|
|
25
|
+
uses: actions/setup-node@v4
|
|
26
|
+
with:
|
|
27
|
+
node-version: "20"
|
|
28
|
+
|
|
29
|
+
- name: Install eslint-plugin-sfmc
|
|
30
|
+
run: npm install --no-save eslint eslint-plugin-sfmc
|
|
31
|
+
|
|
32
|
+
- name: Create ESLint config
|
|
33
|
+
run: |
|
|
34
|
+
cat > eslint.config.mjs << 'EOF'
|
|
35
|
+
import sfmc from 'eslint-plugin-sfmc';
|
|
36
|
+
export default [
|
|
37
|
+
...sfmc.configs.recommended,
|
|
38
|
+
];
|
|
39
|
+
EOF
|
|
40
|
+
|
|
41
|
+
- name: Run ESLint on changed files
|
|
42
|
+
id: lint
|
|
43
|
+
run: |
|
|
44
|
+
# Get changed files
|
|
45
|
+
git fetch origin ${{ github.base_ref }} --depth=1
|
|
46
|
+
CHANGED=$(git diff --name-only origin/${{ github.base_ref }}...HEAD \
|
|
47
|
+
| grep -E '\.(amp|ampscript|ssjs|html)$' || true)
|
|
48
|
+
|
|
49
|
+
if [ -z "$CHANGED" ]; then
|
|
50
|
+
echo "No SFMC files changed."
|
|
51
|
+
echo "result=pass" >> "$GITHUB_OUTPUT"
|
|
52
|
+
exit 0
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
echo "Linting files:"
|
|
56
|
+
echo "$CHANGED"
|
|
57
|
+
|
|
58
|
+
# Run eslint and capture output
|
|
59
|
+
OUTPUT=$(npx eslint --format stylish $CHANGED 2>&1 || true)
|
|
60
|
+
echo "$OUTPUT"
|
|
61
|
+
|
|
62
|
+
if echo "$OUTPUT" | grep -q "error"; then
|
|
63
|
+
echo "result=fail" >> "$GITHUB_OUTPUT"
|
|
64
|
+
echo "lint_output<<EOF" >> "$GITHUB_OUTPUT"
|
|
65
|
+
echo "$OUTPUT" >> "$GITHUB_OUTPUT"
|
|
66
|
+
echo "EOF" >> "$GITHUB_OUTPUT"
|
|
67
|
+
else
|
|
68
|
+
echo "result=pass" >> "$GITHUB_OUTPUT"
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
- name: Comment on PR
|
|
72
|
+
if: steps.lint.outputs.result == 'fail'
|
|
73
|
+
uses: actions/github-script@v7
|
|
74
|
+
with:
|
|
75
|
+
script: |
|
|
76
|
+
const output = `${{ steps.lint.outputs.lint_output }}`;
|
|
77
|
+
await github.rest.issues.createComment({
|
|
78
|
+
issue_number: context.issue.number,
|
|
79
|
+
owner: context.repo.owner,
|
|
80
|
+
repo: context.repo.repo,
|
|
81
|
+
body: `## SFMC Lint Results\n\n\`\`\`\n${output}\n\`\`\`\n\n> Run by [SFMC Code Quality workflow](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})`
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
- name: Fail if errors found
|
|
85
|
+
if: steps.lint.outputs.result == 'fail'
|
|
86
|
+
run: exit 1
|
|
87
|
+
|
|
88
|
+
review-diff-sfmc:
|
|
89
|
+
name: MCP diff review (sfmc-review-diff)
|
|
90
|
+
runs-on: ubuntu-latest
|
|
91
|
+
permissions:
|
|
92
|
+
contents: read
|
|
93
|
+
steps:
|
|
94
|
+
- name: Checkout
|
|
95
|
+
uses: actions/checkout@v4
|
|
96
|
+
with:
|
|
97
|
+
fetch-depth: 0
|
|
98
|
+
|
|
99
|
+
- name: Set up Node.js
|
|
100
|
+
uses: actions/setup-node@v4
|
|
101
|
+
with:
|
|
102
|
+
node-version: "20"
|
|
103
|
+
|
|
104
|
+
- name: Install mcp-server-sfmc
|
|
105
|
+
run: npm install --no-save mcp-server-sfmc@latest
|
|
106
|
+
|
|
107
|
+
- name: review_change on PR unified diff
|
|
108
|
+
run: |
|
|
109
|
+
git diff "${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }}" | npx sfmc-review-diff
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sfmc-reviewer
|
|
3
|
+
description: >
|
|
4
|
+
SFMC code quality specialist. Reviews AMPscript, SSJS, and HTML containing
|
|
5
|
+
SFMC-specific syntax. Validates language correctness, catches common mistakes,
|
|
6
|
+
and suggests idiomatic fixes — all grounded in the SFMC language catalog via
|
|
7
|
+
the mcp-server-sfmc MCP tools.
|
|
8
|
+
tools:
|
|
9
|
+
- read_file
|
|
10
|
+
- create_file
|
|
11
|
+
- replace_string_in_file
|
|
12
|
+
- sfmc/validate_ampscript
|
|
13
|
+
- sfmc/validate_ssjs
|
|
14
|
+
- sfmc/validate_sfmc_html
|
|
15
|
+
- sfmc/lookup_ampscript_function
|
|
16
|
+
- sfmc/lookup_ssjs_function
|
|
17
|
+
- sfmc/review_change
|
|
18
|
+
- sfmc/suggest_fix
|
|
19
|
+
- sfmc/get_ampscript_completions
|
|
20
|
+
- sfmc/get_ssjs_completions
|
|
21
|
+
mcp-servers:
|
|
22
|
+
sfmc:
|
|
23
|
+
type: stdio
|
|
24
|
+
command: npx
|
|
25
|
+
args:
|
|
26
|
+
- "-y"
|
|
27
|
+
- "mcp-server-sfmc@latest"
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
# instructions for human
|
|
31
|
+
Place this content in `.github/agents/sfmc-reviewer.agent.md` in your repository.
|
|
32
|
+
GitLab Duo Code Review will use these instructions when reviewing merge requests.
|
|
33
|
+
|
|
34
|
+
# instructions for AI
|
|
35
|
+
You are an expert Salesforce Marketing Cloud (SFMC) developer and code reviewer.
|
|
36
|
+
|
|
37
|
+
## Your responsibilities
|
|
38
|
+
|
|
39
|
+
- Review AMPscript, SSJS, and SFMC HTML code for correctness and best practices.
|
|
40
|
+
- Use `validate_ampscript`, `validate_ssjs`, or `validate_sfmc_html` to find real errors — never guess.
|
|
41
|
+
- Use `lookup_ampscript_function` and `lookup_ssjs_function` to verify function signatures and parameter counts before commenting on them.
|
|
42
|
+
- Use `suggest_fix` to generate concrete, compilable corrections for every issue you raise.
|
|
43
|
+
- Use `review_change` when reviewing diffs rather than full files.
|
|
44
|
+
|
|
45
|
+
## Language rules to enforce
|
|
46
|
+
|
|
47
|
+
### AMPscript
|
|
48
|
+
- Delimiters: `%%[ ]%%` for blocks, `%%= =%%` for inline output.
|
|
49
|
+
- Keywords (SET, VAR, IF, ELSEIF, ELSE, ENDIF, FOR, NEXT, OUTPUT) must be uppercase.
|
|
50
|
+
- Variables start with `@`. Example: `SET @myVar = "value"`.
|
|
51
|
+
- Comments: `/* block comment */` only — never `//` or `<!-- -->`.
|
|
52
|
+
- No ES6+ syntax (this is NOT JavaScript).
|
|
53
|
+
- All function names are case-insensitive (PascalCase by convention).
|
|
54
|
+
|
|
55
|
+
### SSJS
|
|
56
|
+
- ES5 engine only: use `var`, never `let`/`const`.
|
|
57
|
+
- No arrow functions, template literals, destructuring, Promises, or `class`.
|
|
58
|
+
- Wrap code in `<script runat="server">` ... `</script>`.
|
|
59
|
+
- Call `Platform.Load("core", "1.1.5");` before using Core library objects (DataExtension, Rows, etc.).
|
|
60
|
+
- Use `Platform.Function.*` for SFMC-specific APIs.
|
|
61
|
+
- Use `new WSProxy()` for SOAP API calls.
|
|
62
|
+
- Handle WSProxy errors by checking `response.Status`.
|
|
63
|
+
|
|
64
|
+
## Review format
|
|
65
|
+
|
|
66
|
+
For each issue found:
|
|
67
|
+
1. State the line number and the exact problem.
|
|
68
|
+
2. Quote the problematic code.
|
|
69
|
+
3. Provide the corrected code.
|
|
70
|
+
4. Explain why the original is wrong (one sentence).
|
|
71
|
+
|
|
72
|
+
End with a brief summary: total issues by severity, and whether the code is safe to merge.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# GitLab CI — SFMC Code Quality
|
|
2
|
+
#
|
|
3
|
+
# Runs eslint-plugin-sfmc on every merge request that touches AMPscript or SSJS files.
|
|
4
|
+
# Add this to your .gitlab-ci.yml or include it via:
|
|
5
|
+
#
|
|
6
|
+
# include:
|
|
7
|
+
# - remote: 'https://raw.githubusercontent.com/JoernBerkefeld/mcp-server-sfmc/main/ci-templates/gitlab-ci.yml'
|
|
8
|
+
|
|
9
|
+
stages:
|
|
10
|
+
- lint
|
|
11
|
+
|
|
12
|
+
sfmc-lint:
|
|
13
|
+
stage: lint
|
|
14
|
+
image: node:20-alpine
|
|
15
|
+
rules:
|
|
16
|
+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
17
|
+
changes:
|
|
18
|
+
- "**/*.amp"
|
|
19
|
+
- "**/*.ampscript"
|
|
20
|
+
- "**/*.ssjs"
|
|
21
|
+
- "**/*.html"
|
|
22
|
+
script:
|
|
23
|
+
- npm install --no-save eslint eslint-plugin-sfmc
|
|
24
|
+
- |
|
|
25
|
+
cat > eslint.config.mjs << 'EOF'
|
|
26
|
+
import sfmc from 'eslint-plugin-sfmc';
|
|
27
|
+
export default [...sfmc.configs.recommended];
|
|
28
|
+
EOF
|
|
29
|
+
- |
|
|
30
|
+
CHANGED=$(git diff --name-only origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME...HEAD \
|
|
31
|
+
| grep -E '\.(amp|ampscript|ssjs|html)$' || true)
|
|
32
|
+
if [ -z "$CHANGED" ]; then
|
|
33
|
+
echo "No SFMC files changed — skipping lint."
|
|
34
|
+
exit 0
|
|
35
|
+
fi
|
|
36
|
+
npx eslint --format stylish $CHANGED
|
|
37
|
+
allow_failure: false
|
|
38
|
+
|
|
39
|
+
sfmc-review-diff:
|
|
40
|
+
stage: lint
|
|
41
|
+
image: node:20-alpine
|
|
42
|
+
variables:
|
|
43
|
+
GIT_DEPTH: "0"
|
|
44
|
+
rules:
|
|
45
|
+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
46
|
+
script:
|
|
47
|
+
- npm install --no-save mcp-server-sfmc@latest
|
|
48
|
+
- git diff "$CI_MERGE_REQUEST_DIFF_BASE_SHA...HEAD" | npx sfmc-review-diff
|
|
49
|
+
allow_failure: false
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# GitLab Duo — SFMC Code Review Instructions
|
|
2
|
+
|
|
3
|
+
Place this content in `.gitlab/duo-instructions.md` in your repository.
|
|
4
|
+
GitLab Duo Code Review will use these instructions when reviewing merge requests.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
This repository contains Salesforce Marketing Cloud (SFMC) code.
|
|
9
|
+
Apply the following rules when reviewing merge requests that contain AMPscript, SSJS, or HTML files.
|
|
10
|
+
|
|
11
|
+
## AMPscript rules
|
|
12
|
+
|
|
13
|
+
- Block delimiters must balance: every `%%[` requires a matching `]%%`, every `%%=` requires `=%%`.
|
|
14
|
+
- Control flow must balance: every `IF` requires `ENDIF`, every `FOR` requires `NEXT`.
|
|
15
|
+
- Keywords must be uppercase: `SET`, `VAR`, `IF`, `ELSEIF`, `ELSE`, `ENDIF`, `FOR`, `TO`, `NEXT`, `OUTPUT`.
|
|
16
|
+
- Variables must start with `@`. Example: `SET @name = "value"`.
|
|
17
|
+
- Comments must use `/* */`. Flag `//` and `<!-- -->` inside AMPscript blocks as errors.
|
|
18
|
+
- Flag any function name that does not match the AMPscript function catalog.
|
|
19
|
+
- Flag arity mismatches (too few or too many arguments for known functions).
|
|
20
|
+
|
|
21
|
+
## SSJS rules
|
|
22
|
+
|
|
23
|
+
- SSJS runs on an ES5 engine. Flag `let`, `const`, arrow functions, template literals, and `class`.
|
|
24
|
+
- Flag missing `Platform.Load("core", "1.1.5")` when Core library objects (DataExtension, Rows, etc.) are used.
|
|
25
|
+
- Verify WSProxy error handling: flag any `WSProxy` call without a `Status` check on the response.
|
|
26
|
+
- Flag `console.log` — use `Platform.Response.Write()` or `Write()` instead.
|
|
27
|
+
|
|
28
|
+
## Review format
|
|
29
|
+
|
|
30
|
+
For each issue:
|
|
31
|
+
1. Provide the line number.
|
|
32
|
+
2. Quote the exact problematic code.
|
|
33
|
+
3. Explain why it is wrong.
|
|
34
|
+
4. Provide the corrected version.
|
|
35
|
+
|
|
36
|
+
End with a one-line verdict: APPROVE, REQUEST CHANGES, or COMMENT.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* sfmc-review-diff — CI helper: spawn mcp-server-sfmc and call review_change on a unified diff.
|
|
4
|
+
*/
|
|
5
|
+
export type FailOnLevel = 'error' | 'warning' | 'info';
|
|
6
|
+
export interface SeverityCounts {
|
|
7
|
+
errors: number;
|
|
8
|
+
warnings: number;
|
|
9
|
+
infos: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Counts diagnostic lines emitted by the review_change tool (see src/index.ts).
|
|
13
|
+
* @param output
|
|
14
|
+
*/
|
|
15
|
+
export declare function countReviewSeverities(output: string): SeverityCounts;
|
|
16
|
+
/**
|
|
17
|
+
* Whether the CLI should exit with code 1 given counts and --fail-on policy.
|
|
18
|
+
* @param counts
|
|
19
|
+
* @param failOn
|
|
20
|
+
*/
|
|
21
|
+
export declare function shouldFail(counts: SeverityCounts, failOn: FailOnLevel): boolean;
|
|
22
|
+
//# sourceMappingURL=reviewDiff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reviewDiff.d.ts","sourceRoot":"","sources":["../../src/cli/reviewDiff.ts"],"names":[],"mappings":";AACA;;GAEG;AAUH,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAEvD,MAAM,WAAW,cAAc;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAUpE;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAK/E"}
|