Malevich and external tools

Malevich has several features that allow integrating it into existing software development tools, such as source control installations, bug databases, patch tools, etc.

Links to external resources

Starting with CL 22174 review.exe has been extended to allow specifying links to the external resources, such as patches, bug database, etc. A command addlink has been added, and review submission command line has been extended with two command line parameters: --link and --linkdescr that specify a URL and the description. Links added in such a way appear on a change description page.

For example:
    review 5151 alice bob --link file:\\server\patches\5151.patch --linkdescr "Download the patch"

or
    review addlink 5151 http://bugzilla/bugid=3452637 --linkdescr "Resolves bug 3452637"


For example, let's say a hypothetical command bbpack -c changelistnumber -o outputfile creates a file with the patch that implements the change. One can create a following wrapper for review.exe to automatically create patch for code review that will be downloadable from the web site (you do need to create a share \\malevichserver\bbpacks - substitute for the real name - and grant it appropriate permissions):
review.cmd:
    setlocal
    REM Test of the first argument is a CL number, i.e. this is a change list submission.
    REM if %1 is anything but a number, it is treated as 0. The _CLTEST will then be 1.
    set /A _CLTEST=%1 + 1
    if "%_CLTEST%" == "1" goto :firstargisnotclnumber
    REM Create the patch
    bbpack -c %1 -f -o \\malevichserver\bbpacks\%1.cmd
    review.exe %*
    review.exe addlink %1 file:\\malevichserver\bbpacks\%1.cmd "Download bbpack"
    goto :eof
    :firstargisnotclnumber
    review.exe %*
    endlocal

Data model and programmability

Malevich is built on LINQ and its binary distribution ships with a DLL CodeReviewDataModel.dll (found in review client directory) that exports the database as a SQL-to-LINQ class. To use it from any managed language, simply add a reference to it, and code away. Here's an example of what can be done - the program below processes output of Perforce (or Source Depot) command and if the change list has been submitted, renames the review to the new, submitted change number and closes it:
    using System;
    using System.IO;
    using System.Linq;
    using System.Text.RegularExpressions;

    using DataModel;

    internal class Program
    {
        private static void Main(string[] args)
        {
            if (args.Length != 1)
            {
                Console.WriteLine("Usage: processcodereview file_name");
                return;
            }

            string databaseServer = Environment.GetEnvironmentVariable("REVIEW_DATABASE");
            if (databaseServer == null)
                return;

            Regex submitted = new Regex("^Change ([0-9]+) submitted with .* file\\(s\\)\\.$");
            Regex renamed = new Regex("^Change ([0-9]+) renamed to ([0-9]+) and submitted with 1 file\\(s\\)\\.$");

            using (StreamReader text = new StreamReader(args[0]))
            {
                for (;;)
                {
                    string line = text.ReadLine();
                    if (line == null)
                        break;

                    string cl = null;
                    string newCl = null;

                    Match m = submitted.Match(line);
                    if (m.Success)
                        cl = m.Groups[1].Value;
                    else
                    {
                        m = renamed.Match(line);
                        if (m.Success)
                        {
                            cl = m.Groups[1].Value;
                            newCl = m.Groups[2].Value;
                        }
                    }

                    if (cl != null)
                    {
                        CodeReviewDataContext context = new CodeReviewDataContext("Data Source=" + databaseServer +
                            ";Initial Catalog=CodeReview;Integrated Security=True");

                        int[] cids = (from cc in context.ChangeLists where cc.CL == cl select cc.Id).ToArray();
                        if (cids.Length != 1)
                            return;

                        if (newCl != null)
                            context.RenameChangeList(cids[0], newCl);

                        context.SubmitChangeList(cids[0]);
                        break;
                    }
                }
            }
        }
    }

This code program can be wrapped, together with source control command in a batch file to manage code review automatically:
p4.cmd
    p4.exe %* | tee %TEMP%\p4out.txt
    processcodereview %TEMP%\p4out.txt


And here is a code snippet that can be put in a check-in trigger to verify that there are no outstanding reviews with the "Needs work" vote and no reviews in progress:
            string changeList = ... change list number ...
            CodeReviewDataContext context = ... as above ...

            int[] changeListIds = (from cc in context.ChangeLists where cc.CL == changeList select cc.Id).ToArray();
            if (changeListIds.Length != 1)
                return;

            var reviewsQuery = from rr in context.Reviews
                               where rr.ChangeListId == changeListIds[0]
                               orderby rr.Id
                               select rr;

            HashSet<string> needsWorkVotes = new HashSet<string>();

            bool haveUnsubmittedReviews = false;
            foreach (Review review in reviewsQuery)
            {
                if (review.IsSubmitted)
                {
                    if (review.OverallStatus == 0)
                        needsWorkVotes.Add(review.UserName);
                    else if (review.OverallStatus == 1 || review.OverallStatus == 2)
                        needsWorkVotes.Remove(review.UserName);
                }
                else
                {
                    int comments = (from cc in context.Comments where cc.ReviewId == review.Id select cc).Count();
                    if (comments == 0)
                        continue;
  
                    haveUnsubmittedReviews = true;
                    Console.WriteLine(
                        "Found an unsubmitted review from {0} ({1} comments).",
                        review.UserName,
                        comments);
                }
            }

            foreach (string user in needsWorkVotes)
                Console.WriteLine("{0} said this change needs work!", user);


Last edited Jun 29, 2009 at 3:57 AM by SergeySolyanik, version 5

Comments

No comments yet.