From 99fcc774b431faad15757f04396754c3ae5fd060 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Sun, 4 Oct 2026 21:09:16 -0400 Subject: [PATCH] CI: validate pushes on every branch; a GitHub source names owner and repo alone Co-Authored-By: Claude Opus 5.5 --- .github/workflows/catalog.yml | 1 - README.md | 2 +- scripts/catalog.mjs | 1 + tests/catalog.test.mjs | 2 ++ 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/catalog.yml b/.github/workflows/catalog.yml index e5f7b7d..4374a1c 100644 --- a/.github/workflows/catalog.yml +++ b/.github/workflows/catalog.yml @@ -3,7 +3,6 @@ name: Catalog on: pull_request: push: - branches: [main] schedule: # Mondays, 00:00 UTC. - cron: "0 0 * * 1" diff --git a/README.md b/README.md index f985315..1fa4beb 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ apps/ | `description` | At most 280 weighted characters, counted by [twitter-text](https://github.com/twitter/twitter-text): an address counts 23, CJK and emoji 2. | | `category` | `dev` (Developer Tools), `terminal` (Terminal & Network), `system` (System & Desktop) or `work` (Productivity & Media). | | `platforms` | Some of `macOS`, `Windows`, `Linux`, `Web`. | -| `website`, `source` | Canonical `https` addresses with a plain host, or `null`. One at least. | +| `website`, `source` | Canonical `https` addresses with a plain host, or `null`. One at least. A GitHub source is `https://github.com/owner/repo`, nothing after. | | `previews` | PNG file names in the folder. The first is the cover. | | `building` | Optional. `true` while the app is not out yet. | | `publishedAt` | ISO 8601 with a zone, such as `2026-10-04T12:00:00Z`: when the app joins the catalog. Maintainers confirm it; later updates keep it. | diff --git a/scripts/catalog.mjs b/scripts/catalog.mjs index 2d5a27e..98b02c8 100644 --- a/scripts/catalog.mjs +++ b/scripts/catalog.mjs @@ -126,6 +126,7 @@ function manifest(dir, id) { if (new Set(app.platforms).size !== app.platforms.length) fail(where, "platforms repeat"); address(where, app.website, "website"); address(where, app.source, "source"); + if (app.source && new URL(app.source).hostname === "github.com" && !github(app.source)) fail(where, `a GitHub source is https://github.com/owner/repo: ${app.source}`); if (app.website === null && app.source === null) fail(where, "website or source is required"); if (!Array.isArray(app.previews) || !app.previews.length) fail(where, "previews must be a non-empty list"); if (new Set(app.previews).size !== app.previews.length) fail(where, "previews repeat"); diff --git a/tests/catalog.test.mjs b/tests/catalog.test.mjs index dda3417..fa70ec3 100644 --- a/tests/catalog.test.mjs +++ b/tests/catalog.test.mjs @@ -59,6 +59,8 @@ const bad = [ ["a zone past 59 minutes", { app: { ...good, publishedAt: "2026-10-04T00:00:00+01:60" } }, /with its zone/], ["a day that does not exist", { app: { ...good, publishedAt: "2026-02-30T00:00:00Z" } }, /with its zone/], ["an encoded host", { app: { ...good, website: "https://good.example@evil.com/" } }, /plain host/], + ["a GitHub source with a trailing slash", { app: { ...good, source: "https://github.com/ada/tally/" } }, /github.com\/owner\/repo/], + ["a GitHub source with a query", { app: { ...good, source: "https://github.com/ada/tally?tab=readme-ov-file" } }, /github.com\/owner\/repo/], ["a host with credentials", { app: { ...good, website: "https://good.example@evil.com/" } }, /plain host/], ["a long description", { app: { ...good, description: "a".repeat(281) } }, /281 weighted characters/], ["stars without their time", { app: { ...good, stars: 3 } }, /go together/],