fix(release): test candidate external channel plugins (#112899)

This commit is contained in:
Peter Steinberger
2026-07-23 00:53:23 -04:00
committed by GitHub
parent e99d978e24
commit ec8f957f2e
4 changed files with 77 additions and 4 deletions
@@ -4,6 +4,7 @@
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
SOURCE_ROOT="$(cd "${OPENCLAW_NPM_ONBOARD_SOURCE_ROOT:-${OPENCLAW_LIVE_DOCKER_REPO_ROOT:-$ROOT_DIR}}" && pwd)"
source "$ROOT_DIR/scripts/lib/docker-e2e-image.sh"
source "$ROOT_DIR/scripts/lib/docker-e2e-package.sh"
@@ -12,6 +13,7 @@ DOCKER_TARGET="${OPENCLAW_NPM_ONBOARD_DOCKER_TARGET:-bare}"
HOST_BUILD="${OPENCLAW_NPM_ONBOARD_HOST_BUILD:-1}"
PACKAGE_TGZ="${OPENCLAW_CURRENT_PACKAGE_TGZ:-}"
CHANNEL="${OPENCLAW_NPM_ONBOARD_CHANNEL:-telegram}"
USE_SOURCE_PLUGIN_PACKAGE="${OPENCLAW_NPM_ONBOARD_USE_SOURCE_PLUGIN_PACKAGE:-0}"
JSON_ARTIFACT_MAX_BYTES="$(
docker_e2e_read_positive_int_env OPENCLAW_NPM_ONBOARD_JSON_ARTIFACT_MAX_BYTES 1048576
)"
@@ -19,6 +21,8 @@ STATUS_TEXT_MAX_BYTES="$(
docker_e2e_read_positive_int_env OPENCLAW_NPM_ONBOARD_STATUS_TEXT_MAX_BYTES 1048576
)"
run_log=""
plugin_pack_dir=""
plugin_package_args=()
cleanup() {
if [ -n "${PACKAGE_TGZ:-}" ]; then
@@ -27,6 +31,9 @@ cleanup() {
if [ -n "${run_log:-}" ]; then
rm -f "$run_log"
fi
if [ -n "${plugin_pack_dir:-}" ]; then
rm -rf "$plugin_pack_dir"
fi
}
trap cleanup EXIT
@@ -54,6 +61,40 @@ prepare_package_tgz() {
prepare_package_tgz
prepare_source_plugin_package() {
if [ "$USE_SOURCE_PLUGIN_PACKAGE" != "1" ] || [ "$CHANNEL" = "telegram" ]; then
return 0
fi
local package_dir="extensions/$CHANNEL"
if [ ! -f "$SOURCE_ROOT/$package_dir/package.json" ]; then
echo "Missing source plugin package for $CHANNEL: $package_dir" >&2
exit 1
fi
plugin_pack_dir="$(mktemp -d "${TMPDIR:-/tmp}/openclaw-npm-onboard-plugin.XXXXXX")"
(
cd "$SOURCE_ROOT"
OPENCLAW_PLUGIN_NPM_PACK_OUTPUT_DIR="$plugin_pack_dir" \
bash scripts/plugin-npm-publish.sh --pack "$package_dir"
)
local archives=("$plugin_pack_dir"/*.tgz)
if [ "${#archives[@]}" -ne 1 ] || [ ! -f "${archives[0]}" ]; then
echo "Expected exactly one packed source plugin for $CHANNEL" >&2
exit 1
fi
local container_package="/tmp/openclaw-channel-plugin.tgz"
plugin_package_args=(
-v "${archives[0]}:$container_package:ro"
-e OPENCLAW_ALLOW_PLUGIN_INSTALL_OVERRIDES=1
-e "OPENCLAW_PLUGIN_INSTALL_OVERRIDES={\"$CHANNEL\":\"npm-pack:$container_package\"}"
)
}
prepare_source_plugin_package
docker_e2e_package_mount_args "$PACKAGE_TGZ"
run_log="$(docker_e2e_run_log npm-onboard-channel-agent)"
OPENCLAW_TEST_STATE_SCRIPT_B64="$(docker_e2e_test_state_shell_b64 npm-onboard-channel-agent empty)"
@@ -66,6 +107,7 @@ if ! docker_e2e_run_with_harness \
-e "OPENCLAW_NPM_ONBOARD_STATUS_TEXT_MAX_BYTES=$STATUS_TEXT_MAX_BYTES" \
-e "OPENCLAW_TEST_STATE_SCRIPT_B64=$OPENCLAW_TEST_STATE_SCRIPT_B64" \
"${DOCKER_E2E_PACKAGE_ARGS[@]}" \
"${plugin_package_args[@]}" \
-i "$IMAGE_NAME" bash -s >"$run_log" 2>&1 <<'EOF'; then
set -Eeuo pipefail
+18
View File
@@ -382,6 +382,24 @@ export const mainLanes = [
"OPENCLAW_NPM_ONBOARD_CHANNEL=slack OPENCLAW_SKIP_DOCKER_BUILD=1 pnpm test:docker:npm-onboard-channel-agent",
{ resources: ["service"], stateScenario: "empty", weight: 3 },
),
// Prerelease validation must pair frozen core bytes with matching target plugin bytes.
// Keep the registry-backed lanes above unchanged for published-package proof.
npmLane(
"npm-onboard-discord-candidate-channel-agent",
liveDockerScriptCommand(
"e2e/npm-onboard-channel-agent-docker.sh",
"OPENCLAW_NPM_ONBOARD_CHANNEL=discord OPENCLAW_NPM_ONBOARD_USE_SOURCE_PLUGIN_PACKAGE=1",
),
{ resources: ["service"], stateScenario: "empty", weight: 3 },
),
npmLane(
"npm-onboard-slack-candidate-channel-agent",
liveDockerScriptCommand(
"e2e/npm-onboard-channel-agent-docker.sh",
"OPENCLAW_NPM_ONBOARD_CHANNEL=slack OPENCLAW_NPM_ONBOARD_USE_SOURCE_PLUGIN_PACKAGE=1",
),
{ resources: ["service"], stateScenario: "empty", weight: 3 },
),
npmLane(
"release-user-journey",
"OPENCLAW_SKIP_DOCKER_BUILD=1 pnpm test:docker:release-user-journey",
+2 -2
View File
@@ -27,7 +27,7 @@ const pluginPrereleaseDockerLanes = Object.freeze([
surfaces: ["package-artifact", "gateway-bootstrap", "status-diagnostics"],
},
{
lane: "npm-onboard-discord-channel-agent",
lane: "npm-onboard-discord-candidate-channel-agent",
surfaces: [
"package-artifact",
"external-plugins",
@@ -37,7 +37,7 @@ const pluginPrereleaseDockerLanes = Object.freeze([
],
},
{
lane: "npm-onboard-slack-channel-agent",
lane: "npm-onboard-slack-candidate-channel-agent",
surfaces: ["package-artifact", "gateway-bootstrap", "status-diagnostics"],
},
{
@@ -57,11 +57,15 @@ describe("scripts/lib/plugin-prerelease-test-plan.mjs", () => {
it("runs the package and Docker product lanes through the existing scheduler", () => {
const plan = createPluginPrereleaseTestPlan();
const channelLaneScript = readFileSync(
"scripts/e2e/npm-onboard-channel-agent-docker.sh",
"utf8",
);
expect(plan.dockerLanes).toEqual([
"npm-onboard-channel-agent",
"npm-onboard-discord-channel-agent",
"npm-onboard-slack-channel-agent",
"npm-onboard-discord-candidate-channel-agent",
"npm-onboard-slack-candidate-channel-agent",
"doctor-switch",
"update-channel-switch",
"plugins-offline",
@@ -82,6 +86,15 @@ describe("scripts/lib/plugin-prerelease-test-plan.mjs", () => {
for (const lane of plan.dockerLanes) {
expect(getDockerLane(lane).name).toBe(lane);
}
expect(channelLaneScript).toContain("OPENCLAW_NPM_ONBOARD_USE_SOURCE_PLUGIN_PACKAGE");
expect(channelLaneScript).toContain("bash scripts/plugin-npm-publish.sh --pack");
expect(channelLaneScript).toContain("OPENCLAW_ALLOW_PLUGIN_INSTALL_OVERRIDES=1");
expect(channelLaneScript).toContain("npm-pack:$container_package");
const candidateLane = getDockerLane("npm-onboard-discord-candidate-channel-agent");
expect(candidateLane.command).toContain("OPENCLAW_DOCKER_E2E_TRUSTED_HARNESS_DIR");
expect(candidateLane.command).toContain(
'OPENCLAW_LIVE_DOCKER_REPO_ROOT="${OPENCLAW_DOCKER_E2E_REPO_ROOT:-$PWD}"',
);
});
it("keeps live-ish coverage outside provider-backed Docker lanes", () => {