public async Task <PerformanceRunOptions> CreateAsync() { var options = new PerformanceRunOptions(); using (var appVeyorClient = new AppVeyorClient(_log)) { // Get latest private extension url from appvayor build string lastSuccessfulVersion = await appVeyorClient.GetLastSuccessfulBuildVersionAsync(Branch, options.FunctionsHostSlug); options.ExtensionUrl = await appVeyorClient.GetArtifactUrlAsync(lastSuccessfulVersion, options.FunctionsHostSlug, string.Empty, "inproc"); options.AppUrl = await appVeyorClient.GetArtifactUrlAsync(lastSuccessfulVersion, options.FunctionsHostSlug, string.Empty, "WebJobs.Script.Performance.App"); } return(options); }
static async Task Main(string[] args) { ServicePointManager.DefaultConnectionLimit = Int32.MaxValue; int daysToScan = 7; DateTimeOffset endDate = DateTime.UtcNow; var client = new AppVeyorClient { ApiKey = ConfigurationManager.AppSettings["AppVeyorApiKey"] }; DateTimeOffset startDate = endDate.AddDays(-daysToScan); await Work(client, "azure-functions-host", "v1.x", startDate, endDate); await Work(client, "azure-webjobs-sdk", "v2.x", startDate, endDate); Console.Write("Press any key to exit..."); Console.ReadKey(); }
static async Task Work(AppVeyorClient client, string projectName, string branch, DateTimeOffset startDate, DateTimeOffset endDate, bool ignorePullRequests = true) { Console.Write($"Finding AppVeyor details for project '{projectName}'."); var projects = await client.GetProjectsAsync(); Console.Write("."); var project = await client.GetProjectByNameAsync(projectName); Console.Write("."); Console.WriteLine("Done"); int? lastBuildId = null; List <Build> buildsToAnalyze = new List <Build>(); string prString = ignorePullRequests ? "non-PR" : "all"; Console.Write($"Getting {prString} non-canceled '{project}|{branch}' builds between {startDate} and {endDate}"); while (true) { Console.Write("."); var history = await client.GetBuildHistoryAsync(project, branch, lastBuildId + 1); if (history.builds.Length == 0) { break; } IEnumerable <Build> builds = history.builds.Where(p => p.branch == branch && (p.status == BuildStatus.success || p.status == BuildStatus.failed) && !(ignorePullRequests && p.pullRequestId != null)); // See if we've pulled any older than this. If so, we've got enough and we'll stop. bool reachedCutoff = builds.Any(b => b.finished < startDate); // Only add those that are between the start and end dates buildsToAnalyze.AddRange(builds); if (reachedCutoff) { Console.WriteLine("Done"); break; } lastBuildId = buildsToAnalyze.Min(p => p.buildId); } // Only analyze those that are between the start and end dates buildsToAnalyze = buildsToAnalyze.Where(p => p.finished > startDate && p.finished < endDate).ToList(); Console.WriteLine($"Found {buildsToAnalyze.Count()} eligible builds."); List <JobTestResults> testResultsToAnalyze = new List <JobTestResults>(); Console.Write("Pulling test results for eligible builds"); List <Task> requestTasks = new List <Task>(); string order = string.Empty; foreach (var build in buildsToAnalyze) { Task t = Task.Run(async() => { var jobs = await client.GetJobInfoAsync(project, build.version); foreach (var job in jobs) { var testResults = await client.GetTestResultsAsync(job); order += string.Join(Environment.NewLine, testResults.list.OrderBy(p => p.created).Select(p => $"{p.name} {p.outcome} {p.created}")); order += Environment.NewLine + Environment.NewLine; testResults.BuildNumber = build.version; testResultsToAnalyze.Add(testResults); } Console.Write("."); }); requestTasks.Add(t); } await Task.WhenAll(requestTasks); Console.WriteLine("Done"); Dictionary <string, Stats> results = new Dictionary <string, Stats>(); foreach (var testResults in testResultsToAnalyze) { foreach (var item in testResults.list) { var key = item.name; Stats stats; results.TryGetValue(key, out stats); if (stats == null) { stats = new Stats(); results[key] = stats; } switch (item.outcome) { case Status.passed: stats.Passed++; break; case Status.failed: stats.Fail++; stats.BuildLinks.Add(ConstructAppVeyorTestLink(project.slug, testResults.BuildNumber)); break; } } } // Print summary DateTimeOffset now = DateTimeOffset.UtcNow; var path = Path.Combine(root, projectName, branch); Directory.CreateDirectory(path); var outFile = Path.Combine(path, $"results_{now.ToString("yyyyddMMHHmmss")}.html"); var pairs = results.OrderByDescending(kv => kv.Value.Fail).ToArray(); using (var tw = new StreamWriter(outFile)) { string dateFormat = "MM-dd-yy HH:mm:ss UTC"; tw.WriteLine($"{projectName} {branch}<br/>"); tw.WriteLine($"Start: {startDate.ToString(dateFormat)}<br/>"); tw.WriteLine($"End: {endDate.ToString(dateFormat)}<br/>"); tw.WriteLine("<table>"); tw.WriteLine("<tr><th>Name</th><th>Fail</th><th>Pass</th><th>FailLinks</th><th>Owner</th><th>Note</th></tr>"); foreach (var kv in pairs) { tw.Write("<tr>"); string linkString = string.Empty; for (int i = 0; i < kv.Value.BuildLinks.Count; i++) { linkString += $"<a href=\"{kv.Value.BuildLinks[i]}\">{i + 1}</a> "; } linkString.Trim(); tw.WriteLine($"<td>{Clean(kv.Key)}</td><td>{kv.Value.Fail}</td><td>{kv.Value.Passed}</td><td>{linkString}</td><td></td><td></td>"); tw.Write("</tr>"); } tw.WriteLine("</table>"); } Console.WriteLine($"Summary written to {outFile}"); Console.WriteLine($"Opening {outFile}"); Process.Start(outFile); Console.WriteLine(); }