< Summary

Information
Class: Orchestrator.Commands.Utility.UploadKpi.UploadKpiCommand
Assembly: Orchestrator
File(s): /home/runner/work/KicktippAi/KicktippAi/src/Orchestrator/Commands/Utility/UploadKpi/UploadKpiCommand.cs
Line coverage
100%
Covered lines: 69
Uncovered lines: 0
Coverable lines: 69
Total lines: 149
Line coverage: 100%
Branch coverage
100%
Covered branches: 20
Total branches: 20
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
ExecuteAsync()100%2020100%
.ctor()100%11100%

File(s)

/home/runner/work/KicktippAi/KicktippAi/src/Orchestrator/Commands/Utility/UploadKpi/UploadKpiCommand.cs

#LineLine coverage
 1using Microsoft.Extensions.DependencyInjection;
 2using Microsoft.Extensions.FileProviders;
 3using Microsoft.Extensions.Logging;
 4using Spectre.Console.Cli;
 5using Spectre.Console;
 6using System.Text.Json;
 7using EHonda.KicktippAi.Core;
 8using Orchestrator.Infrastructure;
 9using Orchestrator.Infrastructure.Factories;
 10
 11namespace Orchestrator.Commands.Utility.UploadKpi;
 12
 13public class UploadKpiCommand : AsyncCommand<UploadKpiSettings>
 14{
 15    private readonly IAnsiConsole _console;
 16    private readonly IFirebaseServiceFactory _firebaseServiceFactory;
 17    private readonly IFileProvider _fileProvider;
 18    private readonly ILogger<UploadKpiCommand> _logger;
 19
 120    public UploadKpiCommand(
 121        IAnsiConsole console,
 122        IFirebaseServiceFactory firebaseServiceFactory,
 123        [FromKeyedServices(ServiceRegistrationExtensions.KpiDocumentsFileProviderKey)] IFileProvider fileProvider,
 124        ILogger<UploadKpiCommand> logger)
 25    {
 126        _console = console;
 127        _firebaseServiceFactory = firebaseServiceFactory;
 128        _fileProvider = fileProvider;
 129        _logger = logger;
 130    }
 31
 32    protected override async Task<int> ExecuteAsync(CommandContext context, UploadKpiSettings settings, CancellationToke
 33    {
 34        try
 35        {
 136            _console.MarkupLine($"[green]Upload KPI command initialized for document:[/] [yellow]{settings.DocumentName}
 137            _console.MarkupLine($"[blue]Using community context:[/] [yellow]{settings.CommunityContext}[/]");
 138            var competition = CompetitionResolver.ResolveCompetition(settings.Competition, settings.CommunityContext, se
 139            var repositoryCompetition = CompetitionResolver.ToRepositoryCompetitionArgument(competition);
 140            _console.MarkupLine($"[blue]Using competition:[/] [yellow]{competition}[/]");
 41
 142            if (settings.Verbose)
 43            {
 144                _console.MarkupLine("[dim]Verbose mode enabled[/]");
 45            }
 46
 47            // Check if the JSON file exists in the community-context specific subfolder
 148            var jsonFilePath = $"output/{settings.CommunityContext}/{settings.DocumentName}.json";
 149            var fileInfo = _fileProvider.GetFileInfo(jsonFilePath);
 150            if (!fileInfo.Exists)
 51            {
 152                _console.MarkupLine($"[red]KPI document file not found:[/] {jsonFilePath}");
 153                _console.MarkupLine($"[dim]Run the PowerShell script with firebase mode to create the document first.[/]
 154                return 1;
 55            }
 56
 157            _console.MarkupLine($"[blue]Reading KPI document from:[/] {jsonFilePath}");
 58
 59            // Read and parse the JSON file
 160            using var stream = fileInfo.CreateReadStream();
 161            var kpiDocument = await JsonSerializer.DeserializeAsync<KpiDocumentJson>(stream, new JsonSerializerOptions
 162            {
 163                PropertyNameCaseInsensitive = true
 164            });
 65
 166            if (kpiDocument == null)
 67            {
 168                _console.MarkupLine("[red]Failed to parse KPI document JSON[/]");
 169                return 1;
 70            }
 71
 172            if (settings.Verbose)
 73            {
 174                _console.MarkupLine($"[dim]Document Name: {kpiDocument.DocumentName}[/]");
 175                _console.MarkupLine($"[dim]Community Context: {kpiDocument.CommunityContext}[/]");
 176                _console.MarkupLine($"[dim]Content length: {kpiDocument.Content.Length} characters[/]");
 77            }
 78
 79            // Create Firebase services using factory (factory handles env var loading)
 180            var kpiRepository = _firebaseServiceFactory.CreateKpiRepository(repositoryCompetition);
 81
 82            // Check if document already exists for this community context
 183            var existingDocument = await kpiRepository.GetKpiDocumentAsync(kpiDocument.DocumentName, kpiDocument.Communi
 84
 185            if (existingDocument != null)
 86            {
 187                _console.MarkupLine($"[blue]Found existing KPI document '{kpiDocument.DocumentName}' (version {existingD
 188                _console.MarkupLine($"[blue]Checking for content changes...[/]");
 89
 190                if (settings.Verbose)
 91                {
 192                    _console.MarkupLine($"[dim]Current content length: {existingDocument.Content.Length} characters[/]")
 193                    _console.MarkupLine($"[dim]New content length: {kpiDocument.Content.Length} characters[/]");
 94                }
 95            }
 96            else
 97            {
 198                _console.MarkupLine($"[blue]No existing KPI document found for '{kpiDocument.DocumentName}' - will creat
 99            }
 100
 101            // Upload the document (versioning is handled automatically by the repository)
 1102            _console.MarkupLine($"[blue]Processing KPI document...[/]");
 103
 1104            var savedVersion = await kpiRepository.SaveKpiDocumentAsync(
 1105                kpiDocument.DocumentName,
 1106                kpiDocument.Content,
 1107                kpiDocument.Description,
 1108                kpiDocument.CommunityContext);
 109
 1110            if (existingDocument != null && savedVersion == existingDocument.Version)
 111            {
 1112                _console.MarkupLine($"[green]✓ Content unchanged - KPI document '[/][white]{kpiDocument.DocumentName}[/]
 113            }
 1114            else if (existingDocument != null)
 115            {
 1116                _console.MarkupLine($"[green]✓ Content changed - Created new version {savedVersion} for KPI document '[/
 117            }
 118            else
 119            {
 1120                _console.MarkupLine($"[green]✓ Successfully created KPI document '[/][white]{kpiDocument.DocumentName}[/
 121            }
 122
 1123            if (settings.Verbose)
 124            {
 1125                _console.MarkupLine($"[dim]Document saved to unified kpi-documents collection with community context: {k
 1126                _console.MarkupLine($"[dim]Document version: {savedVersion}[/]");
 127            }
 128
 1129            return 0;
 130        }
 1131        catch (Exception ex)
 132        {
 1133            _logger.LogError(ex, "Error in upload-kpi command");
 1134            _console.MarkupLine($"[red]Error: {ex.Message}[/]");
 1135            return 1;
 136        }
 1137    }
 138
 139    /// <summary>
 140    /// JSON model for deserializing KPI document files.
 141    /// </summary>
 142    private class KpiDocumentJson
 143    {
 1144        public string DocumentName { get; set; } = string.Empty;
 1145        public string Content { get; set; } = string.Empty;
 1146        public string Description { get; set; } = string.Empty;
 1147        public string CommunityContext { get; set; } = string.Empty;
 148    }
 149}