Compare commits
10 Commits
7998209e95
...
c6212165af
Author | SHA1 | Date | |
---|---|---|---|
c6212165af | |||
0cb732c803 | |||
2c4ca426fd | |||
c8da8fa23f | |||
6a7047cfe9 | |||
7007b184d0 | |||
91cfa35d2c | |||
da98a36142 | |||
d37b3473a4 | |||
7676933e40 |
@ -30,7 +30,7 @@ jobs:
|
|||||||
- attach_workspace:
|
- attach_workspace:
|
||||||
at: /tmp/workspace
|
at: /tmp/workspace
|
||||||
- checkout
|
- checkout
|
||||||
- run: docker/provision.sh
|
- run: docker/php/provision.sh
|
||||||
- run: composer install --no-interaction --no-progress
|
- run: composer install --no-interaction --no-progress
|
||||||
- run: mkdir -p ${STATIC_DIR}
|
- run: mkdir -p ${STATIC_DIR}
|
||||||
- run: cp -R /tmp/workspace/static/* ${STATIC_DIR}
|
- run: cp -R /tmp/workspace/static/* ${STATIC_DIR}
|
||||||
@ -55,7 +55,7 @@ jobs:
|
|||||||
- add_ssh_keys
|
- add_ssh_keys
|
||||||
- run: apt-get update; apt-get install -yy openssh-client
|
- run: apt-get update; apt-get install -yy openssh-client
|
||||||
- run: ssh-keyscan "vakhrushev.me" >> ~/.ssh/known_hosts
|
- run: ssh-keyscan "vakhrushev.me" >> ~/.ssh/known_hosts
|
||||||
- run: docker/provision.sh
|
- run: docker/php/provision.sh
|
||||||
- attach_workspace:
|
- attach_workspace:
|
||||||
at: /tmp/workspace
|
at: /tmp/workspace
|
||||||
- run: mkdir -p ./output_prod
|
- run: mkdir -p ./output_prod
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
/node_modules
|
/node_modules
|
||||||
/output_*
|
|
||||||
/var
|
/var
|
||||||
/vendor
|
/vendor
|
||||||
|
3
.env
3
.env
@ -1,2 +1,3 @@
|
|||||||
|
PROJECT=homepage
|
||||||
PHP_IMAGE=homepage-php
|
PHP_IMAGE=homepage-php
|
||||||
NODE_IMAGE=node:12-alpine
|
NODE_IMAGE=homepage-node
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,7 +1,9 @@
|
|||||||
.idea/
|
.idea/
|
||||||
|
.vscode/
|
||||||
output_*
|
output_*
|
||||||
node_modules/
|
node_modules/
|
||||||
var/
|
var/
|
||||||
vendor/
|
vendor/
|
||||||
|
|
||||||
.php_cs.cache
|
.php_cs.cache
|
||||||
|
.php-cs-fixer.cache
|
||||||
|
@ -7,7 +7,7 @@ $finder = PhpCsFixer\Finder::create()
|
|||||||
->in(__DIR__.'/bundle')
|
->in(__DIR__.'/bundle')
|
||||||
;
|
;
|
||||||
|
|
||||||
return PhpCsFixer\Config::create()
|
return (new PhpCsFixer\Config())
|
||||||
->setFinder($finder)
|
->setFinder($finder)
|
||||||
->setRules([
|
->setRules([
|
||||||
'@Symfony' => true,
|
'@Symfony' => true,
|
2
Makefile
2
Makefile
@ -70,7 +70,7 @@ watch: clean build-assets
|
|||||||
# Deploy
|
# Deploy
|
||||||
|
|
||||||
deploy: build-prod
|
deploy: build-prod
|
||||||
./tools/dep deploy production -vv
|
invoke deploy
|
||||||
|
|
||||||
rollback:
|
rollback:
|
||||||
./tools/dep rollback production -vv
|
./tools/dep rollback production -vv
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use Homepage\HtmlPrettierBundle\HtmlPrettierBundle;
|
use Homepage\HtmlPrettierBundle\HtmlPrettierBundle;
|
||||||
use Homepage\SiteMapBundle\SiteMapBundle;
|
use Homepage\SiteMapBundle\SiteMapBundle;
|
||||||
use Homepage\TwigExtensionBundle\TwigExtensionBundle;
|
use Homepage\TwigExtensionBundle\TwigExtensionBundle;
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace Homepage\HtmlPrettierBundle\DependencyInjection;
|
namespace Homepage\HtmlPrettierBundle\DependencyInjection;
|
||||||
|
|
||||||
use Symfony\Component\Config\FileLocator;
|
use Symfony\Component\Config\FileLocator;
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace Homepage\HtmlPrettierBundle;
|
namespace Homepage\HtmlPrettierBundle;
|
||||||
|
|
||||||
use Generator;
|
use Generator;
|
||||||
@ -7,7 +9,9 @@ use Sculpin\Core\Event\SourceSetEvent;
|
|||||||
use Sculpin\Core\Sculpin;
|
use Sculpin\Core\Sculpin;
|
||||||
use Sculpin\Core\Source\SourceInterface;
|
use Sculpin\Core\Source\SourceInterface;
|
||||||
use Sculpin\Core\Source\SourceSet;
|
use Sculpin\Core\Source\SourceSet;
|
||||||
|
|
||||||
use function strlen;
|
use function strlen;
|
||||||
|
|
||||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||||
|
|
||||||
class HtmlPrettier implements EventSubscriberInterface
|
class HtmlPrettier implements EventSubscriberInterface
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace Homepage\HtmlPrettierBundle;
|
namespace Homepage\HtmlPrettierBundle;
|
||||||
|
|
||||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace Homepage\SiteMapBundle\DependencyInjection;
|
namespace Homepage\SiteMapBundle\DependencyInjection;
|
||||||
|
|
||||||
use Symfony\Component\Config\FileLocator;
|
use Symfony\Component\Config\FileLocator;
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace Homepage\SiteMapBundle;
|
namespace Homepage\SiteMapBundle;
|
||||||
|
|
||||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace Homepage\SiteMapBundle;
|
namespace Homepage\SiteMapBundle;
|
||||||
|
|
||||||
use Sculpin\Core\DataProvider\DataProviderInterface;
|
use Sculpin\Core\DataProvider\DataProviderInterface;
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace Homepage\TwigExtensionBundle\DependencyInjection;
|
namespace Homepage\TwigExtensionBundle\DependencyInjection;
|
||||||
|
|
||||||
use Symfony\Component\Config\FileLocator;
|
use Symfony\Component\Config\FileLocator;
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace Homepage\TwigExtensionBundle;
|
namespace Homepage\TwigExtensionBundle;
|
||||||
|
|
||||||
use Twig\Extension\AbstractExtension;
|
use Twig\Extension\AbstractExtension;
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace Homepage\TwigExtensionBundle;
|
namespace Homepage\TwigExtensionBundle;
|
||||||
|
|
||||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||||
|
@ -9,16 +9,20 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"php": "~7.3",
|
"php": "~7.4",
|
||||||
"ext-tidy": "*"
|
"ext-tidy": "*"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"friendsofphp/php-cs-fixer": "^2.15",
|
|
||||||
"sculpin/sculpin": "^3.0"
|
"sculpin/sculpin": "^3.0"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"Homepage\\": "bundle/"
|
"Homepage\\": "bundle/"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"allow-plugins": {
|
||||||
|
"sculpin/sculpin-theme-composer-plugin": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1740
composer.lock
generated
1740
composer.lock
generated
File diff suppressed because it is too large
Load Diff
49
deploy.php
49
deploy.php
@ -1,49 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Deployer;
|
|
||||||
|
|
||||||
require 'recipe/common.php';
|
|
||||||
|
|
||||||
host('vakhrushev.me')
|
|
||||||
->user('homepage')
|
|
||||||
->stage('production')
|
|
||||||
->set('deploy_path', '/var/www/homepage')
|
|
||||||
;
|
|
||||||
|
|
||||||
host('192.168.50.10')
|
|
||||||
->stage('test')
|
|
||||||
->user('homepage')
|
|
||||||
->set('deploy_path', '/var/www/homepage')
|
|
||||||
->addSshOption('UserKnownHostsFile', '/dev/null')
|
|
||||||
->addSshOption('StrictHostKeyChecking', 'no')
|
|
||||||
;
|
|
||||||
|
|
||||||
// Saved releases
|
|
||||||
set('keep_releases', 2);
|
|
||||||
|
|
||||||
// Excluded dirs for upload
|
|
||||||
set('upload_excluded_dirs', []);
|
|
||||||
|
|
||||||
// Upload app sources on remote host
|
|
||||||
task('upload', function () {
|
|
||||||
$excluded = array_map(function ($dir) {
|
|
||||||
return sprintf('--exclude "%s"', $dir);
|
|
||||||
}, get('upload_excluded_dirs'));
|
|
||||||
upload(__DIR__ . '/output_prod/', '{{release_path}}', [
|
|
||||||
'options' => $excluded,
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Deploy task
|
|
||||||
task('deploy', [
|
|
||||||
'deploy:info',
|
|
||||||
'deploy:prepare',
|
|
||||||
'deploy:lock',
|
|
||||||
'deploy:release',
|
|
||||||
'upload',
|
|
||||||
'deploy:symlink',
|
|
||||||
'deploy:unlock',
|
|
||||||
'cleanup',
|
|
||||||
]);
|
|
||||||
|
|
||||||
after('deploy', 'success');
|
|
@ -1,7 +0,0 @@
|
|||||||
FROM php:7.4.7-cli
|
|
||||||
|
|
||||||
COPY ./docker/provision.sh /opt/
|
|
||||||
|
|
||||||
RUN /opt/provision.sh
|
|
||||||
|
|
||||||
WORKDIR /srv/app
|
|
3
docker/Dockerfile.nginx.prod
Normal file
3
docker/Dockerfile.nginx.prod
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
FROM nginx:stable
|
||||||
|
|
||||||
|
COPY output_prod /usr/share/nginx/html
|
11
docker/docker-compose.prod.yml
Normal file
11
docker/docker-compose.prod.yml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
version: '2'
|
||||||
|
|
||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
image: '${NGINX_IMAGE}'
|
||||||
|
# user: '${CURRENT_UID}:${CURRENT_GID}'
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- '${WEB_SERVER_PORT}:80'
|
||||||
|
env_file:
|
||||||
|
- .env
|
3
docker/node/Dockerfile
Normal file
3
docker/node/Dockerfile
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
FROM node:12.22.3-alpine
|
||||||
|
|
||||||
|
RUN npm install -g npm
|
7
docker/php/Dockerfile
Normal file
7
docker/php/Dockerfile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
FROM php:7.4.21-cli
|
||||||
|
|
||||||
|
COPY ./docker/php/provision.sh /opt/
|
||||||
|
|
||||||
|
RUN /opt/provision.sh
|
||||||
|
|
||||||
|
WORKDIR /srv/app
|
@ -19,11 +19,12 @@ docker-php-ext-install tidy \
|
|||||||
mkdir -p /srv/app
|
mkdir -p /srv/app
|
||||||
|
|
||||||
# Composer and required tools
|
# Composer and required tools
|
||||||
curl -sLO https://getcomposer.org/download/1.10.8/composer.phar \
|
curl -sLO https://getcomposer.org/download/2.3.10/composer.phar \
|
||||||
&& mv composer.phar /usr/local/bin/composer \
|
&& mv composer.phar /usr/local/bin/composer \
|
||||||
&& chmod +x /usr/local/bin/composer
|
&& chmod +x /usr/local/bin/composer
|
||||||
|
|
||||||
# Deployer
|
|
||||||
curl -sLO https://deployer.org/releases/v6.8.0/deployer.phar \
|
# PHP-CS-Fixer
|
||||||
&& mv deployer.phar /usr/local/bin/dep \
|
curl -sLO https://github.com/FriendsOfPHP/PHP-CS-Fixer/releases/download/v3.9.5/php-cs-fixer.phar \
|
||||||
&& chmod +x /usr/local/bin/dep
|
&& mv php-cs-fixer.phar /usr/local/bin/php-cs-fixer \
|
||||||
|
&& chmod +x /usr/local/bin/php-cs-fixer
|
12970
npm-shrinkwrap.json
generated
12970
npm-shrinkwrap.json
generated
File diff suppressed because it is too large
Load Diff
28
package.json
28
package.json
@ -6,27 +6,27 @@
|
|||||||
"description": "Homepage",
|
"description": "Homepage",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@anwinged/predictor": "^0.2.1",
|
"@anwinged/predictor": "^0.2.1",
|
||||||
"@babel/core": "^7.10.3",
|
"@babel/core": "^7.14.6",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.10.1",
|
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
||||||
"@babel/plugin-transform-runtime": "^7.10.3",
|
"@babel/plugin-transform-runtime": "^7.14.5",
|
||||||
"@babel/preset-env": "^7.10.3",
|
"@babel/preset-env": "^7.14.7",
|
||||||
"@babel/runtime": "^7.10.3",
|
"@babel/runtime": "^7.14.6",
|
||||||
"autoprefixer": "^9.8.4",
|
"autoprefixer": "^9.8.6",
|
||||||
"babel-loader": "^8.1.0",
|
"babel-loader": "^8.2.2",
|
||||||
"css-loader": "^2.1.1",
|
"css-loader": "^2.1.1",
|
||||||
"glob": "^7.1.6",
|
"glob": "^7.1.7",
|
||||||
"mini-css-extract-plugin": "^0.6.0",
|
"mini-css-extract-plugin": "^0.6.0",
|
||||||
"node-sass": "^4.14.1",
|
"node-sass": "^4.14.1",
|
||||||
"postcss-loader": "^3.0.0",
|
"postcss-loader": "^3.0.0",
|
||||||
"prettier": "^1.19.1",
|
"prettier": "^1.19.1",
|
||||||
"sass-loader": "^7.3.1",
|
"sass-loader": "^7.3.1",
|
||||||
"style-loader": "^0.23.1",
|
"style-loader": "^0.23.1",
|
||||||
"underscore": "^1.10.2",
|
"underscore": "^1.13.1",
|
||||||
"vue": "^2.6.11",
|
"vue": "^2.6.14",
|
||||||
"vue-loader": "^15.9.3",
|
"vue-loader": "^15.9.7",
|
||||||
"vue-style-loader": "^4.1.2",
|
"vue-style-loader": "^4.1.3",
|
||||||
"vue-template-compiler": "^2.6.11",
|
"vue-template-compiler": "^2.6.14",
|
||||||
"webpack": "^4.43.0",
|
"webpack": "^4.46.0",
|
||||||
"webpack-cli": "^3.3.12"
|
"webpack-cli": "^3.3.12"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
177
source/_articles/2020-11-08-nullable-fields.md
Normal file
177
source/_articles/2020-11-08-nullable-fields.md
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
---
|
||||||
|
title: Организация доступа к nullable полям класса
|
||||||
|
description: Заметка о том, лучше организовать доступ к полям класса, которые могут содержать значение null
|
||||||
|
keywords: [чистый код, php, null, поля класса]
|
||||||
|
---
|
||||||
|
|
||||||
|
Нередкая ситуация, когда в классе есть поле, которое может содержать `null`.
|
||||||
|
|
||||||
|
```php
|
||||||
|
class User
|
||||||
|
{
|
||||||
|
private Email $email;
|
||||||
|
private ?string $name;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Пользователь может указать имя, а может и не указывать,
|
||||||
|
ограничившись только почтовым адресом.
|
||||||
|
|
||||||
|
А далее мы пишем код, которые работает с полем имени.
|
||||||
|
|
||||||
|
```php
|
||||||
|
class User
|
||||||
|
{
|
||||||
|
private ?string $name;
|
||||||
|
|
||||||
|
public function hasName(): bool
|
||||||
|
{
|
||||||
|
return $this->name !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName(): ?string
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setName(?string $name): void
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
И использование этого кода:
|
||||||
|
|
||||||
|
```php
|
||||||
|
/** @var User $user */
|
||||||
|
|
||||||
|
if ($user->hasName()) {
|
||||||
|
do_something_with_name($user->getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
function do_something_with_name(string $name) {}
|
||||||
|
```
|
||||||
|
|
||||||
|
Выглядит хорошо.
|
||||||
|
Сначала убедились, что имя установлено, а потом использовали его.
|
||||||
|
|
||||||
|
Но статический анализатор нам обязательно припомнит, что мы пытаемся передать
|
||||||
|
в функцию `do_something_with_name` значение типа `string|null`, хотя функция
|
||||||
|
ожидает значение типа `string`.
|
||||||
|
И получается дурацкая ситуация, что формально мы должны дописать
|
||||||
|
еще одну проверку.
|
||||||
|
|
||||||
|
```php
|
||||||
|
/** @var User $user */
|
||||||
|
|
||||||
|
if ($user->hasName()) {
|
||||||
|
$name = $user->getName();
|
||||||
|
if ($name !== null) {
|
||||||
|
do_something_with_name($name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function do_something_with_name(string $name) {}
|
||||||
|
```
|
||||||
|
|
||||||
|
Статический анализатор наш друг, он помогает находить ошибки и несоответствия
|
||||||
|
в коде.
|
||||||
|
И здесь он нашел такое формальное несоответствие типов.
|
||||||
|
|
||||||
|
Статический анализатор прав, а мы, как проектировщики интерфейса, не правы.
|
||||||
|
На самом деле мы смешали два подхода, когда описывали методы в нашем классе:
|
||||||
|
|
||||||
|
1. Получить и проверить
|
||||||
|
2. Проверить и получить
|
||||||
|
|
||||||
|
## Получить и проверить
|
||||||
|
|
||||||
|
И сразу начнем с примера использования.
|
||||||
|
|
||||||
|
```php
|
||||||
|
$name = $user->getName();
|
||||||
|
if ($name !== null) {
|
||||||
|
do_something_with_name($name);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Сначала мы получаем значение поля, а потом проверяем, соответствует ли это
|
||||||
|
значение нашим требованиям. Класс при этом будет построен вот так:
|
||||||
|
|
||||||
|
```php
|
||||||
|
class User
|
||||||
|
{
|
||||||
|
private ?string $name;
|
||||||
|
|
||||||
|
public function getName(): ?string
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setName(?string $name): void
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Заметьте, здесь уже нет метода `hasName()`, потому что этот метод перестал быть
|
||||||
|
нужным. Его роль исполняет метод `getName()`.
|
||||||
|
|
||||||
|
## Проверить и получить
|
||||||
|
|
||||||
|
Второй подход: сначала проверяем значение, а потом работаем с ним:
|
||||||
|
|
||||||
|
```php
|
||||||
|
if ($user->hasName()) {
|
||||||
|
do_something_with_name($user->getName());
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Структура класса:
|
||||||
|
|
||||||
|
```php
|
||||||
|
class User
|
||||||
|
{
|
||||||
|
private ?string $name;
|
||||||
|
|
||||||
|
public function hasName(): bool
|
||||||
|
{
|
||||||
|
return $this->name !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName(): string
|
||||||
|
{
|
||||||
|
if ($this->name === null) {
|
||||||
|
throw new \LogicException('Name is not set');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setName(?string $name): void
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Смотрите отличия.
|
||||||
|
Метод `hasName()` остается.
|
||||||
|
А вот метод `getName()` теперь возвращает значение типа `string`.
|
||||||
|
Он выбросит исключение, если мы попытаемся получить значение,
|
||||||
|
которое не установлено.
|
||||||
|
|
||||||
|
## Использование
|
||||||
|
|
||||||
|
Теперь встает вопрос, когда и какой подход следует использовать.
|
||||||
|
|
||||||
|
- Если ситуация, когда поле не установлено, скорее исключительная, нежели
|
||||||
|
обычная, то можно использовать второй подход, а проверку опустить.
|
||||||
|
Исключение в методе `getName()` позволит обнаружить странное поведение.
|
||||||
|
- Если в пустом поле нет ничего не обычного, то подход "получить и проверить"
|
||||||
|
будет удобнее, все равно нужно делать проверку.
|
||||||
|
|
||||||
|
В любом случае, нужно смотреть на уместность того или иного подхода в каждом
|
||||||
|
случае, и не использовать их одновременно.
|
49
tasks.py
Normal file
49
tasks.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
from fabric import Connection
|
||||||
|
from invoke import task
|
||||||
|
from datetime import datetime
|
||||||
|
import subprocess
|
||||||
|
import shlex
|
||||||
|
|
||||||
|
APP_NAME = "homepage"
|
||||||
|
SSH_HOST = "homepage@51.250.85.23"
|
||||||
|
DOCKER_REGISTRY = "cr.yandex/crplfk0168i4o8kd7ade"
|
||||||
|
|
||||||
|
|
||||||
|
def run(args):
|
||||||
|
return subprocess.run(args, check=True, capture_output=True).stdout
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def deploy(c):
|
||||||
|
timestamp = int(datetime.now().timestamp())
|
||||||
|
commit = run(["git", "rev-parse", "--short", "HEAD"]).decode("utf-8").strip()
|
||||||
|
nginx_image_tag = f"{DOCKER_REGISTRY}/homepage-nginx:{commit}-{timestamp}"
|
||||||
|
|
||||||
|
print(f"Build nginx image {nginx_image_tag}")
|
||||||
|
|
||||||
|
run(
|
||||||
|
[
|
||||||
|
"docker",
|
||||||
|
"build",
|
||||||
|
"--file",
|
||||||
|
"docker/Dockerfile.nginx.prod",
|
||||||
|
"--tag",
|
||||||
|
nginx_image_tag,
|
||||||
|
".",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
print("Push nginx image")
|
||||||
|
|
||||||
|
run(["docker", "push", nginx_image_tag])
|
||||||
|
|
||||||
|
print("Ready to setup remote host")
|
||||||
|
|
||||||
|
with Connection(SSH_HOST) as c:
|
||||||
|
c.put(
|
||||||
|
"./docker/docker-compose.prod.yml",
|
||||||
|
remote="/home/homepage/docker-compose.yml",
|
||||||
|
)
|
||||||
|
c.run("cp .env .env.prod")
|
||||||
|
c.run(f"echo NGINX_IMAGE={shlex.quote(nginx_image_tag)} >> .env.prod")
|
||||||
|
c.run(f"docker-compose --project-name {shlex.quote(APP_NAME)} --env-file=.env.prod up --detach")
|
@ -1,8 +1,15 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
source .env
|
source .env
|
||||||
|
|
||||||
docker build \
|
docker build \
|
||||||
--file docker/Dockerfile \
|
--file docker/php/Dockerfile \
|
||||||
--tag "${PHP_IMAGE}" \
|
--tag "${PHP_IMAGE}" \
|
||||||
"$PWD"
|
"$PWD"
|
||||||
|
|
||||||
|
docker build \
|
||||||
|
--file docker/node/Dockerfile \
|
||||||
|
--tag "${NODE_IMAGE}" \
|
||||||
|
"$PWD"
|
||||||
|
@ -6,8 +6,7 @@ docker run \
|
|||||||
--rm \
|
--rm \
|
||||||
--interactive \
|
--interactive \
|
||||||
--tty \
|
--tty \
|
||||||
--init \
|
|
||||||
--user "$UID:$(id -g)" \
|
--user "$UID:$(id -g)" \
|
||||||
--volume="$PWD:/srv/app" \
|
--volume "$PWD:/srv/app" \
|
||||||
"${PHP_IMAGE}" \
|
"${PHP_IMAGE}" \
|
||||||
./vendor/bin/php-cs-fixer "$@"
|
php-cs-fixer "$@"
|
||||||
|
Loading…
Reference in New Issue
Block a user