Универсальная работа с VCS/SCM в рамках автоматизации с FutoIn CID

от автора

use cases

Для некоторых современных программистов не существует систем контроля версий кроме 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

Вроде бы достаточно понятно при всей лаконичности. Стоит лишь отметить, что:

  1. SVN полагается на слияние без явных указаний ревизий — "знай что делаешь".
  2. В Hg нет удаления веток, а bookmarks больше напоминают костыль.
  3. Разумеется, хоть на этих трёх системах свет клином и сошёлся, есть возможность добавить поддержку любой другой через механизм плагинов.

Немного примеров

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

> Подготовительные работы

Снова используем чистый 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

prepare

> 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

case #1

> 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

case #2 prepare

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

case #2

Ошибка ожидаемая — мы специально создали конфликт, а вот опечатка в ней — нет. Будет исправлено в следующем релизе.

> 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

case #3

> 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}"

case #4

> 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}"

case #5
В пример не были добавлены файлы npm/composer/bundler чтобы не загромождать.

Заключение

В целом FutoIn CID не навязывает какие-то технологические процессы, а лишь предоставляет единый легковесный интерфейс к VCS/SCM для простора творчества админа, DevOps’а и даже разработчика в рамках командной строки.

Разумеется интерфейс ещё полностью не устаканился, возможны обратно совместимые изменения. Любые найденные проблемы, предложения и пожелания приветствуются.

ссылка на оригинал статьи https://habrahabr.ru/post/326928/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *