private void AddBuggJiraMapping(Bugg NewBugg, ref HashSet <string> FoundJiras, ref Dictionary <string, List <Bugg> > JiraIDtoBugg) { string JiraID = NewBugg.TTPID; FoundJiras.Add("key = " + JiraID); bool bAdd = !JiraIDtoBugg.ContainsKey(JiraID); if (bAdd) { JiraIDtoBugg.Add(JiraID, new List <Bugg>()); } JiraIDtoBugg[JiraID].Add(NewBugg); }
/// <summary> /// Update an existing Bugg /// </summary> /// <param name="entity"></param> public void Update(Bugg entity) { var set = _entityContext.Set <Bugg>(); var entry = set.Local.SingleOrDefault(f => f.Id == entity.Id); if (entry != null) { var attachedFeature = _entityContext.Entry(entry); attachedFeature.CurrentValues.SetValues(entity); attachedFeature.State = EntityState.Modified; } else { _entityContext.Buggs.Attach(entity); _entityContext.Entry(entity).State = EntityState.Modified; } }
/* * /// <summary> * /// The empty view of the buggs page. * /// </summary> * /// * public ActionResult Index() * { * using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString(), bCreateNewLog: true )) * { * BuggsViewModel Results = new BuggsViewModel(); * Results.GenerationTime = LogTimer.GetElapsedSeconds().ToString( "F2" ); * return View( "Index", Results ); * } * }*/ /// <summary> /// The Index action. /// </summary> /// <param name="BuggsForm">The form of user data passed up from the client.</param> /// <returns>The view to display a list of Buggs on the client.</returns> public ActionResult Index(FormCollection BuggsForm) { using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString(), bCreateNewLog: true)) { BuggRepository Buggs = new BuggRepository(); FormHelper FormData = new FormHelper(Request, BuggsForm, "CrashesInTimeFrameGroup"); BuggsViewModel Results = Buggs.GetResults(FormData); foreach (var Bugg in Results.Results) { // Populate function calls. Bugg.GetFunctionCalls(); } Results.GenerationTime = LogTimer.GetElapsedSeconds().ToString("F2"); return(View("Index", Results)); } }
/// <summary> /// Create a new crash data model object and insert it into the database /// </summary> /// <param name="description"></param> /// <returns></returns> private Crash CreateCrash(CrashDescription description) { var newCrash = new Crash { Branch = description.BranchName, BaseDir = description.BaseDir, BuildVersion = description.EngineVersion, EngineVersion = description.BuildVersion, ChangeListVersion = description.BuiltFromCL.ToString(), CommandLine = description.CommandLine, EngineMode = description.EngineMode, ComputerName = description.MachineGuid }; //if there's a valid username assign the associated UserNameId else use "anonymous". var userName = (!string.IsNullOrEmpty(description.UserName)) ? description.UserName : UserNameAnonymous; var user = _unitOfWork.UserRepository.GetByUserName(userName); if (user != null) { newCrash.UserNameId = user.Id; } else { newCrash.User = new User() { UserName = description.UserName, UserGroupId = 5 }; } //If there's a valid EpicAccountId assign that. if (!string.IsNullOrEmpty(description.EpicAccountId)) { newCrash.EpicAccountId = description.EpicAccountId; } newCrash.Description = ""; if (description.UserDescription != null) { newCrash.Description = string.Join(Environment.NewLine, description.UserDescription); } newCrash.EngineMode = description.EngineMode; newCrash.GameName = description.GameName; newCrash.LanguageExt = description.Language; //Converted by the crash process. newCrash.PlatformName = description.Platform; if (description.ErrorMessage != null) { newCrash.Summary = string.Join("\n", description.ErrorMessage); } if (description.CallStack != null) { newCrash.RawCallStack = string.Join("\n", description.CallStack); } if (description.SourceContext != null) { newCrash.SourceContext = string.Join("\n", description.SourceContext); } newCrash.TimeOfCrash = description.TimeofCrash; newCrash.Processed = description.bAllowToBeContacted; newCrash.Jira = ""; newCrash.FixedChangeList = ""; newCrash.ProcessFailed = description.bProcessorFailed; // Set the crash type newCrash.CrashType = 1; //if we have a crash type set the crash type if (!string.IsNullOrEmpty(description.CrashType)) { switch (description.CrashType.ToLower()) { case "crash": newCrash.CrashType = 1; break; case "assert": newCrash.CrashType = 2; break; case "ensure": newCrash.CrashType = 3; break; case "": case null: default: newCrash.CrashType = 1; break; } } else //else fall back to the old behavior and try to determine type from RawCallStack { if (newCrash.RawCallStack != null) { if (newCrash.RawCallStack.Contains("FDebug::AssertFailed")) { newCrash.CrashType = 2; } else if (newCrash.RawCallStack.Contains("FDebug::Ensure")) { newCrash.CrashType = 3; } else if (newCrash.RawCallStack.Contains("FDebug::OptionallyLogFormattedEnsureMessageReturningFalse")) { newCrash.CrashType = 3; } else if (newCrash.RawCallStack.Contains("NewReportEnsure")) { newCrash.CrashType = 3; } } } // As we're adding it, the status is always new newCrash.Status = "New"; /* * Unused Crashes' fields. * * Title nchar(20) * Selected bit * Version int * AutoReporterID int * Processed bit -> renamed to AllowToBeContacted * HasDiagnosticsFile bit always true * HasNewLogFile bit * HasMetaData bit always true */ // Set the unused fields to the default values. //NewCrash.Title = ""; removed from dbml //NewCrash.Selected = false; removed from dbml //NewCrash.Version = 4; removed from dbml //NewCrash.AutoReporterID = 0; removed from dbml //NewCrash.HasNewLogFile = false;removed from dbml //NewCrash.HasDiagnosticsFile = true; //NewCrash.HasMetaData = true; newCrash.UserActivityHint = description.UserActivityHint; BuildPattern(newCrash); if (newCrash.CommandLine == null) { newCrash.CommandLine = ""; } _unitOfWork.Dispose(); _unitOfWork = new UnitOfWork(new CrashReportEntities()); var callStackRepository = _unitOfWork.CallstackRepository; try { var crashRepo = _unitOfWork.CrashRepository; //if we don't have any callstack data then insert the crash and return if (string.IsNullOrEmpty(newCrash.Pattern)) { crashRepo.Save(newCrash); _unitOfWork.Save(); return(newCrash); } //If this isn't a new pattern then link it to our crash data model if (callStackRepository.Any(data => data.Pattern == newCrash.Pattern)) { var callstackPattern = callStackRepository.First(data => data.Pattern == newCrash.Pattern); newCrash.PatternId = callstackPattern.id; } else { //if this is a new callstack pattern then insert into data model and create a new bugg. var callstackPattern = new CallStackPattern { Pattern = newCrash.Pattern }; callStackRepository.Save(callstackPattern); _unitOfWork.Save(); newCrash.PatternId = callstackPattern.id; } //Mask out the line number and File path from our error message. var errorMessageString = description.ErrorMessage != null?String.Join("", description.ErrorMessage) : ""; //Create our masking regular expressions var fileRegex = new Regex(@"(\[File:).*?(])"); //Match the filename out the file name var lineRegex = new Regex(@"(\[Line:).*?(])"); //Match the line no. /** * Regex to match ints of two characters or longer * First term ((?<=\s)|(-)) : Positive look behind, match if preceeded by whitespace or if first character is '-' * Second term (\d{3,}) match three or more decimal chracters in a row. * Third term (?=(\s|$)) positive look ahead match if followed by whitespace or end of line/file. */ var intRegex = new Regex(@"-?\d{3,}"); /** * Regular expression for masking out floats */ var floatRegex = new Regex(@"-?\d+\.\d+"); /** * Regular expression for masking out hexadecimal numbers */ var hexRegex = new Regex(@"0x[\da-fA-F]+"); //mask out terms matches by our regex's var trimmedError = fileRegex.Replace(errorMessageString, ""); trimmedError = lineRegex.Replace(trimmedError, ""); trimmedError = floatRegex.Replace(trimmedError, ""); trimmedError = hexRegex.Replace(trimmedError, ""); trimmedError = intRegex.Replace(trimmedError, ""); //Check to see if the masked error message is unique ErrorMessage errorMessage = null; if (_unitOfWork.ErrorMessageRepository.Any(data => data.Message.Contains(trimmedError))) { errorMessage = _unitOfWork.ErrorMessageRepository.First(data => data.Message.Contains(trimmedError)); } else { //if it's a new message then add it to the database. errorMessage = new ErrorMessage() { Message = trimmedError }; _unitOfWork.ErrorMessageRepository.Save(errorMessage); _unitOfWork.Save(); } //Check for an existing bugg with this pattern and error message / no error message if (_unitOfWork.BuggRepository.Any(data => (data.PatternId == newCrash.PatternId || data.Pattern == newCrash.Pattern) && (newCrash.CrashType == 3 || (data.ErrorMessageId == errorMessage.Id || data.ErrorMessageId == null)))) { //if a bugg exists for this pattern update the bugg data var bugg = _unitOfWork.BuggRepository.First(data => data.PatternId == newCrash.PatternId) ?? _unitOfWork.BuggRepository.First(data => data.Pattern == newCrash.Pattern); bugg.PatternId = newCrash.PatternId; if (newCrash.CrashType != 3) { bugg.CrashType = newCrash.CrashType; bugg.ErrorMessageId = errorMessage.Id; } //also update the bugg data while we're here bugg.TimeOfLastCrash = newCrash.TimeOfCrash; if (String.Compare(newCrash.BuildVersion, bugg.BuildVersion, StringComparison.Ordinal) != 1) { bugg.BuildVersion = newCrash.BuildVersion; } _unitOfWork.Save(); //if a bugg exists update this crash from the bugg //buggs are authoritative in this case newCrash.Buggs.Add(bugg); newCrash.Jira = bugg.TTPID; newCrash.FixedChangeList = bugg.FixedChangeList; newCrash.Status = bugg.Status; _unitOfWork.CrashRepository.Save(newCrash); _unitOfWork.Save(); } else { //if there's no bugg for this pattern create a new bugg and insert into the data store. var bugg = new Bugg(); bugg.TimeOfFirstCrash = newCrash.TimeOfCrash; bugg.TimeOfLastCrash = newCrash.TimeOfCrash; bugg.TTPID = newCrash.Jira; bugg.Pattern = newCrash.Pattern; bugg.PatternId = newCrash.PatternId; bugg.NumberOfCrashes = 1; bugg.NumberOfUsers = 1; bugg.NumberOfUniqueMachines = 1; bugg.BuildVersion = newCrash.BuildVersion; bugg.CrashType = newCrash.CrashType; bugg.Status = newCrash.Status; bugg.FixedChangeList = newCrash.FixedChangeList; bugg.ErrorMessageId = errorMessage.Id; newCrash.Buggs.Add(bugg); _unitOfWork.BuggRepository.Save(bugg); _unitOfWork.CrashRepository.Save(newCrash); _unitOfWork.Save(); } } catch (DbEntityValidationException dbentEx) { var messageBuilder = new StringBuilder(); messageBuilder.AppendLine("Db Entity Validation Exception Exception was:"); messageBuilder.AppendLine(dbentEx.ToString()); var innerEx = dbentEx.InnerException; while (innerEx != null) { messageBuilder.AppendLine("Inner Exception : " + innerEx.Message); innerEx = innerEx.InnerException; } if (dbentEx.EntityValidationErrors != null) { messageBuilder.AppendLine("Validation Errors : "); foreach (var valErr in dbentEx.EntityValidationErrors) { messageBuilder.AppendLine(valErr.ValidationErrors.Select(data => data.ErrorMessage).Aggregate((current, next) => current + "; /n" + next)); } } FLogger.Global.WriteException(messageBuilder.ToString()); } catch (Exception ex) { var messageBuilder = new StringBuilder(); messageBuilder.AppendLine("Create Crash Exception : "); messageBuilder.AppendLine(ex.Message.ToString()); var innerEx = ex.InnerException; while (innerEx != null) { messageBuilder.AppendLine("Inner Exception : " + innerEx.Message); innerEx = innerEx.InnerException; } FLogger.Global.WriteException("Create Crash Exception : " + messageBuilder.ToString()); _slackWriter.Write("Create Crash Exception : " + messageBuilder.ToString()); throw; } return(newCrash); }
/// <summary> /// Remove a Bugg from the data store /// </summary> /// <param name="entity"></param> public void Delete(Bugg entity) { _entityContext.Buggs.Remove(entity); }
/// <summary> /// Add a new Bugg to the data store /// </summary> /// <param name="entity"></param> public void Save(Bugg entity) { _entityContext.Buggs.Add(entity); }
/// <summary> /// Retrieve all Buggs matching the search criteria. /// </summary> /// <param name="FormData">The incoming form of search criteria from the client.</param> /// <param name="BuggIDToBeAddedToJira">ID of the bugg that will be added to JIRA</param> /// <returns>A view to display the filtered Buggs.</returns> public ReportsViewModel GetResults(FormHelper FormData, int BuggIDToBeAddedToJira) { BuggRepository BuggsRepo = new BuggRepository(); CrashRepository CrashRepo = new CrashRepository(); // @TODO yrx 2015-02-17 BuggIDToBeAddedToJira replace with List<int> based on check box and Submit? // Enumerate JIRA projects if needed. // https://jira.ol.epicgames.net//rest/api/2/project var JC = JiraConnection.Get(); var JiraComponents = JC.GetNameToComponents(); var JiraVersions = JC.GetNameToVersions(); using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString())) { string AnonumousGroup = "Anonymous"; //List<String> Users = FRepository.Get().GetUserNamesFromGroupName( AnonumousGroup ); int AnonymousGroupID = FRepository.Get(BuggsRepo).FindOrAddGroup(AnonumousGroup); HashSet <int> AnonumousIDs = FRepository.Get(BuggsRepo).GetUserIdsFromUserGroup(AnonumousGroup); int AnonymousID = AnonumousIDs.First(); HashSet <string> UserNamesForUserGroup = FRepository.Get(BuggsRepo).GetUserNamesFromGroupName(AnonumousGroup); //FormData.DateFrom = DateTime.Now.AddDays( -1 ); var Crashes = CrashRepo .FilterByDate(CrashRepo.ListAll(), FormData.DateFrom, FormData.DateTo.AddDays(1)) // Only crashes and asserts .Where(Crash => Crash.CrashType == 1 || Crash.CrashType == 2) // Only anonymous user .Where(Crash => Crash.UserNameId.Value == AnonymousID) .Select(Crash => new { ID = Crash.Id, TimeOfCrash = Crash.TimeOfCrash.Value, //UserID = Crash.UserNameId.Value, BuildVersion = Crash.BuildVersion, JIRA = Crash.TTPID, Platform = Crash.PlatformName, FixCL = Crash.FixedChangeList, BuiltFromCL = Crash.ChangeListVersion, Pattern = Crash.Pattern, MachineID = Crash.ComputerName, Branch = Crash.Branch, Description = Crash.Description, RawCallStack = Crash.RawCallStack, }) .ToList(); int NumCrashes = Crashes.Count; /* * // Build patterns for crashes where patters is null. * var CrashesWithoutPattern = FRepository.Get().Crashes * .FilterByDate( FRepository.Get().Crashes.ListAll(), FormData.DateFrom, FormData.DateTo.AddDays( 1 ) ) * // Only crashes and asserts * .Where( Crash => Crash.Pattern == null || Crash.Pattern == "" ) * .Select( Crash => Crash ) * .ToList(); * * foreach( var Crash in CrashesWithoutPattern ) * { * Crash.BuildPattern(); * } */ // Total # of ALL (Anonymous) crashes in timeframe int TotalAnonymousCrashes = NumCrashes; // Total # of UNIQUE (Anonymous) crashes in timeframe HashSet <string> UniquePatterns = new HashSet <string>(); HashSet <string> UniqueMachines = new HashSet <string>(); Dictionary <string, int> PatternToCount = new Dictionary <string, int>(); //List<int> CrashesWithoutPattern = new List<int>(); //List<DateTime> CrashesWithoutPatternDT = new List<DateTime>(); foreach (var Crash in Crashes) { if (string.IsNullOrEmpty(Crash.Pattern)) { //CrashesWithoutPattern.Add( Crash.ID ); //CrashesWithoutPatternDT.Add( Crash.TimeOfCrash ); continue; } UniquePatterns.Add(Crash.Pattern); UniqueMachines.Add(Crash.MachineID); bool bAdd = !PatternToCount.ContainsKey(Crash.Pattern); if (bAdd) { PatternToCount.Add(Crash.Pattern, 1); } else { PatternToCount[Crash.Pattern]++; } } var PatternToCountOrdered = PatternToCount.OrderByDescending(X => X.Value).ToList(); // The 100 top. var PatternAndCount = PatternToCountOrdered.Take(100).ToDictionary(X => X.Key, Y => Y.Value); int TotalUniqueAnonymousCrashes = UniquePatterns.Count; // Total # of AFFECTED USERS (Anonymous) in timeframe int TotalAffectedUsers = UniqueMachines.Count; var RealBuggs = BuggsRepo.Context.Buggs.Where(Bugg => PatternAndCount.Keys.Contains(Bugg.Pattern)).ToList(); // Build search string. HashSet <string> FoundJiras = new HashSet <string>(); Dictionary <string, List <Bugg> > JiraIDtoBugg = new Dictionary <string, List <Bugg> >(); List <Bugg> Buggs = new List <Bugg>(100); foreach (var Top in PatternAndCount) { Bugg NewBugg = RealBuggs.Where(X => X.Pattern == Top.Key).FirstOrDefault(); if (NewBugg != null) { using (FAutoScopedLogTimer TopTimer = new FAutoScopedLogTimer(string.Format("{0}:{1}", Buggs.Count + 1, NewBugg.Id))) { var CrashesForBugg = Crashes.Where(Crash => Crash.Pattern == Top.Key).ToList(); // Convert anonymous to full type; var FullCrashesForBugg = new List <Crash>(CrashesForBugg.Count); foreach (var Anon in CrashesForBugg) { FullCrashesForBugg.Add(new Crash() { ID = Anon.ID, TimeOfCrash = Anon.TimeOfCrash, BuildVersion = Anon.BuildVersion, JIRA = Anon.JIRA, Platform = Anon.Platform, FixCL = Anon.FixCL, BuiltFromCL = Anon.BuiltFromCL, Pattern = Anon.Pattern, MachineID = Anon.MachineID, Branch = Anon.Branch, Description = Anon.Description, RawCallStack = Anon.RawCallStack, }); } NewBugg.PrepareBuggForJira(FullCrashesForBugg); // Verify valid JiraID, this may be still a TTP if (!string.IsNullOrEmpty(NewBugg.TTPID)) { int TTPID = 0; int.TryParse(NewBugg.TTPID, out TTPID); if (TTPID == 0) { AddBuggJiraMapping(NewBugg, ref FoundJiras, ref JiraIDtoBugg); } } Buggs.Add(NewBugg); } } else { FLogger.Global.WriteEvent("Bugg for pattern " + Top.Key + " not found"); } } if (BuggIDToBeAddedToJira > 0) { var Bugg = Buggs.Where(X => X.Id == BuggIDToBeAddedToJira).FirstOrDefault(); if (Bugg != null) { Bugg.CopyToJira(); AddBuggJiraMapping(Bugg, ref FoundJiras, ref JiraIDtoBugg); } } if (JC.CanBeUsed()) { var BuggsCopy = new List <Bugg>(Buggs); // Grab the data form JIRA. string JiraSearchQuery = string.Join(" OR ", FoundJiras); using (FAutoScopedLogTimer JiraResultsTimer = new FAutoScopedLogTimer("JiraResults")) { var JiraResults = JC.SearchJiraTickets( JiraSearchQuery, new string[] { "key", // string "summary", // string "components", // System.Collections.ArrayList, Dictionary<string,object>, name "resolution", // System.Collections.Generic.Dictionary`2[System.String,System.Object], name "fixVersions", // System.Collections.ArrayList, Dictionary<string,object>, name "customfield_11200" // string }); // Jira Key, Summary, Components, Resolution, Fix version, Fix changelist foreach (var Jira in JiraResults) { string JiraID = Jira.Key; string Summary = (string)Jira.Value["summary"]; string ComponentsText = ""; System.Collections.ArrayList Components = (System.Collections.ArrayList)Jira.Value["components"]; foreach (Dictionary <string, object> Component in Components) { ComponentsText += (string)Component["name"]; ComponentsText += " "; } Dictionary <string, object> ResolutionFields = (Dictionary <string, object>)Jira.Value["resolution"]; string Resolution = ResolutionFields != null ? (string)ResolutionFields["name"] : ""; string FixVersionsText = ""; System.Collections.ArrayList FixVersions = (System.Collections.ArrayList)Jira.Value["fixVersions"]; foreach (Dictionary <string, object> FixVersion in FixVersions) { FixVersionsText += (string)FixVersion["name"]; FixVersionsText += " "; } int FixCL = Jira.Value["customfield_11200"] != null ? (int)(decimal)Jira.Value["customfield_11200"] : 0; List <Bugg> BuggsForJira; JiraIDtoBugg.TryGetValue(JiraID, out BuggsForJira); //var BuggsForJira = JiraIDtoBugg[JiraID]; if (BuggsForJira != null) { foreach (Bugg Bugg in BuggsForJira) { Bugg.JiraSummary = Summary; Bugg.JiraComponentsText = ComponentsText; Bugg.JiraResolution = Resolution; Bugg.JiraFixVersionsText = FixVersionsText; if (FixCL != 0) { Bugg.JiraFixCL = FixCL.ToString(); } BuggsCopy.Remove(Bugg); } } } } // If there are buggs, we need to update the summary to indicate an error. // Usually caused when bugg's project has changed. foreach (var Bugg in BuggsCopy.Where(b => !string.IsNullOrEmpty(b.TTPID))) { Bugg.JiraSummary = "JIRA MISMATCH"; Bugg.JiraComponentsText = "JIRA MISMATCH"; Bugg.JiraResolution = "JIRA MISMATCH"; Bugg.JiraFixVersionsText = "JIRA MISMATCH"; Bugg.JiraFixCL = "JIRA MISMATCH"; } } Buggs = Buggs.OrderByDescending(b => b.NumberOfCrashes).ToList(); return(new ReportsViewModel { Buggs = Buggs, /*Crashes = Crashes,*/ DateFrom = (long)(FormData.DateFrom - CrashesViewModel.Epoch).TotalMilliseconds, DateTo = (long)(FormData.DateTo - CrashesViewModel.Epoch).TotalMilliseconds, TotalAffectedUsers = TotalAffectedUsers, TotalAnonymousCrashes = TotalAnonymousCrashes, TotalUniqueAnonymousCrashes = TotalUniqueAnonymousCrashes }); } }
/// <summary> /// Retrieve all Buggs matching the search criteria. /// </summary> /// <returns></returns> private ReportsViewModel GetResults(string branchName, DateTime startDate, DateTime endDate, int BuggIDToBeAddedToJira) { // It would be great to have a CSV export of this as well with buggs ID being the key I can then use to join them :) // // Enumerate JIRA projects if needed. // https://jira.ol.epicgames.net//rest/api/2/project var JC = JiraConnection.Get(); var JiraComponents = JC.GetNameToComponents(); var JiraVersions = JC.GetNameToVersions(); using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString())) { string AnonumousGroup = "Anonymous"; //List<String> Users = FRepository.Get().GetUserNamesFromGroupName( AnonumousGroup ); int AnonymousGroupID = _unitOfWork.UserGroupRepository.First(data => data.Name == "Anonymous").Id; List <int> AnonumousIDs = _unitOfWork.UserGroupRepository.First(data => data.Name == "Anonymous").Users.Select(data => data.Id).ToList(); int AnonymousID = AnonumousIDs.First(); var CrashesQuery = _unitOfWork.CrashRepository.ListAll().Where(data => data.TimeOfCrash > startDate && data.TimeOfCrash <= endDate) // Only crashes and asserts .Where(Crash => Crash.CrashType == 1 || Crash.CrashType == 2) // Only anonymous user .Where(Crash => Crash.UserNameId.Value == AnonymousID); // Filter by BranchName if (!string.IsNullOrEmpty(branchName)) { CrashesQuery = ( from CrashDetail in CrashesQuery where CrashDetail.Branch.Equals(branchName) select CrashDetail ); } var crashes = CrashesQuery.Select(data => new { ID = data.Id, TimeOfCrash = data.TimeOfCrash.Value, //UserID = Crash.UserNameId.Value, BuildVersion = data.BuildVersion, JIRA = data.Jira, Platform = data.PlatformName, FixCL = data.FixedChangeList, BuiltFromCL = data.ChangeListVersion, Pattern = data.Pattern, MachineID = data.ComputerName, Branch = data.Branch, Description = data.Description, RawCallStack = data.RawCallStack, }).ToList(); var numCrashes = CrashesQuery.Count(); /* * // Build patterns for crashes where patters is null. * var CrashesWithoutPattern = FRepository.Get().Crashes * .FilterByDate( FRepository.Get().Crashes.ListAll(), startDate, endDate.AddDays( 1 ) ) * // Only crashes and asserts * .Where( Crash => Crash.Pattern == null || Crash.Pattern == "" ) * .Select( Crash => Crash ) * .ToList(); * * foreach( var Crash in CrashesWithoutPattern ) * { * Crash.BuildPattern(); * } */ // Total # of ALL (Anonymous) crashes in timeframe int TotalAnonymousCrashes = numCrashes; // Total # of UNIQUE (Anonymous) crashes in timeframe HashSet <string> UniquePatterns = new HashSet <string>(); HashSet <string> UniqueMachines = new HashSet <string>(); Dictionary <string, int> PatternToCount = new Dictionary <string, int>(); //List<int> CrashesWithoutPattern = new List<int>(); //List<DateTime> CrashesWithoutPatternDT = new List<DateTime>(); foreach (var Crash in crashes) { if (string.IsNullOrEmpty(Crash.Pattern)) { //CrashesWithoutPattern.Add( Crash.ID ); //CrashesWithoutPatternDT.Add( Crash.TimeOfCrash ); continue; } UniquePatterns.Add(Crash.Pattern); UniqueMachines.Add(Crash.MachineID); bool bAdd = !PatternToCount.ContainsKey(Crash.Pattern); if (bAdd) { PatternToCount.Add(Crash.Pattern, 1); } else { PatternToCount[Crash.Pattern]++; } } var PatternToCountOrdered = PatternToCount.OrderByDescending(X => X.Value).ToList(); const int NumTopRecords = 200; var PatternAndCount = PatternToCountOrdered.Take(NumTopRecords).ToDictionary(X => X.Key, Y => Y.Value); int TotalUniqueAnonymousCrashes = UniquePatterns.Count; // Total # of AFFECTED USERS (Anonymous) in timeframe int TotalAffectedUsers = UniqueMachines.Count; var RealBuggs = _unitOfWork.BuggRepository.ListAll().Where(Bugg => PatternAndCount.Keys.Contains(Bugg.Pattern)); // Build search string. HashSet <string> FoundJiras = new HashSet <string>(); Dictionary <string, List <Bugg> > JiraIDtoBugg = new Dictionary <string, List <Bugg> >(); List <Bugg> Buggs = new List <Bugg>(NumTopRecords); foreach (var Top in PatternAndCount) { Bugg NewBugg = RealBuggs.FirstOrDefault(X => X.Pattern == Top.Key); if (NewBugg != null) { using ( FAutoScopedLogTimer TopTimer = new FAutoScopedLogTimer(string.Format("{0}:{1}", Buggs.Count + 1, NewBugg.Id))) { var CrashesForBugg = crashes.Where(Crash => Crash.Pattern == Top.Key).ToList(); // Convert anonymous to full type; var FullCrashesForBugg = new List <Crash>(CrashesForBugg.Count); foreach (var Anon in CrashesForBugg) { FullCrashesForBugg.Add(new Crash() { Id = Anon.ID, TimeOfCrash = Anon.TimeOfCrash, BuildVersion = Anon.BuildVersion, Jira = Anon.JIRA, PlatformName = Anon.Platform, FixedChangeList = Anon.FixCL, ChangeListVersion = Anon.BuiltFromCL, Pattern = Anon.Pattern, ComputerName = Anon.MachineID, Branch = Anon.Branch, Description = Anon.Description, RawCallStack = Anon.RawCallStack, }); } NewBugg.PrepareBuggForJira(FullCrashesForBugg); // Verify valid JiraID, this may be still a TTP if (!string.IsNullOrEmpty(NewBugg.TTPID)) { int TTPID = 0; int.TryParse(NewBugg.TTPID, out TTPID); if (TTPID == 0) { AddBuggJiraMapping(NewBugg, ref FoundJiras, ref JiraIDtoBugg); } } Buggs.Add(NewBugg); } } else { FLogger.Global.WriteEvent("Bugg for pattern " + Top.Key + " not found"); } } if (BuggIDToBeAddedToJira > 0) { var Bugg = Buggs.Where(X => X.Id == BuggIDToBeAddedToJira).FirstOrDefault(); if (Bugg != null) { Bugg.CopyToJira(); AddBuggJiraMapping(Bugg, ref FoundJiras, ref JiraIDtoBugg); } } if (JC.CanBeUsed()) { var BuggsCopy = new List <Bugg>(Buggs); HashSet <string> InvalidJiras = new HashSet <string>(); // Simple verification of JIRA foreach (var Value in FoundJiras) { if (Value.Length < 3 || !Value.Contains('-')) { InvalidJiras.Add(Value); } } foreach (var InvalidJira in InvalidJiras) { FoundJiras.Remove(InvalidJira); } // Grab the data form JIRA. string JiraSearchQuery = string.Join(" OR ", FoundJiras); using (FAutoScopedLogTimer JiraResultsTimer = new FAutoScopedLogTimer("JiraResults")) { bool bInvalid = false; var JiraResults = new Dictionary <string, Dictionary <string, object> >(); try { if (!string.IsNullOrWhiteSpace(JiraSearchQuery)) { JiraResults = JC.SearchJiraTickets( JiraSearchQuery, new string[] { "key", // string "summary", // string "components", // System.Collections.ArrayList, Dictionary<string,object>, name "resolution", // System.Collections.Generic.Dictionary`2[System.String,System.Object], name "fixVersions", // System.Collections.ArrayList, Dictionary<string,object>, name "customfield_11200" // string }); } } catch (System.Exception) { bInvalid = true; } // Invalid records have been found, find the broken using the slow path. if (bInvalid) { foreach (var Query in FoundJiras) { try { var TempResult = JC.SearchJiraTickets( Query, new string[] { "key", // string "summary", // string "components", // System.Collections.ArrayList, Dictionary<string,object>, name "resolution", // System.Collections.Generic.Dictionary`2[System.String,System.Object], name "fixVersions", // System.Collections.ArrayList, Dictionary<string,object>, name "customfield_11200" // string }); foreach (var Temp in TempResult) { JiraResults.Add(Temp.Key, Temp.Value); } } catch (System.Exception) { } } } // Jira Key, Summary, Components, Resolution, Fix version, Fix changelist foreach (var Jira in JiraResults) { string JiraID = Jira.Key; string Summary = (string)Jira.Value["summary"]; string ComponentsText = ""; System.Collections.ArrayList Components = (System.Collections.ArrayList)Jira.Value["components"]; foreach (Dictionary <string, object> Component in Components) { ComponentsText += (string)Component["name"]; ComponentsText += " "; } Dictionary <string, object> ResolutionFields = (Dictionary <string, object>)Jira.Value["resolution"]; string Resolution = ResolutionFields != null ? (string)ResolutionFields["name"] : ""; string FixVersionsText = ""; System.Collections.ArrayList FixVersions = (System.Collections.ArrayList)Jira.Value["fixVersions"]; foreach (Dictionary <string, object> FixVersion in FixVersions) { FixVersionsText += (string)FixVersion["name"]; FixVersionsText += " "; } int FixCL = Jira.Value["customfield_11200"] != null ? (int)(decimal)Jira.Value["customfield_11200"] : 0; List <Bugg> BuggsForJira; JiraIDtoBugg.TryGetValue(JiraID, out BuggsForJira); //var BuggsForJira = JiraIDtoBugg[JiraID]; if (BuggsForJira != null) { foreach (Bugg Bugg in BuggsForJira) { Bugg.JiraSummary = Summary; Bugg.JiraComponentsText = ComponentsText; Bugg.JiraResolution = Resolution; Bugg.JiraFixVersionsText = FixVersionsText; if (FixCL != 0) { Bugg.JiraFixCL = FixCL.ToString(); } BuggsCopy.Remove(Bugg); } } } } // If there are buggs, we need to update the summary to indicate an error. // Usually caused when bugg's project has changed. foreach (var Bugg in BuggsCopy.Where(b => !string.IsNullOrEmpty(b.TTPID))) { Bugg.JiraSummary = "JIRA MISMATCH"; Bugg.JiraComponentsText = "JIRA MISMATCH"; Bugg.JiraResolution = "JIRA MISMATCH"; Bugg.JiraFixVersionsText = "JIRA MISMATCH"; Bugg.JiraFixCL = "JIRA MISMATCH"; } } Buggs = Buggs.OrderByDescending(b => b.CrashesInTimeFrameGroup).ToList(); return(new ReportsViewModel { Buggs = Buggs, BranchName = branchName, BranchNames = _unitOfWork.CrashRepository.GetBranchesAsListItems(), DateFrom = (long)(startDate - CrashesViewModel.Epoch).TotalMilliseconds, DateTo = (long)(endDate - CrashesViewModel.Epoch).TotalMilliseconds, TotalAffectedUsers = TotalAffectedUsers, TotalAnonymousCrashes = TotalAnonymousCrashes, TotalUniqueAnonymousCrashes = TotalUniqueAnonymousCrashes }); } }
/// <summary> /// Retrieve all Buggs matching the search criteria. /// </summary> /// <param name="FormData">The incoming form of search criteria from the client.</param> /// <param name="BuggIDToBeAddedToJira">ID of the bugg that will be added to JIRA</param> /// <returns>A view to display the filtered Buggs.</returns> public ReportsViewModel GetResults(FormHelper FormData, int BuggIDToBeAddedToJira) { // @TODO yrx 2015-02-17 BuggIDToBeAddedToJira replace with List<int> based on check box and Submit? // Enumerate JIRA projects if needed. // https://jira.ol.epicgames.net//rest/api/2/project var JC = JiraConnection.Get(); var JiraComponents = JC.GetNameToComponents(); var JiraVersions = JC.GetNameToVersions(); using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString())) { string AnonumousGroup = "Anonymous"; List <String> Users = CrashRepository.GetUsersForGroup(AnonumousGroup); int AnonymousGroupID = BuggRepository.GetIdFromUserGroup(AnonumousGroup); HashSet <int> AnonumousIDs = BuggRepository.GetUserIdsFromUserGroup(AnonumousGroup); int AnonymousID = AnonumousIDs.First(); HashSet <string> UserNamesForUserGroup = BuggRepository.GetUserNamesFromUserGroups(AnonumousGroup); //FormData.DateFrom = DateTime.Now.AddDays( -1 ); var Crashes = CrashRepository .FilterByDate(CrashRepository.ListAll(), FormData.DateFrom, FormData.DateTo.AddDays(1)) // Only crashes and asserts .Where(Crash => Crash.CrashType == 1 || Crash.CrashType == 2) // Only anonymous user .Where(Crash => Crash.UserNameId.Value == AnonymousID) .Select(Crash => new { ID = Crash.Id, TimeOfCrash = Crash.TimeOfCrash.Value, //UserID = Crash.UserNameId.Value, BuildVersion = Crash.BuildVersion, JIRA = Crash.TTPID, Platform = Crash.PlatformName, FixCL = Crash.FixedChangeList, BuiltFromCL = Crash.ChangeListVersion, Pattern = Crash.Pattern, MachineID = Crash.ComputerName, Branch = Crash.Branch, }) .ToList(); int NumCrashes = Crashes.Count; /* * // Build patterns for crashes where patters is null. * var CrashesWithoutPattern = CrashRepository * .FilterByDate( CrashRepository.ListAll(), FormData.DateFrom, FormData.DateTo.AddDays( 1 ) ) * // Only crashes and asserts * .Where( Crash => Crash.Pattern == null || Crash.Pattern == "" ) * .Select( Crash => Crash ) * .ToList(); * * foreach( var Crash in CrashesWithoutPattern ) * { * ////BuildPattern( Crash ); * } */ // Total # of ALL (Anonymous) crashes in timeframe int TotalAnonymousCrashes = NumCrashes; // Total # of UNIQUE (Anonymous) crashes in timeframe HashSet <string> UniquePatterns = new HashSet <string>(); HashSet <string> UniqueMachines = new HashSet <string>(); Dictionary <string, int> PatternToCount = new Dictionary <string, int>(); //List<int> CrashesWithoutPattern = new List<int>(); //List<DateTime> CrashesWithoutPatternDT = new List<DateTime>(); foreach (var Crash in Crashes) { if (string.IsNullOrEmpty(Crash.Pattern)) { //CrashesWithoutPattern.Add( Crash.ID ); //CrashesWithoutPatternDT.Add( Crash.TimeOfCrash ); continue; } UniquePatterns.Add(Crash.Pattern); UniqueMachines.Add(Crash.MachineID); bool bAdd = !PatternToCount.ContainsKey(Crash.Pattern); if (bAdd) { PatternToCount.Add(Crash.Pattern, 1); } else { PatternToCount[Crash.Pattern]++; } } var PatternToCountOrdered = PatternToCount.OrderByDescending(X => X.Value).ToList(); // The 100 top. var PatternAndCount = PatternToCountOrdered.Take(100).ToDictionary(X => X.Key, Y => Y.Value); int TotalUniqueAnonymousCrashes = UniquePatterns.Count; // Total # of AFFECTED USERS (Anonymous) in timeframe int TotalAffectedUsers = UniqueMachines.Count; var RealBuggs = BuggRepository.GetDataContext().Buggs.Where(Bugg => PatternAndCount.Keys.Contains(Bugg.Pattern)).ToList(); // Build search string. List <string> FoundJiras = new List <string>(); Dictionary <string, List <Bugg> > JiraIDtoBugg = new Dictionary <string, List <Bugg> >(); List <Bugg> Buggs = new List <Bugg>(100); foreach (var Top in PatternAndCount) { Bugg NewBugg = new Bugg(); Bugg RealBugg = RealBuggs.Where(X => X.Pattern == Top.Key).FirstOrDefault(); if (RealBugg != null) { using (FAutoScopedLogTimer TopTimer = new FAutoScopedLogTimer(string.Format("{0}:{1}", Buggs.Count + 1, RealBugg.Id))) { // Index // number NewBugg.Id = RealBugg.Id; // CrashGroup URL (a link to the Bugg) NewBugg.TTPID = RealBugg.TTPID; // JIRA NewBugg.FixedChangeList = RealBugg.FixedChangeList; // FixCL NewBugg.NumberOfCrashes = Top.Value; // # Occurrences NewBugg.Pattern = RealBugg.Pattern; // # Occurrences //NewBugg.BuildVersion = var CrashesForBugg = Crashes.Where(Crash => Crash.Pattern == Top.Key).ToList(); NewBugg.AffectedVersions = new SortedSet <string>(); NewBugg.AffectedMajorVersions = new SortedSet <string>(); // 4.4, 4.5 and so NewBugg.BranchesFoundIn = new SortedSet <string>(); NewBugg.AffectedPlatforms = new SortedSet <string>(); HashSet <string> MachineIds = new HashSet <string>(); int FirstCLAffected = int.MaxValue; foreach (var Crash in CrashesForBugg) { // Only add machine if the number has 32 characters if (Crash.MachineID != null && Crash.MachineID.Length == 32) { MachineIds.Add(Crash.MachineID); } // Ignore bad build versions. // @TODO yrx 2015-02-17 What about launcher? if (Crash.BuildVersion.StartsWith("4.")) { if (!string.IsNullOrEmpty(Crash.BuildVersion)) { NewBugg.AffectedVersions.Add(Crash.BuildVersion); } if (!string.IsNullOrEmpty(Crash.Branch) && Crash.Branch.StartsWith("UE4")) { NewBugg.BranchesFoundIn.Add(Crash.Branch); } int CrashBuiltFromCL = 0; int.TryParse(Crash.BuiltFromCL, out CrashBuiltFromCL); if (CrashBuiltFromCL > 0) { FirstCLAffected = Math.Min(FirstCLAffected, CrashBuiltFromCL); } if (!string.IsNullOrEmpty(Crash.Platform)) { // Platform = "Platform [Desc]"; var PlatSubs = Crash.Platform.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); if (PlatSubs.Length >= 1) { NewBugg.AffectedPlatforms.Add(PlatSubs[0]); } } } } // CopyToJira NewBugg.ToJiraFirstCLAffected = FirstCLAffected; if (NewBugg.AffectedVersions.Count > 0) { NewBugg.BuildVersion = NewBugg.AffectedVersions.Last(); // Latest Version Affected } foreach (var AffectedBuild in NewBugg.AffectedVersions) { var Subs = AffectedBuild.Split(".".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); if (Subs.Length >= 2) { string MajorVersion = Subs[0] + "." + Subs[1]; NewBugg.AffectedMajorVersions.Add(MajorVersion); } } NewBugg.NumberOfUniqueMachines = MachineIds.Count; // # Affected Users string LatestCLAffected = CrashesForBugg. // CL of the latest build Where(Crash => Crash.BuildVersion == NewBugg.BuildVersion). Max(Crash => Crash.BuiltFromCL); int ILatestCLAffected = -1; int.TryParse(LatestCLAffected, out ILatestCLAffected); NewBugg.LatestCLAffected = ILatestCLAffected; // Latest CL Affected string LatestOSAffected = CrashesForBugg.OrderByDescending(Crash => Crash.TimeOfCrash).First().Platform; NewBugg.LatestOSAffected = LatestOSAffected; // Latest Environment Affected NewBugg.TimeOfFirstCrash = RealBugg.TimeOfFirstCrash; // First Crash Timestamp // ToJiraSummary var Callstack = RealBugg.GetFunctionCalls(); NewBugg.ToJiraSummary = Callstack.Count > 1 ? Callstack[0] : "No valid callstack found"; // ToJiraVersions NewBugg.ToJiraVersions = new List <object>(); foreach (var Version in NewBugg.AffectedMajorVersions) { bool bValid = JC.GetNameToVersions().ContainsKey(Version); if (bValid) { NewBugg.ToJiraVersions.Add(JC.GetNameToVersions()[Version]); } } // ToJiraBranches NewBugg.ToJiraBranches = new List <object>(); foreach (var Platform in NewBugg.BranchesFoundIn) { string CleanedBranch = Platform.Contains("UE4-Releases") ? "UE4-Releases" : Platform; Dictionary <string, object> JiraBranch = null; JC.GetNameToBranchFoundIn().TryGetValue(CleanedBranch, out JiraBranch); if (JiraBranch != null && !NewBugg.ToJiraBranches.Contains(JiraBranch)) { NewBugg.ToJiraBranches.Add(JiraBranch); } } // ToJiraPlatforms NewBugg.ToJiraPlatforms = new List <object>(); foreach (var Platform in NewBugg.AffectedPlatforms) { bool bValid = JC.GetNameToPlatform().ContainsKey(Platform); if (bValid) { NewBugg.ToJiraPlatforms.Add(JC.GetNameToPlatform()[Platform]); } } // Verify valid JiraID, this may be still a TTP if (!string.IsNullOrEmpty(NewBugg.TTPID)) { int TTPID = 0; int.TryParse(NewBugg.TTPID, out TTPID); if (TTPID == 0) { AddBuggJiraMapping(NewBugg, ref FoundJiras, ref JiraIDtoBugg); } } Buggs.Add(NewBugg); } } else { FLogger.WriteEvent("Bugg for pattern " + Top.Key + " not found"); } } if (BuggIDToBeAddedToJira > 0) { var Bugg = Buggs.Where(X => X.Id == BuggIDToBeAddedToJira).FirstOrDefault(); if (Bugg != null) { Bugg.CopyToJira(); AddBuggJiraMapping(Bugg, ref FoundJiras, ref JiraIDtoBugg); } } if (JC.CanBeUsed()) { // Grab the data form JIRA. string JiraSearchQuery = string.Join(" OR ", FoundJiras); using (FAutoScopedLogTimer JiraResultsTimer = new FAutoScopedLogTimer("JiraResults")) { var JiraResults = JC.SearchJiraTickets( JiraSearchQuery, new string[] { "key", // string "summary", // string "components", // System.Collections.ArrayList, Dictionary<string,object>, name "resolution", // System.Collections.Generic.Dictionary`2[System.String,System.Object], name "fixVersions", // System.Collections.ArrayList, Dictionary<string,object>, name "customfield_11200" // string }); // Jira Key, Summary, Components, Resolution, Fix version, Fix changelist foreach (var Jira in JiraResults) { string JiraID = Jira.Key; string Summary = (string)Jira.Value["summary"]; string ComponentsText = ""; System.Collections.ArrayList Components = (System.Collections.ArrayList)Jira.Value["components"]; foreach (Dictionary <string, object> Component in Components) { ComponentsText += (string)Component["name"]; ComponentsText += " "; } Dictionary <string, object> ResolutionFields = (Dictionary <string, object>)Jira.Value["resolution"]; string Resolution = ResolutionFields != null ? (string)ResolutionFields["name"] : ""; string FixVersionsText = ""; System.Collections.ArrayList FixVersions = (System.Collections.ArrayList)Jira.Value["fixVersions"]; foreach (Dictionary <string, object> FixVersion in FixVersions) { FixVersionsText += (string)FixVersion["name"]; FixVersionsText += " "; } int FixCL = Jira.Value["customfield_11200"] != null ? (int)(decimal)Jira.Value["customfield_11200"] : 0; var BuggsForJira = JiraIDtoBugg[JiraID]; foreach (Bugg Bugg in BuggsForJira) { Bugg.JiraSummary = Summary; Bugg.JiraComponentsText = ComponentsText; Bugg.JiraResolution = Resolution; Bugg.JiraFixVersionsText = FixVersionsText; if (FixCL != 0) { Bugg.JiraFixCL = FixCL.ToString(); } } } } } return(new ReportsViewModel { Buggs = Buggs, /*Crashes = Crashes,*/ DateFrom = (long)(FormData.DateFrom - CrashesViewModel.Epoch).TotalMilliseconds, DateTo = (long)(FormData.DateTo - CrashesViewModel.Epoch).TotalMilliseconds, TotalAffectedUsers = TotalAffectedUsers, TotalAnonymousCrashes = TotalAnonymousCrashes, TotalUniqueAnonymousCrashes = TotalUniqueAnonymousCrashes }); } }
/// <summary> /// Update an existing Bugg /// </summary> /// <param name="entity"></param> public void Update(Bugg entity) { var set = _entityContext.Set<Bugg>(); var entry = set.Local.SingleOrDefault(f => f.Id == entity.Id); if (entry != null) { var attachedFeature = _entityContext.Entry(entry); attachedFeature.CurrentValues.SetValues(entity); attachedFeature.State = EntityState.Modified; } else { _entityContext.Buggs.Attach(entity); _entityContext.Entry(entity).State = EntityState.Modified; } }
private void OnBuggsRemove( Bugg BuggInstance ) { var BuggCrash = Buggs_Crashes.FirstOrDefault( c => c.CrashId == Id && c.BuggId == BuggInstance.Id ); Buggs_Crashes.Remove( BuggCrash ); SendPropertyChanged( null ); }
private void OnBuggsAdd( Bugg BuggInstance ) { Buggs_Crashes.Add( new Buggs_Crash { Crash = this, Bugg = BuggInstance } ); SendPropertyChanged( null ); }
private void AddBuggJiraMapping(Bugg NewBugg, ref HashSet<string> FoundJiras, ref Dictionary<string, List<Bugg>> JiraIDtoBugg) { string JiraID = NewBugg.TTPID; FoundJiras.Add("key = " + JiraID); bool bAdd = !JiraIDtoBugg.ContainsKey(JiraID); if (bAdd) { JiraIDtoBugg.Add(JiraID, new List<Bugg>()); } JiraIDtoBugg[JiraID].Add(NewBugg); }
/// <summary> /// The Show action. /// </summary> /// <param name="BuggsForm">The form of user data passed up from the client.</param> /// <param name="id">The unique id of the Bugg.</param> /// <returns>The view to display a Bugg on the client.</returns> public ActionResult Show(FormCollection BuggsForm, int id) { // Set the display properties based on the radio buttons bool DisplayModuleNames = false; if (BuggsForm["DisplayModuleNames"] == "true") { DisplayModuleNames = true; } bool DisplayFunctionNames = false; if (BuggsForm["DisplayFunctionNames"] == "true") { DisplayFunctionNames = true; } bool DisplayFileNames = false; if (BuggsForm["DisplayFileNames"] == "true") { DisplayFileNames = true; } bool DisplayFilePathNames = false; if (BuggsForm["DisplayFilePathNames"] == "true") { DisplayFilePathNames = true; DisplayFileNames = false; } bool DisplayUnformattedCallStack = false; if (BuggsForm["DisplayUnformattedCallStack"] == "true") { DisplayUnformattedCallStack = true; } // Create a new view and populate with crashes List <Crash> Crashes = null; Bugg Bugg = new Bugg(); BuggViewModel Model = new BuggViewModel(); Bugg = LocalBuggRepository.GetBugg(id); if (Bugg == null) { return(RedirectToAction("")); } Crashes = Bugg.GetCrashes().ToList(); // Apply any user settings if (BuggsForm.Count > 0) { if (!string.IsNullOrEmpty(BuggsForm["SetStatus"])) { Bugg.Status = BuggsForm["SetStatus"]; LocalCrashRepository.SetBuggStatus(Bugg.Status, id); } if (!string.IsNullOrEmpty(BuggsForm["SetFixedIn"])) { Bugg.FixedChangeList = BuggsForm["SetFixedIn"]; LocalCrashRepository.SetBuggFixedChangeList(Bugg.FixedChangeList, id); } if (!string.IsNullOrEmpty(BuggsForm["SetTTP"])) { Bugg.TTPID = BuggsForm["SetTTP"]; LocalCrashRepository.SetBuggTTPID(Bugg.TTPID, id); } if (!string.IsNullOrEmpty(BuggsForm["Description"])) { Bugg.Description = BuggsForm["Description"]; } // <STATUS> } // Set up the view model with the crash data Model.Bugg = Bugg; Model.Crashes = Crashes; Crash NewCrash = Model.Crashes.FirstOrDefault(); if (NewCrash != null) { CallStackContainer CallStack = new CallStackContainer(NewCrash); // Set callstack properties CallStack.bDisplayModuleNames = DisplayModuleNames; CallStack.bDisplayFunctionNames = DisplayFunctionNames; CallStack.bDisplayFileNames = DisplayFileNames; CallStack.bDisplayFilePathNames = DisplayFilePathNames; CallStack.bDisplayUnformattedCallStack = DisplayUnformattedCallStack; Model.CallStack = CallStack; NewCrash.CallStackContainer = NewCrash.GetCallStack(); } // Add in the users for each crash in the Bugg foreach (Crash CrashInstance in Model.Crashes) { LocalCrashRepository.PopulateUserInfo(CrashInstance); } return(View("Show", Model)); }
/// <summary> /// The Show action. /// </summary> /// <param name="BuggsForm">The form of user data passed up from the client.</param> /// <param name="id">The unique id of the Bugg.</param> /// <returns>The view to display a Bugg on the client.</returns> public ActionResult Show(FormCollection BuggsForm, int id) { using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(BuggId=" + id + ")", bCreateNewLog: true)) { // Handle 'CopyToJira' button int BuggIDToBeAddedToJira = 0; foreach (var Entry in BuggsForm) { if (Entry.ToString().Contains(Bugg.JiraSubmitName)) { int.TryParse(Entry.ToString().Substring(Bugg.JiraSubmitName.Length), out BuggIDToBeAddedToJira); break; } } BuggRepository Buggs = new BuggRepository(); // Set the display properties based on the radio buttons bool DisplayModuleNames = false; if (BuggsForm["DisplayModuleNames"] == "true") { DisplayModuleNames = true; } bool DisplayFunctionNames = false; if (BuggsForm["DisplayFunctionNames"] == "true") { DisplayFunctionNames = true; } bool DisplayFileNames = false; if (BuggsForm["DisplayFileNames"] == "true") { DisplayFileNames = true; } bool DisplayFilePathNames = false; if (BuggsForm["DisplayFilePathNames"] == "true") { DisplayFilePathNames = true; DisplayFileNames = false; } bool DisplayUnformattedCallStack = false; if (BuggsForm["DisplayUnformattedCallStack"] == "true") { DisplayUnformattedCallStack = true; } // Create a new view and populate with crashes List <Crash> Crashes = null; BuggViewModel Model = new BuggViewModel(); Bugg NewBugg = Buggs.GetBugg(id); if (NewBugg == null) { return(RedirectToAction("")); } Crashes = NewBugg.GetCrashes(); using (FAutoScopedLogTimer GetCrashesTimer = new FAutoScopedLogTimer("Bugg.PrepareBuggForJira")) { if (Crashes.Count > 0) { NewBugg.PrepareBuggForJira(Crashes); if (BuggIDToBeAddedToJira != 0) { NewBugg.CopyToJira(); } } } using (FAutoScopedLogTimer JiraResultsTimer = new FAutoScopedLogTimer("Bugg.GrabJira")) { var JC = JiraConnection.Get(); bool bValidJira = false; // Verify valid JiraID, this may be still a TTP if (!string.IsNullOrEmpty(NewBugg.Jira)) { int TTPID = 0; int.TryParse(NewBugg.Jira, out TTPID); if (TTPID == 0) { //AddBuggJiraMapping( NewBugg, ref FoundJiras, ref JiraIDtoBugg ); bValidJira = true; } } if (JC.CanBeUsed() && bValidJira) { // Grab the data form JIRA. string JiraSearchQuery = "key = " + NewBugg.Jira; var JiraResults = JC.SearchJiraTickets( JiraSearchQuery, new string[] { "key", // string "summary", // string "components", // System.Collections.ArrayList, Dictionary<string,object>, name "resolution", // System.Collections.Generic.Dictionary`2[System.String,System.Object], name "fixVersions", // System.Collections.ArrayList, Dictionary<string,object>, name "customfield_11200" // string }); // Jira Key, Summary, Components, Resolution, Fix version, Fix changelist foreach (var Jira in JiraResults) { string JiraID = Jira.Key; string Summary = (string)Jira.Value["summary"]; string ComponentsText = ""; System.Collections.ArrayList Components = (System.Collections.ArrayList)Jira.Value["components"]; foreach (Dictionary <string, object> Component in Components) { ComponentsText += (string)Component["name"]; ComponentsText += " "; } Dictionary <string, object> ResolutionFields = (Dictionary <string, object>)Jira.Value["resolution"]; string Resolution = ResolutionFields != null ? (string)ResolutionFields["name"] : ""; string FixVersionsText = ""; System.Collections.ArrayList FixVersions = (System.Collections.ArrayList)Jira.Value["fixVersions"]; foreach (Dictionary <string, object> FixVersion in FixVersions) { FixVersionsText += (string)FixVersion["name"]; FixVersionsText += " "; } int FixCL = Jira.Value["customfield_11200"] != null ? (int)(decimal)Jira.Value["customfield_11200"] : 0; NewBugg.JiraSummary = Summary; NewBugg.JiraComponentsText = ComponentsText; NewBugg.JiraResolution = Resolution; NewBugg.JiraFixVersionsText = FixVersionsText; if (FixCL != 0) { NewBugg.JiraFixCL = FixCL.ToString(); } break; } } } // Apply any user settings if (BuggsForm.Count > 0) { if (!string.IsNullOrEmpty(BuggsForm["SetStatus"])) { NewBugg.Status = BuggsForm["SetStatus"]; Buggs.SetBuggStatus(NewBugg.Status, id); } if (!string.IsNullOrEmpty(BuggsForm["SetFixedIn"])) { NewBugg.FixedChangeList = BuggsForm["SetFixedIn"]; Buggs.SetBuggFixedChangeList(NewBugg.FixedChangeList, id); } if (!string.IsNullOrEmpty(BuggsForm["SetTTP"])) { NewBugg.Jira = BuggsForm["SetTTP"]; Buggs.SetJIRAForBuggAndCrashes(NewBugg.Jira, id); } // <STATUS> } // Set up the view model with the crash data Model.Bugg = NewBugg; Model.Crashes = Crashes; Crash NewCrash = Model.Crashes.FirstOrDefault(); if (NewCrash != null) { using (FScopedLogTimer LogTimer2 = new FScopedLogTimer("CallstackTrimming")) { CallStackContainer CallStack = new CallStackContainer(NewCrash); // Set callstack properties CallStack.bDisplayModuleNames = DisplayModuleNames; CallStack.bDisplayFunctionNames = DisplayFunctionNames; CallStack.bDisplayFileNames = DisplayFileNames; CallStack.bDisplayFilePathNames = DisplayFilePathNames; CallStack.bDisplayUnformattedCallStack = DisplayUnformattedCallStack; Model.CallStack = CallStack; // Shorten very long function names. foreach (CallStackEntry Entry in Model.CallStack.CallStackEntries) { Entry.FunctionName = Entry.GetTrimmedFunctionName(128); } Model.SourceContext = NewCrash.SourceContext; } Model.Bugg.LatestCrashSummary = NewCrash.Summary; } Model.GenerationTime = LogTimer.GetElapsedSeconds().ToString("F2"); return(View("Show", Model)); } }
/// <summary> /// The Show action. /// </summary> /// <param name="BuggsForm">The form of user data passed up from the client.</param> /// <param name="id">The unique id of the Bugg.</param> /// <returns>The view to display a Bugg on the client.</returns> public ActionResult Show(FormCollection BuggsForm, int id) { using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(BuggId=" + id + ")")) { // Set the display properties based on the radio buttons bool DisplayModuleNames = false; if (BuggsForm["DisplayModuleNames"] == "true") { DisplayModuleNames = true; } bool DisplayFunctionNames = false; if (BuggsForm["DisplayFunctionNames"] == "true") { DisplayFunctionNames = true; } bool DisplayFileNames = false; if (BuggsForm["DisplayFileNames"] == "true") { DisplayFileNames = true; } bool DisplayFilePathNames = false; if (BuggsForm["DisplayFilePathNames"] == "true") { DisplayFilePathNames = true; DisplayFileNames = false; } bool DisplayUnformattedCallStack = false; if (BuggsForm["DisplayUnformattedCallStack"] == "true") { DisplayUnformattedCallStack = true; } // Create a new view and populate with crashes List <Crash> Crashes = null; Bugg Bugg = new Bugg(); BuggViewModel Model = new BuggViewModel(); Bugg = LocalBuggRepository.GetBugg(id); if (Bugg == null) { return(RedirectToAction("")); } // @TODO yrx 2015-02-17 JIRA using (FAutoScopedLogTimer GetCrashesTimer = new FAutoScopedLogTimer("Bugg.GetCrashes().ToList")) { Crashes = Bugg.GetCrashes(); Bugg.AffectedVersions = new SortedSet <string>(); HashSet <string> MachineIds = new HashSet <string>(); foreach (Crash Crash in Crashes) { MachineIds.Add(Crash.ComputerName); // Ignore bad build versions. if (Crash.BuildVersion.StartsWith("4.")) { Bugg.AffectedVersions.Add(Crash.BuildVersion); } if (Crash.User == null) { //?? } } Bugg.NumberOfUniqueMachines = MachineIds.Count; } // Apply any user settings if (BuggsForm.Count > 0) { if (!string.IsNullOrEmpty(BuggsForm["SetStatus"])) { Bugg.Status = BuggsForm["SetStatus"]; LocalCrashRepository.SetBuggStatus(Bugg.Status, id); } if (!string.IsNullOrEmpty(BuggsForm["SetFixedIn"])) { Bugg.FixedChangeList = BuggsForm["SetFixedIn"]; LocalCrashRepository.SetBuggFixedChangeList(Bugg.FixedChangeList, id); } if (!string.IsNullOrEmpty(BuggsForm["SetTTP"])) { Bugg.TTPID = BuggsForm["SetTTP"]; BuggRepository.SetJIRAForBuggAndCrashes(Bugg.TTPID, id); } if (!string.IsNullOrEmpty(BuggsForm["Description"])) { Bugg.Description = BuggsForm["Description"]; } // <STATUS> } // Set up the view model with the crash data Model.Bugg = Bugg; Model.Crashes = Crashes; Crash NewCrash = Model.Crashes.FirstOrDefault(); if (NewCrash != null) { using (FScopedLogTimer LogTimer2 = new FScopedLogTimer("CallstackTrimming")) { CallStackContainer CallStack = new CallStackContainer(NewCrash); // Set callstack properties CallStack.bDisplayModuleNames = DisplayModuleNames; CallStack.bDisplayFunctionNames = DisplayFunctionNames; CallStack.bDisplayFileNames = DisplayFileNames; CallStack.bDisplayFilePathNames = DisplayFilePathNames; CallStack.bDisplayUnformattedCallStack = DisplayUnformattedCallStack; Model.CallStack = CallStack; // Shorten very long function names. foreach (CallStackEntry Entry in Model.CallStack.CallStackEntries) { Entry.FunctionName = Entry.GetTrimmedFunctionName(128); } Model.SourceContext = NewCrash.SourceContext; } } /*using( FScopedLogTimer LogTimer2 = new FScopedLogTimer( "BuggsController.Show.PopulateUserInfo" + "(id=" + id + ")" ) ) * { * // Add in the users for each crash in the Bugg * foreach( Crash CrashInstance in Model.Crashes ) * { * LocalCrashRepository.PopulateUserInfo( CrashInstance ); * } * }*/ return(View("Show", Model)); } }