diff --git a/.github/workflows/pr-ci-sweeper.yml b/.github/workflows/pr-ci-sweeper.yml index 6d2610e317f2..ced31f187d8f 100644 --- a/.github/workflows/pr-ci-sweeper.yml +++ b/.github/workflows/pr-ci-sweeper.yml @@ -39,13 +39,13 @@ jobs: # lack actions:write/checks:read (every sweep failed 2026-07-24 until the # subset was reverted). No inputs = the app's full granted set, which the # sweep's re-fire lane is known to work with. - - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3 + - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # zizmor: ignore[github-app] v3 id: app-token continue-on-error: true with: app-id: "2729701" private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} - - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3 + - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # zizmor: ignore[github-app] v3 id: app-token-fallback if: steps.app-token.outcome == 'failure' with: diff --git a/extensions/msteams/package.json b/extensions/msteams/package.json index 1c6deb2596f2..f197bbd97b5d 100644 --- a/extensions/msteams/package.json +++ b/extensions/msteams/package.json @@ -76,6 +76,7 @@ "runtimeFormat": "cjs" }, "release": { + "bundleRuntimeDependencies": false, "publishToClawHub": true, "publishToNpm": true } diff --git a/scripts/docker-e2e-rerun.mjs b/scripts/docker-e2e-rerun.mjs index 4589baa2cea6..fac656a388e3 100644 --- a/scripts/docker-e2e-rerun.mjs +++ b/scripts/docker-e2e-rerun.mjs @@ -417,10 +417,14 @@ function downloadDockerArtifacts(runId, repo, outputDir) { if (names.length === 0) { throw new Error(`No docker-e2e-* artifacts found for run ${runId}`); } - for (const name of names) { + for (const [index, name] of names.entries()) { + const artifactDir = path.join( + outputDir, + `${String(index).padStart(3, "0")}-${safePathSegment(name)}`, + ); run( "gh", - ["run", "download", String(runId), "--repo", repo, "--name", name, "--dir", outputDir], + ["run", "download", String(runId), "--repo", repo, "--name", name, "--dir", artifactDir], { stdio: "inherit", }, diff --git a/test/plugin-npm-package-manifest.test.ts b/test/plugin-npm-package-manifest.test.ts index c7c084f797e4..0488913f7bf3 100644 --- a/test/plugin-npm-package-manifest.test.ts +++ b/test/plugin-npm-package-manifest.test.ts @@ -140,6 +140,14 @@ function writeOptionalPlatformDependencyPackage(packageDir: string): string { } describe("plugin npm package manifest staging", () => { + it("keeps msteams runtime dependencies registry-installed", () => { + const packageJson = JSON.parse( + readFileSync(join(process.cwd(), "extensions", "msteams", "package.json"), "utf8"), + ) as { openclaw?: { release?: { bundleRuntimeDependencies?: boolean } } }; + + expect(packageJson.openclaw?.release?.bundleRuntimeDependencies).toBe(false); + }); + it("wraps Windows npm.cmd staging through cmd.exe without shell mode", () => { const nodeDir = "C:\\Program Files\\nodejs"; const npmCmdPath = win32.resolve(nodeDir, "npm.cmd"); diff --git a/test/scripts/docker-e2e-helper-cli.test.ts b/test/scripts/docker-e2e-helper-cli.test.ts index 0b8989a6638d..82e4b181b9c2 100644 --- a/test/scripts/docker-e2e-helper-cli.test.ts +++ b/test/scripts/docker-e2e-helper-cli.test.ts @@ -6,6 +6,7 @@ import { mkdirSync, mkdtempSync, readFileSync, + readdirSync, rmSync, writeFileSync, } from "node:fs"; @@ -687,8 +688,22 @@ describe("Docker E2E helper CLIs", () => { expect(firstDir).not.toBe(secondDir); expect(path.basename(firstDir)).toMatch(/^openclaw-docker-e2e-rerun-12345-/u); expect(path.basename(secondDir)).toMatch(/^openclaw-docker-e2e-rerun-12345-/u); - expect(existsSync(path.join(firstDir, "artifact", "failures.json"))).toBe(true); - expect(existsSync(path.join(secondDir, "artifact", "failures.json"))).toBe(true); + const firstArtifactDir = readdirSync(firstDir, { withFileTypes: true }).find((entry) => + entry.isDirectory(), + ); + const secondArtifactDir = readdirSync(secondDir, { withFileTypes: true }).find((entry) => + entry.isDirectory(), + ); + expect(firstArtifactDir).toBeDefined(); + expect(secondArtifactDir).toBeDefined(); + expect( + existsSync(path.join(firstDir, firstArtifactDir?.name ?? "", "artifact", "failures.json")), + ).toBe(true); + expect( + existsSync( + path.join(secondDir, secondArtifactDir?.name ?? "", "artifact", "failures.json"), + ), + ).toBe(true); expect(first.stdout).toContain(`-f ref='${"d".repeat(40)}'`); expect(first.stdout).not.toContain("-f ref='abc123'"); expect(second.stdout).toContain(`-f ref='${"d".repeat(40)}'`); @@ -700,6 +715,81 @@ describe("Docker E2E helper CLIs", () => { } }); + it("isolates files with the same name across downloaded artifacts", () => { + const root = mkdtempSync(`${tmpdir()}/openclaw-docker-e2e-rerun-collisions-`); + try { + const binDir = path.join(root, "bin"); + const outputDir = path.join(root, "artifacts"); + const ghPath = path.join(binDir, "gh"); + mkdirSync(binDir, { recursive: true }); + writeFileSync( + ghPath, + [ + "#!/usr/bin/env node", + "const fs = require('node:fs');", + "const path = require('node:path');", + "const args = process.argv.slice(2);", + "if (args[0] === 'run' && args[1] === 'view') {", + " console.log(JSON.stringify({ headBranch: 'main', headSha: 'f'.repeat(40), url: 'https://example.invalid/run', workflowName: 'Live E2E' }));", + " process.exit(0);", + "}", + "if (args[0] === 'api') {", + " console.log(JSON.stringify([", + " { expired: false, name: 'docker-e2e-a' },", + " { expired: false, name: 'docker-e2e-b' },", + " ]));", + " process.exit(0);", + "}", + "if (args[0] === 'run' && args[1] === 'download') {", + " const name = args[args.indexOf('--name') + 1];", + " const dir = args[args.indexOf('--dir') + 1];", + " fs.mkdirSync(dir, { recursive: true });", + " const plan = path.join(dir, 'targeted-plan.json');", + " if (fs.existsSync(plan)) {", + " console.error('targeted-plan.json already exists');", + " process.exit(2);", + " }", + " fs.writeFileSync(plan, '{}');", + " fs.writeFileSync(path.join(dir, 'failures.json'), JSON.stringify({", + " lanes: [{ name: name.endsWith('-a') ? 'gateway-network' : 'install-e2e', status: 1 }],", + " ref: 'd'.repeat(40),", + " status: 'failed',", + " }));", + " process.exit(0);", + "}", + "console.error(`unexpected gh args: ${args.join(' ')}`);", + "process.exit(1);", + "", + ].join("\n"), + "utf8", + ); + chmodSync(ghPath, 0o755); + + const result = runHelper( + "scripts/docker-e2e-rerun.mjs", + "12345", + "--repo", + "openclaw/openclaw", + "--dir", + outputDir, + { PATH: `${binDir}${path.delimiter}${process.env.PATH ?? ""}` }, + ); + + expect(result.status, result.stderr).toBe(0); + expect(result.stdout).toContain("gateway-network"); + expect(result.stdout).toContain("install-e2e"); + const artifactDirs = readdirSync(outputDir, { withFileTypes: true }).filter((entry) => + entry.isDirectory(), + ); + expect(artifactDirs).toHaveLength(2); + for (const entry of artifactDirs) { + expect(existsSync(path.join(outputDir, entry.name, "targeted-plan.json"))).toBe(true); + } + } finally { + rmSync(root, { force: true, recursive: true }); + } + }); + it("fails closed when downloaded artifacts contain mixed target refs", () => { const root = mkdtempSync(`${tmpdir()}/openclaw-docker-e2e-rerun-mixed-refs-`); try {