diff options
Diffstat (limited to 'cgithub/src')
| -rw-r--r-- | cgithub/src/app.test.ts | 32 | ||||
| -rw-r--r-- | cgithub/src/app.ts | 19 |
2 files changed, 51 insertions, 0 deletions
diff --git a/cgithub/src/app.test.ts b/cgithub/src/app.test.ts index 274b2d5..8720a23 100644 --- a/cgithub/src/app.test.ts +++ b/cgithub/src/app.test.ts @@ -358,6 +358,38 @@ describe("wiki", () => { }); }); +describe("global search", () => { + it("should keep the rest of the query around the qualifier", async () => { + const res = await app.request( + "http://cgithub.example/search?q=" + + encodeURIComponent("is:issue repo:actions/deploy-pages label:bug") + + "&type=issues", + ); + + assert.strictEqual( + res.headers.get("location"), + "/actions/deploy-pages/search?q=is%3Aissue+label%3Abug&type=issues", + ); + }); + + it("should redirect searches it cannot scope to a repository", async () => { + for (const url of [ + "http://cgithub.example/search?q=dms&type=code", + // An owner-wide search is not a single repository. + "http://cgithub.example/search?q=" + + encodeURIComponent("org:nix-community dms") + + "&type=code", + // Without a type there is no search to hand over. + "http://cgithub.example/search?q=" + encodeURIComponent("repo:actions/deploy-pages dms"), + ]) { + const res = await app.request(url); + + assert.strictEqual(res.status, 200, url); + assert.match(await res.text(), /url=https:\/\/github.com\/search\?/); + } + }); +}); + describe("redirects to GitHub", () => { // An HTTP redirect would be caught by the extension's declarativeNetRequest // rules and bounced straight back here. diff --git a/cgithub/src/app.ts b/cgithub/src/app.ts index a040aaa..7e5e9e8 100644 --- a/cgithub/src/app.ts +++ b/cgithub/src/app.ts @@ -95,6 +95,25 @@ export function createApp(eta: Eta) { return c.render("home.eta"); }); + // GitHub's global search, which we only serve when it is scoped to a single + // repository: strip the qualifier and let that repository's search route + // decide what to do with the rest. + app.get("/search", async (c) => { + const q = c.req.query("q") ?? ""; + const type = c.req.query("type"); + + const repoQualifier = /(?:^|\s)repo:([^/\s]+)\/([^/\s]+)(?=\s|$)/.exec(q); + if (type && repoQualifier) { + const [qualifier, owner, repo] = repoQualifier; + const rest = + q.slice(0, repoQualifier.index) + q.slice(repoQualifier.index + qualifier.length); + const params = new URLSearchParams({ q: rest.trim(), type }); + return c.redirect(`/${owner}/${repo}/search?${params}`); + } + + return redirectToGitHub(c); + }); + app.get("/:owner", async (c) => { const { owner } = c.req.param(); return c.render("owner.eta", await getGitHubOwner(owner)); |
