Skip to content

Commit 9a580f7

Browse files
Merge branch 'main' into fix-33726-include-missing-word
2 parents 3cfaf8e + 3ac6e57 commit 9a580f7

2,462 files changed

Lines changed: 62232 additions & 30606 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/devcontainer.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@
5858
// Use 'postCreateCommand' to run commands after the container is created.
5959
"postCreateCommand": "npm ci",
6060

61+
// Use 'updateContentCommand' to run commands to be included in Codespace pre-builds
62+
"updateContentCommand": "git clone https://github.com/github/rest-api-description.git",
63+
6164
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
6265
"remoteUser": "node",
6366

.github/actions/labeler/action.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Labeler
2+
3+
description: Adds labels to an Issue or PR
4+
inputs:
5+
token:
6+
description: defaults to GITHUB_TOKEN, otherwise can use a PAT
7+
required: false
8+
default: ${{ github.token }}
9+
addLabels:
10+
description: array of labels to apply
11+
required: false
12+
removeLabels:
13+
description: array of labels to remove
14+
required: false
15+
ignoreIfAssigned:
16+
description: don't apply labels if there are assignees
17+
required: false
18+
ignoreIfLabeled:
19+
description: don't apply labels if there are already labels added
20+
required: false
21+
22+
runs:
23+
using: 'composite'
24+
steps:
25+
- name: Add label to an issue or pr
26+
run: node .github/actions/labeler/labeler.js
27+
shell: bash
28+
env:
29+
GITHUB_TOKEN: ${{ inputs.token }}
30+
ADD_LABELS: ${{ inputs.addLabels }}
31+
REMOVE_LABELS: ${{ inputs.removeLabels }}
32+
IGNORE_IF_ASSIGNED: ${{ inputs.ignoreIfAssigned }}
33+
IGNORE_IF_LABELED: ${{ inputs.ignoreIfLabeled }}

.github/actions/labeler/labeler.js

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
/* See function main in this file for documentation */
2+
3+
import coreLib from '@actions/core'
4+
5+
import github from '#src/workflows/github.js'
6+
import { getActionContext } from '#src/workflows/action-context.js'
7+
import { boolEnvVar } from '#src/workflows/get-env-inputs.js'
8+
9+
// When this file is invoked directly from action as opposed to being imported
10+
if (import.meta.url.endsWith(process.argv[1])) {
11+
if (!process.env.GITHUB_TOKEN) {
12+
throw new Error('You must set the GITHUB_TOKEN environment variable.')
13+
}
14+
15+
const { ADD_LABELS, REMOVE_LABELS } = process.env
16+
17+
const octokit = github()
18+
19+
const opts = {
20+
addLabels: ADD_LABELS,
21+
removeLabels: REMOVE_LABELS,
22+
ignoreIfAssigned: boolEnvVar('IGNORE_IF_ASSIGNED'),
23+
ignoreIfLabeled: boolEnvVar('IGNORE_IF_LABELED'),
24+
}
25+
26+
// labels come in comma separated from actions
27+
let addLabels
28+
29+
if (opts.addLabels) {
30+
addLabels = [...opts.addLabels.split(',')]
31+
opts.addLabels = addLabels.map((l) => l.trim())
32+
} else {
33+
opts.addLabels = []
34+
}
35+
36+
let removeLabels
37+
38+
if (opts.removeLabels) {
39+
removeLabels = [...opts.removeLabels.split(',')]
40+
opts.removeLabels = removeLabels.map((l) => l.trim())
41+
} else {
42+
opts.removeLabels = []
43+
}
44+
45+
const actionContext = getActionContext()
46+
const { owner, repo } = actionContext
47+
let issueOrPrNumber = actionContext?.pull_request?.number
48+
49+
if (!issueOrPrNumber) {
50+
issueOrPrNumber = actionContext?.issue?.number
51+
}
52+
53+
opts.issue_number = issueOrPrNumber
54+
opts.owner = owner
55+
opts.repo = repo
56+
57+
main(coreLib, octokit, opts, {})
58+
}
59+
60+
/*
61+
* Applies labels to an issue or pull request.
62+
*
63+
* opts:
64+
* issue_number {number} id of the issue or pull request to label
65+
* owner {string} owner of the repository
66+
* repo {string} repository name
67+
* addLabels {Array<string>} array of labels to apply
68+
* removeLabels {Array<string>} array of labels to remove
69+
* ignoreIfAssigned {boolean} don't apply labels if there are assignees
70+
* ignoreIfLabeled {boolean} don't apply labels if there are already labels added
71+
*/
72+
export default async function main(core, octokit, opts = {}) {
73+
if (opts.addLabels?.length === 0 && opts.removeLabels?.length === 0) {
74+
core.info('No labels to add or remove specified, nothing to do.')
75+
return
76+
}
77+
78+
if (opts.ignoreIfAssigned || opts.ignoreIfLabeled) {
79+
try {
80+
const { data } = await octokit.issues.get({
81+
issue_number: opts.issue_number,
82+
owner: opts.owner,
83+
repo: opts.repo,
84+
})
85+
86+
if (opts.ignoreIfAssigned) {
87+
if (data.assignees.length > 0) {
88+
core.info(
89+
`ignore-if-assigned is true: not applying labels since there's ${data.assignees.length} assignees`,
90+
)
91+
return 0
92+
}
93+
}
94+
95+
if (opts.ignoreIfLabeled) {
96+
if (data.labels.length > 0) {
97+
core.info(
98+
`ignore-if-labeled is true: not applying labels since there's ${data.labels.length} labels applied`,
99+
)
100+
return 0
101+
}
102+
}
103+
} catch (err) {
104+
throw new Error(`Error getting issue: ${err}`)
105+
}
106+
}
107+
108+
if (opts.removeLabels?.length > 0) {
109+
// removing a label fails if the label isn't already applied
110+
let appliedLabels = []
111+
112+
try {
113+
const { data } = await octokit.issues.get({
114+
issue_number: opts.issue_number,
115+
owner: opts.owner,
116+
repo: opts.repo,
117+
})
118+
119+
appliedLabels = data.labels.map((l) => l.name)
120+
} catch (err) {
121+
throw new Error(`Error getting issue: ${err}`)
122+
}
123+
124+
opts.removeLabels = opts.removeLabels.filter((l) => appliedLabels.includes(l))
125+
126+
await Promise.all(
127+
opts.removeLabels.map(async (label) => {
128+
try {
129+
await octokit.issues.removeLabel({
130+
issue_number: opts.issue_number,
131+
owner: opts.owner,
132+
repo: opts.repo,
133+
name: label,
134+
})
135+
} catch (err) {
136+
throw new Error(`Error removing label: ${err}`)
137+
}
138+
}),
139+
)
140+
141+
if (opts.removeLabels.length > 0) {
142+
core.info(`Removed labels: ${opts.removeLabels.join(', ')}`)
143+
}
144+
}
145+
146+
if (opts.addLabels?.length > 0) {
147+
try {
148+
await octokit.issues.addLabels({
149+
issue_number: opts.issue_number,
150+
owner: opts.owner,
151+
repo: opts.repo,
152+
labels: opts.addLabels,
153+
})
154+
155+
core.info(`Added labels: ${opts.addLabels.join(', ')}`)
156+
} catch (err) {
157+
throw new Error(`Error adding label: ${err}`)
158+
}
159+
}
160+
}
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
name: Azure - Deploy Preview Environment (public)
2+
3+
# NOTE! This is specifically and only for github/docs.
4+
5+
# **What it does**: Build and deploy an Azure preview environment for this PR in github/docs
6+
# **Why we have it**: It's our preview environment deploy mechanism, to docs public repo
7+
# **Who does it impact**: All open source contributors.
8+
9+
# !!!
10+
# ! This worflow has access to secrets, runs in the public repository, and clones untrusted user code.
11+
# ! Modify with extreme caution
12+
# !!!
13+
14+
on:
15+
pull_request_target:
16+
# Note that if someone makes a PR that touches `Dockerfile`
17+
# and `content/index.md`, this use of `paths` will still run.
18+
# It would run even if we appended `- '!Dockerfile'` to the list.
19+
# But if someone makes a PR that touches `Dockerfile` only, the
20+
# workflow will not run.
21+
paths:
22+
- 'content/**'
23+
- 'data/**'
24+
- 'assets/**'
25+
merge_group:
26+
27+
permissions:
28+
contents: read
29+
deployments: write
30+
31+
# This allows one deploy workflow to interrupt another
32+
concurrency:
33+
group: 'preview-env @ ${{ github.head_ref || github.run_id }} for ${{ github.event.number || inputs.PR_NUMBER }}'
34+
cancel-in-progress: true
35+
36+
jobs:
37+
build-and-deploy-azure-preview-public:
38+
name: Build and deploy Azure preview environment (public)
39+
runs-on: ubuntu-latest
40+
if: github.repository == 'github/docs'
41+
timeout-minutes: 15
42+
environment:
43+
name: preview-env-${{ github.event.number }}
44+
# The environment variable is computer later in this job in
45+
# the "Get preview app info" step.
46+
# That script sets environment variables which is used by Actions
47+
# to link a PR to a list of environments later.
48+
url: ${{ env.APP_URL }}
49+
env:
50+
PR_NUMBER: ${{ github.event.number || github.run_id }}
51+
COMMIT_REF: ${{ github.event.pull_request.head.sha }}
52+
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
53+
NONPROD_REGISTRY_USERNAME: ghdocs
54+
55+
steps:
56+
- name: 'Az CLI login'
57+
uses: azure/login@6c251865b4e6290e7b78be643ea2d005bc51f69a # pin @v2
58+
with:
59+
creds: ${{ secrets.NONPROD_AZURE_CREDENTIALS }}
60+
61+
- name: 'Docker login'
62+
uses: azure/docker-login@15c4aadf093404726ab2ff205b2cdd33fa6d054c
63+
with:
64+
login-server: ${{ secrets.NONPROD_REGISTRY_SERVER }}
65+
username: ${{ env.NONPROD_REGISTRY_USERNAME }}
66+
password: ${{ secrets.NONPROD_REGISTRY_PASSWORD }}
67+
68+
- name: Set up Docker Buildx
69+
uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb
70+
71+
- name: Check out main branch
72+
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
73+
with:
74+
ref: 'main'
75+
persist-credentials: 'false'
76+
77+
- name: Get preview app info
78+
env:
79+
APP_NAME_SEED: ${{ secrets.PREVIEW_ENV_NAME_SEED }}
80+
run: src/workflows/get-preview-app-info.sh
81+
82+
- name: 'Set env vars'
83+
run: |
84+
# Image tag is unique to each workflow run so that it always triggers a new deployment
85+
echo "DOCKER_IMAGE=${{ secrets.NONPROD_REGISTRY_SERVER }}/${IMAGE_REPO}:${{ env.COMMIT_REF }}-${{ github.run_number }}-${{ github.run_attempt }}" >> $GITHUB_ENV
86+
87+
- name: Check out user code to temp directory
88+
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
89+
with:
90+
path: ./user-code
91+
ref: ${{ env.COMMIT_REF }}
92+
93+
# Move acceptable user changes into our main branch checkout
94+
- name: Move acceptable user changes
95+
run: |
96+
# Make sure recursive path expansion is enabled
97+
shopt -s globstar
98+
rsync -rptovR ./user-code/content/./**/*.md ./content
99+
rsync -rptovR ./user-code/assets/./**/*.png ./assets
100+
rsync -rptovR ./user-code/data/./**/*.{yml,md} ./data
101+
102+
- uses: ./.github/actions/warmup-remotejson-cache
103+
with:
104+
restore-only: true
105+
106+
- uses: ./.github/actions/precompute-pageinfo
107+
with:
108+
restore-only: true
109+
110+
# In addition to making the final image smaller, we also save time by not sending unnecessary files to the docker build context
111+
- name: 'Prune for preview env'
112+
run: src/workflows/prune-for-preview-env.sh
113+
114+
- name: 'Build and push image'
115+
uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25
116+
with:
117+
context: .
118+
push: true
119+
target: preview
120+
tags: ${{ env.DOCKER_IMAGE }}
121+
# we only pull the `main` cache image
122+
cache-from: type=registry,ref=${{ secrets.NONPROD_REGISTRY_SERVER }}/${{ github.repository }}:main-preview
123+
# `main-docker-cache.yml` handles updating the remote cache so we don't pollute it with PR specific code
124+
cache-to: ''
125+
build-args: |
126+
BUILD_SHA=${{ env.COMMIT_REF }}
127+
128+
# Succeed despite any non-zero exit code (e.g. if there is no deployment to cancel)
129+
- name: 'Cancel any existing deployments for this PR'
130+
run: |
131+
az deployment group cancel --name ${{ env.DEPLOYMENT_NAME }} -g ${{ secrets.PREVIEW_ENV_RESOURCE_GROUP }} || true
132+
133+
# Deploy ARM template is idempotent
134+
# Note: once the resources exist the image tag must change for a new deployment to occur (the image tag includes workflow run number, run attempt, as well as sha)
135+
- name: Run ARM deploy
136+
uses: azure/arm-deploy@a1361c2c2cd398621955b16ca32e01c65ea340f5
137+
with:
138+
scope: resourcegroup
139+
resourceGroupName: ${{ secrets.PREVIEW_ENV_RESOURCE_GROUP }}
140+
subscriptionId: ${{ secrets.NONPROD_SUBSCRIPTION_ID }}
141+
template: ./src/workflows/azure-preview-env-template.json
142+
deploymentName: ${{ env.DEPLOYMENT_NAME }}
143+
parameters: appName="${{ env.APP_NAME }}"
144+
containerImage="${{ env.DOCKER_IMAGE }}"
145+
dockerRegistryUrl="${{ secrets.NONPROD_REGISTRY_SERVER }}"
146+
dockerRegistryUsername="${{ env.NONPROD_REGISTRY_USERNAME }}"
147+
dockerRegistryPassword="${{ secrets.NONPROD_REGISTRY_PASSWORD }}"
148+
149+
- name: Check that it can be reached
150+
# This introduces a necessary delay. Because the preview evironment
151+
# URL is announced to the pull request as soon as all the steps
152+
# finish, what sometimes happens is that a viewer of the PR clicks
153+
# that link too fast and are confronted with a broken page.
154+
# It's because there's a delay between the `azure/arm-deploy`
155+
# and when the server is actually started and can receive and
156+
# process requests.
157+
# By introducing a slight "delay" here we avoid announcing a
158+
# preview environment URL that isn't actually working just yet.
159+
# Note the use of `--fail`. It which means that if it actually
160+
# did connect but the error code was >=400, the command will fail.
161+
# The `--fail --retry N` combination means that a 4xx response
162+
# code will exit immediately but a 5xx will exhaust the retries.
163+
run: curl --fail --retry-connrefused --retry 5 -I ${{ env.APP_URL }}

0 commit comments

Comments
 (0)