private static StatusTransition AsStatusTransition(IssueChangeLog changeLog) => new StatusTransition { Date = changeLog.CreatedDate, User = changeLog.Author.DisplayName, From = changeLog.Items.Single().FromValue, To = changeLog.Items.Single().ToValue, };
public JIssueChangeLog(IssueChangeLog changeLog) { _changeLog = changeLog; Initialize(); }
public void AddChangeLog(IssueChangeLog changeLog) { ChangeLogs.Add(new JIssueChangeLog(changeLog)); }
/* Aufbau einer Tabelle: pro gefundenem Issue aufsummiert alle Zeiten pro Status in Minuten. * e.g. To Do | In Progress | In Test * 500 | 876 | 456 * gezählt werden Verstreichminuten (Progress Time), NICHT action Time (echte Arbeitszeit) * 24 h / 7 Tage Woche */ private void Button_IssuesFromJson(object sender, RoutedEventArgs e) { string jsonString = ""; int counter = 0; // Verlaufsbalken Zähler int issuesCount; // wieviele Issues insgesamt issuecount/20 == anzahl abrufe notwendig String csvFileContent = ""; WorkflowExtraxtor wfex = new WorkflowExtraxtor(); IssueChangeLog issueChangelog = new IssueChangeLog(); List <String> notFoundStep = new List <String>(); if (true) { // get json & deserialize jsonString = File.ReadAllText(TextBlock_FilePathJson.Text); TextBox_JsonPath.Text = TextBlock_FilePathJson.Text; IssuesPOCO JsonContent = JsonConvert.DeserializeObject <IssuesPOCO>(jsonString); csvFileContent = ""; csvFileContent += "Group,Key,Issuetype,Status,Created Date,Component,Resolution,"; List <WorkflowStep> statuses = wfex.getWorkflowFromFile(TextBlock_WorkflowFilePath.Text); List <string> doneStatesList = new List <string>(); // foreach (WorkflowStep status in statuses) { csvFileContent += status.Name + ","; if (status.DoneState) { doneStatesList.Add(status.Name); } } csvFileContent += "First Date,Closed Date"; csvFileContent += System.Environment.NewLine; // baue dictionary mit status/zeitpaaren issuesCount = JsonContent.issues.Count; foreach (IssuePOCO issue in JsonContent.issues) { String resultLine = ""; string lastName = ""; string firstName = ""; string group = ""; Boolean foundDate = false; // json convert anpassen auf issuetype "Fields hinzufügen" resultLine += group + "," + issue.key + "," + issue.fields.issuetype.name + "," + issue.fields.status.name + "," + issue.fields.created.ToString() + ","; if (issue.fields.components != null) { foreach (IssueComponentsItemPOCO item in issue.fields.components) { resultLine += item.name + "|"; } } resultLine += ","; if (issue.fields.resolution != null) { resultLine += issue.fields.resolution.name; } resultLine += ","; Dictionary <string, int> dict = new Dictionary <string, int>(); foreach (WorkflowStep status in statuses) { dict[status.Name] = 0; if (status.Last) { lastName = status.Name; } if (status.First) { firstName = status.Name; } } List <StatusRich> statusRichList = new List <StatusRich>(); foreach (IssueHistoryPOCO history in issue.changelog.histories) { foreach (IssueChangeLogItem item in history.items) { if (item.FieldName.Equals("status")) { StatusRich statusTransformation = new StatusRich(item.ToValue, DateTime.Parse(history.created.ToString())); statusRichList.Add(statusTransformation); } } } DateTime CloseDate = new DateTime(); DateTime FirstDate = new DateTime(); DateTime DoneDate = new DateTime(); // umsortieren letzter zuerst, desc statusRichList.Sort((x, y) => y.TimeStamp.CompareTo(x.TimeStamp)); DateTime currentDate = (DateTime)DatePicker_DateOfFile.SelectedDate; // kein Statuswechsel in History ==> immer noch im initialen Status if (statusRichList.Count < 1) { //DateTime currentDate = new DateTime(2020, 12, 17, 12, 29, 00); TimeSpan ts = currentDate - issue.fields.created; int minutes = (int)ts.TotalMinutes; resultLine += minutes + ",,,,,,,,"; } // sonst Status gefunden, wenn nicht: immer noch open else { DateTime last; // wenn es einen Donestatus gibt ist der letzte das Ende Date //if (statusRichList.Any(p => p.Name == "Done") || statusRichList.Any(p => p.Name == "Abgebrochen")) if (statusRichList.Any(p => p.Name.Equals(lastName))) { CloseDate = statusRichList.Max(obj => obj.TimeStamp); } if (statusRichList.Any(p => p.Name.Equals(firstName))) { FirstDate = statusRichList.Min(obj => obj.TimeStamp); } // Erster Zeitpunkt: Erstelldatum des Datenabzugs (aka "heute") last = currentDate; // Dauer eines statusverbleibs: Startdate des nachfolgers - Startdate des betrachteten Status foreach (StatusRich statusTrans in statusRichList) { TimeSpan ts = last - statusTrans.TimeStamp; statusTrans.Minutes = (int)ts.TotalMinutes; last = statusTrans.TimeStamp; string statusName = ""; if (!(dict.ContainsKey(statusTrans.Name))) { statusName = statusTrans.Name; foreach (WorkflowStep step in statuses) { if (step.Aliases.Contains(statusTrans.Name)) { statusName = step.Name; } } } else { statusName = statusTrans.Name; } if (doneStatesList.Contains(statusName)) { DoneDate = statusTrans.TimeStamp; foundDate = true; } if (!dict.ContainsKey(statusName)) { dict.Add(statusName, 0); if (!notFoundStep.Contains(statusName)) { notFoundStep.Add(statusName); } } dict[statusName] += statusTrans.Minutes; } foreach (KeyValuePair <string, int> pair in dict) { resultLine += pair.Value + ","; } } if (FirstDate.Equals(new DateTime())) { resultLine += ","; } else { resultLine += FirstDate.ToString() + ","; } if (CloseDate.Equals(new DateTime())) { if (foundDate) { resultLine += DoneDate.ToString() + ","; } /*resultLine += ",";*/ } else { resultLine += CloseDate.ToString(); } csvFileContent += resultLine + System.Environment.NewLine; Console.WriteLine(resultLine); counter++; ProgressBar_Historie.Value = 100 / issuesCount * counter; } } TextBox_Errors.Text += "\n<< additional Statuses found >> \n"; foreach (String s in notFoundStep) { TextBox_Errors.Text += s + " \n"; } File.WriteAllText(TextBlock_Filepath.Text, csvFileContent); }
private static string GetDevAssignee(List <JiraUser> devs, Issue issue, List <IssueChangeLog> featureLogStatuses, IssueChangeLog inDevelopEntry) { // если оно в разработки сразу берем асайни, т.к. есть странные переходы (дев передал другому деву без смены статуса) if (issue.Status == "Разработка") { return(GetCurrentIssueAssignee(devs, issue)); } // берем assignee последнего статуса перевода в разработку var inDevelopAssignee = inDevelopEntry.Items.SingleOrDefault(o => o.FieldName == "assignee")?.ToValue; // если не нашли - берем ближайшего предыдущего assignee, т.к. при переводе статуса он не всегда меняется if (inDevelopAssignee == null) { // идем назад ищем assignee string prevAssigneeFound = null; var index = featureLogStatuses.IndexOf(inDevelopEntry); while (index >= 0) { prevAssigneeFound = featureLogStatuses[index].Items.SingleOrDefault(o => o.FieldName == "assignee")?.ToValue; if (prevAssigneeFound != null) { break; } index--; } inDevelopAssignee = prevAssigneeFound; // если не нашли, идем вперед и ищем момент когда разработчик сменился на тестеровщика if (prevAssigneeFound == null) { string nextAssigneeFound = null; var ind = featureLogStatuses.IndexOf(inDevelopEntry); while (ind < featureLogStatuses.Count) { nextAssigneeFound = featureLogStatuses[ind].Items.SingleOrDefault(o => o.FieldName == "assignee")?.FromValue; if (nextAssigneeFound != null) { break; } ind++; } inDevelopAssignee = nextAssigneeFound; } } // assignee не менялся в истории, берем указанного при создании задачи if (inDevelopAssignee == null) { inDevelopAssignee = GetCurrentIssueAssignee(devs, issue); } if (inDevelopAssignee == null) { Console.WriteLine(issue.Key + " assignee not found"); } return(inDevelopAssignee); }
private static bool IsStatusChange(IssueChangeLog changeLog) => changeLog.Items.Any(i => i.FieldName == "status");
public void buildCFDDataFile(string workflowPath, string jsonPath, DateTime timeStamp) { { String jsonString = ""; String csvFileContent = ""; WorkflowExtraxtor wfex = new WorkflowExtraxtor(); //int counter = 0; // Verlaufsbalken Zähler //int issuesCount; // wieviele Issues insgesamt issuecount/20 == anzahl abrufe notwendig IssueChangeLog issueChangelog = new IssueChangeLog(); // get json & deserialize jsonString = File.ReadAllText(jsonPath); IssuesPOCO JsonContent = JsonConvert.DeserializeObject <IssuesPOCO>(jsonString); csvFileContent = ""; csvFileContent += "Key,Issuetype,Current Status,Created Date,"; List <WorkflowStep> s = wfex.getWorkflowFromFile(workflowPath); foreach (WorkflowStep item in s) { csvFileContent += item.Name + ","; } csvFileContent += System.Environment.NewLine; // // baue dictionary mit status/zeitpaaren //issuesCount = JsonContent.issues.Count; List <StatusCounts> DatesStatusCounts = new List <StatusCounts>(); foreach (IssuePOCO issue in JsonContent.issues) { foreach (IssueHistoryPOCO history in issue.changelog.histories) { foreach (IssueChangeLogItem item in history.items) { if (item.FieldName.Equals("status")) { //dict[item.] = history.created.ToString(); } } } } String resultLine = ""; //resultLine += issue.key + "," + issue.fields.issuetype.name + "," + issue.fields.status.name + "," + issue.fields.created.ToString() + ","; //Dictionary<WorkflowStep, string> dict = new Dictionary<WorkflowStep, string>(); // foreach (WorkflowStep issueStatus in s) // { // dict.Add(issueStatus, ""); // } //foreach (IssueHistoryPOCO history in issue.changelog.histories) //{ // foreach (IssueChangeLogItem item in history.items) // { // if (item.FieldName.Equals("status")) // { // dict[item.] = history.created.ToString(); // } // } //} //foreach (KeyValuePair<string, string> pair in dict) //{ // resultLine += pair.Value + ","; //} //csvFileContent += resultLine + System.Environment.NewLine; //Console.WriteLine(resultLine); //counter++; //ProgressBar_Historie.Value = 100 / issuesCount * counter; //Console.WriteLine("Ausgabe: " +jsonString); //File.WriteAllText(TextBlock_Filepath.Text, csvFileContent); } }