سؤال

لدينا VisualSVN Server تعيين لدينا التخريب server على ويندوز, ونحن نستخدم Ankhsvn + TortoiseSVN العملاء على محطات العمل.

كيف يمكنك تكوين الملقم يتطلب ارتكاب الرسائل غير فارغة ؟

هل كانت مفيدة؟

المحلول

VisualSVN خادم 3.9 يوفر VisualSVNServerHooks.exe check-logmessage قبل ارتكاب هوك التي تساعدك على رفض يرتكب فارغة أو قصيرة رسائل السجل.راجع المقالة KB140:التحقق من صحة ارتكاب رسائل سجل في VisualSVN الخادم للحصول على تعليمات.

بالإضافة إلى المدمج في VisualSVNServerHooks.exe, VisualSVN خادم إس في عام يستخدم عدد من السنانير لإنجاز المهام مثل هذا.

  • start-commit — تشغيل قبل ارتكاب المعاملات يبدأ, يمكن استخدامها للقيام تصريح خاص التحقق
  • pre-commit — تشغيل في نهاية الصفقة ، ولكن قبل أن يرتكبها.غالبا ما تستخدم للتحقق من الأشياء مثل عدم طول صفر سجل رسالة.
  • post-commit — يعمل بعد هذه الصفقة قد ارتكبت.يمكن استخدامها لإرسال رسائل البريد الإلكتروني أو النسخ الاحتياطي المخزون.
  • pre-revprop-change — يعمل قبل تنقيح تغيير الملكية.يمكن استخدامها للتحقق من الأذونات.
  • post-revprop-change — يعمل بعد تنقيح تغيير الملكية.يمكن استخدام البريد الإلكتروني أو النسخ الاحتياطي هذه التغييرات.

تحتاج إلى استخدام pre-commit هوك.يمكنك كتابة ذلك بنفسك في مجرد عن أي لغة النظام الأساسي الخاص بك يدعم, ولكن هناك عدد من البرامج النصية على شبكة الإنترنت.غوغلينغ "إس precommit ربط تتطلب التعليق" وجدت اثنين التي يبدو أنها تناسب مشروع القانون:

نصائح أخرى

أنا سعيد لأنك سألت هذا السؤال.هذا هو موقفنا قبل ارتكاب هوك نصي مكتوب بلغة مشتركة ويندوز دفعة.أنها تنفي ارتكاب إذا كانت رسالة سجل أقل من 6 أحرف.فقط ضع قبل الالتزام.الخفافيش إلى السنانير الدليل.

قبل الالتزام.الخفافيش

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

التقنية إجابات على سؤالك بالفعل أعطيت.أود أن أضيف الاجتماعية الجواب وهو:"من خلال إنشاء ارتكاب رسالة المعايير مع فريقك و حملهم على الموافقة (أو تقبل) أسباب لماذا تحتاج معبرة ارتكاب الرسائل"

لقد رأيت العديد من ارتكاب الرسائل التي قال "التصحيح", "خطأ مطبعي" ، "إصلاح" أو ما شابه ذلك لقد فقدت العد.

حقا - أوضح للجميع لماذا كنت في حاجة إليها.

أمثلة لأسباب هي:

  • ولدت Changenotes (حسنا - هذا في الحقيقة لطيفة التلقائي أداة لفرض رسائل جيدة إذا كنت تعرف أنها سوف تكون (اسمي) علنا ظاهرا - إلا إذا كان الفريق)
  • قضايا الترخيص:قد تحتاج إلى معرفة أصل رمز في وقت لاحق, على سبيل المثالينبغي أن كنت ترغب في تغيير الرخصة إلى التعليمات البرمجية الخاصة بك (بعض المنظمات حتى معايير ارتكاب رسالة التنسيق - حسنا, هل يمكن أتمتة التحقق من هذا, ولكن كنت لا تحصل بالضرورة جيد ارتكاب الرسائل مع هذا)
  • التوافقية مع غيرها من الأدوات, مثلاbugtrackers/مسألة إدارة النظم التي تتفاعل مع الإصدار الخاص بك ومراقبة استخراج المعلومات من ارتكاب الرسائل.

نأمل أن يساعد هذا بالإضافة إلى التقنية إجابات عن precommit السنانير.

هنا هو الجزء الثاني من العينة دفعة + PowerShell قبل ارتكاب هوك التي تنفي ارتكاب رسالة السجل مع أقل من 25 حرفا.

وضع كل pre-commit.bat و pre-commit.ps1 إلى المستودع الخاص بك hooks مجلد, مثل C:\Repositories\repository\hooks\

قبل الالتزام.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

قبل الالتزام.الخفافيش

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

ملاحظة 1 : pre-commit.bat هو الوحيد الذي يمكن أن يسمى من قبل VisualSVN ثم pre-commit.ps1 هو الذي يطلق عليه من قبل pre-commit.bat.

ملاحظة 2 : pre-commit.bat ويمكن أيضا الكشف عن اسمه pre-commit.cmd.

ملاحظة 3 :إذا كان لك تجربة ترميز القضايا مع بعض أحرف معلمة ، [Console]::Error.WriteLine الإخراج ، ثم يضاف على سبيل المثال chcp 1252 في pre-commit.bat, بجانب الخط بعد @echo off.

وماذا تقدم VisualSVN منك إدخال كما السنانير هي "ويندوز NT البرامج النصية"، والتي هي في الأساس ملفات دفعة واحدة.

والكتابة إذا، ثم-آخر في الملفات الدفعية قبيحة جدا، وربما من الصعب جدا التصحيح.

وسيبدو شيء كما يلي (البحث عن ما قبل commit.bat) (لم تختبر):

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 

وكنت في حاجة الى grep.exe على الطريق،٪ 1 هو المسار إلى هذا المستودع،٪ 2 اسم TXN على وشك أن ترتكب. لديهم أيضا نظرة على ما قبل commit.tmpl في الدليل السنانير من المخزون الخاص بك.

ونحن نستخدم الممتاز CS-سيناريو أداة لدينا قبل ارتكاب السنانير حتى نتمكن من كتابة البرامج النصية في اللغة نفعله التنمية في. وفيما يلي مثال يضمن هناك ارتكاب رسالة أطول من 10 حرفا، ويضمن أن .suo وملفات .user لا إيداعه. يمكنك أيضا اختبار لتزكي التبويب / الفضاء، أو القيام صغير إنفاذ المعايير التعليمات البرمجية في الاختيار، ولكن كن حذرا مما يجعل السيناريو الخاص بك تفعل الكثير كما كنت لا تريد أن يتباطأ يرتكبها.

// 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) {
  }
}

وإليك شل ل JScript ويندوز التي يمكن استخدامها لتحديد هوك على النحو التالي:

%SystemRoot%\System32\CScript.exe //nologo <..path..to..script> %1 %2

وانها سهلة القراءة جدا، لذلك المضي قدما في التجربة.

وراجع للشغل، والسبب أن تفعل هذا في JScript هو أنه لا تعتمد على أي أدوات أخرى (بيرل، سيغوين، الخ) ليتم تثبيتها.

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

استخدم هذا قبل ارتكاب هوك على ويندوز. هو مكتوب في ويندوز دفعة ويستخدم أداة البقرى سطر الأوامر للتحقق من الالتزام طول.

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

وتذكر أن عليك ان تحصل على نسخة من البقرى، أوصي جنو أدوات نسخة .

ملاحظة:هذا ينطبق فقط على TortoiseSVN

ببساطة انقر بزر الماوس الأيمن فوق أعلى مستوى من المخزون الخاص بك.في السياق القائمة حدد TortoiseSVN ثم خصائص لرؤية هذا الحوار:

enter image description here

انقر فوق الزر "جديد" بالقرب من أسفل اليمين ، واختر سجل الأحجام.أدخل عدد الأحرف التي تريد تتطلب الالتزام و قفل (10 في المثال أدناه).

enter image description here

لا يرتكبون من أعلى مستوى الدليل يمكنك فقط تعديل.الآن المستودع الخاص بك يتطلب من جميع المستخدمين من التعليق قبل ارتكاب التغييرات.

وقبل مضيفا ارتكاب السنانير لخدمة بلدي، وأنا مجرد توزيع svnprops للعملاء تورتويز إس في إن.

وهكذا، كبديل:

في تورتويز إس في إن -> خصائص اسم الخاصية - إضافة / مجموعة tsvn:logminsize بشكل مناسب

وهذا بالطبع لا يشكل ضمانة على الخادم كعملاء / يمكن للمستخدمين اختيار عدم فعل ذلك، ولكن يمكنك توزيع الملفات svnprops إذا أردت. بهذه الطريقة، لم يكن لدى المستخدمين لتحديد قيمهم الخاصة - التي يمكن أن توفر لهم جميع المستخدمين

وهذا يعمل أيضا لأشياء مثل bugtraq: ضبط لربط قضية الاشياء تتبع في سجلات

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top