diff --git a/.github/workflows/plugin-tests.yml b/.github/workflows/plugin-tests.yml new file mode 100644 index 00000000..0de32ca4 --- /dev/null +++ b/.github/workflows/plugin-tests.yml @@ -0,0 +1,87 @@ +name: Plugin tests + +on: + pull_request: + paths: + - 'plugins/**' + +permissions: + contents: read + +concurrency: + group: plugin-tests-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + detect: + name: detect changed plugins + runs-on: ubuntu-latest + timeout-minutes: 5 + outputs: + dirs: ${{ steps.detect.outputs.dirs }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + # The pull_request checkout is the PR's merge commit; its first parent is the base. + fetch-depth: 2 + persist-credentials: false + - id: detect + name: List changed plugins with a test script + run: | + set -euo pipefail + git diff --name-only -z HEAD^1 HEAD -- plugins/ \ + | node -e ' + const fs = require("fs"); + const path = require("path"); + const files = fs.readFileSync(0, "utf8").split("\0").filter(Boolean); + const dirs = new Set(); + for (const f of files) { + const p = f.split("/"); + if (p.length >= 4 && p[0] === "plugins" && p[1] && p[2]) dirs.add(`plugins/${p[1]}/${p[2]}`); + } + const out = []; + for (const d of [...dirs].sort()) { + const pkg = path.join(d, "package.json"); + try { + if (!fs.statSync(d).isDirectory()) continue; + const j = JSON.parse(fs.readFileSync(pkg, "utf8")); + if (j && j.scripts && typeof j.scripts.test === "string" && j.scripts.test.trim()) out.push(d); + } catch { /* missing dir or package.json, or invalid JSON: skip */ } + } + process.stdout.write(JSON.stringify(out)); + ' > dirs.json + echo "Plugins to test: $(cat dirs.json)" + echo "dirs=$(cat dirs.json)" >> "$GITHUB_OUTPUT" + + test: + name: test (${{ matrix.dir }}) + needs: detect + if: needs.detect.outputs.dirs != '' && needs.detect.outputs.dirs != '[]' + runs-on: macos-latest + timeout-minutes: 10 + strategy: + fail-fast: false + matrix: + dir: ${{ fromJSON(needs.detect.outputs.dirs) }} + defaults: + run: + working-directory: ${{ matrix.dir }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: 22 + - name: Install plugin dependencies + run: | + set -euo pipefail + if [ -f package-lock.json ]; then + npm ci --no-audit --no-fund + elif node -e 'const p=require("./package.json"); process.exit(Object.keys({...p.dependencies, ...p.devDependencies}).length ? 0 : 1)'; then + npm install --no-audit --no-fund + else + echo "No dependencies declared; skipping install." + fi + - name: npm test + run: npm test diff --git a/AGENTS.md b/AGENTS.md index e15047bf..2c6ca48a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -24,7 +24,12 @@ package at `plugins///`; the rest change the checks (`docs/package-contract.md`), name a MiniMax Code version at or above it under `## Tested environment`. 4. Add one row to the table in both root READMEs. -5. Run `npm run check`. Done when it reports no errors and every warning is either fixed or +5. Tests are optional. Put them in the package directory (for example `tests/`) and run them + through `scripts.test` in the package's `package.json`; the Plugin tests workflow runs `npm test` + there when a pull request changes the package. Keep them off external hosts (loopback is fine), + install dependencies only inside the package with a committed `package-lock.json`, and delete + that `node_modules` before the next step. +6. Run `npm run check`. Done when it reports no errors and every warning is either fixed or explained in the PR description. ## Hard rules diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 27d282cc..ef894040 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,4 +16,13 @@ Submit ready-to-run files. If the app requires a build step, include its source Before submitting, install the app in MiniMax Code, open it, and check its main features. Include your test environment and results in the pull request, and state any unverified behavior. When updating an existing app, keep its plugin ID and update the version and usage instructions as appropriate. +## Plugin tests + +Tests for a plugin are optional and live inside the plugin's own directory (for example `plugins///tests/`). They run through the `test` script in the plugin's `package.json`, i.e. `npm test` from the plugin directory. + +- Tests must not reach external network hosts and must not depend on the MiniMax Code host app. A server the test starts on `127.0.0.1` is fine. +- Install any dependencies only inside the plugin directory (commit a `package-lock.json` if you have dependencies); never add them to the root `package.json`. Delete the plugin's `node_modules` before running `npm run check`: the check rejects any `node_modules` directory inside a package, ignored by Git or not. +- The root `test/` directory is reserved for repository-wide Mini App rule checks. It must not import or run plugin tests. +- The `Plugin tests` workflow runs only for plugins changed by a pull request, separately from the rules CI (`npm run check`). CI uses Node.js 22. + Working with an AI coding agent? It reads `AGENTS.md` automatically; `docs/` holds the same rules for people. diff --git a/CONTRIBUTING.zh-CN.md b/CONTRIBUTING.zh-CN.md index 8487a003..cefd42ca 100644 --- a/CONTRIBUTING.zh-CN.md +++ b/CONTRIBUTING.zh-CN.md @@ -16,4 +16,13 @@ 提交前在 MiniMax Code 中手动安装、打开并检查主要功能,在 PR 中写明测试环境和结果;未验证的部分如实说明。更新已有作品时,保留插件 ID,并按改动更新版本与使用说明。 +## 插件测试 + +插件测试是可选的,放在插件自己的目录里(例如 `plugins///tests/`),通过插件 `package.json` 中的 `test` 脚本运行,即在插件目录下执行 `npm test`。 + +- 测试不得访问外部网络,也不得依赖 MiniMax Code 宿主应用;测试自己在 `127.0.0.1` 上启动的服务不受限制。 +- 依赖只安装在插件目录内(有依赖时请提交 `package-lock.json`),不要加到根目录 `package.json`。运行 `npm run check` 前请删除插件目录里的 `node_modules`:无论是否被 Git 忽略,规则检查都会拒绝包内的 `node_modules` 目录。 +- 根目录 `test/` 只用于仓库级的 MiniApp 规则检查,不得引用或运行插件测试。 +- `Plugin tests` 工作流只针对 PR 改动到的插件运行,与规则 CI(`npm run check`)相互独立。CI 使用 Node.js 22。 + 使用 AI 编码助手时,它会自动读取 `AGENTS.md`;`docs/` 里是同一套规则的人类可读版本。 diff --git a/plugins/hanzijie/cq-viewer/README.md b/plugins/hanzijie/cq-viewer/README.md index aaed7074..543aec2b 100644 --- a/plugins/hanzijie/cq-viewer/README.md +++ b/plugins/hanzijie/cq-viewer/README.md @@ -183,3 +183,5 @@ The model path is validated first (registered folder, allowed extension, no symb ## License [MIT](LICENSE), except `skills/parametric-3d-printing/`, which keeps its own [PolyForm Noncommercial 1.0.0](skills/parametric-3d-printing/LICENSE) license. + + diff --git a/plugins/klarkxy/cutline/README.md b/plugins/klarkxy/cutline/README.md index da5bead0..478aebbc 100644 --- a/plugins/klarkxy/cutline/README.md +++ b/plugins/klarkxy/cutline/README.md @@ -142,3 +142,5 @@ Run plugin integration tests with `npm test --prefix plugins/klarkxy/cutline` fr Source: [ronak-create/FableCut](https://github.com/ronak-create/FableCut), version 1.16.0, commit `fd2af081d73ec94464b88df8c21f640adcc78985`. Original copyright and MIT terms are retained in [LICENSE](LICENSE). Third-party asset licenses remain beside the included assets. The source is vendored directly in this package. See `upstream.json` for provenance and `PATCHES.md` for local adaptations, including the branding changes made for this package. Updates are deliberate: compare the selected upstream revision, reapply necessary Host adaptations, run integration and repository checks, then exercise the installed editor and export path. Installing or updating the plugin does not fetch upstream code or install system software. + + diff --git a/plugins/liuchen19960902/timezone-guard/README.md b/plugins/liuchen19960902/timezone-guard/README.md index 27bda3e5..b0f43ec5 100644 --- a/plugins/liuchen19960902/timezone-guard/README.md +++ b/plugins/liuchen19960902/timezone-guard/README.md @@ -154,3 +154,5 @@ yesterday". ## License [MIT](./LICENSE). + + diff --git a/plugins/stevenjj33/workflow-console/README.md b/plugins/stevenjj33/workflow-console/README.md index 78e00db2..bf696d10 100644 --- a/plugins/stevenjj33/workflow-console/README.md +++ b/plugins/stevenjj33/workflow-console/README.md @@ -264,3 +264,5 @@ directory and prints the URL to open for manual inspection. ## License [MIT](./LICENSE). The vendored upstream runtime keeps its own Apache-2.0 license. + + diff --git a/plugins/zch0227/disk-insight/README.md b/plugins/zch0227/disk-insight/README.md index e30cc0bf..723496d5 100644 --- a/plugins/zch0227/disk-insight/README.md +++ b/plugins/zch0227/disk-insight/README.md @@ -249,3 +249,5 @@ Run the tests with `npm test` in this directory. Fixtures are created under ## License [MIT](./LICENSE). + +