| 1 | using AgentForge.Abstractions; |
| 2 | using AgentForge.Data; |
| 3 | using AgentForge.Data.Entities; |
| 4 | using AgentForge.Options; |
| 5 | using AgentForge.Plugin.RepositoryImport.GitHub.Core; |
| 6 | using AgentForge.Plugin.Sdk; |
| 7 | using Microsoft.Extensions.Hosting; |
| 8 | using Microsoft.Extensions.Options; |
| 9 | |
| 10 | namespace AgentForge.Plugin.RepositoryImport.GitHub; |
| 11 | |
| 12 | internal sealed class GitHubOrgRepositoryImporter( |
| 13 | GitHubRepositoryClient gitHub, |
| 14 | ForgeImportCatalogLoader catalogLoader, |
| 15 | ForgeGitHubRepositoryImportEngine engine, |
| 16 | ForgeRepository repository, |
| 17 | IOptions<ForgeOptions> options, |
| 18 | IHostEnvironment environment) : IForgeRepositoryImporter |
| 19 | { |
| 20 | public string SourceId => "github"; |
| 21 | |
| 22 | public ForgeRepositoryImportScope Scope => ForgeRepositoryImportScope.Organization; |
| 23 | |
| 24 | public string PluginId => "repository-import-org-github"; |
| 25 | |
| 26 | public async Task<ForgeRepositoryImportResponse> ImportAsync( |
| 27 | ForgeRepositoryImportRequest request, |
| 28 | CancellationToken cancellationToken) |
| 29 | { |
| 30 | if (request.Scope != ForgeRepositoryImportScope.Organization) |
| 31 | throw new ForgeApiException(400, $"Importer '{PluginId}' only supports organization scope."); |
| 32 | |
| 33 | var catalogPath = ForgeRepositoryImportRequestMapping.ResolveCatalogPath( |
| 34 | request, |
| 35 | environment.ContentRootPath, |
| 36 | catalogLoader, |
| 37 | options.Value); |
| 38 | var doc = catalogLoader.Load(catalogPath); |
| 39 | var forgeOrgSlug = ForgeRepositoryImportRequestMapping.FirstNonEmpty( |
| 40 | request.ForgeOrg, |
| 41 | doc.Catalog.ForgeOrg, |
| 42 | options.Value.DefaultOrgSlug) |
| 43 | ?? throw new ForgeApiException(400, "forgeOrg is required."); |
| 44 | var externalOrg = ForgeRepositoryImportRequestMapping.FirstNonEmpty(request.ExternalOrg, doc.Catalog.GitHubOrg) |
| 45 | ?? throw new ForgeApiException(400, "externalOrg is required."); |
| 46 | |
| 47 | var org = repository.GetOrgBySlug(forgeOrgSlug) |
| 48 | ?? throw new ForgeApiException(404, $"Organization '{forgeOrgSlug}' not found."); |
| 49 | |
| 50 | var token = options.Value.GitHubImportToken; |
| 51 | if (string.IsNullOrWhiteSpace(token) && !request.DryRun) |
| 52 | throw new ForgeApiException(503, "FORGE_GITHUB_IMPORT_TOKEN is not configured."); |
| 53 | |
| 54 | IReadOnlyList<GitHubRepositoryInfo> remoteRepos = request.DryRun && string.IsNullOrWhiteSpace(token) |
| 55 | ? [] |
| 56 | : await gitHub.ListOrgRepositoriesAsync( |
| 57 | externalOrg, |
| 58 | token, |
| 59 | request.IncludeArchived, |
| 60 | cancellationToken).ConfigureAwait(false); |
| 61 | |
| 62 | return engine.ImportRepositories(org, externalOrg, remoteRepos, doc, request, token); |
| 63 | } |
| 64 | } |
| 65 | |