web-dev-qa-db-fra.com

Crochet de pré-validation SVN pour éviter les modifications des sous-répertoires de balises

Quelqu'un a-t-il des instructions claires sur la manière d'ajouter un point d'ancrage de pré-validation qui évite les modifications des sous-répertoires de balises?

J'ai déjà un peu cherché sur Internet. J'ai trouvé ce lien: SVN :: Hooks :: DenyChanges , mais je n'arrive pas à compiler les choses.

37
Wim Deblauwe

Je n'ai pas assez de réputation pour "commenter" la réponse de Raim ci-dessus, mais cela a très bien fonctionné, à une exception près, son motif de grep est erroné.

J'ai simplement utilisé ce qui suit comme crochet de pré-validation (je n'en possédais pas, vous devez le fusionner dans ce cas):

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

Le seul problème avec le modèle grep de Raim est qu'il ne faisait correspondre les "tags" que s'il se trouvait à la "racine" de votre référentiel. Depuis que j'ai plusieurs projets dans mon référentiel, le script tel qu'il l'écrit permettait les commits sur des branches de tags.

Aussi, assurez-vous de chmod + x comme indiqué, sinon vous penserez que cela a fonctionné car la validation a échoué, mais il a échoué car il ne pouvait pas exécuter le hook de pré-commit, pas parce que le hook fonctionnait.

C'était vraiment génial, merci Raim. Beaucoup mieux et plus léger que toutes les autres suggestions car il n'a pas de dépendances!

38
apinstein

Voici un court script Shell pour empêcher la validation des tags après leur création:

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

Enregistrez-le sous hooks/pre-commit pour votre référentiel Subversion et rendez-le exécutable avec chmod +x.

16
raimue

Voici mon crochet de pré-validation de fichier batch Windows. Si l'utilisateur est un administrateur, les autres vérifications seront ignorées. Il vérifie si le message de validation est vide et s'il est destiné à une balise. Remarque: findstr est une alternative nerveuse à grep sur d'autres plates-formes.

La façon dont il vérifie si la validation est une balise, vérifie d’abord si svnlook modifié contient "tags /". Il vérifie ensuite si svnlook modifié correspond à "^ A . tags/[^ /] / $", ce qui signifie qu'il vérifiera si vous ajoutez un nouveau dossier sous tags /.

Les utilisateurs sont autorisés à créer de nouveaux projets. Le hook de pré-validation permet à un utilisateur de créer les dossiers trunk/tags/et branches /. Les utilisateurs ne sont pas autorisés à supprimer les dossiers trunk/tags/et branches /. Cela fonctionnera pour un référentiel unique ou multi-projets.

 @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

Cette réponse est beaucoup après la date, mais j’ai découvert le paramètre --copy-info pour la commande svnlook modified.

La sortie de cette commande ajoute un '+' dans la troisième colonne, vous savez donc qu'il s'agit d'une copie. Vous pouvez vérifier les commits dans le répertoire des tags et n'autoriser que les commits avec un '+'.

J'ai ajouté quelques sorties dans mon article de blog .

6
coudenysj

Assez tard pour le parti, cependant, j’ai écrit un hook de pré-commit python basé sur le script log-police.py de http://Subversion.tigris.org/ .

Ce script doit faire ce que vous voulez, mais il vérifie également l’existence d’un message de journalisation, même si cela doit être facile à supprimer du script.

Quelques mises en garde:

  • Je suis nouveau sur Python, donc il pourrait probablement être mieux écrit
  • Il n'a été testé que sous Windows 2003 avec Python 2.5 et Subversion 1.4.

Exigences:

  • Subversion
  • Python
  • Liaisons Subversion pour Python

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

La plupart des scripts écrits précédemment sont incomplets car plusieurs cas ne sont pas couverts. Ceci est mon 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

Cela peut paraître compliqué, mais vous devez vous assurer que vous êtes bien dans /tags et que vous êtes autorisé à créer /tags s'il n'existe pas et dans tous les dossiers suivants. Tout autre changement est bloqué. Presque aucun des scripts précédents ne couvre tous les cas décrits dans le livre Subversion pour svnlook changed ....

4
Michael-O

La réponse acceptée empêche la mise à jour des fichiers d'une balise, mais pas l'ajout de fichiers à une balise. La version suivante gère les deux:

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

Puisque la 1ère réponse n'a pas empêché l'ajout de fichiers/suppr, et empêché la création de nouvelles balises, et de nombreuses autres où incomplète ou buggy, je l'ai retravaillée

Voici mon crochet pré-commit: Les objectifs sont:

  • Interdire les commits sur les tags (ajout/suppression/mise à jour de fichier)
  • N'empêche pas la création de tags

--------- fichier "pré-commit" (mis dans les référentiels 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;

--------- fin de fichier "pré-commit" ---------

De plus, j'ai créé 2 scripts Shell pour copier mon hook dans chaque projet de mon svn: Un pour définir un repo en lecture seule:

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

--------- fin du fichier "setOneRepoTagsReadOnly.sh" ---------

Et on l’appelle pour chaque repo, pour que tous mes repo soient en lecture seule:

--------- fichier "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' \{\} \;

--------- fin du fichier "makeTagsReadOnly.sh" ---------

J'exécute ces scripts directement à partir de la "racine" svn (/ var/svn/repos/svn, dans mon cas) . Btw, une tâche cron pourrait être configurée pour modifier automatiquement les nouvelles pensions en exécutant quotidiennement ces scripts

J'espère que ça aide.

1
Balmipour

Ma version ne permet que la création et la suppression de balises. Cela devrait traiter tous les cas particuliers (comme l'ajout de fichiers, la modification des propriétés, etc.).

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

Si vous utilisez JIRA, vous pouvez utiliser le module complémentaire nommé Commit Policy pour protéger les chemins de votre référentiel sans écrire de points d'ancrage personnalisés.

Comment? Utilisez la condition nommée Les fichiers modifiés doivent correspondre à un modèle

Il a un argument de type expression régulière qui doit correspondre à chaque fichier d'une validation, sinon la validation est rejetée. Donc, dans votre cas, vous devriez utiliser une expression régulière qui signifie "ne commence pas par le préfixe/tags /".

(Vous pouvez implémenter beaucoup d'autres contrôles intelligents avec le même plugin.)

_ {Avertissement: je suis un développeur travaillant sur ce module payant.} _

1
Ferenc Kiss

Les réponses énumérées sont excellentes mais aucune n’a fait exactement ce dont j'avais besoin. Je souhaite autoriser la création de balises facilement, mais une fois créées, elles doivent être entièrement en lecture seule. 

Je veux aussi éviter la situation stupide où si vous faites ceci:

svn copy myrepo/trunk myrepo/tags/newrelease

Tout va bien la première fois. Mais la deuxième fois, si la balise existe déjà, vous obtiendrez myrepo/tags/newrelease/trunk.

Mon hook de pré-validation recherchera tout répertoire SVN préexistant correspondant à (repo)/tags/(tag)/ et échouera s'il est trouvé:

$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