Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
c7ca56f
Stop caching truncated AI search answers from failed streams (#63975)
heiskr Oct 19, 2026
69e45b0
Render carousel titles and intros from raw frontmatter (#63978)
heiskr Oct 19, 2026
eeaed17
Fix combined search 400 errors for non-English languages (#63980)
heiskr Oct 19, 2026
df5b6eb
Start Copy as Markdown clipboard write inside the click for Safari (#…
heiskr Oct 19, 2026
f060edc
Validate the Copilot model supported plans table against its schema (…
heiskr Oct 19, 2026
804ea01
Keep old directories with unmoved files in move-by-content-type (#63985)
heiskr Oct 19, 2026
29c6101
Show variants for nested array items that use oneOf, anyOf, or allOf …
heiskr Oct 19, 2026
13fc282
Handle nullable item types in array body params (#63988)
heiskr Oct 19, 2026
abb042e
Scan frontmatter, tables, and early access for orphaned features (#63…
heiskr Oct 19, 2026
8662400
Reset page and category filter when starting a new search (#63992)
heiskr Oct 19, 2026
b9d63a8
Scope Portuguese 2FA intro endif fix to its own page (#63994)
heiskr Oct 19, 2026
e6f4db8
Quote GitHub CLI REST paths that include query params (#63995)
heiskr Oct 19, 2026
daf5e61
Ignore :// in query strings when detecting external redirects (#63996)
heiskr Oct 19, 2026
116b2ae
Keep hand-edited release note fields when rerunning the generator (#6…
heiskr Oct 19, 2026
f6d337d
Save edits in nested expanded blocks when running liquid-tags restore…
heiskr Oct 19, 2026
42404db
Render REST code examples when request and response keys differ (#63999)
heiskr Oct 19, 2026
56d7bf4
Fix Dependabot reviewer workflow paths for moved docs (#64001)
heiskr Oct 19, 2026
6ff8884
Escape Liquid syntax in synced Copilot SDK docs (#64002)
heiskr Oct 19, 2026
d6ec933
Use page URL as Elasticsearch _id so bulk retries don't duplicate pag…
heiskr Oct 19, 2026
a815abf
Ignore input method composition keys in the search overlay (#64004)
heiskr Oct 19, 2026
e039282
Show check and cross marks in secret scanning markdown tables (#64005)
heiskr Oct 19, 2026
f33fc36
Keep the current docs version in sidebar landing and product links (#…
heiskr Oct 19, 2026
f9a4fe0
Let audit log sync reruns recover after a failed PR step (#64010)
heiskr Oct 19, 2026
3a326c0
Fall back to English when translated frontmatter values have wrong ty…
heiskr Oct 19, 2026
37fc2d4
Keep empty table cells in translated pages (#64012)
heiskr Oct 19, 2026
17413ce
Fall back to English when translated ui.yml is corrupt or missing (#6…
heiskr Oct 19, 2026
f77bbdf
Keep search terms when redirecting q= on Enterprise version pages (#6…
heiskr Oct 19, 2026
e5a46ac
Remove stale webhook data files when categories leave the schema (#64…
heiskr Oct 19, 2026
bcd0d64
Add translation corrections for ru octicon and ko data tags (#64269)
docs-bot Oct 19, 2026
ccf443f
Render every webhook action in the Markdown webhook events page (#64018)
heiskr Oct 19, 2026
d5612ab
Keep audit log reference links on the reader's version (#64021)
heiskr Oct 19, 2026
80badfd
Add page surrogate keys to Article API responses (#64022)
heiskr Oct 19, 2026
18653b2
Add markers so deleted asset and feature comments update in place (#6…
heiskr Oct 19, 2026
64246d6
Add patches to the node_modules cache key in CI (#64026)
heiskr Oct 19, 2026
b619fe1
Lint every RAI card in tests when the card template changes (#64027)
heiskr Oct 19, 2026
acbe479
Await YAML fence checks in the scheduled jobs lint rule (#64020)
heiskr Oct 19, 2026
78e9109
Queue overlapping Repo Sync runs instead of closing their pull reques…
heiskr Oct 19, 2026
946903d
Point About versions links at the current article path (#64029)
heiskr Oct 19, 2026
91cbd42
Stop action pinning lint crashes and check bare step lists (#64030)
heiskr Oct 19, 2026
80d0531
Stop add-content-type from overwriting curated contentType values (#6…
heiskr Oct 19, 2026
b74371a
Stop localStorage errors from breaking Ask AI results (#64032)
heiskr Oct 19, 2026
0653180
Await Liquid renders in the image alt text length rule (#64033)
heiskr Oct 19, 2026
9d854cf
Await signal validators in the analyze-comment scripts (#64034)
heiskr Oct 19, 2026
d589b2b
Use real index names in the analyze-text script (#64035)
heiskr Oct 19, 2026
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
3 changes: 2 additions & 1 deletion .github/actions/node-npm-setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ runs:
SEGMENT_DOWNLOAD_TIMEOUT_MINS: '1'
with:
path: node_modules
key: ${{ runner.os }}-node_modules-${{ hashFiles('package*.json') }}-${{ hashFiles('.github/actions/node-npm-setup/action.yml') }}
# The postinstall script applies patches/ during npm ci, so patch changes must miss the cache.
key: ${{ runner.os }}-node_modules-${{ hashFiles('package*.json', 'patches/**') }}-${{ hashFiles('.github/actions/node-npm-setup/action.yml') }}

# The npm download cache only helps npm ci, so skip its 153 MB restore when node_modules hits.
- name: Setup Node.js
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/orphaned-features-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ on:
- 'package*.json'
- 'src/data-directory/scripts/find-orphaned-features/**'
- .github/actions/clone-translations/action.yml
- .github/actions/get-docs-early-access/action.yml
- .github/actions/node-npm-setup/action.yml

permissions:
Expand All @@ -38,6 +39,11 @@ jobs:

- uses: ./.github/actions/node-npm-setup

# Early access docs use data/features too, so include them before deciding that a feature is unused.
- uses: ./.github/actions/get-docs-early-access
with:
token: ${{ secrets.DOCS_BOT_PAT_BASE }}

- name: Check for orphaned features
env:
# The gh CLI reads GITHUB_TOKEN.
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/repo-sync.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ permissions:
contents: write
pull-requests: write

# Queue overlapping runs. A second run closes every open repo-sync pull request, including one
# the first run is still waiting to merge. Cancelling mid-merge would leave that pull request open.
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false

jobs:
repo-sync:
if: github.repository == 'github/docs-internal' || github.repository == 'github/docs'
Expand Down
28 changes: 26 additions & 2 deletions .github/workflows/reviewers-dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,32 @@ on:
- reopened
- synchronize
paths:
- 'data/reusable/dependabot/**'
- 'content/code-security/dependabot/**'
- 'data/reusables/dependabot/**'
- 'data/reusables/**/*dependabot*'
- 'content/code-security/**/*dependabot*'
- 'content/code-security/**/*dependabot*/**'
# Dependabot articles whose paths do not contain "dependabot"
- 'content/code-security/concepts/supply-chain-security/malware-alerts.md'
- 'content/code-security/concepts/supply-chain-security/multi-ecosystem-updates.md'
- 'content/code-security/how-tos/secure-at-scale/configure-enterprise-security/configure-specific-tools/configure-limited-internet-access.md'
- 'content/code-security/how-tos/secure-your-supply-chain/manage-your-dependency-security/configure-access-to-private-registries.md'
- 'content/code-security/how-tos/secure-your-supply-chain/manage-your-dependency-security/configure-on-github-hosted-runners.md'
- 'content/code-security/how-tos/secure-your-supply-chain/manage-your-dependency-security/configure-on-self-hosted-runners.md'
- 'content/code-security/how-tos/secure-your-supply-chain/manage-your-dependency-security/configure-private-registries.md'
- 'content/code-security/how-tos/secure-your-supply-chain/manage-your-dependency-security/controlling-dependencies-updated.md'
- 'content/code-security/how-tos/secure-your-supply-chain/manage-your-dependency-security/list-configured-dependencies.md'
- 'content/code-security/how-tos/secure-your-supply-chain/manage-your-dependency-security/prioritize-with-preset-rules.md'
- 'content/code-security/how-tos/secure-your-supply-chain/manage-your-dependency-security/remove-access-to-public-registries.md'
- 'content/code-security/how-tos/secure-your-supply-chain/manage-your-dependency-security/resolve-a-blocked-host.md'
- 'content/code-security/how-tos/secure-your-supply-chain/secure-your-dependencies/auto-update-actions.md'
- 'content/code-security/how-tos/secure-your-supply-chain/secure-your-dependencies/configure-malware-alerts.md'
- 'content/code-security/how-tos/secure-your-supply-chain/secure-your-dependencies/configure-security-updates.md'
- 'content/code-security/how-tos/secure-your-supply-chain/secure-your-dependencies/configure-version-updates.md'
- 'content/code-security/how-tos/secure-your-supply-chain/secure-your-dependencies/configuring-multi-ecosystem-updates.md'
- 'content/code-security/reference/supply-chain-security/criteria-for-preset-rules.md'
- 'content/code-security/reference/supply-chain-security/supported-ecosystems-and-manifests-for-dependency-scope.md'
- 'content/code-security/reference/supply-chain-security/supported-ecosystems-and-repositories.md'
- 'content/code-security/tutorials/secure-your-dependencies/optimizing-pr-creation-version-updates.md'
- 'content/rest/dependabot/**'
- '.github/workflows/reviewers-dependabot.yml'

Expand Down
102 changes: 61 additions & 41 deletions .github/workflows/sync-audit-logs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,61 +47,81 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }}
run: |
echo "Creating a new branch if needed..."
branchname=audit-logs-schema-update-${{ steps.audit-log-allowlists.outputs.COMMIT_SHA }}
remotesha=$(git ls-remote --heads origin $branchname)
if [ -n "$remotesha" ]; then
echo "Branch $branchname already exists in 'github/docs-internal'. Exiting..."
exit 0
fi
git checkout -b $branchname
echo "Created a new branch $branchname"

echo "Preparing commit..."
git config --global user.name "docs-bot"
git config --global user.email "77750099+docs-bot@users.noreply.github.com"
git add -A .
echo "Prepared commit"

echo "Check if there are changes..."
if git diff-index --cached --quiet HEAD -- . ':(exclude)src/audit-logs/lib/config.json'
then
echo "No real changes (only the SHA in config.json moved). Exiting…"

# People close sync PRs that fail to deploy or merge, so do not reopen this SHA after a close.
# Reuse an open PR from an earlier run so a rerun does not restart its CI.
# --head matches fork branches too, so only trust same-repo PRs that docs-bot opened.
existing_pr=$(gh pr list --repo github/docs-internal --head "$branchname" --state all --json number,state,author,isCrossRepository \
--jq 'map(select(.author.login == "docs-bot" and (.isCrossRepository | not))) | .[0] | select(.) | "\(.number) \(.state)"')
if [ -n "$existing_pr" ] && [ "${existing_pr#* }" != "OPEN" ]; then
echo "Pull request #${existing_pr% *} for branch $branchname is ${existing_pr#* }. Exiting..."
exit 0
elif [ -n "$existing_pr" ]; then
pr=${existing_pr% *}
echo "Pull request #$pr already exists for branch $branchname. Checking that it holds only the regenerated data..."
# Others can push to the branch, so approve only if it matches this run's output.
git add -A .
git fetch --depth=1 origin "$branchname"
pr_files=$(gh api --paginate "repos/github/docs-internal/pulls/$pr/files" --jq '.[].filename')
unexpected_files=$(echo "$pr_files" | grep -v -e '^src/audit-logs/data/' -e '^src/audit-logs/lib/config\.json$' || true)
if [ -n "$unexpected_files" ] || ! git diff --cached --quiet FETCH_HEAD -- src/audit-logs/data src/audit-logs/lib/config.json; then
echo "Pull request #$pr does not match the regenerated audit log data. Fix or close it by hand."
echo "Unexpected files: ${unexpected_files:-none}"
exit 1
fi
echo "Pull request #$pr matches the regenerated data. Skipping to approval."
else
git checkout -b $branchname
echo "Created a new branch $branchname"

echo "Preparing commit..."
git config --global user.name "docs-bot"
git config --global user.email "77750099+docs-bot@users.noreply.github.com"
git add -A .
echo "Prepared commit"

echo "Check if there are changes..."
if git diff-index --cached --quiet HEAD -- . ':(exclude)src/audit-logs/lib/config.json'
then
echo "No real changes (only the SHA in config.json moved). Exiting…"
exit 0
fi
echo "Changes detected, proceeding"

echo "Creating commit..."
git commit -m "Add updated audit log event data"
echo "Created commit"

# Force-push reruns over failed attempts; this workflow exclusively owns these branches.
echo "Pushing commit..."
git push --force -u origin $branchname
echo "Pushed commit"

echo "Creating pull request..."
pr=$(gh pr create \
--title "Update audit log event data" \
--body '👋 Docs First Responder. This PR updates the audit log event data with the latest changes, synced from github/audit-log-allowlists.
Make sure the PR builds successfully and there are no gross errors (for example, a file is deleted). You do not need to validate the contents (that is the responsibility of product teams).
If CI does not pass or other problems arise, contact #technical-content on slack.' \
--repo github/docs-internal \
--label audit-log-pipeline,workflow-generated \
--head=$branchname)
echo "Created pull request $pr"
fi
echo "Changes detected, proceeding"

echo "Creating commit..."
git commit -m "Add updated audit log event data"
echo "Created commit"

echo "Pushing commit..."
git push origin $branchname
echo "Pushed commit"

echo "Creating pull request..."
gh pr create \
--title "Update audit log event data" \
--body '👋 Docs First Responder. This PR updates the audit log event data with the latest changes, synced from github/audit-log-allowlists.
Make sure the PR builds successfully and there are no gross errors (for example, a file is deleted). You do not need to validate the contents (that is the responsibility of product teams).
If CI does not pass or other problems arise, contact #technical-content on slack.' \
--repo github/docs-internal \
--label audit-log-pipeline,workflow-generated \
--head=$branchname
echo "Created pull request"

# docs-bot cannot approve its own PR, so GITHUB_TOKEN approves it.
echo "Approving pull request..."
unset GITHUB_TOKEN
gh auth login --with-token <<< "${{ secrets.GITHUB_TOKEN }}"
gh pr review --approve
gh pr review "$pr" --approve
echo "Approved pull request"

# GITHUB_TOKEN cannot enable auto-merge here, so docs-bot enables it.
echo "Setting pull request to auto merge..."
unset GITHUB_TOKEN
gh auth login --with-token <<< "${{ secrets.DOCS_BOT_PAT_BASE }}"
gh pr merge --auto
gh pr merge "$pr" --auto
echo "Set pull request to auto merge"

- uses: ./.github/actions/create-workflow-failure-issue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ jobs:
```yaml
{% data reusables.actions.actions-not-certified-by-github-comment %}
- name: Sign in to Artifactory Docker registry
uses: docker/login-action@v3
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
registry: {% raw %}${{ env.JF_URL }}{% endraw %}
username: {% raw %}${{ steps.setup-jfrog-cli.outputs.oidc-user }}{% endraw %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
- uses: {% data reusables.actions.action-checkout %}
- run: your-application
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: {% raw %}${{ secrets.GITHUB_TOKEN }}{% endraw %}
```
The organization's **Allow use of Copilot CLI billed to the organization** policy must be enabled. This approach needs no GitHub App or stored authentication secret. For details, see [AUTOTITLE](/copilot/how-tos/copilot-cli/use-copilot-cli-in-actions).
Expand Down
2 changes: 1 addition & 1 deletion data/ui.yml
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ rest:
banner:
api_versioned: The REST API is now versioned.
api_version_info: For more information, see "<a href="{{ versionWithApiVersion }}/rest/overview/api-versions">About API versioning</a>."
ghes_api_versioned: After a site administrator upgrades your Enterprise Server instance to {{ firstGhesReleaseWithApiVersions.versionTitle }} or later, the REST API will be versioned. To learn how to find your instance's version, see "<a href="/{{ currentVersion }}/get-started/learning-about-github/about-versions-of-github-docs#github-enterprise-server">About versions of GitHub Docs</a>".
ghes_api_versioned: After a site administrator upgrades your Enterprise Server instance to {{ firstGhesReleaseWithApiVersions.versionTitle }} or later, the REST API will be versioned. To learn how to find your instance's version, see "<a href="/{{ currentVersion }}/get-started/using-github-docs/about-versions-of-github-docs#github-enterprise-server">About versions of GitHub Docs</a>".
redirect_notice: We've recently moved some of the REST API documentation.
redirect_repo: If you can't find what you're looking for, you might try the new {{ newRestPagesLinks }} REST API pages.
redirect_enterprise: If you can't find what you're looking for, you might try the {{ actionsPageLink }} REST API page.
Expand Down
16 changes: 16 additions & 0 deletions src/article-api/lib/summarize-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,22 @@ function renderProperties(

if (propType === 'array' && prop.items) {
const itemTitle = prop.items.title
const itemKey = (['oneOf', 'anyOf', 'allOf'] as const).find((k) => prop.items![k])
if (itemKey) {
const label = `${itemTitle ? `array of \`${itemTitle}\`` : 'array of items'}${isNullable ? ' or null' : ''}`
if (shouldReference(itemTitle, depth < MAX_DEPTH, seen)) {
lines.push(`${prefix}* \`${name}\`: ${reqStr}${label} (see above)`)
} else {
lines.push(`${prefix}* \`${name}\`: ${reqStr}${label}:`)
if (prop.items.properties && depth < MAX_DEPTH) {
lines.push(renderProperties(prop.items, indent + 1, depth + 1, seen))
}
lines.push(
renderCompositionVariants(itemKey, prop.items[itemKey]!, indent + 1, depth, seen),
)
}
continue
}
const canExpand = Boolean(prop.items.properties) && depth < MAX_DEPTH
if (shouldReference(itemTitle, canExpand, seen)) {
lines.push(
Expand Down
23 changes: 14 additions & 9 deletions src/article-api/middleware/article.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
import { getArticleBody } from './article-body'
import { getMetadata } from './article-pageinfo'
import {
makeLanguageSurrogateKey,
makeContentSurrogateKeys,
setFastlySurrogateKey,
} from '@/frame/middleware/set-fastly-surrogate-key'
import statsd from '@/observability/lib/statsd'
Expand Down Expand Up @@ -60,6 +60,7 @@ router.get(
recordBodySize(req, bodyContent)

defaultCacheControl(res)
setArticleSurrogateKeys(req, res)
return res.json({
meta,
body: bodyContent,
Expand Down Expand Up @@ -102,12 +103,11 @@ router.get(
recordBodySize(req, bodyContent)

defaultCacheControl(res)
setArticleSurrogateKeys(req, res)
return res.type('text/markdown').send(bodyContent)
}),
)

// /api/article/meta sets a language surrogate key because /api URLs lack a language segment.
// Fastly needs the key for staggered language purges.
/**
* Get metadata about an article.
* @route GET /api/article/meta
Expand Down Expand Up @@ -147,16 +147,21 @@ router.get(

incrementArticleLookup(req, 'meta')
defaultCacheControl(res)

setFastlySurrogateKey(
res,
makeLanguageSurrogateKey(req.pageinfo?.page?.languageCode || 'en'),
true,
)
setArticleSurrogateKeys(req, res)
return res.json(meta)
}),
)

// /api URLs lack a language segment, so every Article API route sets language and page keys.
// The page key matches the key that deploy purges build from changed content files.
function setArticleSurrogateKeys(req: ExtendedRequestWithPageInfo, res: Response) {
const keys = makeContentSurrogateKeys({
langCode: req.pageinfo.page?.languageCode || 'en',
relativePath: req.pageinfo.page?.relativePath,
})
setFastlySurrogateKey(res, keys.join(' '), true)
}

// Keep Datadog metric tags consistent across Article API endpoints.
// Datadog tags max at 200 characters, so path and source tags are truncated.
// See https://docs.datadoghq.com/getting_started/tagging/#define-tags
Expand Down
16 changes: 11 additions & 5 deletions src/article-api/templates/webhooks-page.template.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,23 @@ Events below list only their additional parameters beyond these common ones.
**Action type:** {% for actionType in webhook.actionTypes %}`{{ actionType }}`{% unless forloop.last %}, {% endunless %}{% endfor %}

{% endif %}
{% if webhook.description %}
{{ webhook.description }}
{% for action in webhook.actions %}
{% if webhook.actions.size > 1 %}
#### `{{ action.name }}`

{% endif %}
{% if webhook.bodyParameters.size > 0 %}
#### Webhook payload object parameters
{% if action.description %}
{{ action.description }}

{% endif %}
{% if action.bodyParameters.size > 0 %}
{% if webhook.actions.size > 1 %}#####{% else %}####{% endif %} Webhook payload object parameters

| Name | Type | Description |
|------|------|-------------|
{% for param in webhook.bodyParameters %}| `{{ param.name }}` | `{{ param.type }}` | {% if param.isRequired %}**Required.** {% endif %}{{ param.description }} |
{% for param in action.bodyParameters %}| `{{ param.name }}` | `{{ param.type }}` | {% if param.isRequired %}**Required.** {% endif %}{{ param.description }} |
{% endfor %}

{% endif %}
{% endfor %}
{% endfor %}
8 changes: 8 additions & 0 deletions src/article-api/tests/article-body.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ describe('article body api', () => {
expect(res.headers['content-type']).toContain('text/markdown')
})

test('sets the page surrogate key that deploy purges use', async () => {
const res = await get(makeURL('/en/get-started/start-your-journey/hello-world'))
expect(res.statusCode).toBe(200)
const keys = res.headers['surrogate-key'].split(/\s/g)
expect(keys).toContain('language:en')
expect(keys).toContain('language:en,path:get-started/start-your-journey/hello-world.md')
})

test('body includes title and intro', async () => {
const res = await get(makeURL('/en/get-started/start-your-journey/hello-world'))
expect(res.statusCode).toBe(200)
Expand Down
Loading
Loading