ΠΠ²Π΅Π΄Π΅Π½ΠΈΠ΅: Π·Π°ΡΠ΅ΠΌ Π½ΡΠΆΠ΅Π½ CI/CD Π΄Π»Ρ PHP-ΠΏΡΠΎΠ΅ΠΊΡΠΎΠ²
Π ΡΠΎΠ²ΡΠ΅ΠΌΠ΅Π½Π½ΠΎΠΌ ΠΌΠΈΡΠ΅ Π²Π΅Π±-ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΠΈ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΠ·Π°ΡΠΈΡ ΠΏΡΠΎΡΠ΅ΡΡΠΎΠ² Π΄ΠΎΡΡΠ°Π²ΠΊΠΈ ΠΊΠΎΠ΄Π° ΡΡΠ°Π½ΠΎΠ²ΠΈΡΡΡ ΠΊΡΠΈΡΠΈΡΠ΅ΡΠΊΠΈ Π²Π°ΠΆΠ½ΠΎΠΉ Π΄Π»Ρ ΡΡΠΏΠ΅Ρ Π° Π»ΡΠ±ΠΎΠ³ΠΎ ΠΏΡΠΎΠ΅ΠΊΡΠ°. ΠΠ»Ρ PHP-ΠΏΡΠΎΠ΅ΠΊΡΠΎΠ², ΠΊΠ°ΠΊ ΠΈ Π΄Π»Ρ Π»ΡΠ±ΡΡ Π΄ΡΡΠ³ΠΈΡ , Π²Π½Π΅Π΄ΡΠ΅Π½ΠΈΠ΅ CI/CD (Continuous Integration ΠΈ Continuous Delivery/Deployment) ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΡΡΠΊΠΎΡΠΈΡΡ Π²ΡΠΏΡΡΠΊ Π½ΠΎΠ²ΡΡ Π²Π΅ΡΡΠΈΠΉ, ΠΏΠΎΠ²ΡΡΠΈΡΡ ΠΊΠ°ΡΠ΅ΡΡΠ²ΠΎ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΠ½ΠΎΠ³ΠΎ ΠΎΠ±Π΅ΡΠΏΠ΅ΡΠ΅Π½ΠΈΡ ΠΈ ΠΌΠΈΠ½ΠΈΠΌΠΈΠ·ΠΈΡΠΎΠ²Π°ΡΡ ΡΠ΅Π»ΠΎΠ²Π΅ΡΠ΅ΡΠΊΠΈΠΉ ΡΠ°ΠΊΡΠΎΡ ΠΏΡΠΈ Π΄ΠΎΡΡΠ°Π²ΠΊΠ΅ ΠΏΡΠΎΠ΄ΡΠΊΡΠ° Π½Π° ΠΏΡΠΎΠ΄Π°ΠΊΡΠ½. Π ΡΡΠΎΠΉ ΡΡΠ°ΡΡΠ΅ ΠΌΡ ΡΠ°ΡΡΠΌΠΎΡΡΠΈΠΌ ΡΠΎΠ²ΡΠ΅ΠΌΠ΅Π½Π½ΡΠ΅ ΡΠΏΠΎΡΠΎΠ±Ρ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ CI/CD ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½ΠΎΠ² Π΄Π»Ρ PHP-ΠΏΡΠΎΠ΅ΠΊΡΠΎΠ² Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ Π½Π°ΠΈΠ±ΠΎΠ»Π΅Π΅ ΠΏΠΎΠΏΡΠ»ΡΡΠ½ΡΡ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΠΎΠ²: GitLab CI, GitHub Actions ΠΈ Jenkins.
Π§ΡΠΎ ΡΠ°ΠΊΠΎΠ΅ CI/CD ΠΈ ΠΏΠΎΡΠ΅ΠΌΡ ΡΡΠΎ Π²Π°ΠΆΠ½ΠΎ?
CI/CD β ΡΡΠΎ Π½Π°Π±ΠΎΡ ΠΏΡΠ°ΠΊΡΠΈΠΊ, Π½Π°ΠΏΡΠ°Π²Π»Π΅Π½Π½ΡΡ Π½Π° Π°Π²ΡΠΎΠΌΠ°ΡΠΈΠ·Π°ΡΠΈΡ ΠΈΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΠΈ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ Π² ΠΊΠΎΠ΄Π΅ (Continuous Integration) ΠΈ ΠΈΡ Π΄ΠΎΡΡΠ°Π²ΠΊΡ Π½Π° ΡΠ΅ΡΠ²Π΅Ρ (Continuous Delivery ΠΈΠ»ΠΈ Deployment). ΠΠ½Π΅Π΄ΡΠ΅Π½ΠΈΠ΅ CI/CD ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ:
- ΠΠ²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°ΡΡ ΠΊΠ°ΠΆΠ΄ΠΎΠ΅ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ Π² ΠΊΠΎΠ΄Π΅
- Π£ΠΌΠ΅Π½ΡΡΠΈΡΡ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ ΠΎΡΠΈΠ±ΠΎΠΊ ΠΏΡΠΈ ΡΠ΅Π»ΠΈΠ·Π°Ρ
- ΠΡΡΡΡΠΎ Π²ΡΠΏΡΡΠΊΠ°ΡΡ Π½ΠΎΠ²ΡΠ΅ Π²Π΅ΡΡΠΈΠΈ ΠΏΡΠΎΠ΄ΡΠΊΡΠ°
- Π£ΡΠΊΠΎΡΠΈΡΡ ΠΎΠ±ΡΠ°ΡΠ½ΡΡ ΡΠ²ΡΠ·Ρ Π΄Π»Ρ ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊΠΎΠ²
- ΠΠΎΠ²ΡΡΠΈΡΡ ΡΡΠ°Π±ΠΈΠ»ΡΠ½ΠΎΡΡΡ ΠΈ Π½Π°Π΄ΡΠΆΠ½ΠΎΡΡΡ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ
ΠΠΎΠΏΡΠ»ΡΡΠ½ΡΠ΅ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΡ Π΄Π»Ρ CI/CD ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½ΠΎΠ²
ΠΠ»Ρ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΠ·Π°ΡΠΈΠΈ ΠΏΡΠΎΡΠ΅ΡΡΠΎΠ² Π² PHP-ΠΏΡΠΎΠ΅ΠΊΡΠ°Ρ ΡΠ°ΡΠ΅ Π²ΡΠ΅Π³ΠΎ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡΡ:
- GitLab CI/CD β Π²ΡΡΡΠΎΠ΅Π½Π½ΡΠΉ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½Ρ Π² GitLab, ΠΎΠ±Π»Π°Π΄Π°ΡΡΠΈΠΉ ΠΌΠΎΡΠ½ΡΠΌΠΈ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΡΠΌΠΈ Π½Π°ΡΡΡΠΎΠΉΠΊΠΈ ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½ΠΎΠ² ΡΠ΅ΡΠ΅Π· ΡΠ°ΠΉΠ»
.gitlab-ci.yml
. - GitHub Actions β ΡΠ΅ΡΠ²ΠΈΡ Π΄Π»Ρ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΠ·Π°ΡΠΈΠΈ ΡΠ°Π±ΠΎΡΠΈΡ
ΠΏΡΠΎΡΠ΅ΡΡΠΎΠ², Π³Π»ΡΠ±ΠΎΠΊΠΎ ΠΈΠ½ΡΠ΅Π³ΡΠΈΡΠΎΠ²Π°Π½Π½ΡΠΉ Ρ ΡΠΊΠΎΡΠΈΡΡΠ΅ΠΌΠΎΠΉ GitHub, ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡΡΠΈΠΉ Π·Π°ΠΏΡΡΠΊΠ°ΡΡ ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½Ρ ΡΠ΅ΡΠ΅Π· ΡΠ°ΠΉΠ»
.github/workflows/*.yml
. - Jenkins β ΠΌΠΎΡΠ½ΡΠΉ ΠΈ Π³ΠΈΠ±ΠΊΠΈΠΉ open-source ΡΠ΅ΡΠ²Π΅Ρ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΠ·Π°ΡΠΈΠΈ, ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°ΡΡΠΈΠΉ ΠΊΠ°ΡΡΠΎΠΌΠ½ΡΠ΅ ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½Ρ ΠΏΠΎΠ΄ Π»ΡΠ±ΡΠ΅ Π·Π°Π΄Π°ΡΠΈ.
ΠΠΌΠΏΠ»Π΅ΠΌΠ΅Π½ΡΠ°ΡΠΈΡ CI/CD Π΄Π»Ρ PHP Π½Π° GitLab CI
GitLab CI ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΡΠ΅Π°Π»ΠΈΠ·ΠΎΠ²Π°ΡΡ ΠΏΡΠ°ΠΊΡΠΈΡΠ΅ΡΠΊΠΈ Π»ΡΠ±ΠΎΠΉ ΡΡΠ΅Π½Π°ΡΠΈΠΉ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΠ·Π°ΡΠΈΠΈ. ΠΡΠΈΠΌΠ΅Ρ Π±Π°Π·ΠΎΠ²ΠΎΠ³ΠΎ .gitlab-ci.yml
Π΄Π»Ρ PHP-ΠΏΡΠΎΠ΅ΠΊΡΠ°:
stages:
- test
- deploy
test:
image: php:8.2
script:
- composer install
- vendor/bin/phpunit
deploy:
stage: deploy
script:
- ./deploy.sh
only:
- main
Π’Π°ΠΊΠΎΠΉ ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ ΡΡΡΠ°Π½ΠΎΠ²ΠΈΡ Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠΈ, Π·Π°ΠΏΡΡΡΠΈΡ ΡΠ΅ΡΡΡ ΠΈ Π²ΡΠΏΠΎΠ»Π½ΠΈΡ Π΄Π΅ΠΏΠ»ΠΎΠΉ Π½Π° ΠΏΡΠΎΠ΄Π°ΠΊΡΠ½ ΠΏΠΎΡΠ»Π΅ ΡΡΠΏΠ΅ΡΠ½ΠΎΠ³ΠΎ ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ. GitLab CI ΠΈΠ½ΡΠ΅Π³ΡΠΈΡΡΠ΅ΡΡΡ Ρ Docker, ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅Ρ ΠΊΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠ΅ΠΉ ΠΈ Π»Π΅Π³ΠΊΠΎ ΠΌΠ°ΡΡΡΠ°Π±ΠΈΡΡΠ΅ΡΡΡ.
ΠΠ½Π΅Π΄ΡΠ΅Π½ΠΈΠ΅ CI/CD Ρ ΠΏΠΎΠΌΠΎΡΡΡ GitHub Actions
GitHub Actions β ΡΠΎΠ²ΡΠ΅ΠΌΠ΅Π½Π½ΡΠΉ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½Ρ, ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡΡΠΈΠΉ Π·Π°ΠΏΡΡΠΊΠ°ΡΡ ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½Ρ Π² ΠΎΠ±Π»Π°ΠΊΠ΅ ΠΈΠ»ΠΈ Π½Π° ΡΠΎΠ±ΡΡΠ²Π΅Π½Π½ΡΡ runner'Π°Ρ . ΠΡΠΈΠΌΠ΅Ρ ΡΠ°Π±ΠΎΡΠ΅Π³ΠΎ ΠΏΡΠΎΡΠ΅ΡΡΠ° Π΄Π»Ρ PHP-ΠΏΡΠΎΠ΅ΠΊΡΠ°:
name: CI
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.2
- run: composer install
- run: vendor/bin/phpunit
GitHub Actions ΠΏΡΠ΅Π΄Π»Π°Π³Π°Π΅Ρ Π±ΠΎΠ³Π°ΡΡΠΉ marketplace Π³ΠΎΡΠΎΠ²ΡΡ ΡΠΊΡΠ΅Π½ΠΎΠ², Π³ΠΈΠ±ΠΊΡΡ Π½Π°ΡΡΡΠΎΠΉΠΊΡ ΡΡΠΈΠ³Π³Π΅ΡΠΎΠ² ΠΈ Ρ ΠΎΡΠΎΡΡΡ ΠΈΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΡ Ρ Π΄ΡΡΠ³ΠΈΠΌΠΈ ΡΠ΅ΡΠ²ΠΈΡΠ°ΠΌΠΈ GitHub.
Jenkins: ΠΊΠ°ΡΡΠΎΠΌΠΈΠ·Π°ΡΠΈΡ ΠΏΡΠΎΡΠ΅ΡΡΠΎΠ² CI/CD Π΄Π»Ρ PHP
Jenkins β ΠΎΠ΄ΠΈΠ½ ΠΈΠ· ΡΠ°ΠΌΡΡ
Π³ΠΈΠ±ΠΊΠΈΡ
ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΠΎΠ² Π΄Π»Ρ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΠ·Π°ΡΠΈΠΈ. ΠΠ³ΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΠ½ΡΠ΅Π³ΡΠΈΡΠΎΠ²Π°ΡΡ Ρ Π»ΡΠ±ΡΠΌΠΈ ΡΠ΅ΠΏΠΎΠ·ΠΈΡΠΎΡΠΈΡΠΌΠΈ, ΡΠΈΡΡΠ΅ΠΌΠ°ΠΌΠΈ ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ ΠΈ Π΄Π΅ΠΏΠ»ΠΎΡ. ΠΠ»Ρ PHP-ΠΏΡΠΎΠ΅ΠΊΡΠ° ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½ ΠΌΠΎΠΆΠ΅Ρ Π±ΡΡΡ ΠΎΠΏΠΈΡΠ°Π½ ΠΊΠ°ΠΊ Π² Π²Π΅Π±-ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΠ΅, ΡΠ°ΠΊ ΠΈ ΡΠ΅ΡΠ΅Π· ΡΠ°ΠΉΠ» Jenkinsfile
:
pipeline {
agent any
stages {
stage('Install dependencies') {
steps {
sh 'composer install'
}
}
stage('Test') {
steps {
sh 'vendor/bin/phpunit'
}
}
stage('Deploy') {
when {
branch 'main'
}
steps {
sh './deploy.sh'
}
}
}
}
Jenkins Π»Π΅Π³ΠΊΠΎ ΡΠ°ΡΡΠΈΡΡΠ΅ΡΡΡ ΠΏΠ»Π°Π³ΠΈΠ½Π°ΠΌΠΈ, ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅Ρ ΡΠ°ΡΠΏΡΠ΅Π΄Π΅Π»ΡΠ½Π½ΡΠ΅ ΡΠ±ΠΎΡΠΊΠΈ ΠΈ ΠΈΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΡ Ρ ΡΠΈΡΡΠ΅ΠΌΠ°ΠΌΠΈ ΠΌΠΎΠ½ΠΈΡΠΎΡΠΈΠ½Π³Π° ΠΈ ΠΎΠΏΠΎΠ²Π΅ΡΠ΅Π½ΠΈΠΉ.
ΠΡΡΡΠΈΠ΅ ΠΏΡΠ°ΠΊΡΠΈΠΊΠΈ ΠΏΡΠΈ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ CI/CD ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½ΠΎΠ² Π΄Π»Ρ PHP
- ΠΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ ΠΎΡΠ΄Π΅Π»ΡΠ½ΡΠ΅ ΡΡΠ°ΠΏΡ Π΄Π»Ρ ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ, ΡΠ±ΠΎΡΠΊΠΈ ΠΈ Π΄Π΅ΠΏΠ»ΠΎΡ
- Π₯ΡΠ°Π½ΠΈΡΠ΅ ΡΠ΅ΠΊΡΠ΅ΡΡ ΠΈ ΠΏΠ΅ΡΠ΅ΠΌΠ΅Π½Π½ΡΠ΅ ΠΎΠΊΡΡΠΆΠ΅Π½ΠΈΡ Π² Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΠΌ Π²ΠΈΠ΄Π΅
- ΠΠ°ΡΡΡΠ°ΠΈΠ²Π°ΠΉΡΠ΅ ΡΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΡ ΠΎ ΡΡΠ°ΡΡΡΠ΅ ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½ΠΎΠ²
- ΠΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ ΠΊΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠ΅ΠΉ Π΄Π»Ρ ΡΡΠΊΠΎΡΠ΅Π½ΠΈΡ ΡΠ±ΠΎΡΠΎΠΊ
- ΠΡΠΎΠ²ΠΎΠ΄ΠΈΡΠ΅ ΡΡΠ°ΡΠΈΡΠ΅ΡΠΊΠΈΠΉ Π°Π½Π°Π»ΠΈΠ· ΠΊΠΎΠ΄Π° (Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ, PHPStan, Psalm)
- ΠΠ½ΡΠ΅Π³ΡΠΈΡΡΠΉΡΠ΅ Π΄Π΅ΠΏΠ»ΠΎΠΉ ΡΠΎΠ»ΡΠΊΠΎ ΠΏΠΎΡΠ»Π΅ ΡΡΠΏΠ΅ΡΠ½ΠΎΠ³ΠΎ ΠΏΡΠΎΡ ΠΎΠΆΠ΄Π΅Π½ΠΈΡ ΡΠ΅ΡΡΠΎΠ²
ΠΠ°ΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅
ΠΠΌΠΏΠ»Π΅ΠΌΠ΅Π½ΡΠ°ΡΠΈΡ CI/CD ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½ΠΎΠ² β Π²Π°ΠΆΠ½Π΅ΠΉΡΠ°Ρ ΡΠ°ΡΡΡ ΡΠΎΠ²ΡΠ΅ΠΌΠ΅Π½Π½ΠΎΠ³ΠΎ ΠΏΡΠΎΡΠ΅ΡΡΠ° ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΠΈ PHP-ΠΏΡΠΎΠ΅ΠΊΡΠΎΠ². ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ GitLab CI, GitHub Actions ΠΈΠ»ΠΈ Jenkins ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ Π΄ΠΎΠ±ΠΈΡΡΡΡ Π²ΡΡΠΎΠΊΠΎΠΉ ΡΠΊΠΎΡΠΎΡΡΠΈ ΡΠ΅Π»ΠΈΠ·ΠΎΠ², ΠΊΠ°ΡΠ΅ΡΡΠ²Π° ΠΈ Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΡΡΠΈ Π²Π°ΡΠΈΡ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ. ΠΡΠ»ΠΈ Π²Ρ Ρ ΠΎΡΠΈΡΠ΅ Π±ΡΡΡΡΠΎ Π²Π½Π΅Π΄ΡΠΈΡΡ ΠΈΠ»ΠΈ ΠΎΠΏΡΠΈΠΌΠΈΠ·ΠΈΡΠΎΠ²Π°ΡΡ ΠΏΡΠΎΡΠ΅ΡΡΡ CI/CD Π΄Π»Ρ Π²Π°ΡΠ΅Π³ΠΎ PHP-ΠΏΡΠΎΠ΅ΠΊΡΠ°, ΠΌΡ Π³ΠΎΡΠΎΠ²Ρ ΠΏΠΎΠΌΠΎΡΡ! ΠΠ·Π½Π°ΠΊΠΎΠΌΡΡΠ΅ΡΡ Ρ Π½Π°ΡΠΈΠΌΠΈ ΡΡΠ»ΡΠ³Π°ΠΌΠΈ ΠΏΠΎ Π²Π½Π΅Π΄ΡΠ΅Π½ΠΈΡ CI/CD ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½ΠΎΠ² Π΄Π»Ρ PHP.
Raman Sapezhka
CEO Plantago/CTO