Skip to content

Commit 92f989a

Browse files
author
Peter Bengtsson
authored
Run and test server with test fixture root (github#33816)
1 parent a746a8a commit 92f989a

File tree

29 files changed

+647
-34
lines changed

29 files changed

+647
-34
lines changed

.github/workflows/test.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ jobs:
4949
'routing',
5050
'unit',
5151
'linting',
52+
'rendering-fixtures',
5253
];
5354
if (context.payload.repository.full_name === 'github/docs-internal') {
5455
all.push('translations');
@@ -110,6 +111,10 @@ jobs:
110111
.github/actions-scripts/merge-early-access.sh
111112
rm -fr docs-early-access
112113
114+
- name: Check the test fixture data (if applicable)
115+
if: ${{ matrix.test-group == 'rendering-fixtures' }}
116+
run: ./script/copy-fixture-data.js --check
117+
113118
- name: Clone all translations
114119
if: ${{ matrix.test-group == 'translations' }}
115120
uses: ./.github/actions/clone-translations
@@ -172,4 +177,5 @@ jobs:
172177
# tests run only in English. The exception is the
173178
# `tests/translations/` suite which needs all languages to be set up.
174179
ENABLED_LANGUAGES: ${{ matrix.test-group == 'translations' && 'all' || '' }}
180+
ROOT: ${{ matrix.test-group == 'rendering-fixtures' && 'tests/fixtures' || ''}}
175181
run: npm test -- tests/${{ matrix.test-group }}/

lib/all-products.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ import path from 'path'
33
import frontmatter from './read-frontmatter.js'
44
import getApplicableVersions from './get-applicable-versions.js'
55
import removeFPTFromPath from './remove-fpt-from-path.js'
6+
import { ROOT } from './constants.js'
67

78
// Both internal and external products are specified in content/index.md
8-
const homepage = path.posix.join(process.cwd(), 'content/index.md')
9+
const homepage = path.posix.join(ROOT, 'content/index.md')
910
const { data } = frontmatter(await fs.readFile(homepage, 'utf8'))
1011

1112
export const productIds = data.children
@@ -15,7 +16,7 @@ const internalProducts = {}
1516

1617
for (const productId of productIds) {
1718
const relPath = productId
18-
const dir = path.posix.join('content', relPath)
19+
const dir = path.join(ROOT, 'content', relPath)
1920

2021
// Early Access may not exist in the current checkout
2122
try {

lib/constants.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
export const ROOT = process.env.ROOT || '.'
12
export const USER_LANGUAGE_COOKIE_NAME = 'user_language'
23
export const TRANSLATIONS_ROOT = process.env.TRANSLATIONS_ROOT || 'translations'

lib/languages.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import dotenv from 'dotenv'
66

7-
import { TRANSLATIONS_ROOT } from './constants.js'
7+
import { ROOT, TRANSLATIONS_ROOT } from './constants.js'
88
import path from 'path'
99

1010
dotenv.config()
@@ -21,7 +21,7 @@ const possibleEnvVars = {
2121
}
2222

2323
function getRoot(languageCode) {
24-
if (languageCode === 'en') return ''
24+
if (languageCode === 'en') return ROOT
2525
if (languageCode in possibleEnvVars) {
2626
const possibleEnvVar = possibleEnvVars[languageCode]
2727
if (possibleEnvVar) {

lib/redirects/precompile.js

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
1-
import path from 'path'
2-
import { fileURLToPath } from 'url'
3-
41
import { readCompressedJsonFileFallback } from '../read-json-file.js'
52
import getExceptionRedirects from './exception-redirects.js'
6-
73
import { latest } from '../enterprise-server-releases.js'
84

9-
const __dirname = path.dirname(fileURLToPath(import.meta.url))
10-
11-
const EXCEPTIONS_FILE = path.join(__dirname, './static/redirect-exceptions.txt')
5+
const EXCEPTIONS_FILE = './lib/redirects/static/redirect-exceptions.txt'
126

137
// This function runs at server warmup and precompiles possible redirect routes.
148
// It outputs them in key-value pairs within a neat Javascript object: { oldPath: newPath }

middleware/contextualizers/features.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import path from 'path'
2+
3+
import { ROOT } from '../../lib/constants.js'
14
import getApplicableVersions from '../../lib/get-applicable-versions.js'
25
import { getDeepDataByLanguage } from '../../lib/get-data.js'
36

@@ -29,7 +32,10 @@ function getFeaturesByVersion(currentVersion) {
2932
// Determine whether the currentVersion belongs to the list of versions the feature is available in.
3033
for (const [featureName, feature] of Object.entries(allFeatures)) {
3134
const { versions } = feature
32-
const applicableVersions = getApplicableVersions(versions, `data/features/${featureName}.yml`)
35+
const applicableVersions = getApplicableVersions(
36+
versions,
37+
path.join(ROOT, `data/features/${featureName}.yml`)
38+
)
3339

3440
// Adding the resulting boolean to the context object gives us the ability to use
3541
// `{% if featureName ... %}` conditionals in content files.

middleware/find-page.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import path from 'path'
22
import { existsSync } from 'fs'
33

4+
import { ROOT } from '../lib/constants.js'
45
import Page from '../lib/page.js'
56
import { languageKeys } from '../lib/languages.js'
67

78
const languagePrefixRegex = new RegExp(`^/(${languageKeys.join('|')})(/|$)`)
89
const englishPrefixRegex = /^\/en(\/|$)/
9-
const CONTENT_ROOT = 'content'
10+
const CONTENT_ROOT = path.join(ROOT, 'content')
1011

1112
export default async function findPage(
1213
req,

next.config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ import path from 'path'
33

44
import frontmatter from 'gray-matter'
55
import { languageKeys } from './lib/languages.js'
6+
import { ROOT } from './lib/constants.js'
67

7-
const homepage = path.posix.join(process.cwd(), 'content/index.md')
8+
const homepage = path.posix.join(ROOT, 'content/index.md')
89
const { data } = frontmatter(fs.readFileSync(homepage, 'utf8'))
910
const productIds = data.children
1011

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@
185185
"build": "next build",
186186
"debug": "cross-env NODE_ENV=development ENABLED_LANGUAGES=en nodemon --inspect server.js",
187187
"dev": "cross-env npm start",
188+
"fixture-dev": "cross-env ROOT=tests/fixtures npm start",
188189
"index-test-fixtures": "node script/search/index-elasticsearch.js -l en -l ja -V ghae -V dotcom --index-prefix tests -- tests/content/fixtures/search-indexes",
189190
"lint": "eslint '**/*.{js,mjs,ts,tsx}'",
190191
"lint-translation": "cross-env NODE_OPTIONS=--experimental-vm-modules jest tests/linting/lint-files.js",

script/copy-fixture-data.js

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#!/usr/bin/env node
2+
3+
// [start-readme]
4+
//
5+
// There are certain files that have to be manually copied from the
6+
// real data into the test fixture data.
7+
//
8+
// This script copies the files from `data/` into `tests/fitures/data/...`
9+
// that are files that are both needed for fixture testing yet can't
10+
// live with the code. For example, `data/ui.yml` is part of the rendering
11+
// code, but it lives in `data/` so it can be translated.
12+
//
13+
// [end-readme]
14+
15+
import fs from 'fs'
16+
import path from 'path'
17+
18+
import { program } from 'commander'
19+
import chalk from 'chalk'
20+
import mkdirp from 'mkdirp'
21+
22+
// Here, write down all the files that are actually part of the rendering
23+
// functionality yet live in data.
24+
const MANDATORY_FILES = [
25+
'data/ui.yml',
26+
'data/reusables/policies/translation.md',
27+
'data/reusables/enterprise_deprecation/deprecation_details.md',
28+
'data/reusables/enterprise_deprecation/version_was_deprecated.md',
29+
'data/reusables/enterprise_deprecation/version_will_be_deprecated.md',
30+
'data/variables/release_candidate.yml',
31+
]
32+
33+
const DESTINATION = path.resolve('tests/fixtures')
34+
35+
program
36+
.description('Make sure the test fixtures have up-to-date data from the real content')
37+
.option('--check', 'Exit non-zero if it had to actually do something')
38+
.option('--dry-run', "Don't actually write changes to disk")
39+
.option('-v, --verbose', 'Verbose outputs')
40+
.parse(process.argv)
41+
42+
main(program.opts())
43+
44+
async function main(opts) {
45+
let errors = 0
46+
for (const file of MANDATORY_FILES) {
47+
const source = fs.readFileSync(file, 'utf-8')
48+
const destination = path.join(DESTINATION, file)
49+
50+
if (opts.check) {
51+
// The destination has to exist and be identical
52+
try {
53+
const copied = fs.readFileSync(destination, 'utf-8')
54+
if (copied !== source) {
55+
// console.warn(chalk.red(`The file ${destination} is different from ${file}`))
56+
console.warn(`The file ${chalk.red(destination)} is different from ${chalk.red(file)}`)
57+
errors++
58+
} else if (opts.verbose) {
59+
console.log(`The file ${chalk.green(destination)} is up-to-date 🥰`)
60+
}
61+
} catch (error) {
62+
if (error.code === 'ENOENT') {
63+
console.warn(`The file ${chalk.red(destination)} does not exist`)
64+
errors++
65+
} else {
66+
throw error
67+
}
68+
}
69+
} else {
70+
try {
71+
const copied = fs.readFileSync(destination, 'utf-8')
72+
if (copied === source) {
73+
if (opts.verbose) {
74+
console.log(`The file ${chalk.green(destination)} was perfect already 👌`)
75+
}
76+
continue
77+
}
78+
} catch (error) {
79+
if (error.code !== 'ENOENT') throw error
80+
}
81+
if (!opts.dryRun) {
82+
await mkdirp(path.dirname(destination))
83+
fs.writeFileSync(destination, source, 'utf-8')
84+
if (opts.verbose) {
85+
console.log(`Copied latest ${chalk.green(file)} to ${chalk.bold(destination)} 👍🏼`)
86+
}
87+
} else if (opts.verbose) {
88+
console.log(`Would copy latest ${chalk.bold(file)} to ${chalk.bold(destination)}`)
89+
}
90+
}
91+
}
92+
93+
if (errors > 0) {
94+
console.warn(
95+
'\n',
96+
chalk.yellow(
97+
'Run this script again without --check to make all fixture data files up-to-date. ' +
98+
'Then commit and check in.'
99+
)
100+
)
101+
}
102+
103+
process.exitCode = errors
104+
}

0 commit comments

Comments
 (0)