mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:30:42 +00:00
test(docker): cover slack bundled runtime deps
This commit is contained in:
@@ -60,6 +60,7 @@ command -v openclaw >/dev/null
|
||||
package_root="$(npm root -g)/openclaw"
|
||||
test -d "$package_root/dist/extensions/telegram"
|
||||
test -d "$package_root/dist/extensions/discord"
|
||||
test -d "$package_root/dist/extensions/slack"
|
||||
|
||||
if [ -d "$package_root/dist/extensions/telegram/node_modules" ]; then
|
||||
echo "telegram runtime deps should not be preinstalled in package" >&2
|
||||
@@ -71,6 +72,11 @@ if [ -d "$package_root/dist/extensions/discord/node_modules" ]; then
|
||||
find "$package_root/dist/extensions/discord/node_modules" -maxdepth 2 -type f | head -20 >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
if [ -d "$package_root/dist/extensions/slack/node_modules" ]; then
|
||||
echo "slack runtime deps should not be preinstalled in package" >&2
|
||||
find "$package_root/dist/extensions/slack/node_modules" -maxdepth 2 -type f | head -20 >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
write_config() {
|
||||
local mode="$1"
|
||||
@@ -138,6 +144,15 @@ if (mode === "discord") {
|
||||
},
|
||||
};
|
||||
}
|
||||
if (mode === "slack") {
|
||||
config.channels = {
|
||||
...(config.channels || {}),
|
||||
slack: {
|
||||
...(config.channels?.slack || {}),
|
||||
enabled: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
||||
fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`, "utf8");
|
||||
@@ -392,6 +407,12 @@ config.channels = {
|
||||
dmPolicy: "disabled",
|
||||
groupPolicy: "disabled",
|
||||
},
|
||||
slack: {
|
||||
...(config.channels?.slack || {}),
|
||||
enabled: mode === "slack",
|
||||
botToken: "xoxb-bundled-channel-update-token",
|
||||
appToken: "xapp-bundled-channel-update-token",
|
||||
},
|
||||
};
|
||||
|
||||
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
||||
@@ -542,7 +563,11 @@ assert_dep_available telegram grammy
|
||||
echo "Mutating installed package: remove Telegram deps, then update-mode doctor repairs them..."
|
||||
remove_runtime_dep telegram grammy
|
||||
assert_no_dep_available telegram grammy
|
||||
OPENCLAW_UPDATE_IN_PROGRESS=1 openclaw doctor --non-interactive >/tmp/openclaw-update-mode-doctor.log 2>&1
|
||||
if ! OPENCLAW_UPDATE_IN_PROGRESS=1 openclaw doctor --non-interactive >/tmp/openclaw-update-mode-doctor.log 2>&1; then
|
||||
echo "update-mode doctor failed while repairing Telegram deps" >&2
|
||||
cat /tmp/openclaw-update-mode-doctor.log >&2
|
||||
exit 1
|
||||
fi
|
||||
assert_dep_available telegram grammy
|
||||
|
||||
echo "Mutating config to Discord and rerunning same-version update path..."
|
||||
@@ -554,6 +579,15 @@ cat /tmp/openclaw-update-discord.json
|
||||
assert_update_ok /tmp/openclaw-update-discord.json "$candidate_version"
|
||||
assert_dep_available discord discord-api-types
|
||||
|
||||
echo "Mutating config to Slack and rerunning same-version update path..."
|
||||
write_config slack
|
||||
remove_runtime_dep slack @slack/web-api
|
||||
assert_no_dep_available slack @slack/web-api
|
||||
run_update_and_capture slack /tmp/openclaw-update-slack.json
|
||||
cat /tmp/openclaw-update-slack.json
|
||||
assert_update_ok /tmp/openclaw-update-slack.json "$candidate_version"
|
||||
assert_dep_available slack @slack/web-api
|
||||
|
||||
echo "bundled channel runtime deps Docker update E2E passed"
|
||||
EOF
|
||||
then
|
||||
@@ -568,6 +602,7 @@ EOF
|
||||
|
||||
run_channel_scenario telegram grammy
|
||||
run_channel_scenario discord discord-api-types
|
||||
run_channel_scenario slack @slack/web-api
|
||||
if [ "$RUN_UPDATE_SCENARIO" != "0" ]; then
|
||||
run_update_scenario
|
||||
fi
|
||||
|
||||
@@ -172,7 +172,11 @@ describe("doctor bundled plugin runtime deps", () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-doctor-bundled-"));
|
||||
writeJson(path.join(root, "package.json"), { name: "openclaw" });
|
||||
writeBundledChannelPlugin(root, "telegram", { grammy: "1.37.0" });
|
||||
const installed: Array<{ installRoot: string; missingSpecs: string[] }> = [];
|
||||
const installed: Array<{
|
||||
installRoot: string;
|
||||
missingSpecs: string[];
|
||||
installSpecs: string[];
|
||||
}> = [];
|
||||
const prompter = {
|
||||
shouldRepair: false,
|
||||
shouldForce: false,
|
||||
@@ -207,6 +211,64 @@ describe("doctor bundled plugin runtime deps", () => {
|
||||
{
|
||||
installRoot: root,
|
||||
missingSpecs: ["grammy@1.37.0"],
|
||||
installSpecs: ["grammy@1.37.0"],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("retains configured bundled deps when repairing a subset", async () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-doctor-bundled-"));
|
||||
writeJson(path.join(root, "package.json"), { name: "openclaw" });
|
||||
writeBundledChannelPlugin(root, "telegram", { grammy: "1.37.0" });
|
||||
writeBundledChannelPlugin(root, "slack", { "@slack/web-api": "7.15.1" });
|
||||
writeJson(path.join(root, "node_modules", "@slack", "web-api", "package.json"), {
|
||||
name: "@slack/web-api",
|
||||
version: "7.15.1",
|
||||
});
|
||||
const installed: Array<{
|
||||
installRoot: string;
|
||||
missingSpecs: string[];
|
||||
installSpecs: string[];
|
||||
}> = [];
|
||||
const prompter = {
|
||||
shouldRepair: false,
|
||||
shouldForce: false,
|
||||
repairMode: {
|
||||
shouldRepair: false,
|
||||
shouldForce: false,
|
||||
nonInteractive: true,
|
||||
canPrompt: false,
|
||||
updateInProgress: false,
|
||||
},
|
||||
confirm: async () => false,
|
||||
confirmAutoFix: async () => false,
|
||||
confirmAggressiveAutoFix: async () => false,
|
||||
confirmRuntimeRepair: async () => false,
|
||||
select: async (_params: unknown, fallback: unknown) => fallback,
|
||||
} as DoctorPrompter;
|
||||
|
||||
await maybeRepairBundledPluginRuntimeDeps({
|
||||
runtime: { error: () => {} } as never,
|
||||
prompter,
|
||||
packageRoot: root,
|
||||
includeConfiguredChannels: true,
|
||||
config: {
|
||||
plugins: { enabled: true },
|
||||
channels: {
|
||||
telegram: { enabled: true },
|
||||
slack: { enabled: false, botToken: "xoxb-test", appToken: "xapp-test" },
|
||||
},
|
||||
},
|
||||
installDeps: (params) => {
|
||||
installed.push(params);
|
||||
},
|
||||
});
|
||||
|
||||
expect(installed).toEqual([
|
||||
{
|
||||
installRoot: root,
|
||||
missingSpecs: ["grammy@1.37.0"],
|
||||
installSpecs: ["@slack/web-api@7.15.1", "grammy@1.37.0"],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -16,7 +16,11 @@ export async function maybeRepairBundledPluginRuntimeDeps(params: {
|
||||
env?: NodeJS.ProcessEnv;
|
||||
packageRoot?: string | null;
|
||||
includeConfiguredChannels?: boolean;
|
||||
installDeps?: (params: { installRoot: string; missingSpecs: string[] }) => void;
|
||||
installDeps?: (params: {
|
||||
installRoot: string;
|
||||
missingSpecs: string[];
|
||||
installSpecs: string[];
|
||||
}) => void;
|
||||
}): Promise<void> {
|
||||
const packageRoot =
|
||||
params.packageRoot ??
|
||||
@@ -29,7 +33,7 @@ export async function maybeRepairBundledPluginRuntimeDeps(params: {
|
||||
return;
|
||||
}
|
||||
|
||||
const { missing, conflicts } = scanBundledPluginRuntimeDeps({
|
||||
const { deps, missing, conflicts } = scanBundledPluginRuntimeDeps({
|
||||
packageRoot,
|
||||
config: params.config,
|
||||
includeConfiguredChannels: params.includeConfiguredChannels,
|
||||
@@ -58,6 +62,7 @@ export async function maybeRepairBundledPluginRuntimeDeps(params: {
|
||||
}
|
||||
|
||||
const missingSpecs = missing.map((dep) => `${dep.name}@${dep.version}`);
|
||||
const installSpecs = deps.map((dep) => `${dep.name}@${dep.version}`);
|
||||
note(
|
||||
[
|
||||
"Bundled plugin runtime deps are missing.",
|
||||
@@ -84,11 +89,11 @@ export async function maybeRepairBundledPluginRuntimeDeps(params: {
|
||||
((installParams) =>
|
||||
installBundledRuntimeDeps({
|
||||
installRoot: installParams.installRoot,
|
||||
missingSpecs: installParams.missingSpecs,
|
||||
missingSpecs: installParams.installSpecs,
|
||||
env: params.env ?? process.env,
|
||||
}));
|
||||
install({ installRoot: packageRoot, missingSpecs });
|
||||
note(`Installed bundled plugin deps: ${missingSpecs.join(", ")}`, "Bundled plugins");
|
||||
install({ installRoot: packageRoot, missingSpecs, installSpecs });
|
||||
note(`Installed bundled plugin deps: ${installSpecs.join(", ")}`, "Bundled plugins");
|
||||
} catch (error) {
|
||||
params.runtime.error(`Failed to install bundled plugin runtime deps: ${String(error)}`);
|
||||
}
|
||||
|
||||
@@ -484,15 +484,16 @@ export function scanBundledPluginRuntimeDeps(params: {
|
||||
pluginIds?: readonly string[];
|
||||
includeConfiguredChannels?: boolean;
|
||||
}): {
|
||||
deps: RuntimeDepEntry[];
|
||||
missing: RuntimeDepEntry[];
|
||||
conflicts: RuntimeDepConflict[];
|
||||
} {
|
||||
if (isSourceCheckoutRoot(params.packageRoot)) {
|
||||
return { missing: [], conflicts: [] };
|
||||
return { deps: [], missing: [], conflicts: [] };
|
||||
}
|
||||
const extensionsDir = path.join(params.packageRoot, "dist", "extensions");
|
||||
if (!fs.existsSync(extensionsDir)) {
|
||||
return { missing: [], conflicts: [] };
|
||||
return { deps: [], missing: [], conflicts: [] };
|
||||
}
|
||||
const { deps, conflicts } = collectBundledPluginRuntimeDeps({
|
||||
extensionsDir,
|
||||
@@ -509,7 +510,7 @@ export function scanBundledPluginRuntimeDeps(params: {
|
||||
!fs.existsSync(path.join(extensionsDir, pluginId, dependencySentinelPath(dep.name))),
|
||||
),
|
||||
);
|
||||
return { missing, conflicts };
|
||||
return { deps, missing, conflicts };
|
||||
}
|
||||
|
||||
export function resolveBundledRuntimeDependencyInstallRoot(pluginRoot: string): string {
|
||||
|
||||
Reference in New Issue
Block a user