Example #1
0
        public async Task CollectStages(ScorecardBuildBreakdown buildBreakdown)
        {
            string timelineLinkWithAttempts = $"{buildBreakdown.BuildSummary.TimelineLink}?changeId=1";

            Utilities.WriteDebug($"Querying AzDO API: {timelineLinkWithAttempts}", Log, LogLevel);
            JObject jsonTimelineResponse = await GetAzdoApiResponseAsync(timelineLinkWithAttempts);

            BuildTimeline timeline = jsonTimelineResponse.ToObject <BuildTimeline>();

            if (timeline.Records != null)
            {
                // We're going to use this to store previous attempts as we find them
                Dictionary <string, BuildTimeline> previousAttemptTimelines = new Dictionary <string, BuildTimeline>();

                foreach (BuildTimelineEntry record in timeline.Records)
                {
                    // We measure times at the stage level because this is the simplest thing to do
                    // By taking the min start time and max end time of all the stages except for the ones we exclude,
                    // we can determine a pretty accurate measurement of how long it took to rollout
                    if ((record.Type == "Checkpoint.Approval" || record.Type == "Stage") && !RepoConfig.ExcludeStages.Any(s => s == record.Name))
                    {
                        buildBreakdown.BuildSummary.Stages.Add(record);

                        if (record.PreviousAttempts.Count > 0)
                        {
                            // we're going to just add these attempts as additional stages
                            foreach (PreviousAttempt attempt in record.PreviousAttempts)
                            {
                                if (!previousAttemptTimelines.ContainsKey(attempt.TimelineId))
                                {
                                    previousAttemptTimelines.Add(attempt.TimelineId,
                                                                 (await GetAzdoApiResponseAsync($"{buildBreakdown.BuildSummary.TimelineLink}/{attempt.TimelineId}")).ToObject <BuildTimeline>());
                                }

                                if (previousAttemptTimelines[attempt.TimelineId] != null)
                                {
                                    buildBreakdown.BuildSummary.Stages.Add(previousAttemptTimelines[attempt.TimelineId].Records
                                                                           .Where(t => (t.Type == "Checkpoint.Approval" || t.Type == "Stage") && t.Name == record.Name).First());
                                }
                            }
                        }
                    }
                }

                if (buildBreakdown.BuildSummary.Stages.Any(s => s.Name.StartsWith("deploy", StringComparison.InvariantCultureIgnoreCase) && !string.IsNullOrEmpty(s.EndTime)))
                {
                    buildBreakdown.BuildSummary.DeploymentReached = true;
                    Utilities.WriteDebug($"Build {buildBreakdown.BuildSummary.BuildNumber} determined to have reached deployment.", Log, LogLevel);
                }
                else
                {
                    Utilities.WriteDebug($"Build {buildBreakdown.BuildSummary.BuildNumber} determined to NOT have reached deployment.", Log, LogLevel);
                }
            }
        }
Example #2
0
        /// <summary>
        /// Calculates the "Time to Rollout" portion of the scorecard
        /// </summary>
        /// <returns>A timespan representing the total time to rollout and a list of scorecard build breakdowns for each rollout</returns>
        public async Task <TimeSpan> CalculateTimeToRolloutAsync()
        {
            List <TimeSpan> rolloutBuildTimes = new List <TimeSpan>();

            // Loop over all the builds in the returned content and calculate start and end times
            foreach (ScorecardBuildBreakdown build in BuildBreakdowns)
            {
                TimeSpan duration = TimeSpan.Zero;
                string   timelineLinkWithAttempts = $"{build.BuildSummary.TimelineLink}?changeId=1";
                JObject  jsonTimelineResponse     = await GetAzdoApiResponseAsync(timelineLinkWithAttempts);

                BuildTimeline timeline = jsonTimelineResponse.ToObject <BuildTimeline>();

                // We're going to use this to store previous attempts as we find them
                Dictionary <string, BuildTimeline> previousAttemptTimelines = new Dictionary <string, BuildTimeline>();

                if (timeline.Records != null)
                {
                    List <BuildTimelineEntry> stages = new List <BuildTimelineEntry>();
                    List <BuildTimelineEntry> approvalCheckpoints = new List <BuildTimelineEntry>();

                    foreach (BuildTimelineEntry record in timeline.Records)
                    {
                        // We measure times at the stage level because this is the simplest thing to do
                        // By taking the min start time and max end time of all the stages except for the ones we exclude,
                        // we can determine a pretty accurate measurement of how long it took to rollout
                        if ((record.Type == "Checkpoint.Approval" || record.Type == "Stage") && !RepoConfig.ExcludeStages.Any(s => s == record.Name))
                        {
                            stages.Add(record);

                            if (record.PreviousAttempts.Count > 0)
                            {
                                // we're going to just add these attempts as additional stages
                                foreach (PreviousAttempt attempt in record.PreviousAttempts)
                                {
                                    if (!previousAttemptTimelines.ContainsKey(attempt.TimelineId))
                                    {
                                        previousAttemptTimelines.Add(attempt.TimelineId,
                                                                     (await GetAzdoApiResponseAsync($"{build.BuildSummary.TimelineLink}/{attempt.TimelineId}")).ToObject <BuildTimeline>());
                                    }

                                    if (previousAttemptTimelines[attempt.TimelineId] != null)
                                    {
                                        stages.Add(previousAttemptTimelines[attempt.TimelineId].Records
                                                   .Where(t => (t.Type == "Checkpoint.Approval" || t.Type == "Stage") && t.Name == record.Name).First());
                                    }
                                }
                            }
                        }
                    }
                    duration = GetPipelineDurationFromStages(stages);

                    if (stages.Any(s => s.Name.StartsWith("deploy", StringComparison.InvariantCultureIgnoreCase) && !string.IsNullOrEmpty(s.EndTime)))
                    {
                        build.BuildSummary.DeploymentReached = true;
                    }
                }
                rolloutBuildTimes.Add(duration);
                build.Score.TimeToRollout = duration;
            }

            return(new TimeSpan(rolloutBuildTimes.Sum(t => t.Ticks)));
        }