int FindLastNonDuplicateFail(BuildNode NodeToDo, NodeHistory History, JobInfo JobInfo) { int Result = P4Env.Changelist; string GameNameIfAny = NodeToDo.GameNameIfAnyForTempStorage; var TempStorageNodeInfo = new TempStorageNodeInfo(JobInfo, NodeToDo.Name + FailedTempStorageSuffix); List<int> BackwardsFails = new List<int>(History.AllFailed); BackwardsFails.Add(P4Env.Changelist); BackwardsFails.Sort(); BackwardsFails.Reverse(); HashSet<string> CurrentErrors = null; foreach (int CL in BackwardsFails) { if (CL > P4Env.Changelist) { continue; } if (CL <= History.LastSucceeded) { break; } // Find any local temp storage manifest for this changelist and delete it. var ThisTempStorageNodeInfo = new TempStorageNodeInfo(JobInfo.CreateWithNewChangelist(CL), TempStorageNodeInfo.NodeStorageName); TempStorage.DeleteLocalTempStorageManifest(ThisTempStorageNodeInfo, true); // these all clash locally, which is fine we just retrieve them from shared List<string> Files = null; try { bool WasLocal; Files = TempStorage.RetrieveFromTempStorage(ThisTempStorageNodeInfo, out WasLocal, GameNameIfAny, CmdEnv.LocalRoot); // this will fail on our CL if we didn't fail or we are just setting up the branch } catch (Exception) { } if (Files == null) { continue; } if (Files.Count != 1) { throw new AutomationException("Unexpected number of files for fail record {0}", Files.Count); } string ErrorFile = Files[0]; HashSet<string> ThisErrors = ECJobPropsUtils.ErrorsFromProps(ErrorFile); if (CurrentErrors == null) { CurrentErrors = ThisErrors; } else { if (CurrentErrors.Count == 0 || !HashSetEqual(CurrentErrors, ThisErrors)) { break; } Result = CL; } } return Result; }