name: Appsmith Client Workflow 

on:
  push:
    branches: [ release, master ]
    # Only trigger if files have changed in this specific path
    paths:
      - 'app/client/**'
  pull_request_target:
    branches: [ release, master ]
    paths:
      - 'app/client/**'
# Change the working directory for all the jobs in this workflow
defaults:
  run:
    working-directory: app/client

jobs:
  build:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: app/client

    steps:
    # Checkout the code
    - name: Checkout the merged commit from PR and base branch
      if: ${{ github.event_name == 'pull_request_target' }}
      uses: actions/checkout@v2
      with:
        ref: refs/pull/${{ github.event.pull_request.number }}/merge

    - name: Checkout the head commit of the branch
      if: ${{ github.event_name == 'push' }}
      uses: actions/checkout@v2

    - name: Figure out the PR number
      run: echo ${{ github.event.pull_request.number }}

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

    # Retrieve npm dependencies from cache. After a successful run, these dependencies are cached again
    - name: Cache npm dependencies
      uses: actions/cache@v2
      env:
        cache-name: cache-yarn-dependencies
      with:
        # npm dependencies are stored in `~/.npm` on Linux/macOS
        path: ~/.npm
        key: ${{ runner.OS }}-node-${{ hashFiles('**/yarn.lock') }}
        restore-keys: |
            ${{ runner.OS }}-node-
            ${{ runner.OS }}-

    # Install all the dependencies
    - name: Install dependencies
      run: yarn install
    
    - name: Set the build environment based on the branch
      id: vars
      run: |
        REACT_APP_ENVIRONMENT="DEVELOPMENT"  
        if [ ${GITHUB_REF} == '/refs/heads/master' ]; then
            REACT_APP_ENVIRONMENT="PRODUCTION"
        elif [ ${GITHUB_REF} == '/refs/heads/release' ]; then
            REACT_APP_ENVIRONMENT="STAGING"
        fi
        echo ::set-output name=REACT_APP_ENVIRONMENT::${REACT_APP_ENVIRONMENT}

    - name: Run the jest tests
      run: REACT_APP_ENVIRONMENT=${{steps.vars.outputs.REACT_APP_ENVIRONMENT}} yarn run test:unit

    - name: Create the bundle
      run: REACT_APP_ENVIRONMENT=${{steps.vars.outputs.REACT_APP_ENVIRONMENT}} yarn build

    # Upload the build artifact so that it can be used by the test & deploy job in the workflow
    - name: Upload react build bundle
      uses: actions/upload-artifact@v2
      with:
        name: build
        path: app/client/build/

  ui-test:
    needs: build
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: app/client
    strategy:
      fail-fast: false
      matrix:
        job: [0, 1, 2, 3, 4, 5, 6]
    # Service containers to run with this job. Required for running tests
    services:
      # Label used to access the service container
      redis:
        # Docker Hub image for Redis
        image: redis
        ports:
          # Opens tcp port 6379 on the host and service container
          - 6379:6379
      mongo:
        image: mongo
        ports: 
          - 27017:27017
      # This is required in Cypress tests that test the datasource integrations
      postgres:
        image: postgres
        ports: 
          - 5432:5432
        env:
          POSTGRES_PASSWORD: postgres
        # Set health checks to wait until postgres has started
        # Also initialize the docker container with data
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
          --name postgres
          -v ${{ github.workspace }}/app/client/cypress/init-pg-dump-for-test.sql:/docker-entrypoint-initdb.d/init-pg-dump-for-test.sql
      
    steps:
    # Checkout the code
    - name: Checkout the merged commit from PR and base branch
      if: ${{ github.event_name == 'pull_request_target' }}
      uses: actions/checkout@v2
      with:
        ref: refs/pull/${{ github.event.pull_request.number }}/merge

    - name: Checkout the head commit of the branch
      if: ${{ github.event_name == 'push' }}
      uses: actions/checkout@v2

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

    # Retrieve npm dependencies from cache. After a successful run, these dependencies are cached again
    - name: Cache npm dependencies
      uses: actions/cache@v2
      env:
        cache-name: cache-yarn-dependencies
      with:
        # maven dependencies are stored in `~/.m2` on Linux/macOS
        path: ~/.npm
        key: ${{ runner.OS }}-node-${{ hashFiles('**/yarn.lock') }}
        restore-keys: |
            ${{ runner.OS }}-node-
            ${{ runner.OS }}-

    # Install all the dependencies
    - name: Install dependencies
      run: yarn install
  
    - name: Download the react build artifact
      uses: actions/download-artifact@v2
      with:
        name: build
        path: app/client/build
      
    - name: Pull release server docker container and start it locally
      if: github.ref == 'refs/heads/release'
      shell: bash
      run: |
        echo ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} | docker login -u ${{ secrets.DOCKER_HUB_USERNAME }} --password-stdin
        
        docker run -d --net=host --name appsmith-internal-server -p 8080:8080 \
        --env APPSMITH_MONGODB_URI=mongodb://localhost:27017/appsmith \
        --env APPSMITH_REDIS_URL=redis://localhost:6379 \
        --env APPSMITH_ENCRYPTION_PASSWORD=password \
        --env APPSMITH_ENCRYPTION_SALT=salt \
        --env APPSMITH_IS_SELF_HOSTED=false \
        appsmith/appsmith-server:release
  
    - name: Pull master server docker container and start it locally
      if: github.ref == 'refs/heads/master'
      shell: bash
      run: |
        echo ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} | docker login -u ${{ secrets.DOCKER_HUB_USERNAME }} --password-stdin
        
        docker run -d --net=host --name appsmith-internal-server -p 8080:8080 \
        --env APPSMITH_MONGODB_URI=mongodb://localhost:27017/appsmith \
        --env APPSMITH_REDIS_URL=redis://localhost:6379 \
        --env APPSMITH_ENCRYPTION_PASSWORD=password \
        --env APPSMITH_ENCRYPTION_SALT=salt \
        --env APPSMITH_IS_SELF_HOSTED=false \
        appsmith/appsmith-server:nightly

    - name: Installing Yarn serve
      run: |
        yarn global add serve
        echo "$(yarn global bin)" >> $GITHUB_PATH 

    - name: Setting up the cypress tests
      shell: bash
      env:
        APPSMITH_SSL_CERTIFICATE: ${{ secrets.APPSMITH_SSL_CERTIFICATE }}
        APPSMITH_SSL_KEY: ${{ secrets.APPSMITH_SSL_KEY }}
        CYPRESS_URL: ${{ secrets.CYPRESS_URL }}
        CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }}
        CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }}
        CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }}
        CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD1 }}
        CYPRESS_TESTUSERNAME2: ${{ secrets.CYPRESS_TESTUSERNAME2 }}
        CYPRESS_TESTPASSWORD2: ${{ secrets.CYPRESS_TESTPASSWORD1 }}
        POSTGRES_PASSWORD: postgres
      run: |
        ./cypress/setup-test.sh
        
    - name: Run the cypress test
      uses: cypress-io/github-action@v2
      env: 
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
        CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }}
        CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }}
        CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }}
        CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }}
        CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD1 }}
        CYPRESS_TESTUSERNAME2: ${{ secrets.CYPRESS_TESTUSERNAME2 }}
        CYPRESS_TESTPASSWORD2: ${{ secrets.CYPRESS_TESTPASSWORD1 }}
        COMMIT_INFO_MESSAGE: ${{ github.event.pull_request.title }}
      with:
        browser: chrome
        headless: true
        record: true
        install: false
        parallel: true
        group: 'Electrons on Github Action'
        spec: 'cypress/integration/Smoke_TestSuite/*/*'
        working-directory: app/client
        # tag will be either "push" or "pull_request_target"
        tag: ${{ github.event_name }}

    # Upload the screenshots as artifacts if there's a failure
    - uses: actions/upload-artifact@v1
      if: failure()
      with:
        name: cypress-screenshots-${{ matrix.job }}
        path: app/client/cypress/screenshots/

  package:
    needs: ui-test
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: app/client
    # Run this job only if all the previous steps are a success and the reference if the release or master branch
    if: always() && (github.ref == 'refs/heads/release' || github.ref == 'refs/heads/master')

    steps:
    
    # Checkout the code
    - name: Checkout the merged commit from PR and base branch
      if: ${{ github.event_name == 'pull_request_target' }}
      uses: actions/checkout@v2
      with:
        ref: refs/pull/${{ github.event.pull_request.number }}/merge

    - name: Checkout the head commit of the branch
      if: ${{ github.event_name == 'push' }}
      uses: actions/checkout@v2
  
    - name: Download the react build artifact
      uses: actions/download-artifact@v2
      with:
        name: build
        path: app/client/build
    
    # Here, the GITHUB_REF is of type /refs/head/<branch_name>. We extract branch_name from this by removing the
    # first 11 characters. This can be used to build images for several branches
    - name: Get the version to tag the Docker image
      id: branch_name
      run: echo ::set-output name=tag::$(echo ${GITHUB_REF:11})

    # Build release Docker image and push to Docker Hub
    - name: Push release image to Docker Hub
      if: success() && github.ref == 'refs/heads/release' && github.event_name == 'push'
      run: |
        docker build -t appsmith/appsmith-editor:${{steps.branch_name.outputs.tag}} .
        echo ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} | docker login -u ${{ secrets.DOCKER_HUB_USERNAME }} --password-stdin
        docker push appsmith/appsmith-editor
    
    # Build master Docker image and push to Docker Hub
    - name: Push production image to Docker Hub with commit tag
      if: success() && github.ref == 'refs/heads/master' && github.event_name == 'push'
      run: |
        docker build -t appsmith/appsmith-editor:${GITHUB_SHA} .
        docker build -t appsmith/appsmith-editor:nightly .
        echo ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} | docker login -u ${{ secrets.DOCKER_HUB_USERNAME }} --password-stdin
        docker push appsmith/appsmith-editor