Merge pull request #12 from forcedotcom/gbockus/W-21323914-add-react-samples

feat: add first pass at b2e sample
This commit is contained in:
gbockus-sf 2026-02-27 18:08:09 -06:00 committed by GitHub
commit 8572ce8672
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 204 additions and 0 deletions

View File

@ -0,0 +1,82 @@
# Syncs @salesforce/webapp-template-app-react-sample-b2e-experimental into
# samples/webapp-template-app-react-sample-b2e-experimental. Opens a PR only when
# the npm package version has changed. Same steps as running locally:
# npm install && npm run sync-react-b2e-sample
#
# Uses IDEE_GH_TOKEN (bot) for checkout and PR creation; same pattern as
# salesforcedx-vscode-einstein-gpt/.github/workflows/build.yml
name: Sync React B2E sample from npm
on:
workflow_dispatch:
schedule:
# Nightly at 02:00 UTC
- cron: "0 2 * * *"
jobs:
sync:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.IDEE_GH_TOKEN }}
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version-file: ".nvmrc"
cache: npm
- name: Get latest npm version
id: npm-version
run: |
LATEST=$(npm view @salesforce/webapp-template-app-react-sample-b2e-experimental version)
echo "latest=$LATEST" >> $GITHUB_OUTPUT
- name: Read current synced version
id: current-version
run: |
VERSION_FILE="samples/webapp-template-app-react-sample-b2e-experimental/.version"
if [ -f "$VERSION_FILE" ]; then
CURRENT=$(cat "$VERSION_FILE" | tr -d '[:space:]')
echo "current=$CURRENT" >> $GITHUB_OUTPUT
else
echo "current=" >> $GITHUB_OUTPUT
fi
- name: Skip if version unchanged
id: skip
run: |
if [ "${{ steps.current-version.outputs.current }}" = "${{ steps.npm-version.outputs.latest }}" ]; then
echo "skip=true" >> $GITHUB_OUTPUT
echo "No version change. Current=${{ steps.current-version.outputs.current }}, Latest=${{ steps.npm-version.outputs.latest }}"
else
echo "skip=false" >> $GITHUB_OUTPUT
echo "Version change. Current=${{ steps.current-version.outputs.current }}, Latest=${{ steps.npm-version.outputs.latest }}"
fi
- name: Install dependencies and run sync (same as local)
if: steps.skip.outputs.skip != 'true'
run: |
npm install
npm run sync-react-b2e-sample
- name: Create PR on version change
if: steps.skip.outputs.skip != 'true'
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.IDEE_GH_TOKEN }}
branch: chore/sync-react-b2e-sample-${{ steps.npm-version.outputs.latest }}
base: main
title: "chore: sync React B2E sample from npm @ ${{ steps.npm-version.outputs.latest }}"
body: |
Synced `@salesforce/webapp-template-app-react-sample-b2e-experimental` to `samples/webapp-template-app-react-sample-b2e-experimental`.
- **Previous version:** ${{ steps.current-version.outputs.current || 'none' }}
- **New version:** ${{ steps.npm-version.outputs.latest }}
Same flow as running locally: `npm install` then `npm run sync-react-b2e-sample`.
commit-message: "chore: sync react-b2e-sample from npm @ ${{ steps.npm-version.outputs.latest }}"
committer: svc-idee-bot <svc_idee_bot@salesforce.com>
author: svc-idee-bot <svc_idee_bot@salesforce.com>

1
.nvmrc Normal file
View File

@ -0,0 +1 @@
v20.18.1

View File

@ -31,6 +31,8 @@ afv-library/
│ ├── metadata-deployments/
│ ├── testing-automation/
│ └── ...
├── samples/ # Synced sample apps (e.g. from npm)
│ └── webapp-template-app-react-sample-b2e-experimental/
└── README.md
```
@ -48,6 +50,17 @@ afv-library/
Browse the repository and copy/paste any prompt, rule, or skill directly into Agentforce Vibes or your preferred AI tool.
### Samples
The `samples/` folder contains synced sample apps. For example, `samples/webapp-template-app-react-sample-b2e-experimental/` is kept in sync with the npm package `@salesforce/webapp-template-app-react-sample-b2e-experimental` (nightly and on manual trigger via GitHub Actions). To run the same sync locally from the repo root:
```bash
npm install
npm run sync-react-b2e-sample
```
The GitHub Action runs these same commands and opens a PR only when the npm package version has changed. See [samples/README.md](samples/README.md) for details.
### Connecting Team or Personal Libraries
You can register additional repos with the extension as long as they mirror this structure:

11
package.json Normal file
View File

@ -0,0 +1,11 @@
˝{
"name": "afv-library",
"description": "AI prompts and rules library for Agentforce Vibes development",
"private": true,
"devDependencies": {
"@salesforce/webapp-template-app-react-sample-b2e-experimental": "*"
},
"scripts": {
"sync-react-b2e-sample": "node scripts/sync-react-b2e-sample.js"
}
}

23
samples/README.md Normal file
View File

@ -0,0 +1,23 @@
# Samples
Sample apps and templates synced into this repo for reference and reuse.
## webapp-template-app-react-sample-b2e-experimental
Source is synced from the npm package [@salesforce/webapp-template-app-react-sample-b2e-experimental](https://www.npmjs.com/package/@salesforce/webapp-template-app-react-sample-b2e-experimental). Only the packages source (no `node_modules`) is copied into `samples/webapp-template-app-react-sample-b2e-experimental/`.
### How its updated
- **GitHub Action**: Runs nightly and can be triggered manually from the **Actions** tab (“Sync React B2E sample from npm”). The workflow runs the same steps as below and opens a PR against `main` only when the npm package version has changed.
- **Local**: From the **repo root** you can run the same sync anytime:
```bash
npm install
npm run sync-react-b2e-sample
```
This installs the package into root `node_modules` and copies its source into `samples/webapp-template-app-react-sample-b2e-experimental/`, and updates `.version` in that folder.
### Version tracking
The file `samples/webapp-template-app-react-sample-b2e-experimental/.version` stores the last-synced npm version. The Action compares it to the latest on npm and only creates a PR when they differ.

View File

@ -0,0 +1,74 @@
#!/usr/bin/env node
/**
* Syncs source from @salesforce/webapp-template-app-react-sample-b2e-experimental
* into samples/webapp-template-app-react-sample-b2e-experimental/.
* Run from repo root after npm install. Same flow used locally and in CI.
*/
const fs = require('fs');
const path = require('path');
const PACKAGE_NAME = '@salesforce/webapp-template-app-react-sample-b2e-experimental';
const SAMPLE_DIR = path.join(process.cwd(), 'samples', 'webapp-template-app-react-sample-b2e-experimental');
const pkgRoot = path.join(process.cwd(), 'node_modules', PACKAGE_NAME.replace('/', path.sep));
if (!fs.existsSync(pkgRoot)) {
console.error(`Package not found at ${pkgRoot}. Run "npm install" from repo root first.`);
process.exit(1);
}
// Read version from the package we're syncing from
const pkgJsonPath = path.join(pkgRoot, 'package.json');
const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8'));
const version = pkgJson.version;
function copyRecursive(src, dest, excludeDirs = new Set(['node_modules', '.git'])) {
const stat = fs.statSync(src);
const basename = path.basename(src);
if (excludeDirs.has(basename)) return;
if (stat.isDirectory()) {
if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true });
for (const name of fs.readdirSync(src)) {
copyRecursive(path.join(src, name), path.join(dest, name), excludeDirs);
}
} else {
fs.mkdirSync(path.dirname(dest), { recursive: true });
fs.copyFileSync(src, dest);
}
}
// Ensure sample dir exists and clear it (we replace with fresh copy from dist)
if (fs.existsSync(SAMPLE_DIR)) {
for (const name of fs.readdirSync(SAMPLE_DIR)) {
if (name === '.version') continue; // keep .version until we overwrite it
const itemPath = path.join(SAMPLE_DIR, name);
if (fs.statSync(itemPath).isDirectory()) {
fs.rmSync(itemPath, { recursive: true });
} else {
fs.unlinkSync(itemPath);
}
}
} else {
fs.mkdirSync(SAMPLE_DIR, { recursive: true });
}
// Copy dist/ contents into sample dir (package ships source in dist/)
const distPath = path.join(pkgRoot, 'dist');
if (fs.existsSync(distPath)) {
for (const name of fs.readdirSync(distPath)) {
copyRecursive(path.join(distPath, name), path.join(SAMPLE_DIR, name));
}
}
// Copy LICENSE from package root
const licensePath = path.join(pkgRoot, 'LICENSE.txt');
if (fs.existsSync(licensePath)) {
fs.copyFileSync(licensePath, path.join(SAMPLE_DIR, 'LICENSE.txt'));
}
// Write .version for version tracking (used by workflow and local)
fs.writeFileSync(path.join(SAMPLE_DIR, '.version'), version + '\n', 'utf8');
console.log(`Synced ${PACKAGE_NAME}@${version} to ${SAMPLE_DIR}`);