Skip to content

Commit fc769e1

Browse files
authored
Add centralized staging build files for docs-staging-x deploys (#53586)
1 parent 3a792f8 commit fc769e1

18 files changed

+1004
-0
lines changed
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
# **What it does**: Synchronizes each of the github/docs-staging-X repositories with the latest build scripts, workflows, and other files from src/deployments/staging.
2+
# **Why we have it**: We want to centralize build config in src/deployments/staging for use across multiple repos.
3+
# **Who does it impact**: Docs engineering, and potentially content writers.
4+
5+
name: Sync Staging Repo Files
6+
7+
on:
8+
push:
9+
branches: [main]
10+
paths:
11+
- 'src/deployments/staging/build-scripts/*.sh'
12+
- 'src/deployments/staging/.github/**'
13+
- 'src/deployments/staging/Dockerfile'
14+
- 'src/deployments/staging/.env.example'
15+
- 'src/deployments/staging/README.example.md'
16+
- 'src/deployments/staging/config/**'
17+
18+
permissions:
19+
contents: write
20+
21+
jobs:
22+
# Determine how many staging repos we have and generate a matrix with repo and index
23+
generate-matrix:
24+
if: github.repository == 'github/docs-internal'
25+
runs-on: ubuntu-latest
26+
outputs:
27+
matrix: ${{ steps.set-matrix.outputs.matrix }}
28+
steps:
29+
- name: Checkout source repository
30+
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
31+
with:
32+
fetch-depth: 1 # Only need latest commit for config.json
33+
34+
- name: Read configuration
35+
id: read-config
36+
run: |
37+
sudo apt-get update && sudo apt-get install -y jq
38+
NUMBER_OF_REPOS=$(jq '.number_of_staging_repos' src/deployments/staging/config.json)
39+
if ! [[ "$NUMBER_OF_REPOS" =~ ^[0-9]+$ ]]; then
40+
echo "Invalid number_of_staging_repos in config.json: $NUMBER_OF_REPOS"
41+
exit 1
42+
fi
43+
echo "number_of_repos=$NUMBER_OF_REPOS" >> $GITHUB_OUTPUT
44+
45+
- name: Generate repository list with indices
46+
id: generate-repos
47+
run: |
48+
NUMBER_OF_REPOS=${{ steps.read-config.outputs.number_of_repos }}
49+
repos=()
50+
for i in $(seq 0 $NUMBER_OF_REPOS); do
51+
repos+=("{\"repo\": \"github/docs-staging-$i\", \"index\": $i}")
52+
done
53+
json_repos=$(printf '%s\n' "${repos[@]}" | jq -s .)
54+
echo "repos=$json_repos" >> $GITHUB_OUTPUT
55+
56+
- name: Set matrix output with repo and index
57+
id: set-matrix
58+
run: |
59+
repos=${{ steps.generate-repos.outputs.repos }}
60+
echo "matrix={\"include\": $repos}" >> $GITHUB_OUTPUT
61+
62+
- uses: ./.github/actions/slack-alert
63+
if: ${{ failure() && github.event_name != 'workflow_dispatch' }}
64+
with:
65+
slack_channel_id: ${{ secrets.DOCS_ALERTS_SLACK_CHANNEL_ID }}
66+
slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }}
67+
68+
sync:
69+
if: github.repository == 'github/docs-internal'
70+
needs: generate-matrix
71+
runs-on: ubuntu-latest
72+
strategy:
73+
fail-fast: false
74+
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
75+
steps:
76+
- name: Checkout source repository
77+
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
78+
with:
79+
fetch-depth: 0
80+
81+
- name: Checkout target repository
82+
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
83+
with:
84+
repository: ${{ matrix.repo }}
85+
token: ${{ secrets.DOCS_BOT_PAT_READPUBLICKEY }}
86+
path: target_repo
87+
fetch-depth: 0
88+
89+
- name: Synchronize files to target repo
90+
run: |
91+
# Create necessary directories if they DNE
92+
mkdir -p target_repo/build-scripts
93+
mkdir -p target_repo/.github/workflows
94+
mkdir -p target_repo/config
95+
96+
# Copy build scripts
97+
cp src/deployments/staging/build-scripts/*.sh target_repo/build-scripts/ || true
98+
99+
# Copy .github directory
100+
cp -r src/deployments/staging/.github target_repo/
101+
102+
# Copy config files
103+
cp -r src/deployments/staging/config/* target_repo/config/ || true
104+
105+
# Overwrite Dockerfile
106+
cp src/deployments/staging/Dockerfile target_repo/Dockerfile
107+
108+
# Conditional copy for .env if not present
109+
if [ ! -f target_repo/.env ]; then
110+
cp src/deployments/staging/.env.example target_repo/.env
111+
fi
112+
113+
# Conditional copy for README.md if not present
114+
if [ ! -f target_repo/README.md ]; then
115+
cp src/deployments/staging/README.example.md target_repo/README.md
116+
fi
117+
118+
- name: Install jq
119+
run: sudo apt-get update && sudo apt-get install -y jq
120+
121+
- name: Replace template variables
122+
run: |
123+
# Determine which values to use based on the index
124+
INDEX=${{ matrix.index }}
125+
126+
if [ "$INDEX" -eq 0 ]; then
127+
DOMAIN=$(jq -r '.server_domain_name.internal' src/deployments/staging/config.json)
128+
LOADBALANCER=$(jq -r '.load_balancer_type.internal' src/deployments/staging/config.json)
129+
elif [ "$INDEX" -eq 1 ]; then
130+
DOMAIN=$(jq -r '.server_domain_name.external' src/deployments/staging/config.json)
131+
LOADBALANCER=$(jq -r '.load_balancer_type.external' src/deployments/staging/config.json)
132+
else
133+
DOMAIN=$(jq -r '.server_domain_name["docs-staging-x"]' src/deployments/staging/config.json)
134+
LOADBALANCER=$(jq -r '.load_balancer_type.["docs-staging-x"]' src/deployments/staging/config.json)
135+
136+
# Replace {{x}} in the domain variable with the current index
137+
DOMAIN=$(echo "$DOMAIN" | sed "s/{{x}}/$INDEX/g")
138+
fi
139+
140+
# Perform replacements in target_repo files
141+
# Replace the server_domain_name and load_balancer_type
142+
find target_repo -type f -exec sed -i "s|{{server_domain_name}}|$DOMAIN|g" {} +
143+
find target_repo -type f -exec sed -i "s|{{load_balancer_type}}|$LOADBALANCER|g" {} +
144+
145+
# If any files still contain {{x}}, replace them with the current index
146+
find target_repo -type f -exec sed -i "s/{{x}}/$INDEX/g" {} +
147+
148+
- name: Commit and push changes
149+
run: |
150+
cd target_repo
151+
git config user.name "github-actions[bot]"
152+
git config user.email "github-actions[bot]@users.noreply.github.com"
153+
git add .
154+
# If there are changes, commit and push
155+
if ! git diff --cached --quiet; then
156+
git commit -m "Synchronize files from source repository with index ${{ matrix.index }}"
157+
git push
158+
fi
159+
160+
- uses: ./.github/actions/slack-alert
161+
if: ${{ failure() && github.event_name != 'workflow_dispatch' }}
162+
with:
163+
slack_channel_id: ${{ secrets.DOCS_ALERTS_SLACK_CHANNEL_ID }}
164+
slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# **What it does**: Triggers a repo disaptch event when pushing to a `docs-staging-x` branch
2+
# or when a PR is labeled with `docs-staging-x`. The repo dispatch updates the corresponding
3+
# docs-staging-x repo with the latest commit SHA, which triggers a deployment.
4+
#
5+
# Note: This does not work for docs-staging-{0/1} (review servers) updates to those are
6+
# handled in the `update-review-servers-on-code-push.yml` workflow.
7+
#
8+
# **Why we have it**: Makes staging deployments easy
9+
# **Who does it impact**: Anyone trying to deploy a staging branch, both Docs Content and Docs Engineering
10+
11+
name: Update docs-staging-x
12+
13+
on:
14+
push:
15+
branches:
16+
- 'docs-staging-[0-9]*'
17+
pull_request:
18+
types: [labeled]
19+
20+
permissions:
21+
contents: read
22+
23+
jobs:
24+
dispatch-sha:
25+
if: github.repository == 'github/docs-internal'
26+
runs-on: ubuntu-latest
27+
28+
steps:
29+
# Needed because we call a composite action (Slack alert)
30+
- name: Checkout source repository
31+
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
32+
with:
33+
fetch-depth: 1 # Only need latest commit
34+
35+
- name: Determine target staging repo
36+
id: determine_repo
37+
run: |
38+
# Determine the event type
39+
EVENT_TYPE="${{ github.event_name }}"
40+
41+
SHOULD_DISPATCH="false"
42+
if [ "$EVENT_TYPE" = "push" ]; then
43+
# Triggered by a push event
44+
BRANCH_NAME=${GITHUB_REF#refs/heads/}
45+
echo "Triggered by push event on branch: $BRANCH_NAME"
46+
47+
# Extract the staging number from branch name
48+
if [[ "$BRANCH_NAME" =~ ^docs-staging-([0-9]+)$ ]]; then
49+
STAGING_NUMBER="${BASH_REMATCH[1]}"
50+
else
51+
echo "Branch name does not match the required pattern docs-staging-X."
52+
exit 1
53+
fi
54+
55+
# Get the commit SHA from the push event
56+
COMMIT_SHA="${GITHUB_SHA}"
57+
58+
elif [ "$EVENT_TYPE" = "pull_request" ]; then
59+
# Triggered by a PR labeled event
60+
LABEL_NAME="${{ github.event.label.name }}"
61+
echo "Triggered by PR labeled event with label: $LABEL_NAME"
62+
63+
if [[ "$LABEL_NAME" =~ ^docs-staging-([0-9]+)$ ]]; then
64+
STAGING_NUMBER="${BASH_REMATCH[1]}"
65+
else
66+
echo "Label does not match the required pattern docs-staging-X."
67+
# Do not dispatch if it doesn't match
68+
echo "should_dispatch=false" >> $GITHUB_OUTPUT
69+
exit 0
70+
fi
71+
72+
# Get the commit SHA from the pull request head
73+
COMMIT_SHA="${{ github.event.pull_request.head.sha }}"
74+
75+
else
76+
echo "Event type $EVENT_TYPE not supported."
77+
echo "should_dispatch=false" >> $GITHUB_OUTPUT
78+
exit 0
79+
fi
80+
81+
echo "Staging Number: $STAGING_NUMBER"
82+
83+
# Check if staging number is 0 or 1
84+
if [ "$STAGING_NUMBER" = "0" ] || [ "$STAGING_NUMBER" = "1" ]; then
85+
echo "Staging number $STAGING_NUMBER is reserved."
86+
echo "Review server repos are handled in the \`update-review-servers-on-code-push.yml\` repository."
87+
echo "should_dispatch=false" >> $GITHUB_OUTPUT
88+
exit 0
89+
fi
90+
91+
TARGET_REPO="docs-staging-$STAGING_NUMBER"
92+
echo "Target Repository: $TARGET_REPO"
93+
SHOULD_DISPATCH="true"
94+
95+
# Set outputs
96+
echo "target_repo=$TARGET_REPO" >> $GITHUB_OUTPUT
97+
echo "commit_sha=$COMMIT_SHA" >> $GITHUB_OUTPUT
98+
echo "should_dispatch=$SHOULD_DISPATCH" >> $GITHUB_OUTPUT
99+
100+
- name: Dispatch repository dispatch event to staging repo
101+
if: steps.determine_repo.outputs.should_dispatch == 'true'
102+
env:
103+
REPO_DISPATCH_TOKEN: ${{ secrets.DOCS_BOT_PAT_WORKFLOW }}
104+
TARGET_OWNER: github
105+
TARGET_REPO: ${{ steps.determine_repo.outputs.target_repo }}
106+
EVENT_TYPE: update-sha
107+
SHA: ${{ steps.determine_repo.outputs.commit_sha }}
108+
run: |
109+
curl -X POST \
110+
-H "Accept: application/vnd.github.v3+json" \
111+
-H "Authorization: token $REPO_DISPATCH_TOKEN" \
112+
https://api.github.com/repos/$TARGET_OWNER/$TARGET_REPO/dispatches \
113+
-d "{\"event_type\":\"$EVENT_TYPE\",\"client_payload\":{\"SHA\":\"$SHA\"}}"
114+
115+
- uses: ./.github/actions/slack-alert
116+
if: ${{ failure() && github.event_name != 'workflow_dispatch' }}
117+
with:
118+
slack_channel_id: ${{ secrets.DOCS_ALERTS_SLACK_CHANNEL_ID }}
119+
slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# **What it does**: Triggers a repo dispatch event when pushing a code change to `main`
2+
# dispatches the latest SHA to both review server repos, `docs-staging-0` and `docs-staging-1`
3+
#
4+
# Note: We only dispatch on code changes to prevent unnecessary deployments since content changes
5+
# won't affect the review servers.
6+
#
7+
# **Why we have it**: Keeps the review servers up-to-date with the latest code changes
8+
# **Who does it impact**: Docs Content and Docs Engineering
9+
10+
name: Update review servers on code push
11+
12+
on:
13+
push:
14+
branches:
15+
- main
16+
paths:
17+
- 'src/**'
18+
- 'package.json'
19+
- 'tsconfig.json'
20+
- 'next.config.js'
21+
22+
permissions:
23+
contents: read
24+
25+
jobs:
26+
dispatch-sha:
27+
if: github.repository == 'github/docs-internal'
28+
runs-on: ubuntu-latest
29+
strategy:
30+
matrix:
31+
target_repo: [docs-staging-0, docs-staging-1]
32+
33+
steps:
34+
# Needed because we call a composite action (Slack alert)
35+
- name: Checkout source repository
36+
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
37+
with:
38+
fetch-depth: 1 # Only need latest commit
39+
40+
- name: Determine commit SHA and dispatch condition
41+
id: determine_repo
42+
run: |
43+
echo "commit_sha=${GITHUB_SHA}" >> $GITHUB_OUTPUT
44+
# Since this workflow only runs when code changes occur (due to path filters),
45+
# we can always set should_dispatch to true.
46+
echo "should_dispatch=true" >> $GITHUB_OUTPUT
47+
48+
- name: Dispatch repository dispatch event to staging repos
49+
if: steps.determine_repo.outputs.should_dispatch == 'true'
50+
env:
51+
REPO_DISPATCH_TOKEN: ${{ secrets.DOCS_BOT_PAT_WORKFLOW }}
52+
TARGET_OWNER: github
53+
TARGET_REPO: ${{ matrix.target_repo }}
54+
EVENT_TYPE: update-sha
55+
SHA: ${{ steps.determine_repo.outputs.commit_sha }}
56+
run: |
57+
curl -X POST \
58+
-H "Accept: application/vnd.github.v3+json" \
59+
-H "Authorization: token $REPO_DISPATCH_TOKEN" \
60+
https://api.github.com/repos/$TARGET_OWNER/$TARGET_REPO/dispatches \
61+
-d "{\"event_type\":\"$EVENT_TYPE\",\"client_payload\":{\"SHA\":\"$SHA\"}}"
62+
63+
- uses: ./.github/actions/slack-alert
64+
if: ${{ failure() && github.event_name != 'workflow_dispatch' }}
65+
with:
66+
slack_channel_id: ${{ secrets.DOCS_ALERTS_SLACK_CHANNEL_ID }}
67+
slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }}

src/deployments/staging/.env.example

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# The .env file in every docs-staging-X repo can be adjusted freely and is not synchronized
2+
3+
# - - -
4+
# Unique per staging server
5+
# - - -
6+
# The name of the staging branch (should be the same as the repo name except for the review server)
7+
STAGING_BRANCH=docs-staging-{{x}}
8+
# Required for identifing image in datadog metrics
9+
MODA_APP_NAME=docs-staging-{{x}}
10+
# The most recent SHA of the STAGING_BRANCH
11+
SHA={{sha}}
12+
13+
# - - -
14+
# Unique per review server
15+
# - - -
16+
# Empty for regular staging servers, 'internal' or 'external' for review server
17+
REVIEW_SERVER=
18+
19+
# - - -
20+
# Shared defaults
21+
# - - -
22+
NODE_ENV=production
23+
PORT=4000
24+
ENABLED_LANGUAGES='en,zh,es,pt,ru,ja,fr,de,ko'
25+
RATE_LIMIT_MAX='21'
26+
# Moda uses a non-default port for sending datadog metrics
27+
DD_DOGSTATSD_PORT='28125'

0 commit comments

Comments
 (0)