diff --git a/data/reusables/repositories/rulesets-commit-regex.md b/data/reusables/repositories/rulesets-commit-regex.md
index 506e491e77e9..3c73ac70a3e9 100644
--- a/data/reusables/repositories/rulesets-commit-regex.md
+++ b/data/reusables/repositories/rulesets-commit-regex.md
@@ -2,7 +2,7 @@ When you add metadata restrictions, you can use regular expression syntax to def
Rulesets support RE2 syntax. For more information, see Google's [syntax guide](https://github.com/google/re2/wiki/Syntax). To validate your expressions, you can use the validator on [regex101.com](https://regex101.com/), selecting the "Golang" flavor in the left sidebar.
-Regular expressions consider multiple lines of text by default. For example, if you have a multiline commit message, the pattern `^ABC` will be a match if any line in the message starts with `ABC`. To match the start of the message specifically, you can start your expression with `\A`.
+By default, regular expressions in metadata restrictions do not consider multiple lines of text. For example, if you have a multiline commit message, the pattern `^ABC` will be a match if the first line of the message starts with `ABC`. To match multiple lines of the message, start your expression with `(?m)`.
The negative lookahead assertion, denoted `?!`, is not supported. However, for cases where you need to look for a given string that is not followed by another given string, you can use the positive lookahead assertion, denoted `?`, combined with the "Must not match a given regex pattern" requirement.
diff --git a/src/search/components/SearchResults.tsx b/src/search/components/SearchResults.tsx
index e005f8e73456..a6e5aa46c482 100644
--- a/src/search/components/SearchResults.tsx
+++ b/src/search/components/SearchResults.tsx
@@ -3,32 +3,30 @@ import { SearchIcon } from '@primer/octicons-react'
import { useRouter } from 'next/router'
import cx from 'classnames'
-import type { SearchResultsT, SearchResultHitT } from './types'
+import type { SearchResultsT, SearchResultHitT, SearchQueryT } from './types'
import { useTranslation } from 'components/hooks/useTranslation'
import { Link } from 'components/Link'
-import { useQuery } from 'src/search/components/useQuery'
import { sendEvent, EventType } from 'src/events/components/events'
import styles from './SearchResults.module.scss'
type Props = {
results: SearchResultsT
- query: string
+ search: SearchQueryT
}
-export function SearchResults({ results, query }: Props) {
+export function SearchResults({ results, search }: Props) {
const pages = Math.ceil(results.meta.found.value / results.meta.size)
const { page } = results.meta
return (
-
+
{pages > 1 && }
)
}
-function SearchResultHits({ hits, query }: { hits: SearchResultHitT[]; query: string }) {
- const { debug } = useQuery()
+function SearchResultHits({ hits, search }: { hits: SearchResultHitT[]; search: SearchQueryT }) {
return (
{hits.length === 0 && }
@@ -36,10 +34,10 @@ function SearchResultHits({ hits, query }: { hits: SearchResultHitT[]; query: st
))}
@@ -117,7 +115,7 @@ function SearchResultHit({
function ResultsPagination({ page, totalPages }: { page: number; totalPages: number }) {
const router = useRouter()
- const [asPathRoot, asPathQuery = ''] = router.asPath.split('?')
+ const [asPathRoot, asPathQuery = ''] = router.asPath.split('#')[0].split('?')
function hrefBuilder(page: number) {
const params = new URLSearchParams(asPathQuery)
diff --git a/src/search/components/index.tsx b/src/search/components/index.tsx
index 03b918ebc11c..ed7997de141a 100644
--- a/src/search/components/index.tsx
+++ b/src/search/components/index.tsx
@@ -63,7 +63,7 @@ export function Search({ search }: Props) {
) : null}
- {results ? : null}
+ {results ? : null}
)
}
diff --git a/src/search/components/types.ts b/src/search/components/types.ts
index 4d23eeb91a17..f7ce0c5f458c 100644
--- a/src/search/components/types.ts
+++ b/src/search/components/types.ts
@@ -32,21 +32,12 @@ export type SearchResultsT = {
export type SearchQueryT = {
query: string
- version: string
- language: string
- size: number
- page: number
- sort: string
- highlights: string[]
- autocomplete: boolean
debug: boolean
- include: string[]
- indexName: string
}
export type SearchValidationErrorT = {
error: string
- key: string
+ // key: string
}
export type SearchT = {
diff --git a/src/search/middleware/contextualize.js b/src/search/middleware/contextualize.js
index 358b78032fb6..9784f1eb5f1e 100644
--- a/src/search/middleware/contextualize.js
+++ b/src/search/middleware/contextualize.js
@@ -1,5 +1,6 @@
import got from 'got'
import { errors } from '@elastic/elasticsearch'
+import statsd from '#src/observability/lib/statsd.js'
import { getPathWithoutVersion, getPathWithoutLanguage } from '../../../lib/path-utils.js'
import { getSearchFromRequest } from './get-search-request.js'
@@ -61,8 +62,10 @@ export default async function contextualizeSearch(req, res, next) {
// In local dev, you get to see the error. In production,
// you get a "Oops! Something went wrong" which involves a Failbot
// send.
+ const tags = [`indexName:${search.indexName}`]
+ const timed = statsd.asyncTimer(getSearchResults, 'contextualize.search', tags)
try {
- req.context.search.results = await getSearchResults(search)
+ req.context.search.results = await timed(search)
} catch (error) {
// If the error coming from the Elasticsearch client is any sort
// of 4xx error, it will be bubbled up to the next middleware
diff --git a/src/search/pages/search.tsx b/src/search/pages/search.tsx
index 650a48a5f814..37da6bb1b05d 100644
--- a/src/search/pages/search.tsx
+++ b/src/search/pages/search.tsx
@@ -42,7 +42,31 @@ export const getServerSideProps: GetServerSideProps = async (context) =>
// This should have been done by the middleware.
throw new Error('Expected req.context to be populated with .search')
}
- const search: SearchT = req.context.search
+
+ // The `req.context.search` is similar to what's needed to React
+ // render the search result page.
+ // But it contains information (from the contextualizing) that is
+ // not needed to display search results.
+ // For example, the `req.context.search.search` contains things like
+ // `page` and `indexName` which was useful when it made the actual
+ // Elasticsearch query. But it's not needed to render the results.
+ // We explicitly pick out the parts that are needed, only.
+ const search: SearchT = {
+ search: {
+ query: req.context.search.search.query,
+ debug: req.context.search.search.debug,
+ },
+ validationErrors: req.context.search.validationErrors,
+ }
+ // If there are no results (e.g. /en/search?query=) from the
+ // contextualizing, then `req.context.search.results` will
+ // be `undefined` which can't be serialized as a prop, using JSON.stringify.
+ if (req.context.search.results) {
+ search.results = {
+ meta: req.context.search.results.meta,
+ hits: req.context.search.results.hits,
+ }
+ }
return {
props: {