
Для некоторых современных программистов не существует систем контроля версий кроме Git, но на практике Subversion всё ещё востребован, а Mercurial имеет своих ярых сторонников. Быстрый поиск в подкрепление.
В результате DevOps’ы не монопроектных компаний встречаются с необходимостью автоматизировать работу с весьма разными системами. При этом у каждой есть свои нюансы и неизбежно появляются скрытые ошибки в сценариях, выстреливающие в самый неподходящий момент. Возникает потребность в предсказуемом поведении с минимальной "гибкостью", а не пёстрым букетом возможностей.
Интерфейс
В статье знакомства с FutoIn CID уже описывалась неявная работа с различными VCS. В версии v0.7 был добавлен явный командный интерфейс и новый функционал для автоматизации создания и слияния веток:
В общем-то сам интерфейс с комментариями ниже:
cid vcs checkout [<vcs_ref>] [--vcsRepo=<vcs_repo>] [--wcDir=<wc_dir>] cid vcs commit <commit_msg> [<commit_files>...] [--wcDir=<wc_dir>] cid vcs merge <vcs_ref> [--no-cleanup] [--wcDir=<wc_dir>] cid vcs branch <vcs_ref> [--wcDir=<wc_dir>] cid vcs delete <vcs_ref> [--vcsRepo=<vcs_repo>] [--cacheDir=<cache_dir>] [--wcDir=<wc_dir>] cid vcs export <vcs_ref> <dst_dir> [--vcsRepo=<vcs_repo>] [--cacheDir=<cache_dir>] [--wcDir=<wc_dir>] cid vcs tags [<tag_pattern>] [--vcsRepo=<vcs_repo>] [--cacheDir=<cache_dir>] [--wcDir=<wc_dir>] cid vcs branches [<branch_pattern>] [--vcsRepo=<vcs_repo>] [--cacheDir=<cache_dir>] [--wcDir=<wc_dir>] cid vcs reset [--wcDir=<wc_dir>] cid vcs ismerged <vcs_ref> [--wcDir=<wc_dir>]
Если отстраниться от лозунгов об идейном превосходстве децентрализованных систем контроля версий, то в сухом остатке в разработке любого состоятельного проекта остаётся всё та же клиент-серверная модель с дополнительными плюшками на клиентской стороне. Вторым очевидным моментом является беспроблемная "эмуляция" клиент-серверной модели в распределённых системах и сложность реализации обратного. Этим и обусловлена логика работы — обязательная неявная синхронизацию с сервером.
Это подразумевает такую таблицу соответствия:
| CID | Git | Mercurial | Subversion |
|---|---|---|---|
cid vcs checkout |
git clone/fetch + git checkout |
hg pull + hg checkout |
svn checkout/switch |
cid vcs commit |
git commit + git push |
hg commit + hg push |
svn commit |
cid vcs merge |
git merge + git push |
hg merge + hg push |
svn merge + svn commit |
cid vcs branch |
git checkout -b + git push |
hg branch + hg push |
svn copy |
cid vcs delete |
git branch -D + git push -f --delete |
hg checkout + hg commit --close-branch + hg push |
svn remove |
cid vcs export |
git fetch/clone --mirror --depth=1 + git archive | tar |
hg archive --type files + .hg* cleanup |
svn export |
cid vcs tags |
git ls-remote |
hg tags |
svn ls {repo}/tags |
cid vcs branches |
git ls-remote |
hg branches |
svn ls {repo}/branches |
cid vcs reset |
git merge --abort + git reset --hard |
hg update --clean + hg purge -I **/*.orig |
svn revert -R . |
cid vcs ismerged |
git branch -r --merged HEAD |
hg merge --preview |
svn mergeinfo --show-revs eligible |
Вроде бы достаточно понятно при всей лаконичности. Стоит лишь отметить, что:
- SVN полагается на слияние без явных указаний ревизий — "знай что делаешь".
- В Hg нет удаления веток, а bookmarks больше напоминают костыль.
- Разумеется, хоть на этих трёх системах свет клином и сошёлся, есть возможность добавить поддержку любой другой через механизм плагинов.
Немного примеров
Все примеры без лишних слов: маленький комментарий, последовательность команд как есть и наглядный результат.
> Подготовительные работы
Снова используем чистый Debian Jessie. Сделаем Git репозиторий, добавим файл README.txt и LICENSE, сделаем вторую ветку develop.
sudo apt-get install -y python-pip sudo pip install futoin-cid VCS_REPO_DIR=${HOME}/repo VCS_REPO=git:${VCS_REPO_DIR} function prep_cache_dir() { local repo=$1 local cache_dir=$(echo $repo | sed -e 's,[/:@],_,g') [ -d $cache_dir ] && cid vcs reset --wcDir=$cache_dir 1>&2 echo $cache_dir } # set -x is too verbose function cid() { echo '$' cid "$@" 1>&2 $(which cid) "$@" } rm ${VCS_REPO_DIR} wc $(prep_cache_dir ${VCS_REPO}) -rf cid tool exec git -- init --bare ${VCS_REPO_DIR} cid vcs checkout --vcsRepo=${VCS_REPO} --wcDir=wc # Commit All echo 'Info' > wc/README.txt cid vcs commit 'Initial commit' --wcDir=wc # Commit specific file(s) echo 'License' > wc/LICENSE cid vcs commit 'Adding license' LICENSE --wcDir=wc cid vcs branch develop --wcDir=wc

> Job Story №1: когда начинается работа над новой фичей, требуется автоматическое создание ветки, чтобы упорядочить наименование
Примечание: подразумевается, что разработчики не могут создавать ветки самостоятельно или это не приветствуется, а в трекере неким образом срабатывает триггер.
function on_feature_start() { local repo="$1" local feature="$2" local cache_dir=$(prep_cache_dir $repo) cid vcs checkout develop --vcsRepo=$repo --wcDir=$cache_dir cid vcs branch feature-${feature} --wcDir=$cache_dir } function list_branches() { # Remote case cid vcs branches --vcsRepo=${VCS_REPO} # Local case cid vcs branches --wcDir=wc } on_feature_start "${VCS_REPO}" '123_one' on_feature_start "${VCS_REPO}" '234_two' list_branches

> Job Story №2: каждую ночь (каждый коммит), требуется сливать develop (release) ветку в ветку feature (develop), чтобы избежать расхождений и обеспечить соблюдение процесса
Примечание: такой рабочий процесс принято считать идеологически верным [и безопасным], хотя rebase делает более стерильную и понятную историю.
Подготовка веток:
cid vcs checkout develop --wcDir=wc echo 'Info 2' > wc/README.txt cid vcs commit 'Commit 2' --wcDir=wc cid vcs checkout feature-234_two --wcDir=wc echo 'Info 3' > wc/README.txt cid vcs commit 'Conflict 3' --wcDir=wc

function sync_branches() { local repo="$1" local cache_dir=$(prep_cache_dir $repo) local logfile=$(realpath $2) cid vcs checkout develop --vcsRepo=$repo --wcDir=$cache_dir pushd $cache_dir # Release -> Develop echo >$logfile for b in $(cid vcs branches 'release*'); do echo -n "Merging $b into develop: " >>$logfile cid vcs merge $b && \ echo 'OK' >>$logfile || \ echo 'FAIL' >>$logfile done # Develop -> Feature for b in $(cid vcs branches 'feature*'); do echo -n "Merging develop into $b: " >>$logfile cid vcs checkout $b && \ cid vcs merge develop && \ echo 'OK' >>$logfile || \ echo 'FAIL' >>$logfile done popd } sync_branches "${VCS_REPO}" merge.log cat merge.log

Ошибка ожидаемая — мы специально создали конфликт, а вот опечатка в ней — нет. Будет исправлено в следующем релизе.
> Job Story №3: после релиза, удалять все включённые feature ветки, чтобы не засорять пространство имён
Примечание: для Hg и SVN вообще нет ничего страшного, а вот для Git есть риск потерять коммиты — поэтому желательно иметь read-only зеркало для истории.
function remove_merged() { local repo="$1" local cache_dir=$(prep_cache_dir $repo) local logfile=$(realpath $2) cid vcs checkout develop --vcsRepo=$repo --wcDir=$cache_dir pushd $cache_dir echo >$logfile # Removed merged into develop for b in $(cid vcs branches 'feature*'); do if ! cid vcs ismerged $b; then continue fi echo -n "Removing $b: " >>$logfile cid vcs delete $b && \ echo 'OK' >>$logfile || \ echo 'FAIL' >>$logfile done popd } # Merge first branch cid vcs checkout develop --wcDir=wc cid vcs merge feature-123_one --wcDir=wc # Try cleanup remove_merged "${VCS_REPO}" delete.log cat delete.log

> Job Story №4: с заданной периодичностью, генерировать файлы и отправлять в VCS, чтобы иметь целостную историю изменений
Примеры: а) загружаемые файлы в коммерческом блоге или новостном сайте имеют определённую ценность, для повышения целостности и эффективности архивирования крайне уместным становится Subversion б) пример постоянно обновляемых чёрных списков адресов активных атак, без участия FutoIn CID.
function update_file() { local repo="$1" local cache_dir=$(prep_cache_dir $repo) cid vcs checkout develop --vcsRepo=$repo --wcDir=$cache_dir pushd $cache_dir date > Timestamp.txt cid vcs commit 'Updated timestamp' Timestamp.txt popd } update_file "${VCS_REPO}"

> Job Story №5: каждую ночь, требуется обновлять зависимости во всех проектах, чтобы всегда использовать актуальные версии
Примечание: может быть куча других вариаций автоматизированной обработки списка проектов.
function update_project_deps() { local repo="$1" local cache_dir=$(prep_cache_dir $repo) cid vcs checkout develop --vcsRepo=$repo --wcDir=$cache_dir pushd $cache_dir date > Timestamp.txt for t in $(cid tool detect); do case $t in npm*|composer*|bundler*) cid tool exec $t -- update ;; esac done cid vcs commit 'Updated dependencies' popd } update_project_deps "${VCS_REPO}"

В пример не были добавлены файлы npm/composer/bundler чтобы не загромождать.
Заключение
В целом FutoIn CID не навязывает какие-то технологические процессы, а лишь предоставляет единый легковесный интерфейс к VCS/SCM для простора творчества админа, DevOps’а и даже разработчика в рамках командной строки.
Разумеется интерфейс ещё полностью не устаканился, возможны обратно совместимые изменения. Любые найденные проблемы, предложения и пожелания приветствуются.
ссылка на оригинал статьи https://habrahabr.ru/post/326928/
Добавить комментарий