---
name: Release

on:
  workflow_dispatch:
    inputs:
      release_type:
        description: 'Release Options'
        required: true
        default: 'Initial Release'
        type: choice
        options:
          - Initial Release
          - Redeploy
          - Dry Run


jobs:
  setup:
    name: Setup
    runs-on: ubuntu-20.04
    outputs:
      release_version: ${{ steps.version.outputs.package }}
      branch-name: ${{ steps.branch.outputs.branch-name }}
    steps:
      - name: Branch check
        if: ${{ github.event.inputs.release_type != 'Dry Run' }}
        run: |
          if [[ "$GITHUB_REF" != "refs/heads/rc" ]] && [[ "$GITHUB_REF" != "refs/heads/hotfix-rc" ]]; then
            echo "==================================="
            echo "[!] Can only release from the 'rc' or 'hotfix-rc' branches"
            echo "==================================="
            exit 1
          fi

      - name: Checkout repo
        uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579

      - name: Check Release Version
        id: version
        run: |
          version=$( grep -o "<Version>.*</Version>" Directory.Build.props | grep -o "[0-9]*\.[0-9]*\.[0-9]*")
          previous_release_tag_version=$(
            curl -sL https://api.github.com/repos/$GITHUB_REPOSITORY/releases/latest | jq -r ".tag_name"
          )

          if [ "v$version" == "$previous_release_tag_version" ] && \
          [ "${{ github.event.inputs.release_type }}" == "Initial Release" ]; then
            echo "[!] Already released v$version. Please bump version to continue"
            exit 1
          fi

          echo "::set-output name=package::$version"

      - name: Get branch name
        id: branch
        run: |
          BRANCH_NAME=$(basename ${{ github.ref }})
          echo "::set-output name=branch-name::$BRANCH_NAME"


  deploy:
    name: Deploy
    runs-on: ubuntu-20.04
    needs:
      - setup
    strategy:
      fail-fast: false
      matrix:
        include:
          - name: Api
          - name: Admin
          - name: Billing
          - name: Events
          - name: Sso
          - 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 latest Release ${{ matrix.name }} asset
        uses: bitwarden/gh-actions/download-artifacts@23433be15ed6fd046ce12b6889c5184a8d9c8783
        with:
          workflow: build.yml
          workflow_conclusion: success
          branch: ${{ needs.setup.outputs.branch-name }}
          artifacts: ${{ matrix.name }}.zip

      - name: Login to Azure
        uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf
        with:
          creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }}

      - name: Retrieve secrets
        id: retrieve-secrets
        env:
          VAULT_NAME: "bitwarden-prod-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
          )
          publish_profile=$(
            az keyvault secret show --vault-name $VAULT_NAME \
              --name appservices-${{ steps.setup.outputs.name_lower }}-webapp-publish-profile \
              --query value --output tsv
          )
          echo "::add-mask::$webapp_name"
          echo "::set-output name=webapp-name::$webapp_name"
          echo "::add-mask::$publish_profile"
          echo "::set-output name=publish-profile::$publish_profile"

      - name: Deploy App
        uses: azure/webapps-deploy@0b651ed7546ecfc75024011f76944cb9b381ef1e
        with:
          app-name: ${{ steps.retrieve-secrets.outputs.webapp-name }}
          publish-profile: ${{ steps.retrieve-secrets.outputs.publish-profile }}
          package: ./${{ matrix.name }}.zip
          slot-name: "staging"

      - name: Start staging slot
        env:
          SERVICE: ${{ matrix.name }}
          WEBAPP_NAME: ${{ steps.retrieve-secrets.outputs.webapp-name }}
        run: |
          if [[ "$SERVICE" = "Api" ]] || [[ "$SERVICE" = "Identity" ]]; then
            RESOURCE_GROUP=bitwardenappservices
          else
            RESOURCE_GROUP=bitwarden
          fi
          az webapp start -n $WEBAPP_NAME -g $RESOURCE_GROUP -s staging


  release-docker:
    name: Build Docker images
    runs-on: ubuntu-20.04
    needs:
      - setup
    env:
      _RELEASE_VERSION: ${{ needs.setup.outputs.release_version }}
      _BRANCH_NAME: ${{ needs.setup.outputs.branch-name }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - service_name: Admin
          - service_name: Api
          - service_name: Attachments
          - service_name: Events
          - service_name: Icons
          - service_name: Identity
          - service_name: K8S-Proxy
          - service_name: MsSql
          - service_name: Nginx
          - service_name: Notifications
          - service_name: Server
          - service_name: Setup
          - service_name: Sso
    steps:
      - name: Print environment
        env:
          RELEASE_OPTION: ${{ github.event.inputs.release_type }}
        run: |
          whoami
          docker --version
          echo "GitHub ref: $GITHUB_REF"
          echo "GitHub event: $GITHUB_EVENT"
          echo "Github Release Option: $RELEASE_OPTION"

      - name: Checkout repo
        uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579

      - name: Setup service name
        id: setup
        run: |
          SERVICE_NAME=$(echo "${{ matrix.service_name }}" | awk '{print tolower($0)}')
          echo "Matrix name: ${{ matrix.service_name }}"
          echo "SERVICE_NAME: $SERVICE_NAME"
          echo "::set-output name=service_name::$SERVICE_NAME"

      ########## DockerHub ##########
      - name: Setup DCT
        id: setup-dct
        uses: bitwarden/gh-actions/setup-docker-trust@a8c384a05a974c05c48374c818b004be221d43ff
        with:
          azure-creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }}
          azure-keyvault-name: "bitwarden-prod-kv"

      - name: Pull latest selfhost image
        env:
          SERVICE_NAME: ${{ steps.setup.outputs.service_name }}
        run: |
          if [[ "${{ github.event.inputs.release_type }}" == "Dry Run" ]]; then
            docker pull bitwarden/$SERVICE_NAME:latest
          else
            docker pull bitwarden/$SERVICE_NAME:$_BRANCH_NAME
          fi

      - name: Tag version and latest
        env:
          SERVICE_NAME: ${{ steps.setup.outputs.service_name }}
        run: |
          if [[ "${{ github.event.inputs.release_type }}" == "Dry Run" ]]; then
            docker tag bitwarden/$SERVICE_NAME:latest bitwarden/$SERVICE_NAME:dryrun
          else
            docker tag bitwarden/$SERVICE_NAME:$_BRANCH_NAME bitwarden/$SERVICE_NAME:$_RELEASE_VERSION
            docker tag bitwarden/$SERVICE_NAME:$_BRANCH_NAME bitwarden/$SERVICE_NAME:latest
          fi

      - name: Push version and latest image
        if: ${{ github.event.inputs.release_type != 'Dry Run' }}
        env:
          DOCKER_CONTENT_TRUST: 1
          DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE: ${{ steps.setup-dct.outputs.dct-delegate-repo-passphrase }}
          SERVICE_NAME: ${{ steps.setup.outputs.service_name }}
        run: |
          docker push bitwarden/$SERVICE_NAME:$_RELEASE_VERSION
          docker push bitwarden/$SERVICE_NAME:latest

      - name: Log out of Docker and disable Docker Notary
        run: |
          docker logout
          echo "DOCKER_CONTENT_TRUST=0" >> $GITHUB_ENV

      ########## ACR ##########
      - name: Login to Azure - QA Subscription
        uses: Azure/login@77f1b2e3fb80c0e8645114159d17008b8a2e475a
        with:
          creds: ${{ secrets.AZURE_QA_KV_CREDENTIALS }}

      - name: Login to Azure ACR
        run: az acr login -n bitwardenqa

      - name: Tag version and latest
        env:
          SERVICE_NAME: ${{ steps.setup.outputs.service_name }}
          REGISTRY: bitwardenqa.azurecr.io
        run: |
          if [[ "${{ github.event.inputs.release_type }}" == "Dry Run" ]]; then
            docker tag bitwarden/$SERVICE_NAME:latest $REGISTRY/$SERVICE_NAME:dryrun
          else
            docker tag bitwarden/$SERVICE_NAME:$_BRANCH_NAME $REGISTRY/$SERVICE_NAME:$_RELEASE_VERSION
            docker tag bitwarden/$SERVICE_NAME:$_BRANCH_NAME $REGISTRY/$SERVICE_NAME:latest
          fi

      - name: Push version and latest image
        if: ${{ github.event.inputs.release_type != 'Dry Run' }}
        env:
          SERVICE_NAME: ${{ steps.setup.outputs.service_name }}
          REGISTRY: bitwardenqa.azurecr.io
        run: |
          docker push $REGISTRY/$SERVICE_NAME:$_RELEASE_VERSION
          docker push $REGISTRY/$SERVICE_NAME:latest

      - name: Log out of Docker
        run: docker logout


  release:
    name: Create GitHub Release
    runs-on: ubuntu-20.04
    needs:
      - setup
      - deploy
    steps:
      - name: Download latest Release docker-stub
        uses: bitwarden/gh-actions/download-artifacts@23433be15ed6fd046ce12b6889c5184a8d9c8783
        with:
          workflow: build.yml
          workflow_conclusion: success
          branch: ${{ needs.setup.outputs.branch-name }}
          artifacts: "docker-stub.zip,
                      docker-stub-sha256.txt,
                      swagger.json"

      - name: Create release
        if: ${{ github.event.inputs.release_type != 'Dry Run' }}
        uses: ncipollo/release-action@40bb172bd05f266cf9ba4ff965cb61e9ee5f6d01
        with:
          artifacts: 'docker-stub.zip,
                      docker-stub-sha256.txt,
                      swagger.json'
          commit: ${{ github.sha }}
          tag: "v${{ needs.setup.outputs.release_version }}"
          name: "Version ${{ needs.setup.outputs.release_version }}"
          body: "<insert release notes here>"
          token: ${{ secrets.GITHUB_TOKEN }}
          draft: true
