Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ If you need to use multiple accounts on {% data variables.location.product_locat
* You'll create a password when you create your account on {% data variables.product.github %}. We recommend that you use a password manager to generate a random and unique password. For more information, see [AUTOTITLE](/authentication/keeping-your-account-and-data-secure/creating-a-strong-password).{% ifversion fpt or ghec %}
* If you have not enabled 2FA, {% data variables.product.github %} may ask for additional verification when you first sign in from a new or unrecognized device, such as a new browser profile, a browser where the cookies have been deleted, or a new computer. For more information, see [AUTOTITLE](/authentication/keeping-your-account-and-data-secure/verifying-new-devices-when-signing-in).{% endif %} {% ifversion fpt or ghec %}
* **Social login**
* You'll authenticate with one of the supported social login providers (currently only Google is supported) when you create your account on {% data variables.product.github %}. We recommend that you also configure 2FA and add a passkey or a password as an additional account recovery mechanism.
* You'll authenticate with Google or Apple, which are the supported social login providers when you create your account on {% data variables.product.github %}. We recommend that you also configure 2FA and add a passkey or a password as an additional account recovery mechanism.
* If you have an existing account created with a password, you can add your social login email to the account. This allows you to use your social login identity as a first-factor (password) replacement when you sign in to {% data variables.product.github %}.
* You can unlink your social login identities from your {% data variables.product.github %} email settings page. For more information, see [AUTOTITLE](/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-your-personal-account/unlinking-your-email-address-from-a-locked-account) {% endif %}
* **Two-factor authentication (2FA)** (recommended)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,4 @@ When prompted to authenticate for sudo mode, type your password, then click **Co

Before you can access sudo mode, you must first configure social login. For more information, see [AUTOTITLE](/authentication/keeping-your-account-and-data-secure/about-authentication-to-github).

When prompted to authenticate for sudo mode, type the authentication code sent to your social login email account, then click **Verify**.
When prompted to authenticate for sudo mode, type the authentication code sent to your social login email account, then click **Verify**. If you dont receive the email within few minutes, check your spam folder.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ topics:

To get started with {% data variables.product.prodname_dotcom %}, you'll need to create a free personal account and verify your email address.

You can also authenticate with the supported social login providers (currently only Google is supported) when you create your account on {% data variables.product.prodname_dotcom %}.
You can also authenticate with Google or Apple - which are the supported social login providers when you create your account on {% data variables.product.prodname_dotcom %}.
For iOS users, even if you have enabled the setting "Hide My Email addresses" for your Apple account, using social login will result in creating a new {% data variables.product.github %} account.

{% data reusables.accounts.your-personal-account %}

Expand Down
7 changes: 1 addition & 6 deletions content/get-started/using-github/github-mobile.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,7 @@ You can be simultaneously signed into mobile with multiple accounts on {% data v
> [!NOTE]
> Social login is only available for {% data variables.product.prodname_free_user %} and {% data variables.product.prodname_ghe_cloud %} users

You can sign in to {% data variables.product.prodname_mobile %} using a supported social login provider. Currently, only Google is supported for social login on the {% data variables.product.prodname_mobile %} for Android. To use this option, make sure you originally created your {% data variables.product.github %} account using Google.

For iOS users, social login with Google is not supported in {% data variables.product.prodname_mobile %}. Follow the steps below to sign in to {% data variables.product.prodname_mobile %} on iOS using an account that was created with Google:
1. Open the native web browser Safari and sign in to your {% data variables.product.github %} account.
1. Authorize {% data variables.product.prodname_mobile %} in your browser when prompted.
1. If you are unable to sign in through your browser, you can set a password or passkey for your {% data variables.product.github %} account on {% data variables.product.github %}. After setting a password or passkey, use your username and password with two-factor authentication, or a passkey, to sign in to {% data variables.product.prodname_mobile %}.
You can sign in to {% data variables.product.prodname_mobile %} using a supported social login provider. Currently, both Google and Apple are supported for social login on the {% data variables.product.prodname_mobile %} for Android and iOS users. To use this option, make sure you originally created your {% data variables.product.github %} account using the respective social login provider - Google or Apple.

### Prerequisites for {% data variables.enterprise.data_residency_site %} accounts

Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@
"esm": "^3.2.25"
},
"engines": {
"node": "^20 || ^22 || ^24"
"node": "^22 || ^24"
},
"cacheDirectories": [
"node_modules",
Expand Down
4 changes: 2 additions & 2 deletions src/codeql-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ The pipeline is used to generate Markdown files that create article pages on the

![A flow chart describing how the automation pipeline for CodeQL CLI generates documentation](./codeql-cli-pipeline-flowchart.png)

A [workflow](.github/workflows/sync-codeql-cli.yml) is used to trigger the automation of the CodeQL CLI documentation. The workflow is manually triggered by a member of the GitHub Docs team approximately every two weeks to align to releases of the CodeQL CLI. The workflow takes an input parameter that specifies the branch to pull the source files from in the semmle-code repo. If the branch input is omitted, the workflow will default to the `main` branch.
A [workflow](https://github.com/github/docs-internal/blob/main/.github/workflows/sync-codeql-cli.yml) is used to trigger the automation of the CodeQL CLI documentation. The workflow is manually triggered by a member of the GitHub Docs team approximately every two weeks to align to releases of the CodeQL CLI. The workflow takes an input parameter that specifies the branch to pull the source files from in the semmle-code repo. If the branch input is omitted, the workflow will default to the `main` branch.

The workflow runs the `src/codeql-cli/scripts/sync.js` script, which generates Markdown files under `content/code-security/codeql-cli/codeql-cli-manual`.

Expand Down Expand Up @@ -45,4 +45,4 @@ Writers can also add an introduction paragraph _above_ the following Markdown co
Slack: `#docs-engineering`
Repo: `github/docs-engineering`

If you have a question about the CodeQL CLI pipeline, you can ask in the `#docs-engineering` Slack channel. If you notice a problem with the CodeQL CLI pipeline, you can open an issue in the `github/docs-engineering` repository.
If you have a question about the CodeQL CLI pipeline, you can ask in the `#docs-engineering` Slack channel. If you notice a problem with the CodeQL CLI pipeline, you can open an issue in the `github/docs-engineering` repository.
23 changes: 17 additions & 6 deletions src/content-render/index.js → src/content-render/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
import { renderLiquid } from './liquid/index'
import { renderMarkdown, renderUnified } from './unified/index'
import { engine } from './liquid/engine'
import type { Context } from '@/types'

const globalCache = new Map()
interface RenderOptions {
cache?: boolean | ((template: string, context: Context) => string)
filename?: string
textOnly?: boolean
}

const globalCache = new Map<string, string>()

// parse multiple times because some templates contain more templates. :]
export async function renderContent(template = '', context = {}, options = {}) {
export async function renderContent(
template = '',
context: Context = {} as Context,
options: RenderOptions = {},
): Promise<string> {
// If called with a falsy template, it can't ever become something
// when rendered. We can exit early to save some pointless work.
if (!template) return template
let cacheKey = null
let cacheKey: string | null = null
if (options && options.cache) {
if (!context) throw new Error("If setting 'cache' in options, the 'context' must be set too")
if (typeof options.cache === 'function') {
Expand All @@ -21,13 +32,13 @@ export async function renderContent(template = '', context = {}, options = {}) {
throw new Error('cache option must return a string if truthy')
}
if (globalCache.has(cacheKey)) {
return globalCache.get(cacheKey)
return globalCache.get(cacheKey) as string
}
}
try {
template = await renderLiquid(template, context)
if (context.markdownRequested) {
const md = await renderMarkdown(template, context, options)
const md = await renderMarkdown(template, context)

return md
}
Expand All @@ -45,7 +56,7 @@ export async function renderContent(template = '', context = {}, options = {}) {
}
}

function getDefaultCacheKey(template, context) {
function getDefaultCacheKey(template: string, context: Context): string {
return `${template}:${context.currentVersion}:${context.currentLanguage}`
}

Expand Down
54 changes: 0 additions & 54 deletions src/content-render/liquid/engine.js

This file was deleted.

66 changes: 66 additions & 0 deletions src/content-render/liquid/engine.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { Liquid } from 'liquidjs'
import GithubSlugger from 'github-slugger'
// Copilot: When converting data.js to TypeScript, remove the 'as any' assertion for anyData below
import Data from './data'
import Octicon from './octicon'
// Copilot: When converting ifversion.js to TypeScript, remove the 'as any' assertion for anyIfversion below
import Ifversion from './ifversion'
// Copilot: When converting tool.js to TypeScript, remove the 'as any' assertion for anyTool below
import { Tool, tags as toolTags } from './tool'
import { Spotlight, tags as spotlightTags } from './spotlight'
import { Prompt } from './prompt'
import IndentedDataReference from './indented-data-reference'

// Type assertions for .js files without type definitions
// Copilot: Remove these assertions when the corresponding .js files are converted to TypeScript
const anyData = Data as any
const anyIfversion = Ifversion as any
const anyTool = Tool as any
const anySpotlight = Spotlight as any
const anyPrompt = Prompt as any
const anyIndentedDataReference = IndentedDataReference as any

export const engine = new Liquid({
extname: '.html',
dynamicPartials: false,
})

engine.registerTag('indented_data_reference', anyIndentedDataReference)
engine.registerTag('data', anyData)
engine.registerTag('octicon', Octicon)
engine.registerTag('ifversion', anyIfversion)

for (const tag of toolTags) {
engine.registerTag(tag, anyTool)
}

for (const tag in spotlightTags) {
engine.registerTag(tag, anySpotlight)
}

engine.registerTag('prompt', anyPrompt)

/**
* Like the `size` filter, but specifically for
* getting the number of keys in an object
*/
engine.registerFilter('obj_size', (input: Record<string, unknown> | null | undefined): number => {
if (!input) return 0
return Object.keys(input).length
})

/**
* Returns the version number of a GHES version string
* ex: enterprise-server@2.22 => 2.22
*/
engine.registerFilter('version_num', (input: string): string => {
return input.split('@')[1]
})

/**
* Convert the input to a slug
*/
engine.registerFilter('slugify', (input: string): string => {
const slugger = new GithubSlugger()
return slugger.slug(input)
})
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,21 @@ import assert from 'assert'
import { THROW_ON_EMPTY, IndentedDataReferenceError } from './error-handling'
import { getDataByLanguage } from '@/data-directory/lib/get-data'

// Note: Using 'any' for liquidjs-related types because liquidjs doesn't provide comprehensive TypeScript definitions
interface LiquidTag {
markup: string
liquid: any
parse(tagToken: any): void
render(scope: any): Promise<string | undefined>
}

interface LiquidScope {
environments: {
currentLanguage: string
[key: string]: any
}
}

// This class supports a tag that expects two parameters, a data reference and `spaces=NUMBER`:
//
// {% indented_data_reference foo.bar spaces=NUMBER %}
Expand All @@ -13,12 +28,15 @@ import { getDataByLanguage } from '@/data-directory/lib/get-data'
// reference is used inside a block element (like a list or nested list) without
// affecting the formatting when the reference is used elsewhere via {{ site.data.foo.bar }}.

export default {
parse(tagToken) {
const IndentedDataReference: LiquidTag = {
markup: '',
liquid: null as any,

parse(tagToken: any): void {
this.markup = tagToken.args.trim()
},

async render(scope) {
async render(scope: LiquidScope): Promise<string | undefined> {
// obfuscate first legit space, remove all other spaces, then restore legit space
// this way we can support spaces=NUMBER as well as spaces = NUMBER
const input = this.markup
Expand All @@ -29,12 +47,15 @@ export default {
const [dataReference, spaces] = input.split(' ')

// if no spaces are specified, default to 2
const numSpaces = spaces ? spaces.replace(/spaces=/, '') : '2'
const numSpaces: string = spaces ? spaces.replace(/spaces=/, '') : '2'

assert(parseInt(numSpaces) || numSpaces === '0', '"spaces=NUMBER" must include a number')

// Get the referenced value from the context
const text = getDataByLanguage(dataReference, scope.environments.currentLanguage)
const text: string | undefined = getDataByLanguage(
dataReference,
scope.environments.currentLanguage,
)
if (text === undefined) {
if (scope.environments.currentLanguage === 'en') {
const message = `Can't find the key 'indented_data_reference ${dataReference}' in the scope.`
Expand All @@ -47,8 +68,10 @@ export default {
}

// add spaces to each line
const renderedReferenceWithIndent = text.replace(/^/gm, ' '.repeat(numSpaces))
const renderedReferenceWithIndent: string = text.replace(/^/gm, ' '.repeat(parseInt(numSpaces)))

return this.liquid.parseAndRender(renderedReferenceWithIndent, scope.environments)
},
}

export default IndentedDataReference
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
import { TokenizationError } from 'liquidjs'
// @ts-ignore - @primer/octicons doesn't provide TypeScript declarations
import octicons from '@primer/octicons'

// Note: Using 'any' for liquidjs-related types because liquidjs doesn't provide comprehensive TypeScript definitions
interface LiquidTag {
icon: string
options: Record<string, string>
parse(tagToken: any): void
render(): Promise<string>
}

interface OcticonsMatch {
groups: {
icon: string
options?: string
}
}

const OptionsSyntax = /([a-zA-Z-]+)="([\w\s-]+)"*/g
const Syntax = new RegExp('"(?<icon>[a-zA-Z-]+)"(?<options>(?:\\s' + OptionsSyntax.source + ')*)')
const SyntaxHelp = 'Syntax Error in tag \'octicon\' - Valid syntax: octicon "<name>" <key="value">'
Expand All @@ -12,9 +28,12 @@ const SyntaxHelp = 'Syntax Error in tag \'octicon\' - Valid syntax: octicon "<na
* {% octicon "check" %}
* {% octicon "check" width="64" aria-label="Example label" %}
*/
export default {
parse(tagToken) {
const match = tagToken.args.match(Syntax)
const Octicon: LiquidTag = {
icon: '',
options: {},

parse(tagToken: any): void {
const match: OcticonsMatch | null = tagToken.args.match(Syntax)
if (!match) {
throw new TokenizationError(SyntaxHelp, tagToken)
}
Expand All @@ -32,7 +51,7 @@ export default {

// Memoize any options passed
if (match.groups.options) {
let optionsMatch
let optionsMatch: RegExpExecArray | null

// Loop through each option matching the OptionsSyntax regex
while ((optionsMatch = OptionsSyntax.exec(match.groups.options))) {
Expand All @@ -46,13 +65,15 @@ export default {
}
},

async render() {
async render(): Promise<string> {
// Throw an error if the requested octicon does not exist.
if (!Object.prototype.hasOwnProperty.call(octicons, this.icon)) {
throw new Error(`Octicon ${this.icon} does not exist`)
}

const result = octicons[this.icon].toSVG(this.options)
const result: string = octicons[this.icon].toSVG(this.options)
return result
},
}

export default Octicon
Loading
Loading