コード例 #1
0
ファイル: CommentsExchange.cs プロジェクト: daptiv/Malevich
    public void AddComment(string commentId, string commentText)
    {
        if (!HttpContext.Current.User.Identity.IsAuthenticated)
            return;

        CommentId cid = new CommentId(commentId);
        if (!cid.HasParsed())
            return;

        int? result = null;
        CodeReviewDataContext dataContext = new CodeReviewDataContext(
            System.Configuration.ConfigurationManager.ConnectionStrings[Config.ConnectionString].ConnectionString);
        dataContext.AddComment(cid.FileVersionId, cid.Line, cid.LineStamp, commentText, ref result);
        dataContext.Connection.Close();
        dataContext.Dispose();
    }
コード例 #2
0
ファイル: Program.cs プロジェクト: daptiv/Malevich
        /// <summary>
        /// Adds an attachment to code review.
        /// </summary>
        /// <param name="context"> Database context. </param>
        /// <param name="userName"> User alias. </param>
        /// <param name="cl"> Change list to modify. </param>
        /// <param name="link"> The file or web page URL. </param>
        /// <param name="linkDescr"> The text (optional). </param>
        private static void AddAttachment(CodeReviewDataContext context, string userName, string cl,
            string link, string linkDescr)
        {
            var changeListQuery = from ch in context.ChangeLists
                                  where ch.CL.Equals(cl) && ch.UserName.Equals(userName) && ch.Stage == 0
                                  select ch.Id;
            if (changeListQuery.Count() != 1)
            {
                Console.WriteLine("No active change in database.");
                return;
            }

            int cid = changeListQuery.Single();

            int? result = null;
            context.AddAttachment(cid, linkDescr, link, ref result);

            Console.WriteLine("Attachment submitted.");
        }
コード例 #3
0
ファイル: Program.cs プロジェクト: daptiv/Malevich
        /// <summary>
        /// Tests if the current configuration works by sending email.
        /// </summary>
        /// <param name="email"> Who to send email to. </param>
        private static void TestSetup(string email)
        {
            Console.WriteLine("Testing notifier setup.");
            Console.Write("1. Attempting to load configuration... ");
            if (!ReviewNotifierConfiguration.Load())
            {
                Console.WriteLine("Failure!");
                Console.WriteLine("Run 'ReviewNotifier help' for help with configuring this program.");
                return;
            }
            Console.WriteLine("Success!");
            Console.Write("2. Attempting to connect to the database... ");

            CodeReviewDataContext context = new CodeReviewDataContext(Config.Database);
            int openReviews = (from rr in context.ChangeLists where rr.Stage == 0 select rr).Count();
            int totalReviews = (from rr in context.ChangeLists select rr).Count();
            int files = (from ff in context.ChangeFiles select ff).Count();
            int comments = (from cc in context.Comments select cc).Count();

            Console.WriteLine("Success!");

            string mailbody = "If you are reading this message, the notifier configuration should be correct.\n\n" +
                "Check that the mail has come from the right account, and that the following stats are reasonable:\n" +
                "    Open reviews: " + openReviews + "\n    Total reviews: " + totalReviews +
                "\n    Total files in all reviews: " + files + "\n    Total comments in all reviews: " +
                comments + "\n\nRespectfully,\n    Your friendly review notifier.\n";

            bool result = false;
            if (!string.IsNullOrEmpty(Config.EmailService))
            {
                Console.Write("3. Sending mail using Exchange protocol... ");
                List<MessageType> mail = new List<MessageType>();
                mail.Add(MakeExchangeMessage(email + "@" + Config.EmailDomain,
                    Config.FromEmail == null ? null : Config.FromEmail + "@" + Config.EmailDomain,
                    email + "@" + Config.EmailDomain,
                    "A test email from Malevich notifier - sent via Exchange transport", mailbody, false, 0, false));
                result = SendExchangeMail(Config, mail);
            }
            else if (!string.IsNullOrEmpty(Config.SmtpServer))
            {
                Console.Write("3. Sending mail using SMTP protocol... ");
                List<MailMessage> mail = new List<MailMessage>();
                mail.Add(MakeSmtpMessage(email + "@" + Config.EmailDomain,
                    Config.FromEmail == null ? null : Config.FromEmail + "@" + Config.EmailDomain,
                    ResolveUser(Config, Config.User), ResolveUser(Config, Config.User),
                    "A test email from Malevich notifier - sent via SMTP transport", mailbody, false, 0, false));
                result = SendSmtpMail(Config, mail);
            }
            else
            {
                // This should really never happen.
                Console.WriteLine("Failure: mail transport is not configured!");
            }

            if (result)
            {
                Console.WriteLine("Success! (or so we think: check your inbox!");
                Console.WriteLine("Email was sent to {0} @ {1}", email, Config.EmailDomain);
            }
        }
コード例 #4
0
ファイル: Program.cs プロジェクト: daptiv/Malevich
        /// <summary>
        /// Verifies that there are no pending reviews for this change list.
        /// </summary>
        /// <param name="context"> Database context. </param>
        /// <param name="cid"> Change list ID. </param>
        /// <returns></returns>
        private static bool NoPendingReviews(CodeReviewDataContext context, int cid)
        {
            var unsubmittedReviewsQuery = from rr in context.Reviews
                                          where rr.ChangeListId == cid && !rr.IsSubmitted
                                          select rr;

            bool printedTitle = false;
            int unsubmittedComments = 0;

            foreach (Review review in unsubmittedReviewsQuery)
            {
                int comments = (from cc in context.Comments where cc.ReviewId == review.Id select cc).Count();
                if (comments == 0)
                    continue;

                unsubmittedComments += comments;

                if (!printedTitle)
                {
                    printedTitle = true;
                    Console.WriteLine("Reviews are still pending for this change list:");
                }

                Console.WriteLine("{0} : {1} comments.", review.UserName, comments);
            }

            return unsubmittedComments == 0;
        }
コード例 #5
0
ファイル: Program.cs プロジェクト: daptiv/Malevich
        /// <summary>
        /// Marks review as closed.
        /// </summary>
        /// <param name="context"> Database context. </param>
        /// <param name="userName"> User alias. </param>
        /// <param name="sourceControlId"> Source control ID. </param>
        /// <param name="cl"> Review number (source control side). </param>
        /// <param name="force"> Whether to force closing the review even if there are pending changes. </param>
        /// <param name="admin"> Close the review in admin mode, regardless of the user. </param>
        private static void MarkChangeListAsClosed(CodeReviewDataContext context, string userName,
            int sourceControlId, string cl, bool force, bool admin)
        {
            var cid = (from ch in context.ChangeLists
                       where ch.SourceControlId == sourceControlId && ch.CL.Equals(cl) &&
                             ch.Stage == 0 && (admin || ch.UserName.Equals(userName))
                       select ch.Id).FirstOrDefault();

            if (cid == null)
            {
                Console.WriteLine("No active change in database.");
                return;
            }

            if (force || NoPendingReviews(context, cid))
            {
                context.SubmitChangeList(cid);
                Console.WriteLine("{0} closed. Use 'review reopen {0}' to reopen.", cl);
            }
            else
            {
                Console.WriteLine("Pending review detected. If you want to close this change list");
                Console.WriteLine("anyway, use the --force.");
            }
        }
コード例 #6
0
ファイル: Program.cs プロジェクト: daptiv/Malevich
        /// <summary>
        /// The main function. Parses arguments, and if there is enough information, calls ProcessCodeReview.
        /// </summary>
        /// <param name="args"> Arguments passed by the system. </param>
        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                DisplayHelp();
                return;
            }

            // First, rummage through the environment, path, and the directories trying to detect the source
            // control system.
            string sourceControlInstance = Environment.GetEnvironmentVariable("REVIEW_INSTANCE");

            SourceControlSettings sdSettings = SourceDepotInterface.GetSettings();
            SourceControlSettings p4Settings = PerforceInterface.GetSettings();
            SourceControlSettings tfsSettings = SourceControl.Tfs.Factory.GetSettings();
            SourceControlSettings svnSettings = SubversionInterface.GetSettings();

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

            // Now go through the command line to get other options.
            string link = null;
            string linkDescr = null;
            string description = null;

            bool force = false;
            bool admin = false;

            string changeId = null;
            string newChangeId = null;

            bool includeBranchedFiles = false;

            List<string> reviewers = new List<string>();
            List<string> invitees = new List<string>();

            SourceControl.SourceControlType? sourceControlType = null;
            SourceControlSettings settings = new SourceControlSettings();

            string impersonatedUserName = null;

            List<string> bugIds = new List<string>();

            bool verbose = false;
            bool preview = false;

            for (int i = 0; i < args.Length; ++i)
            {
                if (i < args.Length - 1)
                {
                    if (args[i].EqualsIgnoreCase("--sourcecontrol"))
                    {
                        if ("TFS".EqualsIgnoreCase(args[i + 1]))
                        {
                            sourceControlType = SourceControl.SourceControlType.TFS;
                        }
                        else if ("P4".EqualsIgnoreCase(args[i + 1]))
                        {
                            sourceControlType = SourceControl.SourceControlType.PERFORCE;
                        }
                        else if ("SD".EqualsIgnoreCase(args[i + 1]))
                        {
                            sourceControlType = SourceControl.SourceControlType.SD;
                        }
                        else if ("SVN".EqualsIgnoreCase(args[i + 1]))
                        {
                            sourceControlType = SourceControl.SourceControlType.SUBVERSION;
                        }
                        else
                        {
                            Console.WriteLine("error : source control '{0}' is not supported.", args[i + 1]);
                            return;
                        }
                        ++i;
                        continue;
                    }

                    if (args[i].EqualsIgnoreCase("--port"))
                    {
                        settings.Port = args[i + 1];
                        ++i;
                        continue;
                    }

                    if (args[i].EqualsIgnoreCase("--server"))
                    {
                        settings.Port = args[i + 1];
                        ++i;
                        continue;
                    }

                    if (args[i].EqualsIgnoreCase("--client"))
                    {
                        settings.Client = args[i + 1];
                        ++i;
                        continue;
                    }

                    if (args[i].EqualsIgnoreCase("--workspace"))
                    {
                        settings.Client = args[i + 1];
                        ++i;
                        continue;
                    }

                    if (args[i].EqualsIgnoreCase("--tfsdiffsource"))
                    {
                        string diff = args[i + 1];
                        if (diff.EqualsIgnoreCase("local"))
                        {
                            settings.Diff = SourceControlSettings.DiffSource.Local;
                        }
                        else if (diff.EqualsIgnoreCase("shelf"))
                        {
                            settings.Diff = SourceControlSettings.DiffSource.Server;
                        }
                        else
                        {
                            Console.WriteLine(
                                "error : unrecognized value of TFS diff source. Should be either shelf or local.");
                            return;
                        }

                        ++i;
                        continue;
                    }

                    if (args[i].EqualsIgnoreCase("--user"))
                    {
                        settings.User = args[i + 1];
                        ++i;
                        continue;
                    }

                    if (args[i].EqualsIgnoreCase("--password"))
                    {
                        settings.Password = args[i + 1];
                        ++i;
                        continue;
                    }

                    if (args[i].EqualsIgnoreCase("--clientexe"))
                    {
                        settings.ClientExe = args[i + 1];
                        ++i;
                        continue;
                    }

                    if (args[i].EqualsIgnoreCase("--database"))
                    {
                        databaseServer = args[i + 1];
                        ++i;
                        continue;
                    }

                    if (args[i].EqualsIgnoreCase("--instance"))
                    {
                        sourceControlInstance = args[i + 1];
                        ++i;
                        continue;
                    }

                    if (args[i].EqualsIgnoreCase("--invite"))
                    {
                        if (!AddReviewers(invitees, args[i + 1]))
                            return;
                        ++i;
                        continue;
                    }

                    if (args[i].EqualsIgnoreCase("--link"))
                    {
                        link = args[i + 1];
                        ++i;

                        if (!(link.StartsWith(@"file://\\") || link.StartsWith("http://") ||
                            link.StartsWith("https://")))
                        {
                            Console.WriteLine("error : incorrect link specification : should start with http://, https://, or " +
                                              "file://. If the latter is used, the supplied file name should be UNC.");
                            return;
                        }
                        continue;
                    }

                    if (args[i].EqualsIgnoreCase("--linkdescr"))
                    {
                        linkDescr = args[i + 1];
                        ++i;
                        continue;
                    }

                    if (args[i].EqualsIgnoreCase("--description"))
                    {
                        description = args[i + 1];
                        ++i;
                        continue;
                    }

                    if (args[i].EqualsIgnoreCase("--impersonate"))
                    {
                        impersonatedUserName = args[++i];
                        continue;
                    }

                    if (args[i].EqualsIgnoreCase("--bugid"))
                    {
                        bugIds.Add(args[++i]);
                        continue;
                    }
                }

                if (args[i].EqualsIgnoreCase("--force"))
                {
                    force = true;
                    continue;
                }

                if (args[i].EqualsIgnoreCase("--admin"))
                {
                    admin = true;
                    continue;
                }

                if (args[i].EqualsIgnoreCase("--includebranchedfiles"))
                {
                    includeBranchedFiles = true;
                    continue;
                }

                if (args[i].EqualsIgnoreCase("--verbose"))
                {
                    verbose = true;
                    continue;
                }

                if (args[i].EqualsIgnoreCase("--preview"))
                {
                    preview = true;
                    continue;
                }

                if (args[i].EqualsIgnoreCase("help") ||
                    args[i].EqualsIgnoreCase("/help") ||
                    args[i].EqualsIgnoreCase("--help") ||
                    args[i].EqualsIgnoreCase("-help") ||
                    args[i].EqualsIgnoreCase("/h") ||
                    args[i].EqualsIgnoreCase("-h") ||
                    args[i].EqualsIgnoreCase("-?") ||
                    args[i].EqualsIgnoreCase("/?"))
                {
                    DisplayHelp();
                    return;
                }

                if (args[i].StartsWith("-"))
                {
                    Console.WriteLine("error : unrecognized flag: {0}", args[i]);
                    return;
                }

                if (command == null &&
                    args[i].EqualsIgnoreCase("review") ||
                    args[i].EqualsIgnoreCase("close") ||
                    args[i].EqualsIgnoreCase("delete") ||
                    args[i].EqualsIgnoreCase("reopen") ||
                    args[i].EqualsIgnoreCase("rename") ||
                    args[i].EqualsIgnoreCase("addlink"))
                {
                    command = args[i];
                    continue;
                }

                if (changeId == null)
                {
                    changeId = args[i];
                    continue;
                }

                if ("addlink".EqualsIgnoreCase(command))
                {
                    if (link == null)
                    {
                        link = args[i];
                        continue;
                    }
                    else if (linkDescr == null)
                    {
                        linkDescr = args[i];
                        continue;
                    }
                }

                if ("rename".EqualsIgnoreCase(command))
                {
                    if (newChangeId == null)
                    {
                        newChangeId = args[i];
                        continue;
                    }
                }

                if (command == null || "review".EqualsIgnoreCase(command))
                {
                    if (!AddReviewers(reviewers, args[i]))
                        return;

                    continue;
                }

                Console.WriteLine("error : {0} is not recognized. --help for help", args[i]);
                return;
            }

            string userName = impersonatedUserName ?? Environment.GetEnvironmentVariable("USERNAME");

            if (changeId == null)
            {
                Console.WriteLine("error : change list is required. Type 'review help' for help.");
                return;
            }

            if (databaseServer == null)
            {
                Console.WriteLine("error : database server is required. Type 'review help' for help.");
                return;
            }

            if (link == null && linkDescr != null)
            {
                Console.WriteLine("error : if you supply link description, the link must also be present.");
                return;
            }

            if (impersonatedUserName != null && !admin)
            {
                Console.WriteLine("error : --impersonate may only be used in conjunction with --admin.");
                return;
            }

            int sourceControlInstanceId;
            if (!Int32.TryParse(sourceControlInstance, out sourceControlInstanceId))
                sourceControlInstanceId = DefaultSourceControlInstanceId;

            // These commands do not require source control - get them out the way first.
            if (command != null)
            {
                CodeReviewDataContext context = new CodeReviewDataContext("Data Source=" + databaseServer +
                    ";Initial Catalog=CodeReview;Integrated Security=True");

                if (command.EqualsIgnoreCase("close"))
                {
                    MarkChangeListAsClosed(context, userName, sourceControlInstanceId, changeId, force, admin);
                    return;
                }
                else if (command.EqualsIgnoreCase("delete"))
                {
                    DeleteChangeList(context, userName, sourceControlInstanceId, changeId, force, admin);
                    return;
                }
                else if (command.EqualsIgnoreCase("rename"))
                {
                    RenameChangeList(context, userName, sourceControlInstanceId, changeId, newChangeId, admin);
                    return;
                }
                else if (command.EqualsIgnoreCase("reopen"))
                {
                    ReopenChangeList(context, userName, sourceControlInstanceId, changeId, admin);
                    return;
                }
                else if (command.EqualsIgnoreCase("addlink"))
                {
                    if (link != null)
                        AddAttachment(context, userName, changeId, link, linkDescr);
                    else
                        Console.WriteLine("You need to supply the link to add.");
                    return;
                }
            }

            // If we have the client, maybe we can guess the source control...
            if (sourceControlType == null && settings.ClientExe != null)
            {
                string clientExeFile = Path.GetFileName(settings.ClientExe);
                if ("sd.exe".EqualsIgnoreCase(clientExeFile))
                    sourceControlType = SourceControl.SourceControlType.SD;
                else if ("p4.exe".EqualsIgnoreCase(clientExeFile))
                    sourceControlType = SourceControl.SourceControlType.PERFORCE;
                else if ("tf.exe".EndsWith(clientExeFile, StringComparison.InvariantCultureIgnoreCase))
                    sourceControlType = SourceControl.SourceControlType.TFS;
                else if ("svn.exe".EqualsIgnoreCase(clientExeFile))
                    sourceControlType = SourceControl.SourceControlType.SUBVERSION;
            }

            // Attempt to detect the source control system.
            if (sourceControlType == null)
            {
                if (sdSettings.Port != null && sdSettings.Client != null && sdSettings.ClientExe != null)
                    sourceControlType = SourceControl.SourceControlType.SD;
                if (p4Settings.Port != null && p4Settings.Client != null && p4Settings.ClientExe != null)
                    sourceControlType = SourceControl.SourceControlType.PERFORCE;
                if (tfsSettings.Port != null)
                    sourceControlType = SourceControl.SourceControlType.TFS;
                if (svnSettings.Port != null && svnSettings.Client != null && svnSettings.ClientExe != null)
                    sourceControlType = SourceControl.SourceControlType.SUBVERSION;

                if (sourceControlType == null)
                {
                    Console.WriteLine("Could not determine the source control system.");
                    Console.WriteLine("User 'review help' for help with specifying it.");
                    return;
                }
            }

            // If source control is explicitly specified...
            if (sourceControlType == SourceControl.SourceControlType.TFS)
            {
                if (settings.Client != null)
                    tfsSettings.Client = settings.Client;
                if (settings.Port != null)
                    tfsSettings.Port = settings.Port;
                if (settings.User != null)
                    tfsSettings.User = settings.User;
                if (settings.Password != null)
                    tfsSettings.Password = settings.Password;
                if (settings.ClientExe != null)
                    tfsSettings.ClientExe = settings.ClientExe;
                if (settings.Diff != SourceControlSettings.DiffSource.Unspecified)
                    tfsSettings.Diff = settings.Diff;

                if (tfsSettings.Port == null)
                {
                    Console.WriteLine("Could not determine tfs server. Consider specifying it on the command line or " +
                        "in the environment.");
                    return;
                }

                if (tfsSettings.Client == null && tfsSettings.Diff == SourceControlSettings.DiffSource.Local)
                {
                    Console.WriteLine("Could not determine tfs workspace. Consider specifying it on the command line " +
                        "or in the environment.");
                    return;
                }
            }

            if (sourceControlType == SourceControl.SourceControlType.PERFORCE)
            {
                if (settings.Client != null)
                    p4Settings.Client = settings.Client;
                if (settings.Port != null)
                    p4Settings.Port = settings.Port;
                if (settings.User != null)
                    p4Settings.User = settings.User;
                if (settings.Password != null)
                    p4Settings.Password = settings.Password;
                if (settings.ClientExe != null)
                    p4Settings.ClientExe = settings.ClientExe;

                if (p4Settings.ClientExe == null)
                {
                    Console.WriteLine(
                        "Could not find p4.exe. Consider putting it in the path, or on the command line.");
                    return;
                }

                if (p4Settings.Port == null)
                {
                    Console.WriteLine("Could not determine the server port. " +
                        "Consider putting it on the command line, or in p4 config file.");
                    return;
                }

                if (p4Settings.Client == null)
                {
                    Console.WriteLine("Could not determine the perforce client. " +
                        "Consider putting it on the command line, or in p4 config file.");
                    return;
                }
            }

            if (sourceControlType == SourceControl.SourceControlType.SUBVERSION)
            {
                if (settings.Client != null)
                    svnSettings.Client = settings.Client;
                if (settings.Port != null)
                    svnSettings.Port = settings.Port;
                if (settings.User != null)
                    svnSettings.User = settings.User;
                if (settings.Password != null)
                    svnSettings.Password = settings.Password;
                if (settings.ClientExe != null)
                    svnSettings.ClientExe = settings.ClientExe;

                if (svnSettings.ClientExe == null)
                {
                    Console.WriteLine(
                        "Could not find svn.exe. Consider putting it in the path, or on the command line.");
                    return;
                }

                if (svnSettings.Port == null)
                {
                    Console.WriteLine("Could not determine the server Url. " +
                        "Consider putting it on the command line.");
                    return;
                }
            }

            if (sourceControlType == SourceControl.SourceControlType.SD)
            {
                if (settings.Client != null)
                    sdSettings.Client = settings.Client;
                if (settings.Port != null)
                    sdSettings.Port = settings.Port;
                if (settings.ClientExe != null)
                    sdSettings.ClientExe = settings.ClientExe;

                if (sdSettings.ClientExe == null)
                {
                    Console.WriteLine(
                        "Could not find sd.exe. Consider putting it in the path, or on the command line.");
                    return;
                }

                if (sdSettings.Port == null)
                {
                    Console.WriteLine("Could not determine the server port. " +
                        "Consider putting it on the command line, or in sd.ini.");
                    return;
                }

                if (sdSettings.Client == null)
                {
                    Console.WriteLine("Could not determine the source depot client. " +
                        "Consider putting it on the command line, or in sd.ini.");
                    return;
                }
            }

            try
            {
                ISourceControl sourceControl;
                IBugServer bugTracker = null;
                if (sourceControlType == SourceControl.SourceControlType.SD)
                    sourceControl = SourceDepotInterface.GetInstance(sdSettings.ClientExe, sdSettings.Port,
                        sdSettings.Client, sdSettings.Proxy);
                else if (sourceControlType == SourceControl.SourceControlType.PERFORCE)
                    sourceControl = PerforceInterface.GetInstance(p4Settings.ClientExe, p4Settings.Port,
                        p4Settings.Client, p4Settings.User, p4Settings.Password);
                else if (sourceControlType == SourceControl.SourceControlType.SUBVERSION)
                    sourceControl = SubversionInterface.GetInstance(svnSettings.ClientExe, svnSettings.Port, svnSettings.Client);
                else if (sourceControlType == SourceControl.SourceControlType.TFS)
                {
                    sourceControl = SourceControl.Tfs.Factory.GetISourceControl(
                        tfsSettings.Port, tfsSettings.Client, tfsSettings.ClientOwner, tfsSettings.User,
                        tfsSettings.Password, tfsSettings.Diff == SourceControlSettings.DiffSource.Server);
                    bugTracker = SourceControl.Tfs.Factory.GetIBugServer(
                        tfsSettings.Port, tfsSettings.Client, tfsSettings.ClientOwner,
                        tfsSettings.User, tfsSettings.Password);
                }
                else
                    throw new ApplicationException("Unknown source control system.");

                if (verbose)
                {
                    ILogControl logControl = sourceControl as ILogControl;
                    if (logControl != null)
                        logControl.SetLogLevel(LogOptions.ClientUtility);
                    else
                        Console.WriteLine("Note: client log requested, but not supported by the utility.");
                }

                if (!sourceControl.Connect())
                {
                    Console.WriteLine("Failed to connect to the source control system.");
                    return;
                }

                ProcessCodeReview(databaseServer, sourceControl, sourceControlInstanceId, changeId, reviewers, invitees,
                    link, linkDescr, description, bugTracker, bugIds, force, includeBranchedFiles, preview, impersonatedUserName);

                sourceControl.Disconnect();
            }
            catch (SourceControlRuntimeError)
            {
                // The error condition has already been printed out at the site where this has been thrown.
                Console.WriteLine("Code review has not been submitted!");
            }
            catch (SqlException ex)
            {
                Console.WriteLine("Could not connect to Malevich database. This could be a temporary");
                Console.WriteLine("network problem or a misconfigured database name. Please ensure that");
                Console.WriteLine("the database ({0}) is specified correctly.", databaseServer);
                Console.WriteLine("If this is a new Malevich server installation, please ensure that");
                Console.WriteLine("SQL Server TCP/IP protocol is enabled, and its ports are open in");
                Console.WriteLine("the firewall.");
                if (verbose)
                {
                    Console.WriteLine("Exception information (please include in bug reports):");
                    Console.WriteLine("{0}", ex);
                }
                else
                {
                    Console.WriteLine("Use --verbose flag to show detailed error information.");
                }
            }
        }
コード例 #7
0
ファイル: Program.cs プロジェクト: daptiv/Malevich
        /// <summary>
        /// Marks review as deleted.
        /// </summary>
        /// <param name="context"> Database context. </param>
        /// <param name="userName"> User alias. </param>
        /// <param name="sourceControlId"> Source control ID. </param>
        /// <param name="cl"> Review number (source control side). </param>
        /// <param name="force"> Whether to force closing the review even if there are pending changes. </param>
        /// <param name="admin"> Close the review in admin mode, regardless of the user. </param>
        private static void DeleteChangeList(CodeReviewDataContext context, string userName,
            int sourceControlId, string cl, bool force, bool admin)
        {
            int[] cids = admin ?
                (from ch in context.ChangeLists
                 where ch.SourceControlId == sourceControlId && ch.CL.Equals(cl) && ch.Stage == 0
                 select ch.Id).ToArray() :
                (from ch in context.ChangeLists
                 where ch.SourceControlId == sourceControlId && ch.CL.Equals(cl) &&
                       ch.UserName.Equals(userName) && ch.Stage == 0
                 select ch.Id).ToArray();

            if (cids.Length != 1)
            {
                Console.WriteLine("No active change in database.");
                return;
            }

            if (force || NoPendingReviews(context, cids[0]))
            {
                context.DeleteChangeList(cids[0]);
                Console.WriteLine("{0} deleted. Use 'review reopen {0}' to undelete.", cl);
            }
            else
            {
                Console.WriteLine("Pending review detected. If you want to delete this change list");
                Console.WriteLine("anyway, use the --force.");
            }
        }
コード例 #8
0
ファイル: CommentsExchange.cs プロジェクト: daptiv/Malevich
    public int GetNumberOfReviewsWhereIAmTheReviewee()
    {
        string alias = GetUserAlias();
        if (alias == null)
            return 0;

        CodeReviewDataContext dataContext = new CodeReviewDataContext(
            System.Configuration.ConfigurationManager.ConnectionStrings[Config.ConnectionString].ConnectionString);

        int result = (from cc in dataContext.ChangeLists
                      where cc.UserName == alias && cc.Stage == 0
                      select cc).Distinct().Count();

        dataContext.Connection.Close();
        dataContext.Dispose();

        return result;
    }
コード例 #9
0
ファイル: Program.cs プロジェクト: daptiv/Malevich
        /// <summary>
        /// Main driver for the code review submission tool.
        /// </summary>
        /// <param name="context"> The database context. </param>
        /// <param name="sd"> Source control client. </param>
        /// <param name="sourceControlInstanceId"> The ID of source control instance to use.
        ///     This is an ID of a record in the database that is unique for a given CL namespace.</param>
        /// <param name="changeList"> CL. </param>
        /// <param name="reviewers"> The list of people to who to send the code review request. </param>
        /// <param name="invitees"> The list of people who are invited to participate in the code review
        /// (but need to positively acknowledge the invitation by choosing to review the code). </param>
        /// <param name="link"> Optionally, a link to a file or a web page to be displayed in CL page. </param>
        /// <param name="linkDescr"> An optional description of the said link. </param>
        /// <param name="description"> An optional description of the changelist, overrides any description
        ///                             from the source control tool. </param>
        /// <param name="bugTracker">The server for accessing bugs.</param>
        /// <param name="bugIds">List of bugs to associate with review page.</param>
        /// <param name="force"> If branched files are included, confirms the submission even if there
        /// are too many files. </param>
        /// <param name="includeBranchedFiles"> </param>
        /// <param name="preview">If true, do not commit changes.</param>
        private static void ProcessCodeReview(
            string databaseServer,
            ISourceControl sd,
            int sourceControlInstanceId,
            string changeList,
            List<string> reviewers,
            List<string> invitees,
            string link,
            string linkDescr,
            string description,
            IBugServer bugServer,
            List<string> bugIds,
            bool force,
            bool includeBranchedFiles,
            bool preview,
            string impersonateUserName)
        {
            Change change = sd.GetChange(changeList, includeBranchedFiles);
            if (change == null)
                return;

            changeList = change.ChangeListFriendlyName ?? changeList;

            if (change == null)
                return;

            if (includeBranchedFiles && !force)
            {
                int branchedFiles = 0;
                foreach (SourceControl.ChangeFile file in change.Files)
                {
                    if (file.IsText && (file.Action == SourceControl.ChangeFile.SourceControlAction.BRANCH ||
                        file.Action == SourceControl.ChangeFile.SourceControlAction.INTEGRATE))
                        ++branchedFiles;
                }

                if (branchedFiles > MaximumIntegratedFiles)
                {
                    Console.WriteLine("There are {0} branched/integrated files in this change.", branchedFiles);
                    Console.WriteLine("Including the full text of so many files in review may increase the size");
                    Console.WriteLine("of the review database considerably.");
                    Console.Write("Are you sure you want to proceed (Yes/No)? ");
                    string response = Console.ReadLine();
                    Console.WriteLine("NOTE: In the future you can override this check by specifying --force");
                    Console.WriteLine("on the command line.");
                    if (response[0] != 'y' && response[0] != 'Y')
                        return;
                }
            }

            if (!VerifyDiffIntegrity(change))
                return;

            CodeReviewDataContext context = new CodeReviewDataContext("Data Source=" + databaseServer +
                ";Initial Catalog=CodeReview;Integrated Security=True");

            var existingReviewQuery = from rv in context.ChangeLists
                                      where rv.CL == changeList && rv.SourceControlId == sourceControlInstanceId
                                      select rv;

            // is this a new review, or a refresh of an existing one?
            bool isNewReview = (existingReviewQuery.Count() == 0);

            int? changeId = null;
            if (description == null)
                description = change.Description;

            context.Connection.Open();
            using (context.Connection)
            using (context.Transaction = context.Connection.BeginTransaction(System.Data.IsolationLevel.Snapshot))
            {
                // This more like "GetOrAddChangeList", as it returns the id of any pre-existing changelist
                // matching 'changeList'.
                if (impersonateUserName == null)
                {
                    context.AddChangeList(
                        sourceControlInstanceId, change.SdClientName, changeList, description,
                        change.TimeStamp.ToUniversalTime(), ref changeId);
                }
                else
                {
                    var changeListDb = (from c in context.ChangeLists
                                        where c.SourceControlId == sourceControlInstanceId &&
                                              c.UserName == impersonateUserName &&
                                              c.UserClient == change.SdClientName &&
                                              c.CL == changeList
                                        select c).FirstOrDefault();

                    if (changeListDb == null)
                    {
                        changeListDb = new ChangeList()
                        {
                            SourceControlId = sourceControlInstanceId,
                            UserName = impersonateUserName,
                            UserClient = change.SdClientName,
                            CL = changeList,
                            Description = description,
                            TimeStamp = change.TimeStamp.ToUniversalTime(),
                            Stage = 0
                        };

                        context.ChangeLists.InsertOnSubmit(changeListDb);
                        context.SubmitChanges(); // Not actually submitted until transaction completes.
                    }

                    changeId = changeListDb.Id;
                }

                // Get the list of files corresponding to this changelist already on the server.
                var dbChangeFiles = (from fl in context.ChangeFiles
                                     where fl.ChangeListId == changeId && fl.IsActive
                                     select fl)
                                     .OrderBy(file => file.ServerFileName)
                                     .GetEnumerator();

                var inChangeFiles = (from fl in change.Files
                                     select fl)
                                     .OrderBy(file => file.ServerFileName)
                                     .GetEnumerator();

                bool dbChangeFilesValid = dbChangeFiles.MoveNext();
                bool inChangeFilesValid = inChangeFiles.MoveNext();

                // Uses bitwise OR to ensure that both MoveNext methods are invoked.
                FileExistsIn existsIn = FileExistsIn.Neither;
                while (dbChangeFilesValid || inChangeFilesValid)
                {
                    int comp;
                    if (!dbChangeFilesValid) // No more files in database
                        comp = 1;
                    else if (!inChangeFilesValid) // No more files in change list.
                        comp = -1;
                    else
                        comp = string.Compare(dbChangeFiles.Current.ServerFileName,
                                              inChangeFiles.Current.ServerFileName);

                    if (comp < 0) // We have a file in DB, but not in source control. Delete it from DB.
                    {
                        Console.WriteLine("File {0} has been dropped from the change list.",
                                          dbChangeFiles.Current.ServerFileName);
                        context.RemoveFile(dbChangeFiles.Current.Id);

                        dbChangeFilesValid = dbChangeFiles.MoveNext();
                        existsIn = FileExistsIn.Database;
                        continue;
                    }

                    SourceControl.ChangeFile file = inChangeFiles.Current;

                    int? fid = null;
                    if (comp > 0) // File in source control, but not in DB
                    {
                        Console.WriteLine("Adding file {0}", file.ServerFileName);
                        context.AddFile(changeId, file.LocalFileName, file.ServerFileName, ref fid);
                        existsIn = FileExistsIn.Change;
                    }
                    else // Both files are here. Need to check the versions.
                    {
                        fid = dbChangeFiles.Current.Id;
                        existsIn = FileExistsIn.Both;
                    }

                    bool haveBase = (from bv in context.FileVersions
                                     where bv.FileId == fid && bv.Revision == file.Revision && bv.IsRevisionBase
                                     select bv).Count() > 0;

                    var versionQuery = from fv in context.FileVersions
                                       where fv.FileId == fid && fv.Revision == file.Revision
                                       orderby fv.Id descending
                                       select fv;

                    var version = versionQuery.FirstOrDefault();
                    bool haveVersion = false;
                    if (version != null && version.Action == (int)file.Action &&
                        BodiesEqual(NormalizeLineEndings(file.Data), NormalizeLineEndings(version.Text)))
                        haveVersion = true;

                    int? vid = null;
                    if (!haveBase && file.IsText &&
                        (file.Action == SourceControl.ChangeFile.SourceControlAction.EDIT ||
                         (file.Action == SourceControl.ChangeFile.SourceControlAction.INTEGRATE &&
                          includeBranchedFiles)))
                    {
                        string fileBody;
                        DateTime? dateTime;
                        fileBody = sd.GetFile(
                            file.OriginalServerFileName == null ? file.ServerFileName : file.OriginalServerFileName,
                            file.Revision, out dateTime);
                        if (fileBody == null)
                        {
                            Console.WriteLine("ERROR: Could not retrieve {0}#{1}", file.ServerFileName, file.Revision);
                            return;
                        }

                        Console.WriteLine("Adding base revision for {0}#{1}", file.ServerFileName, file.Revision);
                        context.AddVersion(fid, file.Revision, (int)file.Action, dateTime, true, true, true, fileBody,
                            ref vid);
                    }
                    else
                    {
                        // Do this so we print the right thing.
                        haveBase = true;
                    }

                    if (!haveVersion)
                    {
                        if (file.Action == SourceControl.ChangeFile.SourceControlAction.DELETE)
                        {
                            context.AddVersion(
                                fid, file.Revision, (int)file.Action, null, file.IsText, false, false, null, ref vid);
                        }
                        else if ((file.Action == SourceControl.ChangeFile.SourceControlAction.RENAME) || !file.IsText)
                        {
                            context.AddVersion(fid, file.Revision, (int)file.Action, file.LastModifiedTime, file.IsText,
                                false, false, null, ref vid);
                        }
                        else if (file.Action == SourceControl.ChangeFile.SourceControlAction.ADD ||
                            file.Action == SourceControl.ChangeFile.SourceControlAction.BRANCH)
                        {
                            context.AddVersion(fid, file.Revision, (int)file.Action, file.LastModifiedTime, file.IsText,
                                true, false, file.Data, ref vid);
                        }
                        else if (file.Action == SourceControl.ChangeFile.SourceControlAction.EDIT ||
                            file.Action == SourceControl.ChangeFile.SourceControlAction.INTEGRATE)
                        {
                            context.AddVersion(fid, file.Revision, (int)file.Action, file.LastModifiedTime, file.IsText,
                                false, false, file.Data, ref vid);
                        }

                        string textFlag = file.IsText ? "text" : "binary";
                        string action;
                        switch (file.Action)
                        {
                            case SourceControl.ChangeFile.SourceControlAction.ADD:
                                action = "add";
                                break;

                            case SourceControl.ChangeFile.SourceControlAction.EDIT:
                                action = "edit";
                                break;

                            case SourceControl.ChangeFile.SourceControlAction.DELETE:
                                action = "delete";
                                break;

                            case SourceControl.ChangeFile.SourceControlAction.BRANCH:
                                action = "branch";
                                break;

                            case SourceControl.ChangeFile.SourceControlAction.INTEGRATE:
                                action = "integrate";
                                break;

                            case SourceControl.ChangeFile.SourceControlAction.RENAME:
                                action = "rename";
                                break;

                            default:
                                action = "unknown";
                                break;
                        }

                        if (version != null && vid == version.Id)
                        {
                            // The file was already there. This happens sometimes because SQL rountrip (to database
                            // and back) is not an identity: somtimes the non-graphical characters change depending
                            // on the database code page. But if the database has returned a number, and this number
                            // is the same as the previous version id, we know that the file has not really been added.
                            haveVersion = true;
                        }
                        else
                        {
                            Console.WriteLine("Added version for {0}#{1}({2}, {3})", file.ServerFileName, file.Revision,
                                textFlag, action);
                        }
                    }

                    if (haveBase && haveVersion)
                        Console.WriteLine("{0} already exists in the database.", file.ServerFileName);

                    if ((existsIn & FileExistsIn.Database) == FileExistsIn.Database)
                        dbChangeFilesValid = dbChangeFiles.MoveNext();
                    if ((existsIn & FileExistsIn.Change) == FileExistsIn.Change)
                        inChangeFilesValid = inChangeFiles.MoveNext();

                    existsIn = FileExistsIn.Neither;
                }

                foreach (string reviewer in reviewers)
                {
                    int? reviewId = null;
                    context.AddReviewer(reviewer, changeId.Value, ref reviewId);
                }

                foreach (string invitee in invitees)
                {
                    context.AddReviewRequest(changeId.Value, invitee);
                }

                if (link != null)
                {
                    int? attachmentId = null;
                    context.AddAttachment(changeId.Value, linkDescr, link, ref attachmentId);
                }

                if (preview)
                    context.Transaction.Rollback();
                else
                    context.Transaction.Commit();
            }

            var reviewSiteUrl = Environment.GetEnvironmentVariable("REVIEW_SITE_URL");
            if (reviewSiteUrl != null)
            {
                var reviewPage = reviewSiteUrl;
                if (!reviewPage.EndsWith("/"))
                    reviewPage += "/";
                reviewPage += @"default.aspx?cid=" + changeId.ToString();
                Console.WriteLine("Change {0} is ready for review, and may be viewed at", changeList);
                Console.WriteLine("   {0}", reviewPage);

                var allBugIds = Enumerable.Union(change.BugIds, bugIds);
                if (bugServer != null && allBugIds.Count() > 0)
                {
                    Console.WriteLine("Connecting to TFS Work Item Server");
                    if (bugServer.Connect())
                    {
                        foreach (var bugId in allBugIds)
                        {
                            var bug = bugServer.GetBug(bugId);
                            if (bug.AddLink(new Uri(reviewPage), null))
                                Console.WriteLine("Bug {0} has been linked to review page.", bugId);
                        }
                    }
                }
            }
            else
            {
                Console.WriteLine("Change {0} is ready for review.", changeList);
            if (isNewReview)
            {
                if (reviewers.Count == 0 && invitees.Count == 0)
                {
                    Console.WriteLine("Note: no reviewers specified. You can add them later using this utility.");
                }
                else
                {
                    Console.WriteLine("If the mail notifier is enabled, the reviewers will shortly receive mail");
                    Console.WriteLine("asking them to review your changes.");
                }
            }
            else
            {
                Console.WriteLine("Note: existing reviewers will not be immediately informed of this update.");
                Console.WriteLine("To ask them to re-review your updated changes, you can visit the review website");
                Console.WriteLine("and submit a response.");
            }
            }

            if (preview)
                Console.WriteLine("In preview mode -- no actual changes committed.");
        }
コード例 #10
0
ファイル: UserContext.cs プロジェクト: daptiv/Malevich
    /// <summary>
    /// Gets the data context out of the system cache, or the database.
    /// </summary>
    /// <param name="user"> Authenticated user alias (no DOMAIN). </param>
    /// <param name="cache"> System cache. </param>
    /// <param name="context"> Data connection to the database. </param>
    /// <returns> User context. </returns>
    public static UserContext GetUserContext(string user, Cache cache, CodeReviewDataContext context)
    {
        Hashtable allUserContexts = (Hashtable)cache[UserContextTableName];
        if (allUserContexts == null)
            cache[UserContextTableName] = allUserContexts = new Hashtable();

        UserContext uc = (UserContext)allUserContexts[user];
        if (uc == null)
        {
            uc = new UserContext(user);
            var dataContexts = from cc in context.UserContexts
                               where cc.UserName == user
                               select cc;
            foreach (DataModel.UserContext dataContext in dataContexts)
            {
                if (dataContext.KeyName.Equals(UserContext.TEXT_SIZE, StringComparison.OrdinalIgnoreCase))
                {
                    int value;
                    if (int.TryParse(dataContext.Value, out value))
                        uc.TextSize = value;
                }
                else if (dataContext.KeyName.Equals(UserContext.TEXT_FONT, StringComparison.OrdinalIgnoreCase))
                {
                    uc.TextFont = dataContext.Value;
                }
                else if (dataContext.KeyName.Equals(UserContext.HINT_MASK, StringComparison.OrdinalIgnoreCase))
                {
                    int value;
                    if (int.TryParse(dataContext.Value, out value))
                        uc.HintsMask = value;
                }
                else if (dataContext.KeyName.Equals(UserContext.MAX_LINE_LENGTH, StringComparison.OrdinalIgnoreCase))
                {
                    int value;
                    if (int.TryParse(dataContext.Value, out value))
                        uc.MaxLineLength = value;
                }
                else if (dataContext.KeyName.Equals(UserContext.SPACES_PER_TAB, StringComparison.OrdinalIgnoreCase))
                {
                    int value;
                    if (int.TryParse(dataContext.Value, out value))
                        uc.SpacesPerTab = value;
                }
                else if (dataContext.KeyName.Equals(UserContext.UNIFIED_DIFF_VIEW, StringComparison.OrdinalIgnoreCase))
                {
                    bool value;
                    if (bool.TryParse(dataContext.Value, out value))
                        uc.UnifiedDiffView = value;
                }
                else if (dataContext.KeyName.Equals(UserContext.COMMENT_CLICK_MODE, StringComparison.OrdinalIgnoreCase))
                {
                    try
                    {
                        uc.CommentClickMode = (CommentClickMode)Enum.Parse(
                            typeof(CommentClickMode), dataContext.Value);
                    }
                    catch (ArgumentNullException) { }
                    catch (ArgumentException) { }
                }
                // Compat with previous "double/single" click database entries
                else if (dataContext.KeyName.Equals("commentstyle", StringComparison.OrdinalIgnoreCase))
                {
                    int value;
                    if (int.TryParse(dataContext.Value, out value))
                    {
                        uc.CommentClickMode =
                            (value == 0 ? CommentClickMode.SingleClickAnywhere
                                        : CommentClickMode.DoubleClickAnywhere);

                        // Save translated setting
                        context.SetUserContext(UserContext.COMMENT_CLICK_MODE, uc.CommentClickMode.ToString());
                    }

                    // Remove old setting from database
                    context.UserContexts.DeleteOnSubmit(dataContext);
                    context.SubmitChanges();
                }
                else if (dataContext.KeyName.Equals(
                    UserContext.AUTO_COLLAPSE_COMMENTS,
                    StringComparison.OrdinalIgnoreCase))
                {
                    bool value;
                    if (bool.TryParse(dataContext.Value, out value))
                        uc.AutoCollapseComments = value;
                }
            }

            allUserContexts[user] = uc;
        }

        return uc;
    }
コード例 #11
0
ファイル: Program.cs プロジェクト: daptiv/Malevich
 /// <summary>
 /// Sets the source control to point to the selected web site.
 /// </summary>
 /// <param name="installParams"> Installation parameters. </param>
 private static void ConfigureSourceControlInDatabase(InstallParameters installParams)
 {
     try
     {
         using (CodeReviewDataContext context = new CodeReviewDataContext("Data Source=" +
             installParams.Database + ";Initial Catalog=CodeReview;Integrated Security=True"))
         {
             SourceControl[] sourceControls = (from sc in context.SourceControls select sc).ToArray();
             if (sourceControls.Length == 1)
             {
                 sourceControls[0].WebsiteName = "/" + (installParams.WebApplicationName == null ? "Malevich" :
                     installParams.WebApplicationName);
                 context.SubmitChanges();
             }
         }
     }
     catch (Exception ex)
     {
         Log(ex.ToString());
         throw new InstallationException("Failed to adjust source control.");
     }
 }
コード例 #12
0
ファイル: Program.cs プロジェクト: daptiv/Malevich
        /// <summary>
        /// Installs or upgrades the database.
        /// </summary>
        /// <param name="installParams"> Installation parameters. </param>
        private static void InstallDatabase(InstallParameters installParams)
        {
            Log("Installing the database.");
            int changeListCount = 0;
            if (installParams.DatabaseDirectory == null)
            {
                CreateDatabase(installParams);
            }
            else
            {
                BackupDatabase(installParams);
                if (installParams.FixChangeListTimeStamps)
                    FixChangeListTimeStamps(installParams);

                SqlConnection sqlConnection = new SqlConnection("Data Source=" + installParams.Database +
                    ";Initial Catalog=CodeReview;Integrated Security=True");
                sqlConnection.Open();
                using (SqlCommand command = new SqlCommand("SELECT COUNT(Id) FROM ChangeList", sqlConnection))
                    changeListCount = (int)command.ExecuteScalar();
                sqlConnection.Close();
            }

            Log("  Deploying the metadata:");

            // Bug in vsdbcmd: if HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\9.0 does not exist, the tool
            // does not work.
            Registry.CurrentUser.CreateSubKey(@"Software\Microsoft\VisualStudio\9.0").Close();

            string deployer = Path.Combine(installParams.InstallSource, @"redistr\deploy\vsdbcmd.exe");
            string metadata = Path.Combine(installParams.InstallSource, @"$(TargetFileName)");
            string postscript = Path.Combine(installParams.InstallSource, @"Script.PostDeployment.sql");

            Process client = new Process();
            client.StartInfo.UseShellExecute = false;
            client.StartInfo.RedirectStandardError = true;
            client.StartInfo.RedirectStandardOutput = true;
            client.StartInfo.CreateNoWindow = true;
            client.StartInfo.FileName = deployer;
            client.StartInfo.Arguments = "/a:Deploy /cs:\"Data Source=" + installParams.Database +
                ";Integrated Security=true\" /model:\"" + metadata + "\" /dd:+ /p:TargetDatabase=CodeReview";

            client.Start();

            string stderr;
            string stdout = Malevich.Util.CommonUtils.ReadProcessOutput(client, false, out stderr);
            client.Dispose();

            if (!String.IsNullOrEmpty(stderr))
            {
                Log("Deployment has returned an error status:");
                Log(stderr);
                Log("The rest of the output:");
                Log(stdout);
                throw new InstallationException("Failed to deploy the metadata.");
            }

            Log(stdout);

            Log("  Running the post-deployment script.");
            string postdeploycommands = null;
            using (StreamReader pds = new StreamReader(postscript))
                postdeploycommands = pds.ReadToEnd();

            if (String.IsNullOrEmpty(postdeploycommands))
                throw new InstallationException("Could not get postdeployment script.");

            try
            {
                SqlConnection sqlConnection = new SqlConnection("Data Source=" + installParams.Database +
                    ";Initial Catalog=CodeReview;Integrated Security=True");
                sqlConnection.Open();
                using (SqlCommand command = new SqlCommand(postdeploycommands, sqlConnection))
                    command.ExecuteNonQuery();
                sqlConnection.Close();
            }
            catch (SqlException sex)
            {
                Log(sex.ToString());
                throw new InstallationException("Could not deploy the database.");
            }

            Log("  Verifying the database.");

            try
            {
                using (CodeReviewDataContext context = new CodeReviewDataContext("Data Source=" +
                    installParams.Database + ";Initial Catalog=CodeReview;Integrated Security=True"))
                {
                    int? cid = null;
                    context.AddChangeList(1, "Test client", "Test change list", "Test description",
                        DateTime.Now, ref cid);
                    ChangeList[] cl = (from cc in context.ChangeLists where cc.Id == cid.Value select cc).ToArray();
                    if (cl.Length != 1)
                        throw new InstallationException(
                            "Failed to create or query a change list in the verification step.");
                    context.ChangeLists.DeleteOnSubmit(cl[0]);
                    context.SubmitChanges();

                    if ((from cc in context.ChangeLists select cc).Count() != changeListCount)
                        throw new InstallationException(
                            "Verification failed - upgrade changed number of change lists in the database.");
                }
            }
            catch (Exception ex)
            {
                Log(ex.ToString());
                throw new InstallationException("Failed to verify the database.");
            }
        }
コード例 #13
0
ファイル: CommentsExchange.cs プロジェクト: daptiv/Malevich
    public void DeleteComment(string commentId)
    {
        if (!HttpContext.Current.User.Identity.IsAuthenticated)
            return;

        CommentId cid = new CommentId(commentId);

        CodeReviewDataContext dataContext = new CodeReviewDataContext(
            System.Configuration.ConfigurationManager.ConnectionStrings[Config.ConnectionString].ConnectionString);
        var commentQuery = from cm in dataContext.Comments
                           where cm.FileVersionId == cid.FileVersionId && cm.Line == cid.Line &&
                               cm.LineStamp == cid.LineStamp
                           select cm.Id;

        if (commentQuery.Count() == 1)
        {
            int id = commentQuery.Single();
            dataContext.DeleteComment(id);
        }
        dataContext.Connection.Close();
        dataContext.Dispose();
    }
コード例 #14
0
ファイル: CommentsExchange.cs プロジェクト: daptiv/Malevich
    public void RecordHintShowing(int hintNumber)
    {
        string alias = GetUserAlias();
        if (alias == null)
            return;

        CodeReviewDataContext context = new CodeReviewDataContext(
            System.Configuration.ConfigurationManager.ConnectionStrings[Config.ConnectionString].ConnectionString);

        UserContext uc = UserContext.GetUserContext(alias, Context.Cache, context);

        long mask = 1 << (hintNumber - 1);
        uc.HintsMask = (uc.HintsMask == null ? 0 : uc.HintsMask.Value) | mask;

        context.SetUserContext(UserContext.HINT_MASK, uc.HintsMask.Value.ToString());

        context.Connection.Close();
        context.Dispose();
    }
コード例 #15
0
ファイル: Program.cs プロジェクト: daptiv/Malevich
        /// <summary>
        /// Lists the review comments in the string builder.
        /// </summary>
        /// <param name="context"> The data context. </param>
        /// <param name="reviewId"> The review object. </param>
        /// <param name="isBodyHtml"> If true, generate HTML comments. </param>
        /// <param name="malevichPath"> The URL of Malevich server. </param>
        private static void ListCommentsForReview(CodeReviewDataContext context, Review rw, StringBuilder sb,
            bool isBodyHtml, string malevichUrl)
        {
            if (rw.CommentText != null)
            {
                if (isBodyHtml)
                {
                    sb.Append("<div class=\"CssMalevichOverallComment\"><pre>");
                    sb.Append(HttpUtility.HtmlEncode(rw.CommentText));
                    sb.Append("</pre></div>");
                }
                else
                {
                    sb.Append(rw.CommentText);
                    sb.Append("\n\n\n");
                }
            }

            var commentsQuery = from cm in context.Comments
                                where cm.ReviewId == rw.Id
                                join fv in context.FileVersions on cm.FileVersionId equals fv.Id
                                orderby fv.FileId, cm.FileVersionId, cm.Line, cm.LineStamp
                                select cm;

            Comment[] comments = commentsQuery.ToArray();
            if (comments.Length == 0)
                return;

            if (isBodyHtml)
                sb.Append("<table class=\"CssMalevichCommentTable\">");

            int currentFileVersionId = 0;
            int currentLine = 0;
            foreach (Comment comment in comments)
            {
                if (currentFileVersionId != comment.FileVersionId)
                {
                    FileVersion version = comment.FileVersion;
                    string name = version.ChangeFile.ServerFileName;
                    int lastForwardSlash = name.LastIndexOf('/');
                    if (lastForwardSlash >= 0)
                        name = name.Substring(lastForwardSlash + 1);

                    FileVersion ver = comment.FileVersion;

                    if (isBodyHtml)
                        sb.Append("<tr class=\"CssMalevichEmailCommentTableRow\">" +
                            "<td colspan=\"2\" class=\"CssMalevichEmailFileColumn\">" +
                            "<a href=\"" + malevichUrl + "?fid=" + ver.FileId + "&vid1=" + ver.Id + "&vid2=" + ver.Id +
                            "\" class=\"CssMalevichFileLink\">File " + FileDisplayName(name, ver) + "</a>:</td></tr>");
                    else
                        sb.Append("\n\nFile " + FileDisplayName(name, ver) + ":\n");

                    currentFileVersionId = version.Id;
                    currentLine = 0;
                }

                if (isBodyHtml)
                    sb.Append(
                        "<tr class=\"CssMalevichEmailCommentTableRow\"><td class=\"CssMalevichEmailLineColumn\">");

                if (currentLine != comment.Line)
                {
                    currentLine = comment.Line;
                    sb.Append("Line " + currentLine + ":\n");
                }

                if (isBodyHtml)
                {
                    sb.Append("</td><td class=\"CssMalevichEmailCommentColumn\"><pre>");
                    sb.Append(HttpUtility.HtmlEncode(comment.CommentText));
                    sb.Append("</pre></td></tr>");
                }
                else
                {
                    sb.Append(comment.CommentText);
                    sb.Append("\n");
                }
            }

            if (isBodyHtml)
                sb.Append("</table>");
        }
コード例 #16
0
ファイル: Program.cs プロジェクト: daptiv/Malevich
        /// <summary>
        /// Reopens a change list.
        /// </summary>
        /// <param name="context"> Database context. </param>
        /// <param name="userName"> User alias. </param>
        /// <param name="sourceControlId"> Source control ID. </param>
        /// <param name="cl"> Review number (source control side). </param>
        /// <param name="admin"> Close the review in admin mode, regardless of the user. </param>
        private static void ReopenChangeList(CodeReviewDataContext context, string userName,
            int sourceControlId, string cl, bool admin)
        {
            int[] cids = admin ?
                (from ch in context.ChangeLists
                 where ch.SourceControlId == sourceControlId && ch.CL.Equals(cl) && ch.Stage != 0
                 select ch.Id).ToArray() :
                (from ch in context.ChangeLists
                 where ch.SourceControlId == sourceControlId && ch.CL.Equals(cl) &&
                       ch.UserName.Equals(userName) && ch.Stage != 0
                 select ch.Id).ToArray();

            if (cids.Length != 1)
            {
                Console.WriteLine("No inactive change in database.");
                return;
            }

            context.ReopenChangeList(cids[0]);
            Console.WriteLine("{0} reopened.", cl);
        }
コード例 #17
0
ファイル: Program.cs プロジェクト: daptiv/Malevich
        /// <summary>
        /// Does all the work.
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            if (args.Contains<string>("help") || args.Contains("-h") || args.Contains("-?"))
            {
                DisplayUsage();
                return;
            }

            if (args.Length == 2 && args[0].Equals("testsetup", StringComparison.InvariantCultureIgnoreCase))
            {
                TestSetup(args[1]);
                return;
            }

            int remindDaysOld = -1;
            if (args.Length == 2 && args[0].Equals("--remind", StringComparison.InvariantCultureIgnoreCase))
            {
                if ((!Int32.TryParse(args[1], out remindDaysOld)) || (remindDaysOld <= 0))
                {
                    DisplayUsage();
                    return;
                }
            }

            if (args.Length > 0 && remindDaysOld <= 0)
            {
                SetConfiguration(args);
                return;
            }

            if (!ReviewNotifierConfiguration.Load())
                return;

            logger = new Logger(Config.LogFile);

            logger.Log("Started processing review notifications @ {0}", DateTime.Now);

            MailTemplates templates = new MailTemplates(logger);

            CodeReviewDataContext context = new CodeReviewDataContext(Config.Database);
            Dictionary<int, string> sourceControlRoots = new Dictionary<int, string>();

            var sourceControlsQuery = from sc in context.SourceControls select sc;
            foreach (SourceControl sc in sourceControlsQuery)
            {
                string site = string.Empty;
                if (!string.IsNullOrEmpty(sc.WebsiteName))
                {
                    if (!sc.WebsiteName.StartsWith("/"))
                        site = "/" + sc.WebsiteName.Substring(1);
                    else
                        site = sc.WebsiteName;
                }
                sourceControlRoots[sc.Id] = site;
            }

            List<MessageType> exchangeItems = null;
            if (!string.IsNullOrEmpty(Config.EmailService))
                exchangeItems = new List<MessageType>();

            List<MailMessage> smtpItems = null;
            if (!string.IsNullOrEmpty(Config.SmtpServer))
                smtpItems = new List<MailMessage>();

            var mailChangeListQuery = from cl in context.MailChangeLists
                                      join rv in context.Reviewers on cl.ReviewerId equals rv.Id
                                      join ch in context.ChangeLists on cl.ChangeListId equals ch.Id
                                      select new { cl, rv.ReviewerAlias, ch.UserName, ch.SourceControlId, ch.CL,
                                          ch.Description };

            foreach (var request in mailChangeListQuery)
            {
                logger.Log("Sending new review request for {0} to {1}", request.CL, request.ReviewerAlias);

                string subject = templates.CreateMailSubject(MailTemplates.MailType.Request, request.CL,
                    request.UserName, Abbreviate(request.Description, MaxDescriptionLength), null);
                bool isBodyHtml;
                string body = templates.CreateMail(MailTemplates.MailType.Request, request.cl.ChangeListId,
                    ResolveFriendlyName(Config, request.ReviewerAlias), ResolveFriendlyName(Config, request.UserName),
                    Config.WebServer, sourceControlRoots[request.SourceControlId],
                    null, request.Description, request.CL, out isBodyHtml);

                try
                {
                    string email = ResolveUser(Config, request.ReviewerAlias);
                    string replyToAlias = ResolveUser(Config, request.UserName);
                    string sender = ResolveUser(Config, Config.User);
                    string from = Config.FromEmail == null ? null : Config.FromEmail + "@" + Config.EmailDomain;
                    if (exchangeItems != null)
                    {
                        exchangeItems.Add(MakeExchangeMessage(email, from, replyToAlias, subject, body, isBodyHtml,
                            request.cl.ChangeListId, true));
                    }

                    if (smtpItems != null)
                    {
                        smtpItems.Add(MakeSmtpMessage(email, from, replyToAlias, sender, subject, body, isBodyHtml,
                            request.cl.ChangeListId, true));
                    }
                }
                catch (FormatException)
                {
                    logger.Log("Could not send email - invalid email format!");
                }

                context.MailChangeLists.DeleteOnSubmit(request.cl);
            }

            var reviewInviteQuery = (from ri in context.MailReviewRequests
                                     join ch in context.ChangeLists on ri.ChangeListId equals ch.Id
                                     select new { ri, ch }).ToArray();

            foreach (var invite in reviewInviteQuery)
            {
                logger.Log("Sending new review invitation for {0} to {1}", invite.ch.CL,
                    invite.ri.ReviewerAlias);

                string subject = templates.CreateMailSubject(MailTemplates.MailType.Invite, invite.ch.CL,
                    invite.ch.UserName, Abbreviate(invite.ch.Description, MaxDescriptionLength), null);
                bool isBodyHtml;
                string body = templates.CreateMail(MailTemplates.MailType.Invite, invite.ch.Id, null,
                    ResolveFriendlyName(Config, invite.ch.UserName), Config.WebServer,
                    sourceControlRoots[invite.ch.SourceControlId], null,
                    invite.ch.Description, invite.ch.CL, out isBodyHtml);

                try
                {
                    string email = ResolveUser(Config, invite.ri.ReviewerAlias);
                    string replyToAlias = ResolveUser(Config, invite.ch.UserName);
                    string sender = ResolveUser(Config, Config.User);
                    string from = Config.FromEmail == null ? null : Config.FromEmail + "@" + Config.EmailDomain;
                    if (exchangeItems != null)
                        exchangeItems.Add(MakeExchangeMessage(email, from, replyToAlias, subject, body, isBodyHtml,
                            invite.ch.Id, true));

                    if (smtpItems != null)
                        smtpItems.Add(MakeSmtpMessage(email, from, replyToAlias, sender, subject, body, isBodyHtml,
                            invite.ch.Id, true));
                }
                catch (FormatException)
                {
                    logger.Log("Could not send email - invalid email format!");
                }

                context.MailReviewRequests.DeleteOnSubmit(invite.ri);
            }

            var mailReviewQuery = (from mr in context.MailReviews
                                   join rw in context.Reviews on mr.ReviewId equals rw.Id
                                   join cc in context.ChangeLists on rw.ChangeListId equals cc.Id
                                   select new { mr, rw, cc }).ToArray();
            foreach (var request in mailReviewQuery)
            {
                logger.Log("Sending review notification for {0}", request.cc.CL);

                string from = Config.FromEmail == null ? null : Config.FromEmail + "@" + Config.EmailDomain;
                string sender = ResolveUser(Config, Config.User);

                List<string> to = new List<string>();
                List<string> cc = new List<string>();

                if (request.cc.UserName.Equals(request.rw.UserName, StringComparison.InvariantCultureIgnoreCase))
                {
                    // This is a response to review comments. The reviewers are on the 'to' line, reviewee is on 'cc'.
                    cc.Add(ResolveUser(Config, request.cc.UserName));

                    foreach (Reviewer r in request.cc.Reviewers)
                        to.Add(ResolveUser(Config, r.ReviewerAlias));
                }
                else
                {
                    // This is a review. The reviewee is on the 'to' line, the reviewers are on 'cc'.
                    to.Add(ResolveUser(Config, request.cc.UserName));

                    foreach (Reviewer r in request.cc.Reviewers)
                        cc.Add(ResolveUser(Config, r.ReviewerAlias));
                }

                string replyToAlias = ResolveUser(Config, request.rw.UserName);

                string malevichUrl = "http://" + Config.WebServer + sourceControlRoots[request.cc.SourceControlId] +
                    "/default.aspx";

                StringBuilder comments = new StringBuilder();
                string body;
                bool isBodyHtml;
                string subject;
                if (request.cc.UserName.Equals(request.rw.UserName, StringComparison.InvariantCultureIgnoreCase))
                {
                    subject = templates.CreateMailSubject(MailTemplates.MailType.Response, request.cc.CL,
                        request.cc.UserName, Abbreviate(request.cc.Description, MaxDescriptionLength), null);

                    isBodyHtml = templates.IsTemplateHtml(MailTemplates.MailType.Response);

                    ListCommentsForReview(context, request.rw, comments, isBodyHtml, malevichUrl);

                    body = templates.CreateMail(MailTemplates.MailType.Response, request.cc.Id, null,
                        ResolveFriendlyName(Config, request.rw.UserName), Config.WebServer,
                        sourceControlRoots[request.cc.SourceControlId], null,
                        comments.ToString(), request.cc.CL);
                }
                else
                {
                    string verdict = ReviewStatusToSentence(request.rw.OverallStatus);

                    subject = templates.CreateMailSubject(MailTemplates.MailType.Iteration, request.cc.CL,
                        request.cc.UserName, Abbreviate(request.cc.Description, MaxDescriptionLength), verdict);

                    isBodyHtml = templates.IsTemplateHtml(MailTemplates.MailType.Iteration);

                    ListCommentsForReview(context, request.rw, comments, isBodyHtml, malevichUrl);

                    body = templates.CreateMail(MailTemplates.MailType.Iteration, request.cc.Id,
                        ResolveFriendlyName(Config, request.rw.UserName), ResolveFriendlyName(Config, request.cc.UserName),
                        Config.WebServer, sourceControlRoots[request.cc.SourceControlId],
                        verdict, comments.ToString(), request.cc.CL);
                }

                try
                {
                    if (exchangeItems != null)
                        exchangeItems.Add(MakeExchangeMessage(to, cc, from, replyToAlias, subject, body.ToString(),
                            isBodyHtml, request.cc.Id, false));

                    if (smtpItems != null)
                        smtpItems.Add(MakeSmtpMessage(to, cc, from, replyToAlias, sender, subject, body.ToString(),
                            isBodyHtml, request.cc.Id, false));
                }
                catch (FormatException)
                {
                    logger.Log("Could not send email - invalid email format!");
                }

                context.MailReviews.DeleteOnSubmit(request.mr);
            }

            if (remindDaysOld > 0)
            {
                DateTime threshold = DateTime.Now.AddDays(-remindDaysOld);
                var oldChangeListQuery = from rr in context.ChangeLists
                                         where rr.Stage == 0 && rr.TimeStamp < threshold
                                         select rr;

                foreach (ChangeList cl in oldChangeListQuery)
                {
                    logger.Log("Sending review reminder for {0}", cl.CL);

                    string subject = templates.CreateMailSubject(MailTemplates.MailType.Reminder, cl.CL, cl.UserName,
                        Abbreviate(cl.Description, MaxDescriptionLength), null);
                    string email = ResolveUser(Config, cl.UserName);
                    string sender = ResolveUser(Config, Config.User);
                    string from = Config.FromEmail == null ? null : Config.FromEmail + "@" + Config.EmailDomain;
                    bool isBodyHtml;
                    string body = templates.CreateMail(MailTemplates.MailType.Reminder, cl.Id,
                        null, ResolveFriendlyName(Config, cl.UserName), Config.WebServer,
                        sourceControlRoots[cl.SourceControlId],
                        null, cl.Description, cl.CL, out isBodyHtml);

                    try
                    {
                        if (exchangeItems != null)
                            exchangeItems.Add(MakeExchangeMessage(email, from, null, subject, body, isBodyHtml,
                                cl.Id, false));

                        if (smtpItems != null)
                            smtpItems.Add(MakeSmtpMessage(email, from, null, sender, subject, body, isBodyHtml,
                                cl.Id, false));
                    }
                    catch (FormatException)
                    {
                        logger.Log("Could not send email - invalid email format!");
                    }
                }
            }

            if (exchangeItems != null && exchangeItems.Count() > 0)
                SendExchangeMail(Config, exchangeItems);
            if (smtpItems != null && smtpItems.Count() > 0)
                SendSmtpMail(Config, smtpItems);

            context.SubmitChanges();

            logger.Log("Finished processing review mail @ {0}", DateTime.Now);

            logger.Close();
        }
コード例 #18
0
ファイル: CommentsExchange.cs プロジェクト: daptiv/Malevich
    public int GetNumberOfOpenReviews()
    {
        if (!HttpContext.Current.User.Identity.IsAuthenticated)
            return 0;

        CodeReviewDataContext dataContext = new CodeReviewDataContext(
            System.Configuration.ConfigurationManager.ConnectionStrings[Config.ConnectionString].ConnectionString);

        int result = (from cc in dataContext.ChangeLists where cc.Stage == 0 select cc).Distinct().Count();

        dataContext.Connection.Close();
        dataContext.Dispose();

        return result;
    }