1
0
mirror of synced 2026-01-07 09:01:31 -05:00

Merge pull request #32676 from github/repo-sync

Repo sync
This commit is contained in:
docs-bot
2024-04-25 15:58:06 -04:00
committed by GitHub
8 changed files with 211 additions and 1 deletions

View File

@@ -35,7 +35,8 @@ By default, the deployments page shows currently active deployments from select
1. In the right-hand sidebar of the home page of your repository, click **Deployments**.
1. Once you are on the "Deployments" page, you can view the following information about your deployment history.
- **To view recent deployments for a specific environment**, in the "Environments" section of the left sidebar, click an environment. {% ifversion deployment-dashboard-filter %}To pin an environment to the top of the deployment history list, click {% octicon "pin" aria-label="Pin environment" %} to the right of the environment.{% endif %}
- **To view recent deployments for a specific environment**, in the "Environments" section of the left sidebar, click an environment.{% ifversion deployment-dashboard-filter %}
- **To pin an environment to the top of the deployment history list**, repository administrators can click {% octicon "pin" aria-label="Pin environment" %} to the right of the environment. You can pin up to ten environments.{% endif %}
- **To view the commit that triggered a deployment**, in the deployment history list, click the commit message for the deployment you want to view.
>[!NOTE]Deployments from commits that originate from a fork outside of the repository will not show links to the source pull request and branch related to each deployment. For more information about forks, see "[AUTOTITLE](/pull-requests/collaborating-with-pull-requests/working-with-forks/about-forks)."
- **To view the URL for a deployment**, to the right of the commit message in the deployment history list, click {% octicon "link-external" aria-label="Navigate to deployment URL" %}.

View File

@@ -27,6 +27,7 @@ import wrapProceduralImages from './wrap-procedural-images.js'
import parseInfoString from './parse-info-string.js'
import annotate from './annotate.js'
import alerts from './alerts.js'
import replaceDomain from './replace-domain.js'
export function createProcessor(context) {
return (
@@ -44,6 +45,7 @@ export function createProcessor(context) {
.use(headingLinks)
.use(codeHeader)
.use(annotate)
.use(replaceDomain)
.use(highlight, {
languages: { ...common, graphql, dockerfile, http, groovy, erb, powershell },
subset: false,

View File

@@ -0,0 +1,43 @@
/**
* This makes it so that the `github.com` or `HOSTNAME` in a code snippet
* becomes replacable.
*/
import { visit } from 'unist-util-visit'
// Don't use `g` on these regexes
const VALID_REPLACEMENTS = [[/\bHOSTNAME\b/, 'HOSTNAME']]
const CODE_FENCE_KEYWORD = 'replacedomain'
const matcher = (node) => {
return (
node.type === 'element' &&
node.tagName === 'pre' &&
node.children[0]?.data?.meta[CODE_FENCE_KEYWORD]
)
}
export default function alerts() {
return (tree) => {
visit(tree, matcher, (node) => {
const code = node.children[0].children[0].value
let found = false
for (const [regex, replacement] of VALID_REPLACEMENTS) {
if (regex.test(code)) {
const codeTag = node.children[0]
const replacements = codeTag.properties['data-replacedomain'] || []
if (!replacements.includes(replacement)) {
replacements.push(replacement)
codeTag.properties['data-replacedomain'] = replacements
}
found = true
}
}
if (!found && process.env.NODE_ENV === 'development') {
console.warn("The code snippet doesn't contain a valid replacement", { code })
}
})
}
}

View File

@@ -10,4 +10,5 @@ children:
- /permissions
- /code-annotations
- /alerts
- /replace-domain
---

View File

@@ -0,0 +1,40 @@
---
title: Replace domain
intro: This demonstrates code snippets that have host names that can be replaced.
versions:
fpt: '*'
ghes: '*'
ghec: '*'
type: how_to
---
## Overview
If you have an article with code snippets that have the `replacedomain`
annotation on its code fence, that means the page *might* take the current
user's cookie (indicating their personal hostname) and replace that within
the code snippet.
## Shell code snippet (on)
```sh replacedomain
curl https://HOSTNAME/api/v1
```
## Shell code snippet (off)
```sh
curl https://HOSTNAME/api/v2
```
## JavaScript code snippet (on)
```js replacedomain
await fetch("https://HOSTNAME/api/v1")
```
## JavaScript code snippet (off)
```js
await fetch("https://HOSTNAME/api/v2")
```

View File

@@ -593,3 +593,35 @@ test.describe('translations', () => {
await expect(page).toHaveURL('/ja/get-started/start-your-journey/hello-world')
})
})
test.describe('view pages with custom domain cookie', () => {
test('view article page', async ({ page }) => {
await page.goto(
'/enterprise-server@latest/get-started/markdown/replace-domain?ghdomain=example.ghe.com',
)
const content = page.locator('pre')
await expect(content.nth(0)).toHaveText(/curl https:\/\/example.ghe.com\/api\/v1/)
await expect(content.nth(1)).toHaveText(/curl https:\/\/HOSTNAME\/api\/v2/)
await expect(content.nth(2)).toHaveText('await fetch("https://example.ghe.com/api/v1")')
await expect(content.nth(3)).toHaveText('await fetch("https://HOSTNAME/api/v2")')
// Now switch to enterprise-cloud, where replacedomain should not be used
await page.getByLabel('Select GitHub product version').click()
await page.getByLabel('Enterprise Cloud', { exact: true }).click()
await expect(content.nth(0)).toHaveText(/curl https:\/\/HOSTNAME\/api\/v1/)
await expect(content.nth(1)).toHaveText(/curl https:\/\/HOSTNAME\/api\/v2/)
await expect(content.nth(2)).toHaveText('await fetch("https://HOSTNAME/api/v1")')
await expect(content.nth(3)).toHaveText('await fetch("https://HOSTNAME/api/v2")')
// Again switch back to enterprise server again
await page.getByLabel('Select GitHub product version').click()
await page.getByLabel('Enterprise Server 3.').first().click()
await expect(content.nth(0)).toHaveText(/curl https:\/\/example.ghe.com\/api\/v1/)
await expect(content.nth(1)).toHaveText(/curl https:\/\/HOSTNAME\/api\/v2/)
await expect(content.nth(2)).toHaveText('await fetch("https://example.ghe.com/api/v1")')
await expect(content.nth(3)).toHaveText('await fetch("https://HOSTNAME/api/v2")')
})
})

View File

@@ -21,6 +21,7 @@ import { Breadcrumbs } from 'src/frame/components/page-header/Breadcrumbs'
import { Link } from 'src/frame/components/Link'
import { useTranslation } from 'src/languages/components/useTranslation'
import { LinkPreviewPopover } from 'src/links/components/LinkPreviewPopover'
import { ReplaceDomain } from 'src/links/components/replace-domain'
const ClientSideRefresh = dynamic(() => import('src/frame/components/ClientSideRefresh'), {
ssr: false,
@@ -103,6 +104,7 @@ export const ArticlePage = () => {
<LinkPreviewPopover />
{isDev && <ClientSideRefresh />}
{router.pathname.includes('/rest/') && <RestRedirect />}
<ReplaceDomain />
{currentLayout === 'inline' ? (
<>
<ArticleInlineLayout

View File

@@ -0,0 +1,89 @@
import { useEffect } from 'react'
import { useRouter } from 'next/router'
import { useVersion } from 'src/versions/components/useVersion'
import Cookies from 'src/frame/components/lib/cookies'
const COOKIE_KEY = 'github_domains'
// We only want to activate the replace-domain feature for these versions.
// This means that if you're on a version we don't want it activated on,
// even though you have a your-domain cookie, it *won't* replace the
// word HOSTNAME.
const REPLACEDOMAIN_VERSION_PREFIXES = ['enterprise-server@']
// This list needs to match what's in `unified/replace-domain.js`
const regexes = {
HOSTNAME: /\bHOSTNAME\b/g,
} as const
function replaceDomains(domain: string | null) {
document.querySelectorAll<HTMLElement>('pre code[data-replacedomain]').forEach((codeBlock) => {
const replaceDomain = codeBlock.dataset.replacedomain
if (!replaceDomain) return
const replaceDomains = replaceDomain.split(/\s/)
const spans = codeBlock.querySelectorAll<HTMLSpanElement>('span[class*="-string"]')
if (spans.length) {
spans.forEach((span) => {
replaceInTextContent(span, replaceDomains, domain)
})
} else {
replaceInTextContent(codeBlock, replaceDomains, domain)
}
})
}
function replaceInTextContent(
codeBlock: HTMLElement,
replaceDomains: string[],
domain: string | null,
) {
if (!codeBlock.textContent) return
for (const replaceDomain of replaceDomains) {
if (replaceDomain in regexes) {
// If the domain is falsy, it means we're reverting the replacement.
// This happens when you used to be on a version where we want to
// activate this functionality. Then, when you switch to a version
// where you don't want it, we need to revert the replacement to
// to what it was before we did the first replacement.
if (domain) {
const match = codeBlock.textContent.match(regexes[replaceDomain as keyof typeof regexes])
for (const matched of match || []) {
codeBlock.dataset.replacedomainOriginal = matched
codeBlock.dataset.replacedomainReplace = domain
}
codeBlock.textContent = codeBlock.textContent.replace(
regexes[replaceDomain as keyof typeof regexes],
domain,
)
} else {
if (codeBlock.dataset.replacedomainOriginal && codeBlock.dataset.replacedomainReplace) {
// Reverse it
codeBlock.textContent = codeBlock.textContent.replace(
codeBlock.dataset.replacedomainReplace,
codeBlock.dataset.replacedomainOriginal,
)
}
}
}
}
}
export function ReplaceDomain() {
const { asPath } = useRouter()
const { currentVersion } = useVersion()
const bother = REPLACEDOMAIN_VERSION_PREFIXES.some((prefix) => currentVersion.startsWith(prefix))
useEffect(() => {
const cookieValue = Cookies.get(COOKIE_KEY)
if (cookieValue) {
if (bother) {
replaceDomains(cookieValue.split(',')[0])
} else {
replaceDomains(null)
}
}
}, [asPath, bother])
return null
}