Skip to content

Commit a0df710

Browse files
committed
Doc fixes and review nits
- Drop unimplemented "Compare with Instance" diff from features.md and remove its placeholder image; the diffCartridge command is stub functionality. - Fix project-root pinning docs: "Use as B2C Commerce Root" only shows on a workspace-root folder when the workspace has more than one folder open; "Reset" is palette-only. - Replace internal-source pointer with an inline rule in the cloned sandbox indicators paragraph. - Add 24h TTL to the VSIX release data loader cache so a maintainer who cuts a release won't see a stale version on the next local docs build. - Include pnpm-lock.yaml in the .vscode-test cache key so a test-cli / test-electron version bump invalidates the cache. - Comment the activation test's command-registration check to explain why it doubles as a swallowed-failure detector. - Tidy webdav-mappings.test.ts stub.
1 parent b72ed8c commit a0df710

8 files changed

Lines changed: 44 additions & 51 deletions

File tree

.github/workflows/ci-vs-extension.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ jobs:
6363
uses: actions/cache@v5
6464
with:
6565
path: packages/b2c-vs-extension/.vscode-test
66-
key: ${{ runner.os }}-vscode-test-${{ hashFiles('packages/b2c-vs-extension/.vscode-test.mjs') }}
66+
key: ${{ runner.os }}-vscode-test-${{ hashFiles('packages/b2c-vs-extension/.vscode-test.mjs', 'pnpm-lock.yaml') }}
6767
restore-keys: |
6868
${{ runner.os }}-vscode-test-
6969

docs/vscode-extension/configuration.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ The Sandbox Realm Explorer auto-polls a realm only when at least one sandbox is
6666

6767
In a multi-root workspace, the extension auto-detects the project root by walking up from the active editor (or the first workspace folder) looking for `dw.json` / `package.json` markers. Two commands let you override the auto-detected root:
6868

69-
- **B2C DX: Use as B2C Commerce Root**right-click any folder in the Explorer and select this command to pin it. The status bar shows a `$(pinned)` indicator while a pin is active.
70-
- **B2C DX: Reset B2C Commerce Root to Auto-Detect** — clears the pin and returns to auto-detection.
69+
- **B2C DX: Use as B2C Commerce Root**only available on a workspace-root folder when more than one folder is open in the workspace. Right-click that folder in the Explorer and select the command to pin it. While a pin is active, the status bar shows a `$(pinned)` indicator.
70+
- **B2C DX: Reset B2C Commerce Root to Auto-Detect** — clears the pin and returns to auto-detection. Run from the Command Palette (this command has no Explorer context-menu entry).
7171

7272
The pin is workspace-scoped (stored in workspace state). Pin a specific folder when you have multiple cartridge projects in a single workspace and want to keep CLI commands targeting one of them.
7373

docs/vscode-extension/features.md

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Browse and manage on-demand sandboxes (ODS) for one or more realms in a dedicate
1212

1313
**Lifecycle commands** (palette + right-click): create, start, stop, restart, clone, view details, view clone details, extend expiration, open Business Manager, delete.
1414

15-
**Cloned sandbox indicators** — clones are tagged in the tree (the source sandbox shows as `cloning` while a target is being set up; the target shows as `setting up` until it stabilizes). The display logic is identical to the CLI's: see `computeSandboxDisplay` in the package source for the precise rules.
15+
**Cloned sandbox indicators** — clones are tagged in the tree. While a clone is being set up, the source sandbox is shown as `cloning` and the new (target) sandbox is shown as `setting up`. Once the clone stabilizes, both rows display their actual states (`started`, `stopped`, etc.) and the cloned target keeps a visual marker so you can tell it apart from a freshly created sandbox.
1616

1717
<!-- TODO(screenshot): sandbox-explorer.png — started + cloned sandbox in the tree -->
1818
![Sandbox Realm Explorer](./images/sandbox-explorer.png)
@@ -59,16 +59,13 @@ A **Cartridges** tree view (under the **B2C-DX** activity-bar container) lists e
5959

6060
**Title-bar actions**: **Refresh Cartridges**, **Deploy Cartridges**, **Code Versions** (list / create / activate).
6161

62-
**Per-cartridge right-click actions**: **Upload Cartridge**, **Download from Instance**, **Compare with Instance** (diff view), **Add to Site Cartridge Path**, **Remove from Site Cartridge Path**.
62+
**Per-cartridge right-click actions**: **Upload Cartridge**, **Download from Instance**, **Add to Site Cartridge Path**, **Remove from Site Cartridge Path**.
6363

6464
**Workspace toggles**: **Toggle Code Sync** / **Start Code Sync** / **Stop Code Sync** start a watcher that uploads on save. **Upload to Instance** is also available from the file Explorer's context menu when a code-sync session is active.
6565

6666
<!-- TODO(screenshot): code-sync.png — Cartridges view with code-version dropdown -->
6767
![Cartridge Code Sync](./images/code-sync.png)
6868

69-
<!-- TODO(screenshot): code-sync-diff.png — Compare with Instance result -->
70-
![Code Sync diff](./images/code-sync-diff.png)
71-
7269
## SCAPI API Browser
7370

7471
Browse SCAPI OpenAPI schemas for your instance and open a Swagger UI panel for any endpoint. Requires OAuth credentials (`clientId`, `clientSecret`) and `shortCode` in `dw.json` — see the [Authentication Setup guide](../guide/authentication).
-69 Bytes
Binary file not shown.

docs/vscode-extension/installation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ The extension reads B2C Commerce credentials and project settings using the **sa
7676

7777
See the [Authentication Setup guide](../guide/authentication) for credential formats and OAuth scope requirements, and the [CLI Configuration guide](../guide/configuration) for the full list of supported config sources and precedence rules.
7878

79-
For multi-root workspaces, right-click any folder in the Explorer and choose **Use as B2C Commerce Root** to pin which folder the extension treats as the project root. Pair with **Reset B2C Commerce Root to Auto-Detect** to clear the pin.
79+
For multi-root workspaces (more than one folder open), right-click a workspace-root folder in the Explorer and choose **Use as B2C Commerce Root** to pin which folder the extension treats as the project root. To clear the pin, run **B2C DX: Reset B2C Commerce Root to Auto-Detect** from the Command Palette.
8080

8181
## Next Steps
8282

docs/vscode-extension/release.data.ts

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@
2323
* release ships, this fallback is the expected state.
2424
*
2525
* Cache: writes the resolved data to `docs/.vitepress/cache/release-vscode.json`
26-
* to avoid re-hitting the API on repeat local builds. Delete that file (or
27-
* `pnpm run docs:build` from a clean cache) to force a refresh.
26+
* with a 24-hour TTL so repeat local builds don't re-hit the API but a
27+
* maintainer who cuts a release won't see a stale version on the very next
28+
* local build. CI runners have no persisted cache, so each CI build hits the
29+
* API once. Delete the cache file to force an immediate refresh.
2830
*/
2931

3032
import fs from 'node:fs';
@@ -41,6 +43,12 @@ export interface ReleaseData {
4143
publishedAt?: string;
4244
}
4345

46+
interface CachedReleaseData extends ReleaseData {
47+
cachedAt: string;
48+
}
49+
50+
const CACHE_TTL_MS = 24 * 60 * 60 * 1000;
51+
4452
const REPO = 'SalesforceCommerceCloud/b2c-developer-tooling';
4553
const TAG_PREFIX = 'b2c-vs-extension@';
4654
const SEMVER_TAG_RE = /^b2c-vs-extension@\d+\.\d+\.\d+$/;
@@ -62,19 +70,22 @@ const CACHE_FILE = path.resolve(__dirname, '..', '.vitepress', 'cache', 'release
6270

6371
function readCache(): ReleaseData | undefined {
6472
try {
65-
if (fs.existsSync(CACHE_FILE)) {
66-
return JSON.parse(fs.readFileSync(CACHE_FILE, 'utf8')) as ReleaseData;
67-
}
73+
if (!fs.existsSync(CACHE_FILE)) return undefined;
74+
const cached = JSON.parse(fs.readFileSync(CACHE_FILE, 'utf8')) as CachedReleaseData;
75+
if (!cached.cachedAt) return undefined;
76+
if (Date.now() - Date.parse(cached.cachedAt) > CACHE_TTL_MS) return undefined;
77+
const {cachedAt: _cachedAt, ...data} = cached;
78+
return data;
6879
} catch {
69-
/* ignore */
80+
return undefined;
7081
}
71-
return undefined;
7282
}
7383

7484
function writeCache(data: ReleaseData): void {
7585
try {
7686
fs.mkdirSync(path.dirname(CACHE_FILE), {recursive: true});
77-
fs.writeFileSync(CACHE_FILE, JSON.stringify(data, null, 2));
87+
const payload: CachedReleaseData = {...data, cachedAt: new Date().toISOString()};
88+
fs.writeFileSync(CACHE_FILE, JSON.stringify(payload, null, 2));
7889
} catch {
7990
/* ignore */
8091
}

packages/b2c-vs-extension/src/test/integration/activation.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ suite('extension activation', () => {
4848
assert.ok(ext?.isActive, 'extension should be active after suiteSetup activate()');
4949
});
5050

51+
// This is the workhorse check. The extension's top-level try/catch
52+
// (extension.ts:117-136) registers only three stub commands on failure
53+
// (openUI, promptAgent, listWebDav), so any swallowed activation error
54+
// surfaces here as a flood of missing commands.
5155
test('every contributed command is registered', async () => {
5256
const registered = new Set(await vscode.commands.getCommands(true));
5357
const missing = pkg.contributes.commands.filter((c) => !registered.has(c.command));

packages/b2c-vs-extension/src/test/webdav-mappings.test.ts

Lines changed: 15 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,73 +8,56 @@ import * as assert from 'assert';
88
import type {B2CExtensionConfig} from '../config-provider.js';
99
import {WebDavMappingsProvider} from '../webdav-tree/webdav-mappings.js';
1010

11-
interface ResetEmitter {
12-
fire(): void;
13-
}
14-
15-
function makeStubConfig(values: Record<string, unknown>): {provider: B2CExtensionConfig; reset: ResetEmitter} {
16-
let resetListener: (() => void) | undefined;
11+
function makeStubConfig(values: Record<string, unknown>): B2CExtensionConfig {
1712
const stub = {
1813
getConfig: () => ({values}),
19-
onDidReset: (listener: () => void) => {
20-
resetListener = listener;
21-
return {dispose() {}};
22-
},
23-
};
24-
return {
25-
provider: stub as unknown as B2CExtensionConfig,
26-
reset: {
27-
fire() {
28-
resetListener?.();
29-
},
30-
},
14+
onDidReset: (_listener: () => void) => ({dispose() {}}),
3115
};
16+
return stub as unknown as B2CExtensionConfig;
3217
}
3318

3419
suite('WebDavMappingsProvider', () => {
3520
test('seedFromConfig dedupes contentLibrary against libraries', () => {
36-
const {provider} = makeStubConfig({libraries: ['lib-a', 'lib-b'], contentLibrary: 'lib-a'});
37-
const mappings = new WebDavMappingsProvider(provider);
21+
const mappings = new WebDavMappingsProvider(
22+
makeStubConfig({libraries: ['lib-a', 'lib-b'], contentLibrary: 'lib-a'}),
23+
);
3824
mappings.seedFromConfig();
3925

4026
assert.deepStrictEqual(mappings.getLibraryIds().sort(), ['lib-a', 'lib-b']);
4127
});
4228

4329
test('seedFromConfig adds contentLibrary when not already in libraries', () => {
44-
const {provider} = makeStubConfig({libraries: ['lib-a'], contentLibrary: 'lib-c'});
45-
const mappings = new WebDavMappingsProvider(provider);
30+
const mappings = new WebDavMappingsProvider(makeStubConfig({libraries: ['lib-a'], contentLibrary: 'lib-c'}));
4631
mappings.seedFromConfig();
4732

4833
assert.deepStrictEqual(mappings.getLibraryIds().sort(), ['lib-a', 'lib-c']);
4934
});
5035

5136
test('seedFromConfig copies catalogs verbatim', () => {
52-
const {provider} = makeStubConfig({catalogs: ['cat-1', 'cat-2']});
53-
const mappings = new WebDavMappingsProvider(provider);
37+
const mappings = new WebDavMappingsProvider(makeStubConfig({catalogs: ['cat-1', 'cat-2']}));
5438
mappings.seedFromConfig();
5539

5640
assert.deepStrictEqual(mappings.getCatalogIds(), ['cat-1', 'cat-2']);
5741
});
5842

5943
test('getEffectiveContentLibrary prefers explicit contentLibrary over libraries[0]', () => {
60-
const {provider} = makeStubConfig({libraries: ['lib-a', 'lib-b'], contentLibrary: 'lib-b'});
61-
const mappings = new WebDavMappingsProvider(provider);
44+
const mappings = new WebDavMappingsProvider(
45+
makeStubConfig({libraries: ['lib-a', 'lib-b'], contentLibrary: 'lib-b'}),
46+
);
6247
mappings.seedFromConfig();
6348

6449
assert.strictEqual(mappings.getEffectiveContentLibrary(), 'lib-b');
6550
});
6651

6752
test('getEffectiveContentLibrary falls back to libraries[0] when contentLibrary is unset', () => {
68-
const {provider} = makeStubConfig({libraries: ['lib-a', 'lib-b']});
69-
const mappings = new WebDavMappingsProvider(provider);
53+
const mappings = new WebDavMappingsProvider(makeStubConfig({libraries: ['lib-a', 'lib-b']}));
7054
mappings.seedFromConfig();
7155

7256
assert.strictEqual(mappings.getEffectiveContentLibrary(), 'lib-a');
7357
});
7458

7559
test('addCatalog is a no-op when the id is already present', () => {
76-
const {provider} = makeStubConfig({catalogs: ['cat-1']});
77-
const mappings = new WebDavMappingsProvider(provider);
60+
const mappings = new WebDavMappingsProvider(makeStubConfig({catalogs: ['cat-1']}));
7861
mappings.seedFromConfig();
7962

8063
let fires = 0;
@@ -90,8 +73,7 @@ suite('WebDavMappingsProvider', () => {
9073
});
9174

9275
test('removeCatalog is a no-op when the id is absent', () => {
93-
const {provider} = makeStubConfig({catalogs: ['cat-1']});
94-
const mappings = new WebDavMappingsProvider(provider);
76+
const mappings = new WebDavMappingsProvider(makeStubConfig({catalogs: ['cat-1']}));
9577
mappings.seedFromConfig();
9678

9779
let fires = 0;
@@ -106,8 +88,7 @@ suite('WebDavMappingsProvider', () => {
10688
});
10789

10890
test('addLibrary / removeLibrary mirror catalog behavior', () => {
109-
const {provider} = makeStubConfig({libraries: []});
110-
const mappings = new WebDavMappingsProvider(provider);
91+
const mappings = new WebDavMappingsProvider(makeStubConfig({libraries: []}));
11192
mappings.seedFromConfig();
11293

11394
let fires = 0;

0 commit comments

Comments
 (0)