diff --git a/.github/workflows/gcp_deploy.yaml b/.github/workflows/gcp_deploy.yaml new file mode 100644 index 000000000..7f681db12 --- /dev/null +++ b/.github/workflows/gcp_deploy.yaml @@ -0,0 +1,66 @@ +name: Deploy to GCS Stage + +on: + push: + branches: + - master + +jobs: + test-website: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: "18" + + - name: Install dependencies + run: yarn install --immutable + + - name: Test current build + run: yarn run test-ci + continue-on-error: true + + deploy-stage: + runs-on: ubuntu-latest + needs: test-website + if: ${{ success() }} + environment: stage + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 1 + fetch-tags: true + + - name: Setup Node.js + uses: actions/setup-node@v3 + + - name: Set up Google Cloud SDK + uses: google-github-actions/auth@v2 + with: + credentials_json: ${{ secrets.GCP_SA_KEY }} + + - name: Set up gcloud + uses: google-github-actions/setup-gcloud@v2 + + - name: Build the website + run: | + yarn install --immutable + yarn build:production + + - name: Build version.json file + run: | + if [ -e version.json ]; then + echo "version.json exists, skipping build" + else + echo "version.json does not exist, running build-version-json.sh" + bash ./.utils/build-version-json.sh + fi + + - name: Deploy the website to stage + run: | + sh ./.utils/gcs-deploy.sh ${{ vars.EXTENSIONWORKSHOP_BUCKET_STAGE }} diff --git a/.github/workflows/gcp_deploy_prod.yaml b/.github/workflows/gcp_deploy_prod.yaml new file mode 100644 index 000000000..3fb7b442d --- /dev/null +++ b/.github/workflows/gcp_deploy_prod.yaml @@ -0,0 +1,67 @@ +name: Deploy to GCS Prod + +on: + push: + tags: + - "20[0-9][0-9].[0-9][0-9].[0-9][0-9](-[0-9]+)?" + workflow_dispatch: + +jobs: + test-website: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 1 + fetch-tags: true + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: "18" + + - name: Install dependencies + run: yarn install --immutable + + - name: Test current build + run: yarn run test-ci + continue-on-error: true + + deploy-prod: + runs-on: ubuntu-latest + needs: test-website + if: ${{ success() }} + + environment: prod + steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Setup Node.js + uses: actions/setup-node@v3 + + - name: Set up Google Cloud SDK + uses: google-github-actions/auth@v2 + with: + credentials_json: ${{ secrets.GCP_SA_KEY }} + + - name: Set up gcloud + uses: google-github-actions/setup-gcloud@v2 + + - name: Build the website + run: | + yarn install --immutable + yarn build:production + + - name: Build version.json file + run: | + if [ -e version.json ]; then + echo "version.json exists, skipping build" + else + echo "version.json does not exist, running build-version-json.sh" + bash ./.utils/build-version-json.sh + fi + + - name: Deploy website to prod + run: | + sh ./.utils/gcs-deploy.sh ${{ vars.EXTENSIONWORKSHOP_BUCKET_PROD }} diff --git a/.utils/gcs-deploy.sh b/.utils/gcs-deploy.sh new file mode 100644 index 000000000..7bafc1b60 --- /dev/null +++ b/.utils/gcs-deploy.sh @@ -0,0 +1,96 @@ +#!/bin/bash + +set -ex +EXTENSION_WORKSHOP_BUCKET_GCS=$1 + +echo $EXTENSION_WORKSHOP_BUCKET_GCS + +# For short-lived assets; in seconds +TEN_MINS="600" + +# For long-lived assets; in seconds +ONE_YEAR="31536000" + +CSPSTATIC="x-goog-meta-content-security-policy: default-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors: 'none'; object-src 'none'" +CSP="x-goog-meta-content-security-policy: default-src 'none'; img-src 'self' data:; form-action 'self' https://www.mozilla.org/en-US/newsletter/; media-src 'self' blob:; script-src 'self' https://www.youtube.com/iframe_api https://www.youtube.com/s/player/ 'sha256-vqFvYKh0rwFP9fSa0PuzUff2ElHQ+rkjGfycqUNqufQ=' https://www.googletagmanager.com/gtag/js ; font-src 'self'; frame-ancestors 'none'; frame-src https://www.youtube.com/embed/ https://calendar.google.com/calendar/appointments/; base-uri 'none'; style-src 'self' 'unsafe-inline'; connect-src 'self' https://blog.mozilla.org/addons/feed/ https://www.mozilla.org/en-US/newsletter/ https://*.google-analytics.com;" +ACAO="x-goog-meta-access-control-allow-origin: *" + +if [ -z "$EXTENSION_WORKSHOP_BUCKET_GCS" ]; then + echo "The GCS bucket is not set. Failing." + exit 1 +fi + +if [ -e version.json ]; then + mv version.json dist/__version__ + gsutil cp -a public-read dist/__version__ "gs://${EXTENSION_WORKSHOP_BUCKET_GCS}/__version__" + # __version__ JSON; short cache + gsutil \ + setmeta \ + -h "cache-control: max-age=${TEN_MINS}" \ + -h "content-type: application/json" \ + -h "$CSPSTATIC" \ + -h "$ACAO" \ + "gs://${EXTENSION_WORKSHOP_BUCKET_GCS}/__version__" + +fi + +deploy_code() { + + # The basic strategy is to sync all the files that need special attention + # first, and then sync everything else which will get defaults + # + # Note that we use single quotes below for the regex pattern so that we don't + # have to deal with history expansion in shell. + + # HTML; short cache + gsutil \ + -h "cache-control: max-age=${TEN_MINS}" \ + -h "content-type: text/html" \ + -h "$CSP" \ + -h "$ACAO" \ + rsync \ + -R \ + -J \ + -a public-read \ + -x '.*(?