public ActionResult Index() { var startDate = new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, 1); using (var dbContext = new ReportingContext()) { var buildSummary = GetLastBuildSummary(dbContext); var viewModel = new HomeViewModel { Builds = buildSummary, CoverageStat = new ModuleCoverageForABuild(), Challenges = ComputeChallengesSummary(dbContext, startDate, startDate.AddMonths(1)), }; var mainProjectName = ConfigurationManager.AppSettings["MainProjectName"]; var lastBuild = !string.IsNullOrEmpty(mainProjectName) ? buildSummary.FirstOrDefault(i => i.ActualBuild.Definition == mainProjectName) : buildSummary.FirstOrDefault(); if (lastBuild != null) { var coverages = lastBuild.ActualBuild.CoverageCollection.OrderBy(i => (i.BlocksCovered * 100) / (i.BlocksNotCovered + i.BlocksCovered)).ToArray(); viewModel.CoverageStat.Modules = string.Join(", ", coverages.Select(i => i.Name.Replace(".dll", string.Empty).Replace(".exe", string.Empty))); viewModel.CoverageStat.Coverages = string.Join(", ", coverages.Select(i => (i.BlocksCovered * 100) / (i.BlocksNotCovered + i.BlocksCovered))); } viewModel.ShootBoxBuilds = GetLastBuilds(dbContext, startDate, startDate.AddMonths(1)).ToArray(); return View(viewModel); } }
public ActionResult Challenges() { var monthChallenges = new List<MonthChallenge>(); using (var context = new ReportingContext()) { var firstDate = context.Builds.OrderBy(i => i.Date).Select(i => i.Date).FirstOrDefault(); firstDate = new DateTime(firstDate.Year, firstDate.Month, 1); for (var date = firstDate; date < DateTime.UtcNow; date = date.AddMonths(1)) { var challengeSummary = ComputeChallengesSummary(context, date, date.AddMonths(1)); monthChallenges.Add(new MonthChallenge { Date = date, Summary = challengeSummary }); } } return View(new ChallengesViewModel { MonthChallenges = monthChallenges.OrderByDescending(i => i.Date).ToArray() }); }
private IEnumerable<ChallengeSummary> ComputeChallengesSummary(ReportingContext dbContext, DateTime startDate, DateTime stopDate) { var challenges = new List<ChallengeSummary>(); var committers = dbContext.Builds.Where(i => i.Date >= startDate && i.Date < stopDate).Select(i => i.User).Distinct().ToArray(); // ReSharper disable once LoopCanBeConvertedToQuery foreach (var committer in committers) { var currentCommitter = committer; var challengeEntities = dbContext.Challenges.Where(i => i.User == currentCommitter && i.Build.Date >= startDate && i.Build.Date < stopDate).ToList(); var points = challengeEntities.Sum(i => i.Points); var challengeSummary = new ChallengeSummary { Name = committer, Points = Convert.ToInt32(points) }; challenges.Add(challengeSummary); } return challenges.OrderByDescending(i => i.Points).Take(3); }
private double ComputeRatio(BuildEntity buildEntity, ReportingContext context) { var currentProject = context.Projects.FirstOrDefault(i => i.Name == buildEntity.Definition); if (currentProject == null) { currentProject = new ProjectEntity { Name = buildEntity.Definition }; context.Projects.Add(currentProject); } if (!buildEntity.CoverageCollection.Any()) return 0; var currentProjectBlock = buildEntity.CoverageCollection.Sum(i => i.BlocksCovered + i.BlocksNotCovered); currentProject.Blocks = currentProjectBlock; if (!context.Projects.Any()) return 1; var maxBlock = context.Projects.Max(i => i.Blocks); var maxProject = context.Projects.FirstOrDefault(i => i.Blocks == maxBlock); if (maxProject == null || maxBlock == 0) return 1; // Ratio = 1 : no project to be compared. if (maxProject.Id == currentProject.Id) return 1; // current projet is the bigest project. return (double)currentProjectBlock / maxBlock; }
public async Task<IHttpActionResult> Post([FromBody] HttpHookBuild build) { var knowDefinitionsBuilds = ConfigurationManager.AppSettings["ExpectedBuilds"].Split('|').Where(i => !string.IsNullOrEmpty(i)).ToArray(); if (knowDefinitionsBuilds.Any() && !knowDefinitionsBuilds.Contains(build.resource.definition.name)) return Ok(); try { using (var context = new ReportingContext()) { var request = build.resource.requests.FirstOrDefault(); var buildEntity = new BuildEntity { BuildName = build.resource.buildNumber, Definition = build.resource.definition.name, Date = build.resource.finishTime, Status = build.resource.status, Reason = build.resource.reason, Link = build.message.html, User = request != null ? request.requestedFor.uniqueName : "Unknown user", CoverageCollection = new Collection<CoverageEntity>() }; if (buildEntity.User == "Project Collection Service Accounts") buildEntity.User = "******"; if (buildEntity.User == ConfigurationManager.AppSettings["VsoUsername"]) return Ok(); if (string.IsNullOrEmpty(ConfigurationManager.AppSettings["VSO.OrganisationName"]) || string.IsNullOrEmpty(ConfigurationManager.AppSettings["VSO.ProjectName"])) throw new ApplicationException("Please configuration VSO.OrganisationName and VSO.ProjectName first."); var api = new ApiWrapper(ConfigurationManager.AppSettings["VSO.OrganisationName"], ConfigurationManager.AppSettings["VSO.ProjectName"]); var coverage = await api.GetBuildCoverageAsync(build); if (coverage != null) { foreach (var moduleCoverage in coverage) { buildEntity.CoverageCollection.Add(new CoverageEntity { Name = moduleCoverage.Name, ComputedAverage = moduleCoverage.ComputedAverage, BlocksCovered = moduleCoverage.BlocksCovered, BlocksNotCovered = moduleCoverage.BlocksNotCovered, Build = buildEntity }); } } double currentRatio = ComputeRatio(buildEntity, context); var challenge = ComputeCoverageChanges(buildEntity, context, currentRatio); if (challenge != null) context.Challenges.Add(challenge); context.Builds.Add(buildEntity); context.SaveChanges(); } return Ok(); } catch (Exception e) { return BadRequest(e.Message); } }
private ChallengeEntity ComputeCoverageChanges(BuildEntity buildEntity, ReportingContext context, double currentRatio) { if (buildEntity.Status != "succeeded") return null; var previousBuild = context.Builds .OrderByDescending(i => i.Date) .FirstOrDefault(i => i.Definition == buildEntity.Definition && i.Status == "succeeded" && i.CoverageCollection.Any()); if (previousBuild == null) return null; var challenge = new ChallengeEntity { User = buildEntity.User, Build = buildEntity, ModuleCoverages = new List<ModuleChallengeCoverage>() }; var allModules = previousBuild.CoverageCollection.Select(i => i.Name).Union(buildEntity.CoverageCollection.Select(i => i.Name)); foreach (var moduleName in allModules) { var currentModuleName = moduleName; var previousModule = previousBuild.CoverageCollection.FirstOrDefault(i => i.Name == currentModuleName); var currentModule = buildEntity.CoverageCollection.FirstOrDefault(i => i.Name == currentModuleName); if (currentModule != null && previousModule != null && (previousModule.BlocksCovered == currentModule.BlocksCovered && previousModule.BlocksNotCovered == currentModule.BlocksNotCovered)) continue; // Ignore if no change in the module. if (currentModule == null) continue; var previousModuleCoverage = ComputeBuildCoverage(previousModule); var currentModuleCoverage = ComputeBuildCoverage(currentModule); var deltaCoverage = currentModuleCoverage - previousModuleCoverage; var allBlocks = currentModule.BlocksCovered + currentModule.BlocksNotCovered; challenge.ModuleCoverages.Add(new ModuleChallengeCoverage { Module = currentModuleName, DeltaCoverage = deltaCoverage, Blocks = allBlocks }); } var previousProjectCoverage = ComputeBuildCoverage(previousBuild); var currentProjectCoverage = ComputeBuildCoverage(buildEntity); challenge.Points = (currentProjectCoverage - previousProjectCoverage) * 100 * currentRatio; if (double.IsNaN(challenge.Points)) challenge.Points = 0; return challenge; }
private IEnumerable<ShootBoxBuild> GetLastBuilds(ReportingContext dbContext, DateTime startDate, DateTime stopDate) { return dbContext.Builds.Where(i => i.Date >= startDate && i.Date < stopDate).OrderByDescending(i => i.Date).ToList().Select(i => { var challenge = dbContext.Challenges.FirstOrDefault(j => j.Build.Id == i.Id); return new ShootBoxBuild { BuildName = i.BuildName, BuildDate = string.Format("{0} {1}", i.Date.ToShortDateString(), i.Date.ToShortTimeString()), BuildColor = i.Status == "succeeded" ? "#5cb85c" : "#d9534f", SumPoints = challenge != null ? Convert.ToInt32(challenge.Points) : 0, DetailPoints = challenge != null ? challenge.ModuleCoverages : null, User = i.User, }; }); }
private AboutViewModel GetCoverageStat(string buildName, int top) { using (var context = new ReportingContext()) { var allStats = context.Builds .Where(i => i.Definition == buildName && i.CoverageCollection.Any()).ToArray(); if (top != 0) { var count = allStats.Count(); if (count > top) { allStats = allStats.Skip(count - top).Take(top).ToArray(); } } var stats = allStats .ToArray(); var step = (stats.Length / 20); var selectedEntries = new List<BuildEntity>(); for (var i = stats.Min(a => a.Id); i < stats.Max(a => a.Id); i += step) { var b = stats.FirstOrDefault(j => j.Id == i); if (b != null) selectedEntries.Add(b); } if (!selectedEntries.Any()) { return new AboutViewModel { BuildName = buildName, Message = "No coverage result" }; } if (selectedEntries.Count() == 1) { selectedEntries = new List<BuildEntity> { selectedEntries[0], selectedEntries[0] }; } selectedEntries = selectedEntries.OrderBy(i => i.Date).ToList(); var moduleCoverages = new List<int>(); foreach (var buildInformation in selectedEntries) { if (buildInformation.CoverageCollection.Any()) { var allCovered = buildInformation.CoverageCollection.Sum(i => i.BlocksCovered); var allNotCovered = buildInformation.CoverageCollection.Sum(i => i.BlocksNotCovered); moduleCoverages.Add((allCovered * 100) / (allNotCovered + allCovered)); } else { moduleCoverages.Add(0); } } var averageStat = new ModuleCoverageByBuild { ModuleName = buildName, Dates = string.Join(", ", selectedEntries.Select(i => string.Format("{0} {1}", i.Date.ToShortDateString(), i.Date.ToShortTimeString()))), Coverages = string.Join(", ", moduleCoverages) }; return new AboutViewModel { BuildName = buildName, AverageStatistics = averageStat, BuildNames = ConfigurationManager.AppSettings["ExpectedBuilds"].Split('|').Select(i => new SelectListItem { Text = i }).ToList() }; } }
private List<BuildSummary> GetLastBuildSummary(ReportingContext dbContext) { var builds = new List<BuildSummary>(); foreach (var buildName in ConfigurationManager.AppSettings["ExpectedBuilds"].Split('|')) { var orderByDescending = dbContext.Builds.OrderByDescending(i => i.Date); var build = orderByDescending.FirstOrDefault(i => i.Definition == buildName); if (build == null) { builds.Add(new BuildSummary { ActualBuild = new BuildEntity { BuildName = "Not actually a build.", CoverageCollection = new Collection<CoverageEntity>() }, Challenge = new ChallengeEntity() }); continue; } var actualBuild = build; foreach (var coverageEntity in actualBuild.CoverageCollection) { coverageEntity.ComputedAverage = (coverageEntity.BlocksCovered * 100) / (coverageEntity.BlocksCovered + coverageEntity.BlocksNotCovered); } actualBuild.CoverageCollection = actualBuild.CoverageCollection.OrderBy(i => i.ComputedAverage).ToArray(); var actualAverageCoverage = ComputeBuildCoverage(actualBuild.CoverageCollection.ToList()); var buildSummary = new BuildSummary { ActualBuild = actualBuild, ActualAverageCoverage = actualAverageCoverage, Challenge = dbContext.Challenges.FirstOrDefault(i => i.Build.Id == actualBuild.Id), UserGravatar = CalculateMD5Hash(actualBuild.User.ToLower()).ToLower() }; builds.Add(buildSummary); } return builds; }