Example #1
0
        public async Task <List <NGenAssemblyData> > GetNGenAssemblyDataAsync(Build build)
        {
            VerifyBuild(build);

            var uri = DevOpsUtil.GetBuildUri(build);

            Logger.LogInformation($"Processing {build.Id} - {uri}");

            // Newer builds have the NGEN logs in a separate artifact altogether to decrease the time needed
            // to downloaad them. Try that first and fall back to the diagnostic logs if it doesn't exist.
            MemoryStream stream;
            Func <ZipArchiveEntry, bool> predicate;

            try
            {
                Logger.LogInformation("Downloading NGEN logs");
                stream = await DevOpsServer.DownloadArtifactAsync(ProjectName, build.Id, "NGen Logs");

                predicate = e => !string.IsNullOrEmpty(e.Name);
            }
            catch (Exception)
            {
                Logger.LogInformation("Falling back to diagnostic logs");
                stream = await DevOpsServer.DownloadArtifactAsync(ProjectName, build.Id, "Build Diagnostic Files");

                predicate = e => !string.IsNullOrEmpty(e.Name) && e.FullName.StartsWith("Build Diagnostic Files/ngen/");
            }

            return(await GetFromStream(stream, predicate));
        }
Example #2
0
        public async Task <List <JobCloneTime> > GetJobCloneTimesAsync(Build build)
        {
            var list     = new List <JobCloneTime>();
            var timeline = await DevOpsServer.GetTimelineAsync(ProjectName, build.Id);

            if (timeline is null)
            {
                return(list);
            }

            foreach (var record in timeline.Records.Where(x => x.Name == "Checkout" && x.FinishTime is object && x.StartTime is object))
            {
                var duration  = DateTime.Parse(record.FinishTime) - DateTime.Parse(record.StartTime);
                var startTime = DateTimeOffset.Parse(record.StartTime);
                var parent    = timeline.Records.Single(x => x.Id == record.ParentId);
                var(fetchSize, minFetchSpeed, maxFetchSpeed, averageFetchSpeed) = await GetSizesAsync(record);

                var jobCloneTime = new JobCloneTime(
                    parent.Name,
                    startTime,
                    duration,
                    fetchSize,
                    minFetchSpeed: minFetchSpeed,
                    maxFetchSpeed: maxFetchSpeed,
                    averageFetchSpeed: averageFetchSpeed);
                list.Add(jobCloneTime);
            }

            return(list);
        }
Example #3
0
        public async IAsyncEnumerable <(PullRequest PullReuqest, Build Build)> EnumerateMergedPullRequestBuilds(
            DevOpsServer server,
            GitHubBuildInfo gitHubInfo,
            string project,
            int[]?definitions)
        {
            await foreach (var pullRequest in EnumerateClosedPullRequests(gitHubInfo.Organization, gitHubInfo.Repository).ConfigureAwait(false))
            {
                var   prKey = new GitHubPullRequestKey(gitHubInfo.Organization, gitHubInfo.Repository, pullRequest.Number);
                Build?build = null;
                try
                {
                    var builds = (await server.ListPullRequestBuildsAsync(prKey, project, definitions).ConfigureAwait(false))
                                 .OrderByDescending(b => b.BuildNumber)
                                 .Where(x => x.Status == BuildStatus.Completed && x.Result != BuildResult.Canceled)
                                 .ToList();
                    if (builds.Count > 0)
                    {
                        build = builds[0];
                    }
                }
                catch (Exception)
                {
                    // Error enumerating builds, continue to the next one
                }

                if (build is object)
                {
                    yield return(pullRequest, build);
                }
            }
        }
Example #4
0
        private static async Task DumpTestTimesCsv()
        {
            var server = new DevOpsServer("dnceng", await GetToken("dnceng"));
            var all    = await server.ListTestRunsAsync("public", 585853);

            var debug   = all.Where(x => x.Name == "Windows Desktop Debug Test32").First();
            var spanish = all.Where(x => x.Name == "Windows Desktop Spanish").First();

            await Write(debug, @"p:\temp\data-debug-class.csv");
            await Write(spanish, @"p:\temp\data-spanish-class.csv");

            async Task Write(TestRun testRun, string filePath)
            {
                var testCases = await server.ListTestResultsAsync("public", testRun.Id);

                var sorted = testCases
                             .Select(x => (ClassName: GetClassName(x), Duration: x.DurationInMs))
                             .GroupBy(x => x.ClassName)
                             .OrderBy(x => x.Key);

                var builder = new StringBuilder();

                foreach (var group in sorted)
                {
                    var time = TimeSpan.FromMilliseconds(group.Sum(x => x.Duration));
                    builder.AppendLine($"{group.Key},{time}");
                }
                File.WriteAllText(filePath, builder.ToString());
            }
Example #5
0
        public async Task GetAttemptOneMultiPatch()
        {
            var handler = new TestableHttpMessageHandler();

            handler.AddJson(
                "https://dev.azure.com/dnceng/public/_apis/build/builds/799195/timeline?api-version=5.0",
                ResourceUtil.GetJsonFile("timeline2.json"));
            handler.AddJson(
                "https://dev.azure.com/dnceng/public/_apis/build/builds/799195/timeline/5c657fa2-65d2-55e4-f9c9-8fbd97185e37?api-version=5.0",
                ResourceUtil.GetJsonFile("timeline2-part1.json"));
            handler.AddJson(
                "https://dev.azure.com/dnceng/public/_apis/build/builds/799195/timeline/0254bc91-8160-5748-ab06-8ddd0ae17493?api-version=5.0",
                ResourceUtil.GetJsonFile("timeline2-part2.json"));
            handler.AddJson(
                "https://dev.azure.com/dnceng/public/_apis/build/builds/799195/timeline/b02ddad0-c847-5898-a3e9-29c2612003f0?api-version=5.0",
                ResourceUtil.GetJsonFile("timeline2-part3.json"));

            var server   = new DevOpsServer("dnceng", httpClient: new HttpClient(handler));
            var timeline = await server.GetTimelineAttemptAsync("public", 799195, attempt : 1);

            Assert.NotNull(timeline);
            var timelineTree = TimelineTree.Create(timeline !);

            Assert.NotNull(timelineTree);
        }
Example #6
0
 public Functions(DevOpsServer server, GitHubClient gitHubClient, TriageContext context)
 {
     Server            = server;
     GitHubClient      = gitHubClient;
     Context           = context;
     TriageContextUtil = new TriageContextUtil(context);
 }
Example #7
0
        private static async Task ListBuildsFullAsync()
        {
            var server  = new DevOpsServer("dnceng");
            var builds1 = await server.ListBuildsAsync("public", new[] { 15 });

            var builds2 = await server.ListBuildsAsync("public", top : 10);
        }
Example #8
0
        public async Task OnPullRequestMergedAsync(
            DevOpsServer server,
            TriageContextUtil triageContextUtil,
            GitHubPullRequestKey prKey,
            string project,
            CancellationToken cancellationToken = default)
        {
            // Pull requests can trigger builds in multiple definitions. Need to calculate the merged PR build
            // for each of them
            var allBuilds = await server.ListPullRequestBuildsAsync(prKey, project).ConfigureAwait(false);

            foreach (var group in allBuilds.GroupBy(x => x.Definition.Id))
            {
                var mergedBuild = group
                                  .Where(x => x.Status == BuildStatus.Completed && x.Result != BuildResult.Canceled)
                                  .OrderByDescending(x => x.Id)
                                  .FirstOrDefault();
                if (mergedBuild is object)
                {
                    var modelBuild = await triageContextUtil.EnsureBuildAsync(mergedBuild.GetBuildResultInfo()).ConfigureAwait(false);

                    modelBuild.IsMergedPullRequest = true;
                    await triageContextUtil.Context.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
                }
            }
        }
Example #9
0
        private static async Task Scratch2()
        {
            var server = new DevOpsServer("dnceng", await GetToken("dnceng"));
            var builds = await server.ListBuildsAsync("public", definitions : new[] { 686 }, top : 3000);

            var buildTimes = new List <(int BuildNumber, DateTime StartTime, DateTime EndTime)>();

            GetBuildTimes();

            var firstDay    = buildTimes.Min(x => x.StartTime).Date;
            var lastDay     = DateTime.UtcNow.Date;
            var maxCapacity = GetCapacity();

            Console.WriteLine($"Max capacity is {maxCapacity}");

            void GetBuildTimes()
            {
                using var writer = new StreamWriter(@"p:\temp\builds.csv", append: false);
                writer.WriteLine("Build Number,Start Time, End Time");
                foreach (var build in builds)
                {
                    if (build.FinishTime is null)
                    {
                        continue;
                    }

                    if (!DateTime.TryParse(build.StartTime, out var startTime) ||
                        !DateTime.TryParse(build.FinishTime, out var endTime))
                    {
                        continue;
                    }

                    writer.WriteLine($"{build.Id},{build.StartTime},{build.FinishTime}");
                    buildTimes.Add((build.Id, startTime, endTime));
                }
            }

            int GetCapacity()
            {
                using var writer = new StreamWriter(@"p:\temp\capacity.csv", append: false);
                writer.WriteLine("Time,Build Count");
                var current = firstDay;
                var max     = 0;

                while (current.Date <= lastDay)
                {
                    var count = buildTimes.Count(x => current >= x.StartTime && current <= x.EndTime);
                    if (count > max)
                    {
                        max = count;
                    }

                    writer.WriteLine($"{current},{count}");
                    current = current.AddMinutes(15);
                }

                return(max);
            }
        }
Example #10
0
        private DotNetQueryUtil CreateForServer(DevOpsServer server)
        {
            // https://github.com/jaredpar/devops-util/issues/19
            // Consider using a cache here
            var azureUtil = new AzureUtil(server);

            return(new DotNetQueryUtil(server, azureUtil));
        }
Example #11
0
            static async Task <DotNetTestRun> GetDotNetTestRunAsync(DevOpsServer server, Build build, TestRun testRun, TestOutcome[] outcomes)
            {
                var all = await server.ListTestResultsAsync(build.Project.Name, testRun.Id, outcomes : outcomes).ConfigureAwait(false);

                var info = new TestRunInfo(build, testRun);
                var list = ToDotNetTestCaseResult(info, all.ToList());

                return(new DotNetTestRun(info, new ReadOnlyCollection <DotNetTestCaseResult>(list)));
            }
Example #12
0
 public BuildRetryUtil(
     DevOpsServer server,
     TriageContext context,
     ILogger logger)
 {
     Server            = server;
     TriageContextUtil = new TriageContextUtil(context);
     Logger            = logger;
 }
Example #13
0
 public Functions(DevOpsServer server, TriageContext context, GitHubClientFactory gitHubClientFactory)
 {
     Server              = server;
     Context             = context;
     TriageContextUtil   = new TriageContextUtil(context);
     GitHubClientFactory = gitHubClientFactory;
     SiteLinkUtil        = SiteLinkUtil.Published;
     HelixServer         = new HelixServer();
 }
Example #14
0
        private async Task <(double?FetchSize, double?MinFetchSpeed, double?MaxFetchSpeed, double?AverageFetchSpeed)> GetSizesAsync(TimelineRecord record)
        {
            try
            {
                using var stream = await DevOpsServer.DownloadFileAsync(record.Log.Url);

                using var reader = new StreamReader(stream);
                var    sizeAtom    = @"[\d.]+\s+[GMK]iB";
                var    regex       = new Regex($@"Receiving objects:\s+\d+% .*,\s+({sizeAtom})\s+\|\s+({sizeAtom})/s(,\s*done)?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
                var    fetchSpeeds = new List <double>();
                double?fetchSize   = null;

                do
                {
                    var line = await reader.ReadLineAsync();

                    if (line is null)
                    {
                        break;
                    }

                    var match = regex.Match(line);
                    if (match.Success)
                    {
                        var size  = parseSize(match.Groups[1].Value);
                        var speed = parseSize(match.Groups[2].Value);
                        if (speed.HasValue)
                        {
                            fetchSpeeds.Add(speed.Value);
                        }

                        updateIfBigger(ref fetchSize, size);

                        if (!string.IsNullOrEmpty(match.Groups[3].Value))
                        {
                            break;
                        }
                    }
                } while (true);

                if (fetchSpeeds.Count == 0)
                {
                    return(fetchSize, null, null, null);
                }

                return(
                    fetchSize,
                    fetchSpeeds.Min(),
                    fetchSpeeds.Max(),
                    fetchSpeeds.Average());
            }
            catch (Exception ex)
            {
                Logger.LogInformation($"Error parsing fetch times: {ex.Message}");
                return(null, null, null, null);
            }
Example #15
0
        public DotNetQueryUtil(DevOpsServer server, IAzureUtil?azureUtil = null)
        {
            if (azureUtil is object && server.Organization != azureUtil.Organization)
            {
                throw new ArgumentException();
            }

            Server    = server;
            AzureUtil = azureUtil ?? new AzureUtil(server);
        }
Example #16
0
 internal RuntimeInfo(
     DevOpsServer devopsServer,
     HelixServer helixServer,
     IAzureUtil azureUtil)
 {
     DevOpsServer = devopsServer;
     HelixServer  = helixServer;
     AzureUtil    = azureUtil;
     QueryUtil    = new DotNetQueryUtil(DevOpsServer, azureUtil);
 }
Example #17
0
 public AutoTriageUtil(
     DevOpsServer server,
     GitHubClient gitHubClient,
     TriageContext context,
     ILogger logger)
 {
     Server            = server;
     GitHubClient      = gitHubClient;
     QueryUtil         = new DotNetQueryUtil(server);
     TriageContextUtil = new TriageContextUtil(context);
     Logger            = logger;
 }
Example #18
0
        public async Task UpdateDatabaseAsync(int?top = null)
        {
            var builds = await DevOpsServer.ListBuildsAsync(ProjectName, top : top);

            foreach (var build in builds)
            {
                try
                {
                    await UploadBuild(build);
                }
                catch (Exception ex)
                {
                    Logger.LogError($"Unable to upload {build.Id}: {ex.Message}");
                }
            }
        }
Example #19
0
        /// <summary>
        /// List the set of <see cref="TestCaseResult"/> for a given <see cref="TestRun"/>.
        ///
        /// Ideally we could include sub results in the ListTestResultsAsync call because it's a supported parameter of
        /// the ListTestResults AzDO REST API call. Unfortunately there is a bug right now where they are not respecting
        /// that parameter.
        ///
        /// As a fallback for now we simply iterate the results, look for ones that are likely theories, and then request the
        /// results individually. This means we also limit to only failed outcomes bc otherwise we'd be making an additional
        /// API call for every single result. That could be extremely expensive
        /// </summary>
        public static async Task <List <TestCaseResult> > ListTestResultsAsync(
            this DevOpsServer server,
            string project,
            int testRunId,
            TestOutcome[]?outcomes,
            bool includeSubResults,
            Action <Exception>?onError = null)
        {
            var testCaseResults = await server.ListTestResultsAsync(project, testRunId, outcomes : outcomes).ConfigureAwait(false);

            if (includeSubResults)
            {
                var comparer = StringComparer.OrdinalIgnoreCase;
                for (int i = 0; i < testCaseResults.Count; i++)
                {
                    var testCaseResult = testCaseResults[i];
                    if (string.IsNullOrEmpty(testCaseResult.ErrorMessage) && IsFailedOutcome(testCaseResult.Outcome))
                    {
                        try
                        {
                            var otherResult = await server.GetTestCaseResultAsync(project, testRunId, testCaseResult.Id, ResultDetail.SubResults).ConfigureAwait(false);

                            if (otherResult.SubResults is object)
                            {
                                otherResult.SubResults = otherResult
                                                         .SubResults
                                                         .Where(x => IsFailedOutcome(x.Outcome))
                                                         .ToArray();
                            }

                            testCaseResults[i] = otherResult;
                        }
                        catch (Exception ex)
                        {
                            // If we can't fetch the sub-result then just continue
                            onError?.Invoke(ex);
                        }
                    }

                    bool IsFailedOutcome(string outcome) => DotNetUtil.FailedTestOutcomes.Any(x => comparer.Equals(x.ToString(), outcome));
                }
            }

            return(testCaseResults);
        }
Example #20
0
        public async Task GetAttemptOneMissingRecords()
        {
            var handler = new TestableHttpMessageHandler();

            handler.AddJson(
                "https://dev.azure.com/dnceng/public/_apis/build/builds/795146/timeline?api-version=5.0",
                ResourceUtil.GetJsonFile("timeline3.json"));
            handler.AddJson(
                "https://dev.azure.com/dnceng/public/_apis/build/builds/795146/timeline/96ac2280-8cb4-5df5-99de-dd2da759617d?api-version=5.0",
                ResourceUtil.GetJsonFile("timeline3-part1.json"));

            var server   = new DevOpsServer("dnceng", httpClient: new HttpClient(handler));
            var timeline = await server.GetTimelineAttemptAsync("public", 795146, attempt : 1);

            Assert.NotNull(timeline);
            var timelineTree = TimelineTree.Create(timeline !);

            Assert.NotNull(timelineTree);
            Assert.True(timelineTree.TryGetNode("711d63f1-27de-5afd-fdbe-3b9edb784e9f", out var node));
            Assert.Equal(TaskResult.Failed, node !.TimelineRecord.Result);
        }
Example #21
0
        public static async Task <List <DotNetTestRun> > ListDotNetTestRunsAsync(DevOpsServer server, Build build, params TestOutcome[] outcomes)
        {
            var testRuns = await server.ListTestRunsAsync(build.Project.Name, build.Id).ConfigureAwait(false);

            var taskList = new List <Task <DotNetTestRun> >();

            foreach (var testRun in testRuns)
            {
                taskList.Add(GetDotNetTestRunAsync(server, build, testRun, outcomes));
            }

            await Task.WhenAll(taskList);

            var list = new List <DotNetTestRun>();

            foreach (var task in taskList)
            {
                list.Add(task.Result);
            }

            return(list);
Example #22
0
        private static async Task Scratch()
        {
            var server = new DevOpsServer("dnceng", await GetToken("dnceng"));
            var all    = await server.ListArtifactsAsync("internal", 572208);

            var sum = all
                      .Select(x => x.GetByteSize())
                      .Where(x => x.HasValue)
                      .Select(x => (double)x)
                      .Sum();
            var kb = 1_024;
            var mb = kb * kb;
            var gb = mb * kb;

            Console.WriteLine(gb);
            Console.WriteLine(sum / gb);
            foreach (var a in all)
            {
                Console.WriteLine($"{a.Name} {a.GetByteSize()}");
            }
        }
Example #23
0
            static async Task <(Build Build, HelixLogInfo?LogInfo, List <string> BadLogs)> SearchBuild(
                DevOpsServer server,
                DotNetQueryUtil queryUtil,
                Regex textRegex,
                Build build)
            {
                var badLogList = new List <string>();

                try
                {
                    var workItems = await queryUtil
                                    .ListHelixWorkItemsAsync(build, DotNetUtil.FailedTestOutcomes)
                                    .ConfigureAwait(false);

                    foreach (var workItem in workItems)
                    {
                        var logInfo = await HelixUtil.GetHelixLogInfoAsync(server, workItem);

                        if (logInfo.ConsoleUri is object)
                        {
                            var isMatch = await queryUtil.SearchFileForAnyMatchAsync(
                                logInfo.ConsoleUri,
                                textRegex,
                                ex => badLogList.Add($"Unable to search helix logs {build.Id} {workItem.HelixInfo.JobId}, {logInfo.ConsoleUri}: {ex.Message}")).ConfigureAwait(false);

                            if (isMatch)
                            {
                                return(build, logInfo, badLogList);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    badLogList.Add($"Unable to search helix logs for {build.Id}:  {ex.Message}");
                }

                return(build, null, badLogList);
            }
Example #24
0
        public StandardTestBase(ITestOutputHelper testOutputHelper)
        {
            Connection = CreateInMemoryDatabase();
            var options = new DbContextOptionsBuilder <TriageContext>()
                          .UseSqlite(Connection)
                          .Options;

            Context                     = new TriageContext(options);
            TriageContextUtil           = new TriageContextUtil(Context);
            TestableHttpMessageHandler  = new TestableHttpMessageHandler();
            TestableLogger              = new TestableLogger(testOutputHelper);
            TestableGitHubClientFactory = new TestableGitHubClientFactory();

            var httpClient = new HttpClient(TestableHttpMessageHandler);

            Server      = new DevOpsServer("random", httpClient: httpClient);
            HelixServer = new HelixServer(httpClient: httpClient);
            QueryUtil   = new DotNetQueryUtil(Server);

            Context.Database.EnsureDeleted();
            Context.Database.EnsureCreated();
        }
Example #25
0
        public async Task UploadBuildAsync(int buildId)
        {
            var build = await DevOpsServer.GetBuildAsync(ProjectName, buildId);

            await UploadBuild(build);
        }
Example #26
0
        public static async Task <Dictionary <HelixInfo, HelixLogInfo> > GetHelixMapAsync(this DevOpsServer server, IEnumerable <DotNetTestCaseResult> testCaseResults)
        {
            var query = testCaseResults
                        .Where(x => x.HelixWorkItem.HasValue)
                        .Select(x => x.HelixWorkItem !.Value)
                        .GroupBy(x => x.HelixInfo)
                        .ToList()
                        .AsParallel()
                        .Select(async g => (g.Key, await HelixUtil.GetHelixLogInfoAsync(server, g.First())));
            await Task.WhenAll(query).ConfigureAwait(false);

            return(query.ToDictionary(x => x.Result.Key, x => x.Result.Item2));
        }
Example #27
0
 public static Task <Dictionary <HelixInfo, HelixLogInfo> > GetHelixMapAsync(this DevOpsServer server, DotNetTestRun testRun) =>
 GetHelixMapAsync(server, testRun.TestCaseResults);
Example #28
0
        public static Task <List <Timeline> > ListTimelineAttemptsAsync(this DevOpsServer server, string project, int buildNumber)
        {
            IAzureUtil azureUtil = new AzureUtil(server);

            return(azureUtil.ListTimelineAttemptsAsync(project, buildNumber));
        }
Example #29
0
 public CloneTimeUtil(string sqlConnectionString, ILogger logger = null)
 {
     Logger        = logger ?? DotNetUtil.CreateConsoleLogger();
     DevOpsServer  = new DevOpsServer("dnceng");
     SqlConnection = new SqlConnection(sqlConnectionString);
 }
Example #30
0
 public async Task <List <Build> > ListBuildsAsync(int top) => await DevOpsServer.ListBuildsAsync(ProjectName, new[] { BuildDefinitionId }, top : top);