- Added `FilesystemPackRunProvenanceWriter` to write provenance manifests to the filesystem. - Introduced `MongoPackRunArtifactReader` to read artifacts from MongoDB. - Created `MongoPackRunProvenanceWriter` to store provenance manifests in MongoDB. - Developed unit tests for filesystem and MongoDB provenance writers. - Established `ITimelineEventStore` and `ITimelineIngestionService` interfaces for timeline event handling. - Implemented `TimelineIngestionService` to validate and persist timeline events with hashing. - Created PostgreSQL schema and migration scripts for timeline indexing. - Added dependency injection support for timeline indexer services. - Developed tests for timeline ingestion and schema validation.
76 lines
2.3 KiB
C#
76 lines
2.3 KiB
C#
using System.Text.Json;
|
|
using StellaOps.TaskRunner.Core.Execution;
|
|
|
|
namespace StellaOps.TaskRunner.Infrastructure.Execution;
|
|
|
|
public sealed class FilesystemPackRunArtifactReader : IPackRunArtifactReader
|
|
{
|
|
private static readonly JsonSerializerOptions SerializerOptions = new(JsonSerializerDefaults.Web);
|
|
|
|
private readonly string rootPath;
|
|
|
|
public FilesystemPackRunArtifactReader(string rootPath)
|
|
{
|
|
ArgumentException.ThrowIfNullOrWhiteSpace(rootPath);
|
|
this.rootPath = Path.GetFullPath(rootPath);
|
|
}
|
|
|
|
public async Task<IReadOnlyList<PackRunArtifactRecord>> ListAsync(string runId, CancellationToken cancellationToken)
|
|
{
|
|
ArgumentException.ThrowIfNullOrWhiteSpace(runId);
|
|
|
|
var manifestPath = Path.Combine(rootPath, Sanitize(runId), "artifact-manifest.json");
|
|
if (!File.Exists(manifestPath))
|
|
{
|
|
return Array.Empty<PackRunArtifactRecord>();
|
|
}
|
|
|
|
await using var stream = File.OpenRead(manifestPath);
|
|
var manifest = await JsonSerializer.DeserializeAsync<ArtifactManifest>(stream, SerializerOptions, cancellationToken)
|
|
.ConfigureAwait(false);
|
|
|
|
if (manifest is null || manifest.Outputs is null)
|
|
{
|
|
return Array.Empty<PackRunArtifactRecord>();
|
|
}
|
|
|
|
return manifest.Outputs
|
|
.OrderBy(output => output.Name, StringComparer.Ordinal)
|
|
.Select(output => new PackRunArtifactRecord(
|
|
output.Name,
|
|
output.Type,
|
|
output.SourcePath,
|
|
output.StoredPath,
|
|
output.Status,
|
|
output.Notes,
|
|
manifest.UploadedAt,
|
|
output.ExpressionJson))
|
|
.ToList();
|
|
}
|
|
|
|
private static string Sanitize(string value)
|
|
{
|
|
var safe = value.Trim();
|
|
foreach (var invalid in Path.GetInvalidFileNameChars())
|
|
{
|
|
safe = safe.Replace(invalid, '_');
|
|
}
|
|
|
|
return string.IsNullOrWhiteSpace(safe) ? "run" : safe;
|
|
}
|
|
|
|
private sealed record ArtifactManifest(
|
|
string RunId,
|
|
DateTimeOffset UploadedAt,
|
|
List<ArtifactRecord> Outputs);
|
|
|
|
private sealed record ArtifactRecord(
|
|
string Name,
|
|
string Type,
|
|
string? SourcePath,
|
|
string? StoredPath,
|
|
string Status,
|
|
string? Notes,
|
|
string? ExpressionJson);
|
|
}
|