Merge branch 'main' into patch-2
This commit is contained in:
@@ -165,8 +165,8 @@ jobs:
|
||||
rsync -rptovR ./user-code/components/./**/*.{ts,tsx} ./components
|
||||
rsync -rptovR --ignore-missing-args ./user-code/lib/./**/*.{js,ts} ./lib
|
||||
rsync -rptovR --ignore-missing-args ./user-code/middleware/./**/*.{js,ts} ./middleware
|
||||
rsync -rptovR ./user-code/pages/./**/*.{tsx} ./pages
|
||||
rsync -rptovR ./user-code/stylesheets/./**/*.{scss} ./stylesheets
|
||||
rsync -rptovR ./user-code/pages/./**/*.tsx ./pages
|
||||
rsync -rptovR ./user-code/stylesheets/./**/*.scss ./stylesheets
|
||||
|
||||
# In addition to making the final image smaller, we also save time by not sending unnecessary files to the docker build context
|
||||
- name: 'Prune for preview env'
|
||||
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
- name: move PR
|
||||
uses: alex-page/github-project-automation-plus@bb266ff4dde9242060e2d5418e120a133586d488
|
||||
with:
|
||||
project: Docs team reviews
|
||||
project: Docs open source board
|
||||
column: Triage
|
||||
repo-token: ${{ secrets.DOCUBOT_READORG_REPO_WORKFLOW_SCOPES }}
|
||||
|
||||
|
||||
5
.github/workflows/test.yml
vendored
5
.github/workflows/test.yml
vendored
@@ -132,6 +132,11 @@ jobs:
|
||||
- name: Run build script
|
||||
run: npm run build
|
||||
|
||||
- name: Warm possible disk caching
|
||||
env:
|
||||
NODE_ENV: test
|
||||
run: ./script/warm-before-tests.mjs
|
||||
|
||||
- name: Run tests
|
||||
env:
|
||||
DIFF_FILE: get_diff_files.txt
|
||||
|
||||
@@ -245,6 +245,15 @@ function initClipboardEvent() {
|
||||
})
|
||||
}
|
||||
|
||||
function initCopyButtonEvent() {
|
||||
document.documentElement.addEventListener('click', (evt) => {
|
||||
const target = evt.target as HTMLElement
|
||||
const button = target.closest('.js-btn-copy') as HTMLButtonElement
|
||||
if (!button) return
|
||||
sendEvent({ type: EventType.navigate, navigate_label: 'copy icon button' })
|
||||
})
|
||||
}
|
||||
|
||||
function initLinkEvent() {
|
||||
document.documentElement.addEventListener('click', (evt) => {
|
||||
const target = evt.target as HTMLElement
|
||||
@@ -267,6 +276,7 @@ export default function initializeEvents() {
|
||||
initPageAndExitEvent() // must come first
|
||||
initLinkEvent()
|
||||
initClipboardEvent()
|
||||
initCopyButtonEvent()
|
||||
initPrintEvent()
|
||||
// survey event in ./survey.js
|
||||
// experiment event in ./experiment.js
|
||||
|
||||
@@ -1,24 +1,62 @@
|
||||
import cx from 'classnames'
|
||||
import { CheckIcon, CopyIcon } from '@primer/octicons-react'
|
||||
import { Tooltip } from '@primer/react'
|
||||
|
||||
import useClipboard from 'components/hooks/useClipboard'
|
||||
|
||||
import styles from './CodeBlock.module.scss'
|
||||
|
||||
type Props = {
|
||||
verb?: string
|
||||
// Only Code samples should have a copy icon - if there's a headingLang it's a code sample
|
||||
headingLang?: string
|
||||
codeBlock: string
|
||||
highlight?: string
|
||||
}
|
||||
|
||||
export function CodeBlock({ verb, codeBlock, highlight }: Props) {
|
||||
export function CodeBlock({ verb, headingLang, codeBlock, highlight }: Props) {
|
||||
const [isCopied, setCopied] = useClipboard(codeBlock, {
|
||||
successDuration: 1400,
|
||||
})
|
||||
|
||||
return (
|
||||
<pre className={cx(styles.methodCodeBlock, 'rounded-1 border')} data-highlight={highlight}>
|
||||
<code>
|
||||
{verb && (
|
||||
<span className="color-bg-accent-emphasis color-fg-on-emphasis rounded-1 text-uppercase">
|
||||
{verb}
|
||||
</span>
|
||||
)}{' '}
|
||||
{codeBlock}
|
||||
</code>
|
||||
</pre>
|
||||
<div className="code-extra">
|
||||
{headingLang && (
|
||||
<header className="d-flex flex-justify-between flex-items-center p-2 text-small rounded-top-1 border">
|
||||
{headingLang === 'JavaScript' ? (
|
||||
<span>
|
||||
{headingLang} (
|
||||
<a className="text-underline" href="https://github.com/octokit/core.js#readme">
|
||||
@octokit/core.js
|
||||
</a>
|
||||
)
|
||||
</span>
|
||||
) : (
|
||||
`${headingLang}`
|
||||
)}
|
||||
<Tooltip direction="w" aria-label={isCopied ? 'Copied!' : 'Copy to clipboard'}>
|
||||
<button className="js-btn-copy btn-octicon" onClick={() => setCopied()}>
|
||||
{isCopied ? <CheckIcon /> : <CopyIcon />}
|
||||
</button>
|
||||
</Tooltip>
|
||||
</header>
|
||||
)}
|
||||
<pre
|
||||
className={cx(
|
||||
styles.methodCodeBlock,
|
||||
'd-flex flex-justify-between flex-items-center rounded-1 border'
|
||||
)}
|
||||
data-highlight={highlight}
|
||||
>
|
||||
<code>
|
||||
{verb && (
|
||||
<span className="color-bg-accent-emphasis color-fg-on-emphasis rounded-1 text-uppercase">
|
||||
{verb}
|
||||
</span>
|
||||
)}{' '}
|
||||
{codeBlock}
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -18,22 +18,10 @@ export function RestCodeSamples({ slug, xCodeSamples }: Props) {
|
||||
{xCodeSamples.map((sample, index) => {
|
||||
const sampleElements: JSX.Element[] = []
|
||||
if (sample.lang !== 'Ruby') {
|
||||
sampleElements.push(
|
||||
sample.lang === 'JavaScript' ? (
|
||||
<h5 key={`${sample.lang}-${index}`}>
|
||||
{sample.lang} (
|
||||
<a className="text-underline" href="https://github.com/octokit/core.js#readme">
|
||||
@octokit/core.js
|
||||
</a>
|
||||
)
|
||||
</h5>
|
||||
) : (
|
||||
<h5 key={`${sample.lang}-${index}`}>{sample.lang}</h5>
|
||||
)
|
||||
)
|
||||
sampleElements.push(
|
||||
<CodeBlock
|
||||
key={sample.lang + index}
|
||||
headingLang={sample.lang}
|
||||
codeBlock={sample.source}
|
||||
highlight={sample.lang === 'JavaScript' ? 'javascript' : 'curl'}
|
||||
></CodeBlock>
|
||||
|
||||
@@ -183,6 +183,7 @@ The `github` context contains information about the workflow run and the event t
|
||||
| `github.action_path` | `string` | The path where an action is located. This property is only supported in composite actions. You can use this path to access files located in the same repository as the action. |
|
||||
| `github.action_ref` | `string` | For a step executing an action, this is the ref of the action being executed. For example, `v2`. |
|
||||
| `github.action_repository` | `string` | For a step executing an action, this is the owner and repository name of the action. For example, `actions/checkout`. |
|
||||
| `github.action_status` | `string` | For a composite action, the current result of the composite action. |
|
||||
| `github.actor` | `string` | The username of the user that initiated the workflow run. |
|
||||
| `github.api_url` | `string` | The URL of the {% data variables.product.prodname_dotcom %} REST API. |
|
||||
| `github.base_ref` | `string` | The `base_ref` or target branch of the pull request in a workflow run. This property is only available when the event that triggers a workflow run is either `pull_request` or `pull_request_target`. |
|
||||
|
||||
@@ -156,7 +156,7 @@ We strongly recommend that actions use environment variables to access the files
|
||||
| `GITHUB_RUN_ID` | {% data reusables.actions.run_id_description %} For example, `1658821493`. |
|
||||
| `GITHUB_RUN_NUMBER` | {% data reusables.actions.run_number_description %} For example, `3`. |
|
||||
| `GITHUB_SERVER_URL`| The URL of the {% data variables.product.product_name %} server. For example: `https://{% data variables.product.product_url %}`.
|
||||
| `GITHUB_SHA` | The commit SHA that triggered the workflow. For example, `ffac537e6cbbf934b08745a378932722df287a53`. |
|
||||
| `GITHUB_SHA` | The commit SHA that triggered the workflow. The value of this commit SHA depends on the event that triggered the workflow. For more information, see [Events that trigger workflows](/actions/using-workflows/events-that-trigger-workflows). For example, `ffac537e6cbbf934b08745a378932722df287a53`. |
|
||||
| `GITHUB_WORKFLOW` | The name of the workflow. For example, `My test workflow`. If the workflow file doesn't specify a `name`, the value of this variable is the full path of the workflow file in the repository. |
|
||||
| `GITHUB_WORKSPACE` | The default working directory on the runner for steps, and the default location of your repository when using the [`checkout`](https://github.com/actions/checkout) action. For example, `/home/runner/work/my-repo-name/my-repo-name`. |
|
||||
{%- if actions-runner-arch-envvars %}
|
||||
|
||||
@@ -22,7 +22,6 @@ shortTitle: Recover an account with 2FA
|
||||
**Warnings**:
|
||||
|
||||
- {% data reusables.two_fa.support-may-not-help %}
|
||||
- {% data reusables.accounts.you-must-know-your-password %}
|
||||
|
||||
{% endwarning %}
|
||||
|
||||
@@ -32,7 +31,13 @@ shortTitle: Recover an account with 2FA
|
||||
|
||||
Use one of your recovery codes to automatically regain entry into your account. You may have saved your recovery codes to a password manager or your computer's downloads folder. The default filename for recovery codes is `github-recovery-codes.txt`. For more information about recovery codes, see "[Configuring two-factor authentication recovery methods](/authentication/securing-your-account-with-two-factor-authentication-2fa/configuring-two-factor-authentication-recovery-methods#downloading-your-two-factor-authentication-recovery-codes)."
|
||||
|
||||
{% data reusables.two_fa.username-password %}
|
||||
1. Type your username and password to prompt authentication.
|
||||
|
||||
{% warning %}
|
||||
|
||||
**Warning**: {% data reusables.accounts.you-must-know-your-password %}
|
||||
|
||||
{% endwarning %}
|
||||
|
||||
{% ifversion fpt or ghec %}
|
||||
1. Under "Having problems?", click **Use a recovery code or request a reset**.
|
||||
|
||||
@@ -31,6 +31,7 @@ includeGuides:
|
||||
- /code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/tracking-code-scanning-alerts-in-issues-using-task-lists
|
||||
- /code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/about-code-scanning
|
||||
- /code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/about-code-scanning-alerts
|
||||
- /code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/about-code-scanning-with-codeql
|
||||
- /code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning
|
||||
- /code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages
|
||||
- /code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/managing-code-scanning-alerts-for-your-repository
|
||||
@@ -38,6 +39,7 @@ includeGuides:
|
||||
- /code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/setting-up-code-scanning-for-a-repository
|
||||
- /code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/triaging-code-scanning-alerts-in-pull-requests
|
||||
- /code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/troubleshooting-the-codeql-workflow
|
||||
- /code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/viewing-code-scanning-logs
|
||||
- /code-security/code-scanning/integrating-with-code-scanning/about-integration-with-code-scanning
|
||||
- /code-security/code-scanning/integrating-with-code-scanning/sarif-support-for-code-scanning
|
||||
- /code-security/code-scanning/integrating-with-code-scanning/uploading-a-sarif-file-to-github
|
||||
@@ -45,6 +47,7 @@ includeGuides:
|
||||
- /code-security/code-scanning/using-codeql-code-scanning-with-your-existing-ci-system/configuring-codeql-cli-in-your-ci-system
|
||||
- /code-security/code-scanning/using-codeql-code-scanning-with-your-existing-ci-system/configuring-codeql-runner-in-your-ci-system
|
||||
- /code-security/code-scanning/using-codeql-code-scanning-with-your-existing-ci-system/installing-codeql-cli-in-your-ci-system
|
||||
- /code-security/code-scanning/using-codeql-code-scanning-with-your-existing-ci-system/migrating-from-the-codeql-runner-to-codeql-cli
|
||||
- /code-security/code-scanning/using-codeql-code-scanning-with-your-existing-ci-system/running-codeql-runner-in-your-ci-system
|
||||
- /code-security/code-scanning/using-codeql-code-scanning-with-your-existing-ci-system/troubleshooting-codeql-runner-in-your-ci-system
|
||||
- /code-security/repository-security-advisories/about-coordinated-disclosure-of-security-vulnerabilities
|
||||
@@ -58,6 +61,8 @@ includeGuides:
|
||||
- /code-security/repository-security-advisories/removing-a-collaborator-from-a-repository-security-advisory
|
||||
- /code-security/repository-security-advisories/withdrawing-a-repository-security-advisory
|
||||
- /code-security/security-overview/about-the-security-overview
|
||||
- /code-security/security-overview/filtering-alerts-in-the-security-overview
|
||||
- /code-security/security-overview/viewing-the-security-overview
|
||||
- /code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/about-dependabot-version-updates
|
||||
- /code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/automating-dependabot-with-github-actions
|
||||
- /code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/configuration-options-for-dependency-updates
|
||||
|
||||
@@ -8,17 +8,17 @@ featuredLinks:
|
||||
guides:
|
||||
- /code-security/getting-started/securing-your-repository
|
||||
- /code-security/getting-started/securing-your-organization
|
||||
- '{% ifversion fpt %}/code-security/repository-security-advisories/creating-a-repository-security-advisory{% endif %}'
|
||||
- '{% ifversion ghes or ghae %}/code-security/secure-coding/automatically-scanning-your-code-for-vulnerabilities-and-errors/setting-up-code-scanning-for-a-repository{% endif%}'
|
||||
- '{% ifversion fpt or ghec %}/code-security/repository-security-advisories/creating-a-repository-security-advisory{% endif %}'
|
||||
- '{% ifversion ghes or ghae %}/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/setting-up-code-scanning-for-a-repository{% endif%}'
|
||||
guideCards:
|
||||
- '{% ifversion fpt %}/code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/configuring-dependabot-security-updates{% endif %}'
|
||||
- '{% ifversion fpt %}/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/enabling-and-disabling-dependabot-version-updates{% endif %}'
|
||||
- '{% ifversion fpt %}/code-security/secure-coding/automatically-scanning-your-code-for-vulnerabilities-and-errors/setting-up-code-scanning-for-a-repository{% endif %}'
|
||||
- '{% ifversion ghes %}/code-security/supply-chain-security/understanding-your-software-supply-chain/exploring-the-dependencies-of-a-repository{% endif %}'
|
||||
- '{% ifversion ghes %}/code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/configuring-notifications-for-vulnerable-dependencies{% endif %}'
|
||||
- '{% ifversion ghes or ghae %}/code-security/secret-security/configuring-secret-scanning-for-your-repositories{% endif %}'
|
||||
- '{% ifversion ghae %}/code-security/secure-coding/integrating-with-code-scanning/uploading-a-sarif-file-to-github{% endif %}'
|
||||
- '{% ifversion ghae %}/code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system{% endif %}'
|
||||
- '{% ifversion fpt or ghec or ghes > 3.2 %}/code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/configuring-dependabot-security-updates{% endif %}'
|
||||
- '{% ifversion fpt or ghec or ghes > 3.2 %}/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/enabling-and-disabling-dependabot-version-updates{% endif %}'
|
||||
- '{% ifversion fpt or ghec or ghes > 3.2 %}/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/setting-up-code-scanning-for-a-repository{% endif %}'
|
||||
- '{% ifversion ghes < 3.3 %}/code-security/supply-chain-security/understanding-your-software-supply-chain/exploring-the-dependencies-of-a-repository{% endif %}'
|
||||
- '{% ifversion ghes < 3.3 %}/code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/configuring-notifications-for-vulnerable-dependencies{% endif %}'
|
||||
- '{% ifversion ghes < 3.3 or ghae %}/code-security/secret-scanning/configuring-secret-scanning-for-your-repositories{% endif %}'
|
||||
- '{% ifversion ghae %}/code-security/code-scanning/integrating-with-code-scanning/uploading-a-sarif-file-to-github{% endif %}'
|
||||
- '{% ifversion ghae %}/code-security/code-scanning/using-codeql-code-scanning-with-your-existing-ci-system{% endif %}'
|
||||
popular:
|
||||
- '{% ifversion ghes %}/admin/release-notes{% endif %}'
|
||||
- /code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/about-alerts-for-vulnerable-dependencies
|
||||
@@ -26,11 +26,11 @@ featuredLinks:
|
||||
- /code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/keeping-your-actions-up-to-date-with-dependabot
|
||||
- /code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/configuration-options-for-dependency-updates
|
||||
- /code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/managing-encrypted-secrets-for-dependabot
|
||||
- '{% ifversion ghae %}/code-security/secret-security/about-secret-scanning{% endif %}'
|
||||
- '{% ifversion ghae %}/code-security/secret-scanning/about-secret-scanning{% endif %}'
|
||||
- /code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/troubleshooting-the-detection-of-vulnerable-dependencies
|
||||
- '{% ifversion ghes or ghae %}/code-security/secure-coding/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages{% endif %}'
|
||||
- '{% ifversion ghes or ghae %}/code-security/secure-coding/automatically-scanning-your-code-for-vulnerabilities-and-errors/troubleshooting-the-codeql-workflow{% endif %}'
|
||||
- '{% ifversion ghes or ghae %}/code-security/secure-coding/automatically-scanning-your-code-for-vulnerabilities-and-errors/running-codeql-code-scanning-in-a-container{% endif %}'
|
||||
- '{% ifversion ghes < 3.3 or ghae %}/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages{% endif %}'
|
||||
- '{% ifversion ghes < 3.3 or ghae %}/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/troubleshooting-the-codeql-workflow{% endif %}'
|
||||
- '{% ifversion ghes < 3.3 or ghae %}/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/running-codeql-code-scanning-in-a-container{% endif %}'
|
||||
changelog:
|
||||
label: security-and-compliance
|
||||
versions:
|
||||
|
||||
@@ -22,7 +22,11 @@ An outside collaborator is a person who is not a member of your organization, bu
|
||||
|
||||
{% data reusables.organizations.outside-collaborators-use-seats %}
|
||||
|
||||
{% ifversion fpt %}
|
||||
Organizations that use {% data variables.product.prodname_ghe_cloud %} can restrict the ability to invite collaborators. For more information, see "[Setting permissions for adding outside collaborators](/enterprise-cloud@latest/organizations/managing-organization-settings/setting-permissions-for-adding-outside-collaborators)" in the {% data variables.product.prodname_ghe_cloud %} documentation.
|
||||
{% else %}
|
||||
An organization owner can restrict the ability to invite collaborators. For more information, see "[Setting permissions for adding outside collaborators](/organizations/managing-organization-settings/setting-permissions-for-adding-outside-collaborators)."
|
||||
{% endif %}
|
||||
|
||||
{% ifversion ghes %}
|
||||
Before you can add someone as an outside collaborator on a repository, the person must have a user account on {% data variables.product.product_location %}. If your enterprise uses an external authentication system such as SAML or LDAP, the person you want to add must sign in through that system to create an account. If the person does not have access to the authentication system and built-in authentication is enabled for your enterprise, a site admin can create a user account for the person. For more information, see "[Using built-in authentication](/admin/authentication/authenticating-users-for-your-github-enterprise-server-instance/using-built-in-authentication#inviting-users)."
|
||||
@@ -32,10 +36,6 @@ Before you can add someone as an outside collaborator on a repository, the perso
|
||||
If your organization requires two-factor authentication, all outside collaborators must enable two-factor authentication before accepting your invitation to collaborate on a repository. For more information, see "[Requiring two-factor authentication in your organization](/organizations/keeping-your-organization-secure/managing-two-factor-authentication-for-your-organization/requiring-two-factor-authentication-in-your-organization)."
|
||||
{% endif %}
|
||||
|
||||
{% ifversion fpt %}
|
||||
To further support your team's collaboration abilities, you can upgrade to {% data variables.product.prodname_ghe_cloud %}, which includes features like protected branches and code owners on private repositories. {% data reusables.enterprise.link-to-ghec-trial %}
|
||||
{% endif %}
|
||||
|
||||
## Adding outside collaborators to a repository
|
||||
|
||||
{% ifversion fpt or ghec or ghes > 3.3 or ghae-issue-5974 %}
|
||||
|
||||
@@ -22,8 +22,6 @@ You can use this information to help off-board people, gather data for complianc
|
||||
|
||||
{% ifversion fpt %}
|
||||
Organizations that use {% data variables.product.prodname_ghe_cloud %} can also export a CSV list of people who have access to a repository. For more information, see [the {% data variables.product.prodname_ghe_cloud %} documentation](/enterprise-cloud@latest/organizations/managing-access-to-your-organizations-repositories/viewing-people-with-access-to-your-repository).
|
||||
|
||||
{% data reusables.enterprise.link-to-ghec-trial %}
|
||||
{% endif %}
|
||||
|
||||
{% ifversion fpt or ghec or ghes > 3.3 or ghae-issue-5974 %}
|
||||
@@ -44,6 +42,14 @@ You can see a combined overview of teams and people with access to your reposito
|
||||
{% ifversion ghec or ghes or ghae %}
|
||||
## Exporting a list of people with access to your repository
|
||||
|
||||
{% ifversion ghec %}
|
||||
{% note %}
|
||||
|
||||
**Note:** Only organizations that use {% data variables.product.prodname_ghe_cloud %} can export a list of people with access to a repository. {% data reusables.enterprise.link-to-ghec-trial %}
|
||||
|
||||
{% endnote %}
|
||||
{% endif %}
|
||||
|
||||
{% data reusables.repositories.navigate-to-repo %}
|
||||
{% data reusables.repositories.accessing-repository-graphs %}
|
||||
{% data reusables.repositories.accessing-repository-people %}
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
---
|
||||
title: Setting permissions for adding outside collaborators
|
||||
intro: 'To protect your organization''s data and the number of paid licenses used in your organization, you can allow only owners to invite outside collaborators to organization repositories.'
|
||||
product: '{% data reusables.gated-features.restrict-add-collaborator %}'
|
||||
redirect_from:
|
||||
- /articles/restricting-the-ability-to-add-outside-collaborators-to-organization-repositories
|
||||
- /articles/setting-permissions-for-adding-outside-collaborators
|
||||
- /github/setting-up-and-managing-organizations-and-teams/setting-permissions-for-adding-outside-collaborators
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
ghae: '*'
|
||||
ghec: '*'
|
||||
@@ -17,7 +15,16 @@ topics:
|
||||
shortTitle: Set collaborator policy
|
||||
---
|
||||
|
||||
Organization owners, and members with admin privileges for a repository, can invite outside collaborators to work on the repository. You can also restrict outside collaborator invite permissions to only organization owners.
|
||||
By default, anyone with admin access to a repository can invite outside collaborators to work on the repository. You can choose to restrict the ability to invite outside collaborators to organization owners only.
|
||||
|
||||
|
||||
{% ifversion ghec %}
|
||||
{% note %}
|
||||
|
||||
**Note:** Only organizations that use {% data variables.product.prodname_ghe_cloud %} can restrict the ability to invite outside collaborators to organization owners. {% data reusables.enterprise.link-to-ghec-trial %}
|
||||
|
||||
{% endnote %}
|
||||
{% endif %}
|
||||
|
||||
{% data reusables.organizations.outside-collaborators-use-seats %}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ For more information on reviewing pull requests in {% data variables.product.pro
|
||||
|
||||
{% data reusables.dependency-review.beta %}
|
||||
|
||||
If the pull request contains changes to dependencies you can use the dependency review for a manifest or lock file to see what has changed and check whether the changes introduce security vulnerabilities. For more information, see "[Reviewing dependency changes in a pull request](/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/incorporating-feedback-in-your-pull-request)."
|
||||
If the pull request contains changes to dependencies you can use the dependency review for a manifest or lock file to see what has changed and check whether the changes introduce security vulnerabilities. For more information, see "[Reviewing dependency changes in a pull request](/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/reviewing-dependency-changes-in-a-pull-request)."
|
||||
|
||||
{% data reusables.repositories.changed-files %}
|
||||
|
||||
|
||||
@@ -322,6 +322,7 @@ Take care to distinguish between product names and product elements. For more in
|
||||
| Product | Element |
|
||||
| --- | --- |
|
||||
| GitHub Actions | an action |
|
||||
| GitHub Codespaces | a codespace |
|
||||
| GitHub Packages | a package |
|
||||
| GitHub Pages | a GitHub Pages site |
|
||||
|
||||
@@ -594,7 +595,7 @@ Avoid ending a sentence with a preposition unless the rewritten sentence would s
|
||||
|
||||
### Product names
|
||||
|
||||
See the “Product names” section of this guide.
|
||||
See the “[Product names](#product-names)” section of this guide.
|
||||
|
||||
### Terms to use or avoid
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
security_advisories:
|
||||
title: 'Fix and disclose a security vulnerability'
|
||||
description: 'Using repository security advisories to privately fix a reported vulnerability and get a CVE.'
|
||||
featured_track: '{% ifversion fpt %}true{% else %}false{% endif %}'
|
||||
featured_track: '{% ifversion fpt or ghec %}true{% else %}false{% endif %}'
|
||||
guides:
|
||||
- /code-security/repository-security-advisories/about-coordinated-disclosure-of-security-vulnerabilities
|
||||
- /code-security/repository-security-advisories/creating-a-repository-security-advisory
|
||||
@@ -13,32 +13,32 @@ security_advisories:
|
||||
- /code-security/repository-security-advisories/withdrawing-a-repository-security-advisory
|
||||
- /code-security/repository-security-advisories/removing-a-collaborator-from-a-repository-security-advisory
|
||||
|
||||
# Feature available on dotcom and GHES
|
||||
# Feature available on dotcom and GHES 3.3+, so articles available on GHAE and earlier GHES hidden to hide the learning track
|
||||
dependabot_alerts:
|
||||
title: 'Get notifications for vulnerable dependencies'
|
||||
description: 'Set up Dependabot to alert you to new vulnerabilities in your dependencies.'
|
||||
guides:
|
||||
- /code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/about-alerts-for-vulnerable-dependencies
|
||||
- '{% ifversion not ghae %}/github/administering-a-repository/managing-repository-settings/managing-security-and-analysis-settings-for-your-repository{% endif %}'
|
||||
- '{% ifversion fpt or ghec or ghes > 3.2 %}/github/administering-a-repository/managing-repository-settings/managing-security-and-analysis-settings-for-your-repository{% endif %}'
|
||||
- /code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/viewing-and-updating-vulnerable-dependencies-in-your-repository
|
||||
- /code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/configuring-notifications-for-vulnerable-dependencies
|
||||
- /code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/managing-pull-requests-for-dependency-updates
|
||||
- /code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/troubleshooting-the-detection-of-vulnerable-dependencies
|
||||
- /code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/troubleshooting-dependabot-errors
|
||||
|
||||
# Feature available only on dotcom, so articles available hidden to hide the learning track in other versions
|
||||
# Feature available on dotcom and GHES 3.3+, so articles available on GHAE and earlier GHES hidden to hide the learning track
|
||||
dependabot_security_updates:
|
||||
title: 'Get pull requests to update your vulnerable dependencies'
|
||||
description: 'Set up Dependabot to create pull requests when new vulnerabilities are reported.'
|
||||
guides:
|
||||
- /code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/about-dependabot-security-updates
|
||||
- /code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/configuring-dependabot-security-updates
|
||||
- '{% ifversion fpt %}/code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/configuring-notifications-for-vulnerable-dependencies{% endif %}'
|
||||
- '{% ifversion fpt %}/github/administering-a-repository/managing-repository-settings/managing-security-and-analysis-settings-for-your-repository{% endif %}'
|
||||
- '{% ifversion fpt or ghec or ghes > 3.2 %}/code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/configuring-notifications-for-vulnerable-dependencies{% endif %}'
|
||||
- '{% ifversion fpt or ghec or ghes > 3.2 %}/github/administering-a-repository/managing-repository-settings/managing-security-and-analysis-settings-for-your-repository{% endif %}'
|
||||
- /code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/managing-pull-requests-for-dependency-updates
|
||||
- '{% ifversion fpt %}/code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/troubleshooting-the-detection-of-vulnerable-dependencies{% endif %}'
|
||||
- '{% ifversion fpt or ghec or ghes > 3.2 %}/code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/troubleshooting-the-detection-of-vulnerable-dependencies{% endif %}'
|
||||
|
||||
# Feature available only on dotcom
|
||||
# Feature available only on dotcom and GHES 3.3+
|
||||
dependency_version_updates:
|
||||
title: 'Keep your dependencies up-to-date'
|
||||
description: 'Use Dependabot to check for new releases and create pull requests to update your dependencies.'
|
||||
@@ -54,32 +54,34 @@ dependency_version_updates:
|
||||
- /code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/managing-pull-requests-for-dependency-updates
|
||||
- /code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/troubleshooting-dependabot-errors
|
||||
|
||||
# Feature available in all versions from GHES 3.0 up
|
||||
# Feature available in GHEC, GHES 3.0 up, and GHAE. Feature limited on FPT so hidden there.
|
||||
secret_scanning:
|
||||
title: 'Scan for secrets'
|
||||
description: 'Set up secret scanning to guard against accidental check-ins of tokens, passwords, and other secrets to your repository.'
|
||||
guides:
|
||||
- /code-security/secret-scanning/about-secret-scanning
|
||||
- /code-security/secret-scanning/configuring-secret-scanning-for-your-repositories
|
||||
- /code-security/secret-scanning/defining-custom-patterns-for-secret-scanning
|
||||
- /code-security/secret-scanning/managing-alerts-from-secret-scanning
|
||||
- '{% ifversion not fpt %}/code-security/secret-scanning/about-secret-scanning{% endif %}'
|
||||
- '{% ifversion not fpt %}/code-security/secret-scanning/configuring-secret-scanning-for-your-repositories{% endif %}'
|
||||
- '{% ifversion not fpt %}/code-security/secret-scanning/defining-custom-patterns-for-secret-scanning{% endif %}'
|
||||
- '{% ifversion not fpt %}/code-security/secret-scanning/managing-alerts-from-secret-scanning{% endif %}'
|
||||
- '{% ifversion not fpt %}/code-security/secret-scanning/secret-scanning-patterns{% endif %}'
|
||||
|
||||
# Security overview feature available only on dotcom currently, so other articles hidden to hide the learning path in other versions
|
||||
# Security overview feature available in GHEC and GHES 3.2+, so other articles hidden to hide the learning path in other versions
|
||||
security_alerts:
|
||||
title: 'Explore and manage security alerts'
|
||||
description: 'Learn where to find and resolve security alerts.'
|
||||
guides:
|
||||
- /code-security/security-overview/about-the-security-overview
|
||||
- '{% ifversion fpt %}/code-security/secret-scanning/managing-alerts-from-secret-scanning {% endif %}'
|
||||
- '{% ifversion fpt %}/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/managing-code-scanning-alerts-for-your-repository{% endif %}'
|
||||
- '{% ifversion fpt %}/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/triaging-code-scanning-alerts-in-pull-requests{% endif %}'
|
||||
- '{% ifversion fpt %}/code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/viewing-and-updating-vulnerable-dependencies-in-your-repository{% endif %}'
|
||||
- '{% ifversion ghec or ghes > 3.1 %}/code-security/security-overview/about-the-security-overview {% endif %}'
|
||||
- '{% ifversion ghec or ghes > 3.1 %}/code-security/security-overview/viewing-the-security-overview {% endif %}'
|
||||
- '{% ifversion ghec or ghes > 3.1 %}/code-security/secret-scanning/managing-alerts-from-secret-scanning {% endif %}'
|
||||
- '{% ifversion ghec or ghes > 3.1 %}/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/managing-code-scanning-alerts-for-your-repository{% endif %}'
|
||||
- '{% ifversion ghec or ghes > 3.1 %}/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/triaging-code-scanning-alerts-in-pull-requests{% endif %}'
|
||||
- '{% ifversion ghec or ghes > 3.1 %}/code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/viewing-and-updating-vulnerable-dependencies-in-your-repository{% endif %}'
|
||||
|
||||
# Feature available in all versions from GHES 2.22 up
|
||||
code_security_actions:
|
||||
title: 'Run code scanning with GitHub Actions'
|
||||
description: 'Check your default branch and every pull request to keep vulnerabilities and errors out of your repository.'
|
||||
featured_track: '{% ifversion ghae or ghes > 2.22 %}true{% else %}false{% endif %}'
|
||||
featured_track: '{% ifversion ghae or ghes %}true{% else %}false{% endif %}'
|
||||
guides:
|
||||
- /code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/about-code-scanning
|
||||
- /code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/setting-up-code-scanning-for-a-repository
|
||||
@@ -106,6 +108,5 @@ code_security_ci:
|
||||
- /code-security/code-scanning/using-codeql-code-scanning-with-your-existing-ci-system/about-codeql-code-scanning-in-your-ci-system
|
||||
- /code-security/code-scanning/using-codeql-code-scanning-with-your-existing-ci-system/installing-codeql-cli-in-your-ci-system
|
||||
- /code-security/code-scanning/using-codeql-code-scanning-with-your-existing-ci-system/configuring-codeql-cli-in-your-ci-system
|
||||
- /code-security/code-scanning/using-codeql-code-scanning-with-your-existing-ci-system/running-codeql-runner-in-your-ci-system
|
||||
- /code-security/code-scanning/using-codeql-code-scanning-with-your-existing-ci-system/configuring-codeql-runner-in-your-ci-system
|
||||
- /code-security/code-scanning/using-codeql-code-scanning-with-your-existing-ci-system/migrating-from-the-codeql-runner-to-codeql-cli
|
||||
- /code-security/code-scanning/using-codeql-code-scanning-with-your-existing-ci-system/troubleshooting-codeql-runner-in-your-ci-system
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
- GitHub Actions
|
||||
|
||||
# Security policies
|
||||
- title: Microsoft security policy
|
||||
- title: Microsoft security policy template
|
||||
description: Example security policy
|
||||
href: /microsoft/microsoft.github.io/blob/master/SECURITY.MD
|
||||
href: https://github.com/microsoft/repo-templates/blob/main/shared/SECURITY.md
|
||||
tags:
|
||||
- Security policy
|
||||
- title: Electron security policy
|
||||
@@ -50,8 +50,9 @@
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghec: '*'
|
||||
ghes: '>=3.3'
|
||||
|
||||
# Dependabot configuration only relevant to GitHub.com
|
||||
# Dependabot configuration only relevant to GitHub.com and GHES 3.3+
|
||||
# Convert "languages" to "package-ecosystems" for Dependabot configurations
|
||||
- title: Super linter configuration
|
||||
description: Example Dependabot version updates configuration from the Super linter repository.
|
||||
@@ -69,6 +70,7 @@
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghec: '*'
|
||||
ghes: '>=3.3'
|
||||
|
||||
- title: Dependabot version update PR
|
||||
description: Example pull request generated by the Dependabot version updates configuration in the Super linter repository.
|
||||
@@ -81,3 +83,4 @@
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghec: '*'
|
||||
ghes: '>=3.3'
|
||||
|
||||
@@ -1 +1 @@
|
||||
If you protect your personal account with two-factor authentication but do not know your password, you will not be able to generate a one-time password to recover your account. {% data variables.product.company_short %} can send a password reset email to a verified address associated with your account. For more information, see "[Updating your {% data variables.product.prodname_dotcom %} access credentials](/authentication/keeping-your-account-and-data-secure/updating-your-github-access-credentials#requesting-a-new-password)."
|
||||
If you protect your personal account with two-factor authentication but do not know your password, you will not be able to follow these steps to recover your account. {% data variables.product.company_short %} can send a password reset email to a verified address associated with your account. For more information, see "[Updating your {% data variables.product.prodname_dotcom %} access credentials](/authentication/keeping-your-account-and-data-secure/updating-your-github-access-credentials#requesting-a-new-password)."
|
||||
|
||||
@@ -5,7 +5,7 @@ Use the `branches` filter when you want to include branch name patterns or when
|
||||
|
||||
Use the `tags` filter when you want to include tag name patterns or when you want to both include and exclude tag names patterns. Use the `tags-ignore` filter when you only want to exclude tag name patterns. You cannot use both the `tags` and `tags-ignore` filters for the same event in a workflow.
|
||||
|
||||
If you define only `tags`/`tag-ignore` or only `branches`/`branches-ignore`, the workflow won't run for events affecting the undefined Git ref. If you define neither `tags`/`tag-ignore` or `branches`/`branches-ignore`, the workflow will run for events affecting either branches or tags. If you define both `branches`/`branches-ignore` and [`paths`](#onpushpull_requestpull_request_targetpathspaths-ignore), the workflow will only run when both filters are satisfied.
|
||||
If you define only `tags`/`tags-ignore` or only `branches`/`branches-ignore`, the workflow won't run for events affecting the undefined Git ref. If you define neither `tags`/`tags-ignore` or `branches`/`branches-ignore`, the workflow will run for events affecting either branches or tags. If you define both `branches`/`branches-ignore` and [`paths`](#onpushpull_requestpull_request_targetpathspaths-ignore), the workflow will only run when both filters are satisfied.
|
||||
|
||||
The `branches`, `branches-ignore`, `tags`, and `tags-ignore` keywords accept glob patterns that use characters like `*`, `**`, `+`, `?`, `!` and others to match more than one branch or tag name. If a name contains any of these characters and you want a literal match, you need to *escape* each of these special characters with `\`. For more information about glob patterns, see the "[Filter pattern cheat sheet](/actions/using-workflows/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet)."
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
Restricting the ability to add outside collaborators to owners is available with {% data variables.product.prodname_ghe_cloud %}. For more information, see "[GitHub's products](/articles/githubs-products)."
|
||||
@@ -1,5 +1,5 @@
|
||||
You can manage permissions and policies for a number of different actions and features in your organization.
|
||||
|
||||
For example, to protect your organization's data and number of paid licenses, you can choose to allow only organization owners to invite outside collaborators to organization repositories. You can also choose to allow or prevent the forking of private repositories owned by your organization. For more information, see "[Setting permissions for adding outside collaborators](/organizations/managing-organization-settings/setting-permissions-for-adding-outside-collaborators)" and "[Managing the forking policy for your organization](/organizations/managing-organization-settings/managing-the-forking-policy-for-your-organization)."
|
||||
For example, to protect your organization's data, you can restrict repository creation in your organization. You can also choose to allow or prevent the forking of private repositories owned by your organization. For more information, see "[Restricting repository creation in your organization](/organizations/managing-organization-settings/restricting-repository-creation-in-your-organization)" and "[Managing the forking policy for your organization](/organizations/managing-organization-settings/managing-the-forking-policy-for-your-organization)."
|
||||
|
||||
For the full list of settings you can configure for your organization, see "[Managing organization settings](/organizations/managing-organization-settings)."
|
||||
|
||||
@@ -90,6 +90,7 @@ contribution_cta:
|
||||
products:
|
||||
graphql:
|
||||
reference:
|
||||
implements: Implements
|
||||
fields: Fields
|
||||
arguments: Arguments
|
||||
name: Name
|
||||
|
||||
@@ -14,8 +14,18 @@ export const next = '3.5'
|
||||
export const nextNext = '3.6'
|
||||
|
||||
export const supported = ['3.4', '3.3', '3.2', '3.1']
|
||||
|
||||
// This indicates the point where we started treating redirect lookups
|
||||
// to be a *function* rather than a big *lookup object*.
|
||||
// This is important distinguish because we need to leverage that
|
||||
// when dealing with redirects specifically in these archived
|
||||
// enterprise versions.
|
||||
// When you're archiving a version, add the new archived number to this
|
||||
// array and you should never need to touch the `deprecated` array
|
||||
// on the line just below.
|
||||
export const deprecatedWithFunctionalRedirects = ['3.0']
|
||||
export const deprecated = [
|
||||
'3.0',
|
||||
...deprecatedWithFunctionalRedirects,
|
||||
'2.22',
|
||||
'2.21',
|
||||
'2.20',
|
||||
|
||||
@@ -2,21 +2,32 @@ import { languageKeys } from './languages.js'
|
||||
import nonEnterpriseDefaultVersion from './non-enterprise-default-version.js'
|
||||
|
||||
import { allVersions } from './all-versions.js'
|
||||
import { latest, supported } from './enterprise-server-releases.js'
|
||||
import {
|
||||
latest,
|
||||
supported,
|
||||
deprecatedWithFunctionalRedirects,
|
||||
} from './enterprise-server-releases.js'
|
||||
|
||||
const languagePrefixRegex = new RegExp(`^/(${languageKeys.join('|')})/`)
|
||||
const nonEnterpriseDefaultVersionPrefix = `/${nonEnterpriseDefaultVersion}`
|
||||
|
||||
// Return the new URI if there is one, otherwise return undefined.
|
||||
export default function getRedirect(uri, context) {
|
||||
const { redirects, userLanguage } = context
|
||||
const supportedAndRecentlyDeprecated = [...supported, ...deprecatedWithFunctionalRedirects]
|
||||
|
||||
export function splitPathByLanguage(uri, userLanguage) {
|
||||
let language = userLanguage || 'en'
|
||||
let withoutLanguage = uri
|
||||
if (languagePrefixRegex.test(uri)) {
|
||||
language = uri.match(languagePrefixRegex)[1]
|
||||
withoutLanguage = uri.replace(languagePrefixRegex, '/')
|
||||
}
|
||||
return [language, withoutLanguage]
|
||||
}
|
||||
|
||||
// Return the new URI if there is one, otherwise return undefined.
|
||||
export default function getRedirect(uri, context) {
|
||||
const { redirects, userLanguage } = context
|
||||
|
||||
const [language, withoutLanguage] = splitPathByLanguage(uri, userLanguage)
|
||||
|
||||
let destination
|
||||
|
||||
@@ -54,7 +65,6 @@ export default function getRedirect(uri, context) {
|
||||
if (withoutLanguage === '/enterprise-server') {
|
||||
return basicCorrection
|
||||
}
|
||||
// console.log({ basicCorrection })
|
||||
} else if (withoutLanguage.startsWith('/enterprise-server@latest')) {
|
||||
// E.g. '/enterprise-server@latest' or '/enterprise-server@latest/3.3/foo'
|
||||
basicCorrection =
|
||||
@@ -67,9 +77,9 @@ export default function getRedirect(uri, context) {
|
||||
}
|
||||
} else if (
|
||||
withoutLanguage.startsWith('/enterprise/') &&
|
||||
supported.includes(withoutLanguage.split('/')[2])
|
||||
supportedAndRecentlyDeprecated.includes(withoutLanguage.split('/')[2])
|
||||
) {
|
||||
// E.g. '/enterprise/3.3' or '/enterprise/3.3/foo'
|
||||
// E.g. '/enterprise/3.3' or '/enterprise/3.3/foo' or '/enterprise/3.0/foo
|
||||
|
||||
// If the URL is without a language, and no redirect is necessary,
|
||||
// but it has as version prefix, the language has to be there
|
||||
|
||||
@@ -440,3 +440,9 @@
|
||||
- /github/administering-a-repository/managing-alerts-from-secret-scanning
|
||||
- /code-security/secret-security/managing-alerts-from-secret-scanning
|
||||
- /code-security/secret-scanning/managing-alerts-from-secret-scanning
|
||||
|
||||
/enterprise-cloud@latest/organizations/managing-organization-settings/setting-permissions-for-adding-outside-collaborators
|
||||
- /articles/restricting-the-ability-to-add-outside-collaborators-to-organization-repositories
|
||||
- /articles/setting-permissions-for-adding-outside-collaborators
|
||||
- /github/setting-up-and-managing-organizations-and-teams/setting-permissions-for-adding-outside-collaborators
|
||||
- /organizations/managing-organization-settings/setting-permissions-for-adding-outside-collaborators
|
||||
@@ -1,3 +1,5 @@
|
||||
import fs from 'fs'
|
||||
import os from 'os'
|
||||
import path from 'path'
|
||||
import flat from 'flat'
|
||||
import { get, set } from 'lodash-es'
|
||||
@@ -5,17 +7,42 @@ import languages from './languages.js'
|
||||
import dataDirectory from './data-directory.js'
|
||||
import encodeBracketedParentheses from './encode-bracketed-parentheses.js'
|
||||
|
||||
const loadSiteDataFromDir = (dir) => ({
|
||||
site: {
|
||||
data: dataDirectory(path.join(dir, 'data'), {
|
||||
preprocess: (dataString) => encodeBracketedParentheses(dataString.trimEnd()),
|
||||
ignorePatterns: [/README\.md$/],
|
||||
}),
|
||||
},
|
||||
const TEMP_DIRECTORY = process.env.RUNNER_TEMP || os.tmpdir()
|
||||
|
||||
function diskMemoize(prefix, fn) {
|
||||
const useCache = process.env.NODE_ENV !== 'development'
|
||||
return (dir) => {
|
||||
const cacheFileName = `${prefix}.${dir.replace(/[^\w]+/g, '-').toLowerCase() || 'en'}.json`
|
||||
if (useCache) {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(cacheFileName, 'utf-8'))
|
||||
} catch (err) {
|
||||
if (!(err.code === 'ENOENT' || err instanceof SyntaxError)) throw err
|
||||
}
|
||||
}
|
||||
|
||||
const result = fn(dir)
|
||||
if (useCache) {
|
||||
fs.writeFileSync(cacheFileName, JSON.stringify(result), 'utf-8')
|
||||
console.log(`Disk-cache miss on ${cacheFileName}`, new Date())
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
const loadSiteDataFromDir = diskMemoize(path.join(TEMP_DIRECTORY, 'docs-site-data'), (dir) => {
|
||||
return {
|
||||
site: {
|
||||
data: dataDirectory(path.join(dir, 'data'), {
|
||||
preprocess: (dataString) => encodeBracketedParentheses(dataString.trimEnd()),
|
||||
ignorePatterns: [/README\.md$/],
|
||||
}),
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
export default function loadSiteData() {
|
||||
// load english site data
|
||||
// load English site data
|
||||
const siteData = {
|
||||
en: loadSiteDataFromDir(languages.en.dir),
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import statsd from '../lib/statsd.js'
|
||||
import {
|
||||
firstVersionDeprecatedOnNewSite,
|
||||
lastVersionWithoutArchivedRedirectsFile,
|
||||
deprecatedWithFunctionalRedirects,
|
||||
} from '../lib/enterprise-server-releases.js'
|
||||
import patterns from '../lib/patterns.js'
|
||||
import versionSatisfiesRange from '../lib/version-satisfies-range.js'
|
||||
@@ -13,6 +14,7 @@ import got from 'got'
|
||||
import { readCompressedJsonFileFallbackLazily } from '../lib/read-json-file.js'
|
||||
import { cacheControlFactory } from './cache-control.js'
|
||||
import { pathLanguagePrefixed, languagePrefixPathRegex } from '../lib/languages.js'
|
||||
import getRedirect, { splitPathByLanguage } from '../lib/get-redirect.js'
|
||||
|
||||
function splitByLanguage(uri) {
|
||||
let language = null
|
||||
@@ -35,6 +37,7 @@ const archivedFrontmatterFallbacks = readCompressedJsonFileFallbackLazily(
|
||||
)
|
||||
|
||||
const cacheControl = cacheControlFactory(60 * 60 * 24 * 365)
|
||||
const noCacheControl = cacheControlFactory(0)
|
||||
|
||||
// Combine all the things you need to make sure the response is
|
||||
// aggresively cached.
|
||||
@@ -99,6 +102,39 @@ export default async function archivedEnterpriseVersions(req, res, next) {
|
||||
|
||||
const redirectCode = pathLanguagePrefixed(req.path) ? 301 : 302
|
||||
|
||||
if (deprecatedWithFunctionalRedirects.includes(requestedVersion)) {
|
||||
const redirectTo = getRedirect(req.path, req.context)
|
||||
if (redirectTo) {
|
||||
if (redirectCode === 301) {
|
||||
cacheControl(res)
|
||||
} else {
|
||||
noCacheControl(res)
|
||||
}
|
||||
res.removeHeader('set-cookie')
|
||||
return res.redirect(redirectCode, redirectTo)
|
||||
}
|
||||
|
||||
const redirectJson = await getRemoteJSON(getProxyPath('redirects.json', requestedVersion), {
|
||||
retry: retryConfiguration,
|
||||
// This is allowed to be different compared to the other requests
|
||||
// we make because downloading the `redirects.json` once is very
|
||||
// useful because it caches so well.
|
||||
// And, as of 2021 that `redirects.json` is 10MB so it's more likely
|
||||
// to time out.
|
||||
timeout: 1000,
|
||||
})
|
||||
const [language, withoutLanguage] = splitPathByLanguage(req.path, req.context.userLanguage)
|
||||
const newRedirectTo = redirectJson[withoutLanguage]
|
||||
if (newRedirectTo) {
|
||||
if (redirectCode === 301) {
|
||||
cacheControl(res)
|
||||
} else {
|
||||
noCacheControl(res)
|
||||
}
|
||||
res.removeHeader('set-cookie')
|
||||
return res.redirect(redirectCode, `/${language}${newRedirectTo}`)
|
||||
}
|
||||
}
|
||||
// redirect language-prefixed URLs like /en/enterprise/2.10 -> /enterprise/2.10
|
||||
// (this only applies to versions <2.13)
|
||||
if (
|
||||
@@ -135,7 +171,10 @@ export default async function archivedEnterpriseVersions(req, res, next) {
|
||||
}
|
||||
}
|
||||
|
||||
if (versionSatisfiesRange(requestedVersion, `>${lastVersionWithoutArchivedRedirectsFile}`)) {
|
||||
if (
|
||||
versionSatisfiesRange(requestedVersion, `>${lastVersionWithoutArchivedRedirectsFile}`) &&
|
||||
!deprecatedWithFunctionalRedirects.includes(requestedVersion)
|
||||
) {
|
||||
const redirectJson = await getRemoteJSON(getProxyPath('redirects.json', requestedVersion), {
|
||||
retry: retryConfiguration,
|
||||
// This is allowed to be different compared to the other requests
|
||||
|
||||
22
script/warm-before-tests.mjs
Executable file
22
script/warm-before-tests.mjs
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// [start-readme]
|
||||
//
|
||||
// It runs the warmServer() function because that function can do things
|
||||
// like writing to disk as a caching mechanism.
|
||||
// When jest runs tests, it starts multiple concurrent processes,
|
||||
// even if it runs it serially (`--runInBand`) so it's highly likely
|
||||
// that two concurrent processes both attempt to writing to
|
||||
// the same exact file. By running this script before anything
|
||||
// begins, we can be certain that files that should have been created
|
||||
// are created.
|
||||
//
|
||||
// [end-readme]
|
||||
|
||||
import warmServer from '../lib/warm-server.js'
|
||||
|
||||
main()
|
||||
|
||||
async function main() {
|
||||
await warmServer()
|
||||
}
|
||||
@@ -17,13 +17,7 @@ const slugger = new GithubSlugger()
|
||||
const contentDir = path.join(__dirname, '../../content')
|
||||
|
||||
describe('category pages', () => {
|
||||
let siteData
|
||||
|
||||
beforeAll(async () => {
|
||||
// Load the English site data
|
||||
const allSiteData = await loadSiteData()
|
||||
siteData = allSiteData.en.site
|
||||
})
|
||||
const siteData = loadSiteData().en.site
|
||||
|
||||
const walkOptions = {
|
||||
globs: ['*/index.md', 'enterprise/*/index.md'],
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import loadSiteData from '../../lib/site-data.js'
|
||||
|
||||
describe('glossaries', () => {
|
||||
let glossaries
|
||||
beforeAll(async () => {
|
||||
glossaries = (await loadSiteData()).en.site.data.glossaries
|
||||
})
|
||||
const glossaries = loadSiteData().en.site.data.glossaries
|
||||
|
||||
test('are broken into external, internal, and candidates', async () => {
|
||||
const keys = Object.keys(glossaries)
|
||||
@@ -41,7 +38,7 @@ describe('glossaries', () => {
|
||||
})
|
||||
|
||||
test('non-English external glossary is in correct order', async () => {
|
||||
const vals = (await loadSiteData()).ja.site.data.glossaries.external
|
||||
const vals = loadSiteData().ja.site.data.glossaries.external
|
||||
vals.forEach((val, i) => {
|
||||
expect(val.term.localeCompare(vals[i + 1], 'ja')).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
@@ -11,17 +11,12 @@ import { jest } from '@jest/globals'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const siteData = loadSiteData()
|
||||
const pages = (await loadPages()).filter((page) => page.languageCode === 'en')
|
||||
|
||||
describe('data references', () => {
|
||||
jest.setTimeout(60 * 1000)
|
||||
|
||||
let data, pages
|
||||
|
||||
beforeAll(async () => {
|
||||
data = await loadSiteData()
|
||||
pages = await loadPages()
|
||||
pages = pages.filter((page) => page.languageCode === 'en')
|
||||
})
|
||||
|
||||
test('every data reference found in English content files is defined and has a value', () => {
|
||||
let errors = []
|
||||
expect(pages.length).toBeGreaterThan(0)
|
||||
@@ -30,7 +25,7 @@ describe('data references', () => {
|
||||
const file = path.join('content', page.relativePath)
|
||||
const pageRefs = getDataReferences(page.markdown)
|
||||
pageRefs.forEach((key) => {
|
||||
const value = get(data.en, key)
|
||||
const value = get(siteData.en, key)
|
||||
if (typeof value !== 'string') errors.push({ key, value, file })
|
||||
})
|
||||
})
|
||||
@@ -50,7 +45,7 @@ describe('data references', () => {
|
||||
const { data: metadata } = frontmatter(fileContents, { filepath: page.fullPath })
|
||||
const metadataRefs = getDataReferences(JSON.stringify(metadata))
|
||||
metadataRefs.forEach((key) => {
|
||||
const value = get(data.en, key)
|
||||
const value = get(siteData.en, key)
|
||||
if (typeof value !== 'string') errors.push({ key, value, metadataFile })
|
||||
})
|
||||
})
|
||||
@@ -62,7 +57,7 @@ describe('data references', () => {
|
||||
|
||||
test('every data reference found in English reusable files is defined and has a value', async () => {
|
||||
let errors = []
|
||||
const allReusables = data.en.site.data.reusables
|
||||
const allReusables = siteData.en.site.data.reusables
|
||||
const reusables = Object.values(allReusables)
|
||||
expect(reusables.length).toBeGreaterThan(0)
|
||||
|
||||
@@ -78,7 +73,7 @@ describe('data references', () => {
|
||||
const reusableRefs = getDataReferences(JSON.stringify(reusablesPerFile))
|
||||
|
||||
reusableRefs.forEach((key) => {
|
||||
const value = get(data.en, key)
|
||||
const value = get(siteData.en, key)
|
||||
if (typeof value !== 'string') errors.push({ key, value, reusableFile })
|
||||
})
|
||||
})
|
||||
@@ -90,7 +85,7 @@ describe('data references', () => {
|
||||
|
||||
test('every data reference found in English variable files is defined and has a value', async () => {
|
||||
let errors = []
|
||||
const allVariables = data.en.site.data.variables
|
||||
const allVariables = siteData.en.site.data.variables
|
||||
const variables = Object.values(allVariables)
|
||||
expect(variables.length).toBeGreaterThan(0)
|
||||
|
||||
@@ -106,7 +101,7 @@ describe('data references', () => {
|
||||
const variableRefs = getDataReferences(JSON.stringify(variablesPerFile))
|
||||
|
||||
variableRefs.forEach((key) => {
|
||||
const value = get(data.en, key)
|
||||
const value = get(siteData.en, key)
|
||||
if (typeof value !== 'string') errors.push({ key, value, variableFile })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
import { fileURLToPath } from 'url'
|
||||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
import { get, isPlainObject, has } from 'lodash-es'
|
||||
import flat from 'flat'
|
||||
import walkSync from 'walk-sync'
|
||||
import { ParseError } from 'liquidjs'
|
||||
import loadSiteData from '../../lib/site-data.js'
|
||||
import patterns from '../../lib/patterns.js'
|
||||
import { liquid } from '../../lib/render-content/index.js'
|
||||
import walkSync from 'walk-sync'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
describe('siteData module (English)', () => {
|
||||
let data
|
||||
beforeAll(async () => {
|
||||
data = await loadSiteData()
|
||||
})
|
||||
const data = loadSiteData()
|
||||
|
||||
test('makes an object', async () => {
|
||||
expect(isPlainObject(data)).toBe(true)
|
||||
@@ -49,21 +45,6 @@ describe('siteData module (English)', () => {
|
||||
expect(reusable.includes('任意のページの左上で')).toBe(true)
|
||||
})
|
||||
|
||||
test('backfills missing translated site data with English values', async () => {
|
||||
const newFile = path.join(__dirname, '../../data/newfile.yml')
|
||||
fs.writeFileSync(newFile, 'newvalue: bar')
|
||||
try {
|
||||
const data = loadSiteData()
|
||||
expect(get(data, 'en.site.data.newfile.newvalue')).toEqual('bar')
|
||||
expect(get(data, 'ja.site.data.newfile.newvalue')).toEqual('bar')
|
||||
} finally {
|
||||
// If an error is thrown above, it will still "bubble up"
|
||||
// to the jest reporter, but we still always need to clean up
|
||||
// the temporary file.
|
||||
fs.unlinkSync(newFile)
|
||||
}
|
||||
})
|
||||
|
||||
test('all Liquid tags are valid', async () => {
|
||||
const dataMap = flat(data)
|
||||
for (const key in dataMap) {
|
||||
|
||||
@@ -25,6 +25,7 @@ import allowedVersionOperators from '../../lib/liquid-tags/ifversion-supported-o
|
||||
import semver from 'semver'
|
||||
import { jest } from '@jest/globals'
|
||||
import { getDiffFiles } from '../helpers/diff-files.js'
|
||||
import loadSiteData from '../../lib/site-data.js'
|
||||
|
||||
jest.useFakeTimers('legacy')
|
||||
|
||||
@@ -410,6 +411,9 @@ if (
|
||||
|
||||
describe('lint markdown content', () => {
|
||||
if (mdToLint.length < 1) return
|
||||
|
||||
const siteData = loadSiteData()
|
||||
|
||||
describe.each(mdToLint)('%s', (markdownRelPath, markdownAbsPath) => {
|
||||
let content,
|
||||
ast,
|
||||
@@ -453,12 +457,14 @@ describe('lint markdown content', () => {
|
||||
}
|
||||
})
|
||||
|
||||
const context = { site: siteData.en.site }
|
||||
|
||||
// visit is not async-friendly so we need to do an async map to parse the YML snippets
|
||||
yamlScheduledWorkflows = (
|
||||
await Promise.all(
|
||||
yamlScheduledWorkflows.map(async (snippet) => {
|
||||
// If we don't parse the Liquid first, yaml loading chokes on {% raw %} tags
|
||||
const rendered = await renderContent.liquid.parseAndRender(snippet)
|
||||
const rendered = await renderContent.liquid.parseAndRender(snippet, context)
|
||||
const parsed = yaml.load(rendered)
|
||||
return parsed.on.schedule
|
||||
})
|
||||
@@ -1031,6 +1037,9 @@ describe('lint GHAE release notes', () => {
|
||||
|
||||
describe('lint learning tracks', () => {
|
||||
if (learningTracksToLint.length < 1) return
|
||||
|
||||
const siteData = loadSiteData()
|
||||
|
||||
describe.each(learningTracksToLint)('%s', (yamlRelPath, yamlAbsPath) => {
|
||||
let dictionary
|
||||
let dictionaryError = false
|
||||
@@ -1066,7 +1075,7 @@ describe('lint learning tracks', () => {
|
||||
const productVersions = getApplicableVersions(data.versions, productTocPath)
|
||||
|
||||
const featuredTracks = {}
|
||||
const context = { enterpriseServerVersions }
|
||||
const context = { enterpriseServerVersions, site: siteData.en.site }
|
||||
|
||||
// For each of the product's versions, render the learning track data and look for a featured track.
|
||||
await Promise.all(
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import supertest from 'supertest'
|
||||
import { describe, jest, test } from '@jest/globals'
|
||||
|
||||
import createApp from '../../lib/app.js'
|
||||
import enterpriseServerReleases from '../../lib/enterprise-server-releases.js'
|
||||
import { get, getDOM } from '../helpers/supertest.js'
|
||||
import { SURROGATE_ENUMS } from '../../middleware/set-fastly-surrogate-key.js'
|
||||
import supertest from 'supertest'
|
||||
import { jest } from '@jest/globals'
|
||||
import { PREFERRED_LOCALE_COOKIE_NAME } from '../../middleware/detect-language.js'
|
||||
|
||||
jest.useFakeTimers('legacy')
|
||||
|
||||
@@ -89,6 +91,73 @@ describe('enterprise deprecation', () => {
|
||||
})
|
||||
})
|
||||
|
||||
// Starting with the deprecation of 3.0, it's the first time we deprecate
|
||||
// enterprise versions since redirects is a *function* rather than a
|
||||
// lookup in a big object.
|
||||
describe('recently deprecated redirects', () => {
|
||||
test('basic enterprise 3.0 redirects', async () => {
|
||||
const res = await get('/enterprise/3.0')
|
||||
expect(res.statusCode).toBe(302)
|
||||
expect(res.headers.location).toBe('/en/enterprise-server@3.0')
|
||||
expect(res.headers['set-cookie']).toBeUndefined()
|
||||
// Deliberately no cache control because it is user-dependent
|
||||
expect(res.headers['cache-control']).toBe('private, no-store')
|
||||
})
|
||||
test('basic enterprise 3.0 redirects by cookie', async () => {
|
||||
const res = await get('/enterprise/3.0', {
|
||||
headers: {
|
||||
Cookie: `${PREFERRED_LOCALE_COOKIE_NAME}=ja`,
|
||||
},
|
||||
})
|
||||
expect(res.statusCode).toBe(302)
|
||||
expect(res.headers.location).toBe('/ja/enterprise-server@3.0')
|
||||
})
|
||||
test('already languaged enterprise 3.0 redirects', async () => {
|
||||
const res = await get('/en/enterprise/3.0')
|
||||
expect(res.statusCode).toBe(301)
|
||||
expect(res.headers.location).toBe('/en/enterprise-server@3.0')
|
||||
// 301 redirects are safe to cache aggressively
|
||||
expect(res.headers['set-cookie']).toBeUndefined()
|
||||
expect(res.headers['cache-control']).toContain('public')
|
||||
expect(res.headers['cache-control']).toMatch(/max-age=\d+/)
|
||||
})
|
||||
test('redirects enterprise-server 3.0 with actual redirect without language', async () => {
|
||||
const res = await get(
|
||||
'/enterprise-server@3.0/github/getting-started-with-github/githubs-products'
|
||||
)
|
||||
expect(res.statusCode).toBe(302)
|
||||
expect(res.headers['set-cookie']).toBeUndefined()
|
||||
// Deliberately no cache control because it is user-dependent
|
||||
expect(res.headers['cache-control']).toBe('private, no-store')
|
||||
// This is based on
|
||||
// https://github.com/github/help-docs-archived-enterprise-versions/blob/master/3.0/redirects.json
|
||||
expect(res.headers.location).toBe(
|
||||
'/en/enterprise-server@3.0/get-started/learning-about-github/githubs-products'
|
||||
)
|
||||
})
|
||||
test('redirects enterprise-server 3.0 with actual redirect with language', async () => {
|
||||
const res = await get(
|
||||
'/ja/enterprise-server@3.0/github/getting-started-with-github/githubs-products'
|
||||
)
|
||||
expect(res.statusCode).toBe(301)
|
||||
expect(res.headers['set-cookie']).toBeUndefined()
|
||||
expect(res.headers['cache-control']).toContain('public')
|
||||
expect(res.headers['cache-control']).toMatch(/max-age=\d+/)
|
||||
// This is based on
|
||||
// https://github.com/github/help-docs-archived-enterprise-versions/blob/master/3.0/redirects.json
|
||||
expect(res.headers.location).toBe(
|
||||
'/ja/enterprise-server@3.0/get-started/learning-about-github/githubs-products'
|
||||
)
|
||||
})
|
||||
test('follow redirects enterprise-server 3.0 with actual redirect without language', async () => {
|
||||
const res = await get(
|
||||
'/enterprise-server@3.0/github/getting-started-with-github/githubs-products',
|
||||
{ followAllRedirects: true }
|
||||
)
|
||||
expect(res.statusCode).toBe(200)
|
||||
})
|
||||
})
|
||||
|
||||
describe('deprecation banner', () => {
|
||||
test('renders a deprecation warning banner on oldest supported Enterprise version', async () => {
|
||||
const $ = await getDOM(`/en/enterprise/${enterpriseServerReleases.oldestSupported}`)
|
||||
|
||||
@@ -1,6 +1,36 @@
|
||||
import getRedirect from '../../lib/get-redirect.js'
|
||||
import { describe, expect, test } from '@jest/globals'
|
||||
|
||||
import getRedirect, { splitPathByLanguage } from '../../lib/get-redirect.js'
|
||||
import { latest } from '../../lib/enterprise-server-releases.js'
|
||||
|
||||
describe('splitPathByLanguage', () => {
|
||||
test('basic', () => {
|
||||
const [language, withoutLanguage] = splitPathByLanguage('/foo/')
|
||||
expect(language).toBe('en')
|
||||
expect(withoutLanguage).toBe('/foo/')
|
||||
})
|
||||
test('already has /en in it', () => {
|
||||
const [language, withoutLanguage] = splitPathByLanguage('/en/foo/')
|
||||
expect(language).toBe('en')
|
||||
expect(withoutLanguage).toBe('/foo/')
|
||||
})
|
||||
test('basic with different fallback', () => {
|
||||
const [language, withoutLanguage] = splitPathByLanguage('/foo/', 'ja')
|
||||
expect(language).toBe('ja')
|
||||
expect(withoutLanguage).toBe('/foo/')
|
||||
})
|
||||
test('already has /en different fallback', () => {
|
||||
const [language, withoutLanguage] = splitPathByLanguage('/en/foo/', 'ja')
|
||||
expect(language).toBe('en')
|
||||
expect(withoutLanguage).toBe('/foo/')
|
||||
})
|
||||
test('unrecognized prefix is ignored', () => {
|
||||
const [language, withoutLanguage] = splitPathByLanguage('/sv/foo/')
|
||||
expect(language).toBe('en')
|
||||
expect(withoutLanguage).toBe('/sv/foo/')
|
||||
})
|
||||
})
|
||||
|
||||
describe('getRedirect basics', () => {
|
||||
it('should sometimes not correct the version prefix', () => {
|
||||
// This essentially tests legacy entries that come from the
|
||||
@@ -162,4 +192,15 @@ describe('getRedirect basics', () => {
|
||||
ctx.userLanguage = null
|
||||
expect(getRedirect('/foo', ctx)).toBe(`/en/bar`)
|
||||
})
|
||||
|
||||
it('should work for some deprecated enterprise-server URLs too', () => {
|
||||
// Starting with enterprise-server 3.0, we have made redirects become
|
||||
// a *function* rather than a lookup on a massive object.
|
||||
const ctx = {
|
||||
pages: {},
|
||||
redirects: {},
|
||||
}
|
||||
expect(getRedirect('/enterprise/3.0', ctx)).toBe('/en/enterprise-server@3.0')
|
||||
expect(getRedirect('/enterprise/3.0/foo', ctx)).toBe('/en/enterprise-server@3.0/foo')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -191,11 +191,7 @@ describe('liquid template parser', () => {
|
||||
// Create a fake req so we can test the feature versions middleware
|
||||
const req = { language: 'en', query: {} }
|
||||
|
||||
let siteData
|
||||
beforeAll(async () => {
|
||||
const allSiteData = await loadSiteData()
|
||||
siteData = allSiteData.en.site
|
||||
})
|
||||
const siteData = loadSiteData().en.site
|
||||
|
||||
test('does not render in FPT because feature is not available in FPT', async () => {
|
||||
req.context = {
|
||||
|
||||
Reference in New Issue
Block a user