1. Trong rails

version: 2

jobs:
  test:
    docker:
      - image: circleci/ruby:2.6.0-node
        environment:
          BUNDLE_JOBS: 3
          BUNDLE_RETRY: 3
          BUNDLE_PATH: vendor/bundle
          RAILS_ENV: test
          RACK_ENV: test
      - image: circleci/postgres:9.6-ram
        environment:
          POSTGRES_USER: test
          POSTGRES_DB: test
          POSTGRES_PASSWORD: ""
      - image: redis

    steps:
      - checkout

      # Which version of bundler?
      - run:
          name: Which bundler?
          command: bundle -v

      # Restore bundle cache
      - restore_cache:
          keys:
            - project-v1-{{ checksum "Gemfile.lock" }}
            - project-v1-

      - run:
          name: Bundle Install
          command: bundle check || bundle install

      # Store bundle cache
      - save_cache:
          key: project-v1-{{ checksum "Gemfile.lock" }}
          paths:
            - vendor/bundle

      - run:
          name: Wait for DB
          command: dockerize -wait tcp://localhost:5432 -timeout 1m

      - run: |-
          mkdir -p config && echo 'test:
            adapter: postgresql
            database: test
            username: test
            host: 127.0.0.1
          ' > config/database.yml

      - run:
          name: Prepare DB
          command: bundle exec rake db:create db:schema:load --trace

      - store_artifacts:
          path: coverage


  deploy_ssh:
    docker:
      - image: circleci/ruby:2.6-node

    steps:
      - add_ssh_keys:
          fingerprints:
            - "a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1"

      - run:
          name: Deploy
          command: |
            ssh -o StrictHostKeyChecking=no [email protected] deploy.sh "$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME" $CIRCLE_BRANCH $CIRCLE_SHA1

workflows:
  version: 2

  test-deploy:
    jobs:
      - test
      - deploy_ssh:
          requires:
            - test
          filters:
            branches:
              only:
                - deploy_test
                - develop
                - master

 

2. React

version: 2
jobs:
  test:
    docker:
      # 3.6.5-stretch-node has NodeJS 8.11.1 and yarn 1.5.1 installed
      - image: circleci/python:3.6.5-stretch-node
    working_directory: ~/project/
    steps:
      - checkout
      - save_cache:
          key: v1-repo-{{ .Environment.CIRCLE_SHA1 }}
          paths: ~/project/
      - restore_cache:
          key: v1-node-build-deps-{{ .Branch }}
      - run:
          name: Install node dependencies
          command: npm install --no-progress
      - save_cache:
          key: v1-node-build-deps-{{ .Branch }}
          paths:
            - "~/project/node_modules"
      - run:
          name: Run tests and coverage
          command: npm run test-coverage

  deploy:
    docker:
      - image: circleci/python:3.6.5-stretch-node
    working_directory: ~/project/
    steps:
      - restore_cache:
          key: v1-repo-{{ .Environment.CIRCLE_SHA1 }}
      - restore_cache:
          key: v1-node-build-deps-{{ .Branch }}
      - run:
          name: Prepare environment variables
          command: |
            commit_msg=$(git log -n 1 --pretty=format:"%B" ${CIRCLE_SHA1})
            if [[ $commit_msg = *"__DEPLOY_TO_PRODUCTION__"* ]]; then
              CONTAINS_PRODUCTION_DEPLOY=1
            else
              CONTAINS_PRODUCTION_DEPLOY=0
            fi

            case $CIRCLE_BRANCH in
            "master")
              if [[ $CONTAINS_PRODUCTION_DEPLOY = "1" ]]; then
                DEPLOY_ENV=production
              else
                DEPLOY_ENV=staging
              fi
              ;;
            "develop")
              DEPLOY_ENV=dev
              ;;
            *)
            esac

            echo "export CONTAINS_PRODUCTION_DEPLOY=\"${CONTAINS_PRODUCTION_DEPLOY}\"" | tee -a "$BASH_ENV"
            echo "export DEPLOY_ENV=\"${DEPLOY_ENV}\"" | tee -a "$BASH_ENV"

            case $DEPLOY_ENV in
            "production")
              CF_DISTRIBUTION_ID=ABCDEFGHJIK

              NPM_ENV='production'
              REACT_APP_SENTRY_DSN_URL='https://[email protected]/12345678'
              REACT_APP_ENV='production'
              ;;
            "staging")
              CF_DISTRIBUTION_ID=ABCDEFGHJIK

              NPM_ENV='staging'
              REACT_APP_SENTRY_DSN_URL='https://[email protected]/123456'
              REACT_APP_ENV='staging'
              ;;
            "dev")
              CF_DISTRIBUTION_ID=ABCDEFGHJIK

              NPM_ENV='dev'
              REACT_APP_SENTRY_DSN_URL='https://[email protected]/123456'
              REACT_APP_ENV='dev'
              ;;
            *)
            esac

            echo "export CF_DISTRIBUTION_ID=\"${CF_DISTRIBUTION_ID}\"" | tee -a "$BASH_ENV"
            echo "export S3_DIRECTORY=\"s3://bucket-name-${DEPLOY_ENV}\"" | tee -a "$BASH_ENV"

            echo "export NPM_ENV=\"${NPM_ENV}\"" | tee -a "$BASH_ENV" 
            echo "export REACT_APP_SENTRY_DSN_URL=\"${REACT_APP_SENTRY_DSN_URL}\"" | tee -a "$BASH_ENV"
            echo "export REACT_APP_ENV=\"${REACT_APP_ENV}\"" | tee -a "$BASH_ENV"

            source "$BASH_ENV"
      - restore_cache:
          key: v1-deploy-deps-{{ .Branch }}
      - run:
          name: Install deployment Python deps in venv
          command: |
            python3 -m venv venv
            . venv/bin/activate
            pip install awscli
      - save_cache:
          key: v1-deploy-deps-{{ .Branch }}
          paths:
            - "~/project/venv"
      - run:
          name: Build
          command: |
            CI=false npm run build:${NPM_ENV}
      - run:
          name: Deploy to S3
          command: |
            . venv/bin/activate

            echo "> Removing old files..."
            aws s3 rm "${S3_DIRECTORY}"/project-rollback/ --recursive

            echo "> Creating rollback..."
            aws s3 cp "${S3_DIRECTORY}"/project/ "${S3_DIRECTORY}"/projtect-rollback/ --recursive

            echo "> Uploading new files..."
            aws s3 sync ./build "${S3_DIRECTORY}"/project/ --delete --exact-timestamps

            echo "> Creating CloudFront invalidation"
            aws cloudfront create-invalidation --distribution-id "$CF_DISTRIBUTION_ID" --paths "/project/*"

workflows:
  version: 2
  test-and-deploy:
    jobs:
      - test
      - deploy:
          requires:
            - test
          filters:
            branches:
              only:
                - develop
                - master