Skip to content

Commit 165356b

Browse files
authored
Merge branch 'main' into docs/workflow-dispatch-input-options
2 parents 178fae4 + cb05161 commit 165356b

220 files changed

Lines changed: 4359 additions & 2066 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.devcontainer/Dockerfile‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# Update ARG and FROM together from the Node devcontainer image tags:
22
# https://mcr.microsoft.com/en-us/product/devcontainers/javascript-node/tags
33
ARG VARIANT=dev-24-bookworm
4-
FROM mcr.microsoft.com/devcontainers/javascript-node:dev-24-bookworm@sha256:02207aa539c49a8714bd18ba482a05381a42ee4768ea19a39a4c58f2ae6f7644
4+
FROM mcr.microsoft.com/devcontainers/javascript-node:dev-24-bookworm@sha256:5ed0bf1411cffe8182ee6808477dd64c969a4ce78fee1b63e6a654d7deff889c

‎.github/rulesets/docs-internal/main-branch-protection.json‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,10 @@
196196
"context": "shielding",
197197
"integration_id": 15368
198198
},
199+
{
200+
"context": "tools",
201+
"integration_id": 15368
202+
},
199203
{
200204
"context": "versions",
201205
"integration_id": 15368

‎.github/rulesets/docs/main-branch-protection.json‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,10 @@
173173
"context": "shielding",
174174
"integration_id": 15368
175175
},
176+
{
177+
"context": "tools",
178+
"integration_id": 15368
179+
},
176180
{
177181
"context": "versions",
178182
"integration_id": 15368

‎.github/workflows/auto-close-dependencies.yml‎

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,6 @@ on:
99
- 'Gemfile*'
1010
- 'Dockerfile'
1111
- '.github/workflows/**'
12-
pull_request_review:
13-
types:
14-
- edited
15-
- submitted
1612

1713
permissions:
1814
contents: write

‎.github/workflows/confirm-internal-staff-work-in-docs.yml‎

Lines changed: 95 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ jobs:
7575
github-token: ${{ github.token }}
7676
script: |
7777
const githubLogin = context.payload.sender.login.toLowerCase();
78+
const lookupStartedAt = Date.now();
7879
7980
core.info(`Looking up Slack user for @${githubLogin}...`);
8081
core.setOutput('slack_user_id', '');
@@ -85,59 +86,127 @@ jobs:
8586
throw new Error('SLACK_DOCS_BOT_TOKEN is not configured.');
8687
}
8788
89+
const sleep = (milliseconds) =>
90+
new Promise((resolve) => setTimeout(resolve, milliseconds));
91+
const maxRetries = 5;
92+
const minimumRequestIntervalMs = 3000;
93+
let lastRequestAt = 0;
94+
95+
async function fetchUsersPage(url, pageNumber) {
96+
for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
97+
const spacingDelay = Math.max(
98+
0,
99+
minimumRequestIntervalMs - (Date.now() - lastRequestAt),
100+
);
101+
if (spacingDelay > 0) {
102+
await sleep(spacingDelay);
103+
}
104+
105+
lastRequestAt = Date.now();
106+
const requestStartedAt = lastRequestAt;
107+
const response = await fetch(url, {
108+
headers: {
109+
Authorization: `Bearer ${token}`,
110+
},
111+
});
112+
const requestDurationMs = Date.now() - requestStartedAt;
113+
114+
if (response.status === 429) {
115+
if (attempt === maxRetries) {
116+
throw new Error(
117+
`Slack users.list page ${pageNumber} remained rate-limited after ${maxRetries} retries.`,
118+
);
119+
}
120+
121+
const retryAfterSeconds = Number(response.headers.get('retry-after'));
122+
const retryDelayMs =
123+
Number.isFinite(retryAfterSeconds) && retryAfterSeconds > 0
124+
? retryAfterSeconds * 1000
125+
: Math.min(1000 * 2 ** attempt, 30000);
126+
127+
core.warning(
128+
`Slack users.list page ${pageNumber} was rate-limited (attempt ${attempt + 1}/${maxRetries + 1}); retrying in ${retryDelayMs} ms.`,
129+
);
130+
await sleep(retryDelayMs);
131+
continue;
132+
}
133+
134+
if (!response.ok) {
135+
throw new Error(
136+
`Slack users.list page ${pageNumber} returned HTTP ${response.status} after ${requestDurationMs} ms.`,
137+
);
138+
}
139+
140+
if (attempt > 0) {
141+
core.info(
142+
`Slack users.list page ${pageNumber} succeeded after ${attempt} retry attempt(s) in ${requestDurationMs} ms.`,
143+
);
144+
} else {
145+
core.info(
146+
`Slack users.list page ${pageNumber} returned HTTP ${response.status} in ${requestDurationMs} ms.`,
147+
);
148+
}
149+
150+
return response.json();
151+
}
152+
153+
throw new Error(`Slack users.list page ${pageNumber} request did not complete.`);
154+
}
155+
88156
let cursor = '';
89157
let pages = 0;
90-
const matches = [];
91158
92159
do {
93-
core.info(`Fetching Slack users.list page ${pages + 1}...`);
160+
const pageNumber = pages + 1;
161+
core.info(`Fetching Slack users.list page ${pageNumber}...`);
94162
const url = new URL('https://slack.com/api/users.list');
95163
url.searchParams.set('limit', '200');
96164
if (cursor) {
97165
url.searchParams.set('cursor', cursor);
98166
}
99167
100-
const response = await fetch(url, {
101-
headers: {
102-
Authorization: `Bearer ${token}`,
103-
},
104-
});
105-
106-
if (!response.ok) {
107-
throw new Error(`Slack users.list returned HTTP ${response.status}.`);
108-
}
109-
110-
const result = await response.json();
168+
const result = await fetchUsersPage(url, pageNumber);
111169
if (!result.ok) {
112-
throw new Error(`Slack users.list failed: ${result.error || 'unknown error'}.`);
170+
throw new Error(
171+
`Slack users.list page ${pageNumber} failed: ${result.error || 'unknown error'}.`,
172+
);
113173
}
114174
115175
if (!Array.isArray(result.members)) {
116-
throw new Error('Slack users.list response did not include a members array.');
176+
throw new Error(
177+
`Slack users.list page ${pageNumber} did not include a members array.`,
178+
);
117179
}
118180
119181
pages += 1;
120-
matches.push(...result.members.filter((member) =>
182+
core.info(`Slack users.list page ${pages} contained ${result.members.length} member records.`);
183+
const match = result.members.find((member) =>
121184
!member.deleted &&
122185
!member.is_bot &&
123186
!member.is_app_user &&
124187
typeof member.id === 'string' &&
125188
typeof member.name === 'string' &&
126189
member.name.toLowerCase() === githubLogin
127-
));
190+
);
191+
192+
if (match) {
193+
core.info(
194+
`Found the matching Slack username on page ${pages} after ${Date.now() - lookupStartedAt} ms.`,
195+
);
196+
core.setOutput('slack_user_id', match.id);
197+
core.setOutput('slack_mention', `<@${match.id}>`);
198+
return;
199+
}
128200
129201
cursor = result.response_metadata?.next_cursor || '';
202+
core.info(
203+
`No matching Slack username on page ${pages}; ${cursor ? 'continuing pagination.' : 'no more pages.'}`,
204+
);
130205
} while (cursor);
131206
132-
core.info(`Checked ${pages} pages of users.list. Found ${matches.length} match(es) for @${githubLogin}.`);
133-
if (matches.length !== 1) {
134-
core.warning(`Expected one Slack username matching @${githubLogin}; found ${matches.length}. No DM will be sent.`);
135-
return;
136-
}
137-
138-
core.info(`Will DM Slack user ${matches[0].id}.`);
139-
core.setOutput('slack_user_id', matches[0].id);
140-
core.setOutput('slack_mention', `<@${matches[0].id}>`);
207+
core.warning(
208+
`No active Slack username matched @${githubLogin} after ${pages} page(s) and ${Date.now() - lookupStartedAt} ms; no DM will be sent.`,
209+
);
141210
142211
- name: DM the author in Slack
143212
id: slack_dm

‎.github/workflows/reviewers-docs-engineering.yml‎

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,8 @@ jobs:
5151
# Detect PRs that only change package-lock.json. Contributors often create
5252
# cross-platform npm install churn while editing content.
5353
# Comment with reset instructions instead of adding them to the engineering review board.
54-
# Dependabot security updates can change only the lockfile when package.json
55-
# does not name the transitive dependency.
56-
# Those PRs are intentional, so reset instructions would be wrong and
57-
# keeping them off the board would leave them without engineering triage.
54+
# Dependabot and docs-bot PRs can change only the lockfile on purpose, for example
55+
# to fix a transitive dependency. Skip the check for them so they still get engineering triage.
5856
- name: Detect lockfile-only churn
5957
id: detect
6058
env:
@@ -64,8 +62,8 @@ jobs:
6462
CHANGED_FILES: ${{ github.event.pull_request.changed_files }}
6563
REPO: ${{ github.repository }}
6664
run: |
67-
if [ "$PR_AUTHOR" = "dependabot[bot]" ]; then
68-
echo "Author is Dependabot; skipping lockfile churn detection."
65+
if [ "$PR_AUTHOR" = "dependabot[bot]" ] || [ "$PR_AUTHOR" = "docs-bot" ]; then
66+
echo "Author is $PR_AUTHOR; skipping lockfile churn detection."
6967
echo "lockfile_only=false" >> "$GITHUB_OUTPUT"
7068
exit 0
7169
fi

‎.github/workflows/test.yml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ jobs:
6969
- secret-scanning
7070
- shielding
7171
# - tests
72-
# - tools
72+
- tools
7373
# - types
7474
- versions
7575
- webhooks
@@ -85,7 +85,7 @@ jobs:
8585
env:
8686
# These suites make no HTTP requests, so they skip the Next.js build and test server.
8787
# A suite that adds an HTTP test fails with a connection error until it's removed from this list.
88-
START_VITEST_SERVER: ${{ contains(fromJSON('["color-schemes", "content-linter", "data-directory", "ghes-releases", "journeys", "links", "observability", "products", "workflows"]'), matrix.name) && 'false' || 'true' }}
88+
START_VITEST_SERVER: ${{ contains(fromJSON('["color-schemes", "content-linter", "data-directory", "ghes-releases", "journeys", "links", "observability", "products", "tools", "workflows"]'), matrix.name) && 'false' || 'true' }}
8989

9090
steps:
9191
# Repeat each if on its step so skipped work still leaves the required check present.

‎config/moda/deployment.yaml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ environments:
196196
require_vault: true
197197
secret_environment: staging
198198
required_review_tasks: []
199-
auto_deploy: true
199+
auto_deploy: false
200200
skip_auto_merge: true
201201
proxima: true
202202
resource_path: config/kubernetes/docs-internal-review-lab

‎content/admin/backing-up-and-restoring-your-instance/configuring-elasticsearch-snapshots.md‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ This feature is opt-in. If you don't configure a snapshot repository, {% data va
3333

3434
Configure the following settings using `ghe-config` over SSH. For more information, see [AUTOTITLE](/admin/administering-your-instance/administering-your-instance-from-the-command-line/accessing-the-administrative-shell-ssh).
3535

36-
You'll apply the configuration to register the snapshot repository with Elasticsearch. The repository is named `search_index_snapshots-VERSION`, where `VERSION` is the current {% data variables.product.prodname_ghe_server %} release version.
36+
You'll apply the configuration to register the snapshot repository with Elasticsearch. The repository is named `search_index_snapshots-vVERSION`, where `VERSION` is the current {% data variables.product.prodname_ghe_server %} release version.
3737

3838
### Azure Blob storage
3939

@@ -106,7 +106,7 @@ You'll apply the configuration to register the snapshot repository with Elastics
106106
After configuration apply completes, confirm the snapshot repository was registered.
107107

108108
```shell
109-
curl -k "http://127.0.0.1:9200/_snapshot/search_index_snapshots-$(ghe-version -v)/_status"
109+
curl -k "http://127.0.0.1:9200/_snapshot/search_index_snapshots-v$(ghe-version -v)/_status"
110110
```
111111

112112
If a required secret is missing, configuration apply fails while registering the repository. Update the secrets and rerun `ghe-config-apply` to retry.
@@ -137,9 +137,9 @@ You can manage Elasticsearch snapshots directly using the following commands. Ru
137137

138138
| Command | Description |
139139
| --- | --- |
140-
| `ghe-es-create-snapshot` | Creates a new snapshot in the configured repository. |
141-
| `ghe-es-list-snapshots` | Lists snapshot repositories, or snapshots within a repository. |
142-
| `ghe-es-restore-snapshot` | Restores search indices from a snapshot. |
140+
| `/usr/local/share/enterprise/ghe-es-create-snapshot` | Creates a new snapshot in the configured repository. |
141+
| `/usr/local/share/enterprise/ghe-es-list-snapshots` | Lists snapshot repositories, or snapshots within a repository. |
142+
| `/usr/local/share/enterprise/ghe-es-restore-snapshot` | Restores search indices from a snapshot. |
143143

144144
> [!TIP]
145145
> For routine backups and restores, use {% data variables.product.prodname_enterprise_backup_utilities %} or {% data variables.product.prodname_enterprise_backup_service %} instead of these commands directly. The backup tooling coordinates Elasticsearch snapshots with the rest of your instance's data to ensure a consistent backup or restore. Use the manual commands only when you need to manage search index snapshots independently of a full instance backup or restore.
@@ -151,13 +151,13 @@ You can restore a snapshot created by an earlier {% data variables.product.prodn
151151
1. List available snapshots for the earlier version.
152152

153153
```shell
154-
ghe-es-list-snapshots -v 3.14.0
154+
/usr/local/share/enterprise/ghe-es-list-snapshots -v 3.14.0
155155
```
156156

157157
1. Restore the snapshot you want.
158158

159159
```shell
160-
ghe-es-restore-snapshot -v 3.14.0 -s SNAPSHOT-NAME
160+
/usr/local/share/enterprise/ghe-es-restore-snapshot -v 3.14.0 -s SNAPSHOT-NAME
161161
```
162162

163163
Elasticsearch automatically upgrades the restored indices to the current version's format.

‎content/admin/data-residency/feature-overview-for-github-enterprise-cloud-with-data-residency.md‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ The following features are currently unavailable on {% data variables.enterprise
2323
| Feature | Details | More information |
2424
| :- | :- | :- |
2525
| Dependency insights | Organization-level and enterprise-level dependency insights are unavailable and display no data. | [AUTOTITLE](/organizations/collaborating-with-groups-in-organizations/viewing-insights-for-dependencies-in-your-organization) |
26-
| License and package metadata in the dependency graph | License and package details are not currently populated in the dependency graph. This can result in empty license fields in software bill of materials (SBOM) exports and missing license information from the {% data variables.dependency-review.action_name %}. | [AUTOTITLE](/code-security/how-tos/secure-your-supply-chain/establish-provenance-and-integrity/export-dependencies-as-sbom)<br>[AUTOTITLE](/code-security/how-tos/secure-your-supply-chain/manage-your-dependency-security/configure-dependency-review-action) |
2726
| macOS runners for {% data variables.product.prodname_actions %} | Currently unavailable. | [AUTOTITLE](/actions/concepts/runners/github-hosted-runners) |
2827
| Maven and Gradle support for {% data variables.product.prodname_registry %} | Currently unavailable. | [AUTOTITLE](/packages/working-with-a-github-packages-registry/working-with-the-apache-maven-registry) |
2928
| {% data variables.product.prodname_marketplace %} | {% data variables.product.prodname_marketplace %}, as a means of searching for, purchasing, and directly installing apps and actions, is unavailable. Ecosystem apps and actions can still be discovered and installed from their source, but they may require modification to work on {% data variables.enterprise.data_residency_site %}. | [{% data variables.product.prodname_actions %} workflows from {% data variables.product.prodname_marketplace %}](#github-actions-workflows-from-github-marketplace) |

0 commit comments

Comments
 (0)