Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
47ccf2d
Hard-purge and batch manual Fastly purges, and run purge_all twice (#…
heiskr Oct 8, 2026
3a9f552
Drop Elasticsearch image cache and pull from docker.elastic.co (#63744)
heiskr Oct 8, 2026
c3b4dde
Cache parsed archived redirects JSON and split developer-site-redirec…
heiskr Oct 8, 2026
76d019e
Restore the npm cache only when node_modules misses (#63752)
heiskr Oct 8, 2026
d6282f5
Add 7-day min-release-age to .npmrc (#63737)
heiskr Oct 8, 2026
585c2bc
Narrow cache-nextjs key globs to skip node_modules and translations (…
heiskr Oct 8, 2026
fbc3214
Block Microsoft package feed URLs in package-lock.json and .npmrc (#6…
heiskr Oct 8, 2026
623e27c
Clone translation repos in parallel (#63748)
heiskr Oct 8, 2026
18482ab
Keep dev page rereads inside the content root (#63684)
heiskr Oct 8, 2026
df701b8
Honor START_VITEST_SERVER=false in vitest global setup (#63747)
heiskr Oct 8, 2026
9553539
Bump github/gh-base-image/gh-base-noble from 20260914-014148-gb620b63…
dependabot[bot] Oct 8, 2026
c129a69
Clarify Copilot restoration after failed renewal and cancellation (#6…
Copilot Oct 8, 2026
2066232
Start Elasticsearch in the background in test.yml (#63750)
heiskr Oct 8, 2026
7c7a9d3
Bump next from 16.3.6 to 16.3.8 in the npm_and_yarn group across 1 di…
dependabot[bot] Oct 8, 2026
55b5b0d
Sync secret scanning data (#63765)
docs-bot Oct 8, 2026
bd52de7
GraphQL schema update (#63768)
docs-bot Oct 8, 2026
62ea212
[2026-10-01] CCR - Direct Org Billing for users with Copilot licenses…
jclement136 Oct 8, 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
5 changes: 3 additions & 2 deletions .github/actions/cache-nextjs/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ runs:
with:
path: ${{ github.workspace }}/.next/cache
# Packages and source files both invalidate the cache.
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.ts', '**/*.tsx') }}
# Use narrow globs: `**` walks node_modules and translations and takes about 35s per hash.
key: ${{ runner.os }}-nextjs-${{ hashFiles('package-lock.json') }}-${{ hashFiles('src/**/*.ts', 'src/**/*.tsx', '*.ts') }}
# With matching restore-key prefixes, source-only changes restore the same-package cache.
restore-keys: |
${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-
${{ runner.os }}-nextjs-${{ hashFiles('package-lock.json') }}-
93 changes: 38 additions & 55 deletions .github/actions/clone-translations/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,58 +10,41 @@ inputs:
runs:
using: 'composite'
steps:
- name: Clone Spanish
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
repository: github/docs-internal.es-es
token: ${{ inputs.token }}
path: translations/es-es

- name: Clone Japanese
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
repository: github/docs-internal.ja-jp
token: ${{ inputs.token }}
path: translations/ja-jp

- name: Clone Portuguese
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
repository: github/docs-internal.pt-br
token: ${{ inputs.token }}
path: translations/pt-br

- name: Clone Simplified Chinese
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
repository: github/docs-internal.zh-cn
token: ${{ inputs.token }}
path: translations/zh-cn

- name: Clone Russian
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
repository: github/docs-internal.ru-ru
token: ${{ inputs.token }}
path: translations/ru-ru

- name: Clone French
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
repository: github/docs-internal.fr-fr
token: ${{ inputs.token }}
path: translations/fr-fr

- name: Clone Korean
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
repository: github/docs-internal.ko-kr
token: ${{ inputs.token }}
path: translations/ko-kr

- name: Clone German
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
repository: github/docs-internal.de-de
token: ${{ inputs.token }}
path: translations/de-de
# Clone in parallel; sequential actions/checkout steps took about 30s.
- name: Clone all translations
shell: bash
working-directory: ${{ github.workspace }}
env:
TOKEN: ${{ inputs.token }}
run: |
auth=$(printf 'x-access-token:%s' "$TOKEN" | base64 | tr -d '\n')
echo "::add-mask::$auth"
# Pass auth through the environment so the token stays out of process
# arguments and out of the clones' git config.
export GIT_CONFIG_COUNT=1
export GIT_CONFIG_KEY_0=http.https://github.com/.extraheader
export GIT_CONFIG_VALUE_0="AUTHORIZATION: basic $auth"

clone() {
local lang=$1
for attempt in 1 2 3; do
rm -rf "translations/$lang"
git clone --quiet --depth 1 "https://github.com/github/docs-internal.$lang.git" "translations/$lang" \
&& return 0
echo "Clone of $lang failed on attempt $attempt"
sleep $((attempt * 5))
done
return 1
}

pids=()
for lang in es-es ja-jp pt-br zh-cn ru-ru fr-fr ko-kr de-de; do
clone "$lang" &
pids+=($!)
done

status=0
for pid in "${pids[@]}"; do
wait "$pid" || status=1
done
exit $status
4 changes: 3 additions & 1 deletion .github/actions/node-npm-setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ runs:
path: node_modules
key: ${{ runner.os }}-node_modules-${{ hashFiles('package*.json') }}-${{ 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
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version-file: 'package.json'
cache: npm
package-manager-cache: false
cache: ${{ steps.cache-node_modules.outputs.cache-hit != 'true' && 'npm' || '' }}

- name: Install dependencies
if: ${{ steps.cache-node_modules.outputs.cache-hit != 'true' }}
Expand Down
95 changes: 31 additions & 64 deletions .github/actions/setup-elasticsearch/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,82 +10,49 @@ inputs:
elasticsearch_version:
description: Version of Elasticsearch to install
required: true
# Version must match production and be published on Docker Hub.
# Version must match production and be published on docker.elastic.co.
default: '8.12.0'
mode:
description: >-
'both' starts Elasticsearch and waits until it is ready.
'start' starts it in the background and returns right away.
'wait' waits for a background start from an earlier 'start' step, then for readiness.
required: false
default: 'both'

runs:
using: 'composite'
steps:
# Cache the Elasticsearch image to prevent Docker Hub rate limits.
- name: Cache Docker layers
id: cache-docker-layers
uses: actions/cache@v4
with:
path: /tmp/docker-cache
key: ${{ runner.os }}-elasticsearch-${{ inputs.elasticsearch_version }}
restore-keys: |
${{ runner.os }}-elasticsearch-

- name: Load cached Docker image
shell: bash
if: steps.cache-docker-layers.outputs.cache-hit == 'true'
run: docker load -i /tmp/docker-cache/elasticsearch.tar || echo "No cache found for elasticsearch, pulling image"

- name: Pull Docker image
- name: Start Elasticsearch
if: ${{ inputs.mode == 'both' }}
shell: bash
if: steps.cache-docker-layers.outputs.cache-hit != 'true'
env:
ES_VERSION: ${{ inputs.elasticsearch_version }}
run: docker pull elasticsearch:${ES_VERSION}
run: bash "$GITHUB_ACTION_PATH/start.sh"

- name: Save Docker image to cache
# Later steps such as npm ci and the build run while the image pulls and Elasticsearch boots.
- name: Start Elasticsearch in the background
if: ${{ inputs.mode == 'start' }}
shell: bash
if: steps.cache-docker-layers.outputs.cache-hit != 'true'
env:
ES_VERSION: ${{ inputs.elasticsearch_version }}
ES_STATUS_FILE: ${{ runner.temp }}/elasticsearch-start.status
ES_LOG_FILE: ${{ runner.temp }}/elasticsearch-start.log
run: |
mkdir -p /tmp/docker-cache
docker save -o /tmp/docker-cache/elasticsearch.tar elasticsearch:${ES_VERSION}

# Run a single-node container with settings copied from getong/elasticsearch-action.
- name: Run Docker container
rm -f "$ES_STATUS_FILE"
(
status=0
bash "$GITHUB_ACTION_PATH/start.sh" || status=$?
echo "$status" > "$ES_STATUS_FILE.tmp"
mv "$ES_STATUS_FILE.tmp" "$ES_STATUS_FILE"
) > "$ES_LOG_FILE" 2>&1 < /dev/null &
echo "Starting Elasticsearch in the background. A mode: wait step prints the log."

- name: Wait for Elasticsearch
if: ${{ inputs.mode != 'start' }}
shell: bash
env:
INPUT_ELASTICSEARCH_VERSION: ${{ inputs.elasticsearch_version }}
INPUT_HOST_PORT: 9200
INPUT_CONTAINER_PORT: 9200
INPUT_HOST_NODE_PORT: 9300
INPUT_NODE_PORT: 9300
INPUT_DISCOVERY_TYPE: 'single-node'
run: |
docker network create elastic

docker run --network elastic \
-e 'node.name=es1' \
-e 'cluster.name=docker-elasticsearch' \
-e 'cluster.initial_master_nodes=es1' \
-e 'discovery.seed_hosts=es1' \
-e 'cluster.routing.allocation.disk.threshold_enabled=false' \
-e 'bootstrap.memory_lock=true' \
-e 'ES_JAVA_OPTS=-Xms1g -Xmx1g' \
-e 'xpack.security.enabled=false' \
-e 'xpack.license.self_generated.type=basic' \
--ulimit nofile=65536:65536 \
--ulimit memlock=-1:-1 \
--name='es1' \
-d \
-p $INPUT_HOST_PORT:$INPUT_CONTAINER_PORT \
-p $INPUT_HOST_NODE_PORT:$INPUT_NODE_PORT \
-e discovery_type=$INPUT_DISCOVERY_TYPE \
elasticsearch:$INPUT_ELASTICSEARCH_VERSION

for i in {1..120}; do
if curl --silent --fail http://localhost:9200; then
echo "Elasticsearch is up and running"
exit 0
fi
echo "Waiting for Elasticsearch to be ready..."
sleep 1
done
echo "Elasticsearch did not become ready in time"
exit 1
ES_BACKGROUND: ${{ inputs.mode == 'wait' }}
ES_STATUS_FILE: ${{ runner.temp }}/elasticsearch-start.status
ES_LOG_FILE: ${{ runner.temp }}/elasticsearch-start.log
run: bash "$GITHUB_ACTION_PATH/wait.sh"
45 changes: 45 additions & 0 deletions .github/actions/setup-elasticsearch/start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/bin/bash

# Pull the Elasticsearch image and start the es1 container. wait.sh checks readiness.

set -euo pipefail

image="docker.elastic.co/elasticsearch/elasticsearch:$ES_VERSION"

# Pull from Elastic's registry to avoid Docker Hub rate limits.
# A pull is faster than restoring and loading a cached image tarball.
pulled=false
for attempt in 1 2 3; do
if docker pull "$image"; then
pulled=true
break
fi
echo "Pull attempt $attempt failed"
sleep $((attempt * 10))
done
if [ "$pulled" != true ]; then
echo "Could not pull $image"
exit 1
fi

# Run a single-node container with settings copied from getong/elasticsearch-action.
docker network create elastic

docker run --network elastic \
-e 'node.name=es1' \
-e 'cluster.name=docker-elasticsearch' \
-e 'cluster.initial_master_nodes=es1' \
-e 'discovery.seed_hosts=es1' \
-e 'cluster.routing.allocation.disk.threshold_enabled=false' \
-e 'bootstrap.memory_lock=true' \
-e 'ES_JAVA_OPTS=-Xms1g -Xmx1g' \
-e 'xpack.security.enabled=false' \
-e 'xpack.license.self_generated.type=basic' \
--ulimit nofile=65536:65536 \
--ulimit memlock=-1:-1 \
--name='es1' \
-d \
-p 9200:9200 \
-p 9300:9300 \
-e discovery_type=single-node \
"$image"
38 changes: 38 additions & 0 deletions .github/actions/setup-elasticsearch/wait.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/bin/bash

# Wait until Elasticsearch answers on localhost:9200.
# With ES_BACKGROUND=true, first wait for the background start.sh to finish.

set -euo pipefail

if [ "${ES_BACKGROUND:-false}" = true ]; then
for _ in {1..300}; do
[ -f "$ES_STATUS_FILE" ] && break
sleep 1
done
echo "::group::Background start log"
cat "$ES_LOG_FILE" || true
echo "::endgroup::"
if [ ! -f "$ES_STATUS_FILE" ]; then
echo "::error::Elasticsearch start did not finish in time. Did a mode: start step run first?"
exit 1
fi
status=$(cat "$ES_STATUS_FILE")
if [ "$status" != 0 ]; then
echo "::error::Elasticsearch start failed with exit code $status"
exit 1
fi
fi

for _ in {1..120}; do
if curl --silent --fail http://localhost:9200; then
echo
echo "Elasticsearch is up and running"
exit 0
fi
echo "Waiting for Elasticsearch to be ready..."
sleep 1
done
echo "::error::Elasticsearch did not become ready in time"
docker logs --tail 100 es1 || true
exit 1
2 changes: 1 addition & 1 deletion .github/workflows/index-general-search-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ on:
# Debugging changes to this workflow need the same PR index test.
- .github/workflows/index-general-search-pr.yml
# Setup changes can break the local Elasticsearch path this workflow tests.
- .github/actions/setup-elasticsearch/action.yml
- '.github/actions/setup-elasticsearch/**'

permissions:
contents: read
Expand Down
14 changes: 14 additions & 0 deletions .github/workflows/package-lock-lint.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
name: Package lock lint

# This workflow catches manual package.json edits that leave package-lock.json out of sync.
# It also blocks Microsoft package feed URLs, which break installs outside GitHub.

on:
pull_request:
paths:
- .npmrc
- package.json
- package-lock.json
- .github/workflows/package-lock-lint.yml
Expand All @@ -25,6 +27,18 @@ jobs:
- name: Check out repo
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0

- name: Check for package feed URLs
run: |
status=0
grep -inE 'https?://[^/"]*(pkgs\.visualstudio\.com|pkgs\.dev\.azure\.com|packagefeedproxy\.microsoft\.io)' .npmrc package-lock.json || status=$?
if [ "$status" -eq 0 ]; then
echo "::error::Found Microsoft package feed URLs. Use https://registry.npmjs.org/ instead."
exit 1
elif [ "$status" -ne 1 ]; then
echo "::error::Could not scan .npmrc and package-lock.json for package feed URLs."
exit "$status"
fi
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
Expand Down
Loading
Loading