Пример #1
0
 /// <summary>
 /// Creates fingerprints from any matching diagnostics
 /// </summary>
 /// <param name="Job">The job that was run</param>
 /// <param name="JobStep">The job step that was run</param>
 /// <param name="Diagnostics">List of diagnostics that were produced by the build. Items should be removed from this list if they match.</param>
 /// <param name="Issues">List which receives all the matched issues.</param>
 public virtual void Match(InputJob Job, InputJobStep JobStep, List <InputDiagnostic> Diagnostics, List <Issue> Issues)
 {
     for (int Idx = 0; Idx < Diagnostics.Count; Idx++)
     {
         InputDiagnostic Diagnostic = Diagnostics[Idx];
         if (TryMatch(Job, JobStep, Diagnostic, Issues))
         {
             Diagnostics.RemoveAt(Idx);
             Idx--;
         }
     }
 }
Пример #2
0
        /// <summary>
        /// Adds diagnostics from a job step into the issue database
        /// </summary>
        /// <param name="Perforce">Perforce connection used to find possible causers</param>
        /// <param name="State">The current set of tracked issues</param>
        /// <param name="Build">The new build</param>
        /// <param name="PreviousChange">The last changelist that was built before this one</param>
        /// <param name="InputJob">Job containing the step to add</param>
        /// <param name="InputJobStep">The job step to add</param>
        void AddStep(PerforceConnection Perforce, PersistentState State, InputJob InputJob, InputJobStep InputJobStep)
        {
            // Create a lazily evaluated list of changes that are responsible for any errors
            Lazy <IReadOnlyList <ChangeInfo> > LazyChanges = new Lazy <IReadOnlyList <ChangeInfo> >(() => FindChanges(Perforce, State, InputJob));

            // Create issues for any diagnostics in this step
            List <Issue> InputIssues = new List <Issue>();

            foreach (Matcher Matcher in Matchers)
            {
                Matcher.Match(InputJob, InputJobStep, InputJobStep.Diagnostics, InputIssues);
            }

            // Merge the issues together
            List <Issue> NewIssues = new List <Issue>();

            foreach (Issue InputIssue in InputIssues)
            {
                Issue OutputIssue = MergeIntoExistingIssue(Perforce, State, InputJob, InputJobStep, InputIssue, LazyChanges);
                if (OutputIssue == null)
                {
                    NewIssues.Add(InputIssue);
                    State.Issues.Add(InputIssue);
                    OutputIssue = InputIssue;
                }
                AddFailureToIssue(OutputIssue, InputJob, InputJobStep, InputIssue.Diagnostics[0].ErrorUrl, State);
            }

            // Update the watchers for any new issues
            foreach (Issue NewIssue in NewIssues)
            {
                IReadOnlyList <ChangeInfo> Changes = LazyChanges.Value;
                if (Changes != null)
                {
                    // Find the pattern matcher for this issue
                    Matcher Matcher = CategoryToMatcher[NewIssue.Category];

                    // Update the causers
                    List <ChangeInfo> Causers = Matcher.FindCausers(Perforce, NewIssue, Changes);
                    foreach (ChangeInfo Causer in Causers)
                    {
                        NewIssue.SourceChanges.UnionWith(Causer.SourceChanges);
                        NewIssue.PendingWatchers.Add(Causer.Record.User);
                    }
                }
            }
        }
Пример #3
0
        /// <summary>
        /// Adds a new build history for a stream
        /// </summary>
        /// <param name="Issue">The issue to add a build to</param>
        /// <param name="InputJob">The job containing the error</param>
        /// <param name="InputJobStep">The job step containing the error</param>
        /// <param name="InputErrorUrl">Url of the error</param>
        /// <param name="State">Current persistent state. Used to find previous build history.</param>
        void AddFailureToIssue(Issue Issue, InputJob InputJob, InputJobStep InputJobStep, string InputErrorUrl, PersistentState State)
        {
            // Find or add a step name to history mapping
            Dictionary <string, IssueHistory> StepNameToHistory;

            if (!Issue.Streams.TryGetValue(InputJob.Stream, out StepNameToHistory))
            {
                StepNameToHistory = new Dictionary <string, IssueHistory>();
                Issue.Streams.Add(InputJob.Stream, StepNameToHistory);
            }

            // Find or add a history for this step
            IssueHistory History;

            if (!StepNameToHistory.TryGetValue(InputJobStep.Name, out History))
            {
                History = new IssueHistory(State.FindBuildBefore(InputJob.Stream, InputJob.Change, InputJobStep.Name));
                StepNameToHistory.Add(InputJobStep.Name, History);
            }

            // Add the new build
            History.AddFailedBuild(CreateBuildForJobStep(InputJob, InputJobStep, InputErrorUrl));
        }
Пример #4
0
 /// <summary>
 /// Tries to create a fingerprint from an individual diagnostic.
 /// </summary>
 /// <param name="Job">The job that was run</param>
 /// <param name="JobStep">The job step that was run</param>
 /// <param name="Diagnostic">A diagnostic from the given job step</param>
 /// <param name="Issues">List which receives all the matched issues.</param>
 /// <returns>True if this diagnostic should be removed (usually because a fingerprint was created)</returns>
 public abstract bool TryMatch(InputJob Job, InputJobStep JobStep, InputDiagnostic Diagnostic, List <Issue> Issues);
Пример #5
0
        /// <summary>
        /// Find all changes PLUS all robomerge source changes
        /// </summary>
        /// <param name="Perforce">The Perforce connection to use</param>
        /// <param name="State">State of </param>
        /// <param name="InputJob">The job that failed</param>
        /// <returns>Set of changelist numbers</returns>
        IReadOnlyList <ChangeInfo> FindChanges(PerforceConnection Perforce, PersistentState State, InputJob InputJob)
        {
            // List of changes since the last successful build in this stream
            IReadOnlyList <ChangeInfo> Changes = null;

            // Find the previous changelist that was built in this stream
            List <IssueBuild> StreamBuilds;

            if (State.Streams.TryGetValue(InputJob.Stream, out StreamBuilds))
            {
                // Find the last change submitted to this stream before it started failing
                int LastChange = -1;
                for (int Idx = 0; Idx < StreamBuilds.Count && StreamBuilds[Idx].Change < InputJob.Change; Idx++)
                {
                    LastChange = StreamBuilds[Idx].Change;
                }

                // Allow adding to any open issue that contains changes merged from other branches
                if (LastChange != -1)
                {
                    // Query for all the changes since then
                    Changes = FindChanges(Perforce, InputJob.Stream, LastChange, InputJob.Change);
                }
            }
            return(Changes);
        }
Пример #6
0
 /// <summary>
 /// Creates a TrackedBuild instance for the given jobstep
 /// </summary>
 /// <param name="InputJob">The job to create a build for</param>
 /// <param name="InputJobStep">The step to create a build for</param>
 /// <param name="InputErrorUrl">The error Url</param>
 /// <returns>New build instance</returns>
 IssueBuild CreateBuildForJobStep(InputJob InputJob, InputJobStep InputJobStep, string InputErrorUrl)
 {
     return(new IssueBuild(InputJob.Change, InputJob.Name, InputJob.Url, InputJobStep.Name, InputJobStep.Url, InputErrorUrl));
 }
Пример #7
0
        /// <summary>
        /// Finds or adds an issue for a particular issue
        /// </summary>
        /// <param name="Perforce">Perforce connection used to find possible causers</param>
        /// <param name="State">The current set of tracked issues</param>
        /// <param name="Build">The new build</param>
        /// <param name="PreviousChange">The last changelist that was built before this one</param>
        /// <param name="InputJob">Job containing the step to add</param>
        /// <param name="InputJobStep">The job step to add</param>
        Issue MergeIntoExistingIssue(PerforceConnection Perforce, PersistentState State, InputJob InputJob, InputJobStep InputJobStep, Issue InputIssue, Lazy <IReadOnlyList <ChangeInfo> > LazyChanges)
        {
            // Find the pattern matcher for this fingerprint
            Matcher Matcher = CategoryToMatcher[InputIssue.Category];

            // Check if it can be added to an existing open issue
            foreach (Issue Issue in State.Issues)
            {
                // Check this issue already exists in the current stream
                Dictionary <string, IssueHistory> StepNameToHistory;
                if (!Issue.Streams.TryGetValue(InputJob.Stream, out StepNameToHistory))
                {
                    continue;
                }

                // Check that this issue has not already been closed
                IssueHistory History;
                if (StepNameToHistory.TryGetValue(InputJobStep.Name, out History))
                {
                    if (!History.CanAddFailedBuild(InputJob.Change))
                    {
                        continue;
                    }
                }
                else
                {
                    if (!StepNameToHistory.Values.Any(x => x.CanAddFailedBuild(InputJob.Change)))
                    {
                        continue;
                    }
                }

                // Try to merge the fingerprint
                if (!Matcher.CanMerge(InputIssue, Issue))
                {
                    continue;
                }

                // Add the new build
                Matcher.Merge(InputIssue, Issue);
                return(Issue);
            }

            // Check if this issue can be merged with an issue built in another stream
            IReadOnlyList <ChangeInfo> Changes = LazyChanges.Value;

            if (Changes != null && Changes.Count > 0)
            {
                SortedSet <int> SourceChanges = new SortedSet <int>(Changes.SelectMany(x => x.SourceChanges));
                foreach (Issue Issue in State.Issues)
                {
                    // Check if this issue does not already contain this stream, but contains one of the causing changes
                    if (Issue.Streams.ContainsKey(InputJob.Stream))
                    {
                        continue;
                    }
                    if (!SourceChanges.Any(x => Issue.SourceChanges.Contains(x)))
                    {
                        continue;
                    }
                    if (!Matcher.CanMerge(InputIssue, Issue))
                    {
                        continue;
                    }

                    // Merge the issue
                    Matcher.Merge(InputIssue, Issue);
                    return(Issue);
                }
            }

            // Check if it can be merged into an issue that's been created for this job. We only do this after exhausting all other options.
            foreach (Issue Issue in State.Issues)
            {
                if (Issue.InitialJobUrl == InputIssue.InitialJobUrl && Matcher.CanMergeInitialJob(InputIssue, Issue))
                {
                    Matcher.Merge(InputIssue, Issue);
                    return(Issue);
                }
            }

            return(null);
        }