1
0
mirror of synced 2025-12-19 09:57:42 -05:00

Create & migrate a subject folder for Redirects (#39052)

This commit is contained in:
Tina Barfield
2023-07-17 09:50:04 -04:00
committed by GitHub
parent 36c2210f8c
commit 0e1dc7862a
40 changed files with 69 additions and 63 deletions

View File

@@ -11,5 +11,5 @@
# need these legacy redirects. Only the redirects from
# front-matter will be at play.
# These static redirects json files are notoriously large
echo '[]' > lib/redirects/static/archived-frontmatter-valid-urls.json
echo '{}' > lib/redirects/static/archived-redirects-from-213-to-217.json
echo '[]' > src/redirects/lib/static/archived-frontmatter-valid-urls.json
echo '{}' > src/redirects/lib/static/archived-redirects-from-213-to-217.json

View File

@@ -12,7 +12,7 @@ import { JSONFile } from 'lowdb/node'
import shortVersions from '../../middleware/contextualizers/short-versions.js'
import contextualize from '../../middleware/context.js'
import features from '../../middleware/contextualizers/features.js'
import getRedirect from '../../lib/get-redirect.js'
import getRedirect from '../../src/redirects/lib/get-redirect.js'
import warmServer from '../../lib/warm-server.js'
import { liquid } from '../../src/content-render/index.js'
import { deprecated } from '../../lib/enterprise-server-releases.js'

View File

@@ -53,6 +53,7 @@ jobs:
{ name: 'linting', path: 'src/content-linter/tests', },
{ name: 'observability', path: 'src/observability/tests' },
{ name: 'pageinfo', path: 'src/pageinfo/tests', },
{ name: 'redirects', path: 'src/redirects/tests', },
{ name: 'rendering', path: 'tests/rendering', },
{ name: 'rendering-fixtures', path: 'tests/rendering-fixtures', },
{ name: 'rest', path: 'src/rest/tests', },

View File

@@ -382,7 +382,7 @@ Sometimes you want to link to a Dotcom-only article in Enterprise content and yo
"[GitHub's Terms of Service](/free-pro-team@latest/github/site-policy/github-terms-of-service)"
```
Sometimes the canonical home of content moves outside the docs site. None of the links included in [`lib/redirects/external-sites.json`](/lib/redirects/external-sites.json) get rewritten. See [`contributing/redirects.md`](/contributing/redirects.md) for more info about this type of redirect.
Sometimes the canonical home of content moves outside the docs site. None of the links included in [`src/redirects/lib/external-sites.json`](/src/redirects/lib/external-sites.json) get rewritten. See [`contributing/redirects.md`](/contributing/redirects.md) for more info about this type of redirect.
### Legacy filepaths and redirects for links

View File

@@ -12,7 +12,7 @@ Sometimes we change the name of an article but want its old URL to redirect to i
### Automatic redirects for URLs that do not include a version
If a URL for a docs page is entered without a version segment (e.g., `https://docs.github.com/foo` instead of `https://docs.github.com/<version>/foo`), the site will automatically redirect it to the **first available version** of the page. The order of precedence is specified in `lib/all-versions.js`, where the current order is:
If a URL for a docs page is entered without a version segment (e.g., `https://docs.github.com/foo` instead of `https://docs.github.com/<version>/foo`), the site will automatically redirect it to the **first available version** of the page. The order of precedence is specified in `lib/all-versions.js`, where the current order is:
1. Free, Pro, & Team (`fpt`)
1. Enterprise Cloud (`ghec`)
@@ -25,11 +25,11 @@ If `foo.md` is available in Free, Pro, & Team, no redirect will occur because `f
### Redirects across versions
If you want the URL for one version of an article to redirect to a URL for another version, you must use [/lib/redirects/static/redirect-exceptions.txt](/lib/redirects/static/redirect-exceptions.txt) instead. For example, if you remove the Free, Pro, & Team (`fpt`) version of an article, the URL will [automatically redirect](#automatic-redirects-for-urls-that-do-not-include-a-version) to the next available version of the page. If you want it to redirect to a version that is **lower in the order of precedence**, or to a different page entirely, you must specify an exception.
If you want the URL for one version of an article to redirect to a URL for another version, you must use [/src/redirects/lib/static/redirect-exceptions.txt](/src/redirects/lib/static/redirect-exceptions.txt) instead. For example, if you remove the Free, Pro, & Team (`fpt`) version of an article, the URL will [automatically redirect](#automatic-redirects-for-urls-that-do-not-include-a-version) to the next available version of the page. If you want it to redirect to a version that is **lower in the order of precedence**, or to a different page entirely, you must specify an exception.
Another example: we removed the `ghes` version of "[Exporting member information for your organization](https://docs.github.com/en/organizations/managing-membership-in-your-organization/exporting-member-information-for-your-organization)," but we don't want URLs that include the `enterprise-server@<release>` version segment to 404. In order to redirect `ghes` URLs to another version (such as `ghec`), we need to add an exception.
Each entry in [the exceptions file](/lib/redirects/static/redirect-exceptions.txt) should start with the path you want to redirect _to_, including the version, followed by an unordered list of the paths you want to redirect _from_:
Each entry in [the exceptions file](/src/redirects/lib/static/redirect-exceptions.txt) should start with the path you want to redirect _to_, including the version, followed by an unordered list of the paths you want to redirect _from_:
```
/enterprise-cloud@latest/organizations/managing-membership-in-your-organization/exporting-member-information-for-your-organization
@@ -40,11 +40,11 @@ Each entry in [the exceptions file](/lib/redirects/static/redirect-exceptions.tx
## External redirects
Sometimes the canonical home of some content moves outside the help site. For these types of redirects, we add entries to [/lib/redirects/external-sites.json](/lib/redirects/external-sites.json).
Sometimes the canonical home of some content moves outside the help site. For these types of redirects, we add entries to [/src/redirects/lib/external-sites.json](/src/redirects/lib/external-sites.json).
## Custom redirects
We also have custom routing code that automatically creates redirects under the hood for things like moved Admin guide pages. This code lives in [/lib/redirects/get-old-paths-from-permalink.js](/lib/redirects/get-old-paths-from-permalink.js). All redirects for the site are compiled when the server starts by [/lib/redirects/precompile.js](/lib/redirects/precompile.js).
We also have custom routing code that automatically creates redirects under the hood for things like moved Admin guide pages. This code lives in [/src/redirects/lib/get-old-paths-from-permalink.js](/src/redirects/lib/get-old-paths-from-permalink.js). All redirects for the site are compiled when the server starts by [/src/redirects/lib/precompile.js](/src/redirects/lib/precompile.js).
See [Links and image paths](../content/README.md#links-and-image-paths) for info on how links and images are rewritten on the fly at page render time.

View File

@@ -1,5 +1,5 @@
import { getLanguageCode } from './patterns.js'
import getRedirect from './get-redirect.js'
import getRedirect from '#src/redirects/lib/get-redirect.js'
export default function findPage(href, pages, redirects) {
if (Array.isArray(pages)) throw new Error("'pages' is not supposed to be an array")

View File

@@ -3,7 +3,7 @@ import path from 'path'
import cheerio from 'cheerio'
import patterns from './patterns.js'
import getApplicableVersions from './get-applicable-versions.js'
import generateRedirectsForPermalinks from './redirects/permalinks.js'
import generateRedirectsForPermalinks from '#src/redirects/lib/permalinks.js'
import getEnglishHeadings from './get-english-headings.js'
import getTocItems from './get-toc-items.js'
import pathUtils from './path-utils.js'

View File

@@ -13,10 +13,10 @@ import {
getPathWithoutVersion,
getVersionStringFromPath,
} from './path-utils.js'
import loadRedirects from './redirects/precompile.js'
import loadRedirects from '#src/redirects/lib/precompile.js'
import patterns from './patterns.js'
import { loadUnversionedTree, loadPages, loadPageMap } from './page-data.js'
import getRedirect, { splitPathByLanguage } from './get-redirect.js'
import getRedirect, { splitPathByLanguage } from '#src/redirects/lib/get-redirect.js'
import nonEnterpriseDefaultVersion from './non-enterprise-default-version.js'
import { deprecated } from './enterprise-server-releases.js'

View File

@@ -1,6 +1,6 @@
import statsd from '#src/observability/lib/statsd.js'
import { loadUnversionedTree, loadSiteTree, loadPages, loadPageMap } from './page-data.js'
import loadRedirects from './redirects/precompile.js'
import loadRedirects from '#src/redirects/lib/precompile.js'
// Instrument these functions so that
// it's wrapped in a timer that reports to Datadog

View File

@@ -15,7 +15,7 @@ import got from 'got'
import { readCompressedJsonFileFallbackLazily } from '../lib/read-json-file.js'
import { archivedCacheControl, languageCacheControl } from './cache-control.js'
import { pathLanguagePrefixed, languagePrefixPathRegex } from '../lib/languages.js'
import getRedirect, { splitPathByLanguage } from '../lib/get-redirect.js'
import getRedirect, { splitPathByLanguage } from '../src/redirects/lib/get-redirect.js'
import getRemoteJSON from './get-remote-json.js'
const REMOTE_ENTERPRISE_STORAGE_URL = 'https://githubdocs.azureedge.net/enterprise'
@@ -34,10 +34,10 @@ function splitByLanguage(uri) {
// `readJsonFileLazily()` function will, at import-time, check that
// the path does exist.
const archivedRedirects = readCompressedJsonFileFallbackLazily(
'./lib/redirects/static/archived-redirects-from-213-to-217.json',
'./src/redirects/lib/static/archived-redirects-from-213-to-217.json',
)
const archivedFrontmatterValidURLS = readCompressedJsonFileFallbackLazily(
'./lib/redirects/static/archived-frontmatter-valid-urls.json',
'./src/redirects/lib/static/archived-frontmatter-valid-urls.json',
)
// Combine all the things you need to make sure the response is

View File

@@ -21,8 +21,8 @@ import detectLanguage from './detect-language.js'
import reloadTree from './reload-tree.js'
import context from './context.js'
import shortVersions from './contextualizers/short-versions.js'
import languageCodeRedirects from './redirects/language-code-redirects.js'
import handleRedirects from './redirects/handle-redirects.js'
import languageCodeRedirects from '#src/redirects/middleware/language-code-redirects.js'
import handleRedirects from '#src/redirects/middleware/handle-redirects.js'
import findPage from './find-page.js'
import blockRobots from './block-robots.js'
import archivedEnterpriseVersionsAssets from './archived-enterprise-versions-assets.js'

View File

@@ -20,7 +20,7 @@ import languages, { languageKeys } from '../lib/languages.js'
import createTree from '../lib/create-tree.js'
import warmServer from '../lib/warm-server.js'
import { loadSiteTree, loadPages, loadPageMap } from '../lib/page-data.js'
import loadRedirects from '../lib/redirects/precompile.js'
import loadRedirects from '#src/redirects/lib/precompile.js'
const languagePrefixRegex = new RegExp(`^/(${languageKeys.join('|')})(/|$)`)
const englishPrefixRegex = /^\/en(\/|$)/

View File

@@ -5,7 +5,7 @@ import walk from 'walk-sync'
import frontmatter from '../../lib/read-frontmatter.js'
import { loadPages, loadPageMap } from '../../lib/page-data.js'
import patterns from '../../lib/patterns.js'
import loadRedirects from '../../lib/redirects/precompile.js'
import loadRedirects from '../../src/redirects/lib/precompile.js'
import { allVersionKeys } from '../../lib/all-versions.js'
// get all content and data files

View File

@@ -61,7 +61,7 @@ console.warn = console.error = (...args) => {
// Weird import syntax, but forces it to load after process.env... changes
const { languageKeys } = await import('../../lib/languages.js')
const { loadPages, loadPageMap } = await import('../../lib/page-data.js')
const { precompileRedirects } = await import('../../lib/redirects/precompile.js')
const { precompileRedirects } = await import('../../src/redirects/lib/precompile.js')
const { allVersions, allVersionKeys } = await import('../../lib/all-versions.js')
const { getProductStringFromPath } = await import('../../lib/path-utils.js')

View File

@@ -12,7 +12,7 @@ import { mkdirp } from 'mkdirp'
import { program } from 'commander'
import { execSync } from 'child_process'
import frontmatter from '../lib/read-frontmatter.js'
import addRedirectToFrontmatter from './helpers/add-redirect-to-frontmatter.js'
import addRedirectToFrontmatter from '../src/redirects/scripts/helpers/add-redirect-to-frontmatter.js'
import walkFiles from './helpers/walk-files.js'
const contentFiles = walkFiles('content', '.md')

View File

@@ -16,7 +16,7 @@ import GithubSlugger from 'github-slugger'
import { decode } from 'html-entities'
import frontmatter from '../lib/read-frontmatter.js'
import { execSync } from 'child_process'
import addRedirectToFrontmatter from './helpers/add-redirect-to-frontmatter.js'
import addRedirectToFrontmatter from '../src/redirects/scripts/helpers/add-redirect-to-frontmatter.js'
const slugger = new GithubSlugger()

View File

@@ -14,7 +14,7 @@ import findPage from '../../../lib/find-page.js'
const isProd = process.env.NODE_ENV === 'production'
const supportedPlans = new Set(Object.values(allVersions).map((v) => v.plan))
const externalRedirects = readJsonFile('./lib/redirects/external-sites.json')
const externalRedirects = readJsonFile('./src/redirects/lib/external-sites.json')
// Meaning it can be 'AUTOTITLE ' or ' AUTOTITLE' or 'AUTOTITLE'
const AUTOTITLE = /^\s*AUTOTITLE\s*$/

View File

@@ -14,7 +14,7 @@ import { program } from 'commander'
import { execFileSync } from 'child_process'
import frontmatter from '../../../lib/read-frontmatter.js'
import patterns from '../../../lib/patterns.js'
import addRedirectToFrontmatter from '../../../script/helpers/add-redirect-to-frontmatter.js'
import addRedirectToFrontmatter from '#src/redirects/scripts/helpers/add-redirect-to-frontmatter.js'
import walkFiles from '../../../script/helpers/walk-files.js'
const contentFiles = walkFiles('content', '.md', { includeEarlyAccess: true })

View File

@@ -17,7 +17,7 @@ import http from 'http'
import createApp from '../../../lib/app.js'
import EnterpriseServerReleases from '../../../lib/enterprise-server-releases.js'
import loadRedirects from '../../../lib/redirects/precompile.js'
import loadRedirects from '#src/redirects/lib/precompile.js'
import { loadPageMap } from '../../../lib/page-data.js'
import { languageKeys } from '../../../lib/languages.js'

View File

@@ -11,7 +11,7 @@ import {
import shortVersions from '../../middleware/contextualizers/short-versions.js'
import contextualize from '../../middleware/context.js'
import features from '../../middleware/contextualizers/features.js'
import getRedirect from '../../lib/get-redirect.js'
import getRedirect from '#src/redirects/lib/get-redirect.js'
import { isArchivedVersionByPath } from '../../lib/is-archived-version.js'
const router = express.Router()

View File

@@ -1,12 +1,12 @@
import { languageKeys } from './languages.js'
import nonEnterpriseDefaultVersion from './non-enterprise-default-version.js'
import { allVersions } from './all-versions.js'
import { languageKeys } from '../../../lib/languages.js'
import nonEnterpriseDefaultVersion from '../../../lib/non-enterprise-default-version.js'
import { allVersions } from '../../../lib/all-versions.js'
import {
latest,
supported,
deprecatedWithFunctionalRedirects,
} from './enterprise-server-releases.js'
import { getPathWithLanguage } from './path-utils.js'
} from '../../../lib/enterprise-server-releases.js'
import { getPathWithLanguage } from '../../../lib/path-utils.js'
const languagePrefixRegex = new RegExp(`^/(${languageKeys.join('|')})/`)
const nonEnterpriseDefaultVersionPrefix = `/${nonEnterpriseDefaultVersion}`

View File

@@ -1,5 +1,5 @@
import nonEnterpriseDefaultVersion from '../non-enterprise-default-version.js'
import { getPathWithoutVersion } from '../path-utils.js'
import nonEnterpriseDefaultVersion from '../../../lib/non-enterprise-default-version.js'
import { getPathWithoutVersion } from '../../../lib/path-utils.js'
export default function permalinkRedirects(permalinks, redirectFrom) {
const redirects = {}

View File

@@ -1,15 +1,17 @@
import { readCompressedJsonFileFallback } from '../read-json-file.js'
import { readCompressedJsonFileFallback } from '../../../lib/read-json-file.js'
import getExceptionRedirects from './exception-redirects.js'
import { latest } from '../enterprise-server-releases.js'
import { latest } from '../../../lib/enterprise-server-releases.js'
const EXCEPTIONS_FILE = './lib/redirects/static/redirect-exceptions.txt'
const EXCEPTIONS_FILE = './src/redirects/lib/static/redirect-exceptions.txt'
// This function runs at server warmup and precompiles possible redirect routes.
// It outputs them in key-value pairs within a neat Javascript object: { oldPath: newPath }
export async function precompileRedirects(pageList) {
const allRedirects = readCompressedJsonFileFallback('./lib/redirects/static/developer.json')
const allRedirects = readCompressedJsonFileFallback('./src/redirects/lib/static/developer.json')
const externalRedirects = readCompressedJsonFileFallback('./lib/redirects/external-sites.json')
const externalRedirects = readCompressedJsonFileFallback(
'./src/redirects/lib/external-sites.json',
)
Object.assign(allRedirects, externalRedirects)
// CURRENT PAGES PERMALINKS AND FRONTMATTER

View File

@@ -1,9 +1,9 @@
import patterns from '../../lib/patterns.js'
import patterns from '../../../lib/patterns.js'
import { URL } from 'url'
import { pathLanguagePrefixed } from '../../lib/languages.js'
import { deprecatedWithFunctionalRedirects } from '../../lib/enterprise-server-releases.js'
import getRedirect from '../../lib/get-redirect.js'
import { defaultCacheControl, languageCacheControl } from '../cache-control.js'
import { pathLanguagePrefixed } from '../../../lib/languages.js'
import { deprecatedWithFunctionalRedirects } from '../../../lib/enterprise-server-releases.js'
import getRedirect from '../lib/get-redirect.js'
import { defaultCacheControl, languageCacheControl } from '../../../middleware/cache-control.js'
export default function handleRedirects(req, res, next) {
// never redirect assets

View File

@@ -1,5 +1,5 @@
import languages from '../../lib/languages.js'
import { defaultCacheControl } from '../cache-control.js'
import languages from '../../../lib/languages.js'
import { defaultCacheControl } from '../../../middleware/cache-control.js'
const redirectPatterns = Object.values(languages)
.map((language) => language.redirectPatterns || [])

View File

@@ -2,8 +2,8 @@ import path from 'path'
import { jest } from '@jest/globals'
import { loadPages } from '../../lib/page-data.js'
import Permalink from '../../lib/permalink.js'
import { loadPages } from '../../../../lib/page-data.js'
import Permalink from '../../../../lib/permalink.js'
describe('redirect orphans', () => {
// Because calling `loadPages` will trigger a warmup, this can potentially

View File

@@ -1,8 +1,8 @@
import { jest } from '@jest/globals'
import path from 'path'
import enterpriseServerReleases from '../../lib/enterprise-server-releases.js'
import { get } from '../helpers/e2etest.js'
import readJsonFile from '../../lib/read-json-file.js'
import enterpriseServerReleases from '../../../../lib/enterprise-server-releases.js'
import { get } from '../../../../tests/helpers/e2etest.js'
import readJsonFile from '../../../../lib/read-json-file.js'
jest.useFakeTimers({ legacyFakeTimers: true })

View File

@@ -2,13 +2,13 @@ import { fileURLToPath } from 'url'
import path from 'path'
import { jest } from '@jest/globals'
import { get } from '../helpers/e2etest.js'
import getExceptionRedirects from '../../lib/redirects/exception-redirects.js'
import { latest } from '../../lib/enterprise-server-releases.js'
import { get } from '../../../../tests/helpers/e2etest.js'
import getExceptionRedirects from '../../lib/exception-redirects.js'
import { latest } from '../../../../lib/enterprise-server-releases.js'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const EXCEPTIONS_FILE = path.join(__dirname, '../../lib/redirects/static/redirect-exceptions.txt')
const EXCEPTIONS_FILE = path.join(__dirname, '../../lib/static/redirect-exceptions.txt')
describe('redirect exceptions', () => {
jest.setTimeout(5 * 60 * 1000)

View File

@@ -1,6 +1,6 @@
import { jest } from '@jest/globals'
import { head } from '../helpers/e2etest.js'
import { head } from '../../../../tests/helpers/e2etest.js'
jest.useFakeTimers({ legacyFakeTimers: true })

View File

@@ -1,17 +1,20 @@
import { jest } from '@jest/globals'
import { get } from '../helpers/e2etest.js'
import getExceptionRedirects from '../../lib/redirects/exception-redirects.js'
import { latest } from '../../lib/enterprise-server-releases.js'
import { get } from '../../../../tests/helpers/e2etest.js'
import getExceptionRedirects from '../../lib/exception-redirects.js'
import { latest } from '../../../../lib/enterprise-server-releases.js'
import path from 'path'
import { fileURLToPath } from 'url'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const VERSIONLESS_REDIRECTS_FILE = path.join(__dirname, '../fixtures/versionless-redirects.txt')
const VERSIONLESS_REDIRECTS_FILE = path.join(
__dirname,
'../../../../tests/fixtures/versionless-redirects.txt',
)
// This test checks the default versioning redirect fallbacks described in lib/all-versions.js.
// The fixture is a text file that formerly lived in lib/redirects/static/redirect-exceptions.txt.
// The fixture is a text file that formerly lived in /src/redirects/lib/static/redirect-exceptions.txt.
//
// (That exceptions file still exists but is much smaller now that we've added the default fallbacks.
// It only contains "true" exceptions now. Those are tested in tests/routing/redirect-exceptions.js.)

View File

@@ -1,7 +1,7 @@
import { describe, expect } from '@jest/globals'
import getRedirect from '../../lib/get-redirect.js'
import { latest, supported } from '../../lib/enterprise-server-releases.js'
import { latest, supported } from '../../../../lib/enterprise-server-releases.js'
const previousEnterpriserServerVersion = supported[1]
describe('getRedirect basics', () => {