/// <summary> /// Update the table storage to contain the result of the specified build. /// </summary> private async Task <BuildResultEntity> GetBuildFailureEntity(BuildId id) { var buildInfo = await _client.GetBuildInfoAsync(id); var jobKind = await _client.GetJobKindAsync(id.JobId); PullRequestInfo prInfo = null; if (JobUtil.IsPullRequestJobName(id.JobId.Name)) { try { prInfo = await _client.GetPullRequestInfoAsync(id); } catch (Exception ex) { // TODO: Flow builds don't have the PR directly in the triggered jobs. Have to walk // back up to the parent job. For now swallow this error so we don't trigger false // positives in the error detection. _textWriter.WriteLine($"Error pulling PR info for {id}: {ex.Message}"); } } BuildResultClassification classification; switch (buildInfo.State) { case BuildState.Succeeded: classification = BuildResultClassification.Succeeded; break; case BuildState.Aborted: classification = BuildResultClassification.Aborted; break; case BuildState.Failed: classification = await PopulateFailedBuildResult(buildInfo, jobKind, prInfo); break; case BuildState.Running: classification = BuildResultClassification.Unknown; break; default: throw new Exception($"Invalid enum: {buildInfo.State} for {id.JobName} - {id.Number}"); } return(new BuildResultEntity( buildInfo.Id, buildInfo.Date, buildInfo.Duration, jobKind: jobKind, machineName: buildInfo.MachineName, classification: classification, prInfo: prInfo)); }
private static async Task QueueBuildAsync(IQueueJenkinsBuildArgs args, CancellationToken cancellationToken) { args.LogInformation($"Queueing build for job \"{args.JobName}\"{IfHasValue(args.BranchName, $" on branch \"{args.BranchName}\"")}..."); var client = new JenkinsClient(args.UserName, args.Password, args.ServerUrl, args.CsrfProtectionEnabled, args, cancellationToken); var queueItem = await client.TriggerBuildAsync(args.JobName, args.BranchName, args.AdditionalParameters).ConfigureAwait(false); args.LogInformation($"Jenkins build queued successfully."); args.LogDebug($"Queue item number: {queueItem}"); if (!args.WaitForStart && !args.WaitForCompletion) { args.LogDebug("The operation is not configured to wait for the build to start."); return; } string buildNumber; string lastReason = null; while (true) { await Task.Delay(2 * 1000, cancellationToken).ConfigureAwait(false); var info = await client.GetQueuedBuildInfoAsync(queueItem).ConfigureAwait(false); if (!string.IsNullOrEmpty(info.BuildNumber)) { buildNumber = info.BuildNumber; args.JenkinsBuildNumber = buildNumber; args.LogInformation($"Build number is {buildNumber}."); break; } if (!string.Equals(lastReason, info.WaitReason)) { args.LogDebug($"Waiting for build to start... ({info.WaitReason})"); lastReason = info.WaitReason; } args.SetProgress(new OperationProgress(null, info.WaitReason)); } if (args.WaitForCompletion) { args.LogInformation($"Waiting for build {buildNumber} to complete..."); JenkinsBuild build; int attempts = 5; while (true) { await Task.Delay(2 * 1000, cancellationToken).ConfigureAwait(false); build = await client.GetBuildInfoAsync(args.JobName, args.BranchName, buildNumber).ConfigureAwait(false); if (build == null) { args.LogDebug("Build information was not returned."); if (attempts > 0) { args.LogDebug($"Reloading build data ({attempts} attempts remaining)..."); attempts--; continue; } break; } // reset retry counter attempts = 5; if (!build.Building) { args.LogDebug("Build has finished building."); args.SetProgress(new OperationProgress(100)); break; } args.SetProgress(ComputeProgress(build)); } if (string.Equals("success", build?.Result, StringComparison.OrdinalIgnoreCase)) { args.LogDebug("Build status returned: success"); } else { args.LogError("Build not not report success; result was: " + (build?.Result ?? "<not returned>")); } } else { args.LogDebug("The operation is not configured to wait for build completion."); } }