1
0
mirror of synced 2025-12-22 11:26:57 -05:00

Merge branch 'main' into codewithdev-docs

This commit is contained in:
Laura Coursen
2021-06-03 15:33:18 -05:00
committed by GitHub
55 changed files with 871 additions and 631 deletions

View File

@@ -17,11 +17,11 @@ jobs:
const repo = context.payload.repository.name const repo = context.payload.repository.name
const allStatusLabels = [ const allStatusLabels = [
'Status: GREEN', 'green',
'Status: GREY', 'grey',
'Status: YELLOW', 'yellow',
'Status: BLACK', 'black',
'Status: RED' 'red'
]; ];
const currentLabels = await github.issues.listLabelsOnIssue({ const currentLabels = await github.issues.listLabelsOnIssue({
@@ -33,7 +33,7 @@ jobs:
const newLabels = currentLabels.data.filter( label => allStatusLabels.includes(label.name) === false) const newLabels = currentLabels.data.filter( label => allStatusLabels.includes(label.name) === false)
allStatusLabels.forEach( label => { allStatusLabels.forEach( label => {
if(context.payload.comment.body.includes(label)) { if(context.payload.comment.body.toLowerCase().includes(`status: ${label}`)) {
newLabels.push(label) newLabels.push(label)
} }
}); });

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

View File

@@ -1,7 +1,7 @@
import cx from 'classnames' import cx from 'classnames'
import Link from 'next/link'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import { useMainContext } from './context/MainContext' import { useMainContext } from './context/MainContext'
import { Link } from 'components/Link'
export type BreadcrumbT = { export type BreadcrumbT = {
title: string title: string
@@ -12,7 +12,7 @@ export type BreadcrumbT = {
type Props = {} type Props = {}
export const Breadcrumbs = (props: Props) => { export const Breadcrumbs = (props: Props) => {
const router = useRouter() const router = useRouter()
const pathWithLocale = `/${router.locale}${router.asPath}` const pathWithLocale = `/${router.locale}${router.asPath.split('?')[0]}` // remove query string
const { breadcrumbs } = useMainContext() const { breadcrumbs } = useMainContext()
return ( return (
@@ -28,16 +28,16 @@ export const Breadcrumbs = (props: Props) => {
{breadcrumb.title} {breadcrumb.title}
</span> </span>
) : ( ) : (
<Link key={title} href={breadcrumb.href}> <Link
<a key={title}
title={title} href={breadcrumb.href}
className={cx( title={title}
'd-inline-block', className={cx(
pathWithLocale === breadcrumb.href && 'color-text-tertiary' 'd-inline-block',
)} pathWithLocale === breadcrumb.href && 'color-text-tertiary'
> )}
{breadcrumb.title} >
</a> {breadcrumb.title}
</Link> </Link>
) )
})} })}

View File

@@ -24,7 +24,6 @@ export const DefaultLayout = (props: Props) => {
<title>{page.fullTitle}</title> <title>{page.fullTitle}</title>
) : null} ) : null}
<link rel="stylesheet" href={builtAssets.main.css} />
<script id="expose" type="application/json" dangerouslySetInnerHTML={{ __html: expose }} /> <script id="expose" type="application/json" dangerouslySetInnerHTML={{ __html: expose }} />
<script src={builtAssets.main.js} /> <script src={builtAssets.main.js} />

View File

@@ -1,10 +1,10 @@
import { useState } from 'react' import { useState } from 'react'
import Link from 'next/link'
import cx from 'classnames' import cx from 'classnames'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import { ChevronDownIcon, MarkGithubIcon, ThreeBarsIcon, XIcon } from '@primer/octicons-react' import { ChevronDownIcon, MarkGithubIcon, ThreeBarsIcon, XIcon } from '@primer/octicons-react'
import { ButtonOutline } from '@primer/components' import { ButtonOutline } from '@primer/components'
import { Link } from 'components/Link'
import { useMainContext } from './context/MainContext' import { useMainContext } from './context/MainContext'
import { LanguagePicker } from './LanguagePicker' import { LanguagePicker } from './LanguagePicker'
import { HeaderNotifications } from 'components/HeaderNotifications' import { HeaderNotifications } from 'components/HeaderNotifications'
@@ -34,16 +34,15 @@ export const Header = () => {
id="github-logo-mobile" id="github-logo-mobile"
role="banner" role="banner"
> >
<Link href={`/${router.locale}`}> <Link aria-hidden="true" tabIndex={-1} href={`/${router.locale}`}>
<a aria-hidden="true" tabIndex={-1}> <MarkGithubIcon size={32} className="color-icon-primary" />
<MarkGithubIcon size={32} className="color-icon-primary" />
</a>
</Link> </Link>
<Link href={`/${router.locale}`}> <Link
<a className="h4-mktg color-text-primary no-underline no-wrap pl-2"> href={`/${router.locale}`}
{t('github_docs')} className="h4-mktg color-text-primary no-underline no-wrap pl-2"
</a> >
{t('github_docs')}
</Link> </Link>
</div> </div>

View File

@@ -70,7 +70,7 @@ export const HeaderNotifications = () => {
return ( return (
<> <>
{allNotifications.map(({ type, content }, i) => { {allNotifications.map(({ type, content }, i) => {
const isLast = i !== allNotifications.length - 1 const isLast = i === allNotifications.length - 1
return ( return (
<div <div
className={cx( className={cx(

View File

@@ -1,6 +1,7 @@
import Link from 'next/link'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import { Dropdown } from '@primer/components' import { Dropdown } from '@primer/components'
import { Link } from 'components/Link'
import { useMainContext } from './context/MainContext' import { useMainContext } from './context/MainContext'
export const LanguagePicker = () => { export const LanguagePicker = () => {
@@ -12,7 +13,13 @@ export const LanguagePicker = () => {
return ( return (
<div className="ml-4 d-flex flex-justify-center flex-items-center"> <div className="ml-4 d-flex flex-justify-center flex-items-center">
<Dropdown css> <Dropdown
css={`
ul {
width: unset;
}
`}
>
<summary> <summary>
{selectedLang.nativeName || selectedLang.name} {selectedLang.nativeName || selectedLang.name}
<Dropdown.Caret /> <Dropdown.Caret />
@@ -22,15 +29,13 @@ export const LanguagePicker = () => {
return ( return (
<Dropdown.Item key={lang.code}> <Dropdown.Item key={lang.code}>
<Link href={router.asPath} locale={lang.hreflang}> <Link href={router.asPath} locale={lang.hreflang}>
<a> {lang.nativeName ? (
{lang.nativeName ? ( <>
<> {lang.nativeName} ({lang.name})
{lang.nativeName} ({lang.name}) </>
</> ) : (
) : ( lang.name
lang.name )}
)}
</a>
</Link> </Link>
</Dropdown.Item> </Dropdown.Item>
) )

25
components/Link.tsx Normal file
View File

@@ -0,0 +1,25 @@
import NextLink from 'next/link'
import { ComponentProps } from 'react'
const { NODE_ENV } = process.env
const enableNextLinks = false
type Props = { locale?: string } & ComponentProps<'a'>
export function Link(props: Props) {
const { href, locale, ...restProps } = props
if (!href && NODE_ENV !== 'production') {
console.warn('Missing href on Link')
}
if (enableNextLinks) {
return (
<NextLink href={href || ''} locale={locale}>
<a {...restProps} />
</NextLink>
)
}
return <a href={locale ? `/${locale}${href}` : href} {...restProps} />
}

View File

@@ -1,8 +1,8 @@
import Link from 'next/link'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import { LinkExternalIcon } from '@primer/octicons-react' import { LinkExternalIcon } from '@primer/octicons-react'
import cx from 'classnames' import cx from 'classnames'
import { Link } from 'components/Link'
import { useMainContext } from 'components/context/MainContext' import { useMainContext } from 'components/context/MainContext'
export const MobileProductDropdown = () => { export const MobileProductDropdown = () => {
@@ -20,22 +20,19 @@ export const MobileProductDropdown = () => {
<Link <Link
key={product.id} key={product.id}
href={`${product.external ? '' : `/${router.locale}`}${product.href}`} href={`${product.external ? '' : `/${router.locale}`}${product.href}`}
className={cx(
'd-block py-2',
product.id === currentProduct.id
? 'color-text-link text-underline active'
: 'Link--primary no-underline'
)}
> >
<a {product.name}
className={cx( {product.external && (
'd-block py-2', <span className="ml-1">
product.id === currentProduct.id <LinkExternalIcon size="small" />
? 'color-text-link text-underline active' </span>
: 'Link--primary no-underline' )}
)}
>
{product.name}
{product.external && (
<span className="ml-1">
<LinkExternalIcon size="small" />
</span>
)}
</a>
</Link> </Link>
) )
})} })}

View File

@@ -45,17 +45,6 @@ export const ScrollButton = () => {
> >
<ChevronUpIcon /> <ChevronUpIcon />
</button> </button>
<style jsx>{`
.opacity-0 {
opacity: 0;
}
.opacity-100 {
opacity: 1;
}
.transition-200 {
transition: 200ms;
}
`}</style>
</div> </div>
) )
} }

View File

@@ -1,6 +1,7 @@
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import Link from 'next/link'
import { LinkExternalIcon, MarkGithubIcon } from '@primer/octicons-react' import { LinkExternalIcon, MarkGithubIcon } from '@primer/octicons-react'
import { Link } from 'components/Link'
import { useTranslation } from './hooks/useTranslation' import { useTranslation } from './hooks/useTranslation'
import { useMainContext } from './context/MainContext' import { useMainContext } from './context/MainContext'
import { SidebarProduct } from './product/SidebarProduct' import { SidebarProduct } from './product/SidebarProduct'
@@ -22,15 +23,19 @@ export const SidebarNav = (props: Props) => {
id="github-logo" id="github-logo"
role="banner" role="banner"
> >
<Link href={`/${router.locale}`}> <Link
<a className="color-text-primary" aria-hidden="true" tabIndex={-1}> href={`/${router.locale}`}
<MarkGithubIcon size={32} /> className="color-text-primary"
</a> aria-hidden="true"
tabIndex={-1}
>
<MarkGithubIcon size={32} />
</Link> </Link>
<Link href={`/${router.locale}`}> <Link
<a className="h4-mktg color-text-primary no-underline no-wrap pl-2 flex-auto"> href={`/${router.locale}`}
{t('github_docs')} className="h4-mktg color-text-primary no-underline no-wrap pl-2 flex-auto"
</a> >
{t('github_docs')}
</Link> </Link>
</div> </div>
<nav> <nav>

View File

@@ -8,14 +8,15 @@ type Props = {
className?: string className?: string
} }
export const TruncateLines = (props: Props) => { export const TruncateLines = (props: Props) => {
const Component = props.as || 'div' const { as, maxLines, className, children } = props
const Component = as || 'div'
return ( return (
<Component className={cx('root', props.className)}> <Component className={cx('root', className)}>
{props.children} {children}
<style jsx>{` <style jsx>{`
.root { .root {
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: ${props.maxLines}; -webkit-line-clamp: ${maxLines};
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
overflow: hidden; overflow: hidden;
} }

View File

@@ -1,44 +0,0 @@
import Link from 'next/link'
import { useRouter } from 'next/router'
import { Dropdown } from '@primer/components'
import { useMainContext } from './context/MainContext'
import { useVersion } from './hooks/useVersion'
export const VersionPicker = () => {
const router = useRouter()
const { currentVersion } = useVersion()
const { allVersions } = useMainContext()
const versions = Object.values(allVersions)
const activeVersion = allVersions[currentVersion]
return (
<div className="ml-4 d-flex flex-justify-center flex-items-center">
<Dropdown css>
<summary>
{activeVersion.versionTitle}
<Dropdown.Caret />
</summary>
<Dropdown.Menu direction="sw">
{versions.map((version) => {
return (
<Dropdown.Item key={version.version}>
<Link
href={{
pathname: router.pathname,
query: {
...router.query,
versionId: version.version,
},
}}
>
<a>{version.versionTitle}</a>
</Link>
</Dropdown.Item>
)
})}
</Dropdown.Menu>
</Dropdown>
</div>
)
}

View File

@@ -0,0 +1,31 @@
import { Tooltip, Link } from '@primer/components'
import { PrinterIcon } from './PrinterIcon'
type Props = {
children: React.ReactNode
}
export const ArticleTitle = ({ children }: Props) => {
return (
<div className="d-flex flex-items-baseline flex-justify-between">
<h1 className="my-4">{children}</h1>
<div className="d-none d-lg-block ml-2">
<Tooltip aria-label="Print this article" noDelay direction="n">
<Link
as="button"
underline={false}
muted
onClick={() => {
try {
document.execCommand('print', false)
} catch (e) {
window.print()
}
}}
>
<PrinterIcon />
</Link>
</Tooltip>
</div>
</div>
)
}

View File

@@ -1,7 +1,7 @@
import Link from 'next/link'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import { Dropdown } from '@primer/components' import { Dropdown } from '@primer/components'
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' import { useTranslation } from 'components/hooks/useTranslation'
@@ -17,42 +17,39 @@ export const ArticleVersionPicker = () => {
} }
return ( return (
<div className="d-none d-lg-flex flex-justify-end"> <Dropdown
<Dropdown css={`
css={` ul {
ul { width: unset;
width: unset; }
`}
>
<summary className="f4 h5-mktg btn-outline-mktg btn-mktg p-2">
<span className="d-md-none d-xl-inline-block">{t('article_version')}</span>{' '}
{allVersions[currentVersion].versionTitle}
<Dropdown.Caret />
</summary>
<Dropdown.Menu direction="sw">
{(page.permalinks || []).map((permalink) => {
if (permalink.pageVersion === 'homepage') {
return null
} }
`}
>
<summary className="f4 h5-mktg btn-outline-mktg btn-mktg p-2">
<span className="d-md-none d-xl-inline-block">{t('article_version')}</span>{' '}
{allVersions[currentVersion].versionTitle}
<Dropdown.Caret />
</summary>
<Dropdown.Menu direction="sw">
{(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}> <Link href={permalink.href}>{permalink.pageVersionTitle}</Link>
<a>{permalink.pageVersionTitle}</a> </Dropdown.Item>
</Link> )
</Dropdown.Item> })}
) <div className="pb-1">
})} <Link
<div className="pb-1"> href={`/${router.locale}/${enterpriseServerVersions[0]}/admin/all-releases`}
<Link href={`/${router.locale}/${enterpriseServerVersions[0]}/admin/all-releases`}> className="f6 no-underline color-text-tertiary pl-3 pr-2 no-wrap"
<a className="f6 no-underline color-text-tertiary pl-3 pr-2 no-wrap"> >
See all Enterprise releases See all Enterprise releases
</a> </Link>
</Link> </div>
</div> </Dropdown.Menu>
</Dropdown.Menu> </Dropdown>
</Dropdown>
</div>
) )
} }

View File

@@ -0,0 +1,20 @@
// From https://heroicons.com
export const PrinterIcon = () => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
height={18}
width={18}
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M17 17h2a2 2 0 002-2v-4a2 2 0 00-2-2H5a2 2 0 00-2 2v4a2 2 0 002 2h2m2 4h6a2 2 0 002-2v-4a2 2 0 00-2-2H9a2 2 0 00-2 2v4a2 2 0 002 2zm8-12V5a2 2 0 00-2-2H9a2 2 0 00-2 2v4h10z"
/>
</svg>
)
}

View File

@@ -67,7 +67,7 @@ export type MainContextT = {
maptopic?: BreadcrumbT maptopic?: BreadcrumbT
article?: BreadcrumbT article?: BreadcrumbT
} }
builtAssets: { main: { css: string; js: string } } builtAssets: { main: { js: string } }
expose: string expose: string
activeProducts: Array<ProductT> activeProducts: Array<ProductT>
currentProduct: ProductT currentProduct: ProductT
@@ -84,6 +84,7 @@ export type MainContextT = {
currentProductTree?: CurrentProductTree currentProductTree?: CurrentProductTree
featureFlags: FeatureFlags featureFlags: FeatureFlags
page: { page: {
documentType: string
languageVariants: Array<{ name: string; code: string; hreflang: string; href: string }> languageVariants: Array<{ name: string; code: string; hreflang: string; href: string }>
topics: Array<string> topics: Array<string>
fullTitle?: string fullTitle?: string
@@ -104,7 +105,7 @@ export type MainContextT = {
export const getMainContextFromRequest = (req: any): MainContextT => { export const getMainContextFromRequest = (req: any): MainContextT => {
return { return {
builtAssets: req.context.builtAssets, builtAssets: { main: { js: req.context.builtAssets.main.js } },
expose: req.context.expose, expose: req.context.expose,
breadcrumbs: req.context.breadcrumbs || {}, breadcrumbs: req.context.breadcrumbs || {},
activeProducts: req.context.activeProducts, activeProducts: req.context.activeProducts,
@@ -126,6 +127,7 @@ export const getMainContextFromRequest = (req: any): MainContextT => {
relativePath: req.context.page?.relativePath, relativePath: req.context.page?.relativePath,
page: { page: {
languageVariants: req.context.page.languageVariants, languageVariants: req.context.page.languageVariants,
documentType: req.context.page.documentType,
fullTitle: req.context.page.fullTitle, fullTitle: req.context.page.fullTitle,
topics: req.context.page.topics || [], topics: req.context.page.topics || [],
introPlainText: req.context.page?.introPlainText, introPlainText: req.context.page?.introPlainText,

View File

@@ -70,8 +70,9 @@ export const useProductLandingContext = (): ProductLandingContextT => {
export const getProductLandingContextFromRequest = (req: any): ProductLandingContextT => { export const getProductLandingContextFromRequest = (req: any): ProductLandingContextT => {
const productTree = req.context.currentProductTree const productTree = req.context.currentProductTree
const page = req.context.page
return { return {
...pick(req.context.page, [ ...pick(page, [
'title', 'title',
'shortTitle', 'shortTitle',
'introPlainText', 'introPlainText',
@@ -96,11 +97,11 @@ export const getProductLandingContextFromRequest = (req: any): ProductLandingCon
}) })
), ),
introLinks: productTree.page.introLinks introLinks: page.introLinks
? { ? {
quickstart: productTree.page.introLinks.quickstart, quickstart: page.introLinks.quickstart,
reference: productTree.page.introLinks.reference, reference: page.introLinks.reference,
overview: productTree.page.introLinks.overview, overview: page.introLinks.overview,
} }
: null, : null,

View File

@@ -0,0 +1,33 @@
import { createContext, useContext } from 'react'
export type TocItem = {
fullPath: string
title: string
intro?: string
}
export type TocLandingContextT = {
title: string
introPlainText: string
tocItems: Array<TocItem>
}
export const TocLandingContext = createContext<TocLandingContextT | null>(null)
export const useTocLandingContext = (): TocLandingContextT => {
const context = useContext(TocLandingContext)
if (!context) {
throw new Error('"useTocLandingContext" may only be used inside "TocLandingContext.Provider"')
}
return context
}
export const getTocLandingContextFromRequest = (req: any): TocLandingContextT => {
return {
title: req.context.page.title,
introPlainText: req.context.page.introPlainText,
tocItems: req.context.tocItems || [],
}
}

View File

@@ -1,7 +1,7 @@
import cx from 'classnames' import cx from 'classnames'
import Link from 'next/link'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { Link } from 'components/Link'
import { ArrowRightIcon } from '@primer/octicons-react' import { ArrowRightIcon } from '@primer/octicons-react'
import { FeaturedLink, useProductLandingContext } from 'components/context/ProductLandingContext' import { FeaturedLink, useProductLandingContext } from 'components/context/ProductLandingContext'
import { useTranslation } from 'components/hooks/useTranslation' import { useTranslation } from 'components/hooks/useTranslation'
@@ -63,10 +63,8 @@ const ArticleList = ({ title, viewAllHref, articles }: ArticleListProps) => {
<div className="featured-links-heading mb-4 d-flex flex-items-baseline"> <div className="featured-links-heading mb-4 d-flex flex-items-baseline">
<h3 className="f4 text-normal text-mono text-uppercase">{title}</h3> <h3 className="f4 text-normal text-mono text-uppercase">{title}</h3>
{viewAllHref && ( {viewAllHref && (
<Link href={viewAllHref}> <Link href={viewAllHref} className="ml-4">
<a className="ml-4"> View all <ArrowRightIcon size={14} className="v-align-middle" />
View all <ArrowRightIcon size={14} className="v-align-middle" />
</a>
</Link> </Link>
)} )}
</div> </div>
@@ -75,30 +73,31 @@ const ArticleList = ({ title, viewAllHref, articles }: ArticleListProps) => {
{articles.map((link, i) => { {articles.map((link, i) => {
return ( return (
<li key={link.href} className="border-top"> <li key={link.href} className="border-top">
<Link href={link.href}> <Link
<a className="link-with-intro Bump-link--hover no-underline d-block py-3"> href={link.href}
<h4 className="link-with-intro-title"> className="link-with-intro Bump-link--hover no-underline d-block py-3"
{link.title} >
<span className="Bump-link-symbol"></span> <h4 className="link-with-intro-title">
</h4> <span dangerouslySetInnerHTML={{ __html: link.title }} />
{!link.hideIntro && link.intro && ( <span className="Bump-link-symbol"></span>
<TruncateLines </h4>
as="p" {!link.hideIntro && link.intro && (
maxLines={2} <TruncateLines
className="link-with-intro-intro color-text-secondary mb-0 mt-1" as="p"
> maxLines={2}
{link.intro} className="link-with-intro-intro color-text-secondary mb-0 mt-1"
</TruncateLines> >
)} <span dangerouslySetInnerHTML={{ __html: link.intro }} />
{link.date && ( </TruncateLines>
<time )}
className="tooltipped tooltipped-n color-text-tertiary text-mono mt-1" {link.date && (
aria-label={dayjs(link.date).format('LLL')} <time
> className="tooltipped tooltipped-n color-text-tertiary text-mono mt-1"
{dayjs(link.date).format('MMMM DD')} aria-label={dayjs(link.date).format('LLL')}
</time> >
)} {dayjs(link.date).format('MMMM DD')}
</a> </time>
)}
</Link> </Link>
</li> </li>
) )

View File

@@ -1,6 +1,6 @@
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import Link from 'next/link'
import { Link } from 'components/Link'
import { ArrowRightIcon } from '@primer/octicons-react' import { ArrowRightIcon } from '@primer/octicons-react'
import { useMainContext } from 'components/context/MainContext' import { useMainContext } from 'components/context/MainContext'
@@ -11,6 +11,7 @@ export const GuideCards = () => {
const router = useRouter() const router = useRouter()
const { currentCategory } = useMainContext() const { currentCategory } = useMainContext()
const { guideCards } = useProductLandingContext() const { guideCards } = useProductLandingContext()
const routePath = `/${router.locale}${router.asPath.split('?')[0]}` // remove query string
if (!guideCards) { if (!guideCards) {
return null return null
@@ -25,10 +26,8 @@ export const GuideCards = () => {
</div> </div>
{!currentCategory && ( {!currentCategory && (
<Link href={`${router.asPath}/guides`}> <Link href={`${routePath}/guides`} className="btn btn-outline float-right">
<a className="btn btn-outline float-right"> Explore guides <ArrowRightIcon />
Explore guides <ArrowRightIcon />
</a>
</Link> </Link>
)} )}
</div> </div>

View File

@@ -1,7 +1,7 @@
import Link from 'next/link'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import { Dropdown } from '@primer/components' import { Dropdown } from '@primer/components'
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' import { useTranslation } from 'components/hooks/useTranslation'
@@ -41,17 +41,16 @@ export const HomepageVersionPicker = () => {
return ( return (
<Dropdown.Item key={permalink.href}> <Dropdown.Item key={permalink.href}>
<Link href={permalink.href}> <Link href={permalink.href}>{permalink.pageVersionTitle}</Link>
<a>{permalink.pageVersionTitle}</a>
</Link>
</Dropdown.Item> </Dropdown.Item>
) )
})} })}
<div className="pb-1"> <div className="pb-1">
<Link href={`/${router.locale}/${enterpriseServerVersions[0]}/admin/all-releases`}> <Link
<a className="f6 no-underline color-text-tertiary pl-3 pr-2 no-wrap"> href={`/${router.locale}/${enterpriseServerVersions[0]}/admin/all-releases`}
See all Enterprise releases className="f6 no-underline color-text-tertiary pl-3 pr-2 no-wrap"
</a> >
See all Enterprise releases
</Link> </Link>
</div> </div>
</Dropdown.Menu> </Dropdown.Menu>

View File

@@ -1,9 +1,9 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import cx from 'classnames' import cx from 'classnames'
import Link from 'next/link'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import { useMainContext } from 'components/context/MainContext' import { useMainContext } from 'components/context/MainContext'
import { Link } from 'components/Link'
import { useProductLandingContext } from 'components/context/ProductLandingContext' import { useProductLandingContext } from 'components/context/ProductLandingContext'
import { useTranslation } from 'components/hooks/useTranslation' import { useTranslation } from 'components/hooks/useTranslation'
import { useVersion } from 'components/hooks/useVersion' import { useVersion } from 'components/hooks/useVersion'
@@ -107,8 +107,8 @@ export const FullLink = ({ href, children, className }: Props) => {
currentVersion !== 'free-pro-team@latest' ? `/${currentVersion}` : '' currentVersion !== 'free-pro-team@latest' ? `/${currentVersion}` : ''
}${href}` }${href}`
return ( return (
<Link href={fullyQualifiedHref}> <Link href={fullyQualifiedHref} className={className}>
<a className={className}>{children}</a> {children}
</Link> </Link>
) )
} }

View File

@@ -1,9 +1,10 @@
import Link from 'next/link'
import cx from 'classnames' import cx from 'classnames'
import { useState } from 'react' import { useState } from 'react'
import { ChevronUpIcon } from '@primer/octicons-react' import { ChevronUpIcon } from '@primer/octicons-react'
import { CurrentProductTree, useMainContext } from 'components/context/MainContext' import { CurrentProductTree, useMainContext } from 'components/context/MainContext'
import { Link } from 'components/Link'
const maxArticles = 10 const maxArticles = 10
@@ -33,9 +34,7 @@ const ArticleList = ({ page }: { page: CurrentProductTree }) => {
return ( return (
<div className="col-12 col-lg-4 mb-6 height-full"> <div className="col-12 col-lg-4 mb-6 height-full">
<h4 className="mb-3"> <h4 className="mb-3">
<Link href={page.href}> <Link href={page.href}>{page.page.title}</Link>
<a>{page.page.title}</a>
</Link>
</h4> </h4>
<ul className="list-style-none"> <ul className="list-style-none">
@@ -47,11 +46,9 @@ const ArticleList = ({ page }: { page: CurrentProductTree }) => {
return ( return (
<li <li
key={grandchildPage.href + index} key={grandchildPage.href + index}
className={cx('mb-3', index >= maxArticles ? 'd-none' : null)} className={cx('mb-3', !isShowingMore && index >= maxArticles ? 'd-none' : null)}
> >
<Link href={grandchildPage.href}> <Link href={grandchildPage.href}>{grandchildPage.page.title}</Link>
<a>{grandchildPage.page.title}</a>
</Link>
{grandchildPage.page.documentType === 'mapTopic' ? ( {grandchildPage.page.documentType === 'mapTopic' ? (
<small className="color-text-secondary d-inline-block"> <small className="color-text-secondary d-inline-block">
&nbsp;&bull; {page.childPages.length} articles &nbsp;&bull; {page.childPages.length} articles

View File

@@ -0,0 +1,69 @@
import { DefaultLayout } from 'components/DefaultLayout'
import { useProductLandingContext } from 'components/context/ProductLandingContext'
import { LandingHero } from 'components/landing/LandingHero'
import { FeaturedArticles } from 'components/landing/FeaturedArticles'
import { GuideCards } from 'components/landing/GuideCards'
import { SponsorsExamples } from 'components/landing/SponsorsExamples'
import { CommunityExamples } from 'components/landing/CommunityExamples'
import { CodeExamples } from 'components/landing/CodeExamples'
import { LandingSection } from 'components/landing/LandingSection'
import { useTranslation } from 'components/hooks/useTranslation'
import { ProductArticlesList } from 'components/landing/ProductArticlesList'
export const ProductLanding = () => {
const {
shortTitle,
guideCards,
productUserExamples,
productCommunityExamples,
productCodeExamples,
} = useProductLandingContext()
const { t } = useTranslation('product_landing')
return (
<DefaultLayout>
<LandingSection className="pt-3">
<LandingHero />
</LandingSection>
<LandingSection>
<FeaturedArticles />
</LandingSection>
{productCodeExamples.length > 0 && (
<LandingSection title={t('code_examples')} className="my-6">
<CodeExamples />
</LandingSection>
)}
{productCommunityExamples.length > 0 && (
<LandingSection title={t('communities_using_discussions')} className="my-6">
<CommunityExamples />
</LandingSection>
)}
{productUserExamples.length > 0 && (
<LandingSection title={t('sponsor_community')} className="my-6">
<SponsorsExamples />
</LandingSection>
)}
{/* {% if currentVersion contains 'enterprise-server' and currentProduct == 'admin' %}
{% include product-releases %}
{% endif %} */}
{guideCards.length > 0 && (
<div className="color-bg-tertiary py-6 my-8">
<LandingSection title={t('guides')} className="my-6">
<GuideCards />
</LandingSection>
</div>
)}
<LandingSection sectionLink="all-docs" title={`All ${shortTitle} Docs`}>
<ProductArticlesList />
</LandingSection>
</DefaultLayout>
)
}

View File

@@ -1,6 +1,6 @@
import Link from 'next/link'
import { ArrowRightIcon } from '@primer/octicons-react' import { ArrowRightIcon } from '@primer/octicons-react'
import { Link } from 'components/Link'
import { useProductLandingContext } from 'components/context/ProductLandingContext' import { useProductLandingContext } from 'components/context/ProductLandingContext'
import { useTranslation } from 'components/hooks/useTranslation' import { useTranslation } from 'components/hooks/useTranslation'
import { UserCard } from 'components/landing/UserCard' import { UserCard } from 'components/landing/UserCard'
@@ -24,10 +24,8 @@ export const SponsorsExamples = () => {
) )
})} })}
</div> </div>
<Link href={`https://github.com/sponsors/community`}> <Link href={`https://github.com/sponsors/community`} className="btn btn-outline float-right">
<a className="btn btn-outline float-right"> {t('explore_people_and_projects')} <ArrowRightIcon />
{t('explore_people_and_projects')} <ArrowRightIcon />
</a>
</Link> </Link>
</div> </div>
) )

View File

@@ -1,34 +1,45 @@
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import Link from 'next/link'
import cx from 'classnames' import cx from 'classnames'
import type { TocItem } from '../context/ProductLandingContext' import { Link } from 'components/Link'
import type { TocItem } from 'components/context/ProductLandingContext'
export const TableOfContents = (props: { items?: Array<TocItem> }) => { type Props = {
items: Array<TocItem>
variant?: 'compact' | 'expanded'
}
export const TableOfContents = (props: Props) => {
const { items, variant = 'expanded' } = props
const router = useRouter() const router = useRouter()
return ( return (
<div> <ul className={cx(variant === 'compact' ? 'list-style-inside pl-2' : 'list-style-none')}>
{(props.items || []).map((obj) => { {(items || []).map((item) => {
if (!obj) { if (!item) {
return null return null
} }
const { fullPath: href, title, intro } = obj
const { fullPath: href, title, intro } = item
const isActive = router.pathname === href const isActive = router.pathname === href
return ( return variant === 'compact' ? (
<div key={href} className={cx('mb-5', isActive && 'color-auto-gray-4')}> <li key={href} className="f4 my-1">
<Link href={href}> <Link href={href}>{title}</Link>
<a className="Bump-link--hover no-underline d-block py-1 border-bottom color-border-primary"> </li>
<h4> ) : (
{title} <li key={href} className={cx('mb-5', isActive && 'color-auto-gray-4')}>
<span className="Bump-link-symbol"></span> <Link
</h4> href={href}
</a> className="Bump-link--hover no-underline d-block py-1 border-bottom color-border-primary"
>
<h4>
{title}
<span className="Bump-link-symbol"></span>
</h4>
</Link> </Link>
{intro && <p className="f4 mt-3" dangerouslySetInnerHTML={{ __html: intro }} />} {intro && <p className="f4 mt-3" dangerouslySetInnerHTML={{ __html: intro }} />}
</div> </li>
) )
})} })}
</div> </ul>
) )
} }

View File

@@ -0,0 +1,55 @@
import { Grid } from '@primer/components'
import { DefaultLayout } from 'components/DefaultLayout'
import { TableOfContents } from 'components/landing/TableOfContents'
import { ArticleVersionPicker } from 'components/article/ArticleVersionPicker'
import { Breadcrumbs } from 'components/Breadcrumbs'
import { useTocLandingContext } from 'components/context/TocLandingContext'
import { ArticleTitle } from 'components/article/ArticleTitle'
type Props = {
variant?: 'compact' | 'expanded'
}
export const TocLanding = ({ variant = 'expanded' }: Props) => {
const { title, introPlainText, tocItems } = useTocLandingContext()
return (
<DefaultLayout>
<div className="container-xl px-3 px-md-6 my-4 my-lg-4">
<div className="d-lg-flex flex-justify-between">
<div className="d-block d-lg-none">
<ArticleVersionPicker />
</div>
<div className="d-flex flex-items-center">
<Breadcrumbs />
</div>
<div className="d-none d-lg-block">
<ArticleVersionPicker />
</div>
</div>
<Grid
gridTemplateColumns="minmax(500px, 720px) minmax(220px, 1fr)"
gridTemplateRows="auto 1fr"
gridGap={16}
>
<div>
<div className="mt-8">
<ArticleTitle>{title}</ArticleTitle>
<div className="lead-mktg">
<p>{introPlainText}</p>
</div>
</div>
<div className="border-bottom border-xl-0 pb-4 mb-5 pb-xl-0 mb-xl-0" />
<div className={variant === 'expanded' ? 'mt-7' : 'mt-2'}>
<TableOfContents items={tocItems} variant={variant} />
</div>
</div>
<div></div>
</Grid>
</div>
</DefaultLayout>
)
}

View File

@@ -1,16 +1,12 @@
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import Link from 'next/link'
import cx from 'classnames' import cx from 'classnames'
import { useDetails, Details } from '@primer/components'
import { ChevronDownIcon } from '@primer/octicons-react'
import { useMainContext } from 'components/context/MainContext' import { Link } from 'components/Link'
import { CurrentProductTree, useMainContext } from 'components/context/MainContext'
import { AllProductsLink } from 'components/product/AllProductsLink' import { AllProductsLink } from 'components/product/AllProductsLink'
// <!--
// Styling note:
// Categories, Maptopics, and Articles list items get a class of `active` when they correspond to content
// hierarchy of the current page. If an item's URL is also the same as the current URL, the item
// also gets an `is-current-page` class.
// -->
export const SidebarProduct = () => { export const SidebarProduct = () => {
const router = useRouter() const router = useRouter()
const { currentProductTree: currentProductTree } = useMainContext() const { currentProductTree: currentProductTree } = useMainContext()
@@ -28,8 +24,11 @@ export const SidebarProduct = () => {
{!currentProductTree.page.hidden && ( {!currentProductTree.page.hidden && (
<> <>
<li title="" className="sidebar-product mb-2"> <li title="" className="sidebar-product mb-2">
<Link href={currentProductTree.href}> <Link
<a className="pl-4 pr-5 pb-1 f4 color-text-primary">{productTitle}</a> href={currentProductTree.href}
className="pl-4 pr-5 pb-1 f4 color-text-primary no-underline"
>
{productTitle}
</Link> </Link>
</li> </li>
@@ -52,136 +51,19 @@ export const SidebarProduct = () => {
)} )}
> >
{isStandaloneCategory ? ( {isStandaloneCategory ? (
<Link href={childPage.href}> <Link
<a className="pl-4 pr-2 py-2 f6 text-uppercase d-block flex-auto mr-3 color-text-primary"> href={childPage.href}
{childTitle} className="pl-4 pr-2 py-2 f6 text-uppercase d-block flex-auto mr-3 color-text-primary no-underline"
</a> >
{childTitle}
</Link> </Link>
) : ( ) : (
<details <CollapsibleSection
className={cx('dropdown-withArrow details details-reset')} index={i}
open={routePath.includes(childPage.href) || i < 3} routePath={routePath}
> title={childTitle}
<summary> page={childPage}
<div className="d-flex flex-justify-between"> />
<Link href={childPage.href}>
<a className="pl-4 pr-2 py-2 f6 text-uppercase d-block flex-auto mr-3 color-text-primary">
{childTitle}
</a>
</Link>
{i < 3 && (
<svg
xmlns="http://www.w3.org/2000/svg"
className="octicon flex-shrink-0 arrow mr-3"
style={{ marginTop: 7 }}
viewBox="0 0 16 16"
width="16"
height="16"
>
{' '}
<path
fillRule="evenodd"
clipRule="evenodd"
d="M12.7803 6.21967C13.0732 6.51256 13.0732 6.98744 12.7803 7.28033L8.53033 11.5303C8.23744 11.8232 7.76256 11.8232 7.46967 11.5303L3.21967 7.28033C2.92678 6.98744 2.92678 6.51256 3.21967 6.21967C3.51256 5.92678 3.98744 5.92678 4.28033 6.21967L8 9.93934L11.7197 6.21967C12.0126 5.92678 12.4874 5.92678 12.7803 6.21967Z"
></path>
</svg>
)}
</div>
</summary>
{routePath.includes(childPage.href) || i < 3 ? (
<>
{/* <!-- some categories have maptopics with child articles --> */}
{childPage.childPages[0].page.documentType === 'mapTopic' ? (
<ul className="sidebar-topics list-style-none position-relative">
{childPage.childPages.map((grandchildPage, i) => {
const grandchildTitle =
grandchildPage.renderedShortTitle ||
grandchildPage.renderedFullTitle
const isActive = routePath.includes(grandchildPage.href)
const isCurrent = routePath === grandchildPage.href
return (
<li
key={childPage.href + i}
className={cx(
'sidebar-maptopic',
isActive && 'active',
isCurrent && 'is-current-page'
)}
>
<Link href={grandchildPage.href}>
<a className="pl-4 pr-5 py-2 color-text-primary">{grandchildTitle}</a>
</Link>
<ul className="sidebar-articles my-2">
{grandchildPage.childPages.map(
(greatgrandchildPage, i, arr) => {
const greatgrandchildTitle =
greatgrandchildPage.renderedShortTitle ||
greatgrandchildPage.renderedFullTitle
const isLast = i === arr.length - 1
const isActive = routePath.includes(
greatgrandchildPage.href
)
const isCurrent = routePath === greatgrandchildPage.href
return (
<li
key={greatgrandchildPage.href + i}
className={cx(
'sidebar-article',
isActive && 'active',
isCurrent && 'is-current-page'
)}
>
<Link href={greatgrandchildPage.href}>
<a
className={cx(
'pl-6 pr-5 py-1 color-text-primary',
isLast && 'pb-2'
)}
>
{greatgrandchildTitle}
</a>
</Link>
</li>
)
}
)}
</ul>
</li>
)
})}
</ul>
) : childPage.childPages[0].page.documentType == 'article' ? (
<ul className="sidebar-articles list-style-none">
{/* <!-- some categories have no maptopics, only articles --> */}
{childPage.childPages.map((grandchildPage, i, arr) => {
const grandchildTitle =
grandchildPage.renderedShortTitle ||
grandchildPage.renderedFullTitle
const isLast = i === arr.length - 1
const isActive = routePath.includes(grandchildPage.href)
const isCurrent = routePath === grandchildPage.href
return (
<li
key={grandchildPage.href + i}
className={cx(
'sidebar-article',
isActive && 'active',
isCurrent && 'is-current-page'
)}
>
<Link href={grandchildPage.href}>
<a className={cx('pl-6 pr-5 py-1 color-text-primary', isLast && 'pb-2')}>
{grandchildTitle}
</a>
</Link>
</li>
)
})}
</ul>
) : null}
</>
) : null}
</details>
)} )}
</li> </li>
) )
@@ -193,3 +75,117 @@ export const SidebarProduct = () => {
</> </>
) )
} }
type SectionProps = {
index: number
routePath: string
page: CurrentProductTree
title: string
}
const CollapsibleSection = (props: SectionProps) => {
const { routePath, index, title, page } = props
const isDefaultOpen = routePath.includes(page.href) || index < 3
const { getDetailsProps, open: isOpen } = useDetails({ defaultOpen: isDefaultOpen })
return (
<Details {...getDetailsProps()} className="details-reset">
<summary>
<div className="d-flex flex-justify-between">
<Link
href={page.href}
className="pl-4 pr-2 py-2 f6 text-uppercase d-block flex-auto mr-3 color-text-primary no-underline"
>
{title}
</Link>
{page.childPages.length > 0 && (
<span style={{ marginTop: 7 }} className="flex-shrink-0 pr-3">
<ChevronDownIcon className={cx('opacity-60', isOpen && 'rotate-180')} />
</span>
)}
</div>
</summary>
{/* <!-- some categories have maptopics with child articles --> */}
{page.childPages[0].page.documentType === 'mapTopic' ? (
<ul className="sidebar-topics list-style-none position-relative">
{page.childPages.map((childPage, i) => {
const childTitle = childPage.renderedShortTitle || childPage.renderedFullTitle
const isActive = routePath.includes(childPage.href)
const isCurrent = routePath === childPage.href
return (
<li
key={childPage.href + i}
className={cx(
'sidebar-maptopic',
isActive && 'active',
isCurrent && 'is-current-page'
)}
>
<Link
href={childPage.href}
className="pl-4 pr-5 py-2 color-text-primary no-underline"
>
{childTitle}
</Link>
<ul className="sidebar-articles my-2">
{childPage.childPages.map((grandchildPage, i, arr) => {
const grandchildTitle =
grandchildPage.renderedShortTitle || grandchildPage.renderedFullTitle
const isLast = i === arr.length - 1
const isActive = routePath.includes(grandchildPage.href)
const isCurrent = routePath === grandchildPage.href
return (
<li
key={grandchildPage.href + i}
className={cx(
'sidebar-article',
isActive && 'active',
isCurrent && 'is-current-page'
)}
>
<Link
href={grandchildPage.href}
className={cx(
'pl-6 pr-5 py-1 color-text-primary no-underline',
isLast && 'pb-2'
)}
>
{grandchildTitle}
</Link>
</li>
)
})}
</ul>
</li>
)
})}
</ul>
) : page.childPages[0].page.documentType == 'article' ? (
<ul className="sidebar-articles list-style-none">
{/* <!-- some categories have no maptopics, only articles --> */}
{page.childPages.map((childPage, i, arr) => {
const childTitle = childPage.renderedShortTitle || childPage.renderedFullTitle
const isLast = i === arr.length - 1
const isActive = routePath.includes(childPage.href)
const isCurrent = routePath === childPage.href
return (
<li
key={childPage.href + i}
className={cx(
'sidebar-article',
isActive && 'active',
isCurrent && 'is-current-page'
)}
>
<Link
href={childPage.href}
className={cx('pl-6 pr-5 py-1 color-text-primary no-underline', isLast && 'pb-2')}
>
{childTitle}
</Link>
</li>
)
})}
</ul>
) : null}
</Details>
)
}

View File

@@ -35,13 +35,13 @@ Once you complete this project, you should understand how to build your own Java
### Prerequisites ### Prerequisites
Before you begin, you'll need to download Node.js and create a GitHub repository. Before you begin, you'll need to download Node.js and create a public {% data variables.product.prodname_dotcom %} repository.
1. Download and install Node.js 12.x, which includes npm. 1. Download and install Node.js 12.x, which includes npm.
https://nodejs.org/en/download/current/ https://nodejs.org/en/download/current/
1. Create a new repository on {% data variables.product.product_location %}. You can choose any repository name or use "hello-world-javascript-action" like this example. You can add these files after your project has been pushed to {% data variables.product.product_name %}. For more information, see "[Create a new repository](/articles/creating-a-new-repository)." 1. Create a new public repository on {% data variables.product.product_location %} and call it "hello-world-javascript-action". For more information, see "[Create a new repository](/articles/creating-a-new-repository)."
1. Clone your repository to your computer. For more information, see "[Cloning a repository](/articles/cloning-a-repository)." 1. Clone your repository to your computer. For more information, see "[Cloning a repository](/articles/cloning-a-repository)."
@@ -51,7 +51,7 @@ Before you begin, you'll need to download Node.js and create a GitHub repository
cd hello-world-javascript-action cd hello-world-javascript-action
``` ```
1. From your terminal, initialize the directory with a `package.json` file. 1. From your terminal, initialize the directory with npm to generate a `package.json` file.
```shell ```shell
npm init -y npm init -y
@@ -59,10 +59,8 @@ Before you begin, you'll need to download Node.js and create a GitHub repository
### Creating an action metadata file ### Creating an action metadata file
Create a new file `action.yml` in the `hello-world-javascript-action` directory with the following example code. For more information, see "[Metadata syntax for {% data variables.product.prodname_actions %}](/actions/creating-actions/metadata-syntax-for-github-actions)." Create a new file named `action.yml` in the `hello-world-javascript-action` directory with the following example code. For more information, see "[Metadata syntax for {% data variables.product.prodname_actions %}](/actions/creating-actions/metadata-syntax-for-github-actions)."
**action.yml**
```yaml ```yaml
name: 'Hello World' name: 'Hello World'
description: 'Greet someone and record the time' description: 'Greet someone and record the time'
@@ -108,7 +106,7 @@ GitHub Actions provide context information about the webhook event, Git refs, wo
Add a new file called `index.js`, with the following code. Add a new file called `index.js`, with the following code.
**index.js** {% raw %}
```javascript ```javascript
const core = require('@actions/core'); const core = require('@actions/core');
const github = require('@actions/github'); const github = require('@actions/github');
@@ -126,6 +124,7 @@ try {
core.setFailed(error.message); core.setFailed(error.message);
} }
``` ```
{% endraw %}
If an error is thrown in the above `index.js` example, `core.setFailed(error.message);` uses the actions toolkit [`@actions/core`](https://github.com/actions/toolkit/tree/main/packages/core) package to log a message and set a failing exit code. For more information, see "[Setting exit codes for actions](/actions/creating-actions/setting-exit-codes-for-actions)." If an error is thrown in the above `index.js` example, `core.setFailed(error.message);` uses the actions toolkit [`@actions/core`](https://github.com/actions/toolkit/tree/main/packages/core) package to log a message and set a failing exit code. For more information, see "[Setting exit codes for actions](/actions/creating-actions/setting-exit-codes-for-actions)."
@@ -143,7 +142,6 @@ In your `hello-world-javascript-action` directory, create a `README.md` file tha
- Environment variables the action uses. - Environment variables the action uses.
- An example of how to use your action in a workflow. - An example of how to use your action in a workflow.
**README.md**
```markdown ```markdown
# Hello world javascript action # Hello world javascript action
@@ -180,7 +178,7 @@ It's best practice to also add a version tag for releases of your action. For mo
```shell ```shell
git add action.yml index.js node_modules/* package.json package-lock.json README.md git add action.yml index.js node_modules/* package.json package-lock.json README.md
git commit -m "My first action is ready" git commit -m "My first action is ready"
git tag -a -m "My first action release" v1 git tag -a -m "My first action release" v1.1
git push --follow-tags git push --follow-tags
``` ```
@@ -205,7 +203,7 @@ Checking in your `node_modules` directory can cause problems. As an alternative,
```shell ```shell
git add action.yml dist/index.js node_modules/* git add action.yml dist/index.js node_modules/*
git commit -m "Use vercel/ncc" git commit -m "Use vercel/ncc"
git tag -a -m "My first action release" v1 git tag -a -m "My first action release" v1.1
git push --follow-tags git push --follow-tags
``` ```
@@ -217,10 +215,11 @@ Now you're ready to test your action out in a workflow. When an action is in a p
#### Example using a public action #### Example using a public action
The following workflow code uses the completed hello world action in the `actions/hello-world-javascript-action` repository. Copy the workflow code into a `.github/workflows/main.yml` file, but replace the `actions/hello-world-javascript-action` repository with the repository you created. You can also replace the `who-to-greet` input with your name. This example demonstrates how your new public action can be run from within an external repository.
Copy the following YAML into a new file at `.github/workflows/main.yml`, and update the `uses: octocat/hello-world-javascript-action@v1.1` line with your username and the name of the public repository you created above. You can also replace the `who-to-greet` input with your name.
{% raw %} {% raw %}
**.github/workflows/main.yml**
```yaml ```yaml
on: [push] on: [push]
@@ -231,7 +230,7 @@ jobs:
steps: steps:
- name: Hello world action step - name: Hello world action step
id: hello id: hello
uses: actions/hello-world-javascript-action@v1.1 uses: octocat/hello-world-javascript-action@v1.1
with: with:
who-to-greet: 'Mona the Octocat' who-to-greet: 'Mona the Octocat'
# Use the output from the `hello` step # Use the output from the `hello` step
@@ -240,6 +239,8 @@ jobs:
``` ```
{% endraw %} {% endraw %}
When this workflow is triggered, the runner will download the `hello-world-javascript-action` action from your public repository and then execute it.
#### Example using a private action #### Example using a private action
Copy the workflow code into a `.github/workflows/main.yml` file in your action's repository. You can also replace the `who-to-greet` input with your name. Copy the workflow code into a `.github/workflows/main.yml` file in your action's repository. You can also replace the `who-to-greet` input with your name.

View File

@@ -10,6 +10,13 @@ versions:
topics: topics:
- Enterprise - Enterprise
--- ---
{% note %}
**Note:** Support for {% data variables.product.prodname_ghe_server %} on XenServer will be discontinued in {% data variables.product.prodname_ghe_server %} 3.3. For more information, see the [{% data variables.product.prodname_ghe_server %} 3.1 release notes](/admin/release-notes#3.1.0)
{% endnote %}
### Prerequisites ### Prerequisites
- {% data reusables.enterprise_installation.software-license %} - {% data reusables.enterprise_installation.software-license %}

View File

@@ -2,13 +2,14 @@
title: Viewing your subscriptions and billing date title: Viewing your subscriptions and billing date
intro: 'You can view your account''s subscription, your other paid features and products, and your next billing date in your account''s billing settings.' intro: 'You can view your account''s subscription, your other paid features and products, and your next billing date in your account''s billing settings.'
redirect_from: redirect_from:
- /github/setting-up-and-managing-billing-and-payments-on-github/managing-your-github-billing-settings/viewing-your-subscriptions-and-billing-date
- /github/setting-up-and-managing-billing-and-payments-on-github/viewing-your-subscriptions-and-billing-date - /github/setting-up-and-managing-billing-and-payments-on-github/viewing-your-subscriptions-and-billing-date
- /articles/finding-your-next-billing-date/ - /articles/finding-your-next-billing-date/
- /articles/finding-your-personal-account-s-next-billing-date/ - /articles/finding-your-personal-account-s-next-billing-date/
- /articles/finding-your-organization-s-next-billing-date/ - /articles/finding-your-organization-s-next-billing-date/
- /articles/viewing-your-plans-and-billing-date/ - /articles/viewing-your-plans-and-billing-date/
- /articles/viewing-your-subscriptions-and-billing-date - /articles/viewing-your-subscriptions-and-billing-date
- /github/setting-up-and-managing-billing-and-payments-on-github/viewing-your-subscriptions-and-billing-date
versions: versions:
free-pro-team: '*' free-pro-team: '*'
type: how_to type: how_to

View File

@@ -81,6 +81,18 @@ For more information about the `pull_request` event, see "[Workflow syntax for {
If you scan pull requests, then the results appear as alerts in a pull request check. For more information, see "[Triaging code scanning alerts in pull requests](/code-security/secure-coding/triaging-code-scanning-alerts-in-pull-requests)." If you scan pull requests, then the results appear as alerts in a pull request check. For more information, see "[Triaging code scanning alerts in pull requests](/code-security/secure-coding/triaging-code-scanning-alerts-in-pull-requests)."
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.1" or currentVersion == "github-ae@next" %}
#### Defining the alert severities causing pull request check failure
By default, only alerts with the severity level of `error` will cause a pull request check failure, and a check will still succeed with alerts of lower severities. You can change the levels of alert severities that will cause a pull request check failure in your repository settings.
{% data reusables.repositories.navigate-to-repo %}
{% data reusables.repositories.sidebar-settings %}
{% data reusables.repositories.navigate-to-security-and-analysis %}
1. Under "Code scanning", to the right of "Check Failure", use the drop-down menu to select the level of severity you would like to cause a pull request check failure.
![Check failure setting](/assets/images/help/repository/code-scanning-check-failure-setting.png)
{% endif %}
#### Avoiding unnecessary scans of pull requests #### Avoiding unnecessary scans of pull requests
You might want to avoid a code scan being triggered on specific pull requests targeted against the default branch, irrespective of which files have been changed. You can configure this by specifying `on:pull_request:paths-ignore` or `on:pull_request:paths` in the {% data variables.product.prodname_code_scanning %} workflow. For example, if the only changes in a pull request are to files with the file extensions `.md` or `.txt` you can use the following `paths-ignore` array. You might want to avoid a code scan being triggered on specific pull requests targeted against the default branch, irrespective of which files have been changed. You can configure this by specifying `on:pull_request:paths-ignore` or `on:pull_request:paths` in the {% data variables.product.prodname_code_scanning %} workflow. For example, if the only changes in a pull request are to files with the file extensions `.md` or `.txt` you can use the following `paths-ignore` array.

View File

@@ -27,7 +27,11 @@ topics:
In repositories where {% data variables.product.prodname_code_scanning %} is configured as a pull request check, {% data variables.product.prodname_code_scanning %} checks the code in the pull request. By default, this is limited to pull requests that target the default branch, but you can change this configuration within {% data variables.product.prodname_actions %} or in a third-party CI/CD system. If merging the changes would introduce new {% data variables.product.prodname_code_scanning %} alerts to the target branch, these are reported as check results in the pull request. The alerts are also shown as annotations in the **Files changed** tab of the pull request. If you have write permission for the repository, you can see any existing {% data variables.product.prodname_code_scanning %} alerts on the **Security** tab. For information about repository alerts, see "[Managing {% data variables.product.prodname_code_scanning %} alerts for your repository](/code-security/secure-coding/managing-code-scanning-alerts-for-your-repository)." In repositories where {% data variables.product.prodname_code_scanning %} is configured as a pull request check, {% data variables.product.prodname_code_scanning %} checks the code in the pull request. By default, this is limited to pull requests that target the default branch, but you can change this configuration within {% data variables.product.prodname_actions %} or in a third-party CI/CD system. If merging the changes would introduce new {% data variables.product.prodname_code_scanning %} alerts to the target branch, these are reported as check results in the pull request. The alerts are also shown as annotations in the **Files changed** tab of the pull request. If you have write permission for the repository, you can see any existing {% data variables.product.prodname_code_scanning %} alerts on the **Security** tab. For information about repository alerts, see "[Managing {% data variables.product.prodname_code_scanning %} alerts for your repository](/code-security/secure-coding/managing-code-scanning-alerts-for-your-repository)."
If {% data variables.product.prodname_code_scanning %} has any results with a severity of `error`, the check fails and the error is reported in the check results. If all the results found by {% data variables.product.prodname_code_scanning %} have lower severities, the alerts are treated as warnings or notices and the check succeeds. If your pull request targets a protected branch that uses {% data variables.product.prodname_code_scanning %}, and the repository owner has configured required status checks, then you must either fix or dismiss all error alerts before the pull request can be merged. For more information, see "[About protected branches](/github/administering-a-repository/about-protected-branches#require-status-checks-before-merging)." If {% data variables.product.prodname_code_scanning %} has any results with a severity of `error`, the check fails and the error is reported in the check results. If all the results found by {% data variables.product.prodname_code_scanning %} have lower severities, the alerts are treated as warnings or notices and the check succeeds.
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.1" or currentVersion == "github-ae@next" %}You can override the default behavior in your repository settings, by specifying the level of severities that will cause a pull request check failure. For more information, see "[Defining the alert severities causing pull request check failure](/code-security/secure-coding/configuring-code-scanning#defining-the-alert-severities-causing-pull-request-check-failure)".
{% endif %}If your pull request targets a protected branch that uses {% data variables.product.prodname_code_scanning %}, and the repository owner has configured required status checks, then you must either fix or dismiss all error alerts before the pull request can be merged. For more information, see "[About protected branches](/github/administering-a-repository/about-protected-branches#require-status-checks-before-merging)."
![Failed {% data variables.product.prodname_code_scanning %} check on a pull request](/assets/images/help/repository/code-scanning-check-failure.png) ![Failed {% data variables.product.prodname_code_scanning %} check on a pull request](/assets/images/help/repository/code-scanning-check-failure.png)

View File

@@ -298,7 +298,7 @@ Dependencies ignored by using the `@dependabot ignore` command are stored centra
You can check whether a repository has stored `ignore` preferences by searching the repository for `"@dependabot ignore" in:comments`. If you wish to un-ignore a dependency ignored this way, re-open the pull request. You can check whether a repository has stored `ignore` preferences by searching the repository for `"@dependabot ignore" in:comments`. If you wish to un-ignore a dependency ignored this way, re-open the pull request.
For more information about the `@dependabot ignore` commands, see "[Managing pull requests for dependency updates](/github/administering-a-repository/managing-pull-requests-for-dependency-updates)." For more information about the `@dependabot ignore` commands, see "[Managing pull requests for dependency updates](/github/administering-a-repository/managing-pull-requests-for-dependency-updates#managing-dependabot-pull-requests-with-comment-commands)."
##### Specifying dependencies and versions to ignore ##### Specifying dependencies and versions to ignore

View File

@@ -37,6 +37,21 @@ By default, {% data variables.product.prodname_dependabot %} automatically rebas
### Managing {% data variables.product.prodname_dependabot %} pull requests with comment commands ### Managing {% data variables.product.prodname_dependabot %} pull requests with comment commands
{% data variables.product.prodname_dependabot %} responds to simple commands in comments. Each pull request contains details of the commands you can use to process the pull request, for example: to merge, squash, reopen, close, or rebase the pull request. The aim is to make it as easy as possible for you to triage these automatically generated pull requests. {% data variables.product.prodname_dependabot %} responds to simple commands in comments. Each pull request contains details of the commands you can use to process the pull request (for example: to merge, squash, reopen, close, or rebase the pull request) under the "{% data variables.product.prodname_dependabot %} commands and options" section. The aim is to make it as easy as possible for you to triage these automatically generated pull requests.
You can use any of the following commands on a {% data variables.product.prodname_dependabot %} pull request.
- `@dependabot cancel merge` cancels a previously requested merge.
- `@dependabot close` closes the pull request and prevents {% data variables.product.prodname_dependabot %} from recreating that pull request. You can achieve the same result by closing the pull request manually.
- `@dependabot ignore this dependency` closes the pull request and prevents {% data variables.product.prodname_dependabot %} from creating any more pull requests for this dependency (unless you reopen the pull request or upgrade to the suggested version of the dependency yourself).
- `@dependabot ignore this major version` closes the pull request and prevents {% data variables.product.prodname_dependabot %} from creating any more pull requests for this major version (unless you reopen the pull request or upgrade to this major version yourself).
- `@dependabot ignore this minor version` closes the pull request and prevents {% data variables.product.prodname_dependabot %} from creating any more pull requests for this minor version (unless you reopen the pull request or upgrade to this minor version yourself).
- `@dependabot merge` merges the pull request once your CI tests have passed.
- `@dependabot rebase` rebases the pull request.
- `@dependabot recreate` recreates the pull request, overwriting any edits that have been made to the pull request.
- `@dependabot reopen` reopens the pull request if the pull request is closed.
- `@dependabot squash and merge` squashes and merges the pull request once your CI tests have passed.
{% data variables.product.prodname_dependabot %} will react with a "thumbs up" emoji to acknowledge the command, and may respond with a comment on the pull request. While {% data variables.product.prodname_dependabot %} usually responds quickly, some commands may take several minutes to complete if {% data variables.product.prodname_dependabot %} is busy processing other updates or commands.
If you run any of the commands for ignoring dependencies or versions, {% data variables.product.prodname_dependabot %} stores the preferences for the repository centrally. While this is a quick solution, for repositories with more than one contributor it is better to explicitly define the dependencies and versions to ignore in the configuration file. This makes it easy for all contributors to see why a particular dependency isn't being updated automatically. For more information, see "[Configuration options for dependency updates](/github/administering-a-repository/configuration-options-for-dependency-updates#ignore)." If you run any of the commands for ignoring dependencies or versions, {% data variables.product.prodname_dependabot %} stores the preferences for the repository centrally. While this is a quick solution, for repositories with more than one contributor it is better to explicitly define the dependencies and versions to ignore in the configuration file. This makes it easy for all contributors to see why a particular dependency isn't being updated automatically. For more information, see "[Configuration options for dependency updates](/github/administering-a-repository/configuration-options-for-dependency-updates#ignore)."

View File

@@ -19,7 +19,7 @@ topics:
{% if currentVersion == "free-pro-team@latest" %} {% if currentVersion == "free-pro-team@latest" %}
You can store a variety of projects in {% data variables.product.product_name %} repositories, including open source projects. With [open source projects](http://opensource.org/about), you can share code to make better, more reliable software. You can store a variety of projects in {% data variables.product.product_name %} repositories, including open source projects. With [open source projects](http://opensource.org/about), you can share code to make better, more reliable software. You can use repositories to collaborate with others and track your work. For more information, see "[About repositories](/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/about-repositories)."
{% elsif enterpriseServerVersions contains currentVersion or currentVersion == "github-ae@latest" %} {% elsif enterpriseServerVersions contains currentVersion or currentVersion == "github-ae@latest" %}
@@ -82,6 +82,7 @@ Congratulations! You have now created a repository, including a *README* file, a
- "[Set up Git](/articles/set-up-git)" - "[Set up Git](/articles/set-up-git)"
- **Create a repository** - **Create a repository**
- "[Clone a repository](/github/creating-cloning-and-archiving-repositories/cloning-a-repository)"
- "[Fork a repository](/articles/fork-a-repo)" - "[Fork a repository](/articles/fork-a-repo)"
- "[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 %}

View File

@@ -1,5 +1,6 @@
--- ---
title: Searching for information on GitHub title: Searching for information on GitHub
intro: Use different types of searches to find the information you want.
redirect_from: redirect_from:
- /categories/78/articles/ - /categories/78/articles/
- /categories/search/ - /categories/search/
@@ -14,4 +15,3 @@ children:
- /getting-started-with-searching-on-github - /getting-started-with-searching-on-github
- /searching-on-github - /searching-on-github
--- ---

View File

@@ -26,7 +26,7 @@ For more information about adding people to your enterprise, see "{% if currentV
Enterprise owners have complete control over the enterprise and can take every action, including: Enterprise owners have complete control over the enterprise and can take every action, including:
- Managing administrators - Managing administrators
- {% if currentVersion == "free-pro-team@latest" %}Adding and removing {% elsif currentVersion == "github-ae@latest" %}Managing{% endif %} organizations {% if currentVersion == "free-pro-team@latest" %}to and from {% elsif currentVersion == "github-ae@latest" %} in{% endif %} the enterprise - {% if currentVersion == "free-pro-team@latest" %}Adding and removing {% elsif currentVersion == "github-ae@latest" or currentVersion ver_gt "enterprise-server@2.20" %}Managing{% endif %} organizations {% if currentVersion == "free-pro-team@latest" %}to and from {% elsif currentVersion == "github-ae@latest" or currentVersion ver_gt "enterprise-server@2.20" %} in{% endif %} the enterprise
- Managing enterprise settings - Managing enterprise settings
- Enforcing policy across organizations - Enforcing policy across organizations
{% if currentVersion == "free-pro-team@latest" %}- Managing billing settings{% endif %} {% if currentVersion == "free-pro-team@latest" %}- Managing billing settings{% endif %}

View File

@@ -17,6 +17,7 @@ sections:
changes: changes:
- Check annotations older than 4 months will be archived. - Check annotations older than 4 months will be archived.
known_issues: known_issues:
- Access to a repository through the administrative shell using `ghe-repo <owner>/<reponame>` will hang. As a workaround, use `ghe-repo <owner>/<reponame> -c "bash -i"` until a fix is available in the next version.
- On a freshly set up GitHub Enterprise Server without any users, an attacker could create the first admin user. - On a freshly set up GitHub Enterprise Server without any users, an attacker could create the first admin user.
- Custom firewall rules are not maintained during an upgrade. - Custom firewall rules are not maintained during an upgrade.
- Git LFS tracked files [uploaded through the web interface](https://github.com/blog/2105-upload-files-to-your-repositories) are incorrectly added directly to the repository. - Git LFS tracked files [uploaded through the web interface](https://github.com/blog/2105-upload-files-to-your-repositories) are incorrectly added directly to the repository.

View File

@@ -1,130 +1,20 @@
date: '2021-05-06' date: '2021-05-06'
release_candidate: true release_candidate: true
deprecated: true
intro: If {% data variables.product.product_location %} is running a release candidate build, you can't upgrade with a hotpatch. We recommend only running release candidates on test environments. intro: If {% data variables.product.product_location %} is running a release candidate build, you can't upgrade with a hotpatch. We recommend only running release candidates on test environments.
sections: sections:
features: security_fixes:
- heading: GitHub Advanced Security Secret Scanning - '**MEDIUM** Under certain circumstances, users who were removed from a team or organization could retain write access to branches they had existing pull requests opened for.'
notes: - Packages have been updated to the latest security versions.
- | bugs:
[Secret Scanning](https://github.com/features/security) is now generally available on {% data variables.product.prodname_ghe_server %} 3.1+. Scan public and private repositories for committed credentials, find secrets, and notify the secret provider or admin the moment they are committed into a repository. - 'A scheduled cleanup job can cause performance to degrade on an instance with a very large `check_annotations` table.'
This release includes several improvements from the beta of Secret Scanning on {% data variables.product.prodname_ghe_server %}:
- Expanded our [pattern coverage](/enterprise-server@3.1/code-security/secret-security/about-secret-scanning#about-secret-scanning-for-private-repositories) from 24 partners to 37
- Added an [API](/rest/reference/secret-scanning) and [webhooks](/developers/webhooks-and-events/webhook-events-and-payloads#secret_scanning_alert)
- Added [notifications for commit authors](https://github.blog/changelog/2021-03-05-secret-scanning-notifications-for-commit-authors-on-private-repositories/) when they commit secrets
- Updated the index view to made it easy to triage secrets in bulk
- Reduced the false positive rate on many patterns
Administrators using {% data variables.product.prodname_GH_advanced_security %} can [enable and configure](/enterprise-server@3.1/admin/configuration/configuring-secret-scanning-for-your-appliance) {% data variables.product.prodname_GH_advanced_security %} secret scanning. You can review the [updated minimum requirements for your platform](/enterprise-server@3.1/admin/installation/setting-up-a-github-enterprise-server-instance) before you turn on {% data variables.product.prodname_GH_advanced_security %} secret scanning.
- heading: GitHub Advanced Security Code Scanning
notes:
- |
[{% data variables.product.prodname_GH_advanced_security %} code scanning](https://github.com/features/security) is now generally available on {% data variables.product.prodname_ghe_server %} 3.1+. Organizations who have purchased {% data variables.product.prodname_GH_advanced_security %} can use this capability to do static analysis security testing against their code, and prevent vulnerabilities from making it to their production code using CodeQL, our semantic analysis engine. For more information, see "[Configuring code scanning on your appliance](/en/enterprise-server@3.1/admin/configuration/configuring-code-scanning-for-your-appliance#running-code-scanning-using-github-actions)."
- heading: GitHub Advanced Security billing improvements
notes:
- |
This release includes several improvements to {% data variables.product.prodname_GH_advanced_security %} billing in {% data variables.product.prodname_ghe_server %}:
- {% data variables.product.prodname_GH_advanced_security %} customers can now view their active committer count and the remaining number of unused committer seats on their organization or enterprise accounts Billing page. If Advanced Security is purchased for an enterprise, administrators can also view the active committer seats which are being used by other organizations within their enterprise. For more information, see "[About GitHub Advanced Security licensing](/enterprise-server@3.1/admin/advanced-security/about-licensing-for-github-advanced-security)" and "[Viewing your GitHub Advanced Security usage](/enterprise-server@3.1/admin/advanced-security/viewing-your-github-advanced-security-usage)."
- GitHub Advanced Security customers can now view their active committer count for any Advanced Security enabled repositories on their organization or enterprise account's Billing page. These changes help billing administrators track their usage against how many committer licenses they purchased. For more information see "[Managing security and analysis settings for your organization](/enterprise-server@3.1/organizations/keeping-your-organization-secure/managing-security-and-analysis-settings-for-your-organization)."
- heading: Dependabot improvements
notes:
- |
This release includes improvements to Dependabot alerts in {% data variables.product.prodname_ghe_server %}:
- Users with Dependabot alerts enabled can see which of their repositories are impacted by a given vulnerability by navigating to its entry in the [GitHub Advisory Database](https://github.com/advisories). This feature is available in public beta. For more information, see "[Viewing and updating vulnerable dependencies in your repository](/enterprise-server@3.1/code-security/supply-chain-security/viewing-and-updating-vulnerable-dependencies-in-your-repository)."
- When a vulnerability is added to GitHub Advisory Database, you will no longer receive [email and web notifications](https://github.com/notifications) for Dependabot alerts on low and moderate severity vulnerabilities. These alerts are still accessible from the repository's Security tab. For more information, see [Viewing and updating vulnerable dependencies in your repository](/enterprise-server@3.1/code-security/supply-chain-security/viewing-and-updating-vulnerable-dependencies-in-your-repository).
- 'You can now give people instructions on how to responsibly report security vulnerabilities in your project by adding a `SECURITY.md` file to your repository's `root`, `docs`, or `.github` folder. When someone creates an issue in your repository, they will see a link to your project's security policy. For more information, see "[Adding a security policy to your repository](/enterprise-server@3.1/code-security/getting-started/adding-a-security-policy-to-your-repository)."'
- heading: GitHub Actions Workflow Visualization beta
notes:
- |
GitHub Actions can now generate a visual graph of your workflow on every run. With workflow visualization, you can:
- View and understand complex workflows
- Track progress of workflows in real-time
- Troubleshoot runs quickly by easily accessing logs and jobs metadata
- Monitor progress of deployment jobs and easily access deployment targets
For more information, see "[Using the visualization graph](/actions/managing-workflow-runs/using-the-visualization-graph)."
- heading: OAuth 2.0 Device Authorization Grant
notes:
- |
[OAuth 2.0 Device Authorization Grant](https://github.com/login/device) allows any CLI client or developer tool to authenticate using a secondary system with a browser.
Administrators using [OAuth Apps](/developers/apps/authorizing-oauth-apps#device-flow) and [GitHub Apps](/developers/apps/authorizing-oauth-apps#device-flow) can [enable and configure](/enterprise-server@3.1/admin/configuration/configuring-secret-scanning-for-your-appliance) OAuth 2.0 Device Authorization Flow, in addition to the existing Web Application Flow. You can review the [updated minimum requirements for your platform](/enterprise-server@3.1/admin/installation/setting-up-a-github-enterprise-server-instance) before you enable OAuth 2.0 Device Authorization Flow.
- heading: Pull request auto-merge
notes:
- |
With auto-merge, pull requests can be set to merge automatically when all merge requirements have been satisfied. This saves users from needing to constantly check the state of their pull requests just to merge them. Auto-merge can be enabled by a user with permission to merge and on pull requests that have unsatisfied merge requirements. For more information, see "[Automatically merging a pull request](/enterprise-server@3.1/github/collaborating-with-issues-and-pull-requests/automatically-merging-a-pull-request)."
- heading: Custom notifications
notes:
- |
You can customize the types of notifications you want to receive from individual repositories. For more information, see "[Configuring notifications](/enterprise-server@3.1/github/managing-subscriptions-and-notifications-on-github/configuring-notifications#configuring-your-watch-settings-for-an-individual-repository)."
changes: changes:
- heading: Administration Changes - Check annotations older than 4 months will be archived.
notes: - 'The `firstPatchedVersion` field is now available on `SecurityVulnerability` objects in the GraphQL API.'
- By precomputing checksums, the amount of time a repository is under the lock has reduced dramatically, allowing more write operations to succeed immediately and improving monorepo performance.
- The latest release of the CodeQL CLI supports uploading analysis results to GitHub. This makes it easier to run code analysis for customers who wish to use CI/CD systems other than GitHub Actions. Previously, such users had to use the separate CodeQL runner, which will continue to be available. For more information, see "[About CodeQL code scanning in your CI system](/enterprise-server@3.1/code-security/secure-coding/about-codeql-code-scanning-in-your-ci-system)."
- GitHub Actions now supports skipping `push` and `pull_request` workflows by looking for some common keywords in your commit message.
- Check annotations older than four months will be archived.
- heading: Security Changes
notes:
- Display of Code Scanning results on a pull request without submitting with a pull request ID is no longer supported. For more information, see "[Configuring code scanning](/enterprise-server@3.1/code-security/secure-coding/configuring-code-scanning#scanning-pull-requests)" and "[Configuring CodeQL code scanning in your CI system](/enterprise-server@3.1/code-security/secure-coding/configuring-codeql-code-scanning-in-your-ci-system#scanning-pull-requests).
- SARIF upload support increased to a maximum of 5000 results per upload.
- heading: Developer Changes
notes:
- You can specify multiple callback URLs while configuring a GitHub App. This can be used in services with multiple domains or subdomains. GitHub will always deny authorization if the callback URL from the request is not in the authorization callback URL list.
- The GitHub App file permission has been updated to allow an app developer to specify up to 10 files for read-only or read-write access that their app can request access to.
- CodeQL now supports more [libraries and frameworks](https://codeql.github.com/docs/codeql-overview/supported-languages-and-frameworks/) for a variety of languages ([C++](https://github.com/github/codeql/tree/main/cpp), [JavaScript](https://github.com/github/codeql/tree/main/javascript), [Python](https://github.com/github/codeql/tree/main/python),[Java](https://github.com/github/codeql/tree/main/java), [Go](https://github.com/github/codeql-go/tree/main)). The CodeQL engine can now detect more sources of untrusted user data, which improves the quality and depth of the code scanning alerts. For more information, see "[About CodeQL](https://codeql.github.com/docs/codeql-overview/about-codeql/)."
- When configuring a GitHub App, the authorization callback URL is a required field. Now, we allow the developer to specify multiple callback URLs. This can be used in services with multiple domains or subdomains. GitHub will always deny authorization if the callback URL from the request is not in the authorization callback URL list.
- Delete an entire directory of files, including subdirectories, from your web browser. For more information, see "[Deleting a file or directory](/enterprise-server@3.1/github/managing-files-in-a-repository/deleting-files-in-a-repository#deleting-a-directory)."
- 'Include multiple words after the `#` in an issue, discussion, or pull request comment to further narrow your search.'
- 'When youre writing an issue, pull request, or discussion comment the list syntax for bullets, numbers, and tasks autocompletes after you press `return` or `enter`.'
- heading: API Changes
notes:
- The code scanning API allows users to upload data about static analysis security testing results, or export data about alerts. For more information, see the [code scanning API reference](https://docs.github.com/en/rest/reference/code-scanning).
- The [GitHub Apps API](https://docs.github.com/rest/reference/apps) for managing installations has now graduated from an API preview to a generally available API. The [preview header](https://docs.github.com/rest/overview/api-previews) is no longer required to access these endpoints.
known_issues: known_issues:
- The GitHub Packages npm registry no longer returns a time value in metadata responses. This was done to allow for substantial performance improvements. We continue to have all the data necessary to return a time value as part of the metadata response and will resume returning this value in the future once we have solved the existing performance issues. - The GitHub Packages npm registry no longer returns a time value in metadata responses. This was done to allow for substantial performance improvements. We continue to have all the data necessary to return a time value as part of the metadata response and will resume returning this value in the future once we have solved the existing performance issues.
- 'A scheduled cleanup job can cause performance to degrade on an instance with a very large `check_annotations` table.'
- On a freshly set up GitHub Enterprise Server without any users, an attacker could create the first admin user. - On a freshly set up GitHub Enterprise Server without any users, an attacker could create the first admin user.
- Custom firewall rules are not maintained during an upgrade. - Custom firewall rules are not maintained during an upgrade.
- Git LFS tracked files [uploaded through the web interface](https://github.com/blog/2105-upload-files-to-your-repositories) are incorrectly added directly to the repository. - Git LFS tracked files [uploaded through the web interface](https://github.com/blog/2105-upload-files-to-your-repositories) are incorrectly added directly to the repository.
- Issues cannot be closed if they contain a permalink to a blob in the same repository where the file path is longer than 255 characters. - Issues cannot be closed if they contain a permalink to a blob in the same repository where the file path is longer than 255 characters.
- When "Users can search GitHub.com" is enabled with GitHub Connect, issues in private and internal repositories are not included in GitHub.com search results. - When "Users can search GitHub.com" is enabled with GitHub Connect, issues in private and internal repositories are not included in GitHub.com search results.
deprecations:
- heading: Deprecation of GitHub Enterprise Server 2.20
notes:
- '**{% data variables.product.prodname_ghe_server %} 2.20 was discontinued on March 2, 2021**. That means that no patch releases will be made, even for critical security issues, after this date. For better performance, improved security, and new features, [upgrade to the newest version of {% data variables.product.prodname_ghe_server %}](/enterprise-server@3.1/admin/enterprise-management/upgrading-github-enterprise-server) as soon as possible.'
- heading: Deprecation of GitHub Enterprise Server 2.21
notes:
- '**{% data variables.product.prodname_ghe_server %} 2.21 will be discontinued on June 9, 2021**. That means that no patch releases will be made, even for critical security issues, after this date. For better performance, improved security, and new features, [upgrade to the newest version of {% data variables.product.prodname_ghe_server %}](/enterprise-server@3.1/admin/enterprise-management/upgrading-github-enterprise-server) as soon as possible.'
- heading: Deprecation of Legacy GitHub App Webhook Events
notes:
- 'Starting with {% data variables.product.prodname_ghe_server %} 2.21.0 two legacy GitHub Apps-related webhook events have been deprecated and will be removed in {% data variables.product.prodname_ghe_server %} 3.2.0. The deprecated events `integration_installation` and `integration_installation_repositories` have equivalent events which will be supported. More information is available in the [deprecation announcement blog post](https://developer.github.com/changes/2020-04-15-replacing-the-installation-and-installation-repositories-events/).'
- heading: Deprecation of Legacy GitHub Apps Endpoint
notes:
- Starting with {% data variables.product.prodname_ghe_server %} 2.21.0 the legacy GitHub Apps endpoint for creating installation access tokens was deprecated and will be removed in {% data variables.product.prodname_ghe_server %} 3.2.0. More information is available in the [deprecation announcement blog post](https://developer.github.com/changes/2020-04-15-replacing-create-installation-access-token-endpoint/).
- heading: Deprecation of OAuth Application API
notes:
- 'GitHub no longer supports the OAuth application endpoints that contain `access_token` as a path parameter. We have introduced new endpoints that allow you to securely manage tokens for OAuth Apps by moving `access_token` to the request body. While deprecated, the endpoints are still accessible in this version. We intend to remove these endpoints on {% data variables.product.prodname_ghe_server %} 3.4. For more information, see the [deprecation announcement blog post](https://developer.github.com/changes/2020-02-14-deprecating-oauth-app-endpoint/).'
- heading: Deprecation of GitHub Actions short SHA support
notes:
- GitHub Actions will remove support for referencing actions using the shortened version of a git commit SHA. This may cause some workflows in your repository to break. To fix these workflows, you will need to update the action reference to use the full commit SHA. For more information, see "[Security hardening for GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/security-hardening-for-github-actions#using-third-party-actions)."
backups:
- '{% data variables.product.prodname_ghe_server %} 3.1 requires at least [GitHub Enterprise Backup Utilities 3.1.0](https://github.com/github/backup-utils) for [Backups and Disaster Recovery](/enterprise-server@3.1/admin/configuration/configuring-backups-on-your-appliance).'

View File

@@ -0,0 +1,159 @@
date: '2021-06-03'
intro: For minimum infrastructure requirements, see "[About minimum requirements for {% data variables.product.prodname_ghe_server %} 3.0 and later](/admin/enterprise-management/upgrading-github-enterprise-server#about-minimum-requirements-for-github-enterprise-server-30-and-later)."
sections:
features:
- heading: GitHub Advanced Security Secret Scanning
notes:
- |
[Secret Scanning](https://github.com/features/security) is now generally available on {% data variables.product.prodname_ghe_server %} 3.1+. Scan public and private repositories for committed credentials, find secrets, and notify the secret provider or admin the moment they are committed into a repository.
This release includes several improvements from the beta of Secret Scanning on {% data variables.product.prodname_ghe_server %}:
- Expanded our [pattern coverage](/enterprise-server@3.1/code-security/secret-security/about-secret-scanning#about-secret-scanning-for-private-repositories) from 24 partners to 37
- Added an [API](/rest/reference/secret-scanning) and [webhooks](/developers/webhooks-and-events/webhook-events-and-payloads#secret_scanning_alert)
- Added [notifications for commit authors](https://github.blog/changelog/2021-03-05-secret-scanning-notifications-for-commit-authors-on-private-repositories/) when they commit secrets
- Updated the index view to made it easy to triage secrets in bulk
- Reduced the false positive rate on many patterns
Administrators using {% data variables.product.prodname_GH_advanced_security %} can [enable and configure](/enterprise-server@3.1/admin/configuration/configuring-secret-scanning-for-your-appliance) {% data variables.product.prodname_GH_advanced_security %} secret scanning. You can review the [updated minimum requirements for your platform](/enterprise-server@3.1/admin/installation/setting-up-a-github-enterprise-server-instance) before you turn on {% data variables.product.prodname_GH_advanced_security %} secret scanning.
- heading: GitHub Advanced Security billing improvements
notes:
- |
This release includes several improvements to {% data variables.product.prodname_GH_advanced_security %} billing in {% data variables.product.prodname_ghe_server %}:
- {% data variables.product.prodname_GH_advanced_security %} customers can now view their active committer count and the remaining number of unused committer seats on their organization or enterprise accounts Billing page. If Advanced Security is purchased for an enterprise, administrators can also view the active committer seats which are being used by other organizations within their enterprise. For more information, see "[About GitHub Advanced Security licensing](/enterprise-server@3.1/admin/advanced-security/about-licensing-for-github-advanced-security)" and "[Viewing your GitHub Advanced Security usage](/enterprise-server@3.1/admin/advanced-security/viewing-your-github-advanced-security-usage)."
- GitHub Advanced Security customers can now view their active committer count for any Advanced Security enabled repositories on their organization or enterprise account's Billing page. These changes help billing administrators track their usage against how many committer licenses they purchased. For more information see "[Managing security and analysis settings for your organization](/enterprise-server@3.1/organizations/keeping-your-organization-secure/managing-security-and-analysis-settings-for-your-organization)."
- heading: Dependabot improvements
notes:
- |
This release includes improvements to Dependabot alerts in {% data variables.product.prodname_ghe_server %}:
- Users with Dependabot alerts enabled can see which of their repositories are impacted by a given vulnerability by navigating to its entry in the [GitHub Advisory Database](https://github.com/advisories). This feature is available in public beta. For more information, see "[Viewing and updating vulnerable dependencies in your repository](/enterprise-server@3.1/code-security/supply-chain-security/viewing-and-updating-vulnerable-dependencies-in-your-repository)."
- When a vulnerability is added to GitHub Advisory Database, you will no longer receive [email and web notifications](https://github.com/notifications) for Dependabot alerts on low and moderate severity vulnerabilities. These alerts are still accessible from the repository's Security tab. For more information, see "[Viewing and updating vulnerable dependencies in your repository](/enterprise-server@3.1/code-security/supply-chain-security/viewing-and-updating-vulnerable-dependencies-in-your-repository)."
- You can now give people instructions on how to responsibly report security vulnerabilities in your project by adding a `SECURITY.md` file to your repository's `root`, `docs`, or `.github` folder. When someone creates an issue in your repository, they will see a link to your project's security policy. For more information, see "[Adding a security policy to your repository](/enterprise-server@3.1/code-security/getting-started/adding-a-security-policy-to-your-repository)."
- heading: GitHub Actions Workflow Visualization beta
notes:
- |
{% data variables.product.prodname_actions %} can now generate a visual graph of your workflow on every run. With workflow visualization, you can:
- View and understand complex workflows
- Track progress of workflows in real-time
- Troubleshoot runs quickly by easily accessing logs and jobs metadata
- Monitor progress of deployment jobs and easily access deployment targets
For more information, see "[Using the visualization graph](/actions/managing-workflow-runs/using-the-visualization-graph)."
- heading: OAuth 2.0 Device Authorization Grant
notes:
- |
[OAuth 2.0 Device Authorization Grant](https://github.com/login/device) allows any CLI client or developer tool to authenticate using a secondary system with a browser.
Administrators using [OAuth Apps](/developers/apps/authorizing-oauth-apps#device-flow) and [GitHub Apps](/developers/apps/authorizing-oauth-apps#device-flow) can enable and configure OAuth 2.0 Device Authorization Flow, in addition to the existing Web Application Flow. You can review the [updated minimum requirements for your platform](/enterprise-server@3.1/admin/installation/setting-up-a-github-enterprise-server-instance) before you enable OAuth 2.0 Device Authorization Flow.
- heading: Pull request auto-merge
notes:
- |
With auto-merge, pull requests can be set to merge automatically when all merge requirements have been satisfied. This saves users from needing to constantly check the state of their pull requests just to merge them. Auto-merge can be enabled by a user with permission to merge and on pull requests that have unsatisfied merge requirements. For more information, see "[Automatically merging a pull request](/enterprise-server@3.1/github/collaborating-with-issues-and-pull-requests/automatically-merging-a-pull-request)."
- heading: Custom notifications
notes:
- |
You can customize the types of notifications you want to receive from individual repositories. For more information, see "[Configuring notifications](/enterprise-server@3.1/github/managing-subscriptions-and-notifications-on-github/configuring-notifications#configuring-your-watch-settings-for-an-individual-repository)."
- heading: GitHub Mobile filtering
notes:
- |
[{% data variables.product.prodname_mobile %}](https://github.com/mobile) filtering allows you to search for and find issues, pull requests, and discussions from your device. New metadata for issues and pull request list items allow you to filter by assignees, checks status, review states, and comment counts.
{% data variables.product.prodname_mobile %} beta is available for {% data variables.product.prodname_ghe_server %}. Sign in with our [Android](https://play.google.com/store/apps/details?id=com.github.android) and [iOS](https://apps.apple.com/app/github/id1477376905) apps to triage notifications and manage issues and pull requests on the go. Administrators can disable mobile support for their Enterprise using the management console or by running `ghe-config app.mobile.enabled false`. For more information, see "[GitHub for mobile](/github/getting-started-with-github/using-github/github-for-mobile)."
changes:
- heading: Administration Changes
notes:
- By precomputing checksums, the amount of time a repository is under the lock has reduced dramatically, allowing more write operations to succeed immediately and improving monorepo performance.
- The latest release of the CodeQL CLI supports uploading analysis results to GitHub. This makes it easier to run code analysis for customers who wish to use CI/CD systems other than {% data variables.product.prodname_actions %}. Previously, such users had to use the separate CodeQL runner, which will continue to be available. For more information, see "[About CodeQL code scanning in your CI system](/enterprise-server@3.1/code-security/secure-coding/about-codeql-code-scanning-in-your-ci-system)."
- '{% data variables.product.prodname_actions %} now supports skipping `push` and `pull_request` workflows by looking for some common keywords in your commit message.'
- Check annotations older than four months will be archived.
- heading: Security Changes
notes:
- Following feedback, display of Code Scanning results on a pull request without submitting with a pull request ID will remain supported. For more information, see "[Configuring code scanning](/enterprise-server@3.1/code-security/secure-coding/configuring-code-scanning#scanning-pull-requests)" and "[Configuring CodeQL code scanning in your CI system](/enterprise-server@3.1/code-security/secure-coding/configuring-codeql-code-scanning-in-your-ci-system#scanning-pull-requests).
- SARIF upload support increased to a maximum of 5000 results per upload.
- heading: Developer Changes
notes:
- You can specify multiple callback URLs while configuring a GitHub App. This can be used in services with multiple domains or subdomains. GitHub will always deny authorization if the callback URL from the request is not in the authorization callback URL list.
- The GitHub App file permission has been updated to allow an app developer to specify up to 10 files for read-only or read-write access that their app can request access to.
- CodeQL now supports more [libraries and frameworks](https://codeql.github.com/docs/codeql-overview/supported-languages-and-frameworks/) for a variety of languages ([C++](https://github.com/github/codeql/tree/main/cpp), [JavaScript](https://github.com/github/codeql/tree/main/javascript), [Python](https://github.com/github/codeql/tree/main/python),[Java](https://github.com/github/codeql/tree/main/java), [Go](https://github.com/github/codeql-go/tree/main)). The CodeQL engine can now detect more sources of untrusted user data, which improves the quality and depth of the code scanning alerts. For more information, see "[About CodeQL](https://codeql.github.com/docs/codeql-overview/about-codeql/)."
- When configuring a GitHub App, the authorization callback URL is a required field. Now, we allow the developer to specify multiple callback URLs. This can be used in services with multiple domains or subdomains. GitHub will always deny authorization if the callback URL from the request is not in the authorization callback URL list.
- Delete an entire directory of files, including subdirectories, from your web browser. For more information, see "[Deleting a file or directory](/enterprise-server@3.1/github/managing-files-in-a-repository/deleting-files-in-a-repository#deleting-a-directory)."
- 'Include multiple words after the `#` in an issue, discussion, or pull request comment to further narrow your search.'
- 'When youre writing an issue, pull request, or discussion comment the list syntax for bullets, numbers, and tasks autocompletes after you press `return` or `enter`.'
- heading: API Changes
notes:
- The code scanning API allows users to upload data about static analysis security testing results, or export data about alerts. For more information, see the [code scanning API reference](/rest/reference/code-scanning).
- The [GitHub Apps API](/rest/reference/apps) for managing installations has now graduated from an API preview to a generally available API. The [preview header](/rest/overview/api-previews) is no longer required to access these endpoints.
security_fixes:
- '**MEDIUM** Under certain circumstances, users who were removed from a team or organization could retain write access to branches they had existing pull requests opened for.'
- Packages have been updated to the latest security versions.
bugs:
- heading: Fixes for known issues from Release Candidate
notes:
- All known issues from Release Candidate 1 have been fixed, except those listed in the Known Issues section below.
- heading: Fixes for other issues
notes:
- On the "Configure Actions and Packages" page of the initial installation process, clicking on the "Test domain settings" button did not complete the test.
- 'Running `ghe-btop` failed with an error and cannot find a `babeld` container.'
- MySQL could reload and cause downtime if you change auto failover settings.
- After upgrading, a mismatch of internal and external timeout values created service unavailability.
- Expected replication delays in MSSQL generated warnings.
- 'Link to "[Configuring clustering](/admin/enterprise-management/configuring-clustering)" on the Management Console was incorrect.'
- When creating or editing a pre-receive hook, a race condition in the user interface meant that after selecting a repository, files within the repository were sometimes not populated in files dropdown.
- When an IP address is added to a whitelist using "Create Whitelist Entry" button, it could still be shown as locked out.
- References to the "Dependency graph" and "Dependabot alerts" features were not shown as disabled on some repositories.
- Setting an announcement in the enterprise account settings could result in a 500 Internal Server Error.
- HTTP POST requests to the `/hooks` endpoint could fail with a 401 response due to an incorrectly configured `hookID`.
- The `build-server` process failed to clean up processes, leaving them in the `defunct` state.
- '`spokesd` created excessive log entries, including the phrase "fixing placement skipped".'
- While upgrading Actions the upgrade could fail if the instance could not make self-requests via its configured hostname.
- Upgrading from 2.22.x to 3.1.0.rc1 could result in a database migration error relating to the `BackfillIntegrationApplicationCallbackUrlsTransition` data transition.
known_issues:
- Access to a repository through the administrative shell using `ghe-repo <owner>/<reponame>` will hang. As a workaround, use `ghe-repo <owner>/<reponame> -c "bash -i"` until a fix is available in the next version.
- The {% data variables.product.prodname_registry %} npm registry no longer returns a time value in metadata responses. This was done to allow for substantial performance improvements. We continue to have all the data necessary to return a time value as part of the metadata response and will resume returning this value in the future once we have solved the existing performance issues.
- On a freshly set up {% data variables.product.prodname_ghe_server %} without any users, an attacker could create the first admin user.
- Custom firewall rules are not maintained during an upgrade.
- Git LFS tracked files [uploaded through the web interface](https://github.com/blog/2105-upload-files-to-your-repositories) are incorrectly added directly to the repository.
- Issues cannot be closed if they contain a permalink to a blob in the same repository where the file path is longer than 255 characters.
- When "Users can search GitHub.com" is enabled with GitHub Connect, issues in private and internal repositories are not included in GitHub.com search results.
deprecations:
- heading: Deprecation of GitHub Enterprise Server 2.20
notes:
- '**{% data variables.product.prodname_ghe_server %} 2.20 was discontinued on March 2, 2021**. That means that no patch releases will be made, even for critical security issues, after this date. For better performance, improved security, and new features, [upgrade to the newest version of {% data variables.product.prodname_ghe_server %}](/enterprise-server@3.1/admin/enterprise-management/upgrading-github-enterprise-server) as soon as possible.'
- heading: Deprecation of GitHub Enterprise Server 2.21
notes:
- '**{% data variables.product.prodname_ghe_server %} 2.21 will be discontinued on June 9, 2021**. That means that no patch releases will be made, even for critical security issues, after this date. For better performance, improved security, and new features, [upgrade to the newest version of {% data variables.product.prodname_ghe_server %}](/enterprise-server@3.1/admin/enterprise-management/upgrading-github-enterprise-server) as soon as possible.'
- heading: Deprecation of Legacy GitHub App Webhook Events
notes:
- 'Starting with {% data variables.product.prodname_ghe_server %} 2.21.0 two legacy GitHub Apps-related webhook events have been deprecated and will be removed in {% data variables.product.prodname_ghe_server %} 3.2.0. The deprecated events `integration_installation` and `integration_installation_repositories` have equivalent events which will be supported. More information is available in the [deprecation announcement blog post](https://developer.github.com/changes/2020-04-15-replacing-the-installation-and-installation-repositories-events/).'
- heading: Deprecation of Legacy GitHub Apps Endpoint
notes:
- Starting with {% data variables.product.prodname_ghe_server %} 2.21.0 the legacy GitHub Apps endpoint for creating installation access tokens was deprecated and will be removed in {% data variables.product.prodname_ghe_server %} 3.2.0. More information is available in the [deprecation announcement blog post](https://developer.github.com/changes/2020-04-15-replacing-create-installation-access-token-endpoint/).
- heading: Deprecation of OAuth Application API
notes:
- 'GitHub no longer supports the OAuth application endpoints that contain `access_token` as a path parameter. We have introduced new endpoints that allow you to securely manage tokens for OAuth Apps by moving `access_token` to the request body. While deprecated, the endpoints are still accessible in this version. We intend to remove these endpoints on {% data variables.product.prodname_ghe_server %} 3.4. For more information, see the [deprecation announcement blog post](https://developer.github.com/changes/2020-02-14-deprecating-oauth-app-endpoint/).'
- heading: Deprecation of GitHub Actions short SHA support
notes:
- '{% data variables.product.prodname_actions %} will remove support for referencing actions using the shortened version of a git commit SHA. This may cause some workflows in your repository to break. To fix these workflows, you will need to update the action reference to use the full commit SHA. For more information, see "[Security hardening for {% data variables.product.prodname_actions %}](/actions/learn-github-actions/security-hardening-for-github-actions#using-third-party-actions)."'
- heading: Deprecation of XenServer Hypervisor support
notes:
- Beginning in {% data variables.product.prodname_ghe_server %} 3.1, we will begin discontinuing support for Xen Hypervisor. The complete deprecation is scheduled for {% data variables.product.prodname_ghe_server %} 3.3, following the standard one year deprecation window.
backups:
- '{% data variables.product.prodname_ghe_server %} 3.1 requires at least [GitHub Enterprise Backup Utilities 3.1.0](https://github.com/github/backup-utils) for [Backups and Disaster Recovery](/enterprise-server@3.1/admin/configuration/configuring-backups-on-your-appliance).'

View File

@@ -1,6 +1,6 @@
1. From the list of GPG keys, copy the GPG key ID you'd like to use. In this example, the GPG key ID is `3AA5C34371567BD2`: 1. From the list of GPG keys, copy the long form of the GPG key ID you'd like to use. In this example, the GPG key ID is `3AA5C34371567BD2`:
```shell ```shell
$ gpg --list-secret-keys --keyid-format LONG $ gpg --list-secret-keys --keyid-format=long
/Users/hubot/.gnupg/secring.gpg /Users/hubot/.gnupg/secring.gpg
------------------------------------ ------------------------------------
sec 4096R/<em>3AA5C34371567BD2</em> 2016-03-10 [expires: 2017-03-10] sec 4096R/<em>3AA5C34371567BD2</em> 2016-03-10 [expires: 2017-03-10]

View File

@@ -1,7 +1,7 @@
1. Use the `gpg --list-secret-keys --keyid-format LONG` command to list GPG keys for which you have both a public and private key. A private key is required for signing commits or tags. 1. Use the `gpg --list-secret-keys --keyid-format=long` command to list the long form of the GPG keys for which you have both a public and private key. A private key is required for signing commits or tags.
```shell ```shell
$ gpg --list-secret-keys --keyid-format LONG $ gpg --list-secret-keys --keyid-format=long
``` ```
{% note %} {% note %}

View File

@@ -1 +1 @@
version: enterprise-server@3.1 version: ''

View File

@@ -1,5 +1,5 @@
{ {
"FEATURE_TEST_TRUE": true, "FEATURE_TEST_TRUE": true,
"FEATURE_TEST_FALSE": false, "FEATURE_TEST_FALSE": false,
"FEATURE_NEXTJS": false "FEATURE_NEXTJS": true
} }

View File

@@ -10,6 +10,13 @@ const { isConnectionDropped } = require('./halt-on-dropped-connection')
const { nextHandleRequest } = require('./next') const { nextHandleRequest } = require('./next')
const { HEROKU_RELEASE_VERSION, FEATURE_NEXTJS } = process.env const { HEROKU_RELEASE_VERSION, FEATURE_NEXTJS } = process.env
const defaultNextJSRoutes = FEATURE_NEXTJS
? [
'/en/sponsors',
'/en/discussions'
]
: []
const pageCacheDatabaseNumber = 1 const pageCacheDatabaseNumber = 1
const pageCacheExpiration = 24 * 60 * 60 * 1000 // 24 hours const pageCacheExpiration = 24 * 60 * 60 * 1000 // 24 hours
@@ -88,7 +95,7 @@ module.exports = async function renderPage (req, res, next) {
const isRequestingJsonForDebugging = 'json' in req.query && process.env.NODE_ENV !== 'production' const isRequestingJsonForDebugging = 'json' in req.query && process.env.NODE_ENV !== 'production'
// Should the current path be rendered by NextJS? // Should the current path be rendered by NextJS?
const renderWithNextjs = 'nextjs' in req.query && FEATURE_NEXTJS const renderWithNextjs = (defaultNextJSRoutes.includes(pathname) || 'nextjs' in req.query) && FEATURE_NEXTJS
// Is in an airgapped session? // Is in an airgapped session?
const isAirgapped = Boolean(req.cookies.AIRGAP) const isAirgapped = Boolean(req.cookies.AIRGAP)

View File

@@ -0,0 +1,5 @@
import GlobalPage from '../index'
export { getServerSideProps } from '../index'
export default GlobalPage

View File

@@ -1,126 +1,61 @@
import { GetServerSideProps } from 'next' import { GetServerSideProps } from 'next'
import { Grid } from '@primer/components'
import { import {
MainContextT, MainContextT,
MainContext, MainContext,
getMainContextFromRequest, getMainContextFromRequest,
} from 'components/context/MainContext' } from 'components/context/MainContext'
import { DefaultLayout } from 'components/DefaultLayout'
import { import {
getProductLandingContextFromRequest, getProductLandingContextFromRequest,
ProductLandingContextT, ProductLandingContextT,
ProductLandingContext, ProductLandingContext,
useProductLandingContext,
} from 'components/context/ProductLandingContext' } from 'components/context/ProductLandingContext'
import { LandingHero } from 'components/landing/LandingHero' import { ProductLanding } from 'components/landing/ProductLanding'
import { FeaturedArticles } from 'components/landing/FeaturedArticles' import { TocLanding } from 'components/landing/TocLanding'
import { GuideCards } from 'components/landing/GuideCards' import {
import { SponsorsExamples } from 'components/landing/SponsorsExamples' getTocLandingContextFromRequest,
import { CommunityExamples } from 'components/landing/CommunityExamples' TocLandingContext,
import { CodeExamples } from 'components/landing/CodeExamples' TocLandingContextT,
import { LandingSection } from 'components/landing/LandingSection' } from 'components/context/TocLandingContext'
import { useTranslation } from 'components/hooks/useTranslation'
import { ProductArticlesList } from 'components/landing/ProductArticlesList'
import { TableOfContents } from 'components/landing/TableOfContents'
import { ArticleVersionPicker } from 'components/article/ArticleVersionPicker'
type Props = { type Props = {
mainContext: MainContextT mainContext: MainContextT
productLandingContext: ProductLandingContextT productLandingContext: ProductLandingContextT
tocLandingContext: TocLandingContextT
} }
const ProductPage = ({ mainContext, productLandingContext }: Props) => { const GlobalPage = ({ mainContext, productLandingContext, tocLandingContext }: Props) => {
return ( const { currentLayoutName, page, relativePath } = mainContext
<MainContext.Provider value={mainContext}>
let content
if (currentLayoutName === 'product-landing') {
content = (
<ProductLandingContext.Provider value={productLandingContext}> <ProductLandingContext.Provider value={productLandingContext}>
{mainContext.currentLayoutName === 'product-landing' ? ( <ProductLanding />
<ProductLanding />
) : (
<TocProductLanding />
)}
</ProductLandingContext.Provider> </ProductLandingContext.Provider>
</MainContext.Provider> )
) } else if (currentLayoutName === 'product-sublanding') {
content = <p>todo: product sub-landing</p>
} else if (relativePath?.endsWith('index.md')) {
content = (
<TocLandingContext.Provider value={tocLandingContext}>
<TocLanding
variant={
page.documentType === 'category' || relativePath === 'github/index.md'
? 'compact'
: 'expanded'
}
/>
</TocLandingContext.Provider>
)
} else {
content = <p>article / fallback rendering</p>
}
return <MainContext.Provider value={mainContext}>{content}</MainContext.Provider>
} }
const ProductLanding = () => { export default GlobalPage
const { title, guideCards, productUserExamples, productCommunityExamples, productCodeExamples } =
useProductLandingContext()
const { t } = useTranslation('product_landing')
return (
<DefaultLayout>
<LandingSection className="pt-3">
<LandingHero />
</LandingSection>
<LandingSection>
<FeaturedArticles />
</LandingSection>
{productCodeExamples.length > 0 && (
<LandingSection title={t('code_examples')} className="my-6">
<CodeExamples />
</LandingSection>
)}
{productCommunityExamples.length > 0 && (
<LandingSection title={t('communities_using_discussions')} className="my-6">
<CommunityExamples />
</LandingSection>
)}
{productUserExamples.length > 0 && (
<LandingSection title={t('sponsor_community')} className="my-6">
<SponsorsExamples />
</LandingSection>
)}
{guideCards.length > 0 && (
<div className="color-bg-tertiary py-6 my-8">
<LandingSection title={t('guides')} className="my-6">
<GuideCards />
</LandingSection>
</div>
)}
<LandingSection sectionLink="all-docs" title={`All ${title} Docs`}>
<ProductArticlesList />
</LandingSection>
</DefaultLayout>
)
}
const TocProductLanding = () => {
const { title, introPlainText, tocItems } = useProductLandingContext()
return (
<DefaultLayout>
<Grid
className="container-xl px-3 px-md-6 my-4 my-lg-4 container-xl "
gridTemplateColumns="minmax(500px, 720px) minmax(220px, 1fr)"
gridTemplateRows="auto 1fr"
gridGap={16}
>
<div>
<h1 className="my-4">{title}</h1>
<div className="lead-mktg">
<p>{introPlainText}</p>
</div>
<div className="mt-7">
<TableOfContents items={tocItems} />
</div>
</div>
<div>
<ArticleVersionPicker />
</div>
</Grid>
</DefaultLayout>
)
}
export default ProductPage
export const getServerSideProps: GetServerSideProps<Props> = async (context) => { export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
const req = context.req as any const req = context.req as any
@@ -129,6 +64,7 @@ export const getServerSideProps: GetServerSideProps<Props> = async (context) =>
props: { props: {
mainContext: getMainContextFromRequest(req), mainContext: getMainContextFromRequest(req),
productLandingContext: getProductLandingContextFromRequest(req), productLandingContext: getProductLandingContextFromRequest(req),
tocLandingContext: getTocLandingContextFromRequest(req),
}, },
} }
} }

View File

@@ -5,7 +5,7 @@ import Head from 'next/head'
import { useTheme, ThemeProvider } from '@primer/components' import { useTheme, ThemeProvider } from '@primer/components'
import { getThemeProps } from 'components/lib/getThemeProps' import { getThemeProps } from 'components/lib/getThemeProps'
import '@primer/css/index.scss' import '../stylesheets/index.scss'
import { defaultThemeProps } from 'components/lib/getThemeProps' import { defaultThemeProps } from 'components/lib/getThemeProps'

View File

@@ -39,3 +39,4 @@ $marketing-font-path: "/dist/fonts/";
@import "tables.scss"; @import "tables.scss";
@import "toggle-images-button.scss"; @import "toggle-images-button.scss";
@import "underline-dashed.scss"; @import "underline-dashed.scss";
@import "utilities.scss";

View File

@@ -1,6 +1,10 @@
/* Numbered procedures (step 1, step 2, ...) /* Numbered procedures (step 1, step 2, ...)
------------------------------------------------------------------------------*/ ------------------------------------------------------------------------------*/
.list-style-inside {
list-style: inside;
}
.markdown-body ol { .markdown-body ol {
counter-reset: li; counter-reset: li;
list-style: none; list-style: none;

View File

@@ -1,6 +1,12 @@
.opacity-0 {
opacity: 0;
}
.opacity-60 { .opacity-60 {
opacity: 0.6; opacity: 0.6;
} }
.opacity-70 { .opacity-70 {
opacity: 0.7; opacity: 0.7;
} }
.opacity-100 {
opacity: 1;
}

View File

@@ -0,0 +1,7 @@
.transition-200 {
transition: 200ms
}
.rotate-180 {
transform: rotateX(180deg)
}

View File

@@ -314,13 +314,13 @@ describe('nextjs query param', () => {
it('conditionally renders through nextjs pipeline depending on FEATURE_NEXTJS value', async () => { it('conditionally renders through nextjs pipeline depending on FEATURE_NEXTJS value', async () => {
const flagVal = require('../../feature-flags.json').FEATURE_NEXTJS const flagVal = require('../../feature-flags.json').FEATURE_NEXTJS
await page.goto('http://localhost:4001/en/sponsors?nextjs=') await page.goto('http://localhost:4001/en/actions?nextjs=')
const nextWrapper = await page.$('#__next') const nextWrapper = await page.$('#__next')
flagVal === true ? expect(nextWrapper).toBeDefined() : expect(nextWrapper).toBeNull() flagVal === true ? expect(nextWrapper).toBeDefined() : expect(nextWrapper).toBeNull()
}) })
it('does not render through nextjs pipeline when nextjs query param is missing', async () => { it('does not render through nextjs pipeline when nextjs query param is missing', async () => {
await page.goto('http://localhost:4001/en/sponsors') await page.goto('http://localhost:4001/en/actions')
const nextWrapper = await page.$('#__next') const nextWrapper = await page.$('#__next')
expect(nextWrapper).toBeNull() expect(nextWrapper).toBeNull()
}) })