public void PushToGoogleSpreadsheet(BoardStatsAnalysis boardStatsAnalysis, string spreadsheetName) { var listFeed = _googleClient.GetListFeedForSpreadsheet(spreadsheetName); AddTitleCard(boardStatsAnalysis, listFeed); AddGoodCards(boardStatsAnalysis, listFeed); AddBadCards(boardStatsAnalysis, listFeed); }
public BoardStatsAnalysis BuildBoardStatsAnalysis(TrelloData trelloData, List<TimesheetData> timesheetData) { var boardStats = new BoardStats(); BuildCardStats(trelloData, boardStats); boardStats.ListStats = GetListStats(trelloData.ListsToCount); boardStats.TimesheetData = timesheetData; boardStats.ProjectStartDate = ProjectStartDate; var boardStatsAnalysis = new BoardStatsAnalysis(_configuration, boardStats); boardStatsAnalysis.NextMilestoneProjection = BuildProjectionsForNextMilestone(trelloData, boardStatsAnalysis); boardStatsAnalysis.Projections = BuildProjections(trelloData, boardStatsAnalysis); if (trelloData.MilestoneList != null) { var milestones = new List<Milestone>(); foreach (var card in trelloData.MilestoneList.CardDataCollection) { if (card.Card.Due.HasValue) { milestones.Add(new Milestone() { Name = card.Card.Name, TargetDate = card.Card.Due.Value }); } } boardStatsAnalysis.Milestones = milestones; } return boardStatsAnalysis; }
private void AddBadCards(BoardStatsAnalysis boardStatsAnalysis, ListFeed listFeed) { if (boardStatsAnalysis.BoardStats.BadCardStats.Count > 0) { var errorRow = _spreadsheetEntryFactory.GetBadCardEntry(boardStatsAnalysis); _googleClient.Insert(listFeed, errorRow); } }
private void AddGoodCards(BoardStatsAnalysis boardStatsAnalysis, ListFeed listFeed) { foreach (var dayGroups in boardStatsAnalysis.CompletedCardStats.GroupBy(b => b.DoneAction.DateInTimeZone(_configuration.TimeZone).ToShortDateString())) { var dayGroupList = dayGroups.ToList(); for (int i = 0; i < dayGroupList.Count(); i++) { var cardStat = dayGroupList[i]; var minutesConfig = i * _configuration.TimelineJsOffsetMinutesPerCard; var timeOffset = new TimeSpan(0, minutesConfig, 0); var row = _spreadsheetEntryFactory.GetCompletedCardEntry(cardStat, timeOffset); _googleClient.Insert(listFeed, row); } } }
public void CreateJsonData(BoardStatsAnalysis boardStatsAnalysis) { dynamic data = new ExpandoObject(); data.weeklyStats = CreateWeeklyStatsSeriesCollection(boardStatsAnalysis); data.burndown = new ExpandoObject(); var burndownPointsData = GetBurndownData(boardStatsAnalysis); var historicalPointsSeries = CreateSeries("Historical", burndownPointsData); data.burndown.historicalPoints = historicalPointsSeries; AddProjectionsSeries(boardStatsAnalysis.Projections, data.burndown); data.nextMilestoneBurndown = new ExpandoObject(); AddProjectionsSeries(boardStatsAnalysis.NextMilestoneProjection, data.nextMilestoneBurndown); AddHourTimesheetData(boardStatsAnalysis, data); data.milestoneSeries = GetMilestonesSeries(boardStatsAnalysis); var json = JsonConvert.SerializeObject(data, Newtonsoft.Json.Formatting.Indented, new JavaScriptDateTimeConverter()); var jsonFileInfo = new FileInfo(Path.Combine(_configuration.WebsiteOutputFolder,_configuration.WebsiteJsonFilename)); File.WriteAllText(jsonFileInfo.FullName, "var data = " + json); var htmlFileInfo = new FileInfo(Path.Combine(_configuration.WebsiteOutputFolder, _configuration.WebsiteHtmlFilename)); var htmlSourceFileInfo = new FileInfo("Html\\index.html"); var html = File.ReadAllText(htmlSourceFileInfo.FullName); html = html.Replace("[[summary]]",_htmlFactory.GetSummaryTextForBoardStat(boardStatsAnalysis)); html = html.Replace("[[extra_lists_stats_table]]", _htmlFactory.GetExtraListsStatsTable(boardStatsAnalysis)); html = html.Replace("[[weekly_stats_rows]]", _htmlFactory.GetWeeklyStatsRows(boardStatsAnalysis)); html = html.Replace("[[projections_summary]]", _htmlFactory.GetProjectionsSummaryText(boardStatsAnalysis.Projections)); html = html.Replace("[[next_milestone_projections_summary]]", _htmlFactory.GetProjectionsSummaryText(boardStatsAnalysis.NextMilestoneProjection)); File.WriteAllText(htmlFileInfo.FullName, html); CopyFileToOutputFolder("style.css"); CopyFileToOutputFolder("bootstrap.min.css"); }
private BoardProjections BuildBoardProjection(BoardStatsAnalysis boardStatsAnalysis, double estimatedPoints) { var totalDonePoints = boardStatsAnalysis.TotalPoints; var elapsedWeeks = boardStatsAnalysis.CompletedWeeksElapsed - _configuration.WeeksToSkipForVelocityCalculation; var historicalPointsPerWeek = totalDonePoints / elapsedWeeks; var projectedWeeksToComplete = estimatedPoints / historicalPointsPerWeek; var projectedWeeksMin = projectedWeeksToComplete * _configuration.TrelloProjectionsEstimateWindowLowerBoundFactor; var projectedWeeksMax = projectedWeeksToComplete * _configuration.TrelloProjectionsEstimateWindowUpperBoundFactor; var projection = new BoardProjections() { EstimatePoints = estimatedPoints, TotalPointsCompleted = totalDonePoints, elapsedWeeks = elapsedWeeks, historicalPointsPerWeek = historicalPointsPerWeek, ProjectedWeeksToCompletion = projectedWeeksToComplete, ProjectionCompletionDate = GetCompletionDate(projectedWeeksToComplete), ProjectedMinimumCompletionDate = GetCompletionDate(projectedWeeksMin), ProjectedMaximumCompletionDate = GetCompletionDate(projectedWeeksMax) }; return projection; }
private void AddHourTimesheetData(BoardStatsAnalysis boardStatsAnalysis, dynamic data) { var burndownHoursData = GetBurndownHoursData(boardStatsAnalysis); var burndownHoursSeries = CreateSeries("HistoricalHours", burndownHoursData); data.historicalHours = burndownHoursSeries; var burndownExcludedHoursData = GetBurndownExcludedHoursData(boardStatsAnalysis); var burndownExcludedHoursSeries = CreateSeries("HistoricalExcludedHours", burndownExcludedHoursData); data.historicalExcludedHours = burndownExcludedHoursSeries; }
private List<dynamic> GetMilestonesSeries(BoardStatsAnalysis boardStatsAnalysis) { var totalPoints = boardStatsAnalysis.TotalPoints + boardStatsAnalysis.EstimatedListPoints; List<Milestone> milestones = boardStatsAnalysis.Milestones; var milestoneSeries = new List<dynamic>(); foreach (var milestone in milestones) { var topPoint = GetDateValuePoint(milestone.TargetDate, totalPoints); topPoint.milestoneName = milestone.Name; topPoint.isTopPoint = true; var bottomPoint = GetDateValuePoint(milestone.TargetDate, 0); bottomPoint.milestoneName = milestone.Name; bottomPoint.isTopPoint = false; var series = CreateSeries(milestone.Name + "(Milestone)", new List<dynamic>() { bottomPoint, topPoint }); series.color = "#AFAFC1"; series.marker = new ExpandoObject(); series.marker.enabled = false; milestoneSeries.Add(series); } return milestoneSeries; }
private List<dynamic> GetBurndownHoursData(BoardStatsAnalysis boardStatsAnalysis) { var burndownHoursData = new List<dynamic>(); foreach (var weekStats in boardStatsAnalysis.WeekStats.Take(boardStatsAnalysis.WeekStats.Count - 1)) { var point = GetDateValuePoint(weekStats.EndDate, weekStats.TotalHours); burndownHoursData.Add(point); } var lastWeekStats = boardStatsAnalysis.WeekStats.Last(); var lastPoint = GetDateValuePoint(DateTime.Now, lastWeekStats.TotalHours); burndownHoursData.Add(lastPoint); return burndownHoursData; }
private List<dynamic> GetBurndownData(BoardStatsAnalysis boardStatsAnalysis) { var totalPoints = boardStatsAnalysis.TotalPoints + boardStatsAnalysis.EstimatedListPoints; var totalPointsRemaining = totalPoints; var burnDownData = new List<dynamic>(); foreach (var weekStats in boardStatsAnalysis.WeekStats.Take(boardStatsAnalysis.WeekStats.Count - 1)) { totalPointsRemaining -= weekStats.PointsCompleted; var point = GetDateValuePoint(weekStats.EndDate, totalPointsRemaining); burnDownData.Add(point); } var lastWeekStats = boardStatsAnalysis.WeekStats.Last(); totalPointsRemaining -= lastWeekStats.PointsCompleted; var lastPoint = GetDateValuePoint(DateTime.Now, totalPointsRemaining); burnDownData.Add(lastPoint); return burnDownData; }
private List<dynamic> CreateWeeklyStatsSeriesCollection(BoardStatsAnalysis boardStatsAnalysis) { var seriesCollection = new System.Collections.Generic.List<dynamic>(); dynamic series = CreateSeries("In Progress", "In Progress", boardStatsAnalysis.WeekStats.Select(w => w.NumberOfCardsInProgress).ToArray()); seriesCollection.Add(series); series = CreateSeries("In Test", "In Test", boardStatsAnalysis.WeekStats.Select(w => w.NumberOfCardsInTest).ToArray()); seriesCollection.Add(series); series = CreateSeries("Trinity", "Stories Completed", boardStatsAnalysis.WeekStats.Select(w => w.GetNumberOfCardsWithLabel("Trinity")).ToArray()); seriesCollection.Add(series); series = CreateSeries("Classic", "Stories Completed", boardStatsAnalysis.WeekStats.Select(w => w.GetNumberOfCardsWithLabel("Classic")).ToArray()); seriesCollection.Add(series); series = CreateSeries("Implemented Prior to Estimate", "Implemented Prior to Estimate", boardStatsAnalysis.WeekStats.Select(w => w.GetNumberOfCardsWithLabel("Implemented Prior to Estimate")).ToArray()); seriesCollection.Add(series); series = CreateSeries("Hotfix", "Hotfix", boardStatsAnalysis.WeekStats.Select(w => w.GetNumberOfCardsWithLabel("Hotfix")).ToArray()); seriesCollection.Add(series); return seriesCollection; }
private void AddTitleCard(BoardStatsAnalysis boardStatsAnalysis, ListFeed listFeed) { var titleRow = _spreadsheetEntryFactory.GetTitleCardEntry(boardStatsAnalysis); _googleClient.Insert(listFeed, titleRow); }
private BoardProjections BuildProjectionsForNextMilestone(TrelloData trelloData, BoardStatsAnalysis boardStatsAnalysis) { var estimatedPoints = GetEstimatedPointsNextMilestoneForList(trelloData, _configuration.ListNames.EstimatedList); estimatedPoints += GetEstimatedPointsNextMilestoneForList(trelloData, _configuration.ListNames.InProgressListName); estimatedPoints += GetEstimatedPointsNextMilestoneForList(trelloData, _configuration.ListNames.InTestListName); boardStatsAnalysis.EstimatedListPoints = estimatedPoints; var projection = BuildBoardProjection(boardStatsAnalysis, estimatedPoints); return projection; }