fix(e2e): preserve Windows config shape during updates

This commit is contained in:
Vincent Koc
2026-07-04 12:49:52 -07:00
parent bee5dee521
commit a580a7fe3f
3 changed files with 57 additions and 46 deletions

View File

@@ -275,51 +275,47 @@ ${windowsScopedEnvFunction}
function Remove-FuturePluginEntries {
$configPath = Join-Path $env:USERPROFILE '.openclaw\\openclaw.json'
if (-not (Test-Path $configPath)) { return }
try { $config = Get-Content $configPath -Raw | ConvertFrom-Json } catch { return }
$plugins = Get-OpenClawJsonProperty $config 'plugins'
if ($null -eq $plugins) { return }
$entries = Get-OpenClawJsonProperty $plugins 'entries'
if ($null -ne $entries) {
foreach ($pluginId in @('feishu', 'whatsapp', 'openai')) {
Remove-OpenClawJsonProperty $entries $pluginId
$nodeScript = @'
const fs = require("node:fs");
const configPath = process.argv[2];
let config;
try {
config = JSON.parse(fs.readFileSync(configPath, "utf8").replace(/^\\uFEFF/u, ""));
} catch {
process.exit(0);
}
const plugins = config.plugins;
if (!plugins || typeof plugins !== "object") {
process.exit(0);
}
const futurePluginIds = new Set(["feishu", "whatsapp", "openai"]);
let changed = false;
if (plugins.entries && typeof plugins.entries === "object") {
for (const pluginId of futurePluginIds) {
if (Object.hasOwn(plugins.entries, pluginId)) {
delete plugins.entries[pluginId];
changed = true;
}
}
$allow = Get-OpenClawJsonProperty $plugins 'allow'
if ($null -ne $allow) {
Set-OpenClawJsonProperty $plugins 'allow' @($allow | Where-Object { $_ -notin @('feishu', 'whatsapp', 'openai') })
}
$config | ConvertTo-Json -Depth 100 | Set-Content -Path $configPath -Encoding UTF8
}
function Get-OpenClawJsonProperty {
param([object]$Object, [string]$Name)
if ($null -eq $Object) { return $null }
if ($Object -is [System.Collections.IDictionary]) { return $Object[$Name] }
$property = $Object.PSObject.Properties[$Name]
if ($null -eq $property) { return $null }
return $property.Value
if (Array.isArray(plugins.allow)) {
const allow = plugins.allow.filter((pluginId) => !futurePluginIds.has(pluginId));
if (allow.length !== plugins.allow.length) {
plugins.allow = allow;
changed = true;
}
}
function Set-OpenClawJsonProperty {
param([object]$Object, [string]$Name, [object]$Value)
if ($Object -is [System.Collections.IDictionary]) {
$Object[$Name] = $Value
return
}
$property = $Object.PSObject.Properties[$Name]
if ($null -ne $property) {
$property.Value = $Value
return
}
$Object | Add-Member -NotePropertyName $Name -NotePropertyValue $Value
if (changed) {
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\\n");
}
function Remove-OpenClawJsonProperty {
param([object]$Object, [string]$Name)
if ($null -eq $Object) { return }
if ($Object -is [System.Collections.IDictionary]) {
if ($Object.Contains($Name)) { $Object.Remove($Name) }
return
}
if ($null -ne $Object.PSObject.Properties[$Name]) {
$Object.PSObject.Properties.Remove($Name)
'@
$nodeScriptPath = Join-Path ([System.IO.Path]::GetTempPath()) ('openclaw-future-plugin-scrub-' + [guid]::NewGuid().ToString('N') + '.cjs')
try {
$nodeScript | Set-Content -Path $nodeScriptPath -Encoding UTF8
& node.exe $nodeScriptPath $configPath
if ($LASTEXITCODE -ne 0) { throw "failed to scrub future plugin entries" }
} finally {
Remove-Item $nodeScriptPath -Force -ErrorAction SilentlyContinue
}
}
function Stop-OpenClawGatewayProcesses {

View File

@@ -846,6 +846,11 @@ exit 7
it("scrubs future plugin entries before invoking old same-guest updaters", () => {
const script = readFileSync(UPDATE_SCRIPTS_PATH, "utf8");
const windowsScript = windowsUpdateScript({
auth: TEST_AUTH,
expectedNeedle: "2026.5.3-beta.2",
updateTarget: "2026.5.3-beta.2",
});
const macosScript = macosUpdateScript({
auth: TEST_AUTH,
expectedNeedle: "2026.5.3-beta.2",
@@ -856,9 +861,18 @@ exit 7
expect(script).toContain("scrub_future_plugin_entries");
expect(script).toContain("delete plugins.entries.feishu");
expect(script).toContain("delete plugins.entries.whatsapp");
expect(script).toContain("if ($null -ne $allow)");
expect(script).not.toContain("if ($allow -is [array])");
expect(script).toContain("Remove-FuturePluginEntries\nStop-OpenClawGatewayProcesses");
expect(windowsScript).toContain(
'const futurePluginIds = new Set(["feishu", "whatsapp", "openai"])',
);
expect(windowsScript).toContain('replace(/^\\uFEFF/u, "")');
expect(windowsScript).toContain("if (allow.length !== plugins.allow.length)");
expect(windowsScript).toContain('JSON.stringify(config, null, 2) + "\\n"');
expect(windowsScript).not.toContain("ConvertTo-Json -Depth 100");
expect(windowsScript).toContain("& node.exe $nodeScriptPath $configPath");
expect(windowsScript).toContain(
"Remove-Item $nodeScriptPath -Force -ErrorAction SilentlyContinue",
);
expect(windowsScript).toContain("Remove-FuturePluginEntries\nStop-OpenClawGatewayProcesses");
expect(script).toContain("scrub_future_plugin_entries\nstop_openclaw_gateway_processes");
expect(script).toContain("Invoke-WithScopedEnv @{ OPENCLAW_DISABLE_BUNDLED_PLUGINS = '1'");
expect(macosScript).toContain('OPENCLAW_BIN="$(resolve_required_command openclaw)"');

View File

@@ -1399,9 +1399,10 @@ if (isPrlctl) {
const script = readFileSync(TS_PATHS.npmUpdateScripts, "utf8");
expect(script).not.toContain("ConvertFrom-Json -AsHashtable");
expect(script).toContain("function Get-OpenClawJsonProperty");
expect(script).toContain("function Remove-OpenClawJsonProperty");
expect(script).toContain("Remove-OpenClawJsonProperty $entries $pluginId");
expect(script).not.toContain("ConvertTo-Json -Depth 100");
expect(script).toContain('replace(/^\\\\uFEFF/u, "")');
expect(script).toContain("$nodeScript | Set-Content -Path $nodeScriptPath -Encoding UTF8");
expect(script).toContain("& node.exe $nodeScriptPath $configPath");
});
it("keeps aggregate update guest scripts isolated from the npm-update orchestrator", () => {