Skip to content

Instantly share code, notes, and snippets.

@hackimov
Created March 11, 2020 05:43
Show Gist options
  • Save hackimov/9b0dbaabdb99cd720e4bc40fb0826c62 to your computer and use it in GitHub Desktop.
Save hackimov/9b0dbaabdb99cd720e4bc40fb0826c62 to your computer and use it in GitHub Desktop.

Revisions

  1. hackimov created this gist Mar 11, 2020.
    504 changes: 504 additions & 0 deletions AutoDeployController.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,504 @@
    <?php /** @noinspection PhpUndefinedMethodInspection PhpUnused */

    /**
    * НЕ ИЗМЕНЯТЬ!!!!! (жене мужу и т.д., а контроллер можно но в исключительных случаях)
    * Автор класса Александр Хакимов https://github.com/hackimov
    * Контроллер который занимается автодеплоем на стэйджинг и продакшин.
    * Это функционал ядра который восприимчив к изменению!
    * Если затронуть код то автодеплой сломается, исключением является если он уже сломался по причине если сервера были перенесены или недоступны из вне!
    */

    namespace App\Http\Controllers\API\autodeploy;

    use App\Http\Controllers\Controller;
    use App\Services\ErgResponseService;
    use Illuminate\Http\JsonResponse;
    use Illuminate\Support\Facades\Config;
    use Illuminate\Http\Request;

    class AutoDeployController extends Controller
    {
    protected static $path = '/home/bitrix/ext_www/';
    protected static $url_path = '@github.com/MicrosDevGroup/';
    protected static $reset = 'git reset --hard 2>&1';
    protected static $git_push = 'git push --force';
    protected static $build = '/home/bitrix/bin/Sencha/Cmd/sencha app build -des ./ 2>&1';
    protected static $cd = 'cd ';
    protected static $and = ' && ';
    protected static $quot = '"';
    protected static $protocol = 'https://';
    protected static $git_pull = 'git pull ';
    protected static $git_ext = '.git';
    protected static $master_branch = ' master 2>&1';
    protected static $dev_branch = ' dev 2>&1';

    public static function back_production(Request $request): JsonResponse
    {
    // получаем параметр payload с входными данными пул реквеста
    $payload = $request->get('payload');
    if(empty($payload)){
    $payload = $request->getContent();
    }

    // форматируем данные
    $pull_response = self::github_pull_request_formatter($payload);

    $return_data['request_content'] = $payload;
    $return_data['request_response'] = $pull_response;

    // проверяем на нужную ли ветку пришёл пул реквест
    if(isset($pull_response['branch']) && $pull_response['branch'] === 'master' && $pull_response['branch'] !== false) {
    $repo = Config::get('application.github.production.backend');
    $token = Config::get('application.github.token');
    $git_repo = Config::get('application.github.github_repo.backend');

    // git reset --hard
    $reset_output = [];
    $reset_command = self::$cd . self::$path . $repo . self::$and . self::$reset;
    exec($reset_command, $reset_output);
    $data['reset_output']['command'] = $reset_command;
    $data['reset_output']['data'] = $reset_output;

    // git pull origin master
    $pull_output = [];
    $pull = self::$git_pull . self::$quot . self::$protocol . $token . self::$url_path . $git_repo . self::$git_ext . self::$quot . self::$master_branch;
    $pull_command = self::$cd . self::$path . $repo . self::$and . $pull;
    exec($pull_command, $pull_output);
    $data['pull_output']['command'] = $pull_command;
    $data['pull_output']['data'] = $pull_output;

    // сообщение об успешном принятии данных с гитхаба
    return ErgResponseService::success('backend production git pull executed successfully', $data);
    }
    // сообщение о том, что это не нужный нам пулл реквест (был прислан на другую ветку или вообще не является пулл реквестом)
    return ErgResponseService::success('get backend push response production but is not needed branch', $return_data);
    }

    public static function back_staging(Request $request): JsonResponse
    {
    // получаем параметр payload с входными данными пул реквеста
    $payload = $request->get('payload');
    if(empty($payload)){
    $payload = $request->getContent();
    }

    // форматируем данные
    $pull_response = self::github_pull_request_formatter($payload);

    $return_data['request_content'] = $payload;
    $return_data['request_response'] = $pull_response;

    // проверяем на нужную ли ветку пришёл пул реквест
    if(isset($pull_response['branch']) && $pull_response['branch'] === 'dev' && $pull_response['branch'] !== false) {
    $repo = Config::get('application.github.staging.backend');
    $token = Config::get('application.github.token');
    $git_repo = Config::get('application.github.github_repo.backend');

    // git reset --hard
    $reset_output = [];
    $reset_command = self::$cd . self::$path . $repo . self::$and . self::$reset;
    exec($reset_command, $reset_output);
    $data['reset_output']['command'] = $reset_command;
    $data['reset_output']['data'] = $reset_output;

    // git pull origin dev
    $pull_output = [];
    $pull = self::$git_pull . self::$quot . self::$protocol . $token . self::$url_path . $git_repo . self::$git_ext . self::$quot . self::$dev_branch;
    $pull_command = self::$cd . self::$path . $repo . self::$and . $pull;
    exec($pull_command, $pull_output);
    $data['pull_output']['command'] = $pull_command;
    $data['pull_output']['data'] = $pull_output;

    // сообщение об успешном принятии данных с гитхаба
    return ErgResponseService::success('backend staging git pull executed successfully', $data);
    }
    // сообщение о том, что это не нужный нам пулл реквест (был прислан на другую ветку или вообще не является пулл реквестом)
    return ErgResponseService::success('get backend push response staging but is not needed branch', $return_data);
    }

    public static function front_production(Request $request): JsonResponse
    {
    // получаем параметр payload с входными данными пул реквеста
    $payload = $request->get('payload');
    if(empty($payload)){
    $payload = $request->getContent();
    }

    // форматируем данные
    $pull_response = self::github_pull_request_formatter($payload);

    $return_data['request_content'] = $payload;
    $return_data['request_response'] = $pull_response;

    // проверяем на нужную ли ветку пришёл пул реквест
    if(isset($pull_response['branch']) && $pull_response['branch'] === 'master' && $pull_response['branch'] !== false) {
    $repo = Config::get('application.github.production.frontend');
    $token = Config::get('application.github.token');
    $git_repo = Config::get('application.github.github_repo.frontend');

    // git reset --hard
    $reset_output = [];
    $reset_command = self::$cd . self::$path . $repo . self::$and . self::$reset;
    exec($reset_command, $reset_output);
    $data['reset_output']['command'] = $reset_command;
    $data['reset_output']['data'] = $reset_output;

    // git pull origin master
    $pull_output = [];
    $pull = self::$git_pull . self::$quot . self::$protocol . $token . self::$url_path . $git_repo . self::$git_ext . self::$quot . self::$master_branch;
    $pull_command = self::$cd . self::$path . $repo . self::$and . $pull;
    exec($pull_command, $pull_output);
    $data['pull_output']['command'] = $pull_command;
    $data['pull_output']['data'] = $pull_output;

    // sencha app build -des ./
    $build_output = [];
    $build_command = self::$cd . self::$path . $repo . self::$and . self::$build;
    exec($build_command, $build_output);
    $data['build_output']['command'] = $build_command;
    $data['build_output']['data'] = $build_output;

    // ищем ошибки билда
    $build_errors = [];
    foreach ($build_output as $build_string) {
    if(false !== stripos($build_string, '[ERR]')) {
    $build_errors[] = $build_string;
    }
    }
    $data['build_output']['data']['errors'] = $build_errors;

    if(empty($build_errors)){
    // сообщение об успешном принятии данных с гитхаба и билд прошёл без ошибок
    return ErgResponseService::success('frontend production git pull and build executed successfully without errors', $data);
    }

    // обработка проблемного реквеста с ошибками в билде (откат последнего пул реквеста на основной ветке)

    // git reset --hard
    $reset_output_force = [];
    $reset_command_force = self::$cd . self::$path . $repo . self::$and . self::$reset;
    exec($reset_command_force, $reset_output_force);
    $data['reset_output_force']['command'] = $reset_command_force;
    $data['reset_output_force']['data'] = $reset_output_force;

    // git push origin master --force
    $push_output_force = [];
    $push_force = self::$git_push . self::$quot . self::$protocol . $token . self::$url_path . $git_repo . self::$git_ext . self::$quot . self::$master_branch;
    $push_command_force = self::$cd . self::$path . $repo . self::$and . $push_force;
    exec($push_command_force, $push_output_force);
    $data['push_output_force']['command'] = $push_command_force;
    $data['push_output_force']['data'] = $push_output_force;

    // sencha app build -des ./
    $build_output_force = [];
    $build_command_force = self::$cd . self::$path . $repo . self::$and . self::$build;
    exec($build_command_force, $build_output_force);
    $data['build_output_force']['command'] = $build_command_force;
    $data['build_output_force']['data'] = $build_output_force;

    // сообщение о проблемном пулл реквесте, и откат на предыдущий, с выводом ошибок проблемного билда в ответе
    return ErgResponseService::success('frontend production git pull and build executed successfully but with errors. last commit build', $data);
    }
    // сообщение о том, что это не нужный нам пулл реквест (был прислан на другую ветку или вообще не является пулл реквестом)
    return ErgResponseService::success('get frontend push response production but is not needed branch', $return_data);
    }

    public static function front_staging(Request $request): JsonResponse
    {
    // получаем параметр payload с входными данными пул реквеста
    $payload = $request->get('payload');
    if(empty($payload)){
    $payload = $request->getContent();
    }

    // форматируем данные
    $pull_response = self::github_pull_request_formatter($payload);

    $return_data['request_content'] = $payload;
    $return_data['request_response'] = $pull_response;

    // проверяем на нужную ли ветку пришёл пул реквест
    if(isset($pull_response['branch']) && $pull_response['branch'] === 'dev' && $pull_response['branch'] !== false) {
    $repo = Config::get('application.github.staging.frontend');
    $token = Config::get('application.github.token');
    $git_repo = Config::get('application.github.github_repo.frontend');

    // git reset --hard
    $reset_output = [];
    $reset_command = self::$cd . self::$path . $repo . self::$and . self::$reset;
    exec($reset_command, $reset_output);
    $data['reset_output']['command'] = $reset_command;
    $data['reset_output']['data'] = $reset_output;

    // git pull origin dev
    $pull_output = [];
    $pull = self::$git_pull . self::$quot . self::$protocol . $token . self::$url_path . $git_repo . self::$git_ext . self::$quot . self::$dev_branch;
    $pull_command = self::$cd . self::$path . $repo . self::$and . $pull;
    exec($pull_command, $pull_output);
    $data['pull_output']['command'] = $pull_command;
    $data['pull_output']['data'] = $pull_output;

    // sencha app build -des ./
    $build_output = [];
    $build_command = self::$cd . self::$path . $repo . self::$and . self::$build;
    exec($build_command, $build_output);
    $data['build_output']['command'] = $build_command;
    $data['build_output']['data'] = $build_output;

    // ищем ошибки билда
    $build_errors = [];
    foreach ($build_output as $build_string) {
    if(false !== stripos($build_string, '[ERR]')) {
    $build_errors[] = $build_string;
    }
    }
    $data['build_output']['data']['errors'] = $build_errors;

    if(empty($build_errors)){
    // сообщение об успешном принятии данных с гитхаба и билд прошёл без ошибок
    return ErgResponseService::success('frontend staging git pull and build executed successfully without errors', $data);
    }

    // обработка проблемного реквеста с ошибками в билде (откат последнего пул реквеста на основной ветке)

    // git reset --hard
    $reset_output_force = [];
    $reset_command_force = self::$cd . self::$path . $repo . self::$and . self::$reset;
    exec($reset_command_force, $reset_output_force);
    $data['reset_output_force']['command'] = $reset_command_force;
    $data['reset_output_force']['data'] = $reset_output_force;

    // git push origin dev --force
    $push_output_force = [];
    $push_force = self::$git_push . self::$quot . self::$protocol . $token . self::$url_path . $git_repo . self::$git_ext . self::$quot . self::$dev_branch;
    $push_command_force = self::$cd . self::$path . $repo . self::$and . $push_force;
    exec($push_command_force, $push_output_force);
    $data['push_output_force']['command'] = $push_command_force;
    $data['push_output_force']['data'] = $push_output_force;

    // sencha app build -des ./
    $build_output_force = [];
    $build_command_force = self::$cd . self::$path . $repo . self::$and . self::$build;
    exec($build_command_force, $build_output_force);
    $data['build_output_force']['command'] = $build_command_force;
    $data['build_output_force']['data'] = $build_output_force;

    // сообщение о проблемном пулл реквесте, и откат на предыдущий, с выводом ошибок проблемного билда в ответе
    return ErgResponseService::success('frontend staging git pull and build executed successfully but with errors. last commit build', $data);
    }
    // сообщение о том, что это не нужный нам пулл реквест (был прислан на другую ветку или вообще не является пулл реквестом)
    return ErgResponseService::success('get frontend push response staging but is not needed branch', $return_data);
    }

    public static function admin_production(Request $request): JsonResponse
    {
    // получаем параметр payload с входными данными пул реквеста
    $payload = $request->get('payload');
    if(empty($payload)){
    $payload = $request->getContent();
    }

    // форматируем данные
    $pull_response = self::github_pull_request_formatter($payload);

    $return_data['request_content'] = $payload;
    $return_data['request_response'] = $pull_response;

    // проверяем на нужную ли ветку пришёл пул реквест
    if(isset($pull_response['branch']) && $pull_response['branch'] === 'master' && $pull_response['branch'] !== false) {
    $repo = Config::get('application.github.production.admin');
    $token = Config::get('application.github.token');
    $git_repo = Config::get('application.github.github_repo.admin');

    // git reset --hard
    $reset_output = [];
    $reset_command = self::$cd . self::$path . $repo . self::$and . self::$reset;
    exec($reset_command, $reset_output);
    $data['reset_output']['command'] = $reset_command;
    $data['reset_output']['data'] = $reset_output;

    // git pull origin master
    $pull_output = [];
    $pull = self::$git_pull . self::$quot . self::$protocol . $token . self::$url_path . $git_repo . self::$git_ext . self::$quot . self::$master_branch;
    $pull_command = self::$cd . self::$path . $repo . self::$and . $pull;
    exec($pull_command, $pull_output);
    $data['pull_output']['command'] = $pull_command;
    $data['pull_output']['data'] = $pull_output;

    // сообщение об успешном принятии данных с гитхаба
    return ErgResponseService::success('admin production git pull executed successfully', $data);
    }
    // сообщение о том, что это не нужный нам пулл реквест (был прислан на другую ветку или вообще не является пулл реквестом)
    return ErgResponseService::success('get admin panel push response production but is not needed branch', $return_data);
    }

    public static function admin_staging(Request $request): JsonResponse
    {
    // получаем параметр payload с входными данными пул реквеста
    $payload = $request->get('payload');
    if(empty($payload)){
    $payload = $request->getContent();
    }

    // форматируем данные
    $pull_response = self::github_pull_request_formatter($payload);

    $return_data['request_content'] = $payload;
    $return_data['request_response'] = $pull_response;

    // проверяем на нужную ли ветку пришёл пул реквест
    if(isset($pull_response['branch']) && $pull_response['branch'] === 'dev' && $pull_response['branch'] !== false) {
    $repo = Config::get('application.github.staging.admin');
    $token = Config::get('application.github.token');
    $git_repo = Config::get('application.github.github_repo.admin');

    // git reset --hard
    $reset_output = [];
    $reset_command = self::$cd . self::$path . $repo . self::$and . self::$reset;
    exec($reset_command, $reset_output);
    $data['reset_output']['command'] = $reset_command;
    $data['reset_output']['data'] = $reset_output;

    // git pull origin dev
    $pull_output = [];
    $pull = self::$git_pull . self::$quot . self::$protocol . $token . self::$url_path . $git_repo . self::$git_ext . self::$quot . self::$dev_branch;
    $pull_command = self::$cd . self::$path . $repo . self::$and . $pull;
    exec($pull_command, $pull_output);
    $data['pull_output']['command'] = $pull_command;
    $data['pull_output']['data'] = $pull_output;

    // сообщение об успешном принятии данных с гитхаба
    return ErgResponseService::success('admin staging git pull executed successfully', $data);
    }
    // сообщение о том, что это не нужный нам пулл реквест (был прислан на другую ветку или вообще не является пулл реквестом)
    return ErgResponseService::success('get admin panel push response staging but is not needed branch', $return_data);
    }


    public static function auth_production(Request $request): JsonResponse
    {
    // получаем параметр payload с входными данными пул реквеста
    $payload = $request->get('payload');
    if(empty($payload)){
    $payload = $request->getContent();
    }

    // форматируем данные
    $pull_response = self::github_pull_request_formatter($payload);

    $return_data['request_content'] = $payload;
    $return_data['request_response'] = $pull_response;

    // проверяем на нужную ли ветку пришёл пул реквест
    if(isset($pull_response['branch']) && $pull_response['branch'] === 'master' && $pull_response['branch'] !== false) {
    $repo = Config::get('application.github.production.auth');
    $token = Config::get('application.github.token');
    $git_repo = Config::get('application.github.github_repo.auth');

    // git reset --hard
    $reset_output = [];
    $reset_command = self::$cd . self::$path . $repo . self::$and . self::$reset;
    exec($reset_command, $reset_output);
    $data['reset_output']['command'] = $reset_command;
    $data['reset_output']['data'] = $reset_output;

    // git pull origin master
    $pull_output = [];
    $pull = self::$git_pull . self::$quot . self::$protocol . $token . self::$url_path . $git_repo . self::$git_ext . self::$quot . self::$master_branch;
    $pull_command = self::$cd . self::$path . $repo . self::$and . $pull;
    exec($pull_command, $pull_output);
    $data['pull_output']['command'] = $pull_command;
    $data['pull_output']['data'] = $pull_output;

    // сообщение об успешном принятии данных с гитхаба
    return ErgResponseService::success('auth production git pull executed successfully', $data);
    }
    // сообщение о том, что это не нужный нам пулл реквест (был прислан на другую ветку или вообще не является пулл реквестом)
    return ErgResponseService::success('get auth repo push response production but is not needed branch', $return_data);
    }

    public static function auth_staging(Request $request): JsonResponse
    {
    // получаем параметр payload с входными данными пул реквеста
    $payload = $request->get('payload');
    if(empty($payload)){
    $payload = $request->getContent();
    }

    // форматируем данные
    $pull_response = self::github_pull_request_formatter($payload);

    $return_data['request_content'] = $payload;
    $return_data['request_response'] = $pull_response;

    // проверяем на нужную ли ветку пришёл пул реквест
    if(isset($pull_response['branch']) && $pull_response['branch'] === 'dev' && $pull_response['branch'] !== false) {
    $repo = Config::get('application.github.staging.auth');
    $token = Config::get('application.github.token');
    $git_repo = Config::get('application.github.github_repo.auth');

    // git reset --hard
    $reset_output = [];
    $reset_command = self::$cd . self::$path . $repo . self::$and . self::$reset;
    exec($reset_command, $reset_output);
    $data['reset_output']['command'] = $reset_command;
    $data['reset_output']['data'] = $reset_output;

    // git pull origin dev
    $pull_output = [];
    $pull = self::$git_pull . self::$quot . self::$protocol . $token . self::$url_path . $git_repo . self::$git_ext . self::$quot . self::$dev_branch;
    $pull_command = self::$cd . self::$path . $repo . self::$and . $pull;
    exec($pull_command, $pull_output);
    $data['pull_output']['command'] = $pull_command;
    $data['pull_output']['data'] = $pull_output;

    // сообщение об успешном принятии данных с гитхаба
    return ErgResponseService::success('auth staging git pull executed successfully', $data);
    }
    // сообщение о том, что это не нужный нам пулл реквест (был прислан на другую ветку или вообще не является пулл реквестом)
    return ErgResponseService::success('get auth repo push response staging but is not needed branch', $return_data);
    }

    /**
    * @param $json
    * @return array|bool
    * функция возвращает результат форматирования входящих данных пулл реквеста и выдаёт необходимые данные
    */
    public static function github_pull_request_formatter($json)
    {
    // декодируем тело реквеста
    $request = json_decode($json, true);

    $pull_response = [];

    // если нам прислали подмассив с полным путем, обрабатываем и получаем название ветки
    if(isset($request['ref'])){
    $branch_data = explode('/', $request['ref']);
    $branch = end($branch_data);
    $pull_response['branch'] = $branch;
    }

    // смотрим кто был инициатором пулл реквеста
    if(isset($request['head_commit']['committer']['username'])){
    $pull_response['pushed_from'] = $request['head_commit']['committer']['username'];
    }

    // регулярное выражение которое проверяет является ли это пулл реквестом
    $merge_pattern = '/Merge pull request/m';
    if(isset($request['head_commit']['message']) && preg_match($merge_pattern, $request['head_commit']['message'])){
    $pull_response['github_merge'] = true;
    } else {
    $pull_response['github_merge'] = false;
    }

    // если это не пул реквест возвращает пустой результат
    if(empty($pull_response)){
    return false;
    }

    // возвращаем результат форматированны пул реквест
    return $pull_response;
    }

    }