name: Build and Test

on:
  release:
    types: [published]
  pull_request:
    branches: '**'
  push:
    branches:
      - develop

env:
  CI: true
  MONGO_URL: mongodb://localhost:27017
  TOOL_NODE_FLAGS: --max_old_space_size=4096

jobs:
  build:
    runs-on: ubuntu-latest

    steps:

    - name: Github Info
      run: |
        echo "GITHUB_ACTION: $GITHUB_ACTION"
        echo "GITHUB_ACTOR: $GITHUB_ACTOR"
        echo "GITHUB_REF: $GITHUB_REF"
        echo "GITHUB_HEAD_REF: $GITHUB_HEAD_REF"
        echo "GITHUB_BASE_REF: $GITHUB_BASE_REF"
        echo "github.event_name: ${{ github.event_name }}"
        cat $GITHUB_EVENT_PATH

    - name: Use Node.js 12.18.4
      uses: actions/setup-node@v1
      with:
        node-version: "12.18.4"

    - uses: actions/checkout@v2

    - name: Free disk space
      run: |
        sudo swapoff -a
        sudo rm -f /swapfile
        sudo apt clean
        docker rmi $(docker image ls -aq)
        df -h

    - name: check package-lock
      run: |
        npx package-lock-check

    - name: Cache cypress
      id: cache-cypress
      uses: actions/cache@v1
      with:
        path: /home/runner/.cache/Cypress
        key: ${{ runner.OS }}-cache-cypress-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('.github/workflows/build_and_test.yml') }}

    - name: Cache node modules
      if: steps.cache-cypress.outputs.cache-hit == 'true'
      id: cache-nodemodules
      uses: actions/cache@v1
      with:
        path: node_modules
        key: ${{ runner.OS }}-node_modules-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('.github/workflows/build_and_test.yml') }}

    - name: Cache meteor local
      uses: actions/cache@v1
      with:
        path: ./.meteor/local
        key: ${{ runner.OS }}-meteor_cache-${{ hashFiles('.meteor/versions') }}-${{ hashFiles('.github/workflows/build_and_test.yml') }}

    - name: Cache meteor
      uses: actions/cache@v1
      with:
        path: ~/.meteor
        key: ${{ runner.OS }}-meteor-${{ hashFiles('.meteor/release') }}-${{ hashFiles('.github/workflows/build_and_test.yml') }}

    - name: Install Meteor
      run: |
        # Restore bin from cache
        set +e
        METEOR_SYMLINK_TARGET=$(readlink ~/.meteor/meteor)
        METEOR_TOOL_DIRECTORY=$(dirname "$METEOR_SYMLINK_TARGET")
        set -e
        LAUNCHER=$HOME/.meteor/$METEOR_TOOL_DIRECTORY/scripts/admin/launch-meteor
        if [ -e $LAUNCHER ]
        then
          echo "Cached Meteor bin found, restoring it"
          sudo cp "$LAUNCHER" "/usr/local/bin/meteor"
        else
          echo "No cached Meteor bin found."
        fi

        # only install meteor if bin isn't found
        command -v meteor >/dev/null 2>&1 || curl https://install.meteor.com | sed s/--progress-bar/-sL/g | /bin/sh

    - name: Versions
      run: |
        npm --versions
        node -v
        meteor --version
        meteor npm --versions
        meteor node -v
        git version

    - name: npm install
      if: steps.cache-nodemodules.outputs.cache-hit != 'true' || steps.cache-cypress.outputs.cache-hit != 'true'
      run: |
        meteor npm install

    - run: meteor npm run lint

    - run: meteor npm run translation-check

    - name: Launch MongoDB
      uses: wbari/start-mongoDB@v0.2
      with:
        mongoDBVersion: "4.0"

    - run: meteor npm run testunit

    - run: meteor npm run typecheck

    # To reduce memory need during actual build, build the packages solely first
    # - name: Build a Meteor cache
    #   run: |
    #     # to do this we can clear the main files and it build the rest
    #     echo "" > server/main.js
    #     echo "" > client/main.js
    #     sed -i.backup 's/rocketchat:livechat/#rocketchat:livechat/' .meteor/packages
    #     meteor build --server-only --debug --directory /tmp/build-temp
    #     git checkout -- server/main.js client/main.js .meteor/packages

    - name: Reset Meteor
      if: startsWith(github.ref, 'refs/tags/') == 'true' || github.ref == 'refs/heads/develop'
      run: |
        meteor reset

    - name: Build Rocket.Chat From Pull Request
      if: startsWith(github.ref, 'refs/pull/') == true
      env:
        METEOR_PROFILE: 1000
      run: |
        meteor build --server-only --directory --debug /tmp/build-test

    - name: Build Rocket.Chat
      if: startsWith(github.ref, 'refs/pull/') != true
      run: |
        meteor build --server-only --directory /tmp/build-test

    - name: Prepare build
      run: |
        mkdir /tmp/build/
        cd /tmp/build-test
        tar czf /tmp/build/Rocket.Chat.tar.gz bundle
        cd /tmp/build-test/bundle/programs/server
        npm install
        cd /tmp
        tar czf Rocket.Chat.test.tar.gz ./build-test

    - name: Store build for tests
      uses: actions/upload-artifact@v1
      with:
        name: build-test
        path: /tmp/Rocket.Chat.test.tar.gz

    - name: Store build
      uses: actions/upload-artifact@v1
      with:
        name: build
        path: /tmp/build

  test:
    runs-on: ubuntu-16.04
    needs: build

    strategy:
      matrix:
        node-version: ["12.18.4"]
        mongodb-version: ["3.4", "3.6", "4.0"]

    steps:
    - name: Launch MongoDB
      uses: wbari/start-mongoDB@v0.2
      with:
        mongoDBVersion: ${{ matrix.mongodb-version }} --noprealloc --smallfiles --replSet=rs0

    - name: Restore build for tests
      uses: actions/download-artifact@v1
      with:
        name: build-test
        path: /tmp

    - name: Decompress build
      run: |
        cd /tmp
        tar xzf Rocket.Chat.test.tar.gz
        cd -

    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v1
      with:
        node-version: ${{ matrix.node-version }}

    - name: Setup Chrome
      run: |
        npm i chromedriver

    - name: Configure Replica Set
      run: |
        docker exec mongo mongo --eval 'rs.initiate({_id:"rs0", members: [{"_id":1, "host":"localhost:27017"}]})'
        docker exec mongo mongo --eval 'rs.status()'

    - uses: actions/checkout@v2

    - name: Cache cypress
      id: cache-cypress
      uses: actions/cache@v1
      with:
        path: /home/runner/.cache/Cypress
        key: ${{ runner.OS }}-cache-cypress-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('.github/workflows/build_and_test.yml') }}

    - name: Cache node modules
      if: steps.cache-cypress.outputs.cache-hit == 'true'
      id: cache-nodemodules
      uses: actions/cache@v1
      with:
        path: node_modules
        key: ${{ runner.OS }}-build-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('.github/workflows/build_and_test.yml') }}

    - name: NPM install
      if: steps.cache-nodemodules.outputs.cache-hit != 'true' || steps.cache-cypress.outputs.cache-hit != 'true'
      run: |
        npm install

    - name: Test
      env:
        TEST_MODE: "true"
        MONGO_URL: mongodb://localhost:27017/rocketchat
        MONGO_OPLOG_URL: mongodb://localhost:27017/local
      run: |
        echo -e 'pcm.!default {\n type hw\n card 0\n}\n\nctl.!default {\n type hw\n card 0\n}' > ~/.asoundrc
        Xvfb -screen 0 1024x768x24 :99 &
        for i in $(seq 1 5); do (docker exec mongo mongo rocketchat --eval 'db.dropDatabase()') && npm run testci && s=0 && break || s=$? && sleep 1; done; (exit $s)

#   notification:
#     runs-on: ubuntu-latest
#     needs: test

#     steps:
#     - name: Rocket.Chat Notification
#       uses: RocketChat/Rocket.Chat.GitHub.Action.Notification@1.1.1
#       with:
#         type: ${{ job.status }}
#         job_name: '**Build and Test**'
#         url: ${{ secrets.ROCKETCHAT_WEBHOOK }}
#         commit: true
#         token: ${{ secrets.GITHUB_TOKEN }}

  build-image-pr:
    runs-on: ubuntu-latest
    if: github.event.pull_request.head.repo.full_name == github.repository

    steps:
    - uses: actions/checkout@v2

    - name: Login to GitHub Container Registry
      uses: docker/login-action@v1
      with:
        registry: ghcr.io
        username: ${{ secrets.CR_USER }}
        password: ${{ secrets.CR_PAT }}

    - name: Free disk space
      run: |
        sudo swapoff -a
        sudo rm -f /swapfile
        sudo apt clean
        docker rmi $(docker image ls -aq)
        df -h

    - name: Cache node modules
      id: cache-nodemodules
      uses: actions/cache@v1
      with:
        path: node_modules
        key: ${{ runner.OS }}-node_modules-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('.github/workflows/build_and_test.yml') }}

    - name: Cache meteor local
      uses: actions/cache@v1
      with:
        path: ./.meteor/local
        key: ${{ runner.OS }}-meteor_cache-${{ hashFiles('.meteor/versions') }}-${{ hashFiles('.github/workflows/build_and_test.yml') }}

    - name: Cache meteor
      uses: actions/cache@v1
      with:
        path: ~/.meteor
        key: ${{ runner.OS }}-meteor-${{ hashFiles('.meteor/release') }}-${{ hashFiles('.github/workflows/build_and_test.yml') }}

    - name: Use Node.js 12.18.4
      uses: actions/setup-node@v1
      with:
        node-version: "12.18.4"

    - name: Install Meteor
      run: |
        # Restore bin from cache
        set +e
        METEOR_SYMLINK_TARGET=$(readlink ~/.meteor/meteor)
        METEOR_TOOL_DIRECTORY=$(dirname "$METEOR_SYMLINK_TARGET")
        set -e
        LAUNCHER=$HOME/.meteor/$METEOR_TOOL_DIRECTORY/scripts/admin/launch-meteor
        if [ -e $LAUNCHER ]
        then
          echo "Cached Meteor bin found, restoring it"
          sudo cp "$LAUNCHER" "/usr/local/bin/meteor"
        else
          echo "No cached Meteor bin found."
        fi

        # only install meteor if bin isn't found
        command -v meteor >/dev/null 2>&1 || curl https://install.meteor.com | sed s/--progress-bar/-sL/g | /bin/sh

    - name: Versions
      run: |
        npm --versions
        node -v
        meteor --version
        meteor npm --versions
        meteor node -v
        git version
        echo $GITHUB_REF

    - name: npm install
      if: steps.cache-nodemodules.outputs.cache-hit != 'true'
      run: |
        meteor npm install

    # To reduce memory need during actual build, build the packages solely first
    # - name: Build a Meteor cache
    #   run: |
    #     # to do this we can clear the main files and it build the rest
    #     echo "" > server/main.js
    #     echo "" > client/main.js
    #     sed -i.backup 's/rocketchat:livechat/#rocketchat:livechat/' .meteor/packages
    #     meteor build --server-only --debug --directory /tmp/build-temp
    #     git checkout -- server/main.js client/main.js .meteor/packages

    - name: Build Rocket.Chat
      run: |
        meteor build --server-only --directory /tmp/build-pr

    - name: Build Docker image for PRs
      run: |
        cd /tmp/build-pr

        LOWERCASE_REPOSITORY=$(echo "${{ github.repository_owner }}" | tr "[:upper:]" "[:lower:]")
        IMAGE_NAME="ghcr.io/${LOWERCASE_REPOSITORY}/rocket.chat:pr-${{ github.event.number }}"

        echo "Build official Docker image ${IMAGE_NAME}"

        docker build -f $GITHUB_WORKSPACE/.docker/Dockerfile -t $IMAGE_NAME .
        docker push $IMAGE_NAME

  deploy:
    runs-on: ubuntu-latest
    if: github.event_name == 'release' || github.ref == 'refs/heads/develop'
    needs: test

    steps:
    - uses: actions/checkout@v2

    - name: Restore build
      uses: actions/download-artifact@v1
      with:
        name: build
        path: /tmp/build

    - name: Publish assets
      env:
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        GPG_PASSWORD: ${{ secrets.GPG_PASSWORD }}
        REDHAT_REGISTRY_PID: ${{ secrets.REDHAT_REGISTRY_PID }}
        REDHAT_REGISTRY_KEY: ${{ secrets.REDHAT_REGISTRY_KEY }}
        UPDATE_TOKEN: ${{ secrets.UPDATE_TOKEN }}
      run: |
        if [[ '${{ github.event_name }}' = 'release' ]]; then
          export CIRCLE_TAG="${GITHUB_REF#*tags/}"
          export CIRCLE_BRANCH=""
        else
          export CIRCLE_TAG=""
          export CIRCLE_BRANCH="${GITHUB_REF#*heads/}"
        fi;

        export CIRCLE_SHA1=$GITHUB_SHA
        export CIRCLE_BUILD_NUM=$GITHUB_SHA

        aws s3 cp s3://rocketchat/sign.key.gpg .circleci/sign.key.gpg

        source .circleci/setartname.sh
        source .circleci/setdeploydir.sh
        bash .circleci/setupsig.sh
        bash .circleci/namefiles.sh

        aws s3 cp $ROCKET_DEPLOY_DIR/ s3://download.rocket.chat/build/ --recursive

        bash .circleci/update-releases.sh
        # bash .circleci/snap.sh
        bash .circleci/redhat-registry.sh

  image-build:
    runs-on: ubuntu-latest
    needs: deploy

    strategy:
      matrix:
        release: ["official", "preview"]

    env:
      IMAGE: "rocketchat/rocket.chat"

    steps:
    - uses: actions/checkout@v2

    - name: Login to DockerHub
      uses: docker/login-action@v1
      with:
        username: ${{ secrets.DOCKER_USER }}
        password: ${{ secrets.DOCKER_PASS }}

    - name: Restore build
      uses: actions/download-artifact@v1
      with:
        name: build
        path: /tmp/build

    - name: Unpack build
      run: |
        cd /tmp/build
        tar xzf Rocket.Chat.tar.gz
        rm Rocket.Chat.tar.gz

        DOCKER_PATH="${GITHUB_WORKSPACE}/.docker"
        if [[ '${{ matrix.release }}' = 'preview' ]]; then
          DOCKER_PATH="${DOCKER_PATH}-mongo"
        fi;

        echo "Build ${{ matrix.release }} Docker image"
        cp ${DOCKER_PATH}/Dockerfile .
        if [ -e ${DOCKER_PATH}/entrypoint.sh ]; then
          cp ${DOCKER_PATH}/entrypoint.sh .
        fi;

    - name: Build Docker image for tag
      if: github.event_name == 'release'
      run: |
        cd /tmp/build
        CIRCLE_TAG="${GITHUB_REF#*tags/}"

        if [[ '${{ matrix.release }}' = 'preview' ]]; then
          IMAGE="${IMAGE}.preview"
        fi;

        docker build -t ${IMAGE}:$CIRCLE_TAG .
        docker push ${IMAGE}:$CIRCLE_TAG

        if echo "$CIRCLE_TAG" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$' ; then
          RELEASE="latest"
        elif echo "$CIRCLE_TAG" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$' ; then
          RELEASE="release-candidate"
        fi

        docker tag ${IMAGE}:$CIRCLE_TAG ${IMAGE}:${RELEASE}
        docker push ${IMAGE}:${RELEASE}

    - name: Build Docker image for develop
      if: github.ref == 'refs/heads/develop'
      run: |
        cd /tmp/build

        if [[ '${{ matrix.release }}' = 'preview' ]]; then
          IMAGE="${IMAGE}.preview"
        fi;

        docker build -t ${IMAGE}:develop .
        docker push ${IMAGE}:develop

  services-image-build:
    runs-on: ubuntu-latest
    needs: deploy

    strategy:
      matrix:
        service: ["account", "authorization", "ddp-streamer", "presence", "stream-hub"]

    steps:
    - uses: actions/checkout@v2

    - name: Use Node.js 12.18.4
      uses: actions/setup-node@v1
      with:
        node-version: "12.18.4"

    - name: Login to DockerHub
      uses: docker/login-action@v1
      with:
        username: ${{ secrets.DOCKER_USER }}
        password: ${{ secrets.DOCKER_PASS }}

    - name: Build Docker images
      run: |
        # defines image tag
        if [[ $GITHUB_REF == refs/tags/* ]]; then IMAGE_TAG="${GITHUB_REF#refs/tags/}"; else IMAGE_TAG="${GITHUB_REF#refs/heads/}"; fi

        # first install repo dependencies
        npm i

        # then micro services dependencies
        cd ./ee/server/services
        npm i
        npm run build

        echo "Building Docker image for service: ${{ matrix.service }}:${IMAGE_TAG}"

        docker build --build-arg SERVICE=${{ matrix.service }} -t rocketchat/${{ matrix.service }}-service:${IMAGE_TAG} .

        docker push rocketchat/${{ matrix.service }}-service
