SVN pre-commit hook for avoiding changes to tags subdirectories

前端 未结 11 720
陌清茗
陌清茗 2020-11-28 04:25

Is there anybody who has clear instructions on how to add a pre-commit hook that avoids changes to tags subdirectories?

I already searched the internet quite a bit.

11条回答
  •  一个人的身影
    2020-11-28 05:04

    Pretty late to the party, however I wrote a python pre-commit hook for work which is based off the log-police.py script on http://subversion.tigris.org/.

    This script should do what you want, however it also checks that a log message exists, though that should be easy to remove from the script.

    Some caveats:

    • I'm new to Python, so it most likely could be written better
    • It has only been tested on Windows 2003 with Python 2.5 and Subversion 1.4.

    Requirements:

    • Subversion
    • Python
    • Subversion bindings for Python

    Finally, the code:

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

提交回复
热议问题