| File: Models\CollectionModels.cs | Web Access |
| Project: src\tools\AnalyzeCiFailure\AnalyzeCiFailure.csproj (AnalyzeCiFailure) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Immutable; using System.Text.Json; using System.Text; using System.Text.Json.Serialization; namespace AnalyzeCiFailure; /// <summary>Selects the repository, workflow run and optional pinned attempt to acquire.</summary> internal sealed record EvidenceCollectionRequest(string Repository, long RunId, int? Attempt); /// <summary>Distinguishes optional-context issues, missing test evidence and fatal invocation failures.</summary> internal enum AnalysisProblemCategory { OptionalContext, TestEvidence, Fatal } /// <summary>Associates a recorded problem with the policy that determines its effect on analysis completeness.</summary> internal sealed record CategorizedProblem(AnalysisProblemCategory Category, AnalysisProblem Problem); /// <summary>Groups acquired evidence, raw attachments and the historical catalogue before diagnosis-context projection.</summary> internal sealed record CollectedRun( EvidenceBundle Evidence, ImmutableDictionary<string, CollectedAttachment> Attachments, ImmutableArray<PriorCauseIndexEntry> PriorCauses) { internal ImmutableDictionary<string, JsonElement> JsonContext { get; init; } = ImmutableDictionary<string, JsonElement>.Empty; } /// <summary>Distinguishes a collected run from a legitimate no-relevant-failures acquisition result.</summary> internal sealed record EvidenceCollectionResult(CollectedRun? Run, bool HasRelevantFailures); /// <summary>Groups trusted evidence, agent-facing context and the complete historical catalogue for package writing.</summary> internal sealed record DiagnosisInput( EvidenceBundle Evidence, string Summary, ImmutableArray<PriorCauseIndexEntry> Catalogue, ImmutableDictionary<string, CollectedAttachment> Attachments, ImmutableDictionary<string, JsonElement> JsonContext); // Keep full-record bytes even when an unselected historical record cannot be decoded. /// <summary>Retains complete captured bytes and exposes BOM-aware text without rewriting the original attachment.</summary> internal sealed record CollectedAttachment(ImmutableArray<byte> Bytes) { internal string Text { get { // Match the existing durable file reader's BOM handling without re-encoding its bytes. using var stream = new MemoryStream(Bytes.ToArray(), writable: false); using var reader = new StreamReader(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks: true); return reader.ReadToEnd(); } } internal static CollectedAttachment FromText(string text) => new(Encoding.UTF8.GetBytes(text).ToImmutableArray()); } /// <summary>Tracks tri-state failure discovery, established run identity, phase progress and retained problems.</summary> internal sealed class AnalysisProgress { internal bool? HasRelevantFailures { get; set; } internal long? RunId { get; set; } internal int? RunAttempt { get; set; } internal string? HeadSha { get; set; } internal string? RunUrl { get; set; } internal RunScope? RunScope { get; set; } internal long? SubjectPrNumber { get; set; } internal AnalysisDiagnostics Diagnostics { get; } = new(); internal string Stage { get => Diagnostics.Stage; set => Diagnostics.EnterStage(value); } internal List<CategorizedProblem> Problems { get; } = []; internal void RecordProblem(AnalysisProblemCategory category, string stage, string message) { var problem = new AnalysisProblem { Stage = stage, Message = CiFailureJson.Display(DiagnosticTextSanitizer.Sanitize(message, limit: 500)), }; Problems.Add(new(category, problem)); Diagnostics.ReportProblem(category, problem); } internal AnalysisOutcome CreateOutcome(string status) => new() { SchemaVersion = 1, Status = status, HasRelevantFailures = HasRelevantFailures, RunId = RunId, RunAttempt = RunAttempt, HeadSha = HeadSha, RunUrl = RunUrl, RunScope = RunScope, SubjectPrNumber = SubjectPrNumber, Problems = Problems.Select(problem => problem.Problem).ToImmutableArray(), }; } /// <summary>Serializes an invocation's established run facts, terminal status and problems without authorizing effects.</summary> internal sealed record AnalysisOutcome { public required int SchemaVersion { get; init; } public required string Status { get; init; } [JsonPropertyName("has_work")] public required bool? HasRelevantFailures { get; init; } public required long? RunId { get; init; } public required int? RunAttempt { get; init; } public required string? HeadSha { get; init; } public required string? RunUrl { get; init; } public required RunScope? RunScope { get; init; } public required long? SubjectPrNumber { get; init; } public required ImmutableArray<AnalysisProblem> Problems { get; init; } }