Skip to content

Commit

Permalink
Merge branch 'main' into patch-1
Browse files Browse the repository at this point in the history
  • Loading branch information
nguyenalex836 committed May 22, 2024
2 parents da9e6ca + 8b0d5d7 commit 0d5cffe
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Exploring user activity in your enterprise
intro: 'You can view user and system activity by leveraging dashboards, webhooks and log forwarding.'
intro: 'You can view user {% ifversion ghes%}and system {% endif %}activity with {% ifversion ghes%}dashboards, log forwarding, and {% endif %}webhooks.'
versions:
ghec: '*'
ghes: '*'
Expand Down
2 changes: 1 addition & 1 deletion content/copilot/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ redirect_from:
changelog:
label: copilot
introLinks:
overview: /copilot/copilot-individual/about-github-copilot-individual
overview: /copilot/about-github-copilot
quickstart: /copilot/quickstart
featuredLinks:
startHere:
Expand Down
5 changes: 2 additions & 3 deletions data/glossaries/external.yml
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,7 @@
description: A section for hosting wiki style documentation on a GitHub repository.
- term: gitfile
description: >-
A plain `.git` file, which is always at the root of a working tree and points to the Git directory, which has the entire Git repository and its meta data. You can view this file for your repository on the command line with `git rev-parse --git-dir`.
that is the real repository.
A plain `.git` file, which is always at the root of a working tree and points to the Git directory, which has the entire Git repository and its meta data. You can view this file for your repository on the command line with `git rev-parse --git-dir`. That is the real repository.
- term: GraphQL
description: >-
A query language for APIs and a runtime for fulfilling those queries with
Expand Down Expand Up @@ -570,7 +569,7 @@
- term: punch graph
description: >-
A repository graph that shows the frequency of updates to a repository based
on the day of week and time of day
on the day of week and time of day.
- term: push
description: >-
To push means to send your committed changes to a remote repository on
Expand Down
38 changes: 37 additions & 1 deletion src/search/middleware/es-search.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export async function getSearchResults({
highlights,
include,
toplevel,
aggregate,
}) {
if (topics && !Array.isArray(topics)) {
throw new Error("'topics' has to be an array")
Expand Down Expand Up @@ -114,11 +115,14 @@ export async function getSearchResults({
}
const highlight = getHighlightConfiguration(query, highlightFields)

const aggs = getAggregations(aggregate)

const searchQuery = {
index: indexName,
highlight,
from,
size,
aggs,

// Since we know exactly which fields from the source we're going
// need we can specify that here. It's an inclusion list.
Expand Down Expand Up @@ -185,6 +189,7 @@ export async function getSearchResults({
highlightFields,
include,
})
const aggregations = getAggregationsResult(aggregate, result.aggregations)
const t1 = new Date()

const meta = {
Expand All @@ -197,7 +202,38 @@ export async function getSearchResults({
size,
}

return { meta, hits }
return { meta, hits, aggregations }
}

function getAggregations(aggregate) {
if (!aggregate || !aggregate.length) return undefined

const aggs = {}
for (const key of aggregate) {
aggs[key] = {
terms: {
field: key,
},
}
}
return aggs
}

function getAggregationsResult(aggregate, result) {
if (!aggregate || !aggregate.length) return
return Object.fromEntries(
aggregate.map((key) => [
key,
result[key].buckets
.map((bucket) => {
return {
key: bucket.key,
count: bucket.doc_count,
}
})
.sort((a, b) => a.key.localeCompare(b.key)),
]),
)
}

export async function getAutocompleteSearchResults({ indexName, query, size }) {
Expand Down
9 changes: 9 additions & 0 deletions src/search/middleware/get-search-request.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ const MAX_PAGE = 10
// a 400 Bad Request.
const V1_ADDITIONAL_INCLUDES = ['intro', 'headings', 'toplevel']

const V1_AGGREGATES = ['toplevel']

// If someone searches for `...&version=3.5` what they actually mean
// is `ghes-3.5`. This is because of legacy formatting with the old search.
// In some distant future we can clean up any client enough that this
Expand Down Expand Up @@ -114,6 +116,13 @@ const PARAMS = [
cast: toArray,
multiple: true,
},
{
key: 'aggregate',
default_: [],
cast: toArray,
multiple: true,
validate: (values) => values.every((value) => V1_AGGREGATES.includes(value)),
},
]

const AUTOCOMPLETE_PARAMS = [
Expand Down
6 changes: 4 additions & 2 deletions src/search/middleware/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ router.get(
highlights,
include,
toplevel,
aggregate,
} = req.search

const options = {
Expand All @@ -56,9 +57,10 @@ router.get(
usePrefixSearch: autocomplete,
include,
toplevel,
aggregate,
}
try {
const { meta, hits } = await getSearchResults(options)
const { meta, hits, aggregations } = await getSearchResults(options)

if (process.env.NODE_ENV !== 'development') {
searchCacheControl(res)
Expand All @@ -70,7 +72,7 @@ router.get(

// The v1 version of the output matches perfectly what comes out
// of the getSearchResults() function.
res.status(200).json({ meta, hits })
res.status(200).json({ meta, hits, aggregations })
} catch (error) {
// If getSearchResult() throws an error that might be 404 inside
// elasticsearch, if we don't capture that here, it will propagate
Expand Down
27 changes: 27 additions & 0 deletions src/search/tests/api-search.js
Original file line number Diff line number Diff line change
Expand Up @@ -364,3 +364,30 @@ describeIfElasticsearchURL('filter by toplevel', () => {
expect(results.meta.found.value).toBe(0)
})
})

describeIfElasticsearchURL('aggregate', () => {
vi.setConfig({ testTimeout: 60 * 1000 })

test("aggregate by 'toplevel'", async () => {
const sp = new URLSearchParams()
sp.set('query', 'foo')
sp.set('aggregate', 'toplevel')
const res = await get('/api/search/v1?' + sp)
expect(res.statusCode).toBe(200)
const results = JSON.parse(res.body)
expect(results.aggregations).toBeTruthy()
expect(results.aggregations.toplevel).toBeTruthy()
const firstAgg = results.aggregations.toplevel[0]
expect(firstAgg.key).toBeTruthy()
expect(firstAgg.count).toBeTruthy()
})

test("aggregate by 'unrecognizedxxx'", async () => {
const sp = new URLSearchParams()
sp.set('query', 'foo')
sp.set('aggregate', 'unrecognizedxxx')
const res = await get('/api/search/v1?' + sp)
expect(res.statusCode).toBe(400)
expect(JSON.parse(res.body).error).toMatch('aggregate')
})
})

0 comments on commit 0d5cffe

Please sign in to comment.