Gitlab CI và một ví dụ với dự án Laravel

Tram Ho

Giới thiệu

Trong bài viết này, chúng ta sẽ tìm hiểu về hệ thống CI trên gitlab.com và tích hợp vào một project Laravel để tự động quá trình build, test pull request: check convention, chạy phpunit… Các cấu hình cơ bản, cách optimze để tăng tốc quá trình build…

Luồng hoạt động

Để bắt đầu, chúng ta sẽ tạo một repository trên gitlab.com và khởi tạo Laravel 6.0:

Flow cơ bản của CI:

Cụ thể hơn, ở bài này chúng ta sẽ cần chạy phpcsphpunit để test pull request:

  • phpcs để đảm bảo convention
  • phpunit để chạy unit test

Định nghĩa Job

Sau bước init, tiếp theo chúng ta sẽ tiến hành config để chạy Gitlab CI bằng cách tạo .gitlab-ci.yml và push file này lên repository, Gitlab sẽ đọc và thực hiện các câu lệnh theo chỉ dẫn trong file này.

Bắt đầu bằng file config đơn giản như sau:

Gitlab CI sẽ chạy test trong một Docker container và dòng config đầu tiên chính là để khai báo Docker image dùng để tạo container.

Image chúng ta sử dụng ở đây là framgia/laravel-workspace.

Các dòng còn lại dùng để định nghĩa 1 job.

Mỗi khi có sự kiện push lên repository, Gitlab CI sẽ tạo ra 1 pipeline, 1 pipeline bao gồm 1 hoặc nhiều job và các job chạy song song và độc lập với nhau.

Dựa vào tính năng này chúng ta có thể tăng tốc quá trình chạy CI bằng các tách ra các job riêng biệt để chạy song song.

Với mục đích để test cách hoạt động của Gitlab CI, mình định nghĩa 1 job gọi là list-files chỉ đơn giản là để xem câu lệnh được CI chạy trong thư mục nào, các bạn có thể xem kết quả chạy CI ở đây:

Ok, có thể thấy Gitlab thực hiện fetch code từ commit (pull request, branch) vào một thư mục và thực hiện chạy lệnh trong thư mục này.

PHPCS và PHPUnit

Bây giờ chúng ta sẽ thực hiện config để chạy phpcs, thay đổi file config như sau:

phpcs và standard Framgia đã được cài sẵn trong docker image framgia/laravel-workspace

Lần này thì có 2 job được define và khi push lên chúng ta sẽ có 2 job được chạy song song:

Các bạn có thể thấy 1 job có thể chạy nhiều lệnh như pwdls -a, nhưng các lệnh này là chạy tuần tự, tức là lệnh này chạy xong thì mới chạy lệnh tiếp theo. Khác với các job có thể chạy song song. Vì thế khi các lệnh không phụ thuộc vào nhau, chúng ta có thể tách ra thành job riêng biệt để tăng tốc quá trình build. Tuy nhiên, cũng phải hạn chế tạo quá nhiều job để tiết kiệm tài nguyên server.

Chẳng hạn với Laravel (PHP) chúng ta thường chạy các Static Code Analyse Tools như phpcs, phpmd, phpcpd, phpmetrics, phpstan và unit test phpunit. Ở đây chúng ta focus vào 2 tools là phpcsphpunit, để chạy được phpunit thì chúng ta cần phải cài composer dependencies, nếu có integration test thì cần phải chạy npm nữa, còn phpcs thì không. Do đó ở đây chúng ta sẽ define ra 2 job riêng biệt. Update ci config như sau:

Vì thường có cả unit test và integration test nên cần phải generate key và install npm dependency.

Thêm một bước nữa để Gitlab CI hiển thị code coverage report, theo như screenshot dưới đây:

Khi chạy job phpunit, Gitlab CI sẽ parse output để lấy ra coverage % (dòng Lines: 41.82% (23/55)):

Và kết quả sẽ được hiển thị trên tab Jobs của pipeline detail:

Hoặc có thể hiển thị bằng markdown:
coverage report

Optimize

phpcs

PHPCS là công cụ để đảm bảo convention của dự án, do đó các cấu hình cũng nên được đảm bảo giống nhau giữa các developer, tức là phải có 1 file config chung cho cả dự án. Chẳng hạn, mặc định chúng ta muốn check convention ở 3 folder app/, config/resources/lang hoặc muốn ignore các warning (VD: độ dài dòng code vượt quá 120 ký tự thì chỉ báo warning và coi như không ảnh hưởng đến kết quả build cuối cùng là failed hay success)…
Và PHPCS cũng hỗ trợ file cấu hình như thế, mặc định là phpcs.xml. Chúng ta tiến hành thêm file phpcs.xml và update ci config:

Gitlab CI hay developer chỉ cần chạy phpcs là tool sẽ tự động đọc file config và thực hiện test mà không cần phải các tham số như --standard hay đường dẫn đến folder code.

phpunit

Xem lại các câu lệnh cần thiết khi chạy phpunit:

Câu lệnh đầu tiên là để tạo file .env riêng biệt khi thực hiện unit test. Tuy nhiên, có thể bạn chưa biết là các biến env có thể được khai báo bên trong file phpunit.xml, ví dụ như mặc định của laravel:

=> Có thể bỏ việc khai báo env cho môi trường test bằng file .env mà khai báo trực tiếp trong file phpunit.xml để đồng bộ và không phải mất công sử dụng PHP DotEnv để load file env.

Câu lệnh key generate dùng để khi thực hiện integration test, tuy nhiên khi test thì không cần phải generate lại key, vì thế chúng ta có thể config 1 key cố định trong file phpunit.xml luôn:

Các bạn có thể tắt chế độ debug, sử dụng SQlite in-memory DB để tăng tốc quá trình chạy test.

Ngoài ra, còn có 1 step optimize nhỏ nữa là bỏ color ouput của phpunit với tham số --colors=never.

Tiếp theo là lệnh install npm packages và chạy Laravel Mix, khi xem log của CI bạn có thể thấy nó có 1 loạt output không cần thiết:

Điều này là do Laravel Mix output ra progress của quá trình build assets (tham số --progress, xem file package.json):

Mặc dù nó có ích khi chạy trên máy dev nhưng với CI thì nó không cần thiết và làm chậm quá trình chạy, vì thế ta có thể bỏ progress output bằng cách thêm 1 lệnh npm khác:

Và update ci config:

Caching

Command composer install cài dependencies vào folder vendor/ và command yarn install tạo ra thư mục node_modules. Hầu hết các file trong 2 folder này đều không thay đổi trừ khi có update package hay cài đặt thêm package. Vì thế chúng ta có thể cache lại 2 folder này, khi có mặt 2 folder này thì các command kia có thể sử dụng cache thay vì phải download và cài các package lại từ đầu.

Thêm nữa, các file composer.lockyarn.lock hoặc (package-lock.json nếu không dùng yarn) cũng nên được push lên repository để tăng tốc chạy composer hay yarn (npm).

Update file ci config và thêm cache:

Khi chạy CI sẽ có output dạng như sau:

Conditional build

Dự án của bạn có thể áp dụng git flow: disable fork, tất cả thành viên sẽ push feature lên branch trong repository chính duy nhất và tạo pull request; repo có 2 branch đặc biệt là developmaster. Với CI config như trên thì cứ mỗi lần dev push commit lên repo thì CI sẽ chạy, điều này gây lãng phí tài nguyên, do có thể dev vẫn chưa hoàn thiện feature branch và chỉ đẩy lên để save, vì thế cần phải config cho CI chỉ chạy khi có pull request mới hoặc có push lên 2 branch đặc biệt là developmaster (để kích hoạt deploy chẳng hạn).

Gitlab CI cũng support để config trong trường hợp này:

Với từ khóa only chúng ta có thể khai báo tên branch hoặc một số từ khóa đặc biệt (merge_requests).

Tổng kết

Bài viết giới thiệu cơ bản về Gitlab CI và áp dụng để build và test Laravel app. Trong bài tiếp theo, chúng ta cùng tìm hiểu về auto deploy cùng Gitlab CI/CD. Cảm ơn các bạn đã theo dõi.

Chia sẻ bài viết ngay

Nguồn bài viết : Viblo