Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions apps/web/src/lib/github/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export function prepareQuery(search: string, orgs: string[]): string {
if (orgs.length > 0) {
q.setAll("org", orgs);
}
if (q.has("org") && q.has("repo")) {
if (q.has("org") && q.has("repo", { exclude: false })) {
// GitHub API does not seem to support having both terms with an "org"
// and "repo" qualifier in a given query. In this situation, the term
// with the "repo" qualifier is apparently ignored. We remediate to this
Expand All @@ -54,6 +54,12 @@ export function prepareQuery(search: string, orgs: string[]): string {
//
// Note: We ignore the situation where the targeted repo(s) are not within
// the originally targeted org(s).
//
// Only terms with a positive "repo" qualifier conflict with the "org"
// qualifier. An excluded repo (e.g., "-repo:apache/solr") does not narrow
// the search down to a set of repositories, hence terms with the "org"
// qualifier must be preserved, otherwise the search would be performed
// against the whole of GitHub.
q.delete("org");
}

Expand Down Expand Up @@ -81,8 +87,20 @@ export class SearchQuery {
this.terms = this.parseTerms(q);
}

has(qualifier: string): boolean {
return this.terms.some((t) => t.qualifier === qualifier);
/**
* Return whether this query has at least one term with a given qualifier.
*
* @param qualifier A qualifier.
* @param opts.exclude If defined, only consider terms whose exclusion flag
* matches this value. Otherwise, terms are considered whether they are
* excluded or not.
*/
has(qualifier: string, opts?: { exclude?: boolean }): boolean {
return this.terms.some(
(t) =>
t.qualifier === qualifier &&
(opts?.exclude === undefined || t.exclude === opts.exclude),
);
}

set(qualifier: string, value: string, op?: SearchOp): undefined {
Expand Down
26 changes: 26 additions & 0 deletions apps/web/tests/lib/github/search.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,30 @@ test("should filter by orgs", () => {
expect(prepareQuery("is:open repo:apache/solr", orgs)).toEqual(
"is:open repo:apache/solr type:pr archived:false sort:updated",
);

// An excluded repo does not restrict the search to a set of repositories,
// hence the org filter must be kept, otherwise the search is performed
// against the whole of GitHub.
expect(prepareQuery("is:open -repo:apache/solr", orgs)).toEqual(
"is:open -repo:apache/solr type:pr archived:false org:apache org:kubernetes sort:updated",
);

expect(
prepareQuery("is:open repo:apache/lucene -repo:apache/solr", orgs),
).toEqual(
"is:open repo:apache/lucene -repo:apache/solr type:pr archived:false sort:updated",
);
});

test("should tell whether a qualifier is present", () => {
const q = new SearchQuery("org:apache -repo:apache/solr");

expect(q.has("org")).toBe(true);
expect(q.has("repo")).toBe(true);
expect(q.has("author")).toBe(false);

expect(q.has("org", { exclude: false })).toBe(true);
expect(q.has("org", { exclude: true })).toBe(false);
expect(q.has("repo", { exclude: false })).toBe(false);
expect(q.has("repo", { exclude: true })).toBe(true);
});
Loading