name: QA Deploy on: workflow_dispatch: inputs: migrateDb: required: true default: "true" resetDb: required: true default: "false" jobs: build: runs-on: ubuntu-latest strategy: fail-fast: false matrix: include: - name: Api base_path: . - name: Admin base_path: . gulp: true - name: Billing base_path: . - name: Events base_path: . - name: Notifications base_path: . - name: Sso base_path: ./bitwarden_license gulp: true - name: Portal base_path: ./bitwarden_license gulp: true - name: Identity base_path: . steps: - name: Checkout repo uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f - name: Set up Node uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea with: node-version: '14' - name: Print Environment run: | dotnet --info node --version npm --version gulp --version - name: Load env vars run: | echo "Base Path: ${BASE_PATH}" echo "Name: ${NAME}" env: BASE_PATH: ${{ matrix.base_path }} NAME: ${{ matrix.name }} - name: Build Service run: | work_dir=$(pwd) dir=$BASE_PATH/src/$SERVICE_NAME cd $dir echo "Restore" dotnet restore $SERVICE_NAME.csproj echo "Clean" dotnet clean $SERVICE_NAME.csproj -c "Release" -o obj/build-output/publish if [ "$GULP" == "true" ]; then npm install npm install gulp gulp --gulpfile gulpfile.js build fi echo "Publish" dotnet publish $SERVICE_NAME.csproj -c "Release" -o obj/build-output/publish cd obj/build-output/publish zip -r $SERVICE_NAME.zip . mv $SERVICE_NAME.zip ../../../ env: SERVICE_NAME: ${{ matrix.name }} BASE_PATH: ${{ matrix.base_path }} GULP: ${{ matrix.gulp }} - name: Upload build artifact uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700 with: name: ${{ env.SERVICE_NAME }}.zip path: ${{ env.BASE_PATH }}/src/${{ env.SERVICE_NAME }}/${{ env.SERVICE_NAME }}.zip env: BASE_PATH: ${{ matrix.base_path }} SERVICE_NAME: ${{ matrix.name }} - name: Test build dir run: ls $BASE_PATH/src/$SERVICE_NAME env: SERVICE_NAME: ${{ matrix.name }} BASE_PATH: ${{ matrix.base_path }} reset-db: name: Reset Database if: ${{ github.event.inputs.resetDb == 'true' }} runs-on: ubuntu-latest needs: build steps: - name: Reset Test Data - Stub run: | echo "placeholder for cleaning DB" echo "placeholder for loading test dataset" update-db: name: Update Database if: ${{ github.event.inputs.migrateDb == 'true' }} runs-on: ubuntu-latest needs: build steps: - name: Checkout repo uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f - name: Login to Azure uses: Azure/login@77f1b2e3fb80c0e8645114159d17008b8a2e475a with: creds: ${{ secrets.AZURE_QA_KV_CREDENTIALS }} - name: Retrieve secrets id: retrieve-secrets uses: Azure/get-keyvault-secrets@80ccd3fafe5662407cc2e55f202ee34bfff8c403 with: keyvault: "bitwarden-qa-kv" secrets: "mssql-server-host, mssql-admin-login, mssql-admin-login-password" - name: Migrate database env: MSSQL_HOST: ${{ steps.retrieve-secrets.outputs.mssql-server-host }} MSSQL_USER: ${{ steps.retrieve-secrets.outputs.mssql-admin-login }} MSSQL_PASS: ${{ steps.retrieve-secrets.outputs.mssql-admin-login-password }} working-directory: ./util/Migrator/DbScripts run: | echo "Running database migrations..." for f in `ls -v ./*.sql`; do sqlcmd -S $MSSQL_HOST -d vault -U $MSSQL_USER -P $MSSQL_PASS -I -i $f done; deploy: runs-on: ubuntu-latest if: always() needs: - reset-db - update-db strategy: fail-fast: false matrix: include: - name: Api - name: Admin - name: Billing - name: Events - name: Sso - name: Portal - name: Identity steps: - name: Setup id: setup run: | NAME_LOWER=$(echo "${{ matrix.name }}" | awk '{print tolower($0)}') echo "Matrix name: ${{ matrix.name }}" echo "NAME_LOWER: $NAME_LOWER" echo "::set-output name=name_lower::$NAME_LOWER" - name: Download aritifacts uses: actions/download-artifact@158ca71f7c614ae705e79f25522ef4658df18253 with: name: ${{ matrix.name }}.zip - name: Login to Azure uses: Azure/login@77f1b2e3fb80c0e8645114159d17008b8a2e475a with: creds: ${{ secrets.AZURE_QA_KV_CREDENTIALS }} - name: Retrieve secrets id: retrieve-secrets env: VAULT_NAME: "bitwarden-qa-kv" run: | webapp_name=$(az keyvault secret show --vault-name $VAULT_NAME --name appservices-${{ steps.setup.outputs.name_lower }}-webapp-name --query value --output tsv) echo "::add-mask::$webapp_name" echo "::set-output name=webapp-name::$webapp_name" - name: Deploy App uses: azure/webapps-deploy@798e43877120eda6a2a690a4f212c545e586ae31 with: app-name: ${{ steps.retrieve-secrets.outputs.webapp-name }} slot-name: "staging" package: ./${{ matrix.name }}.zip swap-identity: runs-on: ubuntu-latest needs: deploy steps: - name: Login to Azure uses: Azure/login@77f1b2e3fb80c0e8645114159d17008b8a2e475a with: creds: ${{ secrets.AZURE_QA_KV_CREDENTIALS }} - name: Retrieve secrets id: retrieve-secrets env: VAULT_NAME: "bitwarden-qa-kv" run: | identity_webapp_name=$(az keyvault secret show --vault-name $VAULT_NAME --name appservices-identity-webapp-name --query value --output tsv) echo "::add-mask::$identity_webapp_name" echo "::set-output name=identity-webapp-name::$identity_webapp_name" - name: Start staging slot run: az webapp start --name ${{ steps.retrieve-secrets.outputs.identity-webapp-name }} --resource-group bitwarden-qa --slot staging - name: Make sure staging endpoint is alive run: | SUCCESS="no" while read OUTPUT do STATUS=$( curl -is https://${{ steps.retrieve-secrets.outputs.identity-webapp-name }}-staging.azurewebsites.net/.well-known/openid-configuration/jwks | head -1 ) if [[ "$STATUS" == *"200 OK"* ]]; then echo "It is live!" SUCCESS="yes" break fi echo -e "STAUS=$STATUS\nRetrying: $OUTPUT" sleep 4; done < <(seq 15) if [[ "$SUCCESS" == "no" ]]; then exit 1 fi - name: Swap Identity run: az webapp deployment slot swap -g bitwarden-qa -n ${{ steps.retrieve-secrets.outputs.identity-webapp-name }} --slot staging --target-slot production - name: Stop staging slot run: az webapp stop --name ${{ steps.retrieve-secrets.outputs.identity-webapp-name }} --resource-group bitwarden-qa --slot staging swap-slots: runs-on: ubuntu-latest needs: swap-identity strategy: fail-fast: false matrix: include: - name: Api - name: Billing - name: Events - name: Sso - name: Portal steps: - name: Setup id: setup run: | NAME_LOWER=$(echo "${{ matrix.name }}" | awk '{print tolower($0)}') echo "::set-output name=name_lower::$NAME_LOWER" - name: Login to Azure uses: Azure/login@77f1b2e3fb80c0e8645114159d17008b8a2e475a with: creds: ${{ secrets.AZURE_QA_KV_CREDENTIALS }} - name: Retrieve secrets id: retrieve-secrets env: VAULT_NAME: "bitwarden-qa-kv" run: | webapp_name=$(az keyvault secret show --vault-name $VAULT_NAME --name appservices-${{ steps.setup.outputs.name_lower }}-webapp-name --query value --output tsv) echo "::add-mask::$webapp_name" echo "::set-output name=webapp-name::$webapp_name" - name: Start staging slot run: az webapp start --name ${{ steps.retrieve-secrets.outputs.webapp-name }} --resource-group bitwarden-qa --slot staging - name: Make sure staging endpoint is alive run: | SUCCESS="no" while read OUTPUT do STATUS=$( curl -is https://${{ steps.retrieve-secrets.outputs.webapp-name }}-staging.azurewebsites.net/alive | head -1 ) if [[ "$STATUS" == *"200 OK"* ]]; then echo "It is live!" SUCCESS="yes" break fi echo -e "STAUS=$STATUS\nRetrying: $OUTPUT" sleep 4; done < <(seq 15) if [[ "$SUCCESS" == "no" ]]; then exit 1 fi - name: Swap slots run: az webapp deployment slot swap -g bitwarden-qa -n ${{ steps.retrieve-secrets.outputs.webapp-name }} --slot staging --target-slot production - name: Stop staging slot run: az webapp stop --name ${{ steps.retrieve-secrets.outputs.webapp-name }} --resource-group bitwarden-qa --slot staging swap-admin: runs-on: ubuntu-latest needs: swap-slots steps: - name: Login to Azure uses: Azure/login@77f1b2e3fb80c0e8645114159d17008b8a2e475a with: creds: ${{ secrets.AZURE_QA_KV_CREDENTIALS }} - name: Retrieve secrets id: retrieve-secrets env: VAULT_NAME: "bitwarden-qa-kv" run: | admin_webapp_name=$(az keyvault secret show --vault-name $VAULT_NAME --name appservices-admin-webapp-name --query value --output tsv) echo "::add-mask::$admin_webapp_name" echo "::set-output name=admin-webapp-name::$admin_webapp_name" - name: Start staging slot run: az webapp start --name ${{ steps.retrieve-secrets.outputs.admin-webapp-name }} --resource-group bitwarden-qa --slot staging - name: Make sure staging endpoint is alive run: | sleep 60 # I don't think the admin portal has an alive endpoint - name: Swap Admin run: az webapp deployment slot swap -g bitwarden-qa -n ${{ steps.retrieve-secrets.outputs.admin-webapp-name }} --slot staging --target-slot production - name: Stop staging slot run: az webapp stop --name ${{ steps.retrieve-secrets.outputs.admin-webapp-name }} --resource-group bitwarden-qa --slot staging