From abb8f34b868ff1d6e273264b7f8adf1743f3f3a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?In=C3=AAs=20Moital?= Date: Mon, 9 Nov 2026 08:57:48 +0000 Subject: [PATCH] ci(mirror): mirror hosts that install from the repo root, without a catalog --- CONTRIBUTING.md | 2 +- scripts/lib.mjs | 6 +++--- scripts/validate.mjs | 11 ++--------- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d66be52..0252a11 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -65,7 +65,7 @@ Each host is its own release-please package (`dist/`), with its own versio ### Mirror repos -Some installs name a repo of their own instead of a folder here: `copilot plugin marketplace add ZenRows/copilot-zenrows` reads that repo's root. Such a repo is a mirror: `mirror: ZenRows/copilot-zenrows` in the host's `vars.yaml` makes each release of the host replace the mirror's contents with `dist//`, plus the host's marketplace catalogs at the same paths, listing only that host with `source` set to `./` (the mirror's root), and a banner in its README pointing here. So the catalog is edited in one place, and `npm run validate` fails if a mirrored host has none. Nobody edits a mirror by hand; only its deploy key can push to it. +Some installs name a repo of their own instead of a folder here: `copilot plugin marketplace add ZenRows/copilot-zenrows` reads that repo's root, and so do the Cursor Marketplace and ClawHub. Such a repo is a mirror: `mirror: ZenRows/copilot-zenrows` in the host's `vars.yaml` makes each release of the host replace the mirror's contents with `dist//`, plus a banner in its README pointing here. If the host has marketplace catalogs, the mirror gets them at the same paths, listing only that host with `source` set to `./` (the mirror's root), so the catalog is edited in one place. A host that reads its plugin from the repo root, like Cursor or OpenClaw, needs no catalog. Nobody edits a mirror by hand; only its deploy key can push to it. - The release workflow runs `.github/workflows/mirror.yml` for each released host. It makes one normal commit (`release copilot-v0.1.2 from ZenRows/zenrows-integrations@`), never a force-push, and tags the mirror `v`. No commit is made when nothing changed, so a re-run is safe. - It pushes with the deploy key in the `MIRROR_KEY_` secret of the `release` environment. The key, the mirror's branch protection and its settings are in [iac-bootstrap](https://github.com/ZenRows/iac-bootstrap). diff --git a/scripts/lib.mjs b/scripts/lib.mjs index f607988..ad89784 100644 --- a/scripts/lib.mjs +++ b/scripts/lib.mjs @@ -166,9 +166,9 @@ export function catalogs() { } // A host with mirror: in vars.yaml is also published to that repo, -// whose root is dist// plus the host's marketplace catalogs (see -// catalogs()) at the same paths, listing only this host with source "./" (the -// mirror's root), and a banner under README.md's title pointing back here. +// whose root is dist// plus the host's marketplace catalogs, if it has +// any (see catalogs()), at the same paths, listing only this host with source +// "./" (the mirror's root), and a banner under README.md's title pointing back here. // The banner names the release tag, or for a sync with no tag, the commit. // Reads the committed files, which render --check and validate keep current. // Returns Map. diff --git a/scripts/validate.mjs b/scripts/validate.mjs index 97aeec3..f5d7fca 100644 --- a/scripts/validate.mjs +++ b/scripts/validate.mjs @@ -177,15 +177,8 @@ for (const host of hosts()) { } } - // A mirror repo installs through the host's marketplace catalog, rewritten - // to point at the mirror's root, so a mirrored host needs one. - if (values.mirror !== undefined) { - if (!/^[\w.-]+\/[\w.-]+$/.test(String(values.mirror))) { - errors.push(`${host}: vars.yaml mirror: is "${values.mirror}", expected /`); - } - if (!catalogs().some((c) => c.host === host)) { - errors.push(`${host}: vars.yaml sets mirror:, but ${host} has no marketplace catalog for the mirror to carry (see CONTRIBUTING.md)`); - } + if (values.mirror !== undefined && !/^[\w.-]+\/[\w.-]+$/.test(String(values.mirror))) { + errors.push(`${host}: vars.yaml mirror: is "${values.mirror}", expected /`); } // A whole-file override stops receiving fixes to the shared file it copied.