repositorio - tortoise svn server tutorial
¿Cómo se requieren los mensajes de confirmación en el servidor de VisualSVN? (11)
Antes de agregar commit hooks a mi servidor, acabo de distribuir svnprops a los clientes de TortoiseSVN.
Entonces, como alternativa:
En TortoiseSVN -> Propiedades nombre de la propiedad - agregar / establecer tsvn:logminsize
apropiada.
Esto, por supuesto, no es garantía en el servidor ya que los clientes / usuarios pueden optar por no hacerlo, pero puede distribuir archivos svnprops si lo desea. De esta forma, los usuarios no tienen que establecer sus propios valores; puede proporcionarlos a todos los usuarios.
Esto también funciona para cosas como bugtraq: configuración para vincular cosas de seguimiento de problemas en los registros.
Tenemos el servidor VisualSVN configurado como nuestro servidor Subversion en Windows, y utilizamos Ankhsvn + TortoiseSVN como clientes en nuestras estaciones de trabajo.
¿Cómo se puede configurar el servidor para exigir que los mensajes de confirmación no estén vacíos?
Aquí hay un Shell JScript de Windows que puede usar especificando el gancho como:
%SystemRoot%/System32/CScript.exe //nologo <..path..to..script> %1 %2
Es bastante fácil de leer, así que adelante un experimento.
Por cierto, la razón para hacer esto en JScript es que no se debe instalar ninguna otra herramienta (Perl, CygWin, etc.).
if (WScript.Arguments.Length < 2)
{
WScript.StdErr.WriteLine("Repository Hook Error: Missing parameters. Should be REPOS_PATH then TXN_NAME, e.g. %1 %2 in pre-commit hook");
WScript.Quit(-1);
}
var oShell = new ActiveXObject("WScript.Shell");
var oFSO = new ActiveXObject("Scripting.FileSystemObject");
var preCommitStdOut = oShell.ExpandEnvironmentStrings("%TEMP%//PRE-COMMIT." + WScript.Arguments(1) + ".stdout");
var preCommitStdErr = oShell.ExpandEnvironmentStrings("%TEMP%//PRE-COMMIT." + WScript.Arguments(1) + ".stderr");
var commandLine = "%COMSPEC% /C /"C://Program Files//VisualSVN Server//bin//SVNLook.exe/" log -t ";
commandLine += WScript.Arguments(1);
commandLine += " ";
commandLine += WScript.Arguments(0);
commandLine += "> " + preCommitStdOut + " 2> " + preCommitStdErr;
// Run Synchronously, don''t show a window
// WScript.Echo("About to run: " + commandLine);
var exitCode = oShell.Run(commandLine, 0, true);
var fsOUT = oFSO.GetFile(preCommitStdOut).OpenAsTextStream(1);
var fsERR = oFSO.GetFile(preCommitStdErr).OpenAsTextStream(1);
var stdout = fsOUT && !fsOUT.AtEndOfStream ? fsOUT.ReadAll() : "";
var stderr = fsERR && !fsERR.AtEndOfStream ? fsERR.ReadAll() : "";
if (stderr.length > 0)
{
WScript.StdErr.WriteLine("Error with SVNLook: " + stderr);
WScript.Quit(-2);
}
// To catch naught commiters who write ''blah'' as their commit message
if (stdout.length < 5)
{
WScript.StdErr.WriteLine("Please provide a commit message that describes why you''ve made these changes.");
WScript.Quit(-3);
}
WScript.Quit(0);
Aquí hay un gancho de precompilación de Batch + PowerShell de dos partes que niega la confirmación de un mensaje de registro con menos de 25 caracteres.
Coloque tanto pre-commit.bat
como pre-commit.ps1
en su carpeta de pre-commit.ps1
repositorio, p. Ej. C:/Repositories/repository/hooks/
pre-commit.ps1
# Store hook arguments into variables with mnemonic names
$repos = $args[0]
$txn = $args[1]
# Build path to svnlook.exe
$svnlook = "$env:VISUALSVN_SERVER/bin/svnlook.exe"
# Get the commit log message
$log = (&"$svnlook" log -t $txn $repos)
# Check the log message contains non-empty string
$datalines = ($log | where {$_.trim() -ne ""})
if ($datalines.length -lt 25)
{
# Log message is empty. Show the error.
[Console]::Error.WriteLine("Commit with empty log message is prohibited.")
exit 3
}
exit 0
pre-commit.bat
@echo off
set PWSH=%SystemRoot%/System32/WindowsPowerShell/v1.0/powershell.exe
%PWSH% -command $input ^| %1/hooks/pre-commit.ps1 %1 %2
if errorlevel 1 exit %errorlevel%
Nota 1: pre-commit.bat
es el único al que VisualSVN puede llamar y luego pre-commit.ps1
es el llamado por pre-commit.bat
.
Nota 2: pre-commit.bat
también se puede pre-commit.bat
pre-commit.cmd
.
Nota 3: Si experimenta problemas de codificación con algunos caracteres acentuados y la salida [Console]::Error.WriteLine
, agregue, por ejemplo, chcp 1252
en pre-commit.bat
, siguiente línea después de @echo off
.
Creo que tendrás que configurar un enganche precompromiso que verificará el mensaje.
De hecho, solo buscando en Google, el primer resultado que obtuve fue un script de precompilación de Perl para hacer exactamente lo que usted deseaba.
Las respuestas técnicas a su pregunta ya han sido dadas. Me gustaría agregar la respuesta social, que es: "Estableciendo estándares de mensajes de compromiso con su equipo y logrando que acepten (o acepten) las razones por las cuales se necesitarían mensajes expresivos de compromiso"
He visto tantos mensajes de confirmación que dicen "parche", "error tipográfico", "corregir" o similar que he perdido la cuenta.
Realmente, deja en claro a todos por qué los necesitarías.
Ejemplos de las razones son:
- Generated Changenotes (bueno, esto realmente sería una buena herramienta automática para hacer cumplir buenos mensajes si sé que estarán (con mi nombre) públicamente visibles, aunque solo sea para el equipo)
- Problemas con la licencia : es posible que necesite saber el origen del código más adelante, por ejemplo, si desea cambiar la licencia a su código (algunas organizaciones incluso tienen estándares para el formato de mensajes de confirmación; bueno, podría automatizar la comprobación de esto, pero tendría no necesariamente obtener buenos mensajes de compromiso con esto)
- Interoperabilidad con otras herramientas , por ejemplo, sistemas de administración de problemas / errores que interactúan con el control de su versión y extraen información de los mensajes de confirmación.
Espero que ayude, además de las respuestas técnicas sobre los ganchos precommitidos.
Lo que VisualSVN le ofrece para ingresar como ganchos son "scripts de comandos de Windows NT", que son básicamente archivos por lotes.
Escribir if-then-else en archivos por lotes es muy feo y probablemente sea muy difícil de depurar.
Se verá algo como lo siguiente (búsqueda de pre-commit.bat) (no probado):
SVNLOOK.exe log -t "%2" "%1" | grep.exe "[a-zA-Z0-9]" > nul || GOTO ERROR
GOTO OK
:ERROR
ECHO "Please enter comment and then retry commit!"
exit 1
:OK
exit 0
Necesita un grep.exe en la ruta,% 1 es la ruta a este repositorio,% 2 el nombre del txn a punto de comprometerse. También eche un vistazo a pre-commit.tmpl en el directorio hooks de su repositorio.
Me alegra que hayas hecho esta pregunta. Este es nuestro script de enlace precomprometido escrito en Windows Batch común. Niega la confirmación si el mensaje de registro tiene menos de 6 caracteres. Simplemente coloque el pre-commit.bat en su directorio de ganchos.
pre-commit.bat
setlocal enabledelayedexpansion
set REPOS=%1
set TXN=%2
set SVNLOOK="%VISUALSVN_SERVER%/bin/svnlook.exe"
SET M=
REM Concatenate all the lines in the commit message
FOR /F "usebackq delims==" %%g IN (`%SVNLOOK% log -t %TXN% %REPOS%`) DO SET M=!M!%%g
REM Make sure M is defined
SET M=0%M%
REM Here the 6 is the length we require
IF NOT "%M:~6,1%"=="" goto NORMAL_EXIT
:ERROR_TOO_SHORT
echo "Commit note must be at least 6 letters" >&2
goto ERROR_EXIT
:ERROR_EXIT
exit /b 1
REM All checks passed, so allow the commit.
:NORMAL_EXIT
exit 0
SVN usa varios ganchos para realizar tareas como esta.
-
start-commit
: se ejecuta antes de que comience la transacción de confirmación. Se puede usar para realizar una comprobación de permisos especial. -
pre-commit
: se ejecuta al final de la transacción, pero antes de la confirmación. A menudo se usa para validar cosas como un mensaje de registro de longitud no nula. -
post-commit
: se ejecuta después de que se haya confirmado la transacción. Se puede usar para enviar correos electrónicos o realizar copias de seguridad del repositorio. -
pre-revprop-change
: se ejecuta antes de un cambio de propiedad de revisión. Se puede usar para verificar permisos. -
post-revprop-change
: se ejecuta después de un cambio de propiedad de revisión. Se puede usar para enviar por correo electrónico o hacer una copia de seguridad de estos cambios.
Necesitas usar el gancho de pre-commit
. Puede escribirlo usted mismo en cualquier idioma que admita su plataforma, pero hay una serie de secuencias de comandos en la web. Buscar en Google "svn precommit hook para solicitar un comentario" Encontré una pareja que parecía que encajaría en la factura:
Use este gancho precompromiso en Windows. Está escrito en Windows Batch y utiliza la utilidad de línea de comandos grep para verificar la duración de la confirmación.
svnlook log -t "%2" "%1" | c:/tools/grep -c "[a-zA-z0-9]" > nul
if %ERRORLEVEL% NEQ 1 exit 0
echo Please enter a check-in comment 1>&2
exit 1
Recuerda que necesitarás una copia de grep, recomiendo la versión de las herramientas gnu .
Utilizamos la excelente herramienta CS-Script para nuestros ganchos pre-commit para que podamos escribir scripts en el lenguaje en el que estamos desarrollando. Aquí hay un ejemplo que asegura que hay un mensaje de confirmación de más de 10 caracteres, y asegura que .suo y .Los archivos de usuario no se registran. También puede probar las sangrías de tabulación / espacio, o aplicar estándares de código pequeños en el check-in, pero tenga cuidado haciendo que su script haga demasiado ya que no desea ralentizar un commit .
// run from pre-commit.cmd like so:
// css.exe /nl /c C:/SVN/Scripts/PreCommit.cs %1 %2
using System;
using System.Diagnostics;
using System.Text;
using System.Text.RegularExpressions;
using System.Linq;
class PreCommitCS {
/// <summary>Controls the procedure flow of this script</summary>
public static int Main(string[] args) {
if (args.Length < 2) {
Console.WriteLine("usage: PreCommit.cs repository-path svn-transaction");
Environment.Exit(2);
}
try {
var proc = new PreCommitCS(args[0], args[1]);
proc.RunChecks();
if (proc.MessageBuffer.ToString().Length > 0) {
throw new CommitException(String.Format("Pre-commit hook violation/r/n{0}", proc.MessageBuffer.ToString()));
}
}
catch (CommitException ex) {
Console.WriteLine(ex.Message);
Console.Error.WriteLine(ex.Message);
throw ex;
}
catch (Exception ex) {
var message = String.Format("SCRIPT ERROR! : {1}{0}{2}", "/r/n", ex.Message, ex.StackTrace.ToString());
Console.WriteLine(message);
Console.Error.WriteLine(message);
throw ex;
}
// return success if we didn''t throw
return 0;
}
public string RepoPath { get; set; }
public string SvnTx { get; set; }
public StringBuilder MessageBuffer { get; set; }
/// <summary>Constructor</summary>
public PreCommitCS(string repoPath, string svnTx) {
this.RepoPath = repoPath;
this.SvnTx = svnTx;
this.MessageBuffer = new StringBuilder();
}
/// <summary>Main logic controller</summary>
public void RunChecks() {
CheckCommitMessageLength(10);
// Uncomment for indent checks
/*
string[] changedFiles = GetCommitFiles(
new string[] { "A", "U" },
new string[] { "*.cs", "*.vb", "*.xml", "*.config", "*.vbhtml", "*.cshtml", "*.as?x" },
new string[] { "*.designer.*", "*.generated.*" }
);
EnsureTabIndents(changedFiles);
*/
CheckForIllegalFileCommits(new string[] {"*.suo", "*.user"});
}
private void CheckForIllegalFileCommits(string[] filesToExclude) {
string[] illegalFiles = GetCommitFiles(
new string[] { "A", "U" },
filesToExclude,
new string[] {}
);
if (illegalFiles.Length > 0) {
Echo(String.Format("You cannot commit the following files: {0}", String.Join(",", illegalFiles)));
}
}
private void EnsureTabIndents(string[] filesToCheck) {
foreach (string fileName in filesToCheck) {
string contents = GetFileContents(fileName);
string[] lines = contents.Replace("/r/n", "/n").Replace("/r", "/n").Split(new string[] { "/n" }, StringSplitOptions.None);
var linesWithSpaceIndents =
Enumerable.Range(0, lines.Length)
.Where(i => lines[i].StartsWith(" "))
.Select(i => i + 1)
.Take(11)
.ToList();
if (linesWithSpaceIndents.Count > 0) {
var message = String.Format("{0} has spaces for indents on line(s): {1}", fileName, String.Join(",", linesWithSpaceIndents));
if (linesWithSpaceIndents.Count > 10) message += "...";
Echo(message);
}
}
}
private string GetFileContents(string fileName) {
string args = GetSvnLookCommandArgs("cat") + " /"" + fileName + "/"";
string svnlookResults = ExecCmd("svnlook", args);
return svnlookResults;
}
private void CheckCommitMessageLength(int minLength) {
string args = GetSvnLookCommandArgs("log");
string svnlookResults = ExecCmd("svnlook", args);
svnlookResults = (svnlookResults ?? "").Trim();
if (svnlookResults.Length < minLength) {
if (svnlookResults.Length > 0) {
Echo("Your commit message was too short.");
}
Echo("Please describe the changes you''ve made in a commit message in order to successfully commit. Include support ticket number if relevant.");
}
}
private string[] GetCommitFiles(string[] changedIds, string[] includedFiles, string[] exclusions) {
string args = GetSvnLookCommandArgs("changed");
string svnlookResults = ExecCmd("svnlook", args);
string[] lines = svnlookResults.Split(new string[] { "/r", "/n" }, StringSplitOptions.RemoveEmptyEntries);
var includedPatterns = (from a in includedFiles select ConvertWildcardPatternToRegex(a)).ToArray();
var excludedPatterns = (from a in exclusions select ConvertWildcardPatternToRegex(a)).ToArray();
var opts = RegexOptions.IgnoreCase;
var results =
from line in lines
let fileName = line.Substring(1).Trim()
let changeId = line.Substring(0, 1).ToUpper()
where changedIds.Any(x => x.ToUpper() == changeId)
&& includedPatterns.Any(x => Regex.IsMatch(fileName, x, opts))
&& !excludedPatterns.Any(x => Regex.IsMatch(fileName, x, opts))
select fileName;
return results.ToArray();
}
private string GetSvnLookCommandArgs(string cmdType) {
string args = String.Format("{0} -t {1} /"{2}/"", cmdType, this.SvnTx, this.RepoPath);
return args;
}
/// <summary>
/// Executes a command line call and returns the output from stdout.
/// Raises an error is stderr has any output.
/// </summary>
private string ExecCmd(string command, string args) {
Process proc = new Process();
proc.StartInfo.FileName = command;
proc.StartInfo.Arguments = args;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.Start();
var stdOut = proc.StandardOutput.ReadToEnd();
var stdErr = proc.StandardError.ReadToEnd();
proc.WaitForExit(); // Do after ReadToEnd() call per: http://chrfalch.blogspot.com/2008/08/processwaitforexit-never-completes.html
if (!string.IsNullOrWhiteSpace(stdErr)) {
throw new Exception(string.Format("Error: {0}", stdErr));
}
return stdOut;
}
/// <summary>
/// Writes the string provided to the Message Buffer - this fails
/// the commit and this message is presented to the comitter.
/// </summary>
private void Echo(object s) {
this.MessageBuffer.AppendLine((s == null ? "" : s.ToString()));
}
/// <summary>
/// Takes a wildcard pattern (like *.bat) and converts it to the equivalent RegEx pattern
/// </summary>
/// <param name="wildcardPattern">The wildcard pattern to convert. Syntax similar to VB''s Like operator with the addition of pipe ("|") delimited patterns.</param>
/// <returns>A regex pattern that is equivalent to the wildcard pattern supplied</returns>
private string ConvertWildcardPatternToRegex(string wildcardPattern) {
if (string.IsNullOrEmpty(wildcardPattern)) return "";
// Split on pipe
string[] patternParts = wildcardPattern.Split(''|'');
// Turn into regex pattern that will match the whole string with ^$
StringBuilder patternBuilder = new StringBuilder();
bool firstPass = true;
patternBuilder.Append("^");
foreach (string part in patternParts) {
string rePattern = Regex.Escape(part);
// add support for ?, #, *, [...], and [!...]
rePattern = rePattern.Replace("//[!", "[^");
rePattern = rePattern.Replace("//[", "[");
rePattern = rePattern.Replace("//]", "]");
rePattern = rePattern.Replace("//?", ".");
rePattern = rePattern.Replace("//*", ".*");
rePattern = rePattern.Replace("//#", "//d");
if (firstPass) {
firstPass = false;
}
else {
patternBuilder.Append("|");
}
patternBuilder.Append("(");
patternBuilder.Append(rePattern);
patternBuilder.Append(")");
}
patternBuilder.Append("$");
string result = patternBuilder.ToString();
if (!IsValidRegexPattern(result)) {
throw new ArgumentException(string.Format("Invalid pattern: {0}", wildcardPattern));
}
return result;
}
private bool IsValidRegexPattern(string pattern) {
bool result = true;
try {
new Regex(pattern);
}
catch {
result = false;
}
return result;
}
}
public class CommitException : Exception {
public CommitException(string message) : base(message) {
}
}
Nota: Esto solo se aplica a TortoiseSVN
Simplemente haga clic derecho en el nivel superior de su repositorio. En el menú de contexto, seleccione TortoiseSVN, luego Propiedades, para ver este diálogo:
Haga clic en el botón Nuevo, situado en la esquina inferior derecha, y seleccione Log Sizes. Ingrese el número de caracteres que desea requerir para Confirmar y Bloquear (10 en el ejemplo a continuación).
Haga un Compromiso desde el directorio de nivel superior que acaba de modificar. Ahora su repositorio requiere que todos los usuarios comenten antes de cometer cambios.