diff --git a/src/lib/gitea.ts b/src/lib/gitea.ts index e950af5..7517a89 100644 --- a/src/lib/gitea.ts +++ b/src/lib/gitea.ts @@ -1995,11 +1995,20 @@ export async function mirrorGitHubOrgToGitea({ const mirrorStrategy = config.githubConfig?.mirrorStrategy || (config.giteaConfig?.preserveOrgStructure ? "preserve" : "flat-user"); - let giteaOrgId: number; + let giteaOrgId: number | undefined; let targetOrgName: string; // Determine the target organization based on strategy - if (mirrorStrategy === "single-org" && config.giteaConfig?.organization) { + if (organization.destinationOrg) { + // Organization-level override takes precedence over the strategy + targetOrgName = organization.destinationOrg; + giteaOrgId = await getOrCreateGiteaOrg({ + orgId: organization.id, + orgName: targetOrgName, + config, + }); + console.log(`Using organization override: ${organization.name} -> ${targetOrgName}`); + } else if (mirrorStrategy === "single-org" && config.giteaConfig?.organization) { // For single-org strategy, use the configured destination organization targetOrgName = config.giteaConfig.organization || config.giteaConfig.defaultOwner; giteaOrgId = await getOrCreateGiteaOrg({ @@ -2062,23 +2071,35 @@ export async function mirrorGitHubOrgToGitea({ `Starting mirror for repository: ${repo.name} from GitHub org ${organization.name}` ); - // Mirror the repository based on strategy - if (mirrorStrategy === "flat-user") { - // For flat-user strategy, mirror directly to user account + // Resolve per repo with the canonical precedence + const owner = await getGiteaRepoOwnerAsync({ config, repository: repoData }); + + if (owner === config.giteaConfig?.defaultOwner) { await mirrorGithubRepoToGitea({ octokit, repository: repoData, config, }); - } else { - // For preserve and single-org strategies, use organization + } else if (owner === targetOrgName && giteaOrgId !== undefined) { await mirrorGitHubRepoToGiteaOrg({ octokit, config, repository: repoData, - giteaOrgId: giteaOrgId!, + giteaOrgId, orgName: targetOrgName, }); + } else { + const ownerOrgId = await getOrCreateGiteaOrg({ + orgName: owner, + config, + }); + await mirrorGitHubRepoToGiteaOrg({ + octokit, + config, + repository: repoData, + giteaOrgId: ownerOrgId, + orgName: owner, + }); } return repo; diff --git a/src/lib/recovery.ts b/src/lib/recovery.ts index 0d9d631..04a2f61 100644 --- a/src/lib/recovery.ts +++ b/src/lib/recovery.ts @@ -6,7 +6,7 @@ import { findInterruptedJobs, resumeInterruptedJob } from './helpers'; import { db, repositories, organizations, mirrorJobs, configs } from './db'; import { eq, and, lt, inArray, sql } from 'drizzle-orm'; -import { mirrorGithubRepoToGitea, mirrorGitHubOrgRepoToGiteaOrg, syncGiteaRepo } from './gitea'; +import { mirrorGithubRepoToGitea, syncGiteaRepo } from './gitea'; import { createGitHubClient } from './github'; import { processWithResilience } from './utils/concurrency'; import { repositoryVisibilityEnum, repoStatusEnum } from '@/types/Repository'; @@ -290,21 +290,11 @@ async function recoverMirrorJob(job: any, remainingItemIds: string[]) { mirroredLocation: repo.mirroredLocation || "", }; - // Mirror the repository based on whether it's in an organization - if (repo.organization && config.giteaConfig.preserveOrgStructure) { - await mirrorGitHubOrgRepoToGiteaOrg({ - config, - octokit, - orgName: repo.organization, - repository: repoData, - }); - } else { - await mirrorGithubRepoToGitea({ - octokit, - repository: repoData, - config, - }); - } + await mirrorGithubRepoToGitea({ + octokit, + repository: repoData, + config, + }); return repo; },