2

What is a possible way to block svn commits to specified branches using c#? How could I get the path of the branch from the arguments in the pre-commit hook? (or any other suggestions for getting the path to block)

Is there a way to do this using svnlook to see what files it modified, maybe?

Any suggestions are highly appreciated!

user1867353
  • 487
  • 1
  • 6
  • 12
  • 1
    Can you use ACLs and grant all users read access only to the branches you want to protect? You could use C# to modify ACL configuration file. – Marcin Hoppe Dec 03 '12 at 21:12
  • 1
    Take a look at this question to see if this helps: http://stackoverflow.com/questions/8074143 – Richard Morgan Dec 03 '12 at 21:19
  • Does it have to be C#? I have a [pre-commit hook](https://github.com/qazwart/SVN-Precommit-Kitchen-Sink-Hook) in Perl that does exactly what you want. It uses a control file, and the control file can be stored in the repository, so you can modify the commit permissions without having to get on the server. You can get a free version of Perl from [ActiveState](http://www.activestate.com/activeperl). – David W. Dec 03 '12 at 21:58
  • 2
    I don't understand why do you need a hook for this. There is a path-based authorization: http://svnbook.red-bean.com/en/1.7/svn.serverconfig.pathbasedauthz.html – bahrep Dec 04 '12 at 09:18
  • Sorry I'm a year late, but I'm posting it here in case others come across this. I agree with the above posts, use path-based authentication instead, It's built into the authz file and Subversion and designed just for this. See this post: http://stackoverflow.com/questions/1468651/svn-branch-level-commit-permissions – Damon Oct 10 '13 at 22:28

1 Answers1

4

When I had to do this I followed this guide: http://www.troyhunt.com/2010/02/creating-subversion-pre-commit-hooks-in.html

I wrote a C# application that called svnlook and was fired by the precommit hook to check if the path was allowed or not.

Following is my code, it should be easily adaptable to your situation:

class Program
{
    static void Main(string[] args)
    {
        var repos = args[0];
        var txn = args[1];

        var log = GetSvnLookOutput(repos, txn, "log");
        var changedPaths = GetSvnLookOutput(repos, txn, "changed");

        var logValidation = GetLogMessageErrors(log.Replace("\r", "").Replace("\n", ""));
        if (logValidation != null)
        {
            Console.Error.WriteLine(logValidation);
            Environment.Exit(1);
        }

        if (log.Contains("Autoversioning commit"))
        {
            // this is an autoversion webdav client, enforce path rules
            var changedPathsValidation = GetFileNameErrors(changedPaths);
            if (changedPathsValidation != null)
            {
                Console.Error.WriteLine(changedPathsValidation);
                Environment.Exit(1);
            }
        }

        Environment.Exit(0);
    }

    private static string GetLogMessageErrors(string log)
    {
        if (string.IsNullOrEmpty(log))
        {
            return "Log message is required.";
        }

        return null;
    }

    private static string GetFileNameErrors(string changedPaths)
    {
        var changeRows = Regex.Split(changedPaths.TrimEnd(), Environment.NewLine);
        foreach (var changeRow in changeRows)
        {
            var filePath = changeRow.Substring(4, changeRow.Length - 4);

            if (filePath.ToLower().Contains("/code/"))
            {
                return "Autoversioning commits are not allowed inside /CODE/ folders. Use a SVN client for this.";
            }
        }
        return null;
    }

    private static string GetSvnLookOutput(string repos, string txn, string subcommand)
    {
        var processStartInfo = new ProcessStartInfo
        {
            FileName = @"svnlook.exe",
            UseShellExecute = false,
            CreateNoWindow = true,
            RedirectStandardOutput = true,
            RedirectStandardError = true,
            Arguments = String.Format("{0} -t \"{1}\" \"{2}\"", subcommand, txn, repos)
        };

        var process = Process.Start(processStartInfo);
        var output = process.StandardOutput.ReadToEnd();
        process.WaitForExit();
        return output;
    }
}
Kendall Trego
  • 1,975
  • 13
  • 21