VisualSVN सर्वर में प्रतिबद्ध संदेश की आवश्यकता कैसे है?




hook visualsvn-server (8)

आपके प्रश्न के तकनीकी उत्तर पहले ही दिए जा चुके हैं। मैं सामाजिक उत्तर जोड़ना चाहता हूं, जो है: "अपनी टीम के साथ प्रतिबद्ध संदेश मानकों को स्थापित करके और उनसे सहमत होने (या स्वीकार करने) कारणों को अभिव्यक्त करने वाले संदेशों की आवश्यकता क्यों होगी"

मैंने इतने सारे प्रतिबद्ध संदेश देखे हैं जो "पैच", "टाइपो", "फिक्स" या इसी तरह से कहते हैं कि मैंने गिनती खो दी है।

वास्तव में - यह सबको स्पष्ट करें कि आपको उनकी आवश्यकता क्यों है।

कारणों के लिए उदाहरण हैं:

  • जेनरेटेड चेंजोटोट्स (अच्छी तरह से - यह वास्तव में अच्छा संदेश लागू करने के लिए एक अच्छा स्वचालित टूल बना देगा यदि मुझे पता है कि वे (मेरे नाम से) सार्वजनिक रूप से दिखाई देंगे - अगर केवल टीम के लिए)
  • लाइसेंस समस्याएं : आपको बाद में कोड की उत्पत्ति को जानने की आवश्यकता हो सकती है, उदाहरण के लिए आप अपने कोड में लाइसेंस बदलना चाहते हैं (कुछ संगठनों के पास प्रतिबद्धता संदेश स्वरूपण के लिए मानक भी हैं - ठीक है, आप इसके लिए जांच स्वचालित कर सकते हैं, लेकिन आप चाहते हैं जरूरी नहीं कि इसके साथ अच्छे प्रतिबद्ध संदेश प्राप्त करें)
  • अन्य उपकरणों के साथ इंटरऑपरेबिलिटी , उदाहरण के लिए बगट्रैकर्स / इश्यु प्रबंधन प्रबंधन सिस्टम जो आपके संस्करण नियंत्रण के साथ इंटरफ़ेस करते हैं और प्रतिबद्ध संदेशों से जानकारी निकालते हैं।

उम्मीद है कि अतिरिक्त रूप से precommit हुक के बारे में तकनीकी उत्तरों के लिए मदद करता है।

हमारे पास VisualSVN सर्वर विंडोज पर हमारे सबवर्जन सर्वर के रूप में स्थापित है, और हम अपने वर्कस्टेशन पर ग्राहकों के रूप में Ankhsvn + TortoiseSVN का उपयोग करते हैं।

संदेशों को निष्क्रिय करने की आवश्यकता के लिए सर्वर को कॉन्फ़िगर कैसे किया जा सकता है?


एसवीएन इस तरह के कार्यों को पूरा करने के लिए कई हुक का उपयोग करता है।

  • start-commit - प्रतिबद्ध लेनदेन शुरू होने से पहले चलाएं, विशेष अनुमति जांच करने के लिए उपयोग किया जा सकता है
  • pre-commit - लेनदेन के अंत में चलती है, लेकिन प्रतिबद्ध होने से पहले। अक्सर गैर शून्य लंबाई लॉग संदेश जैसी चीज़ों को प्रमाणित करने के लिए उपयोग किया जाता है।
  • post-commit - लेनदेन के बाद चलाया गया है। ईमेल भेजने या भंडार का बैक अप लेने के लिए इस्तेमाल किया जा सकता है।
  • pre-revprop-change - एक संशोधन संपत्ति परिवर्तन से पहले चलता है। अनुमतियों की जांच के लिए इस्तेमाल किया जा सकता है।
  • post-revprop-change - एक संशोधन संपत्ति परिवर्तन के बाद चलता है। इन परिवर्तनों को ईमेल या बैकअप करने के लिए इस्तेमाल किया जा सकता है।

आपको pre-commit हुक का उपयोग करने की आवश्यकता है। आप अपने मंच को समर्थन देने वाली किसी भी भाषा में इसे स्वयं लिख सकते हैं, लेकिन वेब पर कई स्क्रिप्ट हैं। गुगलिंग "एसवीएन प्रीकॉमिट हुक टिप्पणी की आवश्यकता है" मुझे एक जोड़ा मिला जो ऐसा लगता था कि वे बिल फिट करेंगे:


मुझे खुशी है कि आपने यह सवाल पूछा था। यह हमारी पूर्व-प्रतिबद्ध हुक स्क्रिप्ट है जो सामान्य विंडोज बैच में लिखी गई है। अगर लॉग संदेश 6 वर्णों से कम है तो यह प्रतिबद्ध नहीं करता है। बस अपनी हुक निर्देशिका में pre-commit.bat डालें

पूर्व 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

मेरा मानना ​​है कि आपको प्री-प्रतिबद्ध हुक सेट करना होगा जो संदेश की जांच करेगा।

दरअसल, केवल पहले परिणाम को गुगल करके मुझे एक पर्ल प्री-स्क्रिप्ट स्क्रिप्ट मिल गई थी जो आप चाहते थे।

पर्ल प्री-प्रतिबद्ध हुक उदाहरण (अवांछित)


यहां एक विंडोज शैल जेस्क्रिप्ट है जिसका उपयोग आप हुक को निर्दिष्ट करके कर सकते हैं:

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

यह बहुत आसान है पढ़ने के लिए, तो एक प्रयोग आगे बढ़ो।

बीटीडब्ल्यू, जेस्क्रिप्ट में ऐसा करने का कारण यह है कि यह किसी अन्य उपकरण (पर्ल, सिगविन, इत्यादि) पर भरोसा नहीं करता है।

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

यहां दो भाग नमूना बैच + पावरशेल प्री-प्रतिबद्ध हुक है जो 25 से कम वर्णों वाले लॉग संदेश को अस्वीकार करता है।

अपने repository hooks फ़ोल्डर में pre-commit.bat और pre-commit.ps1 दोनों को रखें, उदाहरण के लिए C:\Repositories\repository\hooks\

पूर्व 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

पूर्व 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%

नोट 1: pre-commit.bat केवल एकमात्र है जिसे VisualSVN द्वारा बुलाया जा सकता है और फिर pre-commit.ps1 वह है जिसे pre-commit.bat कहा जाता है।

नोट 2: pre-commit.bat को pre-commit.cmd . pre-commit.cmd भी नामित किया जा सकता है।

नोट 3: यदि आप कुछ उच्चारण वाले अक्षरों और [Console]::Error.WriteLine आउटपुट के साथ एन्कोडिंग समस्याओं का प्रयोग करते हैं, तो उदाहरण के लिए chcp 1252 को pre-commit.bat , pre-commit.bat @echo off बाद अगली पंक्ति।


हम अपने पूर्व-प्रतिबद्ध हुक के लिए उत्कृष्ट CS-Script टूल का उपयोग करते हैं ताकि हम उस भाषा में स्क्रिप्ट लिख सकें जिसमें हम विकास कर रहे हैं। यहां एक उदाहरण दिया गया है जो सुनिश्चित करता है कि 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) {
  }
}

नोट: यह केवल TortoiseSVN पर लागू होता है

बस अपने रिपोजिटरी के शीर्ष स्तर पर राइट-क्लिक करें। संदर्भ-मेनू में इस संवाद को देखने के लिए TortoiseSVN, फिर गुणों का चयन करें:

नीचे दाईं ओर स्थित नया बटन क्लिक करें, और लॉग आकार का चयन करें। Commit और Lock (नीचे उदाहरण में 10) के लिए आवश्यक वर्णों की संख्या दर्ज करें।

शीर्ष स्तर निर्देशिका से एक Commit करें जिसे आपने अभी संशोधित किया है। अब आपके रिपॉजिटरी को सभी उपयोगकर्ताओं को परिवर्तन करने से पहले टिप्पणी करने की आवश्यकता है।





visualsvn-server