From a027ee5a08476b1ce5cf2dd76fc4ac043dde9ff9 Mon Sep 17 00:00:00 2001 From: Vince Grassia <593223+vgrassia@users.noreply.github.com> Date: Tue, 11 Oct 2022 10:46:36 -0400 Subject: [PATCH] DEVOPS-915 - Automate Staged Rollouts for Desktop (#3704) --- .github/workflows/build-web.yml | 6 +- .github/workflows/release-desktop.yml | 71 ++++++------ .github/workflows/staged-rollout-desktop.yml | 114 ++++++++++++++++++- 3 files changed, 145 insertions(+), 46 deletions(-) diff --git a/.github/workflows/build-web.yml b/.github/workflows/build-web.yml index 675f5bbc55..85b6bdf158 100644 --- a/.github/workflows/build-web.yml +++ b/.github/workflows/build-web.yml @@ -370,8 +370,8 @@ jobs: - cloc - setup - build-artifacts - - build-containers - build-commercial-selfhost-image + - build-containers - crowdin-push steps: - name: Check if any job failed @@ -381,7 +381,7 @@ jobs: SETUP_STATUS: ${{ needs.setup.result }} ARTIFACT_STATUS: ${{ needs.build-artifacts.result }} BUILD_SELFHOST_STATUS: ${{ needs.build-commercial-selfhost-image.result }} - BUILD_QA_STATUS: ${{ needs.build-qa.result }} + BUILD_CONTAINERS_STATUS: ${{ needs.build-containers.result }} CROWDIN_PUSH_STATUS: ${{ needs.crowdin-push.result }} run: | if [ "$CLOC_STATUS" = "failure" ]; then @@ -392,7 +392,7 @@ jobs: exit 1 elif [ "$BUILD_SELFHOST_STATUS" = "failure" ]; then exit 1 - elif [ "$BUILD_QA_STATUS" = "failure" ]; then + elif [ "$BUILD_CONTAINERS_STATUS" = "failure" ]; then exit 1 elif [ "$CROWDIN_PUSH_STATUS" = "failure" ]; then exit 1 diff --git a/.github/workflows/release-desktop.yml b/.github/workflows/release-desktop.yml index 85e9122b33..247b59ea43 100644 --- a/.github/workflows/release-desktop.yml +++ b/.github/workflows/release-desktop.yml @@ -13,13 +13,18 @@ on: - Initial Release - Redeploy - Dry Run + rollout_percentage: + description: 'Staged Rollout Percentage' + required: true + default: '10' + type: string snap_publish: - description: 'Publish to snap store' + description: 'Publish to Snap store' required: true default: true type: boolean choco_publish: - description: 'Publish to chocolatey store' + description: 'Publish to Chocolatey store' required: true default: true type: boolean @@ -93,23 +98,16 @@ jobs: - name: Retrieve secrets id: retrieve-secrets - env: - KEYVAULT: bitwarden-prod-kv - SECRETS: | - aws-electron-access-id, + uses: bitwarden/gh-actions/get-keyvault-secrets@c3b3285993151c5af47cefcb3b9134c28ab479af + with: + keyvault: "bitwarden-prod-kv" + secrets: "aws-electron-access-id, aws-electron-access-key, aws-electron-bucket-name, r2-electron-access-id, r2-electron-access-key, r2-electron-bucket-name, - cf-prod-account - run: | - for i in ${SECRETS//,/ } - do - VALUE=$(az keyvault secret show --vault-name $KEYVAULT --name $i --query value --output tsv) - echo "::add-mask::$VALUE" - echo "::set-output name=$i::$VALUE" - done + cf-prod-account" - name: Download all artifacts if: ${{ github.event.inputs.release_type != 'Dry Run' }} @@ -135,6 +133,15 @@ jobs: working-directory: apps/desktop/artifacts run: mv Bitwarden-${{ env.PKG_VERSION }}-universal.pkg Bitwarden-${{ env.PKG_VERSION }}-universal.pkg.archive + - name: Set staged rollout percentage + env: + RELEASE_CHANNEL: ${{ steps.release-channel.outputs.channel }} + ROLLOUT_PCT: ${{ github.event.inputs.rollout_percentage }} + run: | + echo "stagingPercentage: ${ROLLOUT_PCT}" >> apps/desktop/artifacts/${RELEASE_CHANNEL}.yml + echo "stagingPercentage: ${ROLLOUT_PCT}" >> apps/desktop/artifacts/${RELEASE_CHANNEL}-linux.yml + echo "stagingPercentage: ${ROLLOUT_PCT}" >> apps/desktop/artifacts/${RELEASE_CHANNEL}-mac.yml + - name: Publish artifacts to S3 if: ${{ github.event.inputs.release_type != 'Dry Run' }} env: @@ -164,8 +171,8 @@ jobs: --quiet \ --endpoint-url https://${CF_ACCOUNT}.r2.cloudflarestorage.com - - name: Create release - uses: ncipollo/release-action@95215a3cb6e6a1908b3c44e00b4fdb15548b1e09 # v2.8.5 + - name: Create Release + uses: ncipollo/release-action@95215a3cb6e6a1908b3c44e00b4fdb15548b1e09 if: ${{ steps.release-channel.outputs.channel == 'latest' && github.event.inputs.release_type != 'Dry Run' }} env: PKG_VERSION: ${{ steps.version.outputs.version }} @@ -236,17 +243,10 @@ jobs: - name: Retrieve secrets id: retrieve-secrets - env: - KEYVAULT: bitwarden-prod-kv - SECRETS: | - snapcraft-store-token - run: | - for i in ${SECRETS//,/ } - do - VALUE=$(az keyvault secret show --vault-name $KEYVAULT --name $i --query value --output tsv) - echo "::add-mask::$VALUE" - echo "::set-output name=$i::$VALUE" - done + uses: bitwarden/gh-actions/get-keyvault-secrets@c3b3285993151c5af47cefcb3b9134c28ab479af + with: + keyvault: "bitwarden-prod-kv" + secrets: "snapcraft-store-token" - name: Install Snap uses: samuelmeuli/action-snapcraft@10d7d0a84d9d86098b19f872257df314b0bd8e2d # v1.2.0 @@ -293,7 +293,7 @@ jobs: _PKG_VERSION: ${{ needs.setup.outputs.release-version }} steps: - name: Checkout Repo - uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4 + uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f - name: Print Environment run: | @@ -307,17 +307,10 @@ jobs: - name: Retrieve secrets id: retrieve-secrets - env: - KEYVAULT: bitwarden-prod-kv - SECRETS: | - cli-choco-api-key - run: | - for i in ${SECRETS//,/ } - do - VALUE=$(az keyvault secret show --vault-name $KEYVAULT --name $i --query value --output tsv) - echo "::add-mask::$VALUE" - echo "::set-output name=$i::$VALUE" - done + uses: bitwarden/gh-actions/get-keyvault-secrets@c3b3285993151c5af47cefcb3b9134c28ab479af + with: + keyvault: "bitwarden-prod-kv" + secrets: "cli-choco-api-key" - name: Setup Chocolatey shell: pwsh diff --git a/.github/workflows/staged-rollout-desktop.yml b/.github/workflows/staged-rollout-desktop.yml index 14f2b8e972..bf6a21f286 100644 --- a/.github/workflows/staged-rollout-desktop.yml +++ b/.github/workflows/staged-rollout-desktop.yml @@ -3,15 +3,121 @@ name: Staged Rollout Desktop on: workflow_dispatch: + inputs: + rollout_percentage: + description: 'Staged Rollout Percentage' + required: true + default: '10' + type: string defaults: run: shell: bash jobs: - setup: - name: Stub + rollout: + name: Update Rollout Percentage runs-on: ubuntu-22.04 + outputs: + release-version: ${{ steps.version.outputs.version }} + release-channel: ${{ steps.release-channel.outputs.channel }} steps: - - name: TEST - run: exit 0 + - name: Login to Azure + uses: Azure/login@ec3c14589bd3e9312b3cc8c41e6860e258df9010 + with: + creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }} + + - name: Retrieve secrets + id: retrieve-secrets + uses: bitwarden/gh-actions/get-keyvault-secrets@c3b3285993151c5af47cefcb3b9134c28ab479af + with: + keyvault: "bitwarden-prod-kv" + secrets: "aws-electron-access-id, + aws-electron-access-key, + aws-electron-bucket-name, + r2-electron-access-id, + r2-electron-access-key, + r2-electron-bucket-name, + cf-prod-account" + + - name: Download channel update info files from S3 + env: + AWS_ACCESS_KEY_ID: ${{ steps.retrieve-secrets.outputs.aws-electron-access-id }} + AWS_SECRET_ACCESS_KEY: ${{ steps.retrieve-secrets.outputs.aws-electron-access-key }} + AWS_DEFAULT_REGION: 'us-west-2' + AWS_S3_BUCKET_NAME: ${{ steps.retrieve-secrets.outputs.aws-electron-bucket-name }} + run: | + aws s3 cp $AWS_S3_BUCKET_NAME/desktop/latest.yml . \ + --quiet + aws s3 cp $AWS_S3_BUCKET_NAME/desktop/latest-linux.yml . \ + --quiet + aws s3 cp $AWS_S3_BUCKET_NAME/desktop/latest-mac.yml . \ + --quiet + + - name: Download channel update info files from R2 + env: + AWS_ACCESS_KEY_ID: ${{ steps.retrieve-secrets.outputs.r2-electron-access-id }} + AWS_SECRET_ACCESS_KEY: ${{ steps.retrieve-secrets.outputs.r2-electron-access-key }} + AWS_DEFAULT_REGION: 'us-east-1' + AWS_S3_BUCKET_NAME: ${{ steps.retrieve-secrets.outputs.r2-electron-bucket-name }} + CF_ACCOUNT: ${{ steps.retrieve-secrets.outputs.cf-prod-account }} + run: | + aws s3 cp $AWS_S3_BUCKET_NAME/desktop/latest.yml . \ + --quiet \ + --endpoint-url https://${CF_ACCOUNT}.r2.cloudflarestorage.com + aws s3 cp $AWS_S3_BUCKET_NAME/desktop/latest-linux.yml . \ + --quiet \ + --endpoint-url https://${CF_ACCOUNT}.r2.cloudflarestorage.com + aws s3 cp $AWS_S3_BUCKET_NAME/desktop/latest-mac.yml . \ + --quiet \ + --endpoint-url https://${CF_ACCOUNT}.r2.cloudflarestorage.com + + - name: Check new rollout percentage + env: + NEW_PCT: ${{ github.event.inputs.rollout_percentage }} + run: | + CURRENT_PCT=$(sed -r -n "s/stagingPercentage:\s([0-9]+)/\1/p" latest.yml) + echo "Current percentage: ${CURRENT_PCT}" + echo "New percentage: ${NEW_PCT}" + echo + if [ "$NEW_PCT" -le "$CURRENT_PCT" ]; then + echo "New percentage (${NEW_PCT}) must be higher than current percentage (${CURRENT_PCT})!" + echo + echo "If you want to pull a staged release because it hasn’t gone well, you must increment the version \ + number higher than your broken release. Because some of your users will be on the broken 1.0.1, \ + releasing a new 1.0.1 would result in them staying on a broken version.” + exit 1 + fi + + - name: Set staged rollout percentage + env: + ROLLOUT_PCT: ${{ github.event.inputs.rollout_percentage }} + run: | + sed -i -r "/stagingPercentage/s/[0-9]+/${ROLLOUT_PCT}/" latest.yml + sed -i -r "/stagingPercentage/s/[0-9]+/${ROLLOUT_PCT}/" latest-linux.yml + sed -i -r "/stagingPercentage/s/[0-9]+/${ROLLOUT_PCT}/" latest-mac.yml + + - name: Publish channel update info files to S3 + env: + AWS_ACCESS_KEY_ID: ${{ steps.retrieve-secrets.outputs.aws-electron-access-id }} + AWS_SECRET_ACCESS_KEY: ${{ steps.retrieve-secrets.outputs.aws-electron-access-key }} + AWS_DEFAULT_REGION: 'us-west-2' + AWS_S3_BUCKET_NAME: ${{ steps.retrieve-secrets.outputs.aws-electron-bucket-name }} + run: | + aws s3 cp ./ $AWS_S3_BUCKET_NAME/desktop/ \ + --include "latest*.yml" \ + --acl "public-read" \ + --quiet + + - name: Publish channel update info files to R2 + env: + AWS_ACCESS_KEY_ID: ${{ steps.retrieve-secrets.outputs.r2-electron-access-id }} + AWS_SECRET_ACCESS_KEY: ${{ steps.retrieve-secrets.outputs.r2-electron-access-key }} + AWS_DEFAULT_REGION: 'us-east-1' + AWS_S3_BUCKET_NAME: ${{ steps.retrieve-secrets.outputs.r2-electron-bucket-name }} + CF_ACCOUNT: ${{ steps.retrieve-secrets.outputs.cf-prod-account }} + run: | + aws s3 cp ./ $AWS_S3_BUCKET_NAME/desktop/ \ + --include "latest*.yml" \ + --quiet \ + --endpoint-url https://${CF_ACCOUNT}.r2.cloudflarestorage.com