SVN pre-commit hook для исключения изменений в подкаталогах тэгов

Есть ли у кого есть четкие инструкции о том, как добавить крюк pre-commit, который позволяет избежать изменений в подкаталогах тэгов?

Я уже много раз искал в интернете. Я нашел эту ссылку: SVN::Hooks::DenyChanges, но я не могу скомпилировать вещи.

Ответ 1

У меня недостаточно репутации, чтобы "прокомментировать" ответ на Raim выше, но он отлично работал, за одним исключением, его шаблон grep неправильный.

Я просто использовал нижеследующий как мой крюк для предварительной фиксации (у меня не было существующего, вам нужно было бы слить в этом случае):

#!/bin/sh

REPOS="$1"
TXN="$2"

SVNLOOK=/opt/local/bin/svnlook

# Committing to tags is not allowed
$SVNLOOK changed -t "$TXN" "$REPOS" | grep "^U\W.*\/tags\/" && /bin/echo "Cannot commit to tags!" 1>&2 && exit 1

# All checks passed, so allow the commit.
exit 0

Единственная проблема с шаблоном Raim grep заключается в том, что он соответствует только "тегам", если он был в "корне" вашего репо. Поскольку у меня есть несколько проектов в моем репо, script, как он писал, он допускает фиксации на ветвях тегов.

Кроме того, обязательно укажите chmod + x, как указано, иначе вы подумаете, что это сработало. b/c ошибка завершена, но она не удалась. b/c он не смог выполнить привязку pre-commit, а не потому, что крючок работал.

Это было действительно здорово, спасибо Раим. Намного лучше и легче, чем все другие предложения, поскольку у него нет зависимостей!

Ответ 2

Вот короткая оболочка script, чтобы предотвратить фиксацию тегов после их создания:

#!/bin/sh

REPOS="$1"
TXN="$2"

SVNLOOK=/usr/bin/svnlook

# Committing to tags is not allowed
$SVNLOOK changed -t "$TXN" "$REPOS" | grep "^U\W*tags" && /bin/echo "Cannot commit to tags!" 1>&2 && exit 1

# All checks passed, so allow the commit.
exit 0

Сохраните это в hooks/pre-commit для вашего репозитория Subversion и сделайте его исполняемым с помощью chmod +x.

Ответ 3

Вот мой pre-commit hook для пакетного файла. Если пользователь является администратором, другие проверки будут пропущены. Он проверяет, является ли сообщение фиксации пустым, а фиксация - тегом. Примечание: findstr является альтернативой grep для других платформ.

То, как он проверяет, является ли фиксация тегом, сначала проверяет, содержит ли svnlook "теги/". Затем он проверяет, изменился ли svnlook "^ A.tags/[^/]/$", что означает, что он будет проверять, добавляется ли новая папка под тегами /.

Пользователям разрешено создавать новые проекты. Крючок предварительной фиксации позволяет пользователю создавать соединительные линии/метки папок и ветки /. Пользователям запрещается удалять папки/теги/ветки папок /. Это будет работать для одного или многопроектного репозитория.

 @echo off
 rem This pre-commit hook will block commits with no log messages and blocks commits on tags.
 rem Users may create tags, but not modify them.
 rem If the user is an Administrator the commit will succeed.

 rem Specify the username of the repository administrator
 rem commits by this user are not checked for comments or tags
 rem Recommended to change the Administrator only when an admin commit is neccessary
 rem then reset the Administrator after the admin commit is complete
 rem this way the admin user is only an administrator when neccessary
 set Administrator=Administrator

 setlocal

 rem Subversion sends through the path to the repository and transaction id.
 set REPOS=%1%
 set TXN=%2%

 :Main
 rem check if the user is an Administrator
 svnlook author %REPOS% -t %TXN% | findstr /r "^%Administrator%$" >nul
 if %errorlevel%==0 (exit 0)

 rem Check if the commit has an empty log message
 svnlook log %REPOS% -t %TXN% | findstr . > nul
 if %errorlevel% gtr 0 (goto CommentError)

 rem Block deletion of branches and trunk
 svnlook changed %REPOS% -t %TXN% | findstr /r "^D.*trunk/$ ^D.*branches/$" >nul
 if %errorlevel%==0 (goto DeleteBranchTrunkError)

 rem Check if the commit is to a tag
 svnlook changed %REPOS% -t %TXN% | findstr /r "^.*tags/" >nul
 if %errorlevel%==0 (goto TagCommit)
 exit 0

 :DeleteBranchTrunkError
 echo. 1>&2
 echo Trunk/Branch Delete Error: 1>&2
 echo     Only an Administrator may delete the branches or the trunk. 1>&2
 echo Commit details: 1>&2
 svnlook changed %REPOS% -t %TXN% 1>&2
 exit 1

 :TagCommit
 rem Check if the commit is creating a subdirectory under tags/ (tags/v1.0.0.1)
 svnlook changed %REPOS% -t %TXN% | findstr /r "^A.*tags/[^/]*/$" >nul
 if %errorlevel% gtr 0 (goto CheckCreatingTags)
 exit 0

 :CheckCreatingTags
 rem Check if the commit is creating a tags/ directory
 svnlook changed %REPOS% -t %TXN% | findstr /r "^A.*tags/$" >nul
 if %errorlevel% == 0 (exit 0)
 goto TagsCommitError

 :CommentError
 echo. 1>&2
 echo Comment Error: 1>&2
 echo     Your commit has been blocked because you didn't enter a comment. 1>&2
 echo     Write a log message describing your changes and try again. 1>&2
 exit 1

 :TagsCommitError
 echo. 1>&2
 echo %cd% 1>&2
 echo Tags Commit Error: 1>&2
 echo     Your commit to a tag has been blocked. 1>&2
 echo     You are only allowed to create tags. 1>&2
 echo     Tags may only be modified by an Administrator. 1>&2
 echo Commit details: 1>&2
 svnlook changed %REPOS% -t %TXN% 1>&2
 exit 1

Ответ 4

Этот anwser много после даты, но я обнаружил параметр -copy-info для команды svnlook changed.

Результат этой команды добавляет "+" в третий столбец, поэтому вы знаете, что это копия. Вы можете проверить фиксацию в каталоге тегов и разрешить коммит с присутствием "+".

Я добавил некоторый вывод в мой пост в блоге.

Ответ 5

Довольно поздно, но я написал python pre-commit hook для работы, который основан на log-police.py script на http://subversion.tigris.org/.

Этот script должен делать то, что вы хотите, однако он также проверяет наличие сообщения журнала, хотя его легко удалить из script.

Некоторые оговорки:

  • Я новичок в Python, поэтому он скорее всего может быть написан лучше
  • Он был протестирован только в Windows 2003 с Python 2.5 и Subversion 1.4.

Требования:

  • Subversion
  • Python
  • Связи Subversion для Python

Наконец, код:

#!/usr/bin/env python

#
# pre-commit.py:
#
# Performs the following:
#  - Makes sure the author has entered in a log message.
#  - Make sure author is only creating a tag, or if deleting a tag, author is a specific user
#
# Script based on http://svn.collab.net/repos/svn/trunk/tools/hook-scripts/log-police.py
#
# usage: pre-commit.py -t TXN_NAME REPOS
# E.g. in pre-commit.bat (under Windows)
#   python.exe {common_hooks_dir}\pre_commit.py -t %2 %1
#


import os
import sys
import getopt
try:
  my_getopt = getopt.gnu_getopt
except AttributeError:
  my_getopt = getopt.getopt

import re

import svn
import svn.fs
import svn.repos
import svn.core

#
# Check Tags functionality
#
def check_for_tags(txn):
  txn_root = svn.fs.svn_fs_txn_root(txn)
  changed_paths = svn.fs.paths_changed(txn_root)
  for path, change in changed_paths.iteritems():
    if is_path_within_a_tag(path): # else go to next path
      if is_path_a_tag(path):
        if (change.change_kind == svn.fs.path_change_delete):
          if not is_txn_author_allowed_to_delete(txn):
            sys.stderr.write("\nOnly an administrator can delete a tag.\n\nContact your Subversion Administrator for details.")
            return False
        elif (change.change_kind != svn.fs.path_change_add):
          sys.stderr.write("\nUnable to modify " + path + ".\n\nIt is within a tag and tags are read-only.\n\nContact your Subversion Administrator for details.")
          return False
        # else user is adding a tag, so accept this change
      else:
        sys.stderr.write("\nUnable to modify " + path + ".\n\nIt is within a tag and tags are read-only.\n\nContact your Subversion Administrator for details.")
        return False
  return True

def is_path_within_a_tag(path):
  return re.search('(?i)\/tags\/', path)

def is_path_a_tag(path):
  return re.search('(?i)\/tags\/[^\/]+\/?$', path)

def is_txn_author_allowed_to_delete(txn):
  author = get_txn_property(txn, 'svn:author')
  return (author == 'bob.smith')

#
# Check log message functionality
#
def check_log_message(txn):
  log_message = get_txn_property(txn, "svn:log")
  if log_message is None or log_message.strip() == "":
    sys.stderr.write("\nCannot enter in empty commit message.\n")
    return False
  else:
    return True

def get_txn_property(txn, prop_name):
  return svn.fs.svn_fs_txn_prop(txn, prop_name)

def usage_and_exit(error_msg=None):
  import os.path
  stream = error_msg and sys.stderr or sys.stdout
  if error_msg:
    stream.write("ERROR: %s\n\n" % error_msg)
  stream.write("USAGE: %s -t TXN_NAME REPOS\n"
               % (os.path.basename(sys.argv[0])))
  sys.exit(error_msg and 1 or 0)

def main(ignored_pool, argv):
  repos_path = None
  txn_name = None

  try:
    opts, args = my_getopt(argv[1:], 't:h?', ["help"])
  except:
    usage_and_exit("problem processing arguments / options.")
  for opt, value in opts:
    if opt == '--help' or opt == '-h' or opt == '-?':
      usage_and_exit()
    elif opt == '-t':
      txn_name = value
    else:
      usage_and_exit("unknown option '%s'." % opt)

  if txn_name is None:
    usage_and_exit("must provide -t argument")
  if len(args) != 1:
    usage_and_exit("only one argument allowed (the repository).")

  repos_path = svn.core.svn_path_canonicalize(args[0])

  fs = svn.repos.svn_repos_fs(svn.repos.svn_repos_open(repos_path))
  txn = svn.fs.svn_fs_open_txn(fs, txn_name)

  if check_log_message(txn) and check_for_tags(txn):
    sys.exit(0)
  else:
    sys.exit(1)

if __name__ == '__main__':
  sys.exit(svn.core.run_app(main, sys.argv))

Ответ 6

Принятый ответ предотвращает обновление файлов в теге, но не препятствует добавлению файлов в тег. Следующая версия обрабатывает оба:

#!/bin/sh

REPOS="$1"
TXN="$2"
SVNLOOK="/home/staging/thirdparty/subversion-1.6.17/bin/svnlook"

# Committing to tags is not allowed
$SVNLOOK changed -t "$TXN" "$REPOS" --copy-info| grep -v "^ " | grep -P '^[AU]   \w+/tags/' && /bin/echo "Cannot update tags!" 1>&2 && exit 1

# All checks passed, so allow the commit.
exit 0

Ответ 7

Большинство ранее написанных скриптов являются неполными, поскольку некоторые случаи не покрываются. Это мой script:

contains_tags_dir=`$SVNLOOK changed --copy-info -t "$TXN" "$REPOS" | head -1 | egrep "+\/tags\/.*$" | wc -l | sed "s/ //g"`

if [ $contains_tags_dir -gt 0 ]
then
  tags_dir_creation=`$SVNLOOK changed --copy-info -t "$TXN" "$REPOS" | head -1 | egrep "^A       .+\/tags\/$" | wc -l | sed "s/ //g"`
  if [ $tags_dir_creation -ne 1 ]
  then
    initial_add=`$SVNLOOK changed --copy-info -t "$TXN" "$REPOS" | head -1 | egrep "^A \+ .+\/tags\/.+\/$" | wc -l | sed "s/ //g"`
    if [ $initial_add -ne 1 ]
    then
      echo "Tags cannot be changed!" 1>&2
      exit 1
    fi
  fi
fi

Это может показаться сложным, но вы должны убедиться, что находитесь в /tags, и вам разрешено создавать /tags, если он не существует, и все последующие папки. Любые другие изменения блокируются. Почти ни один из предыдущих сценариев не охватывает все случаи, описанные в книге Subversion для svnlook changed ....

Ответ 8

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

Как? Используйте условие с именем Измененные файлы должны соответствовать шаблону.

У него есть аргумент типа регулярного выражения, который должен соответствовать каждому файлу в фиксации, в противном случае фиксация отклоняется. Итак, в вашем случае вы должны использовать регулярное выражение, которое означает, что "не начинается с префикса /tags/ ".

(Вы можете реализовать многие другие интеллектуальные проверки с помощью одного и того же плагина.)

Отказ от ответственности: я разработчик, работающий над этим платным дополнением.

Ответ 9

Моя версия позволяет создавать и удалять теги. Это должно обрабатывать все особые случаи (например, добавлять файлы, изменять свойства и т.д.).

#!/bin/sh

REPOS="$1"
TXN="$2"
SVNLOOK=/usr/local/bin/svnlook

output_error_and_exit() {
    echo "$1" >&2
    exit 1
}

changed_tags=$( $SVNLOOK changed -t "$TXN" "$REPOS" | grep "[ /]tags/." )

if [ "$changed_tags" ]
then 
    echo "$changed_tags" | egrep -v "^[AD] +(.*/)?tags/[^/]+/$" && output_error_and_exit "Modification of tags is not allowed."
fi 

exit 0

Ответ 10

Поскольку первый ответ не мешал файлам add/suppr, а также предотвращал создание новых тегов и многие другие, где они были неполными или ошибочными, я переработал его

Вот мой крюк с предварительной фиксацией: Цели:

  • Запретить совершать теги (добавление/подавление файлов/обновления)
  • Не мешать созданию тегов

--------- файл "pre-commit" (помещается в папку с папками репозиториев) ---------

#!/bin/sh

REPOS="$1"
TXN="$2"

SVNLOOK=/usr/bin/svnlook

#Logs
#$SVNLOOK changed -t "$TXN" "$REPOS" > /tmp/changes
#echo "$TXN" > /tmp/txn
#echo "$REPOS" > /tmp/repos

# Committing to tags is not allowed
# Forbidden changes are Update/Add/Delete.  /W = non alphanum char  Redirect is necessary to get the error message, since regular output is lost.
# BUT, we must allow tag creation / suppression

$SVNLOOK changed -t "$TXN" "$REPOS" | /bin/grep "^A\W.*tags\/[0-9._-]*\/." && /bin/echo "Commit to tags are NOT allowed ! (Admin custom rule)" 1>&2 && exit 101
$SVNLOOK changed -t "$TXN" "$REPOS" | /bin/grep "^U\W.*tags\/[0-9._-]*\/." && /bin/echo "Commit to tags are NOT allowed ! (Admin custom rule)" 1>&2 && exit 102
$SVNLOOK changed -t "$TXN" "$REPOS" | /bin/grep "^D\W.*tags\/[0-9._-]*\/." && /bin/echo "Commit to tags are NOT allowed ! (Admin custom rule)" 1>&2 && exit 104

# All checks passed, so allow the commit.
exit 0;

--------- конец файла "pre-commit" ---------

Кроме того, я сделал 2 сценария оболочки, чтобы скопировать мой крюк в каждый проект моего svn: Один для установки только репо:

--------- script "setOneRepoTagsReadOnly.sh" ---------

#!/bin/sh

cd /var/svn/repos/svn
zeFileName=$1/hooks/pre-commit
/bin/cp ./CUSTOM_HOOKS/pre-commit $zeFileName
chown www-data:www-data $zeFileName
chmod +x $zeFileName

--------- конец файла "setOneRepoTagsReadOnly.sh" ---------

И каждый, вызывающий его для каждого репо, чтобы сделать все мои репозиции только:

--------- файл "makeTagsReadOnly.sh" ---------

#!/bin/shs/svn                                                                                                                                                                         
#Lists all repos, and adds the pre-commit hook to protect tags on each of them
find /var/svn/repos/svn/ -maxdepth 1 -mindepth 1 -type d -execdir '/var/svn/repos/svn/setOneRepoTagsReadOnly.sh' \{\} \;

--------- конец файла "makeTagsReadOnly.sh" ---------

Я выполняю сценарии thoses непосредственно из svn "root" (/var/svn/repos/svn, в моем случае). Btw, задача cron может быть настроена на автоматическое изменение новых репозиториев путем ежедневного выполнения сценариев thoses

Надеюсь, что это поможет.

Ответ 11

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

Я также хочу предотвратить тупую ситуацию, когда вы это сделаете:

svn copy myrepo/trunk myrepo/tags/newrelease

Все хорошо в первый раз. Но во второй раз, если тег уже существует, вы получите myrepo/tags/newrelease/trunk.

Мой крюк для предварительной фиксации будет искать любой существующий каталог SVN, соответствующий (repo)/tags/(tag)/, и сбой, если он найдет:

$SVNLOOK tree -N --full-paths "$REPOS" "`$SVNLOOK changed -t "$TXN" "$REPOS" \
  | sed 's/[A-Z][[:space:]]*\([^/]*\)\/tags\/\([^/]*\)\/.*/\1\/tags\/\2\//' \
  | head -n 1`" \
  && echo "Tag already exists, commit rejected." >&2 \
  && exit 1