deployerを使ってLaravelをデプロイ

# Deployerとは
PHPで作られたデプロイツールです。
各種フレームワークをデプロイするレシピを備えており、簡単にデプロイ環境を構築することができます。

### 公式ページ
<a href="https://deployer.org/" target="_blank">https://deployer.org/</a>


# Deployerのインストール方法
composerを使用してインストールします。

```
$ composer require deployer/deployer --dev
```

```
$ vendor/bin/dep
```
でコマンドの一覧が表示されればインストール完了です。


# デプロイ先のhost情報を定義
```yaml:hosts.yaml
staging: # ステージング環境
  hostname: ***.***.***.*** # デプロイ先のホスト名
  stage: staging  # stage名
  roles:
    - app
  deploy_path: /var/www/deploystg # デプロイするPATH
  branch: developer # デプロイ対象のGITブランチ
  user: testuser # デプロイを行うユーザ
  identityFile: ~/.ssh/test_key  # サーバに接続する秘密鍵
production: # 本番環境
  hostname: ***.***.***.*** # デプロイ先のホスト名
  stage: production
  roles:
    - app
  deploy_path: /var/www/deployprod
  branch: master
  user: testuser # デプロイを行うユーザ
  identityFile: ~/.ssh/test_key  # サーバに接続する秘密鍵

```

# 今回作成したTask
## .envファイルを環境毎に準備するTask
```
.env.staging # ステージング環境用の.env
.env.production # 本番環境用の.env
```
デプロイ時の引数により、.envファイルをコピーするTask


```php:deploy.php
task('copy:env', function () {
  if (input()->hasOption('env-update')){
      $update = input()->getOption('env-update');
      if($update == 'true'){
          $stage = get('stage');
          $src = ".env.${stage}";
          $path = get('deploy_path');
          $shared_path = "${path}/shared";
          run("if [ -e $(echo ${shared_path}/.env ) ]; then cp {{release_path}}/${src} ${shared_path}/.env; fi");
          run("cp {{release_path}}/${src} {{release_path}}/.env");
      }
  }
});
```

### デプロイコマンド（本番環境）
- デプロイコマンド（.envファイル含む）
 
```
$ ./vendor/bin/dep deploy production --env-update=true
```
※.envファイルに変更があった場合に当コマンドを実行してください。

- デプロイコマンド（.envファイル含まない）


```
$ ./vendor/bin/dep deploy production
```

### デプロイコマンド（ステージング環境）

- デプロイコマンド（.envファイル含む）

```
$ ./vendor/bin/dep deploy staging --env-update=true
```
※.envファイルに変更があった場合に当コマンドを実行してください。

- デプロイコマンド（.envファイル含まない）

```
$ ./vendor/bin/dep deploy staging
```

※.いずれのコマンドも.envファイルがある階層で実行してください


## npm系のTask
```php:deploy.php
task('npm:run', function (): void {
    run('cd {{release_path}} && chmod 707 public'); // publicディレクトリに書き込み権限を与える
    run('cd {{release_path}} && npm install'); // npmをインストール

    if (input()->getArgument('stage') === 'production') { // 環境によって npm runコマンドを分岐
        run('cd {{release_path}} && npm run production');
    } else {
        run('cd {{release_path}} && npm run development');
    }
})
```
## php系のTask
```php:deploy.php
task('php:run', function (): void {
    run('cd {{release_path}} && composer dump-autoload'); // オートローディングに関する情報ファイルを生成
    run('cd {{release_path}} && php artisan htaccess:ip'); // DBから取得したIPアドレスをhtaccessに追記するコマンド（スクラッチ）
})
```


# 今回作成したdeploy.php
```php:deploy.php
namespace Deployer;
use Symfony\Component\Console\Input\InputOption;

require 'recipe/laravel.php';
require 'recipe/npm.php';;

// Project name
set('application', 'mfqr');

// Project repository
set('repository', 'ss2@ss2.git.backlog.jp:/MF_QRM/mfqr.git');

// [Optional] Allocate tty for git clone. Default value is false.
set('git_tty', true);

set('keep_releases', 10);

// Shared files/dirs between deploys
// アプリケーションの更新に関わらず継続利用したいものを置くディレクトリやファイル
add('shared_files', []);
add('shared_dirs', [
    'vendor'
]);

// Writable dirs by web server
//add('writable_dirs', []);
add('writable_dirs', ['bootstrap/cache', 'storage']);

// Hosts
inventory('hosts.yaml');

// Tasks
option('env-update', null, InputOption::VALUE_OPTIONAL, 'update env file.');

task('copy:env', function () {
  if (input()->hasOption('env-update')){
      $update = input()->getOption('env-update');
      if($update == 'true'){
          $stage = get('stage');
          $src = ".env.${stage}";
          $path = get('deploy_path');
          $shared_path = "${path}/shared";
          run("if [ -e $(echo ${shared_path}/.env ) ]; then cp {{release_path}}/${src} ${shared_path}/.env; fi");
          run("cp {{release_path}}/${src} {{release_path}}/.env");
      }
  }
});

task('npm:run', function (): void {
    run('cd {{release_path}} && chmod 707 public');
    run('cd {{release_path}} && npm install');

    if (input()->getArgument('stage') === 'production') {
        run('cd {{release_path}} && npm run production');
    } else {
        run('cd {{release_path}} && npm run development');
    }
});

task('php:run', function (): void {
    run('cd {{release_path}} && composer dump-autoload');
    run('cd {{release_path}} && php artisan htaccess:ip');
});


task('deploy', [
    'deploy:info',
    'deploy:prepare', // サーバに接続して、ソースコードを配置するディレクトリを作成するTask
    'deploy:lock', // デプロイをlockすすTask
    'deploy:release', // デプロイするソースコードを配置するためのディレクトリを整備するTask
    'deploy:update_code', // git cloneでソースを落とすTask
    'deploy:shared', // リリースバージョンの共有ディレクトリを設置するTask
    'deploy:writable',
    'deploy:vendors', // composerをinstallするTask
    'deploy:clear_paths',
    'deploy:symlink', // シンボリックリンク差し替えるTask
    'deploy:unlock',  // デプロイのlockを解除するTask
    'cleanup',  // 前リリースバージョンを削除するTask
    'success',
]);

  before('deploy:shared', 'copy:env'); // deploy:sharedの前にTaskを実行
  after('deploy:shared', 'npm:run'); // deploy:sharedの後にTaskを実行
  after('deploy:vendors', 'php:run'); // deploy:vendorsの後にTaskを実行

  // [Optional] if deploy fails automatically unlock.
  after('deploy:failed', 'deploy:unlock');

// Migrate database before symlink new release.

//before('deploy:symlink', 'artisan:migrate');
```

hosts.yamlとdeploy.phpをLaravelアプリケーションを.envと同じ階層に設置して、
上記デプロイコマンドを実行すると、デプロイされます。