CI/CD cho PHP 8.4 với PHPStan, PHPUnit và Semantic Release trên GitLab
Mục tiêu
Xây dựng một dự án PHP 8.4 thuần (không sử dụng framework) với các thành phần:
- CI/CD trên GitLab
- Kiểm tra chất lượng code bằng PHPStan
- Unit Test bằng PHPUnit
- Tự động tạo version và release bằng Semantic Release
- Tự động sinh CHANGELOG.md
- Tự động tạo GitLab Release và Git Tag
1. Cấu trúc dự án
project/
├── src/
├── tests/
├── composer.json
├── phpstan.neon
├── phpunit.xml
├── .gitlab-ci.yml
├── .releaserc.json
└── package.json
2. Cài đặt Composer
composer.json
{
"name": "yourname/project",
"require": {
"php": "^8.4"
},
"require-dev": {
"phpunit/phpunit": "^11.0",
"phpstan/phpstan": "^1.11"
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
},
"scripts": {
"test": "phpunit",
"stan": "phpstan analyse"
}
}
Cài đặt dependencies:
composer install
3. Cấu hình PHPStan
phpstan.neon
parameters:
level: 6
paths:
- src
- tests
tmpDir: var/cache/phpstan
Giải thích
| Cấu hình | Mô tả |
|---|---|
| level | Mức độ kiểm tra code |
| paths | Các thư mục cần phân tích |
| tmpDir | Thư mục cache |
Khuyến nghị: Khi codebase đã ổn định có thể nâng level lên 8 hoặc 9.
4. Cấu hình PHPUnit
phpunit.xml
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/11.0/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true">
<testsuites>
<testsuite name="Unit">
<directory>tests</directory>
</testsuite>
</testsuites>
<source>
<include>
<directory>src</directory>
</include>
</source>
<coverage>
<report>
<clover outputFile="coverage.xml"/>
</report>
</coverage>
</phpunit>
5. Cấu hình GitLab CI/CD
.gitlab-ci.yml
Pipeline gồm 3 stage:
install
↓
test
↓
release
Cấu hình đầy đủ
stages:
- install
- test
- release
image: php:8.4-cli
variables:
COMPOSER_CACHE_DIR: "$CI_PROJECT_DIR/.composer-cache"
cache:
key: ${CI_COMMIT_REF_SLUG}-composer
paths:
- .composer-cache/
- vendor/
before_script:
- apt-get update -yqq
- apt-get install -yqq git unzip libzip-dev
- docker-php-ext-install zip
- curl -sS https://getcomposer.org/installer | php --
--install-dir=/usr/local/bin --filename=composer
install:
stage: install
script:
- composer install --prefer-dist --no-progress
phpstan:
stage: test
script:
- composer install --prefer-dist --no-progress
- vendor/bin/phpstan analyse --no-progress
--error-format=gitlab > phpstan-report.json || vendor/bin/phpstan analyse --no-progress
artifacts:
reports:
codequality: phpstan-report.json
when: always
phpunit:
stage: test
script:
- composer install --prefer-dist --no-progress
- vendor/bin/phpunit --coverage-text --colors=never
coverage: '/^\s*Lines:\s*\d+.\d+\%/'
artifacts:
reports:
junit: coverage.xml
when: always
semantic-release:
stage: release
image: node:20-alpine
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
script:
- npm install --no-save semantic-release
- npm install --no-save @semantic-release/gitlab
- npm install --no-save @semantic-release/git
- npm install --no-save @semantic-release/changelog
- npm install --no-save @semantic-release/commit-analyzer
- npm install --no-save @semantic-release/release-notes-generator
- npx semantic-release
6. Cấu hình Semantic Release
.releaserc.json
{
"branches": ["main"],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
[
"@semantic-release/changelog",
{
"changelogFile": "CHANGELOG.md"
}
],
[
"@semantic-release/gitlab",
{
"gitlabUrl": "https://gitlab.com"
}
],
[
"@semantic-release/git",
{
"assets": [
"CHANGELOG.md"
],
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
}
]
]
}
Cài thêm plugin:
npm install --no-save @semantic-release/git
7. Cấu hình GitLab Variables
Vào:
Settings
└── CI/CD
└── Variables
Tạo biến:
| Variable | Giá trị | Mục đích |
|---|---|---|
| GITLAB_TOKEN | Personal Access Token hoặc Project Access Token | Cho phép Semantic Release tạo tag, release và push commit |
| CI_REGISTRY | Có sẵn | Sử dụng nếu cần build/push Docker image |
Quyền cần cấp cho GITLAB_TOKEN
api
write_repository
8. Quy tắc Commit Message
Semantic Release hoạt động dựa trên chuẩn Conventional Commits.
Patch Release (x.x.1)
fix: sửa lỗi validate email
fix: xử lý null pointer
Minor Release (x.1.0)
feat: thêm API đăng nhập
feat: thêm export excel
Major Release (1.0.0 → 2.0.0)
feat!: thay đổi cấu trúc API
BREAKING CHANGE: endpoint response changed
Không tạo Release
docs: cập nhật tài liệu
test: bổ sung unit test
chore: cập nhật dependencies
style: format code
9. Kiểm tra Local trước khi Push
Cài dependencies
composer install
Chạy PHPStan
vendor/bin/phpstan analyse
Chạy PHPUnit
vendor/bin/phpunit
Kiểm tra Semantic Release
npx semantic-release --dry-run
Lệnh này giúp xem trước version sẽ được tạo mà không thực hiện release thật.
10. Luồng hoạt động sau khi Push Code
Developer Push Code
↓
GitLab Pipeline
↓
Install Dependencies
↓
PHPStan Analysis
↓
PHPUnit Testing
↓
Semantic Release
↓
Create Git Tag
↓
Generate CHANGELOG
↓
Create GitLab Release
11. Các lưu ý quan trọng
1. PHPStan Level
level: 6
Đây là mức kiểm tra trung bình.
Khuyến nghị:
| Level | Mức độ |
|---|---|
| 6 | Trung bình |
| 8 | Nghiêm ngặt |
| 9 | Rất nghiêm ngặt |
2. Release chỉ chạy trên branch main
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
Điều này giúp tránh việc tạo release từ các branch feature hoặc develop.
3. Lỗi Permission Denied
Nếu gặp lỗi:
permission denied
403 forbidden
Hãy kiểm tra:
- GITLAB_TOKEN tồn tại
- Token chưa hết hạn
-
Có quyền
api -
Có quyền
write_repository
4. Tối ưu Pipeline
Có thể cache thêm:
cache:
paths:
- vendor/
- node_modules/
để giảm thời gian chạy pipeline.
Kết quả đạt được
Sau khi hoàn thành cấu hình:
✅ PHPStan chạy tự động trên GitLab
✅ PHPUnit chạy tự động trên GitLab
✅ Pipeline chặn merge nếu test thất bại
✅ Tự động tăng version theo Conventional Commits
✅ Tự động tạo Git Tag
✅ Tự động sinh CHANGELOG.md
✅ Tự động tạo GitLab Release
✅ Hỗ trợ hoàn toàn cho PHP 8.4 và GitLab CI/CD.