diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 574f9fe8c08..9aa81b81306 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,6 +39,7 @@ jobs: run_node: ${{ steps.scope.outputs.run_node }} run_macos: ${{ steps.scope.outputs.run_macos }} run_android: ${{ steps.scope.outputs.run_android }} + run_skills_python: ${{ steps.scope.outputs.run_skills_python }} run_windows: ${{ steps.scope.outputs.run_windows }} steps: - name: Checkout @@ -125,6 +126,9 @@ jobs: - runtime: node task: test command: pnpm canvas:a2ui:bundle && pnpm test + - runtime: node + task: extensions + command: pnpm test:extensions - runtime: node task: protocol command: pnpm protocol:check @@ -250,7 +254,7 @@ jobs: skills-python: needs: [docs-scope, changed-scope] - if: needs.docs-scope.outputs.docs_only != 'true' && (github.event_name == 'push' || needs.changed-scope.outputs.run_node == 'true') + if: needs.docs-scope.outputs.docs_only != 'true' && (github.event_name == 'push' || needs.changed-scope.outputs.run_node == 'true' || needs.changed-scope.outputs.run_skills_python == 'true') runs-on: blacksmith-16vcpu-ubuntu-2404 steps: - name: Checkout diff --git a/scripts/ci-changed-scope.mjs b/scripts/ci-changed-scope.mjs index ee9e66421d6..a4018b30a2c 100644 --- a/scripts/ci-changed-scope.mjs +++ b/scripts/ci-changed-scope.mjs @@ -1,9 +1,10 @@ import { execFileSync } from "node:child_process"; import { appendFileSync } from "node:fs"; -/** @typedef {{ runNode: boolean; runMacos: boolean; runAndroid: boolean; runWindows: boolean }} ChangedScope */ +/** @typedef {{ runNode: boolean; runMacos: boolean; runAndroid: boolean; runWindows: boolean; runSkillsPython: boolean }} ChangedScope */ const DOCS_PATH_RE = /^(docs\/|.*\.mdx?$)/; +const SKILLS_PYTHON_SCOPE_RE = /^skills\//; const MACOS_PROTOCOL_GEN_RE = /^(apps\/macos\/Sources\/OpenClawProtocol\/|apps\/shared\/OpenClawKit\/Sources\/OpenClawProtocol\/)/; const MACOS_NATIVE_RE = /^(apps\/macos\/|apps\/ios\/|apps\/shared\/|Swabble\/)/; @@ -21,13 +22,20 @@ const NATIVE_ONLY_RE = */ export function detectChangedScope(changedPaths) { if (!Array.isArray(changedPaths) || changedPaths.length === 0) { - return { runNode: true, runMacos: true, runAndroid: true, runWindows: true }; + return { + runNode: true, + runMacos: true, + runAndroid: true, + runWindows: true, + runSkillsPython: true, + }; } let runNode = false; let runMacos = false; let runAndroid = false; let runWindows = false; + let runSkillsPython = false; let hasNonDocs = false; let hasNonNativeNonDocs = false; @@ -43,6 +51,10 @@ export function detectChangedScope(changedPaths) { hasNonDocs = true; + if (SKILLS_PYTHON_SCOPE_RE.test(path)) { + runSkillsPython = true; + } + if (!MACOS_PROTOCOL_GEN_RE.test(path) && MACOS_NATIVE_RE.test(path)) { runMacos = true; } @@ -68,7 +80,7 @@ export function detectChangedScope(changedPaths) { runNode = true; } - return { runNode, runMacos, runAndroid, runWindows }; + return { runNode, runMacos, runAndroid, runWindows, runSkillsPython }; } /** @@ -102,6 +114,7 @@ export function writeGitHubOutput(scope, outputPath = process.env.GITHUB_OUTPUT) appendFileSync(outputPath, `run_macos=${scope.runMacos}\n`, "utf8"); appendFileSync(outputPath, `run_android=${scope.runAndroid}\n`, "utf8"); appendFileSync(outputPath, `run_windows=${scope.runWindows}\n`, "utf8"); + appendFileSync(outputPath, `run_skills_python=${scope.runSkillsPython}\n`, "utf8"); } function isDirectRun() { @@ -131,11 +144,23 @@ if (isDirectRun()) { try { const changedPaths = listChangedPaths(args.base, args.head); if (changedPaths.length === 0) { - writeGitHubOutput({ runNode: true, runMacos: true, runAndroid: true, runWindows: true }); + writeGitHubOutput({ + runNode: true, + runMacos: true, + runAndroid: true, + runWindows: true, + runSkillsPython: true, + }); process.exit(0); } writeGitHubOutput(detectChangedScope(changedPaths)); } catch { - writeGitHubOutput({ runNode: true, runMacos: true, runAndroid: true, runWindows: true }); + writeGitHubOutput({ + runNode: true, + runMacos: true, + runAndroid: true, + runWindows: true, + runSkillsPython: true, + }); } } diff --git a/src/scripts/ci-changed-scope.test.ts b/src/scripts/ci-changed-scope.test.ts index bd5c213bd12..358dbfc472c 100644 --- a/src/scripts/ci-changed-scope.test.ts +++ b/src/scripts/ci-changed-scope.test.ts @@ -10,6 +10,7 @@ const { detectChangedScope, listChangedPaths } = runMacos: boolean; runAndroid: boolean; runWindows: boolean; + runSkillsPython: boolean; }; listChangedPaths: (base: string, head?: string) => string[]; }; @@ -32,6 +33,7 @@ describe("detectChangedScope", () => { runMacos: true, runAndroid: true, runWindows: true, + runSkillsPython: true, }); }); @@ -41,6 +43,7 @@ describe("detectChangedScope", () => { runMacos: false, runAndroid: false, runWindows: false, + runSkillsPython: false, }); }); @@ -50,6 +53,7 @@ describe("detectChangedScope", () => { runMacos: false, runAndroid: false, runWindows: true, + runSkillsPython: false, }); }); @@ -59,12 +63,14 @@ describe("detectChangedScope", () => { runMacos: true, runAndroid: false, runWindows: false, + runSkillsPython: false, }); expect(detectChangedScope(["apps/shared/OpenClawKit/Sources/Foo.swift"])).toEqual({ runNode: false, runMacos: true, runAndroid: true, runWindows: false, + runSkillsPython: false, }); }); @@ -75,6 +81,7 @@ describe("detectChangedScope", () => { runMacos: false, runAndroid: false, runWindows: false, + runSkillsPython: false, }, ); }); @@ -85,6 +92,7 @@ describe("detectChangedScope", () => { runMacos: false, runAndroid: false, runWindows: false, + runSkillsPython: false, }); expect(detectChangedScope(["assets/icon.png"])).toEqual({ @@ -92,6 +100,7 @@ describe("detectChangedScope", () => { runMacos: false, runAndroid: false, runWindows: false, + runSkillsPython: false, }); }); @@ -101,6 +110,17 @@ describe("detectChangedScope", () => { runMacos: false, runAndroid: false, runWindows: false, + runSkillsPython: false, + }); + }); + + it("runs Python skill tests when skills change", () => { + expect(detectChangedScope(["skills/openai-image-gen/scripts/test_gen.py"])).toEqual({ + runNode: true, + runMacos: false, + runAndroid: false, + runWindows: false, + runSkillsPython: true, }); });