Skip to content

Commit 2009e73

Browse files
committed
Add Algolia index script to CI
1 parent bcf56a5 commit 2009e73

File tree

6 files changed

+274
-0
lines changed

6 files changed

+274
-0
lines changed

.circleci/config.yml

+22
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,21 @@ jobs:
2222
docker login -u $WEBSITE_DOCKER_USER -p $WEBSITE_DOCKER_PASS
2323
docker push hashicorp/vagrant-website
2424
fi
25+
algolia-index:
26+
docker:
27+
- image: node:12
28+
steps:
29+
- checkout
30+
- run:
31+
name: Push content to Algolia Index
32+
command: |
33+
if [ "$CIRCLE_REPOSITORY_URL" != "[email protected]:hashicorp/vagrant.git" ]; then
34+
echo "Not Vagrant OSS Repo, not indexing Algolia"
35+
exit 0
36+
fi
37+
cd website/
38+
npm install
39+
node scripts/index_search_content.js
2540
workflows:
2641
version: 2
2742
build_website_docker_image:
@@ -31,3 +46,10 @@ workflows:
3146
branches:
3247
only:
3348
- master
49+
algolia_index:
50+
jobs:
51+
- algolia-index:
52+
filters:
53+
branches:
54+
only:
55+
- stable-website

website/.env

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
NEXT_PUBLIC_ALGOLIA_APP_ID=YY0FFNI7MF
2+
NEXT_PUBLIC_ALGOLIA_INDEX=product_VAGRANT
3+
NEXT_PUBLIC_ALGOLIA_SEARCH_ONLY_API_KEY=5037da4824714676226913c65e961ca0

website/.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,7 @@ node_modules
33
.next
44
out
55
.mdx-data
6+
7+
# As per Next.js conventions (https://nextjs.org/docs/basic-features/environment-variables#default-environment-variables)
8+
!.env
9+
.env*.local

website/package-lock.json

+141
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

website/package.json

+3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@
1818
"@hashicorp/react-section-header": "^2.0.0",
1919
"@hashicorp/react-subnav": "^3.2.2",
2020
"@hashicorp/react-vertical-text-block-list": "^2.0.1",
21+
"algoliasearch": "^4.3.0",
2122
"babel-plugin-import-glob-array": "^0.2.0",
23+
"dotenv": "^8.2.0",
24+
"gray-matter": "^4.0.2",
2225
"imagemin-mozjpeg": "^9.0.0",
2326
"imagemin-optipng": "^8.0.0",
2427
"imagemin-svgo": "^8.0.0",
+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
require('dotenv').config()
2+
3+
const algoliasearch = require('algoliasearch')
4+
const glob = require('glob')
5+
const matter = require('gray-matter')
6+
const path = require('path')
7+
8+
// In addition to the content of the page,
9+
// define additional front matter attributes that will be search-indexable
10+
const SEARCH_DIMENSIONS = ['page_title', 'description']
11+
12+
main()
13+
14+
async function main() {
15+
const pagesFolder = path.join(__dirname, '../pages')
16+
17+
// Grab all search-indexable content and format for Algolia
18+
const searchObjects = glob
19+
.sync(path.join(pagesFolder, '**/*.mdx'))
20+
.map((fullPath) => {
21+
const { content, data } = matter.read(fullPath)
22+
23+
// Get path relative to `pages`
24+
const __resourcePath = fullPath.replace(`${pagesFolder}/`, '')
25+
26+
// Use clean URL for Algolia id
27+
const objectID = __resourcePath.replace('.mdx', '')
28+
29+
const searchableDimensions = Object.keys(data)
30+
.filter((key) => SEARCH_DIMENSIONS.includes(key))
31+
.map((dimension) => ({
32+
[dimension]: data[dimension],
33+
}))
34+
35+
return {
36+
...searchableDimensions,
37+
content,
38+
__resourcePath,
39+
objectID,
40+
}
41+
})
42+
43+
try {
44+
await indexSearchContent(searchObjects)
45+
} catch (e) {
46+
console.error(e)
47+
process.exit(1)
48+
}
49+
}
50+
51+
async function indexSearchContent(objects) {
52+
const {
53+
NEXT_PUBLIC_ALGOLIA_APP_ID: appId,
54+
NEXT_PUBLIC_ALGOLIA_INDEX: index,
55+
ALGOLIA_API_KEY: apiKey,
56+
} = process.env
57+
58+
if (!apiKey || !appId || !index) {
59+
throw new Error(
60+
`[*** Algolia Search Indexing Error ***] Received: ALGOLIA_API_KEY=${apiKey} ALGOLIA_APP_ID=${appId} ALGOLIA_INDEX=${index} \n Please ensure all Algolia Search-related environment vars are set in CI settings.`
61+
)
62+
}
63+
64+
console.log(`updating ${objects.length} indices...`)
65+
66+
try {
67+
const searchClient = algoliasearch(appId, apiKey)
68+
const searchIndex = searchClient.initIndex(index)
69+
70+
await searchIndex.partialUpdateObjects(objects, {
71+
createIfNotExists: true,
72+
})
73+
74+
// Remove indices for items that aren't included in the new batch
75+
const newObjectIds = objects.map(({ objectID }) => objectID)
76+
let staleObjects = []
77+
78+
await searchIndex.browseObjects({
79+
query: '',
80+
batch: (batch) => {
81+
staleObjects = staleObjects.concat(
82+
batch.filter(({ objectID }) => !newObjectIds.includes(objectID))
83+
)
84+
},
85+
})
86+
87+
const staleIds = staleObjects.map(({ objectID }) => objectID)
88+
89+
if (staleIds.length > 0) {
90+
console.log(`deleting ${staleIds.length} stale indices:`)
91+
console.log(staleIds)
92+
93+
await searchIndex.deleteObjects(staleIds)
94+
}
95+
96+
console.log('done')
97+
process.exit(0)
98+
} catch (error) {
99+
throw new Error(error)
100+
}
101+
}

0 commit comments

Comments
 (0)