Ejemplo n.º 1
0
        public bool DetermineFailure()
        {
            Utilities.WriteDebug($"Determining failure for {Repo}...", Log, LogLevel);
            if (BuildBreakdowns.Count == 0)
            {
                Utilities.WriteDebug($"No builds found for {Repo} this rollout; rollout marked as FAILED.", Log, LogLevel);
                return(true);
            }

            ScorecardBuildBreakdown lastBuild = BuildBreakdowns.Last();

            Utilities.WriteDebug($"Last build is for {Repo} is {lastBuild.BuildSummary.BuildNumber} ({lastBuild.BuildSummary.WebLink})", Log, LogLevel);

            if (lastBuild.Score.Rollbacks == 1)
            {
                Utilities.WriteDebug($"Last build ({lastBuild.BuildSummary.BuildNumber}) was a rollback; rollout marked as FAILED.", Log, LogLevel);
                return(true);
            }

            string lastBuildResult = lastBuild.BuildSummary.Result;

            Utilities.WriteDebug($"Build {lastBuild.BuildSummary.BuildNumber} has result '{lastBuildResult}'", Log, LogLevel);
            switch (lastBuildResult)
            {
            case "succeeded":
            case "partiallySucceeded":
                Utilities.WriteDebug($"Last build determined successful.", Log, LogLevel);
                return(false);

            default:
                Utilities.WriteDebug($"Last build determined unsuccessful; rollout marked as FAILED.", Log, LogLevel);
                return(true);
            }
        }
Ejemplo n.º 2
0
        public async Task InitAsync()
        {
            // Convert the rollout start time and end time to the strings the AzDO API recognizes and fetch builds
            string rolloutStartTimeUriString = RolloutStartDate.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ");
            string rolloutEndTimeUriString   = RolloutEndDate.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ");

            foreach (string buildDefinitionId in RepoConfig.BuildDefinitionIds)
            {
                string azdoQuery = $"https://dev.azure.com/{RepoConfig.AzdoInstance}/" +
                                   $"{AzdoConfig.Project}/_apis/build/builds?definitions={buildDefinitionId}&branchName={Branch}" +
                                   $"&minTime={rolloutStartTimeUriString}&maxTime={rolloutEndTimeUriString}&api-version=5.1";
                Utilities.WriteDebug($"Querying AzDO API: {azdoQuery}", Log, LogLevel);
                JObject responseContent = await GetAzdoApiResponseAsync(azdoQuery);

                // No builds is a valid case (e.g. a failed rollout) and so the rest of the code can handle this
                // It still is potentially unexpected, so we're going to warn the user here
                if (responseContent.Value <int>("count") == 0)
                {
                    Utilities.WriteWarning($"No builds were found for repo '{RepoConfig.Repo}' " +
                                           $"(Build ID: '{buildDefinitionId}') during the specified dates ({RolloutStartDate} to {RolloutEndDate})", Log);
                }

                JArray builds = responseContent.Value <JArray>("value");
                foreach (JToken build in builds)
                {
                    BuildBreakdowns.Add(new ScorecardBuildBreakdown(build.ToObject <BuildSummary>()));
                }
            }
            BuildBreakdowns = BuildBreakdowns.OrderBy(x => x.BuildSummary.FinishTime).ToList();
            Utilities.WriteDebug($"Builds breakdowns created for: \n\t {string.Join(" \n\t ", BuildBreakdowns.Select(b => b?.BuildSummary?.WebLink ?? ""))}", Log, LogLevel);

            await Task.WhenAll(BuildBreakdowns.Select(b => CollectStages(b)));
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Calculates and returns the number of hotfixes and rollouts that occurred as part of the build
        /// </summary>
        /// <returns>The number of hotfixes and rollbacks which occurred as part of the rollout</returns>
        public async Task <(int numHotfixes, int numRollbacks)> CalculateNumHotfixesAndRollbacksFromAzdoAsync()
        {
            // Any attempt to figure out whether a deployment succeeded or failed will be inherently flawed
            // The process used here is as follows:
            //   * Find the first build where a deployment stage was reached; assume this means some sort of deployment happened
            //   * Every build after that also makes it to deployment (and is tagged "HOTFIX" when --assume-no-tags is not set) is a hotfix

            int numHotfixes  = 0;
            int numRollbacks = 0;

            // This is a list of all builds that were part of this rollout which reached a deployment stage
            // We skip the first deployment because only things after that one can be hotfixes or rollbacks
            IEnumerable <ScorecardBuildBreakdown> buildsToCheck = BuildBreakdowns.Where(b => b.BuildSummary.DeploymentReached).Skip(1);

            foreach (ScorecardBuildBreakdown build in buildsToCheck)
            {
                BuildSource source = (await GetAzdoApiResponseAsync(build.BuildSummary.SourceLink)).ToObject <BuildSource>();

                // we can only automatically calculate rollbacks if they're tagged; so we specifically don't try when --assume-no-tags is passed
                if (!AssumeNoTags && source.Comment.Contains(AzureDevOpsCommitTags.RollbackTag, StringComparison.InvariantCultureIgnoreCase))
                {
                    numRollbacks++;
                    build.Score.Rollbacks = 1;
                    Utilities.WriteDebug($"Build {build.BuildSummary.BuildNumber} determined to be a ROLLBACK with commit message '{source.Comment}'", Log, LogLevel);
                    Utilities.WriteDebug($"Web link: {build.BuildSummary.WebLink}", Log, LogLevel);
                }
                // if we're assuming no tags, every deployment after the first is assumed to be a hotfix; otherwise we need to look specifically for the hotfix tag
                else if (AssumeNoTags || source.Comment.Contains(AzureDevOpsCommitTags.HotfixTag, StringComparison.InvariantCultureIgnoreCase))
                {
                    numHotfixes++;
                    build.Score.Hotfixes = 1;
                    Utilities.WriteDebug($"Build {build.BuildSummary.BuildNumber} determined to be a HOTFIX with commit message '{source.Comment}'", Log, LogLevel);
                    Utilities.WriteDebug($"Web link: {build.BuildSummary.WebLink}", Log, LogLevel);
                }
                // if none of these caught this deployment, then there's an untagged deployment when tags should be present; we'll warn the user about this
                else if (!source.Comment.Contains(AzureDevOpsCommitTags.RolloutTag, StringComparison.InvariantCultureIgnoreCase))
                {
                    Utilities.WriteWarning($"Untagged deployment found: build number '{build.BuildSummary.BuildNumber}' with commit message '{source.Comment}'", Log);
                    Utilities.WriteWarning($"Web link: {build.BuildSummary.WebLink}", Log);
                }
            }
            numHotfixes  += ManualHotfixes;
            numRollbacks += ManualRollbacks;
            Utilities.WriteDebug($"Detected {numHotfixes} hotfixes ({ManualHotfixes} manual) and {numRollbacks} rollbacks ({ManualRollbacks} manual).", Log, LogLevel);

            return(numHotfixes, numRollbacks);
        }
Ejemplo n.º 4
0
        public bool DetermineFailure()
        {
            if (BuildBreakdowns.Count == 0)
            {
                return(true);
            }

            string lastBuildResult = BuildBreakdowns.Last().BuildSummary.Result;

            switch (lastBuildResult)
            {
            case "succeeded":
            case "partiallySucceeded":
                return(false);

            default:
                return(true);
            }
        }
Ejemplo n.º 5
0
        public bool DetermineFailure(List <Issue> githubIssues)
        {
            Utilities.WriteDebug($"Determining failure for {Repo}...", Log, LogLevel);
            if (githubIssues.Any(i => Utilities.IssueContainsRelevantLabels(i, GithubLabelNames.FailureLabel, RepoConfig.GithubIssueLabel, Log, LogLevel)))
            {
                Utilities.WriteDebug($"Issue with failure tag found for {Repo}; rollout marked as FAILED", Log, LogLevel);
                return(true);
            }

            if (BuildBreakdowns.Count == 0)
            {
                Utilities.WriteDebug($"No builds found for {Repo} this rollout; rollout marked as FAILED.", Log, LogLevel);
                return(true);
            }

            ScorecardBuildBreakdown lastBuild = BuildBreakdowns.Last();

            Utilities.WriteDebug($"Last build is for {Repo} is {lastBuild.BuildSummary.BuildNumber} ({lastBuild.BuildSummary.WebLink})", Log, LogLevel);

            if (lastBuild.Score.Rollbacks == 1)
            {
                Utilities.WriteDebug($"Last build ({lastBuild.BuildSummary.BuildNumber}) was a rollback; rollout marked as FAILED.", Log, LogLevel);
                return(true);
            }

            string lastBuildResult = lastBuild.BuildSummary.Result;

            Utilities.WriteDebug($"Build {lastBuild.BuildSummary.BuildNumber} has result '{lastBuildResult}'", Log, LogLevel);
            switch (lastBuildResult)
            {
            case "succeeded":
            case "partiallySucceeded":
                Utilities.WriteDebug($"Last build determined successful.", Log, LogLevel);
                return(false);

            default:
                Utilities.WriteDebug($"Last build determined unsuccessful; rollout marked as FAILED.", Log, LogLevel);
                return(true);
            }
        }
Ejemplo n.º 6
0
        public async Task InitAsync()
        {
            // Convert the rollout start time and end time to the strings the AzDO API recognizes and fetch builds
            string  rolloutStartTimeUriString = RolloutStartDate.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ");
            string  rolloutEndTimeUriString   = RolloutEndDate.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ");
            JObject responseContent           = await GetAzdoApiResponseAsync($"https://dev.azure.com/{RepoConfig.AzdoInstance}/" +
                                                                              $"{AzdoConfig.Project}/_apis/build/builds?definitions={RepoConfig.DefinitionId}&branchName={Branch}" +
                                                                              $"&minTime={rolloutStartTimeUriString}&maxTime={rolloutEndTimeUriString}&api-version=5.1");

            // No builds is a valid case (e.g. a failed rollout) and so the rest of the code can handle this
            // It still is potentially unexpected, so we're going to warn the user here
            if (responseContent.Value <int>("count") == 0)
            {
                Utilities.WriteWarning($"No builds were found for repo '{RepoConfig.Repo}' " +
                                       $"(Build ID: '{RepoConfig.DefinitionId}') during the specified dates ({RolloutStartDate} to {RolloutEndDate})", Log);
            }

            JArray builds = responseContent.Value <JArray>("value");

            foreach (JToken build in builds)
            {
                BuildBreakdowns.Add(new ScorecardBuildBreakdown(build.ToObject <BuildSummary>()));
            }
        }
Ejemplo n.º 7
0
 public bool DetermineFailure()
 {
     return(BuildBreakdowns.Count == 0 || BuildBreakdowns.Last().BuildSummary.Result != "succeeded");
 }