Merge branch 'main' into patch-1
This commit is contained in:
2
.github/workflows/browser-test.yml
vendored
2
.github/workflows/browser-test.yml
vendored
@@ -41,5 +41,5 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci --include=optional
|
run: npm ci --include=optional
|
||||||
|
|
||||||
- name: Run brower-test
|
- name: Run browser-test
|
||||||
run: npm run browser-test
|
run: npm run browser-test
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ jobs:
|
|||||||
owner: owner,
|
owner: owner,
|
||||||
repo: originalRepo,
|
repo: originalRepo,
|
||||||
issue_number: issueNo,
|
issue_number: issueNo,
|
||||||
body: `👋 Moving forward, we're asking that folks create all new Docs issues in the [${process.env.TEAM_ENGINEERING_REPO}](${process.env.TEAM_ENGINEERING_REPO}) repo and all new content issues in [${process.env.TEAM_CONTENT_REPO}](${process.env.TEAM_CONTENT_REPO}). We transferred it for you!`
|
body: `👋 You opened this issue in `${context.repo.repo}`. Moving forward, we're asking that folks create new issues in the following repositories instead:\n- For issues with the docs site, please submit to the [${process.env.TEAM_ENGINEERING_REPO}](/${owner}/${process.env.TEAM_ENGINEERING_REPO}) repo.\n- For all new content issues, please submit to the [${process.env.TEAM_CONTENT_REPO}](/${owner}/${process.env.TEAM_CONTENT_REPO}) repo.\n\nWe will transfer this issue for you!`
|
||||||
})
|
})
|
||||||
|
|
||||||
// Transfer the issue to the correct repo
|
// Transfer the issue to the correct repo
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { useMainContext } from 'components/context/MainContext'
|
|||||||
|
|
||||||
const { NODE_ENV } = process.env
|
const { NODE_ENV } = process.env
|
||||||
|
|
||||||
const enableNextLinks = false
|
const enableNextLinks = true
|
||||||
|
|
||||||
type Props = { locale?: string } & ComponentProps<'a'>
|
type Props = { locale?: string } & ComponentProps<'a'>
|
||||||
export function Link(props: Props) {
|
export function Link(props: Props) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { useVersion } from './hooks/useVersion'
|
|||||||
|
|
||||||
export const SidebarNav = () => {
|
export const SidebarNav = () => {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { error, relativePath, isHomepageVersion } = useMainContext()
|
const { error, relativePath } = useMainContext()
|
||||||
const { t } = useTranslation('header')
|
const { t } = useTranslation('header')
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -39,7 +39,7 @@ export const SidebarNav = () => {
|
|||||||
<nav>
|
<nav>
|
||||||
{error === '404' || relativePath === 'index.md' ? (
|
{error === '404' || relativePath === 'index.md' ? (
|
||||||
<ul className="sidebar-products mt-4">
|
<ul className="sidebar-products mt-4">
|
||||||
{!isHomepageVersion && <AllProductsLink />}
|
{<AllProductsLink />}
|
||||||
<SidebarHomepage />
|
<SidebarHomepage />
|
||||||
</ul>
|
</ul>
|
||||||
) : (
|
) : (
|
||||||
@@ -66,12 +66,12 @@ export const SidebarNav = () => {
|
|||||||
const SidebarHomepage = () => {
|
const SidebarHomepage = () => {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { currentVersion } = useVersion()
|
const { currentVersion } = useVersion()
|
||||||
const { activeProducts, isHomepageVersion } = useMainContext()
|
const { activeProducts } = useMainContext()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{activeProducts.map((product) => {
|
{activeProducts.map((product) => {
|
||||||
if (!product.versions?.includes(currentVersion) && !isHomepageVersion) {
|
if (!product.versions?.includes(currentVersion) && !product.external) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -128,7 +128,9 @@ export const Survey = () => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{state === ViewState.END && <p className="color-text-secondary f6" data-testid="survey-end">{t`feedback`}</p>}
|
{state === ViewState.END && (
|
||||||
|
<p className="color-text-secondary f6" data-testid="survey-end">{t`feedback`}</p>
|
||||||
|
)}
|
||||||
</form>
|
</form>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,10 +31,6 @@ export const ArticleVersionPicker = () => {
|
|||||||
</summary>
|
</summary>
|
||||||
<Dropdown.Menu direction="sw">
|
<Dropdown.Menu direction="sw">
|
||||||
{(page.permalinks || []).map((permalink) => {
|
{(page.permalinks || []).map((permalink) => {
|
||||||
if (permalink.pageVersion === 'homepage') {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown.Item key={permalink.href}>
|
<Dropdown.Item key={permalink.href}>
|
||||||
<Link href={permalink.href}>{permalink.pageVersionTitle}</Link>
|
<Link href={permalink.href}>{permalink.pageVersionTitle}</Link>
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ export const getMainContextFromRequest = (req: any): MainContextT => {
|
|||||||
activeProducts: req.context.activeProducts,
|
activeProducts: req.context.activeProducts,
|
||||||
currentProduct: req.context.productMap[req.context.currentProduct] || null,
|
currentProduct: req.context.productMap[req.context.currentProduct] || null,
|
||||||
currentLayoutName: req.context.currentLayoutName,
|
currentLayoutName: req.context.currentLayoutName,
|
||||||
isHomepageVersion: req.context.currentVersion === 'homepage',
|
isHomepageVersion: req.context.page?.documentType === 'homepage',
|
||||||
error: req.context.error ? req.context.error.toString() : '',
|
error: req.context.error ? req.context.error.toString() : '',
|
||||||
data: {
|
data: {
|
||||||
ui: req.context.site.data.ui,
|
ui: req.context.site.data.ui,
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export const getProductSubLandingContextFromRequest = (req: any): ProductSubLand
|
|||||||
includeGuides: (page.includeGuides || []).map((guide: any) => {
|
includeGuides: (page.includeGuides || []).map((guide: any) => {
|
||||||
return {
|
return {
|
||||||
...pick(guide, ['href', 'title', 'intro', 'topics']),
|
...pick(guide, ['href', 'title', 'intro', 'topics']),
|
||||||
type: guide.type || ''
|
type: guide.type || '',
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import { ChevronDownIcon } from '@primer/octicons-react'
|
|||||||
import { Link } from 'components/Link'
|
import { Link } from 'components/Link'
|
||||||
import { useMainContext } from 'components/context/MainContext'
|
import { useMainContext } from 'components/context/MainContext'
|
||||||
import { useVersion } from 'components/hooks/useVersion'
|
import { useVersion } from 'components/hooks/useVersion'
|
||||||
import { useTranslation } from 'components/hooks/useTranslation'
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
variant?: 'inline'
|
variant?: 'inline'
|
||||||
@@ -15,14 +14,13 @@ export const HomepageVersionPicker = ({ variant }: Props) => {
|
|||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { currentVersion } = useVersion()
|
const { currentVersion } = useVersion()
|
||||||
const { getDetailsProps } = useDetails({})
|
const { getDetailsProps } = useDetails({})
|
||||||
const { allVersions, page, enterpriseServerVersions, isHomepageVersion } = useMainContext()
|
const { allVersions, page, enterpriseServerVersions } = useMainContext()
|
||||||
const { t } = useTranslation('homepage')
|
|
||||||
|
|
||||||
if (page.permalinks && page.permalinks.length <= 1) {
|
if (page.permalinks && page.permalinks.length <= 1) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const label = isHomepageVersion ? t('version_picker') : allVersions[currentVersion].versionTitle
|
const label = allVersions[currentVersion].versionTitle
|
||||||
|
|
||||||
if (variant === 'inline') {
|
if (variant === 'inline') {
|
||||||
return (
|
return (
|
||||||
@@ -35,9 +33,6 @@ export const HomepageVersionPicker = ({ variant }: Props) => {
|
|||||||
</summary>
|
</summary>
|
||||||
<div>
|
<div>
|
||||||
{(page.permalinks || []).map((permalink) => {
|
{(page.permalinks || []).map((permalink) => {
|
||||||
if (permalink.pageVersion === 'homepage') {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
key={permalink.href}
|
key={permalink.href}
|
||||||
@@ -78,10 +73,6 @@ export const HomepageVersionPicker = ({ variant }: Props) => {
|
|||||||
</summary>
|
</summary>
|
||||||
<Dropdown.Menu direction="sw">
|
<Dropdown.Menu direction="sw">
|
||||||
{(page.permalinks || []).map((permalink) => {
|
{(page.permalinks || []).map((permalink) => {
|
||||||
if (permalink.pageVersion === 'homepage') {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown.Item key={permalink.href}>
|
<Dropdown.Item key={permalink.href}>
|
||||||
<Link href={permalink.href}>{permalink.pageVersionTitle}</Link>
|
<Link href={permalink.href}>{permalink.pageVersionTitle}</Link>
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ export const ArticleCard = ({ card, typeLabel }: Props) => {
|
|||||||
<div data-testid="article-card" className="d-flex col-12 col-md-4 pr-0 pr-md-6 pr-lg-8">
|
<div data-testid="article-card" className="d-flex col-12 col-md-4 pr-0 pr-md-6 pr-lg-8">
|
||||||
<a className="no-underline d-flex flex-column py-3 border-bottom" href={card.href}>
|
<a className="no-underline d-flex flex-column py-3 border-bottom" href={card.href}>
|
||||||
<h4 className="h4 color-text-primary mb-1">{card.title}</h4>
|
<h4 className="h4 color-text-primary mb-1">{card.title}</h4>
|
||||||
<div className="h6 text-uppercase" data-testid="article-card-type">{typeLabel}</div>
|
<div className="h6 text-uppercase" data-testid="article-card-type">
|
||||||
|
{typeLabel}
|
||||||
|
</div>
|
||||||
<p className="color-text-secondary my-3">{card.intro}</p>
|
<p className="color-text-secondary my-3">{card.intro}</p>
|
||||||
{card.topics.length > 0 && (
|
{card.topics.length > 0 && (
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export const SubLandingHero = () => {
|
|||||||
const { t } = useTranslation('product_sublanding')
|
const { t } = useTranslation('product_sublanding')
|
||||||
|
|
||||||
const guideItems = featuredTrack?.guides?.map((guide) => (
|
const guideItems = featuredTrack?.guides?.map((guide) => (
|
||||||
<li className="px-2 d-flex flex-shrink-0">
|
<li className="px-2 d-flex flex-shrink-0" key={guide.href}>
|
||||||
<Link
|
<Link
|
||||||
href={`${guide.href}?learn=${featuredTrack.trackName}`}
|
href={`${guide.href}?learn=${featuredTrack.trackName}`}
|
||||||
className="d-inline-block Box p-5 color-bg-primary color-border-primary no-underline"
|
className="d-inline-block Box p-5 color-bg-primary color-border-primary no-underline"
|
||||||
|
|||||||
@@ -39,8 +39,9 @@ includeGuides:
|
|||||||
- /code-security/secure-coding/integrating-with-code-scanning/sarif-support-for-code-scanning
|
- /code-security/secure-coding/integrating-with-code-scanning/sarif-support-for-code-scanning
|
||||||
- /code-security/secure-coding/integrating-with-code-scanning/uploading-a-sarif-file-to-github
|
- /code-security/secure-coding/integrating-with-code-scanning/uploading-a-sarif-file-to-github
|
||||||
- /code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/about-codeql-code-scanning-in-your-ci-system
|
- /code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/about-codeql-code-scanning-in-your-ci-system
|
||||||
|
- /code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/configuring-codeql-cli-in-your-ci-system
|
||||||
- /code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/configuring-codeql-runner-in-your-ci-system
|
- /code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/configuring-codeql-runner-in-your-ci-system
|
||||||
- /code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/running-codeql-cli-in-your-ci-system
|
- /code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/installing-codeql-cli-in-your-ci-system
|
||||||
- /code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/running-codeql-runner-in-your-ci-system
|
- /code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/running-codeql-runner-in-your-ci-system
|
||||||
- /code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/troubleshooting-codeql-runner-in-your-ci-system
|
- /code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/troubleshooting-codeql-runner-in-your-ci-system
|
||||||
- /code-security/security-advisories/about-coordinated-disclosure-of-security-vulnerabilities
|
- /code-security/security-advisories/about-coordinated-disclosure-of-security-vulnerabilities
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ topics:
|
|||||||
If you're setting up {% data variables.product.prodname_code_scanning %} for a compiled language, and you're building the code in a containerized environment, the analysis may fail with the error message "No source code was seen during the build." This indicates that {% data variables.product.prodname_codeql %} was unable to monitor your code as it was compiled.
|
If you're setting up {% data variables.product.prodname_code_scanning %} for a compiled language, and you're building the code in a containerized environment, the analysis may fail with the error message "No source code was seen during the build." This indicates that {% data variables.product.prodname_codeql %} was unable to monitor your code as it was compiled.
|
||||||
|
|
||||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@next" %}
|
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@next" %}
|
||||||
You must run {% data variables.product.prodname_codeql %} inside the container in which you build your code. This applies whether you are using the {% data variables.product.prodname_codeql_cli %}, the {% data variables.product.prodname_codeql_runner %}, or {% data variables.product.prodname_actions %}. For the {% data variables.product.prodname_codeql_cli %} or the {% data variables.product.prodname_codeql_runner %}, see "[Running {% data variables.product.prodname_codeql_cli %} in your CI system](/code-security/secure-coding/running-codeql-cli-in-your-ci-system)" or "[Running {% data variables.product.prodname_codeql_runner %} in your CI system](/code-security/secure-coding/running-codeql-runner-in-your-ci-system)" for more information. If you're using {% data variables.product.prodname_actions %}, configure your workflow to run all the actions in the same container. For more information, see "[Example workflow](#example-workflow)."
|
You must run {% data variables.product.prodname_codeql %} inside the container in which you build your code. This applies whether you are using the {% data variables.product.prodname_codeql_cli %}, the {% data variables.product.prodname_codeql_runner %}, or {% data variables.product.prodname_actions %}. For the {% data variables.product.prodname_codeql_cli %} or the {% data variables.product.prodname_codeql_runner %}, see "[Installing {% data variables.product.prodname_codeql_cli %} in your CI system](/code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/installing-codeql-cli-in-your-ci-system)" or "[Running {% data variables.product.prodname_codeql_runner %} in your CI system](/code-security/secure-coding/running-codeql-runner-in-your-ci-system)" for more information. If you're using {% data variables.product.prodname_actions %}, configure your workflow to run all the actions in the same container. For more information, see "[Example workflow](#example-workflow)."
|
||||||
{% else %}
|
{% else %}
|
||||||
You must run {% data variables.product.prodname_codeql %} inside the container in which you build your code. This applies whether you are using the {% data variables.product.prodname_codeql_runner %} or {% data variables.product.prodname_actions %}. For the {% data variables.product.prodname_codeql_runner %}, see "[Running {% data variables.product.prodname_codeql_runner %} in your CI system](/code-security/secure-coding/running-codeql-runner-in-your-ci-system)" for more information. If you're using {% data variables.product.prodname_actions %}, configure your workflow to run all the actions in the same container. For more information, see "[Example workflow](#example-workflow)."
|
You must run {% data variables.product.prodname_codeql %} inside the container in which you build your code. This applies whether you are using the {% data variables.product.prodname_codeql_runner %} or {% data variables.product.prodname_actions %}. For the {% data variables.product.prodname_codeql_runner %}, see "[Running {% data variables.product.prodname_codeql_runner %} in your CI system](/code-security/secure-coding/running-codeql-runner-in-your-ci-system)" for more information. If you're using {% data variables.product.prodname_actions %}, configure your workflow to run all the actions in the same container. For more information, see "[Example workflow](#example-workflow)."
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ To upload a SARIF file from a third-party static code analysis engine, you'll ne
|
|||||||
If you're using {% data variables.product.prodname_actions %} with the {% data variables.product.prodname_codeql_workflow %} or using the {% data variables.product.prodname_codeql_runner %}, then the {% data variables.product.prodname_code_scanning %} results will automatically use the supported subset of SARIF 2.1.0. For more information, see "[Setting up {% data variables.product.prodname_code_scanning %} for a repository](/code-security/secure-coding/setting-up-code-scanning-for-a-repository)" or "[Running {% data variables.product.prodname_codeql_runner %} in your CI system](/code-security/secure-coding/running-codeql-runner-in-your-ci-system)."
|
If you're using {% data variables.product.prodname_actions %} with the {% data variables.product.prodname_codeql_workflow %} or using the {% data variables.product.prodname_codeql_runner %}, then the {% data variables.product.prodname_code_scanning %} results will automatically use the supported subset of SARIF 2.1.0. For more information, see "[Setting up {% data variables.product.prodname_code_scanning %} for a repository](/code-security/secure-coding/setting-up-code-scanning-for-a-repository)" or "[Running {% data variables.product.prodname_codeql_runner %} in your CI system](/code-security/secure-coding/running-codeql-runner-in-your-ci-system)."
|
||||||
|
|
||||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@next" %}
|
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@next" %}
|
||||||
If you're using the {% data variables.product.prodname_codeql_cli %}, then you can specify the version of SARIF to use. For more information, see "[Running {% data variables.product.prodname_codeql_cli %} in your CI system](/code-security/secure-coding/running-codeql-cli-in-your-ci-system#uploading-results-to-github)."{% endif %}
|
If you're using the {% data variables.product.prodname_codeql_cli %}, then you can specify the version of SARIF to use. For more information, see "[Configuring {% data variables.product.prodname_codeql_cli %} in your CI system](/code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/configuring-codeql-cli-in-your-ci-system#analyzing-a-codeql-database)."{% endif %}
|
||||||
|
|
||||||
{% if currentVersion == "free-pro-team@latest" %}
|
{% if currentVersion == "free-pro-team@latest" %}
|
||||||
You can upload multiple SARIF files for the same tool and commit, and analyze each file using {% data variables.product.prodname_code_scanning %}. You can indicate a "category" for each analysis by specifying a `runAutomationDetails.id` in each file. Only SARIF files with the same category will overwrite each other. For more information about this property, see [`runAutomationDetails` object](#runautomationdetails-object) below.
|
You can upload multiple SARIF files for the same tool and commit, and analyze each file using {% data variables.product.prodname_code_scanning %}. You can indicate a "category" for each analysis by specifying a `runAutomationDetails.id` in each file. Only SARIF files with the same category will overwrite each other. For more information about this property, see [`runAutomationDetails` object](#runautomationdetails-object) below.
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ You can upload the results using {% data variables.product.prodname_actions %},
|
|||||||
|
|
||||||
- {% data variables.product.prodname_actions %} to run the {% data variables.product.prodname_codeql %} action, there is no further action required. The {% data variables.product.prodname_codeql %} action uploads the SARIF file automatically when it completes analysis.
|
- {% data variables.product.prodname_actions %} to run the {% data variables.product.prodname_codeql %} action, there is no further action required. The {% data variables.product.prodname_codeql %} action uploads the SARIF file automatically when it completes analysis.
|
||||||
- {% data variables.product.prodname_actions %} to run a SARIF-compatible analysis tool, you could update the workflow to include a final step that uploads the results (see below). {% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@next" %}
|
- {% data variables.product.prodname_actions %} to run a SARIF-compatible analysis tool, you could update the workflow to include a final step that uploads the results (see below). {% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@next" %}
|
||||||
- The {% data variables.product.prodname_codeql_cli %} to run {% data variables.product.prodname_code_scanning %} in your CI system, you can use the CLI to upload results to {% data variables.product.prodname_dotcom %} (for more information, see "[Running {% data variables.product.prodname_codeql_cli %} in your CI system](/code-security/secure-coding/running-codeql-cli-in-your-ci-system)").{% endif %}
|
- The {% data variables.product.prodname_codeql_cli %} to run {% data variables.product.prodname_code_scanning %} in your CI system, you can use the CLI to upload results to {% data variables.product.prodname_dotcom %} (for more information, see "[Installing {% data variables.product.prodname_codeql_cli %} in your CI system](/code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/installing-codeql-cli-in-your-ci-system)").{% endif %}
|
||||||
- The {% data variables.product.prodname_codeql_runner %}, to run {% data variables.product.prodname_code_scanning %} in your CI system, by default the runner automatically uploads results to {% data variables.product.prodname_dotcom %} on completion. If you block the automatic upload, when you are ready to upload results you can use the `upload` command (for more information, see "[Running {% data variables.product.prodname_codeql_runner %} in your CI system](/code-security/secure-coding/running-codeql-runner-in-your-ci-system)").
|
- The {% data variables.product.prodname_codeql_runner %}, to run {% data variables.product.prodname_code_scanning %} in your CI system, by default the runner automatically uploads results to {% data variables.product.prodname_dotcom %} on completion. If you block the automatic upload, when you are ready to upload results you can use the `upload` command (for more information, see "[Running {% data variables.product.prodname_codeql_runner %} in your CI system](/code-security/secure-coding/running-codeql-runner-in-your-ci-system)").
|
||||||
- A tool that generates results as an artifact outside of your repository, you can use the {% data variables.product.prodname_code_scanning %} API to upload the file (for more information, see "[Upload an analysis as SARIF data](/rest/reference/code-scanning#upload-an-analysis-as-sarif-data)").
|
- A tool that generates results as an artifact outside of your repository, you can use the {% data variables.product.prodname_code_scanning %} API to upload the file (for more information, see "[Upload an analysis as SARIF data](/rest/reference/code-scanning#upload-an-analysis-as-sarif-data)").
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ topics:
|
|||||||
redirect_from:
|
redirect_from:
|
||||||
- /code-security/secure-coding/about-codeql-code-scanning-in-your-ci-system
|
- /code-security/secure-coding/about-codeql-code-scanning-in-your-ci-system
|
||||||
---
|
---
|
||||||
|
<!--UI-LINK: When GitHub Enterprise Server 3.1+ doesn't have GitHub Actions set up, the Security > Code scanning alerts view links to this article.-->
|
||||||
|
|
||||||
{% data reusables.code-scanning.beta %}
|
{% data reusables.code-scanning.beta %}
|
||||||
{% data reusables.code-scanning.enterprise-enable-code-scanning %}
|
{% data reusables.code-scanning.enterprise-enable-code-scanning %}
|
||||||
|
|
||||||
@@ -26,9 +28,35 @@ redirect_from:
|
|||||||
|
|
||||||
{% data reusables.code-scanning.about-code-scanning %} For information, see "[About {% data variables.product.prodname_code_scanning %}](/code-security/secure-coding/about-code-scanning)."
|
{% data reusables.code-scanning.about-code-scanning %} For information, see "[About {% data variables.product.prodname_code_scanning %}](/code-security/secure-coding/about-code-scanning)."
|
||||||
|
|
||||||
You can run {% data variables.product.prodname_codeql %} {% data variables.product.prodname_code_scanning %} within {% data variables.product.product_name %} using actions. Alternatively, if you use a third-party continuous integration or continuous delivery/deployment (CI/CD) system, you can run {% data variables.product.prodname_codeql %} analysis in your existing system and upload the results to {% data variables.product.product_location %}.
|
You can run {% data variables.product.prodname_codeql %} {% data variables.product.prodname_code_scanning %} within {% data variables.product.product_name %} using {% data variables.product.prodname_actions %}. Alternatively, if you use a third-party continuous integration or continuous delivery/deployment (CI/CD) system, you can run {% data variables.product.prodname_codeql %} analysis in your existing system and upload the results to {% data variables.product.product_location %}.
|
||||||
|
|
||||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@next" %}
|
<!--Content for GitHub.com, GHAE next, and GHES 3.2. Both CodeQL CLI and CodeQL runner are available, but CodeQL CLI preferred -->
|
||||||
|
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.1" or currentVersion == "github-ae@next" %}
|
||||||
|
|
||||||
|
You add the {% data variables.product.prodname_codeql_cli %} to your third-party system, then call the tool to analyze code and upload the SARIF results to {% data variables.product.product_name %}. The resulting {% data variables.product.prodname_code_scanning %} alerts are shown alongside any alerts generated within {% data variables.product.product_name %}.
|
||||||
|
|
||||||
|
{% data reusables.code-scanning.upload-sarif-ghas %}
|
||||||
|
|
||||||
|
## About the {% data variables.product.prodname_codeql_cli %}
|
||||||
|
|
||||||
|
{% data reusables.code-scanning.what-is-codeql-cli %}
|
||||||
|
|
||||||
|
Use the {% data variables.product.prodname_codeql_cli %} to analyze:
|
||||||
|
|
||||||
|
- Dynamic languages, for example, JavaScript and Python.
|
||||||
|
- Compiled languages, for example, C/C++, C# and Java.
|
||||||
|
- Codebases written in a mixture of languages.
|
||||||
|
|
||||||
|
For more information, see "[Installing {% data variables.product.prodname_codeql_cli %} in your CI system](/code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/installing-codeql-cli-in-your-ci-system)."
|
||||||
|
|
||||||
|
{% data reusables.code-scanning.licensing-note %}
|
||||||
|
|
||||||
|
{% data reusables.code-scanning.use-codeql-runner-not-cli %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!--Content for GHES 3.1 only. Both CodeQL CLI and CodeQL runner are available -->
|
||||||
|
{% if currentVersion == "enterprise-server@3.1" %}
|
||||||
You add the {% data variables.product.prodname_codeql_cli %} or the {% data variables.product.prodname_codeql_runner %} to your third-party system, then call the tool to analyze code and upload the SARIF results to {% data variables.product.product_name %}. The resulting {% data variables.product.prodname_code_scanning %} alerts are shown alongside any alerts generated within {% data variables.product.product_name %}.
|
You add the {% data variables.product.prodname_codeql_cli %} or the {% data variables.product.prodname_codeql_runner %} to your third-party system, then call the tool to analyze code and upload the SARIF results to {% data variables.product.product_name %}. The resulting {% data variables.product.prodname_code_scanning %} alerts are shown alongside any alerts generated within {% data variables.product.product_name %}.
|
||||||
|
|
||||||
{% data reusables.code-scanning.upload-sarif-ghas %}
|
{% data reusables.code-scanning.upload-sarif-ghas %}
|
||||||
@@ -44,22 +72,18 @@ Use the {% data variables.product.prodname_codeql_cli %} to analyze:
|
|||||||
- Dynamic languages, for example, JavaScript and Python.
|
- Dynamic languages, for example, JavaScript and Python.
|
||||||
- Codebases with a compiled language that can be built with a single command or by running a single script.
|
- Codebases with a compiled language that can be built with a single command or by running a single script.
|
||||||
|
|
||||||
For more information, see "[Running {% data variables.product.prodname_codeql_cli %} in your CI system](/code-security/secure-coding/running-codeql-cli-in-your-ci-system)."
|
For more information, see "[Installing {% data variables.product.prodname_codeql_cli %} in your CI system](/code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/installing-codeql-cli-in-your-ci-system)."
|
||||||
|
|
||||||
{% if currentVersion == "free-pro-team@latest" %}
|
{% data reusables.code-scanning.use-codeql-runner-not-cli %}
|
||||||
If you need to set up the CI system to orchestrate compiler invocations as well as running {% data variables.product.prodname_codeql %} analysis, you must use the {% data variables.product.prodname_codeql_runner %}.
|
|
||||||
{% else %}
|
|
||||||
You will need to use the {% data variables.product.prodname_codeql_runner %} if you need to:
|
|
||||||
- Set up the CI system to orchestrate compiler invocations as well as running {% data variables.product.prodname_codeql %} analysis.
|
|
||||||
- Analyze more than one language in a repository.
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% data reusables.code-scanning.beta-codeql-runner %}
|
{% data reusables.code-scanning.beta-codeql-runner %}
|
||||||
|
|
||||||
For more information, see "[Running {% data variables.product.prodname_codeql_runner %} in your CI system](/code-security/secure-coding/running-codeql-runner-in-your-ci-system)."
|
For more information, see "[Running {% data variables.product.prodname_codeql_runner %} in your CI system](/code-security/secure-coding/running-codeql-runner-in-your-ci-system)."
|
||||||
|
|
||||||
{% else %}
|
{% endif %}
|
||||||
|
|
||||||
|
<!--Content for GHAE and GHES 3.0 only. Only CodeQL runner is available -->
|
||||||
|
{% if currentVersion == "enterprise-server@3.0" or currentVersion == "github-ae@latest" %}
|
||||||
{% data reusables.code-scanning.upload-sarif-ghas %}
|
{% data reusables.code-scanning.upload-sarif-ghas %}
|
||||||
|
|
||||||
You add the {% data variables.product.prodname_codeql_runner %} to your third-party system, then call the tool to analyze code and upload the SARIF results to {% data variables.product.product_name %}. The resulting {% data variables.product.prodname_code_scanning %} alerts are shown alongside any alerts generated within {% data variables.product.product_name %}.
|
You add the {% data variables.product.prodname_codeql_runner %} to your third-party system, then call the tool to analyze code and upload the SARIF results to {% data variables.product.product_name %}. The resulting {% data variables.product.prodname_code_scanning %} alerts are shown alongside any alerts generated within {% data variables.product.product_name %}.
|
||||||
|
|||||||
@@ -0,0 +1,285 @@
|
|||||||
|
---
|
||||||
|
title: Configuring CodeQL CLI in your CI system
|
||||||
|
shortTitle: Configuring CodeQL CLI
|
||||||
|
intro: 'You can configure your continuous integration system to run the {% data variables.product.prodname_codeql_cli %}, perform {% data variables.product.prodname_codeql %} analysis, and upload the results to {% data variables.product.product_name %} for display as {% data variables.product.prodname_code_scanning %} alerts.'
|
||||||
|
product: '{% data reusables.gated-features.code-scanning %}'
|
||||||
|
miniTocMaxHeadingLevel: 3
|
||||||
|
versions:
|
||||||
|
free-pro-team: '*'
|
||||||
|
enterprise-server: '>=3.1'
|
||||||
|
github-ae: 'next'
|
||||||
|
type: how_to
|
||||||
|
topics:
|
||||||
|
- Advanced Security
|
||||||
|
- Code scanning
|
||||||
|
- CodeQL
|
||||||
|
- Repositories
|
||||||
|
- Pull requests
|
||||||
|
- Integration
|
||||||
|
- CI
|
||||||
|
- SARIF
|
||||||
|
---
|
||||||
|
{% data reusables.code-scanning.enterprise-enable-code-scanning %}
|
||||||
|
|
||||||
|
## About generating code scanning results with {% data variables.product.prodname_codeql_cli %}
|
||||||
|
|
||||||
|
Once you've made the {% data variables.product.prodname_codeql_cli %} available to servers in your CI system, and ensured that they can authenticate with {% data variables.product.product_name %}, you're ready to generate data.
|
||||||
|
|
||||||
|
You use three different commands to generate results and upload them to {% data variables.product.product_name %}:
|
||||||
|
|
||||||
|
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.1" or currentVersion == "github-ae@next" %}
|
||||||
|
<!--Option to analyze multiple languages with one call-->
|
||||||
|
1. `database create` to create a {% data variables.product.prodname_codeql %} database to represent the hierarchical structure of each supported programming language in the repository.
|
||||||
|
2. ` database analyze` to run queries to analyze each {% data variables.product.prodname_codeql %} database and summarize the results in a SARIF file.
|
||||||
|
3. `github upload-results` to upload the resulting SARIF files to {% data variables.product.product_name %} where the results are matched to a branch or pull request and displayed as {% data variables.product.prodname_code_scanning %} alerts.
|
||||||
|
{% else %}
|
||||||
|
<!--Only one language can be analyzed-->
|
||||||
|
1. `database create` to create a {% data variables.product.prodname_codeql %} database to represent the hierarchical structure of a supported programming language in the repository.
|
||||||
|
2. ` database analyze` to run queries to analyze the {% data variables.product.prodname_codeql %} database and summarize the results in a SARIF file.
|
||||||
|
3. `github upload-results` to upload the resulting SARIF file to {% data variables.product.product_name %} where the results are matched to a branch or pull request and displayed as {% data variables.product.prodname_code_scanning %} alerts.
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
You can display the command-line help for any command using the <nobr>`--help`</nobr> option.
|
||||||
|
|
||||||
|
{% data reusables.code-scanning.upload-sarif-ghas %}
|
||||||
|
|
||||||
|
## Creating {% data variables.product.prodname_codeql %} databases to analyze
|
||||||
|
|
||||||
|
1. Check out the code that you want to analyze:
|
||||||
|
- For a branch, check out the head of the branch that you want to analyze.
|
||||||
|
- For a pull request, check out either the head commit of the pull request, or check out a {% data variables.product.product_name %}-generated merge commit of the pull request.
|
||||||
|
2. Set up the environment for the codebase, making sure that any dependencies are available. For more information, see [Creating databases for non-compiled languages](https://codeql.github.com/docs/codeql-cli/creating-codeql-databases/#creating-databases-for-non-compiled-languages) and [Creating databases for compiled languages](https://codeql.github.com/docs/codeql-cli/creating-codeql-databases/#creating-databases-for-compiled-languages) in the documentation for the {% data variables.product.prodname_codeql_cli %}.
|
||||||
|
3. Find the build command, if any, for the codebase. Typically this is available in a configuration file in the CI system.
|
||||||
|
4. Run `codeql database create` from the checkout root of your repository and build the codebase.
|
||||||
|
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.1" or currentVersion == "github-ae@next" %}
|
||||||
|
```shell
|
||||||
|
# Single supported language - create one CodeQL databsae
|
||||||
|
codeql database create <database> --command<build> --language=<language-identifier>
|
||||||
|
|
||||||
|
# Multiple supported languages - create one CodeQL database per langauge
|
||||||
|
codeql database create <database> --command<build> \
|
||||||
|
--db-cluster --language=<language-identifier>,<language-identifier>
|
||||||
|
```
|
||||||
|
{% else %}
|
||||||
|
```shell
|
||||||
|
codeql database create <database> --command<build> --language=<language-identifier>
|
||||||
|
```
|
||||||
|
{% endif %}
|
||||||
|
{% note %}
|
||||||
|
|
||||||
|
**Note:** If you use a containerized build, you need to run the {% data variables.product.prodname_codeql_cli %} inside the container where your build task takes place.
|
||||||
|
|
||||||
|
{% endnote %}
|
||||||
|
|
||||||
|
| Option | Required | Usage |
|
||||||
|
|--------|:--------:|-----|
|
||||||
|
| `<database>` | {% octicon "check-circle-fill" aria-label="Required" %} | Specify the name and location of a directory to create for the {% data variables.product.prodname_codeql %} database. The command will fail if you try to overwrite an existing directory. If you also specify `--db-cluster`, this is the parent directory and a subdirectory is created for each language analyzed.|
|
||||||
|
| <nobr>`--language`</nobr> | {% octicon "check-circle-fill" aria-label="Required" %} | Specify the identifier for the language to create a database for, one of: `{% data reusables.code-scanning.codeql-languages-keywords %}` (use `javascript` to analyze TypeScript code). {% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.1" or currentVersion == "github-ae@next" %}When used with <nobr>`--db-cluster`</nobr>, the option accepts a comma-separated list, or can be specified more than once.{% endif %}
|
||||||
|
| <nobr>`--command`</nobr> | | Recommended. Use to specify the build command or script that invokes the build process for the codebase. Commands are run from the current folder or, where it is defined, from <nobr>`--source-root`</nobr>. Not needed for Python and JavaScript/TypeScript analysis. | {% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.1" or currentVersion == "github-ae@next" %}
|
||||||
|
| <nobr>`--db-cluster`</nobr> | | Optional. Use in multi-language codebases to generate one database for each language specified by <nobr>`--language`</nobr>.
|
||||||
|
| <nobr>`--no-run-unnecessary-builds`</nobr> | | Recommended. Use to suppress the build command for languages where the {% data variables.product.prodname_codeql_cli %} does not need to monitor the build (for example, Python and JavaScript/TypeScript). {% endif %}
|
||||||
|
| <nobr>`--source-root`</nobr> | | Optional. Use if you run the CLI outside the checkout root of the repository. By default, the `database create` command assumes that the current directory is the root directory for the source files, use this option to specify a different location. |
|
||||||
|
|
||||||
|
For more information, see [Creating {% data variables.product.prodname_codeql %} databases](https://codeql.github.com/docs/codeql-cli/creating-codeql-databases/) in the documentation for the {% data variables.product.prodname_codeql_cli %}.
|
||||||
|
|
||||||
|
### {% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.1" or currentVersion == "github-ae@next" %}Single language example{% else %}Basic example{% endif %}
|
||||||
|
|
||||||
|
This example creates a {% data variables.product.prodname_codeql %} database for the repository checked out at `/checkouts/example-repo`. It uses the JavaScript extractor to create a hierarchical representation of the JavaScript and TypeScript code in the repository. The resulting database is stored in `/codeql-dbs/example-repo`.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ codeql database create /codeql-dbs/example-repo --language=javascript \
|
||||||
|
--source-root /checkouts/example-repo
|
||||||
|
|
||||||
|
> Initializing database at /codeql-dbs/example-repo.
|
||||||
|
> Running command [/codeql-home/codeql/javascript/tools/autobuild.cmd]
|
||||||
|
in /checkouts/example-repo.
|
||||||
|
> [build-stdout] Single-threaded extraction.
|
||||||
|
> [build-stdout] Extracting
|
||||||
|
...
|
||||||
|
> Finalizing database at /codeql-dbs/example-repo.
|
||||||
|
> Successfully created database at /codeql-dbs/example-repo.
|
||||||
|
```
|
||||||
|
|
||||||
|
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.1" or currentVersion == "github-ae@next" %}
|
||||||
|
### Multiple language example
|
||||||
|
|
||||||
|
This example creates two {% data variables.product.prodname_codeql %} databases for the repository checked out at `/checkouts/example-repo-multi`. It uses:
|
||||||
|
|
||||||
|
- `--db-cluster` to request analysis of more than one language.
|
||||||
|
- `--language` to specify which languages to create databases for.
|
||||||
|
- `--command` to tell the tool the build command for the codebase, here `make`.
|
||||||
|
- `--no-run-unnecessary-builds` to tell the tool to skip the build command for languages where it is not needed (like Python).
|
||||||
|
|
||||||
|
The resulting databases are stored in `python` and `cpp` subdirectories of `/codeql-dbs/example-repo-multi`.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ codeql database create /codeql-dbs/example-repo-multi \
|
||||||
|
--db-cluster --language python,cpp \
|
||||||
|
--command make --no-run-unnecessary-builds \
|
||||||
|
--source-root /checkouts/example-repo-multi
|
||||||
|
Initializing databases at /codeql-dbs/example-repo-multi.
|
||||||
|
Running build command: [make]
|
||||||
|
[build-stdout] Calling python3 /codeql-bundle/codeql/python/tools/get_venv_lib.py
|
||||||
|
[build-stdout] Calling python3 -S /codeql-bundle/codeql/python/tools/python_tracer.py -v -z all -c /codeql-dbs/example-repo-multi/python/working/trap_cache -p ERROR: 'pip' not installed.
|
||||||
|
[build-stdout] /usr/local/lib/python3.6/dist-packages -R /checkouts/example-repo-multi
|
||||||
|
[build-stdout] [INFO] Python version 3.6.9
|
||||||
|
[build-stdout] [INFO] Python extractor version 5.16
|
||||||
|
[build-stdout] [INFO] [2] Extracted file /checkouts/example-repo-multi/hello.py in 5ms
|
||||||
|
[build-stdout] [INFO] Processed 1 modules in 0.15s
|
||||||
|
[build-stdout] <output from calling 'make' to build the C/C++ code>
|
||||||
|
Finalizing databases at /codeql-dbs/example-repo-multi.
|
||||||
|
Successfully created databases at /codeql-dbs/example-repo-multi.
|
||||||
|
$
|
||||||
|
```
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
## Analyzing a {% data variables.product.prodname_codeql %} database
|
||||||
|
|
||||||
|
1. Create a {% data variables.product.prodname_codeql %} database (see above).
|
||||||
|
2. Run `codeql database analyze` on the database and specify which queries to use.
|
||||||
|
```shell
|
||||||
|
codeql database analyze <database> --format=<format> \
|
||||||
|
--output=<output> <queries>
|
||||||
|
```
|
||||||
|
|
||||||
|
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.1" or currentVersion == "github-ae@next" %}
|
||||||
|
{% note %}
|
||||||
|
|
||||||
|
**Note:** If you analyze more than one {% data variables.product.prodname_codeql %} database for a single commit, you must specify a SARIF category for each set of results generated by this command. When you upload the results to {% data variables.product.product_name %}, {% data variables.product.prodname_code_scanning %} uses this category to store the results for each language separately. If you forget to do this, each upload overwrites the previous results.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
codeql database analyze <database> --format=<format> \
|
||||||
|
--sarif-category=<language-specifier> --output=<output> <queries>
|
||||||
|
```
|
||||||
|
{% endnote %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
| Option | Required | Usage |
|
||||||
|
|--------|:--------:|-----|
|
||||||
|
| `<database>` | {% octicon "check-circle-fill" aria-label="Required" %} | Specify the path for the directory that contains the {% data variables.product.prodname_codeql %} database to analyze. |
|
||||||
|
| `<queries>` | {% octicon "check-circle-fill" aria-label="Required" %} | Specify the queries to run. To run the standard queries used for {% data variables.product.prodname_code_scanning %}, use: `<language>-code-scanning.qls` where `<language>` is the short code for the language of the database. To see the other query suites included in the {% data variables.product.prodname_codeql_cli %} bundle, look in `/<extraction-root>/codeql/qlpacks/codeql-<language>/codeql-suites`. For information about creating your own query suite, see [Creating CodeQL query suites](https://codeql.github.com/docs/codeql-cli/creating-codeql-query-suites/) in the documentation for the {% data variables.product.prodname_codeql_cli %}.
|
||||||
|
| <nobr>`--format`</nobr> | {% octicon "check-circle-fill" aria-label="Required" %} | Specify the format for the results file generated by the command. For upload to {% data variables.product.company_short %} this should be: {% if currentVersion == "free-pro-team@latest" or currentVersion == "github-ae@latest" %}`sarif-latest`{% else %}`sarifv2.1.0`{% endif %}. For more information, see "[SARIF support for {% data variables.product.prodname_code_scanning %}](/code-security/secure-coding/sarif-support-for-code-scanning)."
|
||||||
|
| <nobr>`--output`</nobr> | {% octicon "check-circle-fill" aria-label="Required" %} | Specify where to save the SARIF results file.{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.1" or currentVersion == "github-ae@next" %}
|
||||||
|
| <nobr>`--sarif-category`<nobr> | {% octicon "question" aria-label="Required with multiple results sets" %} | Optional for single database analysis. Required to define the language when you analyze multiple databases for a single commit in a repository. Specify a category to include in the SARIF results file for this analysis. A category is used to distinguish multiple analyses for the same tool and commit, but performed on different languages or different parts of the code.|{% endif %}
|
||||||
|
| <nobr>`--threads`</nobr> | | Optional. Use if you want to use more than one thread to run queries. The default value is `1`. You can specify more threads to speed up query execution. To set the number of threads to the number of logical processors, specify `0`.
|
||||||
|
| <nobr>`--verbose`</nobr> | | Optional. Use to get more detailed information about the analysis process{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.1" or currentVersion == "github-ae@next" %} and diagnostic data from the database creation process{% endif %}.
|
||||||
|
|
||||||
|
For more information, see [Analyzing databases with the {% data variables.product.prodname_codeql_cli %}](https://codeql.github.com/docs/codeql-cli/analyzing-databases-with-the-codeql-cli/) in the documentation for the {% data variables.product.prodname_codeql_cli %}.
|
||||||
|
|
||||||
|
### Basic example
|
||||||
|
|
||||||
|
This example analyzes a {% data variables.product.prodname_codeql %} database stored at `/codeql-dbs/example-repo` and saves the results as a SARIF file: `/temp/example-repo-js.sarif`. {% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.1" or currentVersion == "github-ae@next" %}It uses `--sarif-category` to include extra information in the SARIF file that identifies the results as JavaScript. This is essential when you have more than one {% data variables.product.prodname_codeql %} database to analyze for a single commit in a repository.{% endif %}
|
||||||
|
|
||||||
|
```
|
||||||
|
$ codeql database analyze /codeql-dbs/example-repo \
|
||||||
|
javascript-code-scanning.qls {% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.1" or currentVersion == "github-ae@next" %}--sarif-category=javascript{% endif %}
|
||||||
|
--format={% if currentVersion == "free-pro-team@latest" or currentVersion == "github-ae@latest" %}sarif-latest{% else %}sarifv2.1.0{% endif %} --output=/temp/example-repo-js.sarif
|
||||||
|
|
||||||
|
> Running queries.
|
||||||
|
> Compiling query plan for /codeql-home/codeql/qlpacks/
|
||||||
|
codeql-javascript/AngularJS/DisablingSce.ql.
|
||||||
|
...
|
||||||
|
> Shutting down query evaluator.
|
||||||
|
> Interpreting results.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Uploading results to {% data variables.product.product_name %}
|
||||||
|
|
||||||
|
{% data reusables.code-scanning.upload-sarif-alert-limit %}
|
||||||
|
|
||||||
|
Before you can upload results to {% data variables.product.product_name %}, you must determine the best way to pass the {% data variables.product.prodname_github_app %} or personal access token you created earlier to the {% data variables.product.prodname_codeql_cli %} (see [Installing {% data variables.product.prodname_codeql_cli %} in your CI system](/code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/installing-codeql-cli-in-your-ci-system#generating-a-token-for-authentication-with-github)). We recommend that you review your CI system's guidance on the secure use of a secret store. The {% data variables.product.prodname_codeql_cli %} supports:
|
||||||
|
|
||||||
|
- Passing the token to the CLI via standard input using the `--github-auth-stdin` option (recommended).
|
||||||
|
- Saving the secret in the environment variable `GITHUB_TOKEN` and running the CLI without including the `--github-auth-stdin` option.
|
||||||
|
|
||||||
|
When you have decided on the most secure and reliable method for your CI server, run `codeql github upload-results` on each SARIF results file and include `--github-auth-stdin` unless the token is available in the environment variable `GITHUB_TOKEN`.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
echo "$UPLOAD_TOKEN" | codeql github upload-results --repository=<repository-name> \
|
||||||
|
--ref=<ref> --commit=<commit> --sarif=<file> \
|
||||||
|
{% if currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@next" %}--github-url=<URL> {% endif %}--github-auth-stdin
|
||||||
|
```
|
||||||
|
|
||||||
|
| Option | Required | Usage |
|
||||||
|
|--------|:--------:|-----|
|
||||||
|
| <nobr>`--repository`</nobr> | {% octicon "check-circle-fill" aria-label="Required" %} | Specify the *OWNER/NAME* of the repository to upload data to. The owner must be an organization within an enterprise that has a license for {% data variables.product.prodname_GH_advanced_security %} and {% data variables.product.prodname_GH_advanced_security %} must be enabled for the repository{% if currentVersion == "free-pro-team@latest" %}, unless the repository is public{% endif %}. For more information, see "[Managing security and analysis settings for your repository](/github/administering-a-repository/managing-security-and-analysis-settings-for-your-repository)."
|
||||||
|
| <nobr>`--ref`</nobr> | {% octicon "check-circle-fill" aria-label="Required" %} | Specify the name of the `ref` you checked out and analyzed so that the results can be matched to the correct code. For a branch use: `refs/heads/BRANCH-NAME`, for the head commit of a pull request use `refs/pulls/NUMBER/head`, or for the {% data variables.product.product_name %}-generated merge commit of a pull request use `refs/pulls/NUMBER/merge`.
|
||||||
|
| <nobr>`--commit`</nobr> | {% octicon "check-circle-fill" aria-label="Required" %} | Specify the full SHA of the commit you analyzed.
|
||||||
|
| <nobr>`--sarif`</nobr> | {% octicon "check-circle-fill" aria-label="Required" %} | Specify the SARIF file to load.{% if currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@next" %}
|
||||||
|
| <nobr>`--github-url`</nobr> | {% octicon "check-circle-fill" aria-label="Required" %} | Specify the URL for {% data variables.product.product_name %}.{% endif %}
|
||||||
|
| <nobr>`--github-auth-stdin`</nobr> | | Optional. Use to pass the CLI the {% data variables.product.prodname_github_app %} or personal access token created for authentication with {% data variables.product.company_short %}'s REST API via standard input. This is not needed if the command has access to a `GITHUB_TOKEN` environment variable set with this token.
|
||||||
|
|
||||||
|
For more information, see [github upload-results](https://codeql.github.com/docs/codeql-cli/manual/github-upload-results/) in the documentation for the {% data variables.product.prodname_codeql_cli %}.
|
||||||
|
|
||||||
|
### Basic example
|
||||||
|
|
||||||
|
This example uploads results from the SARIF file `temp/example-repo-js.sarif` to the repository `my-org/example-repo`. It tells the {% data variables.product.prodname_code_scanning %} API that the results are for the commit `deb275d2d5fe9a522a0b7bd8b6b6a1c939552718` on the `main` branch.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ echo $UPLOAD_TOKEN | codeql github upload-results --repository=my-org/example-repo \
|
||||||
|
--ref=refs/heads/main --commit=deb275d2d5fe9a522a0b7bd8b6b6a1c939552718 \
|
||||||
|
--sarif=/temp/example-repo-js.sarif {% if currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@next" %}--github-url={% data variables.command_line.git_url_example %} \
|
||||||
|
{% endif %}--github-auth-stdin
|
||||||
|
```
|
||||||
|
|
||||||
|
There is no output from this command unless the upload was unsuccessful. The command prompt returns when the upload is complete and data processing has begun. On smaller codebases, you should be able to explore the {% data variables.product.prodname_code_scanning %} alerts in {% data variables.product.product_name %} shortly afterward. You can see alerts directly in the pull request or on the **Security** tab for branches, depending on the code you checked out. For more information, see "[Triaging {% data variables.product.prodname_code_scanning %} alerts in pull requests](/code-security/secure-coding/triaging-code-scanning-alerts-in-pull-requests)" and "[Managing {% data variables.product.prodname_code_scanning %} alerts for your repository](/code-security/secure-coding/managing-code-scanning-alerts-for-your-repository)."
|
||||||
|
|
||||||
|
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.1" or currentVersion == "github-ae@next" %}
|
||||||
|
## Example CI configuration for {% data variables.product.prodname_codeql %} analysis
|
||||||
|
|
||||||
|
This is an example of the series of commands that you might use to analyze a codebase with two supported languages and then upload the results to {% data variables.product.product_name %}.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# Create CodeQL databases for Java and Python in the 'codeql-dbs' directory
|
||||||
|
# Call the normal build script for the codebase: 'myBuildScript'
|
||||||
|
|
||||||
|
codeql database create codeql-dbs --source-root=src \
|
||||||
|
--db-cluster --language=java,python --command=./myBuildScript
|
||||||
|
|
||||||
|
# Analyze the CodeQL database for Java, 'codeql-dbs/java'
|
||||||
|
# Tag the data as 'java' results and store in: 'java-results.sarif'
|
||||||
|
|
||||||
|
codeql database analyze codeql-dbs/java java-code-scanning.qls \
|
||||||
|
--format=sarif-latest --sarif-category=java --output=java-results.sarif
|
||||||
|
|
||||||
|
# Analyze the CodeQL database for Python, 'codeql-dbs/python'
|
||||||
|
# Tag the data as 'python' results and store in: 'python-results.sarif'
|
||||||
|
|
||||||
|
codeql database analyze codeql-dbs/python python-code-scanning.qls \
|
||||||
|
--format=sarif-latest --sarif-category=python --output=python-results.sarif
|
||||||
|
|
||||||
|
# Upload the SARIF file with the Java results: 'java-results.sarif'
|
||||||
|
|
||||||
|
echo $UPLOAD_TOKEN | codeql github upload-results --repository=my-org/example-repo \
|
||||||
|
--ref=refs/heads/main --commit=deb275d2d5fe9a522a0b7bd8b6b6a1c939552718 \
|
||||||
|
--sarif=java-results.sarif --github-auth-stdin
|
||||||
|
|
||||||
|
# Upload the SARIF file with the Python results: 'python-results.sarif'
|
||||||
|
|
||||||
|
echo $UPLOAD_TOKEN | codeql github upload-results --repository=my-org/example-repo \
|
||||||
|
--ref=refs/heads/main --commit=deb275d2d5fe9a522a0b7bd8b6b6a1c939552718 \
|
||||||
|
--sarif=python-results.sarif --github-auth-stdin
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting the {% data variables.product.prodname_codeql_cli %} in your CI system
|
||||||
|
|
||||||
|
### Diagnostic data and summary metrics
|
||||||
|
|
||||||
|
When you analyze a {% data variables.product.prodname_codeql %} database using a {% data variables.product.prodname_code_scanning %} query suite, in addition to generating detailed information about alerts, the CLI reports diagnostic data from the database generation step and summary metrics. For repositories with few alerts, you may find this information useful for determining if there are genuinely few problems in the code, or if there were errors generating the {% data variables.product.prodname_codeql %} database. For more detailed output from `codeql database analyze`, use the `--verbose` option.
|
||||||
|
|
||||||
|
### {% data variables.product.prodname_code_scanning %} only shows analysis results from one of the analized languages
|
||||||
|
|
||||||
|
By default, {% data variables.product.prodname_code_scanning %} expects one SARIF results file per analysis for a repository. Consequently, when you upload a second SARIF results file for a commit, it is treated as a replacement for the original set of data.
|
||||||
|
|
||||||
|
If you want to upload more than one set of results to the {% data variables.product.prodname_code_scanning %} API for a commit in a repository, you must identify each set of results as a unique set. For repositories where you create more than one {% data variables.product.prodname_codeql %} database to analyze for each commit, use the `--sarif-category` option to specify a language or other unique category for each SARIF file that you generate for that repository.
|
||||||
|
|
||||||
|
### Alternative if your CI system cannot trigger the {% data variables.product.prodname_codeql_cli %}
|
||||||
|
|
||||||
|
{% data reusables.code-scanning.use-codeql-runner-not-cli %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
## Further reading
|
||||||
|
|
||||||
|
- [Creating CodeQL databases](https://codeql.github.com/docs/codeql-cli/creating-codeql-databases/)
|
||||||
|
- [Analyzing databases with the CodeQL CLI](https://codeql.github.com/docs/codeql-cli/analyzing-databases-with-the-codeql-cli/)
|
||||||
@@ -18,7 +18,8 @@ topics:
|
|||||||
- CodeQL
|
- CodeQL
|
||||||
children:
|
children:
|
||||||
- /about-codeql-code-scanning-in-your-ci-system
|
- /about-codeql-code-scanning-in-your-ci-system
|
||||||
- /running-codeql-cli-in-your-ci-system
|
- /installing-codeql-cli-in-your-ci-system
|
||||||
|
- /configuring-codeql-cli-in-your-ci-system
|
||||||
- /running-codeql-runner-in-your-ci-system
|
- /running-codeql-runner-in-your-ci-system
|
||||||
- /configuring-codeql-runner-in-your-ci-system
|
- /configuring-codeql-runner-in-your-ci-system
|
||||||
- /troubleshooting-codeql-runner-in-your-ci-system
|
- /troubleshooting-codeql-runner-in-your-ci-system
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
---
|
||||||
|
title: Installing CodeQL CLI in your CI system
|
||||||
|
shortTitle: Installing CodeQL CLI
|
||||||
|
intro: 'You can install the {% data variables.product.prodname_codeql_cli %} and use it to perform {% data variables.product.prodname_codeql %} {% data variables.product.prodname_code_scanning %} in a third-party continuous integration system.'
|
||||||
|
product: '{% data reusables.gated-features.code-scanning %}'
|
||||||
|
miniTocMaxHeadingLevel: 3
|
||||||
|
versions:
|
||||||
|
free-pro-team: '*'
|
||||||
|
enterprise-server: '>=3.1'
|
||||||
|
github-ae: 'next'
|
||||||
|
type: how_to
|
||||||
|
topics:
|
||||||
|
- Advanced Security
|
||||||
|
- Code scanning
|
||||||
|
- CodeQL
|
||||||
|
- Repositories
|
||||||
|
- Pull requests
|
||||||
|
- Integration
|
||||||
|
- CI
|
||||||
|
- SARIF
|
||||||
|
redirect_from:
|
||||||
|
- /code-security/secure-coding/running-codeql-cli-in-your-ci-system
|
||||||
|
- /code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/running-codeql-cli-in-your-ci-system
|
||||||
|
---
|
||||||
|
{% data reusables.code-scanning.enterprise-enable-code-scanning %}
|
||||||
|
|
||||||
|
## About using the {% data variables.product.prodname_codeql_cli %} for {% data variables.product.prodname_code_scanning %}
|
||||||
|
|
||||||
|
You can use the {% data variables.product.prodname_codeql_cli %} to run {% data variables.product.prodname_code_scanning %} on code that you're processing in a third-party continuous integration (CI) system. {% data reusables.code-scanning.about-code-scanning %} For information, see "[About {% data variables.product.prodname_code_scanning %}](/code-security/secure-coding/about-code-scanning)."
|
||||||
|
|
||||||
|
{% data reusables.code-scanning.what-is-codeql-cli %}
|
||||||
|
|
||||||
|
Alternatively, you can use {% data variables.product.prodname_actions %} to run {% data variables.product.prodname_code_scanning %} within {% data variables.product.product_name %}. For information about {% data variables.product.prodname_code_scanning %} using actions, see "[Setting up {% data variables.product.prodname_code_scanning %} for a repository](/code-security/secure-coding/setting-up-code-scanning-for-a-repository)." For an overview of the options for CI systems, see "[About CodeQL {% data variables.product.prodname_code_scanning %} in your CI system](/code-security/secure-coding/about-codeql-code-scanning-in-your-ci-system)".
|
||||||
|
|
||||||
|
{% data reusables.code-scanning.licensing-note %}
|
||||||
|
|
||||||
|
## Downloading the {% data variables.product.prodname_codeql_cli %}
|
||||||
|
|
||||||
|
You should download the {% data variables.product.prodname_codeql %} bundle from https://github.com/github/codeql-action/releases. The bundle contains:
|
||||||
|
|
||||||
|
- {% data variables.product.prodname_codeql_cli %} product
|
||||||
|
- A compatible version of the queries and libraries from https://github.com/github/codeql
|
||||||
|
- Precompiled versions of all the queries included in the bundle
|
||||||
|
|
||||||
|
You should always use the {% data variables.product.prodname_codeql %} bundle as this ensures compatibility and also gives much better performance than a separate download of the {% data variables.product.prodname_codeql_cli %} and checkout of the {% data variables.product.prodname_codeql %} queries. If you will only be running the CLI on one specific platform, download the appropriate `codeql-bundle-PLATFORM.tar.gz` file. Alternatively, you can download `codeql-bundle.tar.gz`, which contains the CLI for all supported platforms.
|
||||||
|
|
||||||
|
## Setting up the {% data variables.product.prodname_codeql_cli %} in your CI system
|
||||||
|
|
||||||
|
You need to make the full contents of the {% data variables.product.prodname_codeql_cli %} bundle available to every CI server that you want to run CodeQL {% data variables.product.prodname_code_scanning %} analysis on. For example, you might configure each server to copy the bundle from a central, internal location and extract it. Alternatively, you could use the REST API to get the bundle directly from {% data variables.product.prodname_dotcom %}, ensuring that you benefit from the latest improvements to queries. Updates to the {% data variables.product.prodname_codeql_cli %} are released every 2-3 weeks. For example:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ wget https://{% if currentVersion == "free-pro-team@latest" %}github.com{% else %}<em>HOSTNAME</em>{% endif %}/github/codeql-action/releases/latest/download/codeql-bundle-linux64.tar.gz
|
||||||
|
$ tar -xvzf ../codeql-bundle-linux64.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
After you extract the {% data variables.product.prodname_codeql_cli %} bundle, you can run the `codeql` executable on the server:
|
||||||
|
|
||||||
|
- By executing `/<extraction-root>/codeql/codeql`, where `<extraction-root>` is the folder where you extracted the {% data variables.product.prodname_codeql_cli %} bundle.
|
||||||
|
- By adding `/<extraction-root>/codeql` to your `PATH`, so that you can run the executable as just `codeql`.
|
||||||
|
|
||||||
|
## Testing the {% data variables.product.prodname_codeql_cli %} set up
|
||||||
|
|
||||||
|
After you extract the {% data variables.product.prodname_codeql_cli %} bundle, you can run the following command to verify that the CLI is correctly set up to create and analyze databases.
|
||||||
|
|
||||||
|
- `codeql resolve qlpacks` if `/<extraction-root>/codeql` is on the `PATH`.
|
||||||
|
- `/<extraction-root>/codeql/codeql resolve qlpacks` otherwise.
|
||||||
|
|
||||||
|
**Extract from successful output:**
|
||||||
|
```
|
||||||
|
codeql-cpp (/<extraction-root>/codeql/qlpacks/codeql-cpp)
|
||||||
|
codeql-cpp-examples (/<extraction-root>/codeql/qlpacks/codeql-cpp-examples)
|
||||||
|
codeql-cpp-upgrades (/<extraction-root>/codeql/qlpacks/codeql-cpp-upgrades)
|
||||||
|
codeql-csharp (/<extraction-root>/codeql/qlpacks/codeql-csharp)
|
||||||
|
codeql-csharp-examples (/<extraction-root>/codeql/qlpacks/codeql-csharp-examples)
|
||||||
|
codeql-csharp-upgrades (/<extraction-root>/codeql/qlpacks/codeql-csharp-upgrades)
|
||||||
|
codeql-go (/<extraction-root>/codeql/qlpacks/codeql-go)
|
||||||
|
codeql-go-examples (/<extraction-root>/codeql/qlpacks/codeql-go-examples)
|
||||||
|
codeql-go-upgrades (/<extraction-root>/codeql/qlpacks/codeql-go-upgrades)
|
||||||
|
codeql-java (/<extraction-root>/codeql/qlpacks/codeql-java)
|
||||||
|
codeql-java-examples (/<extraction-root>/codeql/qlpacks/codeql-java-examples)
|
||||||
|
codeql-java-upgrades (/<extraction-root>/codeql/qlpacks/codeql-java-upgrades)
|
||||||
|
codeql-javascript (/<extraction-root>/codeql/qlpacks/codeql-javascript)
|
||||||
|
codeql-javascript-examples (/<extraction-root>/codeql/qlpacks/codeql-javascript-examples)
|
||||||
|
codeql-javascript-upgrades (/<extraction-root>/codeql/qlpacks/codeql-javascript-upgrades)
|
||||||
|
codeql-python (/<extraction-root>/codeql/qlpacks/codeql-python)
|
||||||
|
codeql-python-examples (/<extraction-root>/codeql/qlpacks/codeql-python-examples)
|
||||||
|
codeql-python-upgrades (/<extraction-root>/codeql/qlpacks/codeql-python-upgrades)
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
You should check that the output contains the expected languages and also that the directory location for the qlpack files is correct. The location should be within the extracted {% data variables.product.prodname_codeql_cli %} bundle, shown above as `<extraction root>`, unless you are using a checkout of `github/codeql`. If the {% data variables.product.prodname_codeql_cli %} is unable to locate the qlpacks for the expected languages, check that you downloaded the {% data variables.product.prodname_codeql %} bundle and not a standalone copy of the {% data variables.product.prodname_codeql_cli %}.
|
||||||
|
|
||||||
|
## Generating a token for authentication with {% data variables.product.product_name %}
|
||||||
|
|
||||||
|
Each CI server needs a {% data variables.product.prodname_github_app %} or personal access token for the {% data variables.product.prodname_codeql_cli %} to use to upload results to {% data variables.product.product_name %}. You must use an access token or a {% data variables.product.prodname_github_app %} with the `security_events` write permission. If CI servers already use a token with this scope to checkout repositories from {% data variables.product.product_name %}, you could potentially allow the {% data variables.product.prodname_codeql_cli %} to use the same token. Otherwise, you should create a new token with the `security_events` write permission and add this to the CI system's secret store. For information, see "[Building {% data variables.product.prodname_github_apps %}](/developers/apps/building-github-apps)" and "[Creating a personal access token](/github/authenticating-to-github/creating-a-personal-access-token)."
|
||||||
|
|
||||||
|
## Next steps
|
||||||
|
|
||||||
|
You're now ready to configure the CI system to run {% data variables.product.prodname_codeql %} analysis, generate results, and upload them to {% data variables.product.product_name %} where the results will be matched to a branch or pull request and displayed as {% data variables.product.prodname_code_scanning %} alerts. For detailed information, see "[Configuring {% data variables.product.prodname_codeql_cli %} in your CI system](/code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/configuring-codeql-cli-in-your-ci-system)."
|
||||||
@@ -1,225 +0,0 @@
|
|||||||
---
|
|
||||||
title: Running CodeQL CLI in your CI system
|
|
||||||
shortTitle: Running CodeQL CLI
|
|
||||||
intro: 'You can use the {% data variables.product.prodname_codeql_cli %} to perform {% data variables.product.prodname_codeql %} {% data variables.product.prodname_code_scanning %} in a third-party continuous integration system.'
|
|
||||||
product: '{% data reusables.gated-features.code-scanning %}'
|
|
||||||
miniTocMaxHeadingLevel: 3
|
|
||||||
versions:
|
|
||||||
free-pro-team: '*'
|
|
||||||
enterprise-server: '>=3.1'
|
|
||||||
github-ae: 'next'
|
|
||||||
type: how_to
|
|
||||||
topics:
|
|
||||||
- Advanced Security
|
|
||||||
- Code scanning
|
|
||||||
- CodeQL
|
|
||||||
- Repositories
|
|
||||||
- Pull requests
|
|
||||||
- Integration
|
|
||||||
- CI
|
|
||||||
- SARIF
|
|
||||||
redirect_from:
|
|
||||||
- /code-security/secure-coding/running-codeql-cli-in-your-ci-system
|
|
||||||
---
|
|
||||||
{% data reusables.code-scanning.enterprise-enable-code-scanning %}
|
|
||||||
|
|
||||||
## About the {% data variables.product.prodname_codeql_cli %}
|
|
||||||
|
|
||||||
You can use the {% data variables.product.prodname_codeql_cli %} to run {% data variables.product.prodname_code_scanning %} on code that you're processing in a third-party continuous integration (CI) system. {% data reusables.code-scanning.about-code-scanning %} For information, see "[About {% data variables.product.prodname_code_scanning %}](/code-security/secure-coding/about-code-scanning)."
|
|
||||||
|
|
||||||
{% data reusables.code-scanning.what-is-codeql-cli %}
|
|
||||||
|
|
||||||
Alternatively, you can use {% data variables.product.prodname_codeql_runner %} in your CI system, or {% data variables.product.prodname_actions %} to run {% data variables.product.prodname_code_scanning %} within {% data variables.product.product_name %}. For an overview of the options for CI systems, see "[About CodeQL {% data variables.product.prodname_code_scanning %} in your CI system](/code-security/secure-coding/about-codeql-code-scanning-in-your-ci-system)". For information about {% data variables.product.prodname_code_scanning %} using actions, see "[Setting up {% data variables.product.prodname_code_scanning %} for a repository](/code-security/secure-coding/setting-up-code-scanning-for-a-repository)."
|
|
||||||
|
|
||||||
{% note %}
|
|
||||||
|
|
||||||
**Note:** {% if currentVersion == "free-pro-team@latest" %}
|
|
||||||
The {% data variables.product.prodname_codeql_cli %} is free to use on public repositories that are maintained on {% data variables.product.prodname_dotcom_the_website %}, and available to use on private repositories that are owned by customers with an {% data variables.product.prodname_advanced_security %} license. For information, see "[{% data variables.product.product_name %} {% data variables.product.prodname_codeql %} Terms and Conditions](https://securitylab.github.com/tools/codeql/license)" and "[{% data variables.product.prodname_codeql %} CLI](https://codeql.github.com/docs/codeql-cli/)."
|
|
||||||
{%- else %}The {% data variables.product.prodname_codeql_cli %} is available to customers with an {% data variables.product.prodname_advanced_security %} license.
|
|
||||||
{% endif %}
|
|
||||||
{% endnote %}
|
|
||||||
|
|
||||||
## Downloading the {% data variables.product.prodname_codeql_cli %}
|
|
||||||
|
|
||||||
You should download the {% data variables.product.prodname_codeql %} bundle from https://github.com/github/codeql-action/releases. The bundle contains:
|
|
||||||
|
|
||||||
- {% data variables.product.prodname_codeql_cli %} product
|
|
||||||
- A compatible version of the queries and libraries from https://github.com/github/codeql
|
|
||||||
- Precompiled versions of all the queries included in the bundle
|
|
||||||
|
|
||||||
You should always use the {% data variables.product.prodname_codeql %} bundle as this ensures compatibility and also gives much better performance than a separate download of the {% data variables.product.prodname_codeql_cli %} and checkout of the {% data variables.product.prodname_codeql %} queries. If you will only be running the CLI on one specific platform, download the appropriate `codeql-bundle-PLATFORM.tar.gz` file. Alternatively, you can download `codeql-bundle.tar.gz`, which contains the CLI for all supported platforms.
|
|
||||||
|
|
||||||
## Setting up the {% data variables.product.prodname_codeql_cli %} in your CI system
|
|
||||||
|
|
||||||
You need to make the full contents of the {% data variables.product.prodname_codeql_cli %} bundle available to every CI server that you want to run CodeQL {% data variables.product.prodname_code_scanning %} analysis on. For example, you might configure each server to copy the bundle from a central, internal location and extract it. Alternatively, you could use the REST API to get the bundle directly from {% data variables.product.prodname_dotcom %}, ensuring that you benefit from the latest improvements to queries. Updates to the {% data variables.product.prodname_codeql_cli %} are released every 2-3 weeks. For example:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ wget https://{% if currentVersion == "free-pro-team@latest" %}github.com{% else %}<em>HOSTNAME</em>{% endif %}/github/codeql-action/releases/latest/download/codeql-bundle-linux64.tar.gz
|
|
||||||
$ tar -xvzf ../codeql-bundle-linux64.tar.gz
|
|
||||||
```
|
|
||||||
|
|
||||||
After you extract the {% data variables.product.prodname_codeql_cli %} bundle, you can run the `codeql` executable on the server:
|
|
||||||
|
|
||||||
- By executing `/extraction-root/codeql/codeql`, where `<extraction-root>` is the folder where you extracted the {% data variables.product.prodname_codeql_cli %} bundle.
|
|
||||||
- By adding `/extraction-root/codeql` to your `PATH`, so that you can run the executable as just `codeql`.
|
|
||||||
|
|
||||||
## Testing the {% data variables.product.prodname_codeql_cli %} set up
|
|
||||||
|
|
||||||
After you extract the {% data variables.product.prodname_codeql_cli %} bundle, you can run the following command to verify that the CLI is correctly set up to create and analyze databases.
|
|
||||||
|
|
||||||
- `codeql resolve languages` if `/extraction-root/codeql` is on the `PATH`.
|
|
||||||
- `/extraction-root/codeql/codeql resolve languages` otherwise.
|
|
||||||
|
|
||||||
**Example of successful output:**
|
|
||||||
```
|
|
||||||
cpp (/extraction-root/codeql/cpp)
|
|
||||||
csharp (/extraction-root/codeql/csharp)
|
|
||||||
csv (/extraction-root/codeql/csv)
|
|
||||||
go (/extraction-root/codeql/go)
|
|
||||||
html (/extraction-root/codeql/html)
|
|
||||||
java (/extraction-root/codeql/java)
|
|
||||||
javascript (/extraction-root/codeql/javascript)
|
|
||||||
properties (/extraction-root/codeql/properties)
|
|
||||||
python (/extraction-root/codeql/python)
|
|
||||||
xml (/extraction-root/codeql/xml)
|
|
||||||
```
|
|
||||||
|
|
||||||
If the {% data variables.product.prodname_codeql_cli %} is unable to resolve the expected languages, check that you downloaded the {% data variables.product.prodname_codeql %} bundle and not a standalone copy of the {% data variables.product.prodname_codeql_cli %}.
|
|
||||||
|
|
||||||
## Generating a token for authentication with {% data variables.product.product_name %}
|
|
||||||
|
|
||||||
Each CI server needs a {% data variables.product.prodname_github_app %} or personal access token for the {% data variables.product.prodname_codeql_cli %} to use to upload results to {% data variables.product.product_name %}. You must use an access token or a {% data variables.product.prodname_github_app %} with the `security_events` write permission. If CI servers already use a token with this scope to checkout repositories from {% data variables.product.product_name %}, you could potentially allow the {% data variables.product.prodname_codeql_cli %} to use the same token. Otherwise, you should create a new token with the `security_events` write permission and add this to the CI system's secret store. For information, see "[Building {% data variables.product.prodname_github_apps %}](/developers/apps/building-github-apps)" and "[Creating a personal access token](/github/authenticating-to-github/creating-a-personal-access-token)."
|
|
||||||
|
|
||||||
## Using the {% data variables.product.prodname_codeql_cli %} to generate data and upload it to {% data variables.product.product_name %}
|
|
||||||
|
|
||||||
You call the {% data variables.product.prodname_codeql_cli %} to analyze the codebase in three steps:
|
|
||||||
|
|
||||||
1. Create a {% data variables.product.prodname_codeql %} database to represent a single programming language in the repository using: `codeql database create`
|
|
||||||
2. Run queries to analyze the {% data variables.product.prodname_codeql %} database and summarize the results in a SARIF file using: `codeql database analyze`
|
|
||||||
3. Upload the SARIF file to {% data variables.product.product_name %} where the results are matched to a branch or pull request and displayed as {% data variables.product.prodname_code_scanning %} alerts using: `codeql github upload-results`
|
|
||||||
|
|
||||||
Each command has a few mandatory options with additional options that you can use to modify the behavior of the command. You can display the command-line help for any command using the <nobr>`--help`</nobr> option.
|
|
||||||
|
|
||||||
{% data reusables.code-scanning.upload-sarif-ghas %}
|
|
||||||
|
|
||||||
### Creating a {% data variables.product.prodname_codeql %} database to analyze
|
|
||||||
|
|
||||||
1. Check out the code that you want to analyze:
|
|
||||||
- For a branch checkout the head of the branch that you want to analyze.
|
|
||||||
- For a pull request checkout either the head commit of the pull request, or check out a {% data variables.product.product_name %}-generated merge commit of the pull request.
|
|
||||||
2. Set up the environment for the codebase, making sure that any dependencies are available. For more information, see [Creating databases for non-compiled languages](https://codeql.github.com/docs/codeql-cli/creating-codeql-databases/#creating-databases-for-non-compiled-languages) and [Creating databases for compiled languages](https://codeql.github.com/docs/codeql-cli/creating-codeql-databases/#creating-databases-for-compiled-languages) in the documentation for the {% data variables.product.prodname_codeql_cli %}.
|
|
||||||
3. Run `codeql database create` from the checkout root of your repository.
|
|
||||||
```shell
|
|
||||||
codeql database create <database> --language=<language-identifier>
|
|
||||||
```
|
|
||||||
{% note %}
|
|
||||||
|
|
||||||
**Note:** If you use a containerized build, you need to run the {% data variables.product.prodname_codeql_cli %} inside the container where your build task takes place.
|
|
||||||
|
|
||||||
{% endnote %}
|
|
||||||
|
|
||||||
| Option | Required | Usage |
|
|
||||||
|--------|:--------:|-----|
|
|
||||||
| `<database>` | {% octicon "check-circle-fill" aria-label="Required" %} | Specify the name and location of a directory to create for the {% data variables.product.prodname_codeql %} database. The command will fail if you try to overwrite an existing directory. |
|
|
||||||
| <nobr>`--language`</nobr> | {% octicon "check-circle-fill" aria-label="Required" %} | Specify the identifier for the language to create a database for, one of: `{% data reusables.code-scanning.codeql-languages-keywords %}` (use `javascript` to analyze TypeScript code).
|
|
||||||
| <nobr>`--source-root`</nobr> | | Optional. Use if you run the CLI outside the checkout root of the repository. By default, the `database create` command assumes that the current directory is the root directory for the source files, use this option to specify a different location. |
|
|
||||||
| <nobr>`--command`</nobr> | | Optional for compiled languages. Use if you want to override the CLI's automatic build system detection and compilation. Specify the build command or script that invokes the compiler. Commands are run from the current folder or, where it is defined, from <nobr>`--source-root`</nobr>. Do not use this option for Python and JavaScript/TypeScript analysis. |
|
|
||||||
|
|
||||||
For more information, see [Creating {% data variables.product.prodname_codeql %} databases](https://codeql.github.com/docs/codeql-cli/creating-codeql-databases/) in the documentation for the {% data variables.product.prodname_codeql_cli %}.
|
|
||||||
|
|
||||||
#### Basic example
|
|
||||||
|
|
||||||
```
|
|
||||||
$ codeql database create /codeql-dbs/example-repo --language=javascript \
|
|
||||||
--source-root /checkouts/example-repo
|
|
||||||
|
|
||||||
> Initializing database at /codeql-dbs/example-repo.
|
|
||||||
> Running command [/codeql-home/codeql/javascript/tools/autobuild.cmd]
|
|
||||||
in /checkouts/example-repo.
|
|
||||||
> [build-stdout] Single-threaded extraction.
|
|
||||||
> [build-stdout] Extracting
|
|
||||||
...
|
|
||||||
> Finalizing database at /codeql-dbs/example-repo.
|
|
||||||
> Successfully created database at /codeql-dbs/example-repo.
|
|
||||||
```
|
|
||||||
|
|
||||||
For more information and examples, see [Creating {% data variables.product.prodname_codeql %} databases ](https://codeql.github.com/docs/codeql-cli/creating-codeql-databases) in the documentation for the {% data variables.product.prodname_codeql_cli %}.
|
|
||||||
|
|
||||||
### Analyzing a {% data variables.product.prodname_codeql %} database
|
|
||||||
|
|
||||||
1. Create a {% data variables.product.prodname_codeql %} database (see above).
|
|
||||||
2. Run `codeql database analyze` on the database and specify which queries to use.
|
|
||||||
```shell
|
|
||||||
codeql database analyze <database> --format=<format> \
|
|
||||||
--output=<output> <queries>
|
|
||||||
```
|
|
||||||
|
|
||||||
| Option | Required | Usage |
|
|
||||||
|--------|:--------:|-----|
|
|
||||||
| `<database>` | {% octicon "check-circle-fill" aria-label="Required" %} | Specify the path for the directory that contains the {% data variables.product.prodname_codeql %} database to analyze. |
|
|
||||||
| `<queries>` | {% octicon "check-circle-fill" aria-label="Required" %} | Specify the queries to run. To run the standard queries used for {% data variables.product.prodname_code_scanning %}, use: `<language>-code-scanning.qls` where `<language>` is the short code for the language of the database. To see the other query suites included in the {% data variables.product.prodname_codeql_cli %} bundle look in `/extraction-root/codeql/qlpacks/codeql-<language>/codeql-suites`. For information about creating your own query suite, see [Creating CodeQL query suites](https://codeql.github.com/docs/codeql-cli/creating-codeql-query-suites/) in the documentation for the {% data variables.product.prodname_codeql_cli %}.
|
|
||||||
| <nobr>`--format`</nobr> | {% octicon "check-circle-fill" aria-label="Required" %} | Specify the format for the results file generated by the command. For upload to {% data variables.product.company_short %} this should be: {% if currentVersion == "free-pro-team@latest" %}`sarif-latest`{% else %}`sarifv2.1.0`{% endif %}. For more information, see "[SARIF support for {% data variables.product.prodname_code_scanning %}](/code-security/secure-coding/sarif-support-for-code-scanning)."
|
|
||||||
| <nobr>`--output`</nobr> | {% octicon "check-circle-fill" aria-label="Required" %} | Specify where to save the SARIF results file.{% if currentVersion == "free-pro-team@latest" %}
|
|
||||||
| <nobr>`--sarif-category`<nobr> | | Optional. Specify a category to include in the SARIF results file for this analysis. A category can be used to distinguish multiple analyses for the same tool and commit, but performed on different languages or different parts of the code. This value will appear in the `<run>.automationId` property in SARIF v1, the `<run>.automationLogicalId` property in SARIF v2, and the `<run>.automationDetails.id` property in SARIF v2.1.0. |{% endif %}
|
|
||||||
| <nobr>`--threads`</nobr> | | Optional. Use if you want to use more than one thread to run queries. The default value is `1`. You can specify more threads to speed up query execution. To set the number of threads to the number of logical processors, specify `0`.
|
|
||||||
|
|
||||||
For more information, see [Analyzing databases with the {% data variables.product.prodname_codeql_cli %}](https://codeql.github.com/docs/codeql-cli/analyzing-databases-with-the-codeql-cli/) in the documentation for the {% data variables.product.prodname_codeql_cli %}.
|
|
||||||
|
|
||||||
#### Basic example
|
|
||||||
|
|
||||||
```
|
|
||||||
$ codeql database analyze /codeql-dbs/example-repo \
|
|
||||||
javascript-code-scanning.qls --format={% if currentVersion == "free-pro-team@latest" %}sarif-latest{% else %}sarifv2.1.0{% endif %} \
|
|
||||||
--output=/temp/example-repo-js.sarif
|
|
||||||
|
|
||||||
> Running queries.
|
|
||||||
> Compiling query plan for /codeql-home/codeql/qlpacks/
|
|
||||||
codeql-javascript/AngularJS/DisablingSce.ql.
|
|
||||||
...
|
|
||||||
> Shutting down query evaluator.
|
|
||||||
> Interpreting results.
|
|
||||||
```
|
|
||||||
|
|
||||||
### Uploading results to {% data variables.product.product_name %}
|
|
||||||
|
|
||||||
{% data reusables.code-scanning.upload-sarif-alert-limit %}
|
|
||||||
|
|
||||||
Before you can upload results to {% data variables.product.product_name %}, you must determine the best way to pass the {% data variables.product.prodname_github_app %} or personal access token you created earlier to the {% data variables.product.prodname_codeql_cli %} (see [Generating a token for authentication with {% data variables.product.product_name %}](#generating-a-token-for-authentication-with-github) above). We recommend that you review your CI system's guidance on the secure use of the secret store. The {% data variables.product.prodname_codeql_cli %} supports:
|
|
||||||
|
|
||||||
- Passing the token to the CLI via standard input using the `--github-auth-stdin` option (recommended).
|
|
||||||
- Saving the secret in the environment variable `GITHUB_TOKEN` and running the CLI without including the `--github-auth-stdin` option.
|
|
||||||
|
|
||||||
When you have decided on the most secure and reliable method for your CI server, run `codeql github upload-results` on the SARIF results file and include `--github-auth-stdin` unless the token is available in the environment variable `GITHUB_TOKEN`.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
echo "$UPLOAD_TOKEN" | codeql github upload-results --repository=<repository-name> \
|
|
||||||
--ref=<ref> --commit=<commit> --sarif=<file> \
|
|
||||||
{% if currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@next" %}--github-url=<URL> {% endif %}--github-auth-stdin
|
|
||||||
```
|
|
||||||
|
|
||||||
| Option | Required | Usage |
|
|
||||||
|--------|:--------:|-----|
|
|
||||||
| <nobr>`--repository`</nobr> | {% octicon "check-circle-fill" aria-label="Required" %} | Specify the *OWNER/NAME* of the repository to upload data to. The owner must be an organization within an enterprise that has a license for {% data variables.product.prodname_GH_advanced_security %} and {% data variables.product.prodname_GH_advanced_security %} must be enabled for the repository{% if currentVersion == "free-pro-team@latest" %}, unless the repository is public{% endif %}. For more information, see "[Managing security and analysis settings for your repository](/github/administering-a-repository/managing-security-and-analysis-settings-for-your-repository)."
|
|
||||||
| <nobr>`--ref`</nobr> | {% octicon "check-circle-fill" aria-label="Required" %} | Specify the name of the `ref` you checked out and analyzed so that the results can be matched to the correct code. For a branch use: `refs/heads/BRANCH-NAME`, for the head commit of a pull request use `refs/pulls/NUMBER/head`, or for the {% data variables.product.product_name %}-generated merge commit of a pull request use `refs/pulls/NUMBER/merge`.
|
|
||||||
| <nobr>`--commit`</nobr> | {% octicon "check-circle-fill" aria-label="Required" %} | Specify the full SHA of the commit you analyzed.
|
|
||||||
| <nobr>`--sarif`</nobr> | {% octicon "check-circle-fill" aria-label="Required" %} | Specify the SARIF file to load.{% if currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@next" %}
|
|
||||||
| <nobr>`--github-url`</nobr> | {% octicon "check-circle-fill" aria-label="Required" %} | Specify the URL for {% data variables.product.product_name %}.{% endif %}
|
|
||||||
| <nobr>`--github-auth-stdin`</nobr> | | Optional. Use to pass the CLI the {% data variables.product.prodname_github_app %} or personal access token created for authentication with {% data variables.product.company_short %}'s REST API via standard input. This is not needed if the command has access to a `GITHUB_TOKEN` environment variable set with this token.
|
|
||||||
|
|
||||||
For more information, see [github upload-results](https://codeql.github.com/docs/codeql-cli/manual/github-upload-results/) in the documentation for the {% data variables.product.prodname_codeql_cli %}.
|
|
||||||
|
|
||||||
#### Basic example
|
|
||||||
|
|
||||||
```
|
|
||||||
$ echo $UPLOAD_TOKEN | codeql github upload-results --repository=my-org/example-repo \
|
|
||||||
--ref=refs/heads/main --commit=deb275d2d5fe9a522a0b7bd8b6b6a1c939552718 \
|
|
||||||
--sarif=/temp/example-repo-js.sarif {% if currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@next" %}--github-url={% data variables.command_line.git_url_example %} \
|
|
||||||
{% endif %}--github-auth-stdin
|
|
||||||
```
|
|
||||||
|
|
||||||
There is no output from this command unless the upload was unsuccessful. The command prompt returns when the upload is complete and data processing has begun. On smaller codebases, you should be able to explore the {% data variables.product.prodname_code_scanning %} alerts in {% data variables.product.product_name %} shortly afterward. Alerts are shown directly in the pull request or on the **Security** tab for branches, depending on the code that was checked out. For more information, see "[Triaging {% data variables.product.prodname_code_scanning %} alerts in pull requests](/code-security/secure-coding/triaging-code-scanning-alerts-in-pull-requests)" and "[Managing {% data variables.product.prodname_code_scanning %} alerts for your repository](/code-security/secure-coding/managing-code-scanning-alerts-for-your-repository)."
|
|
||||||
|
|
||||||
## Further reading
|
|
||||||
|
|
||||||
- [Creating CodeQL databases](https://codeql.github.com/docs/codeql-cli/creating-codeql-databases/)
|
|
||||||
- [Analyzing databases with the CodeQL CL](https://codeql.github.com/docs/codeql-cli/analyzing-databases-with-the-codeql-cli/)
|
|
||||||
@@ -24,7 +24,7 @@ topics:
|
|||||||
- SARIF
|
- SARIF
|
||||||
---
|
---
|
||||||
<!--For this article in earlier GHES versions, see /content/github/finding-security-vulnerabilities-and-errors-in-your-code-->
|
<!--For this article in earlier GHES versions, see /content/github/finding-security-vulnerabilities-and-errors-in-your-code-->
|
||||||
<!--UI-LINK: When GitHub Enterprise Server doesn't have GitHub Actions set up, the Security > Code scanning alerts view links to this article.-->
|
<!--UI-LINK: When GitHub Enterprise Server <=3.0 doesn't have GitHub Actions set up, the Security > Code scanning alerts view links to this article.-->
|
||||||
|
|
||||||
{% data reusables.code-scanning.beta-codeql-runner %}
|
{% data reusables.code-scanning.beta-codeql-runner %}
|
||||||
{% data reusables.code-scanning.beta %}
|
{% data reusables.code-scanning.beta %}
|
||||||
|
|||||||
@@ -70,11 +70,10 @@ Discover interesting projects using {% data variables.explore.explore_github %},
|
|||||||
## Celebrate
|
## Celebrate
|
||||||
|
|
||||||
You're now connected to the {% data variables.product.product_name %} community. What do you want to do next?
|
You're now connected to the {% data variables.product.product_name %} community. What do you want to do next?
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
- "[Set up Git](/articles/set-up-git)"
|
|
||||||
- "[Create a repository](/articles/create-a-repo)"
|
- To synchronize your {% data variables.product.product_name %} projects with your computer, you can set up Git. For more information see "[Set up Git](/articles/set-up-git)."
|
||||||
- "[Fork a repository](/articles/fork-a-repo)"
|
- You can also create a repository, where you can put all your projects and maintain your workflows. For more information see, "[Create a repository](/articles/create-a-repo)."
|
||||||
- **Be social**
|
- You can fork a repository to make changes you want to see without affecting the original repository. For more information, see "[Fork a repository](/articles/fork-a-repo)."
|
||||||
- {% data reusables.support.connect-in-the-forum-bootcamp %}
|
- {% data reusables.support.connect-in-the-forum-bootcamp %}
|
||||||
|
|||||||
@@ -79,11 +79,12 @@ Let's commit a change to the *README* file.
|
|||||||
|
|
||||||
## Celebrate
|
## Celebrate
|
||||||
|
|
||||||
Congratulations! You have now created a repository, including a *README* file, and created your first commit on {% data variables.product.product_location %}. What do you want to do next?
|
Congratulations! You have now created a repository, including a *README* file, and created your first commit on {% data variables.product.product_location %}.
|
||||||
|
|
||||||
- "[Set up Git](/articles/set-up-git)"
|
You can now clone a {% data variables.product.product_name %} repository to create a local copy on your computer. From your local repository you can commit, and create a pull request to update the changes in the upstream repository. For more information, see "[Cloning a repository](/github/creating-cloning-and-archiving-repositories/cloning-a-repository)" and "[Set up Git](/articles/set-up-git)."
|
||||||
- **Create a repository**
|
|
||||||
- "[Clone a repository](/github/creating-cloning-and-archiving-repositories/cloning-a-repository)"
|
You can find interesting projects and repositories on {% data variables.product.product_name %} and make changes to them by creating a fork of the repository. For more information see, "[Fork a repository](/articles/fork-a-repo)."
|
||||||
- "[Fork a repository](/articles/fork-a-repo)"
|
|
||||||
- "[Be social](/articles/be-social)"
|
Each repository in {% data variables.product.product_name %} is owned by a person or an organization. You can interact with the people, repositories, and organizations by connecting and following them on {% data variables.product.product_name %}. For more information see "[Be social](/articles/be-social)."
|
||||||
- {% data reusables.support.connect-in-the-forum-bootcamp %}
|
|
||||||
|
{% data reusables.support.connect-in-the-forum-bootcamp %}
|
||||||
|
|||||||
@@ -148,10 +148,10 @@ Fork a repository to start contributing to a project. {% data reusables.reposito
|
|||||||
|
|
||||||
## Celebrate
|
## Celebrate
|
||||||
|
|
||||||
You have now forked a repository, practiced cloning your fork, and configured an upstream repository. What do you want to do next?
|
You have now forked a repository, practiced cloning your fork, and configured an upstream repository. For more information about cloning the fork and syncing the changes in a forked repository from your computer see "[Set up Git](/articles/set-up-git)."
|
||||||
|
|
||||||
- "[Set up Git](/articles/set-up-git)"
|
You can also create a new repository where you can put all your projects and share the code on {% data variables.product.prodname_dotcom %}. For more information see, "[Create a repository](/articles/create-a-repo)."
|
||||||
- "[Create a repository](/articles/create-a-repo)"
|
|
||||||
- **Fork a repository**
|
Each repository in {% data variables.product.product_name %} is owned by a person or an organization. You can interact with the people, repositories, and organizations by connecting and following them on {% data variables.product.product_name %}. For more information see "[Be social](/articles/be-social)."
|
||||||
- "[Be social](/articles/be-social)"
|
|
||||||
- {% data reusables.support.connect-in-the-forum-bootcamp %}
|
{% data reusables.support.connect-in-the-forum-bootcamp %}
|
||||||
|
|||||||
@@ -56,10 +56,10 @@ If you [clone with SSH](/github/getting-started-with-github/about-remote-reposit
|
|||||||
|
|
||||||
## Celebrate
|
## Celebrate
|
||||||
|
|
||||||
Congratulations, you now have Git and {% data variables.product.product_name %} all set up! What do you want to do next?
|
Congratulations, you now have Git and {% data variables.product.product_name %} all set up! You may now choose to create a repository where you can put your projects. This is a great way to back up your code and makes it easy to share the code around the world. For more information see "[Create a repository](/articles/create-a-repo)".
|
||||||
|
|
||||||
- **Set up Git**
|
You can create a copy of a repository by forking it and propose the changes that you want to see without affecting the upstream repository. For more information see "[Fork a repository](/articles/fork-a-repo)."
|
||||||
- "[Create a repository](/articles/create-a-repo)"
|
|
||||||
- "[Fork a repository](/articles/fork-a-repo)"
|
Each repository in {% data variables.product.product_name %} is owned by a person or an organization. You can interact with the people, repositories, and organizations by connecting and following them on {% data variables.product.product_name %}. For more information see "[Be social](/articles/be-social)."
|
||||||
- "[Be social](/articles/be-social)"
|
|
||||||
- {% data reusables.support.connect-in-the-forum-bootcamp %}
|
{% data reusables.support.connect-in-the-forum-bootcamp %}
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ topics:
|
|||||||
```shell
|
```shell
|
||||||
$ gpg --default-new-key-algo rsa4096 --gen-key
|
$ gpg --default-new-key-algo rsa4096 --gen-key
|
||||||
```
|
```
|
||||||
4. At the prompt, specify the kind of key you want, or press `Enter` to accept the default `RSA and RSA`.
|
4. At the prompt, specify the kind of key you want, or press `Enter` to accept the default.
|
||||||
5. Enter the desired key size. Your key must be at least `4096` bits.
|
5. At the prompt, specify the key size you want, or press `Enter` to accept the default. Your key must be at least `4096` bits.
|
||||||
6. Enter the length of time the key should be valid. Press `Enter` to specify the default selection, indicating that the key doesn't expire.
|
6. Enter the length of time the key should be valid. Press `Enter` to specify the default selection, indicating that the key doesn't expire.
|
||||||
7. Verify that your selections are correct.
|
7. Verify that your selections are correct.
|
||||||
8. Enter your user ID information.
|
8. Enter your user ID information.
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
title: Comparing commits
|
title: Comparing commits
|
||||||
|
intro: You can compare the state of your repository across branches, tags, commits, forks, and dates.
|
||||||
redirect_from:
|
redirect_from:
|
||||||
- /articles/comparing-commits-across-time
|
- /articles/comparing-commits-across-time
|
||||||
- /github/committing-changes-to-your-project/comparing-commits-across-time
|
- /github/committing-changes-to-your-project/comparing-commits-across-time
|
||||||
@@ -9,7 +10,7 @@ versions:
|
|||||||
enterprise-server: '*'
|
enterprise-server: '*'
|
||||||
github-ae: '*'
|
github-ae: '*'
|
||||||
---
|
---
|
||||||
You can compare the state of your repository across branches, tags, commits, and dates. To compare different versions of your repository, append `/compare` to your repository's path.
|
To compare different versions of your repository, append `/compare` to your repository's path.
|
||||||
|
|
||||||
We'll demonstrate the power of Compare by looking at the compare page for [a fork of the Linguist repo](https://github.com/octocat/linguist), which is at [https://github.com/octocat/linguist/compare/master...octocat:master](https://github.com/octocat/linguist/compare/master...octocat:master).
|
We'll demonstrate the power of Compare by looking at the compare page for [a fork of the Linguist repo](https://github.com/octocat/linguist), which is at [https://github.com/octocat/linguist/compare/master...octocat:master](https://github.com/octocat/linguist/compare/master...octocat:master).
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
title: Differences between commit views
|
title: Differences between commit views
|
||||||
|
intro: You might observe differences in commit history depending on the chosen viewing method.
|
||||||
redirect_from:
|
redirect_from:
|
||||||
- /articles/differences-between-commit-views
|
- /articles/differences-between-commit-views
|
||||||
- /github/committing-changes-to-your-project/differences-between-commit-views
|
- /github/committing-changes-to-your-project/differences-between-commit-views
|
||||||
|
|||||||
@@ -735,6 +735,36 @@ type App implements Node {
|
|||||||
description: String
|
description: String
|
||||||
id: ID!
|
id: ID!
|
||||||
|
|
||||||
|
"""
|
||||||
|
The IP addresses of the app.
|
||||||
|
"""
|
||||||
|
ipAllowListEntries(
|
||||||
|
"""
|
||||||
|
Returns the elements in the list that come after the specified cursor.
|
||||||
|
"""
|
||||||
|
after: String
|
||||||
|
|
||||||
|
"""
|
||||||
|
Returns the elements in the list that come before the specified cursor.
|
||||||
|
"""
|
||||||
|
before: String
|
||||||
|
|
||||||
|
"""
|
||||||
|
Returns the first _n_ elements from the list.
|
||||||
|
"""
|
||||||
|
first: Int
|
||||||
|
|
||||||
|
"""
|
||||||
|
Returns the last _n_ elements from the list.
|
||||||
|
"""
|
||||||
|
last: Int
|
||||||
|
|
||||||
|
"""
|
||||||
|
Ordering options for IP allow list entries returned.
|
||||||
|
"""
|
||||||
|
orderBy: IpAllowListEntryOrder = {field: ALLOW_LIST_VALUE, direction: ASC}
|
||||||
|
): IpAllowListEntryConnection!
|
||||||
|
|
||||||
"""
|
"""
|
||||||
The hex color code, without the leading '#', for the logo background.
|
The hex color code, without the leading '#', for the logo background.
|
||||||
"""
|
"""
|
||||||
@@ -5599,7 +5629,7 @@ input CreateIpAllowListEntryInput {
|
|||||||
"""
|
"""
|
||||||
The ID of the owner for which to create the new IP allow list entry.
|
The ID of the owner for which to create the new IP allow list entry.
|
||||||
"""
|
"""
|
||||||
ownerId: ID! @possibleTypes(concreteTypes: ["Enterprise", "Organization"], abstractType: "IpAllowListOwner")
|
ownerId: ID! @possibleTypes(concreteTypes: ["App", "Enterprise", "Organization"], abstractType: "IpAllowListOwner")
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@@ -12851,7 +12881,7 @@ enum IpAllowListForInstalledAppsEnabledSettingValue {
|
|||||||
"""
|
"""
|
||||||
Types that can own an IP allow list.
|
Types that can own an IP allow list.
|
||||||
"""
|
"""
|
||||||
union IpAllowListOwner = Enterprise | Organization
|
union IpAllowListOwner = App | Enterprise | Organization
|
||||||
|
|
||||||
"""
|
"""
|
||||||
An Issue is a place to discuss ideas, enhancements, tasks, and bugs for a project.
|
An Issue is a place to discuss ideas, enhancements, tasks, and bugs for a project.
|
||||||
@@ -38626,7 +38656,7 @@ input UpdateIpAllowListEnabledSettingInput {
|
|||||||
"""
|
"""
|
||||||
The ID of the owner on which to set the IP allow list enabled setting.
|
The ID of the owner on which to set the IP allow list enabled setting.
|
||||||
"""
|
"""
|
||||||
ownerId: ID! @possibleTypes(concreteTypes: ["Enterprise", "Organization"], abstractType: "IpAllowListOwner")
|
ownerId: ID! @possibleTypes(concreteTypes: ["App", "Enterprise", "Organization"], abstractType: "IpAllowListOwner")
|
||||||
|
|
||||||
"""
|
"""
|
||||||
The value for the IP allow list enabled setting.
|
The value for the IP allow list enabled setting.
|
||||||
@@ -38706,7 +38736,7 @@ input UpdateIpAllowListForInstalledAppsEnabledSettingInput {
|
|||||||
"""
|
"""
|
||||||
The ID of the owner.
|
The ID of the owner.
|
||||||
"""
|
"""
|
||||||
ownerId: ID! @possibleTypes(concreteTypes: ["Enterprise", "Organization"], abstractType: "IpAllowListOwner")
|
ownerId: ID! @possibleTypes(concreteTypes: ["App", "Enterprise", "Organization"], abstractType: "IpAllowListOwner")
|
||||||
|
|
||||||
"""
|
"""
|
||||||
The value for the IP allow list configuration for installed GitHub Apps setting.
|
The value for the IP allow list configuration for installed GitHub Apps setting.
|
||||||
|
|||||||
@@ -825,6 +825,36 @@ type App implements Node {
|
|||||||
description: String
|
description: String
|
||||||
id: ID!
|
id: ID!
|
||||||
|
|
||||||
|
"""
|
||||||
|
The IP addresses of the app.
|
||||||
|
"""
|
||||||
|
ipAllowListEntries(
|
||||||
|
"""
|
||||||
|
Returns the elements in the list that come after the specified cursor.
|
||||||
|
"""
|
||||||
|
after: String
|
||||||
|
|
||||||
|
"""
|
||||||
|
Returns the elements in the list that come before the specified cursor.
|
||||||
|
"""
|
||||||
|
before: String
|
||||||
|
|
||||||
|
"""
|
||||||
|
Returns the first _n_ elements from the list.
|
||||||
|
"""
|
||||||
|
first: Int
|
||||||
|
|
||||||
|
"""
|
||||||
|
Returns the last _n_ elements from the list.
|
||||||
|
"""
|
||||||
|
last: Int
|
||||||
|
|
||||||
|
"""
|
||||||
|
Ordering options for IP allow list entries returned.
|
||||||
|
"""
|
||||||
|
orderBy: IpAllowListEntryOrder = {field: ALLOW_LIST_VALUE, direction: ASC}
|
||||||
|
): IpAllowListEntryConnection!
|
||||||
|
|
||||||
"""
|
"""
|
||||||
The hex color code, without the leading '#', for the logo background.
|
The hex color code, without the leading '#', for the logo background.
|
||||||
"""
|
"""
|
||||||
@@ -5754,7 +5784,7 @@ input CreateIpAllowListEntryInput {
|
|||||||
"""
|
"""
|
||||||
The ID of the owner for which to create the new IP allow list entry.
|
The ID of the owner for which to create the new IP allow list entry.
|
||||||
"""
|
"""
|
||||||
ownerId: ID! @possibleTypes(concreteTypes: ["Enterprise", "Organization"], abstractType: "IpAllowListOwner")
|
ownerId: ID! @possibleTypes(concreteTypes: ["App", "Enterprise", "Organization"], abstractType: "IpAllowListOwner")
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@@ -7315,13 +7345,20 @@ type DependencyGraphDependency @preview(toggledBy: "hawkgirl-preview") {
|
|||||||
"""
|
"""
|
||||||
hasDependencies: Boolean!
|
hasDependencies: Boolean!
|
||||||
|
|
||||||
|
"""
|
||||||
|
The original name of the package, as it appears in the manifest.
|
||||||
|
"""
|
||||||
|
packageLabel: String!
|
||||||
|
|
||||||
"""
|
"""
|
||||||
The dependency package manager
|
The dependency package manager
|
||||||
"""
|
"""
|
||||||
packageManager: String
|
packageManager: String
|
||||||
|
|
||||||
"""
|
"""
|
||||||
The required package name
|
The name of the package in the canonical form used by the package manager.
|
||||||
|
This may differ from the original textual form (see packageLabel), for example
|
||||||
|
in a package manager that uses case-insensitive comparisons.
|
||||||
"""
|
"""
|
||||||
packageName: String!
|
packageName: String!
|
||||||
|
|
||||||
@@ -13597,7 +13634,7 @@ enum IpAllowListForInstalledAppsEnabledSettingValue {
|
|||||||
"""
|
"""
|
||||||
Types that can own an IP allow list.
|
Types that can own an IP allow list.
|
||||||
"""
|
"""
|
||||||
union IpAllowListOwner = Enterprise | Organization
|
union IpAllowListOwner = App | Enterprise | Organization
|
||||||
|
|
||||||
"""
|
"""
|
||||||
An Issue is a place to discuss ideas, enhancements, tasks, and bugs for a project.
|
An Issue is a place to discuss ideas, enhancements, tasks, and bugs for a project.
|
||||||
@@ -41950,7 +41987,7 @@ input UpdateIpAllowListEnabledSettingInput {
|
|||||||
"""
|
"""
|
||||||
The ID of the owner on which to set the IP allow list enabled setting.
|
The ID of the owner on which to set the IP allow list enabled setting.
|
||||||
"""
|
"""
|
||||||
ownerId: ID! @possibleTypes(concreteTypes: ["Enterprise", "Organization"], abstractType: "IpAllowListOwner")
|
ownerId: ID! @possibleTypes(concreteTypes: ["App", "Enterprise", "Organization"], abstractType: "IpAllowListOwner")
|
||||||
|
|
||||||
"""
|
"""
|
||||||
The value for the IP allow list enabled setting.
|
The value for the IP allow list enabled setting.
|
||||||
@@ -42030,7 +42067,7 @@ input UpdateIpAllowListForInstalledAppsEnabledSettingInput {
|
|||||||
"""
|
"""
|
||||||
The ID of the owner.
|
The ID of the owner.
|
||||||
"""
|
"""
|
||||||
ownerId: ID! @possibleTypes(concreteTypes: ["Enterprise", "Organization"], abstractType: "IpAllowListOwner")
|
ownerId: ID! @possibleTypes(concreteTypes: ["App", "Enterprise", "Organization"], abstractType: "IpAllowListOwner")
|
||||||
|
|
||||||
"""
|
"""
|
||||||
The value for the IP allow list configuration for installed GitHub Apps setting.
|
The value for the IP allow list configuration for installed GitHub Apps setting.
|
||||||
|
|||||||
@@ -102,7 +102,8 @@ code_security_ci:
|
|||||||
description: 'Set up CodeQL within your existing CI and upload results to GitHub code scanning.'
|
description: 'Set up CodeQL within your existing CI and upload results to GitHub code scanning.'
|
||||||
guides:
|
guides:
|
||||||
- /code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/about-codeql-code-scanning-in-your-ci-system
|
- /code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/about-codeql-code-scanning-in-your-ci-system
|
||||||
- /code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/running-codeql-cli-in-your-ci-system
|
- /code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/installing-codeql-cli-in-your-ci-system
|
||||||
|
- /code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/configuring-codeql-cli-in-your-ci-system
|
||||||
- /code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/running-codeql-runner-in-your-ci-system
|
- /code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/running-codeql-runner-in-your-ci-system
|
||||||
- /code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/configuring-codeql-runner-in-your-ci-system
|
- /code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/configuring-codeql-runner-in-your-ci-system
|
||||||
- /code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/troubleshooting-codeql-runner-in-your-ci-system
|
- /code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/troubleshooting-codeql-runner-in-your-ci-system
|
||||||
|
|||||||
7
data/reusables/code-scanning/licensing-note.md
Normal file
7
data/reusables/code-scanning/licensing-note.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{% note %}
|
||||||
|
|
||||||
|
**Note:** {% if currentVersion == "free-pro-team@latest" %}
|
||||||
|
The {% data variables.product.prodname_codeql_cli %} is free to use on public repositories that are maintained on {% data variables.product.prodname_dotcom_the_website %}, and available to use on private repositories that are owned by customers with an {% data variables.product.prodname_advanced_security %} license. For information, see "[{% data variables.product.product_name %} {% data variables.product.prodname_codeql %} Terms and Conditions](https://securitylab.github.com/tools/codeql/license)" and "[{% data variables.product.prodname_codeql %} CLI](https://codeql.github.com/docs/codeql-cli/)."
|
||||||
|
{%- else %}The {% data variables.product.prodname_codeql_cli %} is available to customers with an {% data variables.product.prodname_advanced_security %} license.
|
||||||
|
{% endif %}
|
||||||
|
{% endnote %}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.1" or currentVersion == "github-ae@next" %}
|
||||||
|
If the {% data variables.product.prodname_codeql_cli %} is unsuitable for use in your CI system, the {% data variables.product.prodname_codeql_runner %} is available as an alternative. Typically, this is needed if the CI system would need to orchestrate compiler invocations as well as running {% data variables.product.prodname_codeql %} analysis. For more information, see "[Running {% data variables.product.prodname_codeql_runner %} in your CI system](/code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/running-codeql-runner-in-your-ci-system)."
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if currentVersion == "enterprise-server@3.1" %}
|
||||||
|
You will need to use the {% data variables.product.prodname_codeql_runner %} if you need to:
|
||||||
|
- Set up the CI system to orchestrate compiler invocations as well as running {% data variables.product.prodname_codeql %} analysis.
|
||||||
|
- Analyze more than one language in a repository.
|
||||||
|
{% endif %}
|
||||||
@@ -1 +1 @@
|
|||||||
Connect with people around the world in the [{% data variables.product.prodname_gcf %}](https://github.community)
|
{% data variables.product.product_name %} has a great support community where you can ask for help and talk to people from around the world. Join the conversation on [Github Support Community](https://github.community/).
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<head>
|
<head>
|
||||||
{% comment %} For human readers {% endcomment %}
|
{% comment %} For human readers {% endcomment %}
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>{% if error == '404' %}{% data ui.errors.oops %}{% elsif currentVersion == 'homepage' %}GitHub Documentation{% elsif page.fullTitle %}{{ page.fullTitle }}{% else %}GitHub Documentation{% endif %}</title>
|
<title>{% if error == '404' %}{% data ui.errors.oops %}{% elsif page.documentType == 'homepage' and currentVersion == 'free-pro-team@latest' %}GitHub Documentation{% elsif page.fullTitle %}{{ page.fullTitle }}{% else %}GitHub Documentation{% endif %}</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="alternate icon" type="image/png" href="/assets/images/site/favicon.png">
|
<link rel="alternate icon" type="image/png" href="/assets/images/site/favicon.png">
|
||||||
<link rel="icon" type="image/svg+xml" href="/assets/images/site/favicon.svg">
|
<link rel="icon" type="image/svg+xml" href="/assets/images/site/favicon.svg">
|
||||||
|
|||||||
@@ -6,23 +6,17 @@
|
|||||||
<details class="dropdown-withArrow position-relative details details-reset mr-md-3 close-when-clicked-outside">
|
<details class="dropdown-withArrow position-relative details details-reset mr-md-3 close-when-clicked-outside">
|
||||||
<summary class="py-2 color-text-primary" role="button" aria-label="Toggle versions list">
|
<summary class="py-2 color-text-primary" role="button" aria-label="Toggle versions list">
|
||||||
<div class="d-flex flex-items-center flex-justify-between">
|
<div class="d-flex flex-items-center flex-justify-between">
|
||||||
{% if currentVersion == 'homepage' %}
|
|
||||||
{% data ui.homepage.version_picker %}
|
|
||||||
{% else %}
|
|
||||||
{{ allVersions[currentVersion].versionTitle }}
|
{{ allVersions[currentVersion].versionTitle }}
|
||||||
{% endif %}
|
|
||||||
<svg class="arrow ml-md-1" width="14px" height="8px" viewBox="0 0 14 8" xml:space="preserve" fill="none" stroke="currentColor"><path d="M1,1l6.2,6L13,1"></path></svg>
|
<svg class="arrow ml-md-1" width="14px" height="8px" viewBox="0 0 14 8" xml:space="preserve" fill="none" stroke="currentColor"><path d="M1,1l6.2,6L13,1"></path></svg>
|
||||||
</div>
|
</div>
|
||||||
</summary>
|
</summary>
|
||||||
<div id="versions-selector" class="position-md-absolute nav-desktop-langDropdown p-md-4 right-md-n4 top-md-6" style="z-index: 6;">
|
<div id="versions-selector" class="position-md-absolute nav-desktop-langDropdown p-md-4 right-md-n4 top-md-6" style="z-index: 6;">
|
||||||
{% for permalink in page.permalinks %}
|
{% for permalink in page.permalinks %}
|
||||||
{% unless permalink.pageVersion == 'homepage' %}
|
|
||||||
<a
|
<a
|
||||||
href="{{ permalink.href }}"
|
href="{{ permalink.href }}"
|
||||||
class="d-block py-2 no-underline {% if currentPath == permalink.href %}active{% else %}Link--primary{% endif %}"
|
class="d-block py-2 no-underline {% if currentPath == permalink.href %}active{% else %}Link--primary{% endif %}"
|
||||||
style="white-space: nowrap"
|
style="white-space: nowrap"
|
||||||
>{{ allVersions[permalink.pageVersion].versionTitle }}</a>
|
>{{ allVersions[permalink.pageVersion].versionTitle }}</a>
|
||||||
{% endunless %}
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% include all-enterprise-releases-link %}
|
{% include all-enterprise-releases-link %}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
<h2 class="text-mono f5 text-normal color-text-secondary text-md-center mb-4">{% data ui.homepage.explore_by_product %}</h2>
|
<h2 class="text-mono f5 text-normal color-text-secondary text-md-center mb-4">{% data ui.homepage.explore_by_product %}</h2>
|
||||||
<div class="d-flex flex-wrap gutter gutter-xl-spacious">
|
<div class="d-flex flex-wrap gutter gutter-xl-spacious">
|
||||||
{% for product in activeProducts %}
|
{% for product in activeProducts %}
|
||||||
{% if product.versions contains currentVersion or currentVersion == 'homepage' %}
|
{% if product.versions contains currentVersion %}
|
||||||
<div class="d-flex flex-column col-12 col-sm-6 col-lg-3 pb-4">
|
<div class="d-flex flex-column col-12 col-sm-6 col-lg-3 pb-4">
|
||||||
<a class="btn-mktg flex-auto d-flex flex-items-center btn-outline-mktg btn-large-mktg ws-normal " href="{% unless product.external %}/{{ currentLanguage }}{% endunless %}{% if product.versions contains currentVersion %}/{{currentVersion}}/{{product.id}}{% else %}{{product.href}}{% endif %}" {% if product.external %}target="_blank"{% endif %}>{{ product.name }}
|
<a class="btn-mktg flex-auto d-flex flex-items-center btn-outline-mktg btn-large-mktg ws-normal " href="{% unless product.external %}/{{ currentLanguage }}{% endunless %}{% if product.versions contains currentVersion %}/{{currentVersion}}/{{product.id}}{% else %}{{product.href}}{% endif %}" {% if product.external %}target="_blank"{% endif %}>{{ product.name }}
|
||||||
{% if product.external %}
|
{% if product.external %}
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ export default function () {
|
|||||||
const codeTerms = document.querySelectorAll('#article-contents table code')
|
const codeTerms = document.querySelectorAll('#article-contents table code')
|
||||||
if (!codeTerms) return
|
if (!codeTerms) return
|
||||||
|
|
||||||
codeTerms.forEach(node => {
|
codeTerms.forEach((node) => {
|
||||||
// Return early if a child node is an anchor element
|
// Return early if a child node is an anchor element
|
||||||
const hasChildAnchor = Array.from(node.childNodes).some(child => child.nodeName === 'A')
|
const hasChildAnchor = Array.from(node.childNodes).some((child) => child.nodeName === 'A')
|
||||||
if (hasChildAnchor) return
|
if (hasChildAnchor) return
|
||||||
|
|
||||||
// Do the wrapping on the inner text only
|
// Do the wrapping on the inner text only
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
const parse = require('./read-frontmatter')
|
const parse = require('./read-frontmatter')
|
||||||
const layoutNames = Object.keys(require('./layouts')).concat([false])
|
const semver = require('semver')
|
||||||
|
const layouts = require('./layouts')
|
||||||
|
|
||||||
|
const semverValidRange = semver.validRange
|
||||||
|
const layoutNames = Object.keys(layouts).concat([false])
|
||||||
const semverRange = {
|
const semverRange = {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
conform: require('semver').validRange,
|
conform: semverValidRange,
|
||||||
message: 'Must be a valid SemVer range'
|
message: 'Must be a valid SemVer range'
|
||||||
}
|
}
|
||||||
const versionIds = Object.keys(require('./all-versions'))
|
const versionIds = Object.keys(require('./all-versions'))
|
||||||
|
|||||||
@@ -1,4 +1,25 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"schemaChanges": [
|
||||||
|
{
|
||||||
|
"title": "The GraphQL schema includes these changes:",
|
||||||
|
"changes": [
|
||||||
|
"Field `ipAllowListEntries` was added to object type `App`",
|
||||||
|
"Member `App` was added to Union type `IpAllowListOwner`"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"previewChanges": [
|
||||||
|
{
|
||||||
|
"title": "The [Access to a repositories dependency graph preview](/graphql/overview/schema-previews#access-to-a-repositories-dependency-graph-preview) includes these changes:",
|
||||||
|
"changes": [
|
||||||
|
"Field `packageLabel` was added to object type `DependencyGraphDependency`"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"upcomingChanges": [],
|
||||||
|
"date": "2021-06-22"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"schemaChanges": [
|
"schemaChanges": [
|
||||||
{
|
{
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -7004,6 +7004,66 @@
|
|||||||
"kind": "scalars",
|
"kind": "scalars",
|
||||||
"href": "/graphql/reference/scalars#string"
|
"href": "/graphql/reference/scalars#string"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "ipAllowListEntries",
|
||||||
|
"description": "<p>The IP addresses of the app.</p>",
|
||||||
|
"type": "IpAllowListEntryConnection!",
|
||||||
|
"id": "ipallowlistentryconnection",
|
||||||
|
"kind": "objects",
|
||||||
|
"href": "/graphql/reference/objects#ipallowlistentryconnection",
|
||||||
|
"arguments": [
|
||||||
|
{
|
||||||
|
"name": "after",
|
||||||
|
"description": "<p>Returns the elements in the list that come after the specified cursor.</p>",
|
||||||
|
"type": {
|
||||||
|
"name": "String",
|
||||||
|
"id": "string",
|
||||||
|
"kind": "scalars",
|
||||||
|
"href": "/graphql/reference/scalars#string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "before",
|
||||||
|
"description": "<p>Returns the elements in the list that come before the specified cursor.</p>",
|
||||||
|
"type": {
|
||||||
|
"name": "String",
|
||||||
|
"id": "string",
|
||||||
|
"kind": "scalars",
|
||||||
|
"href": "/graphql/reference/scalars#string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "first",
|
||||||
|
"description": "<p>Returns the first <em>n</em> elements from the list.</p>",
|
||||||
|
"type": {
|
||||||
|
"name": "Int",
|
||||||
|
"id": "int",
|
||||||
|
"kind": "scalars",
|
||||||
|
"href": "/graphql/reference/scalars#int"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "last",
|
||||||
|
"description": "<p>Returns the last <em>n</em> elements from the list.</p>",
|
||||||
|
"type": {
|
||||||
|
"name": "Int",
|
||||||
|
"id": "int",
|
||||||
|
"kind": "scalars",
|
||||||
|
"href": "/graphql/reference/scalars#int"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "orderBy",
|
||||||
|
"description": "<p>Ordering options for IP allow list entries returned.</p>",
|
||||||
|
"type": {
|
||||||
|
"name": "IpAllowListEntryOrder",
|
||||||
|
"id": "ipallowlistentryorder",
|
||||||
|
"kind": "input-objects",
|
||||||
|
"href": "/graphql/reference/input-objects#ipallowlistentryorder"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "logoBackgroundColor",
|
"name": "logoBackgroundColor",
|
||||||
"description": "<p>The hex color code, without the leading '#', for the logo background.</p>",
|
"description": "<p>The hex color code, without the leading '#', for the logo background.</p>",
|
||||||
@@ -13540,6 +13600,14 @@
|
|||||||
"kind": "scalars",
|
"kind": "scalars",
|
||||||
"href": "/graphql/reference/scalars#boolean"
|
"href": "/graphql/reference/scalars#boolean"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "packageLabel",
|
||||||
|
"description": "<p>The original name of the package, as it appears in the manifest.</p>",
|
||||||
|
"type": "String!",
|
||||||
|
"id": "string",
|
||||||
|
"kind": "scalars",
|
||||||
|
"href": "/graphql/reference/scalars#string"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "packageManager",
|
"name": "packageManager",
|
||||||
"description": "<p>The dependency package manager.</p>",
|
"description": "<p>The dependency package manager.</p>",
|
||||||
@@ -13550,7 +13618,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "packageName",
|
"name": "packageName",
|
||||||
"description": "<p>The required package name.</p>",
|
"description": "<p>The name of the package in the canonical form used by the package manager.\nThis may differ from the original textual form (see packageLabel), for example\nin a package manager that uses case-insensitive comparisons.</p>",
|
||||||
"type": "String!",
|
"type": "String!",
|
||||||
"id": "string",
|
"id": "string",
|
||||||
"kind": "scalars",
|
"kind": "scalars",
|
||||||
@@ -66969,6 +67037,11 @@
|
|||||||
"href": "/graphql/reference/unions#ipallowlistowner",
|
"href": "/graphql/reference/unions#ipallowlistowner",
|
||||||
"description": "<p>Types that can own an IP allow list.</p>",
|
"description": "<p>Types that can own an IP allow list.</p>",
|
||||||
"possibleTypes": [
|
"possibleTypes": [
|
||||||
|
{
|
||||||
|
"name": "App",
|
||||||
|
"id": "app",
|
||||||
|
"href": "/graphql/reference/objects#app"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Enterprise",
|
"name": "Enterprise",
|
||||||
"id": "enterprise",
|
"id": "enterprise",
|
||||||
|
|||||||
@@ -5987,6 +5987,66 @@
|
|||||||
"kind": "scalars",
|
"kind": "scalars",
|
||||||
"href": "/graphql/reference/scalars#string"
|
"href": "/graphql/reference/scalars#string"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "ipAllowListEntries",
|
||||||
|
"description": "<p>The IP addresses of the app.</p>",
|
||||||
|
"type": "IpAllowListEntryConnection!",
|
||||||
|
"id": "ipallowlistentryconnection",
|
||||||
|
"kind": "objects",
|
||||||
|
"href": "/graphql/reference/objects#ipallowlistentryconnection",
|
||||||
|
"arguments": [
|
||||||
|
{
|
||||||
|
"name": "after",
|
||||||
|
"description": "<p>Returns the elements in the list that come after the specified cursor.</p>",
|
||||||
|
"type": {
|
||||||
|
"name": "String",
|
||||||
|
"id": "string",
|
||||||
|
"kind": "scalars",
|
||||||
|
"href": "/graphql/reference/scalars#string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "before",
|
||||||
|
"description": "<p>Returns the elements in the list that come before the specified cursor.</p>",
|
||||||
|
"type": {
|
||||||
|
"name": "String",
|
||||||
|
"id": "string",
|
||||||
|
"kind": "scalars",
|
||||||
|
"href": "/graphql/reference/scalars#string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "first",
|
||||||
|
"description": "<p>Returns the first <em>n</em> elements from the list.</p>",
|
||||||
|
"type": {
|
||||||
|
"name": "Int",
|
||||||
|
"id": "int",
|
||||||
|
"kind": "scalars",
|
||||||
|
"href": "/graphql/reference/scalars#int"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "last",
|
||||||
|
"description": "<p>Returns the last <em>n</em> elements from the list.</p>",
|
||||||
|
"type": {
|
||||||
|
"name": "Int",
|
||||||
|
"id": "int",
|
||||||
|
"kind": "scalars",
|
||||||
|
"href": "/graphql/reference/scalars#int"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "orderBy",
|
||||||
|
"description": "<p>Ordering options for IP allow list entries returned.</p>",
|
||||||
|
"type": {
|
||||||
|
"name": "IpAllowListEntryOrder",
|
||||||
|
"id": "ipallowlistentryorder",
|
||||||
|
"kind": "input-objects",
|
||||||
|
"href": "/graphql/reference/input-objects#ipallowlistentryorder"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "logoBackgroundColor",
|
"name": "logoBackgroundColor",
|
||||||
"description": "<p>The hex color code, without the leading '#', for the logo background.</p>",
|
"description": "<p>The hex color code, without the leading '#', for the logo background.</p>",
|
||||||
@@ -62000,6 +62060,11 @@
|
|||||||
"href": "/graphql/reference/unions#ipallowlistowner",
|
"href": "/graphql/reference/unions#ipallowlistowner",
|
||||||
"description": "<p>Types that can own an IP allow list.</p>",
|
"description": "<p>Types that can own an IP allow list.</p>",
|
||||||
"possibleTypes": [
|
"possibleTypes": [
|
||||||
|
{
|
||||||
|
"name": "App",
|
||||||
|
"id": "app",
|
||||||
|
"href": "/graphql/reference/objects#app"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Enterprise",
|
"name": "Enterprise",
|
||||||
"id": "enterprise",
|
"id": "enterprise",
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ function getVersionStringFromPath (href) {
|
|||||||
|
|
||||||
// Return immediately if this is a link to the homepage
|
// Return immediately if this is a link to the homepage
|
||||||
if (href === '/') {
|
if (href === '/') {
|
||||||
return 'homepage'
|
return nonEnterpriseDefaultVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the first segment
|
// Get the first segment
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ const assert = require('assert')
|
|||||||
const path = require('path')
|
const path = require('path')
|
||||||
const patterns = require('./patterns')
|
const patterns = require('./patterns')
|
||||||
const allVersions = require('./all-versions')
|
const allVersions = require('./all-versions')
|
||||||
const nonEnterpriseDefaultVersion = require('./non-enterprise-default-version')
|
|
||||||
const removeFPTFromPath = require('./remove-fpt-from-path')
|
const removeFPTFromPath = require('./remove-fpt-from-path')
|
||||||
|
|
||||||
class Permalink {
|
class Permalink {
|
||||||
@@ -27,24 +26,10 @@ class Permalink {
|
|||||||
assert(languageCode, 'languageCode is required')
|
assert(languageCode, 'languageCode is required')
|
||||||
|
|
||||||
const permalinks = applicableVersions
|
const permalinks = applicableVersions
|
||||||
// skip the Dotcom homepage here because a special homepage permalink is added below
|
|
||||||
.filter(pageVersion => !(pageVersion === nonEnterpriseDefaultVersion && relativePath === 'index.md'))
|
|
||||||
.map(pageVersion => {
|
.map(pageVersion => {
|
||||||
return new Permalink(languageCode, pageVersion, relativePath, title)
|
return new Permalink(languageCode, pageVersion, relativePath, title)
|
||||||
})
|
})
|
||||||
|
|
||||||
// special permalink for homepage
|
|
||||||
if (relativePath === 'index.md') {
|
|
||||||
const homepagePermalink = {
|
|
||||||
...permalinks[0],
|
|
||||||
href: '/' + languageCode,
|
|
||||||
pageVersion: 'homepage',
|
|
||||||
pageVersionTitle: permalinks[0].title,
|
|
||||||
homepage: true
|
|
||||||
}
|
|
||||||
permalinks.push(homepagePermalink)
|
|
||||||
}
|
|
||||||
|
|
||||||
return permalinks
|
return permalinks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const path = require('path')
|
const path = require('path')
|
||||||
const patterns = require('../patterns')
|
const patterns = require('../patterns')
|
||||||
const supportedVersions = new Set(Object.keys(require('../all-versions')))
|
const allVersions = require('../all-versions')
|
||||||
|
const supportedVersions = new Set(Object.keys(allVersions))
|
||||||
const getOldPathsFromPermalink = require('./get-old-paths-from-permalink')
|
const getOldPathsFromPermalink = require('./get-old-paths-from-permalink')
|
||||||
const { getVersionStringFromPath } = require('../path-utils')
|
const { getVersionStringFromPath } = require('../path-utils')
|
||||||
const { getNewVersionedPath } = require('../old-versions-utils')
|
const { getNewVersionedPath } = require('../old-versions-utils')
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const operations = {}
|
|||||||
fs.readdirSync(schemasPath)
|
fs.readdirSync(schemasPath)
|
||||||
.forEach(filename => {
|
.forEach(filename => {
|
||||||
const key = filename.replace('.json', '')
|
const key = filename.replace('.json', '')
|
||||||
const value = require(path.join(schemasPath, filename))
|
const value = JSON.parse(fs.readFileSync(path.join(schemasPath, filename)))
|
||||||
operations[key] = value
|
operations[key] = value
|
||||||
})
|
})
|
||||||
const allVersions = require('../all-versions')
|
const allVersions = require('../all-versions')
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ versions.forEach(version => {
|
|||||||
// payload file: /path/to/check_run.completed.payload.json
|
// payload file: /path/to/check_run.completed.payload.json
|
||||||
// payload path: check_run.completed
|
// payload path: check_run.completed
|
||||||
const payloadPath = path.basename(payloadFile).replace('.payload.json', '')
|
const payloadPath = path.basename(payloadFile).replace('.payload.json', '')
|
||||||
set(payloadsPerVersion, payloadPath, formatAsJsonCodeBlock(require(payloadFile)))
|
set(payloadsPerVersion, payloadPath, formatAsJsonCodeBlock(JSON.parse(fs.readFileSync(payloadFile))))
|
||||||
})
|
})
|
||||||
|
|
||||||
payloads[version] = payloadsPerVersion
|
payloads[version] = payloadsPerVersion
|
||||||
|
|||||||
@@ -34,14 +34,14 @@ module.exports = async function contextualize (req, res, next) {
|
|||||||
// e.g. searches for "req.context.page" will include results from this file
|
// e.g. searches for "req.context.page" will include results from this file
|
||||||
req.context.currentLanguage = req.language
|
req.context.currentLanguage = req.language
|
||||||
req.context.userLanguage = req.userLanguage
|
req.context.userLanguage = req.userLanguage
|
||||||
req.context.currentVersion = getVersionStringFromPath(req.path)
|
req.context.currentVersion = getVersionStringFromPath(req.pagePath)
|
||||||
req.context.currentProduct = getProductStringFromPath(req.path)
|
req.context.currentProduct = getProductStringFromPath(req.pagePath)
|
||||||
req.context.currentCategory = getCategoryStringFromPath(req.path)
|
req.context.currentCategory = getCategoryStringFromPath(req.pagePath)
|
||||||
req.context.productMap = productMap
|
req.context.productMap = productMap
|
||||||
req.context.activeProducts = activeProducts
|
req.context.activeProducts = activeProducts
|
||||||
req.context.allVersions = allVersions
|
req.context.allVersions = allVersions
|
||||||
req.context.currentPathWithoutLanguage = getPathWithoutLanguage(req.path)
|
req.context.currentPathWithoutLanguage = getPathWithoutLanguage(req.pagePath)
|
||||||
req.context.currentPath = req.path
|
req.context.currentPath = req.pagePath
|
||||||
req.context.query = req.query
|
req.context.query = req.query
|
||||||
req.context.languages = languages
|
req.context.languages = languages
|
||||||
req.context.productNames = productNames
|
req.context.productNames = productNames
|
||||||
@@ -52,13 +52,6 @@ module.exports = async function contextualize (req, res, next) {
|
|||||||
req.context.siteTree = siteTree
|
req.context.siteTree = siteTree
|
||||||
req.context.pages = pageMap
|
req.context.pages = pageMap
|
||||||
|
|
||||||
// TODO we should create new data directories for these example files instead of using variable files
|
|
||||||
if (productMap[req.context.currentProduct]) {
|
|
||||||
req.context.productCodeExamples = req.context.site.data.variables[`${productMap[req.context.currentProduct].id}_code_examples`]
|
|
||||||
req.context.productCommunityExamples = req.context.site.data.variables[`${productMap[req.context.currentProduct].id}_community_examples`]
|
|
||||||
req.context.productUserExamples = req.context.site.data.variables[`${productMap[req.context.currentProduct].id}_user_examples`]
|
|
||||||
}
|
|
||||||
|
|
||||||
// JS + CSS asset paths
|
// JS + CSS asset paths
|
||||||
req.context.builtAssets = builtAssets
|
req.context.builtAssets = builtAssets
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ module.exports = async function genericToc (req, res, next) {
|
|||||||
const currentTocType = tocTypes[req.context.page.documentType]
|
const currentTocType = tocTypes[req.context.page.documentType]
|
||||||
|
|
||||||
// Find the part of the site tree that corresponds to the current path.
|
// Find the part of the site tree that corresponds to the current path.
|
||||||
const treePage = findPageInSiteTree(req.context.currentProductTree, req.context.currentEnglishTree, req.path)
|
const treePage = findPageInSiteTree(req.context.currentProductTree, req.context.currentEnglishTree, req.pagePath)
|
||||||
|
|
||||||
// Conditionally run getTocItems() recursively.
|
// Conditionally run getTocItems() recursively.
|
||||||
let isRecursive
|
let isRecursive
|
||||||
@@ -50,7 +50,7 @@ module.exports = async function genericToc (req, res, next) {
|
|||||||
async function getTocItems (pagesArray, context, isRecursive, renderIntros) {
|
async function getTocItems (pagesArray, context, isRecursive, renderIntros) {
|
||||||
return (await Promise.all(pagesArray.map(async (child) => {
|
return (await Promise.all(pagesArray.map(async (child) => {
|
||||||
// Do not include hidden child items on a TOC page
|
// Do not include hidden child items on a TOC page
|
||||||
if (child.page.hidden) return
|
if (child.page.hidden && !context.currentPath.includes('/early-access/')) return
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: child.renderedFullTitle,
|
title: child.renderedFullTitle,
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
const previews = require('../../lib/graphql/static/previews')
|
const previews = require('../../lib/graphql/static/previews')
|
||||||
const upcomingChanges = require('../../lib/graphql/static/upcoming-changes')
|
const upcomingChanges = require('../../lib/graphql/static/upcoming-changes')
|
||||||
const changelog = require('../../lib/graphql/static/changelog')
|
const changelog = require('../../lib/graphql/static/changelog')
|
||||||
@@ -13,7 +15,7 @@ module.exports = function graphqlContext (req, res, next) {
|
|||||||
const currentVersionObj = allVersions[req.context.currentVersion]
|
const currentVersionObj = allVersions[req.context.currentVersion]
|
||||||
// ignore requests to non-GraphQL reference paths
|
// ignore requests to non-GraphQL reference paths
|
||||||
// and to versions that don't exist
|
// and to versions that don't exist
|
||||||
if (!req.path.includes('/graphql/') || !currentVersionObj) {
|
if (!req.pagePath.includes('/graphql/') || !currentVersionObj) {
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
// Get the relevant name of the GraphQL schema files for the current version
|
// Get the relevant name of the GraphQL schema files for the current version
|
||||||
@@ -23,7 +25,7 @@ module.exports = function graphqlContext (req, res, next) {
|
|||||||
const graphqlVersion = currentVersionObj.miscVersionName
|
const graphqlVersion = currentVersionObj.miscVersionName
|
||||||
|
|
||||||
req.context.graphql = {
|
req.context.graphql = {
|
||||||
schemaForCurrentVersion: require(`../../lib/graphql/static/schema-${graphqlVersion}`),
|
schemaForCurrentVersion: JSON.parse(fs.readFileSync(path.join(process.cwd(), `lib/graphql/static/schema-${graphqlVersion}.json`))),
|
||||||
previewsForCurrentVersion: previews[graphqlVersion],
|
previewsForCurrentVersion: previews[graphqlVersion],
|
||||||
upcomingChangesForCurrentVersion: upcomingChanges[graphqlVersion],
|
upcomingChangesForCurrentVersion: upcomingChanges[graphqlVersion],
|
||||||
prerenderedObjectsForCurrentVersion: prerenderedObjects[graphqlVersion],
|
prerenderedObjectsForCurrentVersion: prerenderedObjects[graphqlVersion],
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const supported = all.filter(release => {
|
|||||||
|
|
||||||
module.exports = async function releaseNotesContext (req, res, next) {
|
module.exports = async function releaseNotesContext (req, res, next) {
|
||||||
// The `/release-notes` sub-path
|
// The `/release-notes` sub-path
|
||||||
if (!(req.path.endsWith('/release-notes') || req.path.endsWith('/admin'))) return next()
|
if (!(req.pagePath.endsWith('/release-notes') || req.pagePath.endsWith('/admin'))) return next()
|
||||||
|
|
||||||
const [requestedPlan, requestedRelease] = req.context.currentVersion.split('@')
|
const [requestedPlan, requestedRelease] = req.context.currentVersion.split('@')
|
||||||
const releaseNotesPerPlan = req.context.site.data['release-notes'][requestedPlan]
|
const releaseNotesPerPlan = req.context.site.data['release-notes'][requestedPlan]
|
||||||
@@ -28,7 +28,7 @@ module.exports = async function releaseNotesContext (req, res, next) {
|
|||||||
if (hasNumberedReleases) {
|
if (hasNumberedReleases) {
|
||||||
const currentReleaseNotes = releaseNotesPerPlan[`${requestedRelease.replace(/\./g, '-')}`]
|
const currentReleaseNotes = releaseNotesPerPlan[`${requestedRelease.replace(/\./g, '-')}`]
|
||||||
|
|
||||||
if (!currentReleaseNotes && req.path.endsWith('/release-notes')) {
|
if (!currentReleaseNotes && req.pagePath.endsWith('/release-notes')) {
|
||||||
// If the GHES version doesn't have any release notes, let's be helpful and redirect to `enterprise.github.com`
|
// If the GHES version doesn't have any release notes, let's be helpful and redirect to `enterprise.github.com`
|
||||||
return requestedPlan === 'enterprise-server'
|
return requestedPlan === 'enterprise-server'
|
||||||
? res.redirect(`https://enterprise.github.com/releases/${requestedRelease}.0/notes`)
|
? res.redirect(`https://enterprise.github.com/releases/${requestedRelease}.0/notes`)
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ module.exports = function restContext (req, res, next) {
|
|||||||
))
|
))
|
||||||
|
|
||||||
// ignore requests to non-REST reference paths
|
// ignore requests to non-REST reference paths
|
||||||
if (!req.path.includes('rest/reference')) return next()
|
if (!req.pagePath.includes('rest/reference')) return next()
|
||||||
|
|
||||||
// e.g. the `activity` from `/en/rest/reference/activity#events`
|
// e.g. the `activity` from `/en/rest/reference/activity#events`
|
||||||
const category = req.path
|
const category = req.pagePath
|
||||||
.split('rest/reference')[1]
|
.split('rest/reference')[1]
|
||||||
.replace(/^\//, '') // remove leading slash
|
.replace(/^\//, '') // remove leading slash
|
||||||
.split('/')[0]
|
.split('/')[0]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ module.exports = function webhooksContext (req, res, next) {
|
|||||||
const currentVersionObj = allVersions[req.context.currentVersion]
|
const currentVersionObj = allVersions[req.context.currentVersion]
|
||||||
// ignore requests to non-webhook reference paths
|
// ignore requests to non-webhook reference paths
|
||||||
// and to versions that don't exist
|
// and to versions that don't exist
|
||||||
if (!req.path.includes('webhook') || !currentVersionObj) {
|
if (!req.pagePath.includes('webhook') || !currentVersionObj) {
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
const cookieSettings = require('../lib/cookie-settings')
|
||||||
|
|
||||||
module.exports = require('csurf')({
|
module.exports = require('csurf')({
|
||||||
cookie: require('../lib/cookie-settings'),
|
cookie: cookieSettings,
|
||||||
ignoreMethods: ['GET', 'HEAD', 'OPTIONS']
|
ignoreMethods: ['GET', 'HEAD', 'OPTIONS']
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
// This middleware uses the request path to find a page in the preloaded context.pages object
|
// This middleware uses the request path to find a page in the preloaded context.pages object
|
||||||
|
|
||||||
module.exports = async function findPage (req, res, next) {
|
module.exports = async function findPage (req, res, next) {
|
||||||
let page = req.context.pages[req.path]
|
let page = req.context.pages[req.pagePath]
|
||||||
|
|
||||||
// if this is a localized request that can't be found, try finding an English variant
|
// if this is a localized request that can't be found, try finding an English variant
|
||||||
if (!page && req.language !== 'en') {
|
if (!page && req.language !== 'en') {
|
||||||
const englishPath = req.path.replace(new RegExp(`^/${req.language}`), '/en')
|
const englishPath = req.pagePath.replace(new RegExp(`^/${req.language}`), '/en')
|
||||||
// NOTE the fallback page will have page.languageCode = 'en'
|
// NOTE the fallback page will have page.languageCode = 'en'
|
||||||
page = req.context.pages[englishPath]
|
page = req.context.pages[englishPath]
|
||||||
}
|
}
|
||||||
|
|||||||
19
middleware/handle-next-data-path.js
Normal file
19
middleware/handle-next-data-path.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
module.exports = async function handleNextDataPath (req, res, next) {
|
||||||
|
if (req.path.startsWith('/_next/data') && req.path.endsWith('.json')) {
|
||||||
|
// translate a nextjs data request to a page path that the server can use on context
|
||||||
|
// this is triggered via client-side route tranistions
|
||||||
|
// example path:
|
||||||
|
// /_next/data/development/en/free-pro-team%40latest/github/setting-up-and-managing-your-github-user-account.json
|
||||||
|
const decodedPath = decodeURIComponent(req.path)
|
||||||
|
const parts = decodedPath.split('/').slice(4)
|
||||||
|
// free-pro-team@latest should not be included in the page path
|
||||||
|
if (parts[1] === 'free-pro-team@latest') {
|
||||||
|
parts.splice(1,1)
|
||||||
|
}
|
||||||
|
req.pagePath = '/' + parts.join('/').replace(/.json+$/, '')
|
||||||
|
} else {
|
||||||
|
req.pagePath = req.path
|
||||||
|
}
|
||||||
|
|
||||||
|
next()
|
||||||
|
}
|
||||||
@@ -1,6 +1,26 @@
|
|||||||
const express = require('express')
|
const express = require('express')
|
||||||
const instrument = require('../lib/instrument-middleware')
|
const instrument = require('../lib/instrument-middleware')
|
||||||
const haltOnDroppedConnection = require('./halt-on-dropped-connection')
|
const haltOnDroppedConnection = require('./halt-on-dropped-connection')
|
||||||
|
const abort = require('./abort')
|
||||||
|
const timeout = require('./timeout')
|
||||||
|
const morgan = require('morgan')
|
||||||
|
const datadog = require('./connect-datadog')
|
||||||
|
const rateLimit = require('./rate-limit')
|
||||||
|
const cors = require('./cors')
|
||||||
|
const helmet = require('helmet')
|
||||||
|
const csp = require('./csp')
|
||||||
|
const cookieParser = require('./cookie-parser')
|
||||||
|
const csrf = require('./csrf')
|
||||||
|
const handleCsrfErrors = require('./handle-csrf-errors')
|
||||||
|
const compression = require('compression')
|
||||||
|
const disableCachingOnSafari = require('./disable-caching-on-safari')
|
||||||
|
const setFastlySurrogateKey = require('./set-fastly-surrogate-key')
|
||||||
|
const setFastlyCacheHeaders = require('./set-fastly-cache-headers')
|
||||||
|
const catchBadAcceptLanguage = require('./catch-bad-accept-language')
|
||||||
|
const reqUtils = require('./req-utils')
|
||||||
|
const recordRedirect = require('./record-redirect')
|
||||||
|
const connectSlashes = require('connect-slashes')
|
||||||
|
const handleErrors = require('./handle-errors')
|
||||||
|
|
||||||
const { NODE_ENV } = process.env
|
const { NODE_ENV } = process.env
|
||||||
const isDevelopment = NODE_ENV === 'development'
|
const isDevelopment = NODE_ENV === 'development'
|
||||||
@@ -15,57 +35,57 @@ const asyncMiddleware = fn =>
|
|||||||
|
|
||||||
module.exports = function (app) {
|
module.exports = function (app) {
|
||||||
// *** Request connection management ***
|
// *** Request connection management ***
|
||||||
if (!isTest) app.use(require('./timeout'))
|
if (!isTest) app.use(timeout)
|
||||||
app.use(require('./abort'))
|
app.use(abort)
|
||||||
|
|
||||||
// *** Development tools ***
|
// *** Development tools ***
|
||||||
app.use(require('morgan')('dev', { skip: (req, res) => !isDevelopment }))
|
app.use(morgan('dev', { skip: (req, res) => !isDevelopment }))
|
||||||
if (isDevelopment) app.use(require('./webpack'))
|
|
||||||
|
|
||||||
// *** Observability ***
|
// *** Observability ***
|
||||||
if (process.env.DD_API_KEY) {
|
if (process.env.DD_API_KEY) {
|
||||||
app.use(require('./connect-datadog'))
|
app.use(datadog)
|
||||||
}
|
}
|
||||||
|
|
||||||
// *** Early exits ***
|
// *** Early exits ***
|
||||||
// Don't use the proxy's IP, use the requester's for rate limiting
|
// Don't use the proxy's IP, use the requester's for rate limiting
|
||||||
// See https://expressjs.com/en/guide/behind-proxies.html
|
// See https://expressjs.com/en/guide/behind-proxies.html
|
||||||
app.set('trust proxy', 1)
|
app.set('trust proxy', 1)
|
||||||
app.use(require('./rate-limit'))
|
app.use(rateLimit)
|
||||||
app.use(instrument('./handle-invalid-paths'))
|
app.use(instrument('./handle-invalid-paths'))
|
||||||
|
app.use(instrument('./handle-next-data-path'))
|
||||||
|
|
||||||
// *** Security ***
|
// *** Security ***
|
||||||
app.use(require('./cors'))
|
app.use(cors)
|
||||||
app.use(require('helmet')({
|
app.use(helmet({
|
||||||
// Override referrerPolicy to match the browser's default: "strict-origin-when-cross-origin".
|
// Override referrerPolicy to match the browser's default: "strict-origin-when-cross-origin".
|
||||||
// Helmet now defaults to "no-referrer", which is a problem for our archived assets proxying.
|
// Helmet now defaults to "no-referrer", which is a problem for our archived assets proxying.
|
||||||
referrerPolicy: {
|
referrerPolicy: {
|
||||||
policy: 'strict-origin-when-cross-origin'
|
policy: 'strict-origin-when-cross-origin'
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
app.use(require('./csp')) // Must come after helmet
|
app.use(csp) // Must come after helmet
|
||||||
app.use(require('./cookie-parser')) // Must come before csrf
|
app.use(cookieParser) // Must come before csrf
|
||||||
app.use(express.json()) // Must come before csrf
|
app.use(express.json()) // Must come before csrf
|
||||||
app.use(require('./csrf'))
|
app.use(csrf)
|
||||||
app.use(require('./handle-csrf-errors')) // Must come before regular handle-errors
|
app.use(handleCsrfErrors) // Must come before regular handle-errors
|
||||||
|
|
||||||
// *** Headers ***
|
// *** Headers ***
|
||||||
app.set('etag', false) // We will manage our own ETags if desired
|
app.set('etag', false) // We will manage our own ETags if desired
|
||||||
app.use(require('compression')())
|
app.use(compression())
|
||||||
app.use(require('./disable-caching-on-safari'))
|
app.use(disableCachingOnSafari)
|
||||||
app.use(require('./set-fastly-surrogate-key'))
|
app.use(setFastlySurrogateKey)
|
||||||
app.use(require('./catch-bad-accept-language'))
|
app.use(catchBadAcceptLanguage)
|
||||||
|
|
||||||
// *** Config and context for redirects ***
|
// *** Config and context for redirects ***
|
||||||
app.use(require('./req-utils')) // Must come before record-redirect and events
|
app.use(reqUtils) // Must come before record-redirect and events
|
||||||
app.use(require('./record-redirect'))
|
app.use(recordRedirect)
|
||||||
app.use(instrument('./detect-language')) // Must come before context, breadcrumbs, find-page, handle-errors, homepages
|
app.use(instrument('./detect-language')) // Must come before context, breadcrumbs, find-page, handle-errors, homepages
|
||||||
app.use(asyncMiddleware(instrument('./context'))) // Must come before early-access-*, handle-redirects
|
app.use(asyncMiddleware(instrument('./context'))) // Must come before early-access-*, handle-redirects
|
||||||
app.use(asyncMiddleware(instrument('./contextualizers/short-versions'))) // Support version shorthands
|
app.use(asyncMiddleware(instrument('./contextualizers/short-versions'))) // Support version shorthands
|
||||||
|
|
||||||
// *** Redirects, 3xx responses ***
|
// *** Redirects, 3xx responses ***
|
||||||
// I ordered these by use frequency
|
// I ordered these by use frequency
|
||||||
app.use(require('connect-slashes')(false))
|
app.use(connectSlashes(false))
|
||||||
app.use(instrument('./redirects/external'))
|
app.use(instrument('./redirects/external'))
|
||||||
app.use(instrument('./redirects/help-to-docs'))
|
app.use(instrument('./redirects/help-to-docs'))
|
||||||
app.use(instrument('./redirects/language-code-redirects')) // Must come before contextualizers
|
app.use(instrument('./redirects/language-code-redirects')) // Must come before contextualizers
|
||||||
@@ -131,7 +151,7 @@ module.exports = function (app) {
|
|||||||
app.use(asyncMiddleware(instrument('./is-next-request')))
|
app.use(asyncMiddleware(instrument('./is-next-request')))
|
||||||
|
|
||||||
// *** Headers for pages only ***
|
// *** Headers for pages only ***
|
||||||
app.use(require('./set-fastly-cache-headers'))
|
app.use(setFastlyCacheHeaders)
|
||||||
|
|
||||||
// handle serving NextJS bundled code (/_next/*)
|
// handle serving NextJS bundled code (/_next/*)
|
||||||
if (process.env.FEATURE_NEXTJS) {
|
if (process.env.FEATURE_NEXTJS) {
|
||||||
@@ -145,5 +165,5 @@ module.exports = function (app) {
|
|||||||
app.get('/*', asyncMiddleware(instrument('./render-page')))
|
app.get('/*', asyncMiddleware(instrument('./render-page')))
|
||||||
|
|
||||||
// *** Error handling, must go last ***
|
// *** Error handling, must go last ***
|
||||||
app.use(require('./handle-errors'))
|
app.use(handleErrors)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,38 +1,10 @@
|
|||||||
const pathToRegexp = require('path-to-regexp')
|
|
||||||
|
|
||||||
const { productIds } = require('../lib/all-products')
|
|
||||||
const versionIds = Object.keys(require('../lib/all-versions'))
|
|
||||||
|
|
||||||
const { FEATURE_NEXTJS } = process.env;
|
const { FEATURE_NEXTJS } = process.env;
|
||||||
|
|
||||||
const homePageExp = pathToRegexp('/:locale/:versionId?')
|
|
||||||
const productPageExp = pathToRegexp('/:locale/:versionId?/:productId')
|
|
||||||
const subSectionExp = pathToRegexp('/:locale/:versionId?/:productId/:subSection*')
|
|
||||||
|
|
||||||
module.exports = function isNextRequest(req, res, next) {
|
module.exports = function isNextRequest(req, res, next) {
|
||||||
req.renderWithNextjs = false;
|
req.renderWithNextjs = false;
|
||||||
|
|
||||||
if (FEATURE_NEXTJS && !req.path.startsWith('/_next/')) {
|
if (FEATURE_NEXTJS) {
|
||||||
if ('nextjs' in req.query) {
|
req.renderWithNextjs = true;
|
||||||
req.renderWithNextjs = true;
|
|
||||||
} else {
|
|
||||||
// Custom path matching to determine if we should render with nextjs
|
|
||||||
|
|
||||||
// Remove any query string (?...) and/or fragment identifier (#...)
|
|
||||||
const { pathname } = new URL(req.originalUrl, "https://docs.github.com");
|
|
||||||
|
|
||||||
// Should the current path be rendered by NextJS?
|
|
||||||
const homePageMatch = homePageExp.exec(pathname)
|
|
||||||
const productPageMatch = productPageExp.exec(pathname)
|
|
||||||
const subSectionMatch = subSectionExp.exec(pathname)
|
|
||||||
if (homePageMatch && (!homePageMatch[2] || versionIds.includes(homePageMatch[2]))) {
|
|
||||||
req.renderWithNextjs = true
|
|
||||||
} else if (productPageMatch && productIds.includes(productPageMatch[3])) {
|
|
||||||
req.renderWithNextjs = true
|
|
||||||
} else if (subSectionMatch) {
|
|
||||||
req.renderWithNextjs = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
next();
|
next();
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ module.exports = async function learningTrack (req, res, next) {
|
|||||||
|
|
||||||
const currentLearningTrack = { trackName }
|
const currentLearningTrack = { trackName }
|
||||||
|
|
||||||
const guidePath = getPathWithoutLanguage(getPathWithoutVersion(req.path))
|
const guidePath = getPathWithoutLanguage(getPathWithoutVersion(req.pagePath))
|
||||||
const guideIndex = track.guides.findIndex((path) => path === guidePath)
|
const guideIndex = track.guides.findIndex((path) => path === guidePath)
|
||||||
|
|
||||||
if (guideIndex < 0) return noTrack()
|
if (guideIndex < 0) return noTrack()
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ if (FEATURE_NEXTJS) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module.exports = function renderPageWithNext (req, res, next) {
|
module.exports = function renderPageWithNext (req, res, next) {
|
||||||
if (req.path.startsWith('/_next/')) {
|
if (req.path.startsWith('/_next') && !req.path.startsWith('/_next/data')) {
|
||||||
return nextHandleRequest(req, res)
|
return nextHandleRequest(req, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ module.exports = async function renderPage (req, res, next) {
|
|||||||
const context = Object.assign({}, req.context, { page })
|
const context = Object.assign({}, req.context, { page })
|
||||||
|
|
||||||
// collect URLs for variants of this page in all languages
|
// collect URLs for variants of this page in all languages
|
||||||
context.page.languageVariants = Page.getLanguageVariants(req.path)
|
context.page.languageVariants = Page.getLanguageVariants(req.pagePath)
|
||||||
// Stop processing if the connection was already dropped
|
// Stop processing if the connection was already dropped
|
||||||
if (isConnectionDropped(req, res)) return
|
if (isConnectionDropped(req, res)) return
|
||||||
|
|
||||||
@@ -147,14 +147,14 @@ module.exports = async function renderPage (req, res, next) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handle special-case prerendered GraphQL objects page
|
// handle special-case prerendered GraphQL objects page
|
||||||
if (req.path.endsWith('graphql/reference/objects')) {
|
if (req.pagePath.endsWith('graphql/reference/objects')) {
|
||||||
// concat the markdown source miniToc items and the prerendered miniToc items
|
// concat the markdown source miniToc items and the prerendered miniToc items
|
||||||
context.miniTocItems = context.miniTocItems.concat(req.context.graphql.prerenderedObjectsForCurrentVersion.miniToc)
|
context.miniTocItems = context.miniTocItems.concat(req.context.graphql.prerenderedObjectsForCurrentVersion.miniToc)
|
||||||
context.renderedPage = context.renderedPage + req.context.graphql.prerenderedObjectsForCurrentVersion.html
|
context.renderedPage = context.renderedPage + req.context.graphql.prerenderedObjectsForCurrentVersion.html
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle special-case prerendered GraphQL input objects page
|
// handle special-case prerendered GraphQL input objects page
|
||||||
if (req.path.endsWith('graphql/reference/input-objects')) {
|
if (req.pagePath.endsWith('graphql/reference/input-objects')) {
|
||||||
// concat the markdown source miniToc items and the prerendered miniToc items
|
// concat the markdown source miniToc items and the prerendered miniToc items
|
||||||
context.miniTocItems = context.miniTocItems.concat(req.context.graphql.prerenderedInputObjectsForCurrentVersion.miniToc)
|
context.miniTocItems = context.miniTocItems.concat(req.context.graphql.prerenderedInputObjectsForCurrentVersion.miniToc)
|
||||||
context.renderedPage = context.renderedPage + req.context.graphql.prerenderedInputObjectsForCurrentVersion.html
|
context.renderedPage = context.renderedPage + req.context.graphql.prerenderedInputObjectsForCurrentVersion.html
|
||||||
@@ -164,7 +164,7 @@ module.exports = async function renderPage (req, res, next) {
|
|||||||
context.page.fullTitle = context.page.titlePlainText
|
context.page.fullTitle = context.page.titlePlainText
|
||||||
|
|
||||||
// add localized ` - GitHub Docs` suffix to <title> tag (except for the homepage)
|
// add localized ` - GitHub Docs` suffix to <title> tag (except for the homepage)
|
||||||
if (!patterns.homepagePath.test(req.path)) {
|
if (!patterns.homepagePath.test(req.pagePath)) {
|
||||||
context.page.fullTitle = context.page.fullTitle + ' - ' + context.site.data.ui.header.github_docs
|
context.page.fullTitle = context.page.fullTitle + ' - ' + context.site.data.ui.header.github_docs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
const express = require('express')
|
const express = require('express')
|
||||||
const languages = new Set(Object.keys(require('../lib/languages')))
|
const libLanguages = require('../lib/languages')
|
||||||
const versions = new Set(Object.values(require('../lib/search/versions')))
|
const searchVersions = require('../lib/search/versions')
|
||||||
|
const languages = new Set(Object.keys(libLanguages))
|
||||||
|
const versions = new Set(Object.values(searchVersions))
|
||||||
const loadLunrResults = require('../lib/search/lunr-search')
|
const loadLunrResults = require('../lib/search/lunr-search')
|
||||||
const loadAlgoliaResults = require('../lib/search/algolia-search')
|
const loadAlgoliaResults = require('../lib/search/algolia-search')
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
const webpack = require('webpack')
|
|
||||||
const middleware = require('webpack-dev-middleware')
|
|
||||||
const config = require('../webpack.config')
|
|
||||||
|
|
||||||
const webpackCompiler = webpack({
|
|
||||||
...config,
|
|
||||||
plugins: [
|
|
||||||
...config.plugins
|
|
||||||
]
|
|
||||||
})
|
|
||||||
|
|
||||||
module.exports = middleware(webpackCompiler, {
|
|
||||||
publicPath: config.output.publicPath
|
|
||||||
})
|
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
"translations",
|
"translations",
|
||||||
"dist",
|
"dist",
|
||||||
"javascripts",
|
"javascripts",
|
||||||
"stylesheets"
|
"stylesheets",
|
||||||
|
"tests"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
22
package-lock.json
generated
22
package-lock.json
generated
@@ -51,12 +51,12 @@
|
|||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"lunr": "^2.3.9",
|
"lunr": "^2.3.9",
|
||||||
"lunr-languages": "^1.4.0",
|
"lunr-languages": "^1.4.0",
|
||||||
|
"mdast-util-from-markdown": "^0.8.5",
|
||||||
"mdast-util-to-string": "^2.0.0",
|
"mdast-util-to-string": "^2.0.0",
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"next": "^11.0.0",
|
"next": "^11.0.0",
|
||||||
"node-fetch": "^2.6.1",
|
"node-fetch": "^2.6.1",
|
||||||
"parse5": "^6.0.1",
|
"parse5": "^6.0.1",
|
||||||
"path-to-regexp": "^0.1.7",
|
|
||||||
"port-used": "^2.0.8",
|
"port-used": "^2.0.8",
|
||||||
"rate-limit-redis": "^2.1.0",
|
"rate-limit-redis": "^2.1.0",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
@@ -143,7 +143,6 @@
|
|||||||
"jest-slow-test-reporter": "^1.0.0",
|
"jest-slow-test-reporter": "^1.0.0",
|
||||||
"linkinator": "^2.13.6",
|
"linkinator": "^2.13.6",
|
||||||
"make-promises-safe": "^5.1.0",
|
"make-promises-safe": "^5.1.0",
|
||||||
"mdast-util-from-markdown": "^0.8.5",
|
|
||||||
"mini-css-extract-plugin": "^1.6.0",
|
"mini-css-extract-plugin": "^1.6.0",
|
||||||
"mkdirp": "^1.0.4",
|
"mkdirp": "^1.0.4",
|
||||||
"mock-express-response": "^0.3.0",
|
"mock-express-response": "^0.3.0",
|
||||||
@@ -169,7 +168,6 @@
|
|||||||
"url-template": "^2.0.8",
|
"url-template": "^2.0.8",
|
||||||
"webpack": "^5.37.0",
|
"webpack": "^5.37.0",
|
||||||
"webpack-cli": "^4.7.0",
|
"webpack-cli": "^4.7.0",
|
||||||
"webpack-dev-middleware": "^4.2.0",
|
|
||||||
"website-scraper": "^4.2.3"
|
"website-scraper": "^4.2.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -4179,7 +4177,6 @@
|
|||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.3.tgz",
|
||||||
"integrity": "sha512-SXPBMnFVQg1s00dlMCc/jCdvPqdE4mXaMMCeRlxLDmTAEoegHT53xKtkDnzDTOcmMHUfcjyf36/YYZ6SxRdnsw==",
|
"integrity": "sha512-SXPBMnFVQg1s00dlMCc/jCdvPqdE4mXaMMCeRlxLDmTAEoegHT53xKtkDnzDTOcmMHUfcjyf36/YYZ6SxRdnsw==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/unist": "*"
|
"@types/unist": "*"
|
||||||
}
|
}
|
||||||
@@ -16037,7 +16034,6 @@
|
|||||||
"version": "0.8.5",
|
"version": "0.8.5",
|
||||||
"resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz",
|
"resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz",
|
||||||
"integrity": "sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==",
|
"integrity": "sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/mdast": "^3.0.0",
|
"@types/mdast": "^3.0.0",
|
||||||
"mdast-util-to-string": "^2.0.0",
|
"mdast-util-to-string": "^2.0.0",
|
||||||
@@ -16050,7 +16046,6 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz",
|
||||||
"integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==",
|
"integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"character-entities": "^1.0.0",
|
"character-entities": "^1.0.0",
|
||||||
"character-entities-legacy": "^1.0.0",
|
"character-entities-legacy": "^1.0.0",
|
||||||
@@ -16261,7 +16256,6 @@
|
|||||||
"version": "2.11.3",
|
"version": "2.11.3",
|
||||||
"resolved": "https://registry.npmjs.org/micromark/-/micromark-2.11.3.tgz",
|
"resolved": "https://registry.npmjs.org/micromark/-/micromark-2.11.3.tgz",
|
||||||
"integrity": "sha512-oph5YYkVqR2U9OtWBcXYysZMtrdIvi8dfSeyEdr1wFr3Bk6YwI6THosX2AzKnhdps7mVUbXiqhmosu9DcA+xlQ==",
|
"integrity": "sha512-oph5YYkVqR2U9OtWBcXYysZMtrdIvi8dfSeyEdr1wFr3Bk6YwI6THosX2AzKnhdps7mVUbXiqhmosu9DcA+xlQ==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": "^4.0.0",
|
"debug": "^4.0.0",
|
||||||
"parse-entities": "^2.0.0"
|
"parse-entities": "^2.0.0"
|
||||||
@@ -16271,7 +16265,6 @@
|
|||||||
"version": "4.3.1",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
|
||||||
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
|
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ms": "2.1.2"
|
"ms": "2.1.2"
|
||||||
},
|
},
|
||||||
@@ -16282,14 +16275,12 @@
|
|||||||
"node_modules/micromark/node_modules/ms": {
|
"node_modules/micromark/node_modules/ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/micromark/node_modules/parse-entities": {
|
"node_modules/micromark/node_modules/parse-entities": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz",
|
||||||
"integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==",
|
"integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"character-entities": "^1.0.0",
|
"character-entities": "^1.0.0",
|
||||||
"character-entities-legacy": "^1.0.0",
|
"character-entities-legacy": "^1.0.0",
|
||||||
@@ -28366,7 +28357,6 @@
|
|||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.3.tgz",
|
||||||
"integrity": "sha512-SXPBMnFVQg1s00dlMCc/jCdvPqdE4mXaMMCeRlxLDmTAEoegHT53xKtkDnzDTOcmMHUfcjyf36/YYZ6SxRdnsw==",
|
"integrity": "sha512-SXPBMnFVQg1s00dlMCc/jCdvPqdE4mXaMMCeRlxLDmTAEoegHT53xKtkDnzDTOcmMHUfcjyf36/YYZ6SxRdnsw==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/unist": "*"
|
"@types/unist": "*"
|
||||||
}
|
}
|
||||||
@@ -38331,7 +38321,6 @@
|
|||||||
"version": "0.8.5",
|
"version": "0.8.5",
|
||||||
"resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz",
|
"resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz",
|
||||||
"integrity": "sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==",
|
"integrity": "sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/mdast": "^3.0.0",
|
"@types/mdast": "^3.0.0",
|
||||||
"mdast-util-to-string": "^2.0.0",
|
"mdast-util-to-string": "^2.0.0",
|
||||||
@@ -38344,7 +38333,6 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz",
|
||||||
"integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==",
|
"integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"character-entities": "^1.0.0",
|
"character-entities": "^1.0.0",
|
||||||
"character-entities-legacy": "^1.0.0",
|
"character-entities-legacy": "^1.0.0",
|
||||||
@@ -38535,7 +38523,6 @@
|
|||||||
"version": "2.11.3",
|
"version": "2.11.3",
|
||||||
"resolved": "https://registry.npmjs.org/micromark/-/micromark-2.11.3.tgz",
|
"resolved": "https://registry.npmjs.org/micromark/-/micromark-2.11.3.tgz",
|
||||||
"integrity": "sha512-oph5YYkVqR2U9OtWBcXYysZMtrdIvi8dfSeyEdr1wFr3Bk6YwI6THosX2AzKnhdps7mVUbXiqhmosu9DcA+xlQ==",
|
"integrity": "sha512-oph5YYkVqR2U9OtWBcXYysZMtrdIvi8dfSeyEdr1wFr3Bk6YwI6THosX2AzKnhdps7mVUbXiqhmosu9DcA+xlQ==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"debug": "^4.0.0",
|
"debug": "^4.0.0",
|
||||||
"parse-entities": "^2.0.0"
|
"parse-entities": "^2.0.0"
|
||||||
@@ -38545,7 +38532,6 @@
|
|||||||
"version": "4.3.1",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
|
||||||
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
|
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"ms": "2.1.2"
|
"ms": "2.1.2"
|
||||||
}
|
}
|
||||||
@@ -38553,14 +38539,12 @@
|
|||||||
"ms": {
|
"ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"parse-entities": {
|
"parse-entities": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz",
|
||||||
"integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==",
|
"integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"character-entities": "^1.0.0",
|
"character-entities": "^1.0.0",
|
||||||
"character-entities-legacy": "^1.0.0",
|
"character-entities-legacy": "^1.0.0",
|
||||||
|
|||||||
@@ -57,13 +57,12 @@
|
|||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"lunr": "^2.3.9",
|
"lunr": "^2.3.9",
|
||||||
"lunr-languages": "^1.4.0",
|
"lunr-languages": "^1.4.0",
|
||||||
"mdast-util-to-string": "^2.0.0",
|
|
||||||
"mdast-util-from-markdown": "^0.8.5",
|
"mdast-util-from-markdown": "^0.8.5",
|
||||||
|
"mdast-util-to-string": "^2.0.0",
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"next": "^11.0.0",
|
"next": "^11.0.0",
|
||||||
"node-fetch": "^2.6.1",
|
"node-fetch": "^2.6.1",
|
||||||
"parse5": "^6.0.1",
|
"parse5": "^6.0.1",
|
||||||
"path-to-regexp": "^0.1.7",
|
|
||||||
"port-used": "^2.0.8",
|
"port-used": "^2.0.8",
|
||||||
"rate-limit-redis": "^2.1.0",
|
"rate-limit-redis": "^2.1.0",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
@@ -175,7 +174,6 @@
|
|||||||
"url-template": "^2.0.8",
|
"url-template": "^2.0.8",
|
||||||
"webpack": "^5.37.0",
|
"webpack": "^5.37.0",
|
||||||
"webpack-cli": "^4.7.0",
|
"webpack-cli": "^4.7.0",
|
||||||
"webpack-dev-middleware": "^4.2.0",
|
|
||||||
"website-scraper": "^4.2.3"
|
"website-scraper": "^4.2.3"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
|
|||||||
@@ -11,10 +11,8 @@ import events from 'javascripts/events'
|
|||||||
import experiment from 'javascripts/experiment'
|
import experiment from 'javascripts/experiment'
|
||||||
import setNextEnv from 'javascripts/set-next-env'
|
import setNextEnv from 'javascripts/set-next-env'
|
||||||
|
|
||||||
|
|
||||||
type MyAppProps = AppProps & { csrfToken: string; themeProps: typeof defaultThemeProps }
|
type MyAppProps = AppProps & { csrfToken: string; themeProps: typeof defaultThemeProps }
|
||||||
const MyApp = ({ Component, pageProps, csrfToken, themeProps }: MyAppProps) => {
|
const MyApp = ({ Component, pageProps, csrfToken, themeProps }: MyAppProps) => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
events()
|
events()
|
||||||
experiment()
|
experiment()
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ type LandingPageProps = {
|
|||||||
function LandingPage(props: LandingPageProps) {
|
function LandingPage(props: LandingPageProps) {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { gettingStartedLinks, popularLinks } = props
|
const { gettingStartedLinks, popularLinks } = props
|
||||||
const { activeProducts, isHomepageVersion } = useMainContext()
|
const { activeProducts } = useMainContext()
|
||||||
const { currentVersion } = useVersion()
|
const { currentVersion } = useVersion()
|
||||||
const { t } = useTranslation(['homepage', 'search', 'toc'])
|
const { t } = useTranslation(['homepage', 'search', 'toc'])
|
||||||
return (
|
return (
|
||||||
@@ -80,7 +80,7 @@ function LandingPage(props: LandingPageProps) {
|
|||||||
</h2>
|
</h2>
|
||||||
<div className="d-flex flex-wrap gutter gutter-xl-spacious">
|
<div className="d-flex flex-wrap gutter gutter-xl-spacious">
|
||||||
{activeProducts.map((product) => {
|
{activeProducts.map((product) => {
|
||||||
if (!product.versions?.includes(currentVersion) && !isHomepageVersion) {
|
if (!product.versions?.includes(currentVersion) && !product.external) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ async function main () {
|
|||||||
fs.writeFileSync(newDereferencedFile, newDereferenceContent)
|
fs.writeFileSync(newDereferencedFile, newDereferenceContent)
|
||||||
console.log(`Created ${newDereferencedFile}.`)
|
console.log(`Created ${newDereferencedFile}.`)
|
||||||
|
|
||||||
const dereferencedSchema = require(path.join(process.cwd(), newDereferencedFile))
|
const dereferencedSchema = JSON.parse(fs.readFileSync(path.join(process.cwd(), newDereferencedFile)))
|
||||||
|
|
||||||
// Store all operations in an array of operation objects
|
// Store all operations in an array of operation objects
|
||||||
const operations = await getOperations(dereferencedSchema)
|
const operations = await getOperations(dereferencedSchema)
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
const dotenv = require('dotenv')
|
||||||
|
|
||||||
if (!process.env.GITHUB_TOKEN) {
|
if (!process.env.GITHUB_TOKEN) {
|
||||||
require('dotenv').config()
|
dotenv.config()
|
||||||
}
|
}
|
||||||
|
|
||||||
// this module needs to work in development, production, and GitHub Actions
|
// this module needs to work in development, production, and GitHub Actions
|
||||||
|
|||||||
@@ -3,8 +3,10 @@
|
|||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const walk = require('walk-sync')
|
const walk = require('walk-sync')
|
||||||
const slugger = new (require('github-slugger'))()
|
const GithubSlugger = require('github-slugger')
|
||||||
const entities = new (require('html-entities').XmlEntities)()
|
const htmlEntities = require('html-entities')
|
||||||
|
const slugger = new GithubSlugger()
|
||||||
|
const entities = new htmlEntities.XmlEntities()
|
||||||
const frontmatter = require('../lib/read-frontmatter')
|
const frontmatter = require('../lib/read-frontmatter')
|
||||||
const { execSync } = require('child_process')
|
const { execSync } = require('child_process')
|
||||||
const addRedirectToFrontmatter = require('./helpers/add-redirect-to-frontmatter')
|
const addRedirectToFrontmatter = require('./helpers/add-redirect-to-frontmatter')
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
const glob = require('glob')
|
const glob = require('glob')
|
||||||
const program = require('commander')
|
const program = require('commander')
|
||||||
const getOperations = require('./utils/get-operations')
|
const getOperations = require('./utils/get-operations')
|
||||||
@@ -28,8 +29,7 @@ if (filesToCheck.length) {
|
|||||||
|
|
||||||
async function check (files) {
|
async function check (files) {
|
||||||
console.log('Verifying OpenAPI files are valid with decorator')
|
console.log('Verifying OpenAPI files are valid with decorator')
|
||||||
|
const documents = files.map(filename => [filename, JSON.parse(fs.readFileSync(path.join(process.cwd(), filename)))])
|
||||||
const documents = files.map(filename => [filename, require(filename)])
|
|
||||||
|
|
||||||
for (const [filename, schema] of documents) {
|
for (const [filename, schema] of documents) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ async function getDereferencedFiles () {
|
|||||||
// name of the `github/github` checkout. A CI test
|
// name of the `github/github` checkout. A CI test
|
||||||
// checks the version and fails if it's not a semantic version.
|
// checks the version and fails if it's not a semantic version.
|
||||||
schemas.forEach(filename => {
|
schemas.forEach(filename => {
|
||||||
const schema = require(path.join(dereferencedPath, filename))
|
const schema = JSON.parse(fs.readFileSync(path.join(dereferencedPath, filename)))
|
||||||
schema.info.version = `${githubBranch} !!DEVELOPMENT MODE - DO NOT MERGE!!`
|
schema.info.version = `${githubBranch} !!DEVELOPMENT MODE - DO NOT MERGE!!`
|
||||||
fs.writeFileSync(path.join(dereferencedPath, filename), JSON.stringify(schema, null, 2))
|
fs.writeFileSync(path.join(dereferencedPath, filename), JSON.stringify(schema, null, 2))
|
||||||
})
|
})
|
||||||
@@ -85,7 +85,7 @@ async function decorate () {
|
|||||||
console.log('\n🎄 Decorating the OpenAPI schema files in lib/rest/static/dereferenced.\n')
|
console.log('\n🎄 Decorating the OpenAPI schema files in lib/rest/static/dereferenced.\n')
|
||||||
|
|
||||||
const dereferencedSchemas = schemas.reduce((acc, filename) => {
|
const dereferencedSchemas = schemas.reduce((acc, filename) => {
|
||||||
const schema = require(path.join(dereferencedPath, filename))
|
const schema = JSON.parse(fs.readFileSync(path.join(dereferencedPath, filename)))
|
||||||
const key = filename.replace('.deref.json', '')
|
const key = filename.replace('.deref.json', '')
|
||||||
return { ...acc, [key]: schema }
|
return { ...acc, [key]: schema }
|
||||||
}, {})
|
}, {})
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
const { get, flatten, isPlainObject } = require('lodash')
|
const { get, flatten, isPlainObject } = require('lodash')
|
||||||
const { sentenceCase } = require('change-case')
|
const { sentenceCase } = require('change-case')
|
||||||
const slugger = new (require('github-slugger'))()
|
const GitHubSlugger = require('github-slugger')
|
||||||
|
const slugger = new GitHubSlugger()
|
||||||
const httpStatusCodes = require('http-status-code')
|
const httpStatusCodes = require('http-status-code')
|
||||||
const renderContent = require('../../../lib/render-content')
|
const renderContent = require('../../../lib/render-content')
|
||||||
const createCodeSamples = require('./create-code-samples')
|
const createCodeSamples = require('./create-code-samples')
|
||||||
const Ajv = require('ajv')
|
const Ajv = require('ajv')
|
||||||
|
const operationSchema = require('./operation-schema')
|
||||||
|
|
||||||
// titles that can't be derived by sentence-casing the ID
|
// titles that can't be derived by sentence-casing the ID
|
||||||
const categoryTitles = { scim: 'SCIM' }
|
const categoryTitles = { scim: 'SCIM' }
|
||||||
@@ -39,7 +41,7 @@ module.exports = class Operation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get schema () {
|
get schema () {
|
||||||
return require('./operation-schema')
|
return operationSchema
|
||||||
}
|
}
|
||||||
|
|
||||||
async process () {
|
async process () {
|
||||||
|
|||||||
@@ -6,13 +6,13 @@
|
|||||||
// It can also be run manually. For more info see [contributing/search.md](contributing/search.md)
|
// It can also be run manually. For more info see [contributing/search.md](contributing/search.md)
|
||||||
//
|
//
|
||||||
// [end-readme]
|
// [end-readme]
|
||||||
|
const searchSync = require('./search/sync')
|
||||||
require('make-promises-safe')
|
require('make-promises-safe')
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
|
||||||
async function main () {
|
async function main () {
|
||||||
const sync = require('./search/sync')
|
const sync = searchSync
|
||||||
const opts = {
|
const opts = {
|
||||||
dryRun: 'DRY_RUN' in process.env,
|
dryRun: 'DRY_RUN' in process.env,
|
||||||
language: process.env.LANGUAGE,
|
language: process.env.LANGUAGE,
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ const throng = require('throng')
|
|||||||
const os = require('os')
|
const os = require('os')
|
||||||
const portUsed = require('port-used')
|
const portUsed = require('port-used')
|
||||||
const prefixStreamWrite = require('./lib/prefix-stream-write')
|
const prefixStreamWrite = require('./lib/prefix-stream-write')
|
||||||
|
const libApp = require('./lib/app')
|
||||||
|
const libWarmServer = require('./lib/warm-server')
|
||||||
|
const http = require('http')
|
||||||
|
|
||||||
// Intentionally require these for both cluster primary and workers
|
// Intentionally require these for both cluster primary and workers
|
||||||
require('./lib/check-node-version')
|
require('./lib/check-node-version')
|
||||||
@@ -46,8 +49,8 @@ async function checkPortAvailability () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function startServer () {
|
async function startServer () {
|
||||||
const app = require('./lib/app')
|
const app = libApp
|
||||||
const warmServer = require('./lib/warm-server')
|
const warmServer = libWarmServer
|
||||||
|
|
||||||
// If in a deployed environment...
|
// If in a deployed environment...
|
||||||
if (NODE_ENV === 'production') {
|
if (NODE_ENV === 'production') {
|
||||||
@@ -58,7 +61,7 @@ async function startServer () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Workaround for https://github.com/expressjs/express/issues/1101
|
// Workaround for https://github.com/expressjs/express/issues/1101
|
||||||
const server = require('http').createServer(app)
|
const server = http.createServer(app)
|
||||||
server
|
server
|
||||||
.listen(port, () => console.log(`app running on http://localhost:${port}`))
|
.listen(port, () => console.log(`app running on http://localhost:${port}`))
|
||||||
.on('error', () => server.close())
|
.on('error', () => server.close())
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
/* global page, browser */
|
/* global page, browser */
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
const sleep = require('await-sleep')
|
const sleep = require('await-sleep')
|
||||||
const { latest } = require('../../lib/enterprise-server-releases')
|
const { latest } = require('../../lib/enterprise-server-releases')
|
||||||
const languages = require('../../lib/languages')
|
const languages = require('../../lib/languages')
|
||||||
|
const featureFlags = JSON.parse(fs.readFileSync(path.join(process.cwd(), '/feature-flags.json')))
|
||||||
|
|
||||||
describe('homepage', () => {
|
describe('homepage', () => {
|
||||||
jest.setTimeout(60 * 1000)
|
jest.setTimeout(60 * 1000)
|
||||||
@@ -329,7 +332,7 @@ describe('nextjs query param', () => {
|
|||||||
jest.setTimeout(60 * 1000)
|
jest.setTimeout(60 * 1000)
|
||||||
|
|
||||||
it('landing page renders through nextjs pipeline depending on FEATURE_NEXTJS value', async () => {
|
it('landing page renders through nextjs pipeline depending on FEATURE_NEXTJS value', async () => {
|
||||||
const flagVal = require('../../feature-flags.json').FEATURE_NEXTJS
|
const flagVal = featureFlags.FEATURE_NEXTJS
|
||||||
await page.goto('http://localhost:4001/en/actions?nextjs=')
|
await page.goto('http://localhost:4001/en/actions?nextjs=')
|
||||||
const IS_NEXTJS_PAGE = await page.evaluate(() => window.IS_NEXTJS_PAGE)
|
const IS_NEXTJS_PAGE = await page.evaluate(() => window.IS_NEXTJS_PAGE)
|
||||||
const nextWrapper = await page.$('#__next')
|
const nextWrapper = await page.$('#__next')
|
||||||
@@ -337,3 +340,25 @@ describe('nextjs query param', () => {
|
|||||||
flagVal === true ? expect(IS_NEXTJS_PAGE).toBe(true) : expect(IS_NEXTJS_PAGE).toBe(false)
|
flagVal === true ? expect(IS_NEXTJS_PAGE).toBe(true) : expect(IS_NEXTJS_PAGE).toBe(false)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('next/link client-side navigation', () => {
|
||||||
|
jest.setTimeout(60 * 1000)
|
||||||
|
|
||||||
|
it('should have 200 response to /_next/data when link is clicked', async () => {
|
||||||
|
const initialViewport = page.viewport()
|
||||||
|
await page.setViewport({ width: 1024, height: 768 })
|
||||||
|
await page.goto('http://localhost:4001/en/actions')
|
||||||
|
|
||||||
|
const [response] = await Promise.all([
|
||||||
|
page.waitForResponse(
|
||||||
|
(response) =>
|
||||||
|
response.url().startsWith('http://localhost:4001/_next/data')
|
||||||
|
),
|
||||||
|
page.waitForNavigation({ waitUntil: 'networkidle2' }),
|
||||||
|
page.click('.sidebar-categories .sidebar-category:nth-child(2) a'),
|
||||||
|
])
|
||||||
|
|
||||||
|
expect(response.status()).toBe(200)
|
||||||
|
await page.setViewport(initialViewport)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
const previewsJson = require('../../lib/graphql/static/previews')
|
const previewsJson = require('../../lib/graphql/static/previews')
|
||||||
const upcomingChangesJson = require('../../lib/graphql/static/upcoming-changes')
|
const upcomingChangesJson = require('../../lib/graphql/static/upcoming-changes')
|
||||||
const prerenderedObjectsJson = require('../../lib/graphql/static/prerendered-objects')
|
const prerenderedObjectsJson = require('../../lib/graphql/static/prerendered-objects')
|
||||||
@@ -20,7 +22,7 @@ describe('graphql json files', () => {
|
|||||||
|
|
||||||
test('schemas object validation', () => {
|
test('schemas object validation', () => {
|
||||||
graphqlVersions.forEach(version => {
|
graphqlVersions.forEach(version => {
|
||||||
const schemaJsonPerVersion = require(`../../lib/graphql/static/schema-${version}`)
|
const schemaJsonPerVersion = JSON.parse(fs.readFileSync(path.join(process.cwd(), `lib/graphql/static/schema-${version}.json`)))
|
||||||
// all graphql types are arrays except for queries
|
// all graphql types are arrays except for queries
|
||||||
graphqlTypes
|
graphqlTypes
|
||||||
.filter(type => type !== 'queries')
|
.filter(type => type !== 'queries')
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ const flat = require('flat')
|
|||||||
const loadSiteData = require('../../lib/site-data')
|
const loadSiteData = require('../../lib/site-data')
|
||||||
const patterns = require('../../lib/patterns')
|
const patterns = require('../../lib/patterns')
|
||||||
const { liquid } = require('../../lib/render-content')
|
const { liquid } = require('../../lib/render-content')
|
||||||
|
const walkSync = require('walk-sync')
|
||||||
|
|
||||||
describe('siteData module (English)', () => {
|
describe('siteData module (English)', () => {
|
||||||
let data
|
let data
|
||||||
@@ -82,7 +83,7 @@ describe('siteData module (English)', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
test('warn if any YAML reusables are found', async () => {
|
test('warn if any YAML reusables are found', async () => {
|
||||||
const reusables = require('walk-sync')(path.join(__dirname, '../../data/reusables'))
|
const reusables = walkSync(path.join(__dirname, '../../data/reusables'))
|
||||||
expect(reusables.length).toBeGreaterThan(100)
|
expect(reusables.length).toBeGreaterThan(100)
|
||||||
const yamlReusables = reusables.filter(filename => filename.endsWith('.yml') || filename.endsWith('.yaml'))
|
const yamlReusables = reusables.filter(filename => filename.endsWith('.yml') || filename.endsWith('.yaml'))
|
||||||
const message = `reusables are now written as individual Markdown files. Please migrate the following YAML files to Markdown:\n${yamlReusables.join('\n')}`
|
const message = `reusables are now written as individual Markdown files. Please migrate the following YAML files to Markdown:\n${yamlReusables.join('\n')}`
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const path = require('path')
|
|||||||
const { difference, isPlainObject } = require('lodash')
|
const { difference, isPlainObject } = require('lodash')
|
||||||
const { getJSON } = require('../helpers/supertest')
|
const { getJSON } = require('../helpers/supertest')
|
||||||
const enterpriseServerReleases = require('../../lib/enterprise-server-releases')
|
const enterpriseServerReleases = require('../../lib/enterprise-server-releases')
|
||||||
|
const rest = require('../../lib/rest')
|
||||||
// list of REST markdown files that do not correspond to REST API resources
|
// list of REST markdown files that do not correspond to REST API resources
|
||||||
// TODO could we get this list dynamically, say via page frontmatter?
|
// TODO could we get this list dynamically, say via page frontmatter?
|
||||||
const excludeFromResourceNameCheck = [
|
const excludeFromResourceNameCheck = [
|
||||||
@@ -15,7 +16,7 @@ describe('REST references docs', () => {
|
|||||||
jest.setTimeout(3 * 60 * 1000)
|
jest.setTimeout(3 * 60 * 1000)
|
||||||
|
|
||||||
test('markdown file exists for every operationId prefix in the api.github.com schema', async () => {
|
test('markdown file exists for every operationId prefix in the api.github.com schema', async () => {
|
||||||
const { categories } = require('../../lib/rest')
|
const { categories } = rest
|
||||||
const referenceDir = path.join(__dirname, '../../content/rest/reference')
|
const referenceDir = path.join(__dirname, '../../content/rest/reference')
|
||||||
const filenames = (await fs.readdir(referenceDir))
|
const filenames = (await fs.readdir(referenceDir))
|
||||||
.filter(filename => !excludeFromResourceNameCheck.find(excludedFile => filename.endsWith(excludedFile)))
|
.filter(filename => !excludeFromResourceNameCheck.find(excludedFile => filename.endsWith(excludedFile)))
|
||||||
@@ -47,7 +48,7 @@ describe('REST references docs', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
test('no wrongly detected AppleScript syntax highlighting in schema data', async () => {
|
test('no wrongly detected AppleScript syntax highlighting in schema data', async () => {
|
||||||
const { operations } = require('../../lib/rest')
|
const { operations } = rest
|
||||||
expect(JSON.stringify(operations).includes('hljs language-applescript')).toBe(false)
|
expect(JSON.stringify(operations).includes('hljs language-applescript')).toBe(false)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ const path = require('path')
|
|||||||
const { loadPages } = require('../../lib/page-data')
|
const { loadPages } = require('../../lib/page-data')
|
||||||
const builtAssets = require('../../lib/built-asset-urls')
|
const builtAssets = require('../../lib/built-asset-urls')
|
||||||
const AZURE_STORAGE_URL = 'githubdocs.azureedge.net'
|
const AZURE_STORAGE_URL = 'githubdocs.azureedge.net'
|
||||||
|
const CspParse = require('csp-parse')
|
||||||
|
|
||||||
describe('server', () => {
|
describe('server', () => {
|
||||||
jest.setTimeout(60 * 1000)
|
jest.setTimeout(60 * 1000)
|
||||||
@@ -39,7 +40,7 @@ describe('server', () => {
|
|||||||
const res = await get('/en')
|
const res = await get('/en')
|
||||||
expect('content-security-policy' in res.headers).toBe(true)
|
expect('content-security-policy' in res.headers).toBe(true)
|
||||||
|
|
||||||
const csp = new (require('csp-parse'))(res.headers['content-security-policy'])
|
const csp = new CspParse(res.headers['content-security-policy'])
|
||||||
expect(csp.get('default-src')).toBe("'none'")
|
expect(csp.get('default-src')).toBe("'none'")
|
||||||
|
|
||||||
expect(csp.get('font-src').includes("'self'")).toBe(true)
|
expect(csp.get('font-src').includes("'self'")).toBe(true)
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
const { head } = require('../helpers/supertest')
|
const { head } = require('../helpers/supertest')
|
||||||
|
const topOldDeveloperSitePaths = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'tests/fixtures/top-old-developer-site-paths.json')))
|
||||||
|
|
||||||
describe('developer.github.com redirects', () => {
|
describe('developer.github.com redirects', () => {
|
||||||
jest.setTimeout(30 * 60 * 1000)
|
jest.setTimeout(30 * 60 * 1000)
|
||||||
@@ -16,7 +19,7 @@ describe('developer.github.com redirects', () => {
|
|||||||
|
|
||||||
// test a subset of the top paths
|
// test a subset of the top paths
|
||||||
const pathsToCheck = 50
|
const pathsToCheck = 50
|
||||||
const paths = require('../fixtures/top-old-developer-site-paths.json')
|
const paths = topOldDeveloperSitePaths
|
||||||
.filter(path => !ignoredPatterns.some(pattern => path.match(pattern)))
|
.filter(path => !ignoredPatterns.some(pattern => path.match(pattern)))
|
||||||
.slice(0, pathsToCheck)
|
.slice(0, pathsToCheck)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
const fs = require('fs').promises
|
const fs = require('fs').promises
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const { testViaActionsOnly } = require('../helpers/conditional-runs')
|
const { testViaActionsOnly } = require('../helpers/conditional-runs')
|
||||||
|
const { getDOM } = require('../helpers/supertest')
|
||||||
|
const got = require('got')
|
||||||
|
|
||||||
describe('cloning early-access', () => {
|
describe('cloning early-access', () => {
|
||||||
testViaActionsOnly('the content directory exists', async () => {
|
testViaActionsOnly('the content directory exists', async () => {
|
||||||
@@ -18,3 +20,25 @@ describe('cloning early-access', () => {
|
|||||||
expect(await fs.stat(eaDir)).toBeTruthy()
|
expect(await fs.stat(eaDir)).toBeTruthy()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('rendering early-access', () => {
|
||||||
|
jest.setTimeout(5 * 60 * 1000)
|
||||||
|
|
||||||
|
testViaActionsOnly('the top-level TOC renders locally', async () => {
|
||||||
|
const $ = await getDOM('/en/early-access')
|
||||||
|
expect($.html().includes('Hello, local developer! This page is not visible on production.')).toBe(true)
|
||||||
|
expect($('ul a').length).toBeGreaterThan(5)
|
||||||
|
})
|
||||||
|
|
||||||
|
testViaActionsOnly('the top-level TOC does not render on production', async () => {
|
||||||
|
async function getEarlyAccess () {
|
||||||
|
return await got('https://docs.github.com/en/early-access')
|
||||||
|
}
|
||||||
|
await expect(getEarlyAccess).rejects.toThrowError('Response code 404 (Not Found)')
|
||||||
|
})
|
||||||
|
|
||||||
|
testViaActionsOnly('TOCs display on category pages', async () => {
|
||||||
|
const $ = await getDOM('/en/early-access/github/enforcing-best-practices-with-github-policies')
|
||||||
|
expect($('ul a').length).toBeGreaterThan(5)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const { liquid } = require('../../lib/render-content')
|
const { liquid } = require('../../lib/render-content')
|
||||||
const { loadPageMap } = require('../../lib/page-data')
|
const { loadPageMap } = require('../../lib/page-data')
|
||||||
const entities = new (require('html-entities').XmlEntities)()
|
const htmlEntities = require('html-entities')
|
||||||
|
const entities = new htmlEntities.XmlEntities()
|
||||||
const nonEnterpriseDefaultVersion = require('../../lib/non-enterprise-default-version')
|
const nonEnterpriseDefaultVersion = require('../../lib/non-enterprise-default-version')
|
||||||
|
|
||||||
describe('liquid helper tags', () => {
|
describe('liquid helper tags', () => {
|
||||||
|
|||||||
@@ -268,7 +268,7 @@ describe('Page class', () => {
|
|||||||
basePath: path.join(__dirname, '../../content'),
|
basePath: path.join(__dirname, '../../content'),
|
||||||
languageCode: 'en'
|
languageCode: 'en'
|
||||||
})
|
})
|
||||||
expect(page.permalinks.find(permalink => permalink.pageVersion === 'homepage').href).toBe('/en')
|
expect(page.permalinks.find(permalink => permalink.pageVersion === nonEnterpriseDefaultVersion).href).toBe('/en')
|
||||||
expect(page.permalinks.find(permalink => permalink.pageVersion === `enterprise-server@${enterpriseServerReleases.oldestSupported}`).href).toBe(`/en/enterprise-server@${enterpriseServerReleases.oldestSupported}`)
|
expect(page.permalinks.find(permalink => permalink.pageVersion === `enterprise-server@${enterpriseServerReleases.oldestSupported}`).href).toBe(`/en/enterprise-server@${enterpriseServerReleases.oldestSupported}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ const getApplicableVersions = require('../../lib/get-applicable-versions')
|
|||||||
// Permalink.derive requires: languageCode, relativePath, title, versions (<- FM prop)
|
// Permalink.derive requires: languageCode, relativePath, title, versions (<- FM prop)
|
||||||
|
|
||||||
describe('Permalink class', () => {
|
describe('Permalink class', () => {
|
||||||
// We can only use Permalink.derive to get the special 'homepage' permalink
|
|
||||||
test('derives info for unversioned homepage', () => {
|
test('derives info for unversioned homepage', () => {
|
||||||
const versions = {
|
const versions = {
|
||||||
'free-pro-team': '*',
|
'free-pro-team': '*',
|
||||||
@@ -15,7 +14,7 @@ describe('Permalink class', () => {
|
|||||||
}
|
}
|
||||||
const permalinks = Permalink.derive('en', 'index.md', 'Hello World', getApplicableVersions(versions))
|
const permalinks = Permalink.derive('en', 'index.md', 'Hello World', getApplicableVersions(versions))
|
||||||
expect(permalinks.length).toBeGreaterThan(1)
|
expect(permalinks.length).toBeGreaterThan(1)
|
||||||
const homepagePermalink = permalinks.find(permalink => permalink.pageVersion === 'homepage')
|
const homepagePermalink = permalinks.find(permalink => permalink.pageVersion === nonEnterpriseDefaultVersion)
|
||||||
expect(homepagePermalink.href).toBe('/en')
|
expect(homepagePermalink.href).toBe('/en')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -30,10 +30,10 @@ describe('versions middleware', () => {
|
|||||||
|
|
||||||
test('adds res.context.currentVersion string', async () => {
|
test('adds res.context.currentVersion string', async () => {
|
||||||
let currentVersion = await getJSON('/en?json=currentVersion')
|
let currentVersion = await getJSON('/en?json=currentVersion')
|
||||||
expect(currentVersion).toBe('homepage')
|
expect(currentVersion).toBe(nonEnterpriseDefaultVersion)
|
||||||
|
|
||||||
currentVersion = await getJSON(`/en/${nonEnterpriseDefaultVersion}?json=currentVersion`)
|
currentVersion = await getJSON(`/en/${nonEnterpriseDefaultVersion}?json=currentVersion`)
|
||||||
expect(currentVersion).toBe('homepage')
|
expect(currentVersion).toBe(nonEnterpriseDefaultVersion)
|
||||||
|
|
||||||
currentVersion = await getJSON(`/en/enterprise-server@${latest}?json=currentVersion`)
|
currentVersion = await getJSON(`/en/enterprise-server@${latest}?json=currentVersion`)
|
||||||
expect(currentVersion).toBe(`enterprise-server@${latest}`)
|
expect(currentVersion).toBe(`enterprise-server@${latest}`)
|
||||||
|
|||||||
Reference in New Issue
Block a user