Skip to content

Instantly share code, notes, and snippets.

@nguyenthanhcong101096
Last active May 3, 2020 10:59
Show Gist options
  • Save nguyenthanhcong101096/1847d0860a5830785bab27b4975ab395 to your computer and use it in GitHub Desktop.
Save nguyenthanhcong101096/1847d0860a5830785bab27b4975ab395 to your computer and use it in GitHub Desktop.
Circle CI

CI là gì?

  • CI là viết tắt của Continuous Integration (Tích hợp liên tục)
  • CI là phương pháp phát triển phần mềm đòi hỏi các thành viên trong nhóm phải tải code của họ lên kho lưu trữ thường xuyên, lý tưởng là nhiều lần trong ngày.
  • Mỗi lần họ làm, mã được xác minh bởi một bản dựng tự động, bộ kiểm tra chạy các công cụ phân tích mã tĩnh chuyên dụng kiểm tra các lỗ hổng bảo mật, lỗi và tất cả các loại không chính xác.
  • Điều này rất tốt cho cả nhóm giúp giảm bớt vấn đề và phát triển phần mềm nhanh hơn

Tại sao lại cần Continuous Integration?

Thông thường, các lập trình viên thường làm việc độc lập trong 1 thời gian dài và chỉ merge code vào nhánh master khi họ đã hoàn thành công việc. Chưa kể đến sau khi merge còn cần phải chờ review, có khi phải đợi đến vài ngày hay cả tuần. Điều này dẫn đến việc merge code gặp khó khăn, tiêu tốn nhiều thời gian, và đồng thời cũng tạo ra nhiều bugs, conflicts... khi mà code không được cập nhật trong thời gian dài.

CI giúp tìm ra bug ngay từ sớm trong quá trình phát triển, giúp việc sửa chữa tốn ít công sức hơn, từ đó cải thiện chất lượng phần mềm, giảm thời gian review code, đồng thời rút ngắn thời gian release các chức năng mới của sản phẩm. Việc test tự động được chạy với mỗi lần commit hay pull, đảm bảo nhánh master luôn trong trạng thái ổn định, không bug.

Cách thức hoạt động của Continuous Integration

Với continuos integration, lập trình viên thường sử dụng git để commit hay merge code của họ vào các central repo như GitHub, GitLab...

Trên hình là 1 workflow phổ biến của CI. Thường thì mình sẽ thêm 1 bước là chạy test tại local trước, kiểm tra thật kỹ code của mình, khi xác định không có lỗi thì mới push lên. Làm như vậy sẽ giảm số lần test trên server, vì CI được dùng chung cho cả team, tài nguyên có hạn, nếu quá nhiều build cùng lúc thì sẽ có người phải chờ, và tất nhiên là chẳng ai muốn phải chờ rồi đúng không . Hơn nữa việc đó cũng cho thấy bản thân là người cẩn thận, sẽ được đồng nghiệp đánh giá cao hơn . Sau khi push code lên, thông thường sẽ là gửi pull request vào nhánh master. Lúc này trên server sẽ tự động build và chạy test. Nếu như có lỗi xảy ra thì sẽ được thông báo cho các thành viên trong project, người chịu trách nhiệm cho pull đó ngay lập tức sửa code rồi push lên lần nữa, cứ lặp lại như vậy cho tới khi tất cả các test đều thành công. Tất nhiên đây chỉ là thông qua các test case đã được viết trước, còn về logic của đoạn code thì vẫn cần có người review, nếu ok thì lúc đó mới được merge vào nhánh master.

Các bước connect CircleCI với github

Bước 1: Tạo một repository trên github.

  • Sau đó bạn clone repository về máy bằng lệnh

  • git clone YOUR_REPOSITORY_URL

Bước 2: Tạo tài khoản CircleCI được liên kết với Github

Thực hiện theo các hướng dẫn bên dưới để tạo tài khoản CircleCI được liên kết với tài khoản Github và để thiết lập CI cho dự án Ruby on Rails.

  • Trên trang ủy quyền cho CircleCI , nhấp vào "Authorize CircleCI".

Bạn sẽ được chuyển hướng đến bảng điều khiển CircleCI, Trong tab dự án, chọn "Add projects".

Bước 3: Tạo file cấu hình CircleCI

Trong thư mục gốc của dự án, tạo tệp cấu hình CircleCI.

cd path/to/your/project/root
mkdir .circleci
touch .circleci / config.yml

Mở tệp cấu hình CircleCI, Mình sẽ config với MySQL, RSpec, RuboCop, Brakeman, Rails Best Practices

Ruby on Rails với MySQL trên CircleCI

MySQL là lựa chọn phổ biến thứ hai cho các ứng dụng Ruby on Rails, chỉ sau PostgreSQL.

Để CircleCI hoạt động, bạn sẽ cần một thiết lập cụ thể trong tệp config/database.yml. Lưu ý rằng dotenv-rails gem được sử dụng.

config/database.yml

default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV['DB_POOL'] %>
  username: <%= ENV['DB_USERNAME'] %>
  password: <%= ENV['DB_PASSWORD'] %>
  host: <%= ENV['DB_HOST'] %>
  port: 3306

development:
  <<: *default
  database: connect_circleci_demo_development

test:
  <<: *default
  database: connect_circleci_demo_test

production:
  <<: *default
  database: connect_circleci_demo_production

.circleci/config.yml

# Ruby CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-ruby/ for more details
#
version: 2
jobs:
  build:
    parallelism: 1
    working_directory: ~/Documents/project/app
    docker:
       - image: circleci/ruby:2.6.5-node
         environment:
           PGHOST: 127.0.0.1
           PGUSER: app
           RAILS_ENV: test
       - image: circleci/postgres:10-alpine-ram
         environment:
           POSTGRES_USER: app
           POSTGRES_DB: test_coding_test
           POSTGRES_PASSWORD: ''
       - image: redis
       - image: circleci/node:8.11-browsers

    steps:
      - checkout

      - run:
          name: Update Node.js
          command: |
            curl -sSL "https://nodejs.org/dist/v10.16.0/node-v10.16.0-linux-x64.tar.xz" | sudo tar --strip-components=2 -xJ -C /usr/local/bin/ node-v10.16.0-linux-x64/bin/node

      # Download and cache dependencies
      - restore_cache:
          keys:
          - app-v1-dependencies-{{ checksum "Gemfile.lock" }}
          # fallback to using the latest cache if no exact match is found
          - app-v1-dependencies-
      - run:
          name: Install Rails Dependencies
          command: |
            bundle install --jobs=4 --retry=3 --path vendor/bundle
      - save_cache:
          paths:
            - ./vendor/bundle
          key: app-v1-dependencies-{{ checksum "Gemfile.lock" }}

      - restore_cache:
          name: Restore Yarn Package Cache
          keys:
            - yarn-packages-{{ .Branch }}-{{ checksum "yarn.lock" }}
            - yarn-packages-{{ .Branch }}
            - yarn-packages-master
            - yarn-packages-
      - run:
          name: Install Dependencies
          command: |
            yarn install

      - save_cache:
          name: Save Yarn Package Cache
          key: yarn-packages-{{ .Branch }}-{{ checksum "yarn.lock" }}
          paths:
            - node_modules/
      
      # Database setup  
      - run:  
        name: Set up DB  
        command: |  
          bundle exec rake db:create 
          bundle exec rake db:migrate  
      
      # - run: bundle exec rake db:create
      # - run: bundle exec rake db:schema:load

      # Run rubocop  
      - run:  
        name: Run rubocop  
        command: bundle exec rubocop
        
      # run tests!
      - run:
          name: run tests
          command: |
            mkdir /tmp/test-results
            bundle exec rspec --format progress \
                              --format RspecJunitFormatter \
                              --out /tmp/test-results/rspec.xml \
                              --format progress \
                              spec

      # collect reports
      - store_test_results:
          path: /tmp/test-results
      - store_artifacts:
          path: /tmp/test-results
          destination: test-results

Mình sẽ giải thích từng phần để các bạn dễ hình dung nhé .

version: version của CircleCI, hiện nay đã ra tới 2.1 nhưng trong project của mình vẫn là 2 thôi, chưa có thời gian update mà

jobs: các job cần phải thực hiện mỗi khi build trên CircleCI.

build: tên job.

docker: là executor, nói đơn giản là nơi để thực hiện các job. Có 3 loại executor khác nhau: docker, machine và macos.

image: tên image sẽ được sử dụng trong docker, và những image này được lấy từ dockerhub. Trong nddblog mình sử dụng 2 image là ruby - dùng để chạy project và postgres - dùng để lưu trữ dữ liệu.

environment: các biến môi trường của từng image. RAILS_ENV cài đặt môi trường rails trên CircleCI là test. POSTGRES_USER cài đặt username cho database. Lưu ý username ở đây và trong file config/database.yml phải giống nhau.

working_directory: thư mục lưu trữ source code. steps: các bước thực hiện trong job.

checkout: lấy code của nhánh đang build từ github hoặc bitbucket về.

restore_cache: restore các dependencies đã được cache từ lần build trước nếu có.

run: thực hiện các command line. Trong file mình có 4 lệnh run lần lượt là cài đặt các dependencies, tạo vào migrate database, chạy test rubocop và chạy rspec test. Nếu các bạn cần chạy lệnh nào khác có thể thêm thoải mái.

save_cache: lưu cache lại các dependencies.

store_test_results: lưu các kết quả test ra file để hiển thị trên CircleCI.

store_artifacts: lưu các kết quả của artifacts ra file để hiển thị trên CircleCI (artifacts là các file như file ảnh, logs, coverage reports....).

Trên đây mình đã giải thích những key quan trọng cần có của 1 file config.yml. Dựa vào đó chắc hẳn các bạn đã có thể tạo ra file riêng cho project của mình rồi nhỉ . Sau khi đã thêm file config.yml vào project thì hãy commit và push file đó lên repo của mình

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment