Skip to content

Commit 97c2308

Browse files
committed
Merge main into tool-adapter branch
2 parents a3228f8 + 228feb3 commit 97c2308

44 files changed

Lines changed: 2110 additions & 95 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude-plugin/marketplace.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"name": "b2c-developer-tooling",
3+
"description": "B2C Developer Tooling plugins for enhanced development workflows.",
4+
"version": "0.0.1",
5+
"owner": {
6+
"name": "Salesforce Agentforce Commerce",
7+
"email": "clavery@salesforce.com"
8+
},
9+
"plugins": [
10+
{
11+
"name": "b2c-cli",
12+
"description": "B2C CLI Skills for Salesforce Commerce Cloud development.",
13+
"author": {
14+
"name": "Salesforce"
15+
},
16+
"license": "Apache-2.0",
17+
"source": "./plugins/b2c-cli",
18+
"category": "productivity",
19+
"strict": false
20+
}
21+
]
22+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// @ts-check
2+
3+
/**
4+
* Creates a GitHub preview release and uploads tgz assets.
5+
*
6+
* @param {Object} params
7+
* @param {import('@octokit/rest').Octokit} params.github - Octokit instance
8+
* @param {Object} params.context - GitHub Actions context
9+
* @param {string} params.version - Version string (e.g., "0.0.1-preview.1")
10+
* @param {string} params.distDir - Directory containing tgz files
11+
*/
12+
export async function createPreviewRelease({ github, context, version, distDir }) {
13+
const fs = await import('fs');
14+
const path = await import('path');
15+
16+
const tagName = `v${version}`;
17+
18+
const releaseBody = `## Preview Release ${tagName}
19+
20+
### Installation
21+
22+
Download the tgz file and install:
23+
24+
\`\`\`bash
25+
npm install ./salesforce-b2c-cli-${version}.tgz
26+
\`\`\`
27+
28+
Or install globally:
29+
30+
\`\`\`bash
31+
npm install -g ./salesforce-b2c-cli-${version}.tgz
32+
\`\`\`
33+
34+
> **Note:** The SDK is bundled in the CLI package.
35+
`;
36+
37+
// Create the release
38+
const release = await github.rest.repos.createRelease({
39+
owner: context.repo.owner,
40+
repo: context.repo.repo,
41+
tag_name: tagName,
42+
name: tagName,
43+
prerelease: true,
44+
generate_release_notes: true,
45+
body: releaseBody,
46+
});
47+
48+
console.log(`Created release: ${release.data.html_url}`);
49+
50+
// Upload all tgz files from dist/
51+
const files = fs.readdirSync(distDir).filter((f) => f.endsWith('.tgz'));
52+
53+
for (const file of files) {
54+
const filePath = path.join(distDir, file);
55+
const fileData = fs.readFileSync(filePath);
56+
57+
console.log(`Uploading ${file}...`);
58+
59+
await github.rest.repos.uploadReleaseAsset({
60+
owner: context.repo.owner,
61+
repo: context.repo.repo,
62+
release_id: release.data.id,
63+
name: file,
64+
data: fileData,
65+
});
66+
67+
console.log(`Uploaded ${file}`);
68+
}
69+
70+
console.log(`Release complete: ${release.data.html_url}`);
71+
return release.data.html_url;
72+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
name: E2E Shell Tests
2+
3+
on:
4+
schedule:
5+
- cron: '0 3 * * *' # Run at 3 AM UTC daily
6+
workflow_dispatch:
7+
8+
jobs:
9+
e2e-shell-tests:
10+
runs-on: ubuntu-latest
11+
environment: e2e-dev
12+
timeout-minutes: 30
13+
steps:
14+
- uses: actions/checkout@v4
15+
16+
- uses: actions/setup-node@v4
17+
with:
18+
node-version: '24'
19+
20+
- name: Check for required secrets and vars
21+
id: check-secrets
22+
env:
23+
SFCC_CLIENT_ID: ${{ vars.SFCC_CLIENT_ID }}
24+
SFCC_CLIENT_SECRET: ${{ secrets.SFCC_CLIENT_SECRET }}
25+
TEST_REALM: ${{ vars.TEST_REALM }}
26+
SFCC_ACCOUNT_MANAGER_HOST: ${{ vars.SFCC_ACCOUNT_MANAGER_HOST }}
27+
SFCC_SANDBOX_API_HOST: ${{ vars.SFCC_SANDBOX_API_HOST }}
28+
SFCC_SHORTCODE: ${{ vars.SFCC_SHORTCODE }}
29+
run: |
30+
missing=""
31+
[ -z "$SFCC_CLIENT_ID" ] && missing="$missing SFCC_CLIENT_ID"
32+
[ -z "$SFCC_CLIENT_SECRET" ] && missing="$missing SFCC_CLIENT_SECRET"
33+
[ -z "$TEST_REALM" ] && missing="$missing TEST_REALM"
34+
[ -z "$SFCC_ACCOUNT_MANAGER_HOST" ] && missing="$missing SFCC_ACCOUNT_MANAGER_HOST"
35+
[ -z "$SFCC_SANDBOX_API_HOST" ] && missing="$missing SFCC_SANDBOX_API_HOST"
36+
[ -z "$SFCC_SHORTCODE" ] && missing="$missing SFCC_SHORTCODE"
37+
38+
if [ -z "$missing" ]; then
39+
echo "has-secrets=true" >> $GITHUB_OUTPUT
40+
else
41+
echo "has-secrets=false" >> $GITHUB_OUTPUT
42+
echo "E2E shell tests skipped - missing required variables:$missing" >> $GITHUB_STEP_SUMMARY
43+
fi
44+
45+
- name: Setup pnpm
46+
if: steps.check-secrets.outputs.has-secrets == 'true'
47+
uses: pnpm/action-setup@v4
48+
with:
49+
version: 10.17.1
50+
51+
- name: Get pnpm store directory
52+
if: steps.check-secrets.outputs.has-secrets == 'true'
53+
shell: bash
54+
run: |
55+
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
56+
57+
- name: Setup pnpm cache
58+
if: steps.check-secrets.outputs.has-secrets == 'true'
59+
uses: actions/cache@v4
60+
with:
61+
path: ${{ env.STORE_PATH }}
62+
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
63+
restore-keys: |
64+
${{ runner.os }}-pnpm-store-
65+
66+
- name: Install dependencies
67+
if: steps.check-secrets.outputs.has-secrets == 'true'
68+
run: pnpm install --frozen-lockfile
69+
70+
- name: Build packages
71+
if: steps.check-secrets.outputs.has-secrets == 'true'
72+
run: pnpm -r run build
73+
74+
- name: Run E2E Shell Tests
75+
if: steps.check-secrets.outputs.has-secrets == 'true'
76+
env:
77+
SFCC_CLIENT_ID: ${{ vars.SFCC_CLIENT_ID }}
78+
SFCC_CLIENT_SECRET: ${{ secrets.SFCC_CLIENT_SECRET }}
79+
SFCC_ACCOUNT_MANAGER_HOST: ${{ vars.SFCC_ACCOUNT_MANAGER_HOST }}
80+
SFCC_SANDBOX_API_HOST: ${{ vars.SFCC_SANDBOX_API_HOST }}
81+
SFCC_SHORTCODE: ${{ vars.SFCC_SHORTCODE }}
82+
TEST_REALM: ${{ vars.TEST_REALM }}
83+
run: |
84+
echo "Running E2E shell tests with realm: ${TEST_REALM}"
85+
cd packages/b2c-cli
86+
./test/functional/e2e_cli_test.sh

.github/workflows/e2e-tests.yml

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
name: e2e tests
2+
3+
on:
4+
# Nightly workflow - Run at 2 AM UTC daily
5+
schedule:
6+
- cron: '0 2 * * *'
7+
# Post-merge - Run after changes are merged to main
8+
push:
9+
branches: [main]
10+
# Manual trigger - Support workflow_dispatch for on-demand runs
11+
workflow_dispatch:
12+
inputs:
13+
test_realm:
14+
description: 'Test realm to use (optional, defaults to var)'
15+
required: false
16+
type: string
17+
sfcc_client_id:
18+
description: 'SFCC Client ID (optional, defaults to var)'
19+
required: false
20+
type: string
21+
sfcc_client_secret:
22+
description: 'SFCC Client Secret (optional, defaults to secret)'
23+
required: false
24+
type: string
25+
sfcc_account_manager_host:
26+
description: 'SFCC Account Manager Host (optional, defaults to var)'
27+
required: false
28+
type: string
29+
sfcc_sandbox_api_host:
30+
description: 'SFCC Sandbox API Host (optional, defaults to var)'
31+
required: false
32+
type: string
33+
jobs:
34+
e2e-tests:
35+
strategy:
36+
matrix:
37+
node-version: [22.x, 24.x]
38+
runs-on: ubuntu-latest
39+
environment: e2e-dev
40+
timeout-minutes: 25
41+
steps:
42+
- uses: actions/checkout@v4
43+
- uses: actions/setup-node@v4
44+
with:
45+
node-version: ${{ matrix.node-version }}
46+
- name: Check for required secrets and vars
47+
id: check-secrets
48+
env:
49+
SFCC_CLIENT_ID: ${{ vars.SFCC_CLIENT_ID }}
50+
SFCC_CLIENT_SECRET: ${{ secrets.SFCC_CLIENT_SECRET }}
51+
TEST_REALM: ${{ vars.TEST_REALM }}
52+
SFCC_ACCOUNT_MANAGER_HOST: ${{ vars.SFCC_ACCOUNT_MANAGER_HOST }}
53+
SFCC_SANDBOX_API_HOST: ${{ vars.SFCC_SANDBOX_API_HOST }}
54+
run: |
55+
if [ -n "$SFCC_CLIENT_ID" ] && [ -n "$SFCC_CLIENT_SECRET" ] && [ -n "$TEST_REALM" ] && [ -n "$SFCC_ACCOUNT_MANAGER_HOST" ] && [ -n "$SFCC_SANDBOX_API_HOST" ]; then
56+
echo "has-secrets=true" >> $GITHUB_OUTPUT
57+
else
58+
echo "has-secrets=false" >> $GITHUB_OUTPUT
59+
echo " E2E tests skipped - missing required variables:" >> $GITHUB_STEP_SUMMARY
60+
echo " - SFCC_CLIENT_ID (var): ${SFCC_CLIENT_ID:+✓}" >> $GITHUB_STEP_SUMMARY
61+
echo " - TEST_REALM (var): ${TEST_REALM:+✓}" >> $GITHUB_STEP_SUMMARY
62+
echo " - SFCC_ACCOUNT_MANAGER_HOST (var): ${SFCC_ACCOUNT_MANAGER_HOST:+✓}" >> $GITHUB_STEP_SUMMARY
63+
echo " - SFCC_SANDBOX_API_HOST (var): ${SFCC_SANDBOX_API_HOST:+✓}" >> $GITHUB_STEP_SUMMARY
64+
fi
65+
- name: Setup pnpm
66+
uses: pnpm/action-setup@v4
67+
with:
68+
version: 10.17.1
69+
70+
- name: Get pnpm store directory
71+
shell: bash
72+
run: |
73+
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
74+
75+
- name: Setup pnpm cache
76+
uses: actions/cache@v4
77+
with:
78+
path: ${{ env.STORE_PATH }}
79+
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
80+
restore-keys: |
81+
${{ runner.os }}-pnpm-store-
82+
83+
- name: Install dependencies
84+
if: steps.check-secrets.outputs.has-secrets == 'true'
85+
run: pnpm install --frozen-lockfile
86+
- name: Build package
87+
if: steps.check-secrets.outputs.has-secrets == 'true'
88+
run: pnpm -r run build
89+
- name: Run E2E Tests
90+
if: steps.check-secrets.outputs.has-secrets == 'true'
91+
id: e2e-test
92+
working-directory: packages/b2c-cli
93+
env:
94+
# Required environment variables
95+
SFCC_CLIENT_ID: ${{ inputs.sfcc_client_id || vars.SFCC_CLIENT_ID }}
96+
SFCC_CLIENT_SECRET: ${{ inputs.sfcc_client_secret || secrets.SFCC_CLIENT_SECRET }}
97+
SFCC_ACCOUNT_MANAGER_HOST: ${{ inputs.sfcc_account_manager_host || vars.SFCC_ACCOUNT_MANAGER_HOST }}
98+
SFCC_SANDBOX_API_HOST: ${{ inputs.sfcc_sandbox_api_host || vars.SFCC_SANDBOX_API_HOST }}
99+
TEST_REALM: ${{ inputs.test_realm || vars.TEST_REALM }}
100+
# Test configuration
101+
NODE_ENV: test
102+
SFCC_LOG_LEVEL: silent
103+
run: |
104+
echo "Running E2E tests with realm: ${TEST_REALM}"
105+
echo "Node version: $(node --version)"
106+
107+
# Run E2E tests with JSON reporter for test results
108+
pnpm run test:e2e && pnpm run lint
109+
110+
- name: E2E Test Report
111+
uses: dorny/test-reporter@fe45e9537387dac839af0d33ba56eed8e24189e8 # v2.3.0
112+
if: always() && steps.e2e-test.conclusion != 'cancelled' && steps.check-secrets.outputs.has-secrets == 'true'
113+
with:
114+
name: E2E Test Results (Node ${{ matrix.node-version }})
115+
path: 'packages/b2c-cli/test-results.json'
116+
reporter: mocha-json
117+
118+
- name: Upload E2E Test Results
119+
if: always() && steps.e2e-test.conclusion != 'cancelled' && steps.check-secrets.outputs.has-secrets == 'true'
120+
uses: actions/upload-artifact@v4
121+
with:
122+
name: e2e-test-results-node-${{ matrix.node-version }}-${{ github.run_number }}
123+
path: packages/b2c-cli/test-results.json
124+
retention-days: 30
125+
126+
- name: Notify on Failure
127+
if: failure() && (github.event_name == 'schedule' || github.event_name == 'push') && steps.check-secrets.outputs.has-secrets == 'true'
128+
uses: actions/github-script@v7
129+
with:
130+
script: |
131+
const issue = {
132+
owner: context.repo.owner,
133+
repo: context.repo.repo,
134+
title: `CLI E2E Tests Failed - ${new Date().toISOString().split('T')[0]}`,
135+
body: `## CLI E2E Test Failure
136+
137+
The CLI E2E tests have failed. Please investigate.
138+
139+
**Workflow:** ${context.workflow}
140+
**Run:** ${context.runNumber}
141+
**Commit:** ${context.sha}
142+
**Event:** ${context.eventName}
143+
**Node Version:** ${{ matrix.node-version }}
144+
145+
[View workflow run](${context.payload.repository.html_url}/actions/runs/${context.runId})
146+
`,
147+
labels: ['bug', 'e2e-failure', 'cli', 'needs-investigation']
148+
};
149+
150+
// Only create issue for scheduled runs to avoid spam
151+
if (context.eventName === 'schedule') {
152+
github.rest.issues.create(issue);
153+
}

0 commit comments

Comments
 (0)