web-dev-qa-db-ja.com

タグサブディレクトリへの変更を回避するためのSVN事前コミットフック

タグのサブディレクトリへの変更を回避するプリコミットフックを追加する方法について明確な指示を持っている人はいますか?

私はすでにインターネットをかなり検索しました。私はこのリンクを見つけました: SVN :: Hooks :: DenyChanges 、しかし私は物事をコンパイルできないようです。

39
Wim Deblauwe

上記のRaimの答えに「コメント」するほどの評判はありませんが、彼は素晴らしい仕事をしましたが、1つの例外を除いて、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パターンの唯一の問題は、リポジトリの「ルート」にある場合にのみ「タグ」と一致したことです。私のレポにはいくつかのプロジェクトがあるので、彼が書いたスクリプトはタグブランチのコミットを許可しました。

また、示されているようにchmod + xを忘れないでください。そうしないと、コミットが失敗してb/cで動作したと思いますが、b/cで失敗しました。

Raimに感謝します。依存関係がないため、他のすべての提案よりもはるかに優れた軽量です!

39
apinstein

タグが作成された後、タグへのコミットを防ぐための短いシェルスクリプトを次に示します。

#!/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

これをSubversionリポジトリのhooks/pre-commitに保存し、chmod +xで実行可能にします。

16
raimue

これが私のWindowsバッチファイルのプリコミットフックです。ユーザーが管理者である場合、他のチェックはスキップされます。コミットメッセージが空かどうか、およびコミットがタグに対するものかどうかをチェックします。注:findstrは、他のプラットフォームでのgrepの代替手段です。

コミットがタグに対するものであるかどうかを確認する方法は、最初にsvnlookが「tags /」を含むかどうかを確認します。次に、svnlook変更が「^ A .tags/[^ /]/$」と一致するかどうかをチェックします。つまり、tags /の下に新しいフォルダーを追加するかどうかをチェックします。

ユーザーは新しいプロジェクトを作成できます。 pre-commitフックを使用すると、ユーザーはtrunk/tags /およびbranches /フォルダを作成できます。ユーザーは、フォルダーtrunk/tags /およびbranch /を削除できません。これは、単一または複数プロジェクトのリポジトリで機能します。

 @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
7
mcdon

このanwserはかなり後のものですが、svnlook changedコマンドの--copy-infoパラメーターを発見しました。

このコマンドの出力では、3列目に「+」が追加されるため、コピーであることがわかります。タグディレクトリへのコミットを確認し、「+」が存在するコミットのみを許可できます。

私のブログ投稿 に出力を追加しました。

6
coudenysj

パーティーにはかなり遅れましたが、 http://Subversion.tigrisのlog-police.pyスクリプトに基づいたpython pre-commitフックを作成しました。 org /

このスクリプトは、必要な処理を行う必要がありますが、ログメッセージが存在することも確認しますが、スクリプトから簡単に削除できます。

いくつかの注意事項:

  • 私はPythonが初めてなので、おそらくより良く書けるでしょう。
  • Python 2.5およびSubversion 1.4を搭載したWindows 2003でのみテストされています。

要件:

  • 転覆
  • Python
  • PythonのSubversionバインディング

最後に、コード:

#!/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 __== '__main__':
  sys.exit(svn.core.run_app(main, sys.argv))
4
Nick Brooks

以前に記述されたスクリプトのほとんどは、いくつかのケースがカバーされていないため不完全です。これは私のスクリプトです:

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を作成し、それ以降のすべてのフォルダーを作成する必要があります。その他の変更はブロックされます。 svnlook changed ...のSubversion bookで説明されているすべてのケースをカバーする以前のスクリプトはほとんどありません。

4
Michael-O

受け入れられた回答は、タグ内のファイルの更新を防ぎますが、タグへのファイルの追加を防ぎません。次のバージョンは両方を処理します。

#!/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
3
Vinay Sahni

最初の答えは追加/ supprファイルを防ぎませんでした、そして新しいタグの作成、および不完全またはバグがある他の多くを防ぎましたので、私はそれを作り直しました

コミット前のフックは次のとおりです。目標は次のとおりです。

  • タグのコミットを許可しない(ファイルの追加/抑制/更新)
  • タグの作成を妨げない

---------ファイル "pre-commit"(リポジトリに入れるhooks folder)---------

#!/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」ファイルの終わり---------

また、svnのすべてのプロジェクトでフックをコピーするために2つのシェルスクリプトを作成しました。1つは読み取り専用のリポジトリを設定します。

---------スクリプト「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」の終わり---------

これらのスクリプトをsvn "root"(私の場合は/ var/svn/repos/svn)から直接実行します。ところで、cronタスクは、それらのスクリプトを毎日実行することにより、新しいリポジトリを自動的に変更するように設定できます。

それが役に立てば幸い。

1
Balmipour

私のバージョンでは、タグの作成と削除のみが許可されています。これは、すべての特殊なケース(ファイルの追加、プロパティの変更など)を処理する必要があります。

#!/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
1
Marián Černý

JIRAを使用している場合、 Commit Policy という名前のアドオンを使用して、リポジトリ内のパスを保護できますカスタムフックを記述することなく

どうやって? 変更されたファイルはパターンと一致する必要がありますという名前の条件を使用します。

コミット内のすべてのファイルで一致する必要がある正規表現タイプの引数があります。そうでない場合、コミットは拒否されます。したがって、あなたの場合、「接頭辞/ tags /で始まらない」ことを意味する正規表現を使用する必要があります。

(同じプラグインで他の多くのスマートチェックを実装できます。)

免責事項:私はこの有料アドオンに取り組んでいる開発者です。

1
Ferenc Kiss

リストされた答えは素晴らしいですが、私が必要とするものを正確に実現したものはありませんでした。タグを簡単に作成できるようにしたいのですが、一度作成すると完全に読み取り専用になります。

また、あなたがこれを行うと愚かな状況を防ぎたい:

svn copy myrepo/trunk myrepo/tags/newrelease

すべてが初めてです。ただし、2回目は、タグが既に存在する場合、myrepo/tags/newrelease/trunkになります。

私の事前コミットフックは、(repo)/tags/(tag)/に一致する既存のSVNディレクトリを検索し、見つかった場合は失敗します。

$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
0
grue