paint-brush
Использование Git Hooks с MySQLк@yuridanilov
4,692 чтения
4,692 чтения

Использование Git Hooks с MySQL

к Yuri Danilov7m2023/09/30
Read on Terminal Reader
Read this story w/o Javascript

Слишком долго; Читать

Создать тестовую БД Создать git-перехватчик после получения Выполнение SQL-скриптов при нажатии

People Mentioned

Mention Thumbnail
featured image - Использование Git Hooks с MySQL
Yuri Danilov HackerNoon profile picture
0-item
1-item

Системы контроля версий, и в частности Git, являются важными инструментами для отслеживания изменений кода, совместной работы с вашей командой и обеспечения стабильности вашей кодовой базы. Хотя Git в первую очередь предназначен для исходного кода, вы также можете использовать его в сочетании с базами данных MySQL для контроля версий и управления изменениями схемы.


В этой статье мы рассмотрим, как интегрировать Git с MySQL для управления версиями с помощью перехватчиков Git, с конкретными примерами в формате руководства. Все скрипты, представленные в листингах, полностью функциональны и полны. Вы можете воспроизвести их последовательно в своей тестовой среде.


Прежде всего, давайте создадим тестовую базу данных и пользователя:

 create database testdb_remote; create user 'user_remote'@'localhost' identified WITH mysql_native_password by 'remote123'; grant all on testdb_remote.* to 'user_remote'@'localhost'; 


Создание тестовой базы данных


Далее мы создадим удаленный репозиторий. Это может быть репозиторий на любом удаленном сервере, но для простоты мы создадим его локально. Для удобства выполнения команд я использую git bash. На моем локальном компьютере уже есть папка git, поэтому я использую ее:

 cd /c/git mkdir testdb.remote cd testdb.remote git init --bare 


Создание удаленного репозитория

И создадим локальный репозиторий как клон удаленного:

 cd /c/git git clone /c/git/testdb.remote testdb.local cd testdb.local git ls-files 


Создание локального репо


В репозитории нет файлов; давайте создадим его и отправим наши изменения в удаленный репозиторий:

 echo "Test DB repo" > readme.md git status git add . git commit -m "1st commit" git push 


Первый толчок


Проверим содержимое удаленного репозитория:

 cd /c/git/testdb.remote git ls-tree --full-tree -r HEAD 


Файл в удаленном репозитории


В удаленном репозитории есть папкаooks, содержащая несколько файлов с примерами:

 ls -1 /c/git/testdb.remote/hooks 


Образцы крючков


Хуки — это сценарии, которые выполняются при возникновении определенных событий. В Git есть перехватчики на стороне клиента и на стороне сервера. Перехваты на стороне клиента запускаются такими операциями, как фиксация и слияние. Серверные перехватчики выполняются при сетевых операциях, таких как получение принудительной фиксации. Хуки подробно описаны здесь . Существуют разные варианты реализации логики; Я приведу пример использования серверного хука после получения .


В папке с крючками нам нужно создать файл с именем «post-receive», это обычный bash-скрипт:

 #!/bin/sh while read oval nval ref do echo List of files changed in the commit: git diff --name-only $oval $nval done


Приведенный выше скрипт будет выполняться на сервере при успешном завершении отправки и выводить список измененных файлов. Давайте проверим, как это работает, добавив строку в readme.md и отправив изменения в удаленный репозиторий:

 cd /c/git/testdb.local echo "New line" >> readme.md git add . git commit -m "Line added" git push 


Тестирование скрипта перехвата после получения


Вы можете видеть, что при выполнении команды git push выходные данные теперь содержат строки, начинающиеся с remote: — это выходные данные скрипта после получения, который был выполнен на сервере.

Говоря об основных изменениях, файлы можно добавлять, изменять и удалять. Вы можете использовать разные подходы к тому, как применить эти изменения к базе данных:


  1. Вносите изменения в базу данных только при добавлении новых файлов. В этом случае вы можете сохранить все изменения для конкретной задачи в одном файле. Этот файл может содержать название задачи из системы отслеживания ошибок. Это может быть не очень удобно во время разработки, но с такими изменениями легче справиться.
  2. Храните в репозитории отдельный файл для каждого объекта (таблиц, процедур) и применяйте изменения в базе данных при изменении или добавлении файлов.
  3. Более комплексный подход — создать отдельную папку для каждой задачи (запроса на изменение) и поместить в нее файлы, которые должны быть выполнены в рамках установки данного релиза. При этом создайте дополнительный файл, описывающий список файлов и порядок их установки. Этот подход более гибкий, но в то же время более сложный как для разработки, так и для реализации конвейера.


Предположим, вы выбрали второй вариант, поэтому вам нужно выполнить файлы, которые были добавлены или изменены. Мы можем фильтровать такие файлы, как описано здесь , добавив параметр --diff-filter=AM :

 #!/bin/sh while read oval nval ref do echo List of files added or changed in the commit: git diff --name-only --diff-filter=AM $oval $nval done


Добавьте несколько файлов, а также еще раз измените readme.md:

 echo "SELECT 1;" > test1.sql echo "SELECT 2;" > test2.sql echo "SELECT 3;" > test3.sql echo "New line 2" >> readme.md git add . git commit -m "New files" git push


Вывод скрипта перехватчика содержит 4 файла:

Список всех измененных файлов


Редактируем файлы test1.sql и readme.md, удаляем test2.sql и добавляем еще один файл:

 echo "SELECT 11;" > test1.sql echo "New line 2" >> readme.md rm test2.sql echo "SELECT 4;" > test4.sql git add . git commit -m "Modify, remove and add" git push


Отображаются только измененные и добавленные файлы:

Только добавленные или измененные файлы


Наша цель — выполнять SQL-скрипты после каждого успешного нажатия, поэтому нам нужно фильтровать файлы только этого типа; в нашем случае мы установим требование, чтобы все они имели расширение «.sql». Для фильтрации добавьте параметр -- "*.sql" в команду git diff :

 #!/bin/sh while read oval nval ref do echo List of files added or changed in the commit: git diff --name-only --diff-filter=AM $oval $nval -- "*.sql" done


Для выполнения сценариев мы также должны иметь возможность подключаться к базе данных. Для этого мы создадим учетные данные и проверим соединение:

 mysql_config_editor set --login-path=testdb_remote --host=localhost --port=3306 --user=user_remote --password mysql --login-path=testdb_remote --database=testdb_remote 


Создание учетных данных для MySQL


Измените наш скрипт, чтобы он перебирал файлы «.sql», выполнял каждый файл и проверял результат. Нам также необходимо отсортировать вывод списка, чтобы выполнять файлы в необходимом порядке. С помощью команды git show мы отображаем содержимое SQL-скрипта и передаем его по каналу для выполнения MySQL .

Переменная «$?» будет содержать 0, если SQL-скрипт был выполнен успешно, и другое значение, если произошла ошибка:

 #!/bin/sh while read oval nval ref do echo List of files added or changed in the commit: for file in $(git diff --name-only --diff-filter=AM $oval $nval -- "*.sql" | sort); do git show master:${file} | mysql --login-path=testdb_remote --database=testdb_remote echo "FILE: ${file} - result $?" done done


Выполните еще один тест — удалите все ранее созданные файлы «.sql» и создайте скрипты для:


  • создание таблицы
  • вставка данных в таблицу
  • создание процедуры получения данных из таблицы
  • скрипт, содержащий ошибку


Нам также необходимо добавить префикс (1_, 2_ и т. д.) к каждому имени файла, чтобы обеспечить желаемый порядок выполнения файлов:

 rm *.sql echo "DB Initialization" >> readme.md echo " DROP TABLE IF EXISTS customers; CREATE TABLE customers ( id int UNSIGNED NOT NULL AUTO_INCREMENT, name varchar(255) DEFAULT NULL, PRIMARY KEY (id) ); " > 1_customers.sql echo " INSERT INTO customers (id, name) VALUES (1, 'John Doe'), (2, 'Jane Smith') AS new ON DUPLICATE KEY UPDATE customers.name = new.name; " > 2_customers_init.sql echo " DROP PROCEDURE IF EXISTS get_customer; DELIMITER $$ CREATE PROCEDURE get_customer(IN customer_id int UNSIGNED) BEGIN SELECT c.id, c.name FROM customers c WHERE c.id = customer_id; END $$ " > 3_get_customer.sql echo "SELECT FROM customers;" > 4_error_select.sql ls -1


Итак, у нас есть четыре файла «.sql», которые необходимо выполнить:

Список файлов

Вносим изменения в репозиторий:

Выполняются только файлы SQL


И мы видим, что при выполнении git push файлы выполняются последовательно, и отображается результат выполнения (код завершения команды MySQL) каждого файла. Файл «4_error_select.sql» содержит синтаксическую ошибку, поэтому результат его выполнения равен 1.


И напоследок проверим, что у нас есть в базе:

 mysql --login-path=testdb_remote --database=testdb_remote show tables; call get_customer(1); call get_customer(2); 


Тестирование объектов, созданных в БД


Как видите, таблица и процедура были созданы в удаленной базе данных. Процедура выполняется успешно и возвращает данные.


Чтобы улучшить читаемость вывода сценария ловушки, вы можете подавить вывод MySQL CLI или перенаправить его в файл журнала. Вы также можете проанализировать результат выполнения команды MySQL и добавить дополнительную логику в сценарий перехвата.


Например, вы можете выполнить SQL-скрипты на тестовой базе данных, а затем запустить на ней несколько тестов (как я описал здесь ). Если тесты успешно завершены в тестовой базе данных, запустите сценарии SQL в рабочей базе данных и, возможно, также проведите несколько тестов на ней.

Анализируя результаты каждого шага, можно создавать конвейеры любой конфигурации.


Конечно, каждый подход имеет ряд преимуществ и ограничений. При втором подходе необходимо обеспечить порядок выполнения скриптов, поскольку мы не можем, например, вставлять данные в таблицу, пока она не будет создана. Также необходимо обеспечить возможность повторного выполнения скриптов, т.е. корректно обрабатывать ситуации, когда создаваемый объект уже находится в базе данных, или база данных уже содержит добавляемые данные.


При использовании системы версионирования процесс разработки немного усложняется, поскольку необходимо дополнительно формализовать изменения в скриптах заранее заданного формата. Однако вы можете добиться некоторой гибкости, используя установочный файл.


Основным преимуществом описанной методики является реализация версионирования в базе данных с минимальными усилиями, а также возможность реализации CI/CD-конвейеров .

Чтобы оценить, может ли это быть для вас полезным, вы можете начать с вопроса: как часто вы пишете код непосредственно в рабочей среде?