Exemplo n.º 1
0
        /// <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();
        }
Exemplo n.º 2
0
        /// <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.");
        }
Exemplo n.º 3
0
 /// <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.");
     }
 }
Exemplo n.º 4
0
    /// <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;
    }
Exemplo n.º 5
0
        /// <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.");
            }
        }