-
Notifications
You must be signed in to change notification settings - Fork 524
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(cloud-function): setup review environment #12694
base: main
Are you sure you want to change the base?
Changes from 38 commits
33c2f48
8ffd851
3acf49a
246cf50
9618c7b
81a1f6f
8a235e2
037a80f
4d3332f
bc2016f
0b6efdf
6d299d4
195735a
9005ef5
306b3ee
ac6f5e8
510cfc8
dca20d5
e5867ef
6f30f04
b564b3b
a5de311
5bb3d05
e8ce2a1
c29f35c
fa85113
ca9c7ea
4163372
8a0dc6d
912e7e0
de12689
15d8c97
c5871ef
52ff497
f16cfc9
62f7a97
606e696
713026b
1b8074e
fe3f27a
855493a
5c6345e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,27 +18,35 @@ on: | |
required: false | ||
default: "" | ||
|
||
# This is very useful when combined with the "Use workflow from" | ||
# feature that is built into the "Run workflow" button on | ||
# https://github.com/mdn/yari/actions?query=workflow%3A%22Production+Build%22 | ||
# If you override the deployment prefix to something like the name | ||
# of the branch, you can deploy that entire branch to its own prefix | ||
# in S3 which means that it can be fully hosted as its own site. | ||
deployment_prefix: | ||
description: "Deployment prefix" | ||
required: false | ||
default: "main" | ||
|
||
log_each_successful_upload: | ||
description: "Deployer logs each success" | ||
required: false | ||
default: "false" | ||
workflow_call: | ||
secrets: | ||
GCP_PROJECT_NAME: | ||
required: true | ||
WIP_PROJECT_ID: | ||
required: true | ||
|
||
env: | ||
DEFAULT_DEPLOYMENT_PREFIX: "main" | ||
|
||
permissions: | ||
# Authenticate with GCP. | ||
id-token: write | ||
|
||
jobs: | ||
build: | ||
environment: review | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- name: Merge dispatch inputs with default env vars | ||
run: | | ||
echo "PREFIX=${{ github.event.inputs.deployment_prefix || env.DEFAULT_DEPLOYMENT_PREFIX }}" >> "$GITHUB_ENV" | ||
|
||
- uses: actions/checkout@v4 | ||
|
||
- uses: actions/checkout@v4 | ||
|
@@ -51,13 +59,47 @@ jobs: | |
# so we can figure out each document's last-modified date. | ||
fetch-depth: 0 | ||
|
||
- uses: actions/checkout@v4 | ||
with: | ||
repository: mdn/mdn-studio | ||
path: mdn/mdn-studio | ||
lfs: true | ||
token: ${{ secrets.MDN_STUDIO_PAT }} | ||
|
||
- uses: actions/checkout@v4 | ||
with: | ||
repository: mdn/generic-content | ||
path: mdn/generic-content | ||
|
||
- uses: actions/checkout@v4 | ||
with: | ||
repository: mdn/curriculum | ||
path: mdn/curriculum | ||
|
||
- uses: actions/checkout@v4 | ||
with: | ||
repository: mdn/translated-content | ||
path: mdn/translated-content | ||
# See matching warning for mdn/content checkout step | ||
fetch-depth: 0 | ||
|
||
- name: Checkout (translated-content-de) | ||
uses: actions/checkout@v4 | ||
with: | ||
repository: mdn/translated-content-de | ||
path: mdn/translated-content-de | ||
|
||
- name: Move de into translated-content | ||
run: | | ||
mv mdn/translated-content-de/files/de mdn/translated-content/files/ | ||
rm -rf mdn/translated-content-de | ||
|
||
- name: Clean and commit de | ||
working-directory: mdn/translated-content | ||
run: | | ||
git add files/de | ||
git -c user.name='MDN' -c user.email='[email protected]' commit -m 'de' | ||
|
||
- uses: actions/checkout@v4 | ||
with: | ||
repository: mdn/mdn-contributor-spotlight | ||
|
@@ -96,8 +138,7 @@ jobs: | |
- name: Print information about build | ||
run: | | ||
echo "notes: ${{ github.event.inputs.notes }}" | ||
echo "log_each_successful_upload: ${{ github.event.inputs.log_each_successful_upload }}" | ||
echo "deployment_prefix: ${{ github.event.inputs.deployment_prefix }}" | ||
echo "PREFIX: ${{ env.PREFIX }}" | ||
|
||
- name: Print information about CPU | ||
run: cat /proc/cpuinfo | ||
|
@@ -109,6 +150,12 @@ jobs: | |
CONTENT_ROOT: ${{ github.workspace }}/mdn/content/files | ||
CONTENT_TRANSLATED_ROOT: ${{ github.workspace }}/mdn/translated-content/files | ||
CONTRIBUTOR_SPOTLIGHT_ROOT: ${{ github.workspace }}/mdn/mdn-contributor-spotlight/contributors | ||
BLOG_ROOT: ${{ github.workspace }}/mdn/mdn-studio/content/posts | ||
CURRICULUM_ROOT: ${{ github.workspace }}/mdn/curriculum | ||
GENERIC_CONTENT_ROOT: ${{ github.workspace }}/mdn/generic-content/files | ||
|
||
# rari | ||
BUILD_OUT_ROOT: "client/build" | ||
|
||
# This basically means that all live-sample iframes run on the same | ||
# host as the page that includes the iframe. Not great security but the | ||
|
@@ -136,95 +183,57 @@ jobs: | |
# Info about which CONTENT_* environment variables were set and to what. | ||
echo "CONTENT_ROOT=$CONTENT_ROOT" | ||
echo "CONTENT_TRANSLATED_ROOT=$CONTENT_TRANSLATED_ROOT" | ||
yarn build:prepare | ||
|
||
yarn tool sync-translated-content | ||
|
||
# Spread the work across 2 processes. Why 2? Because that's what you | ||
# get in the default GitHub hosting Linux runners. | ||
# See https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources | ||
yarn build:docs --locale en-us --locale ja --locale fr & | ||
build1=$! | ||
yarn build:docs --not-locale en-us --not-locale ja --not-locale fr & | ||
build2=$! | ||
# Build the ServiceWorker first | ||
yarn build:sw | ||
yarn build:client | ||
yarn build:ssr | ||
|
||
# You must explicitly specify the job you're waiting-on to ensure | ||
# that the exit status of the wait command reflects the exit status | ||
# of the job it's waiting-on. | ||
wait $build1 | ||
wait $build2 | ||
cp assets/nonprod/robots.txt client/build/robots.txt | ||
|
||
# TODO: When the deployer is available this is where we | ||
# would upload the whole content of client/build | ||
du -sh client/build | ||
yarn rari content sync-translated-content | ||
yarn rari git-history | ||
|
||
# Generate sitemap index file | ||
yarn build --sitemap-index | ||
yarn rari build --all --issues client/build/issues.json --templ-stats | ||
|
||
# SSR all pages | ||
yarn render:html | ||
|
||
# Generate whatsdeployed files. | ||
yarn tool whatsdeployed --output client/build/_whatsdeployed/code.json | ||
yarn tool whatsdeployed $CONTENT_ROOT --output client/build/_whatsdeployed/content.json | ||
yarn tool whatsdeployed $CONTENT_TRANSLATED_ROOT --output client/build/_whatsdeployed/translated-content.json | ||
yarn tool:legacy whatsdeployed --output client/build/_whatsdeployed/code.json | ||
yarn tool:legacy whatsdeployed $CONTENT_ROOT --output client/build/_whatsdeployed/content.json | ||
yarn tool:legacy whatsdeployed $CONTENT_TRANSLATED_ROOT --output client/build/_whatsdeployed/translated-content.json | ||
|
||
# Sort DE search index by en-US popularity. | ||
node scripts/reorder-search-index.mjs client/build/en-us/search-index.json client/build/de/search-index.json | ||
|
||
- name: Deploy with deployer | ||
- name: Update search index | ||
env: | ||
# Set the CONTENT_ROOT first | ||
CONTENT_ROOT: ${{ github.workspace }}/mdn/content/files | ||
CONTENT_TRANSLATED_ROOT: ${{ github.workspace }}/mdn/translated-content/files | ||
|
||
DEPLOYER_BUCKET_NAME: mdn-content-dev | ||
DEPLOYER_BUCKET_PREFIX: ${{ github.event.inputs.deployment_prefix }} | ||
DEPLOYER_LOG_EACH_SUCCESSFUL_UPLOAD: ${{ github.event.inputs.log_each_successful_upload }} | ||
|
||
AWS_ACCESS_KEY_ID: ${{ secrets.DEPLOYER_STAGE_AND_DEV_AWS_ACCESS_KEY_ID }} | ||
AWS_SECRET_ACCESS_KEY: ${{ secrets.DEPLOYER_STAGE_AND_DEV_AWS_SECRET_ACCESS_KEY }} | ||
|
||
DEPLOYER_ELASTICSEARCH_URL: ${{ secrets.DEPLOYER_DEV_ELASTICSEARCH_URL }} | ||
|
||
run: | | ||
if [ ${{ github.event.inputs.translated_content }} == "true" ]; then | ||
echo "Will build mdn/translated-content too" | ||
export CONTENT_TRANSLATED_ROOT=${{ github.workspace }}/mdn/translated-content/files | ||
else | ||
echo "Will NOT build mdn/translated-content too" | ||
fi | ||
|
||
# Info about which CONTENT_* environment variables were set and to what. | ||
echo "CONTENT_ROOT=$CONTENT_ROOT" | ||
echo "CONTENT_TRANSLATED_ROOT=$CONTENT_TRANSLATED_ROOT" | ||
|
||
cd deployer | ||
|
||
# XXX would be nice to validate here that $DEPLOYER_BUCKET_PREFIX is truthy | ||
echo "DEPLOYER_BUCKET_PREFIX=$DEPLOYER_BUCKET_PREFIX" | ||
|
||
poetry run deployer upload --prune ../client/build | ||
poetry run deployer search-index ../client/build | ||
|
||
- name: Configure AWS Credentials | ||
uses: aws-actions/[email protected] | ||
- name: Authenticate with GCP | ||
uses: google-github-actions/auth@v2 | ||
with: | ||
aws-access-key-id: ${{ secrets.DEPLOYER_STAGE_AND_DEV_AWS_ACCESS_KEY_ID }} | ||
aws-secret-access-key: ${{ secrets.DEPLOYER_STAGE_AND_DEV_AWS_SECRET_ACCESS_KEY }} | ||
aws-region: us-east-1 | ||
token_format: access_token | ||
service_account: deploy-mdn-review-content@${{ secrets.GCP_PROJECT_NAME }}.iam.gserviceaccount.com | ||
workload_identity_provider: projects/${{ secrets.WIP_PROJECT_ID }}/locations/global/workloadIdentityPools/github-actions/providers/github-actions | ||
|
||
- name: Invalidate CDN | ||
env: | ||
DISTRIBUTION: E9813D0RN1QZI | ||
PATHS: /* | ||
run: aws cloudfront create-invalidation --distribution-id "$DISTRIBUTION" --paths "$PATHS" | ||
- name: Setup gcloud | ||
uses: google-github-actions/setup-gcloud@v2 | ||
|
||
- name: Sync build with GCS | ||
uses: "google-github-actions/upload-cloud-storage@v2" | ||
with: | ||
path: "client/build" | ||
destination: "${{ vars.GCP_BUCKET_NAME }}/${{ env.PREFIX }}" | ||
resumable: false | ||
concurrency: 500 | ||
process_gcloudignore: false | ||
|
||
- name: Notify PRs about deployment | ||
run: | | ||
gh pr list -S "$GITHUB_SHA -is:merged" --json number --jq '.[].number' | xargs -i gh pr comment {} --body "Dev build for $GITHUB_SHA was deployed to: $DEPLOYMENT_URL" || true | ||
env: | ||
DEPLOYMENT_URL: https://${{ github.event.inputs.deployment_prefix }}.content.dev.mdn.mozit.cloud/ | ||
DEPLOYMENT_URL: https://${{ env.PREFIX }}.review.mdn.allizom.net/ | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
|
||
- name: Slack Notification | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note: I called this workflow |
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,124 @@ | ||||||||
name: Review Deployment | ||||||||
|
||||||||
on: | ||||||||
push: | ||||||||
branches: | ||||||||
- "MP-1889-review-cloud-function" | ||||||||
|
||||||||
Comment on lines
+4
to
+7
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove before merging:
Suggested change
|
||||||||
schedule: | ||||||||
# * is a special character in YAML so you have to quote this string | ||||||||
- cron: "0 */24 * * *" | ||||||||
|
||||||||
workflow_dispatch: | ||||||||
inputs: | ||||||||
notes: | ||||||||
description: "Notes" | ||||||||
required: false | ||||||||
default: ${DEFAULT_NOTES} | ||||||||
|
||||||||
invalidate: | ||||||||
description: "Invalidate CDN (use only in exceptional circumstances)" | ||||||||
type: boolean | ||||||||
required: false | ||||||||
default: false | ||||||||
|
||||||||
workflow_call: | ||||||||
secrets: | ||||||||
GCP_PROJECT_NAME: | ||||||||
required: true | ||||||||
WIP_PROJECT_ID: | ||||||||
required: true | ||||||||
|
||||||||
permissions: | ||||||||
contents: read | ||||||||
id-token: write | ||||||||
|
||||||||
jobs: | ||||||||
deploy: | ||||||||
environment: review | ||||||||
runs-on: ubuntu-latest | ||||||||
|
||||||||
if: ${{ github.repository == 'mdn/yari' }} | ||||||||
|
||||||||
steps: | ||||||||
- name: Print information about CPU | ||||||||
run: cat /proc/cpuinfo | ||||||||
|
||||||||
- uses: actions/checkout@v4 | ||||||||
|
||||||||
- name: Setup Node.js environment | ||||||||
uses: actions/setup-node@v4 | ||||||||
with: | ||||||||
node-version-file: ".nvmrc" | ||||||||
cache: yarn | ||||||||
|
||||||||
- name: Prepare Cloud Function | ||||||||
working-directory: cloud-function | ||||||||
run: | | ||||||||
npm ci | ||||||||
echo "{}" > redirects.json | ||||||||
echo "{}" > canonicals.json | ||||||||
|
||||||||
- name: Authenticate with GCP | ||||||||
if: ${{ ! vars.SKIP_FUNCTION }} | ||||||||
uses: google-github-actions/auth@v2 | ||||||||
with: | ||||||||
token_format: access_token | ||||||||
service_account: deploy-mdn-review-functions@${{ secrets.GCP_PROJECT_NAME }}.iam.gserviceaccount.com | ||||||||
workload_identity_provider: projects/${{ secrets.WIP_PROJECT_ID }}/locations/global/workloadIdentityPools/github-actions/providers/github-actions | ||||||||
|
||||||||
- name: Setup gcloud | ||||||||
if: ${{ ! vars.SKIP_FUNCTION }} | ||||||||
uses: google-github-actions/setup-gcloud@v2 | ||||||||
with: | ||||||||
install_components: "beta" | ||||||||
|
||||||||
- name: Deploy Function | ||||||||
if: ${{ ! vars.SKIP_FUNCTION }} | ||||||||
run: |- | ||||||||
set -eo pipefail | ||||||||
|
||||||||
for region in europe-west3; do | ||||||||
gcloud beta functions deploy mdn-review-$region \ | ||||||||
--gen2 \ | ||||||||
--runtime=nodejs20 \ | ||||||||
--region=$region \ | ||||||||
--source=cloud-function \ | ||||||||
--trigger-http \ | ||||||||
--entry-point=mdnHandler \ | ||||||||
--concurrency=100 \ | ||||||||
--min-instances=0 \ | ||||||||
--max-instances=10 \ | ||||||||
--memory=2GB \ | ||||||||
--timeout=120s \ | ||||||||
--run-service-account=run-mdn-review-functions@${{ secrets.GCP_PROJECT_NAME }}.iam.gserviceaccount.com \ | ||||||||
--set-env-vars="WILDCARD_ENABLED=true" \ | ||||||||
--set-env-vars="SOURCE_CONTENT=https://storage.googleapis.com/${{ vars.GCP_BUCKET_NAME }}/" \ | ||||||||
--set-env-vars="BSA_ENABLED=true" \ | ||||||||
--set-env-vars="SENTRY_DSN=${{ secrets.SENTRY_DSN_CLOUD_FUNCTION }}" \ | ||||||||
--set-env-vars="SENTRY_ENVIRONMENT=review" \ | ||||||||
--set-env-vars="SENTRY_TRACES_SAMPLE_RATE=${{ vars.SENTRY_TRACES_SAMPLE_RATE }}" \ | ||||||||
--set-env-vars="SENTRY_RELEASE=${{ github.sha }}" \ | ||||||||
--set-secrets="KEVEL_SITE_ID=projects/${{ secrets.GCP_PROJECT_NAME }}/secrets/stage-kevel-site-id/versions/latest" \ | ||||||||
--set-secrets="KEVEL_NETWORK_ID=projects/${{ secrets.GCP_PROJECT_NAME }}/secrets/stage-kevel-network-id/versions/latest" \ | ||||||||
--set-secrets="SIGN_SECRET=projects/${{ secrets.GCP_PROJECT_NAME }}/secrets/stage-sign-secret/versions/latest" \ | ||||||||
--set-secrets="BSA_ZONE_KEYS=projects/${{ secrets.GCP_PROJECT_NAME }}/secrets/stage-bsa-zone-keys/versions/latest" \ | ||||||||
2>&1 | sed "s/^/[$region] /" & | ||||||||
pids+=($!) | ||||||||
done | ||||||||
|
||||||||
for pid in "${pids[@]}"; do | ||||||||
wait $pid | ||||||||
done | ||||||||
|
||||||||
- name: Slack Notification | ||||||||
if: failure() | ||||||||
uses: rtCamp/action-slack-notify@v2 | ||||||||
env: | ||||||||
SLACK_CHANNEL: mdn-notifications | ||||||||
SLACK_COLOR: ${{ job.status }} | ||||||||
SLACK_ICON: https://avatars.slack-edge.com/2020-11-17/1513880588420_fedd7f0e9456888e69ff_96.png | ||||||||
SLACK_TITLE: "Stage" | ||||||||
caugner marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||
SLACK_MESSAGE: "Build failed :collision:" | ||||||||
SLACK_FOOTER: "Powered by stage-build.yml" | ||||||||
caugner marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ node_modules/ | |
/client/.env | ||
__pycache__/ | ||
.idea/ | ||
tsconfig.tsbuildinfo | ||
|
||
*.log | ||
npm-debug.log* | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One could argue that this should be called
review-build
, because it deploys to$prefix.review.mdn.allizom.net
, but since we have rarely used this, let's just keep it as is.