Skip to content

Commit 3b28c16

Browse files
author
Peter Bengtsson
authored
Redirect github-ae to enterprise-cloud or fpt or home page (#43460)
1 parent 454abd8 commit 3b28c16

File tree

14 files changed

+284
-59
lines changed

14 files changed

+284
-59
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"fixture-dev": "cross-env ROOT=src/fixtures/fixtures npm start",
3131
"fixture-test": "cross-env ROOT=src/fixtures/fixtures npm test -- src/fixtures/tests",
3232
"index-elasticsearch": "node src/search/scripts/index-elasticsearch.js",
33-
"index-test-fixtures": "npm run index-elasticsearch -- -l en -l ja -V ghae -V dotcom --index-prefix tests -- src/search/tests/fixtures/search-indexes",
33+
"index-test-fixtures": "npm run index-elasticsearch -- -l en -l ja -V ghec -V dotcom --index-prefix tests -- src/search/tests/fixtures/search-indexes",
3434
"lint": "eslint '**/*.{js,mjs,ts,tsx}'",
3535
"lint-content": "node src/content-linter/scripts/lint-content.js",
3636
"lint-translation": "cross-env NODE_OPTIONS=--experimental-vm-modules jest src/content-linter/tests/lint-files.js",

src/audit-logs/tests/rendering.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { expect } from '@jest/globals'
22

33
import { getDOM } from '#src/tests/helpers/e2etest.js'
4-
import { allVersions } from '#src/versions/lib/all-versions.js'
4+
import { allTestableVersions } from '#src/versions/lib/all-versions.js'
55
import { getAuditLogEvents } from '../lib/index.js'
66

77
describe('audit log events docs', () => {
@@ -26,7 +26,7 @@ describe('audit log events docs', () => {
2626
test.each(auditLogEventPages)(
2727
'loads audit log event data for all versions on page %o',
2828
async (page) => {
29-
for (const version in allVersions) {
29+
for (const version of allTestableVersions) {
3030
const auditLogEvents = getAuditLogEvents(page.type, version, true)
3131

3232
if (Object.keys(auditLogEvents).length === 0) {

src/languages/tests/frame.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,19 +86,27 @@ describe('release notes', () => {
8686
// Return an array of tuples for each language and each first version
8787
// per plan. E.g. ...
8888
// [
89+
// ['ja', 'enterprise-server@3.9'],
90+
// ['pt', 'enterprise-server@3.9'],
91+
// ...
8992
// ['ja', 'enterprise-server@3.8'],
9093
// ['pt', 'enterprise-server@3.8'],
9194
// ...
92-
// ['ja', 'github-ae@latest'],
93-
// ['pt', 'github-ae@latest'],
94-
// ...
9595
//
9696
// This is useful because if we test every single individual version of
9797
// every plan the test just takes way too long.
9898
const getReleaseNotesVersionCombinations = (langs) => {
9999
const combinations = []
100100
const prefixes = []
101101
for (const version of page.applicableVersions) {
102+
// Like a chicken-and-egg problem, we can't entirely remove
103+
// github-ae from the list of versions because first we
104+
// have to stop depending on it and clean up all front matter
105+
// and all Liquid. But we also shouldn't depend on testing it
106+
// any more since it always redirects to enterprise-cloud.
107+
if (version === 'github-ae@latest') {
108+
continue
109+
}
102110
const prefix = version.split('@')[0]
103111
if (prefixes.includes(prefix)) {
104112
continue

src/redirects/lib/get-redirect.js

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
supported,
88
deprecatedWithFunctionalRedirects,
99
} from '#src/versions/lib/enterprise-server-releases.js'
10-
import { getPathWithLanguage } from '#src/frame/lib/path-utils.js'
10+
import { getPathWithLanguage, getVersionStringFromPath } from '#src/frame/lib/path-utils.js'
1111

1212
const languagePrefixRegex = new RegExp(`^/(${languageKeys.join('|')})/`)
1313
const nonEnterpriseDefaultVersionPrefix = `/${nonEnterpriseDefaultVersion}`
@@ -30,6 +30,19 @@ export default function getRedirect(uri, context) {
3030

3131
const [language, withoutLanguage] = splitPathByLanguage(uri, userLanguage)
3232

33+
if (withoutLanguage.startsWith('/github-ae@latest')) {
34+
// It has a different business logic that the rest because it's a
35+
// version that now will always redirect. Just a question of where to
36+
// exactly.
37+
const nonAERedirect = githubAERedirect(uri, context)
38+
if (nonAERedirect.includes('/github-ae@latest')) {
39+
// If this happened some redirect in there didn't completely
40+
// get away from github-ae.
41+
throw new Error('Still going to github-ae@latest URL')
42+
}
43+
return nonAERedirect
44+
}
45+
3346
let destination
3447

3548
// `redirects` is sourced from more than one thing. The primary use
@@ -182,6 +195,88 @@ export default function getRedirect(uri, context) {
182195
}
183196
}
184197

198+
function githubAERedirect(uri, context) {
199+
const { redirects, userLanguage, pages } = context
200+
201+
const [language, withoutLanguage] = splitPathByLanguage(uri, userLanguage)
202+
203+
// From now on, github-ae@latest redirects to enterprise-cloud or
204+
// fpt or the home page.
205+
const cloudEquivalent = uri.replace('/github-ae@latest', '/enterprise-cloud@latest')
206+
const fptEquivalent = uri.replace('/github-ae@latest', '')
207+
const withoutVersion = withoutLanguage.replace('/github-ae@latest', '')
208+
if (!withoutVersion) {
209+
// That means the version home page.
210+
// Don't even need to check if that exists.
211+
// But if it was without language, inject the language as
212+
// we go to the enterprise-cloud equivalent
213+
if (uri.startsWith('/github-ae@latest')) {
214+
return `/${language}${cloudEquivalent}`
215+
}
216+
return cloudEquivalent
217+
}
218+
219+
// What if the only missing thing is a language prefix, then
220+
// it's easy too.
221+
if (uri.startsWith('/github-ae@latest')) {
222+
const languageCloudEquivalent = `/${language}${cloudEquivalent}`
223+
if (languageCloudEquivalent in pages) {
224+
return languageCloudEquivalent
225+
}
226+
227+
const languageFptEquivalent = `/${language}${fptEquivalent}`
228+
if (languageFptEquivalent in pages) {
229+
return languageFptEquivalent
230+
}
231+
} else {
232+
// If you're here it means the URL did start with a language.
233+
if (cloudEquivalent in pages) {
234+
return cloudEquivalent
235+
}
236+
if (fptEquivalent in pages) {
237+
return fptEquivalent
238+
}
239+
}
240+
241+
// There are redirect exceptions the specifically spell out github-ae
242+
// in the redirect.
243+
const legacyRedirect = redirects[withoutLanguage]
244+
if (legacyRedirect && !legacyRedirect.includes('/github-ae@latest')) {
245+
if (legacyRedirect.includes('://')) {
246+
return legacyRedirect
247+
}
248+
return `/${language}${legacyRedirect}`
249+
}
250+
251+
// The `redirects` are "pure" and don't specific a specific version.
252+
// For example `/articles/stuff` to `/get-started/new/name`
253+
// We look for those and try enterprise-cloud in it.
254+
if (redirects[withoutVersion]) {
255+
const cloudCandidate = `/${language}/enterprise-cloud@latest${redirects[withoutVersion]}`
256+
if (cloudCandidate in pages) {
257+
return cloudCandidate
258+
}
259+
260+
const fptCandidate = `/${language}${redirects[withoutVersion]}`
261+
// The lookup of redirects might yield a versioned URL, whose version
262+
// might be github-ae or enterprise-server. Skip those.
263+
if (fptCandidate in pages) {
264+
const versionFromCandidate = getVersionStringFromPath(fptCandidate)
265+
if (
266+
!(
267+
versionFromCandidate.startsWith('enterprise-server@') ||
268+
versionFromCandidate === 'github-ae@latest'
269+
)
270+
) {
271+
return fptCandidate
272+
}
273+
}
274+
}
275+
276+
// Note that this includes completely unknown pages
277+
return `/${language}`
278+
}
279+
185280
// Over time, we've developed multiple ambiguous patterns of URLs
186281
// You can't simply assume that all `/admin/guides` should become
187282
// `/admin` for example.

src/redirects/lib/static/redirect-exceptions.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,16 @@
3636
- /enterprise-server@3.6/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning-for-a-repository
3737

3838
/github-ae@latest/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/configuring-advanced-setup-for-code-scanning
39-
- /github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning-for-a-repository
39+
- /enterprise-cloud@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning-for-a-repository
4040

4141
/billing/managing-your-github-billing-settings/redeeming-a-coupon
4242
- /enterprise-cloud@latest/billing/managing-your-github-billing-settings/redeeming-a-coupon
43+
44+
# Pages that existed *only* in github-ae need their equivalent
45+
/enterprise-cloud@latest/get-started/onboarding/getting-started-with-github-enterprise-cloud
46+
- /github-ae@latest/get-started/onboarding/getting-started-with-github-ae
47+
/enterprise-cloud@latest/admin/overview
48+
- /github-ae@latest/admin/overview/about-github-ae
49+
- /github-ae@latest/admin/overview/about-data-residency
50+
- /github-ae@latest/admin/overview/deploying-github-ae
51+
- /github-ae@latest/admin/overview/initializing-github-ae

src/redirects/tests/ghae.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* We entirely removed GHAE but we have to support legacy links.
3+
* We have some unit tests for this that tests the `getRedirect()` function.
4+
* These tests here are more end-to-end tests that spans middleware
5+
* (which internally uses `getRedirect()`).
6+
*
7+
* These tests are important to have because we intend (not done at the
8+
* time of authoring this test suite) entirely remove ghae from
9+
* the `allVersions` config object. When we do, we want to be certain that
10+
* legacy redirects still work.
11+
*/
12+
13+
import { head } from '#src/tests/helpers/e2etest.js'
14+
15+
describe('ghae redirects', () => {
16+
test('ghae home page', async () => {
17+
const res = await head('/en/github-ae@latest')
18+
expect(res.statusCode).toBe(301)
19+
expect(res.headers.location).toMatch('/en/enterprise-cloud@latest')
20+
})
21+
22+
test('ghae docset landing page', async () => {
23+
const res = await head('/en/github-ae@latest/get-started')
24+
expect(res.statusCode).toBe(301)
25+
expect(res.headers.location).toMatch('/en/enterprise-cloud@latest/get-started')
26+
})
27+
28+
test('search page', async () => {
29+
const res = await head('/en/github-ae@latest/search?query=git')
30+
expect(res.statusCode).toBe(301)
31+
expect(res.headers.location).toMatch('/en/enterprise-cloud@latest/search?query=git')
32+
})
33+
34+
test('ghae release notes', async () => {
35+
const res = await head('/en/github-ae@latest/admin/release-notes')
36+
expect(res.statusCode).toBe(301)
37+
// There is not an "equivalent" release notes page for enterprise-cloud
38+
expect(res.headers.location).toMatch('/en')
39+
})
40+
})

src/redirects/tests/unit/get-redirect.js

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@ describe('getRedirect basics', () => {
3535
pages: {},
3636
redirects: {},
3737
}
38-
expect(getRedirect('/github-ae@latest', ctx)).toBe('/en/github-ae@latest')
39-
4038
expect(getRedirect('/enterprise-cloud@latest', ctx)).toBe('/en/enterprise-cloud@latest')
4139

4240
expect(getRedirect('/enterprise-server@3.8', ctx)).toBe('/en/enterprise-server@3.8')
@@ -161,3 +159,86 @@ describe('getRedirect basics', () => {
161159
expect(getRedirect('/enterprise/3.0/foo', ctx)).toBe('/en/enterprise-server@3.0/foo')
162160
})
163161
})
162+
163+
describe('github-ae@latest', () => {
164+
it('home page should redirect to enterprise-cloud home page', () => {
165+
const ctx = {
166+
pages: {},
167+
redirects: {},
168+
}
169+
expect(getRedirect('/github-ae@latest', ctx)).toBe('/en/enterprise-cloud@latest')
170+
expect(getRedirect('/en/github-ae@latest', ctx)).toBe('/en/enterprise-cloud@latest')
171+
})
172+
it('should redirect to home page for admin/release-notes', () => {
173+
const ctx = {
174+
pages: {},
175+
redirects: {},
176+
}
177+
expect(getRedirect('/github-ae@latest/admin/release-notes', ctx)).toBe('/en')
178+
expect(getRedirect('/en/github-ae@latest/admin/release-notes', ctx)).toBe('/en')
179+
})
180+
it('a page that does exits, without correction, in enterprise-cloud', () => {
181+
const ctx = {
182+
pages: {
183+
'/en/enterprise-cloud@latest/foo': null,
184+
},
185+
redirects: {},
186+
}
187+
expect(getRedirect('/github-ae@latest/foo', ctx)).toBe('/en/enterprise-cloud@latest/foo')
188+
expect(getRedirect('/en/github-ae@latest/foo', ctx)).toBe('/en/enterprise-cloud@latest/foo')
189+
})
190+
it("a page that doesn't exist in enterprise-cloud but in FPT", () => {
191+
const ctx = {
192+
pages: {
193+
'/en/foo': true,
194+
},
195+
redirects: {},
196+
}
197+
expect(getRedirect('/github-ae@latest/foo', ctx)).toBe('/en/foo')
198+
expect(getRedirect('/en/github-ae@latest/foo', ctx)).toBe('/en/foo')
199+
})
200+
it("a page that doesn't exist in enterprise-cloud or in FPT", () => {
201+
const ctx = {
202+
pages: {
203+
'/en/foo': true,
204+
},
205+
redirects: {},
206+
}
207+
expect(getRedirect('/github-ae@latest/bar', ctx)).toBe('/en')
208+
expect(getRedirect('/en/github-ae@latest/bar', ctx)).toBe('/en')
209+
})
210+
it('a URL with legacy redirects, that redirects to enterprise-cloud', () => {
211+
const ctx = {
212+
pages: {
213+
'/en/foo': true,
214+
'/en/enterprise-cloud@latest/foo': true,
215+
},
216+
redirects: {
217+
'/food': '/foo',
218+
},
219+
}
220+
expect(getRedirect('/github-ae@latest/food', ctx)).toBe('/en/enterprise-cloud@latest/foo')
221+
expect(getRedirect('/en/github-ae@latest/food', ctx)).toBe('/en/enterprise-cloud@latest/foo')
222+
})
223+
it("a URL with legacy redirects, that can't redirect to enterprise-cloud", () => {
224+
const ctx = {
225+
pages: {
226+
'/en/foo': true,
227+
// Note the lack of an enterprise-cloud page here
228+
},
229+
redirects: {
230+
'/food': '/foo',
231+
},
232+
}
233+
expect(getRedirect('/github-ae@latest/food', ctx)).toBe('/en/foo')
234+
expect(getRedirect('/en/github-ae@latest/food', ctx)).toBe('/en/foo')
235+
})
236+
it('should 404 if nothing matches at all', () => {
237+
const ctx = {
238+
pages: {},
239+
redirects: {},
240+
}
241+
expect(getRedirect('/github-ae@latest/never/heard/of', ctx)).toBe('/en')
242+
expect(getRedirect('/en/github-ae@latest/never/heard/of', ctx)).toBe('/en')
243+
})
244+
})

src/release-notes/tests/release-notes-1.js

Lines changed: 8 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -46,51 +46,22 @@ describe('release notes', () => {
4646
).toBe(true)
4747
})
4848

49-
it('renders the release-notes layout for GitHub AE', async () => {
50-
const res = await get('/en/github-ae@latest/admin/release-notes')
51-
expect(res.statusCode).toBe(200)
52-
const $ = await getDOM('/en/github-ae@latest/admin/release-notes')
53-
expect($('h1').first().text()).toBe('GitHub AE release notes')
54-
const sectionTitleRegex = /GitHub AE \d\d?\.\d\d?/ // E.g., GitHub AE 3.3
55-
56-
const releaseNotesH2 = $('h2').first().text().trim()
57-
const sectionTitleMatch = sectionTitleRegex.test(releaseNotesH2)
58-
59-
expect(sectionTitleMatch).toBe(true)
60-
})
61-
6249
it('404 if a bogus version is requested', async () => {
6350
const res = await get('/en/enterprise-server@12345/admin/release-notes')
6451
expect(res.statusCode).toBe(404)
6552
})
6653

6754
it('404 if a the pathname only ends with the /release-notes', async () => {
68-
// enterprise-server
69-
{
70-
const res = await get(`/en/enterprise-server@latest/ANY/release-notes`, {
71-
followAllRedirects: true,
72-
})
73-
expect(res.statusCode).toBe(404)
74-
}
75-
// github-ae
76-
{
77-
const res = await get('/en/github-ae@latest/ANY/release-notes')
78-
expect(res.statusCode).toBe(404)
79-
}
55+
const res = await get(`/en/enterprise-server@latest/ANY/release-notes`, {
56+
followAllRedirects: true,
57+
})
58+
expect(res.statusCode).toBe(404)
8059
})
8160

8261
it('404 if a the pathname only ends with the /admin', async () => {
83-
// enterprise-server
84-
{
85-
const res = await get(`/en/enterprise-server@latest/ANY/admin`, {
86-
followAllRedirects: true,
87-
})
88-
expect(res.statusCode).toBe(404)
89-
}
90-
// github-ae
91-
{
92-
const res = await get('/en/github-ae@latest/ANY/admin')
93-
expect(res.statusCode).toBe(404)
94-
}
62+
const res = await get(`/en/enterprise-server@latest/ANY/admin`, {
63+
followAllRedirects: true,
64+
})
65+
expect(res.statusCode).toBe(404)
9566
})
9667
})

0 commit comments

Comments
 (0)