mirror of
https://github.com/RayLabsHQ/gitea-mirror.git
synced 2025-12-06 11:36:44 +03:00
283 lines
10 KiB
TypeScript
283 lines
10 KiB
TypeScript
/**
|
|
* Maps between UI config structure and database schema structure
|
|
*/
|
|
|
|
import type {
|
|
GitHubConfig,
|
|
GiteaConfig,
|
|
MirrorOptions,
|
|
AdvancedOptions,
|
|
SaveConfigApiRequest
|
|
} from "@/types/config";
|
|
import { z } from "zod";
|
|
import { githubConfigSchema, giteaConfigSchema, scheduleConfigSchema, cleanupConfigSchema } from "@/lib/db/schema";
|
|
import { parseInterval } from "@/lib/utils/duration-parser";
|
|
|
|
// Use the actual database schema types
|
|
type DbGitHubConfig = z.infer<typeof githubConfigSchema>;
|
|
type DbGiteaConfig = z.infer<typeof giteaConfigSchema>;
|
|
type DbScheduleConfig = z.infer<typeof scheduleConfigSchema>;
|
|
type DbCleanupConfig = z.infer<typeof cleanupConfigSchema>;
|
|
|
|
/**
|
|
* Maps UI config structure to database schema structure
|
|
*/
|
|
export function mapUiToDbConfig(
|
|
githubConfig: GitHubConfig,
|
|
giteaConfig: GiteaConfig,
|
|
mirrorOptions: MirrorOptions,
|
|
advancedOptions: AdvancedOptions
|
|
): { githubConfig: DbGitHubConfig; giteaConfig: DbGiteaConfig } {
|
|
// Map GitHub config to match database schema fields
|
|
const dbGithubConfig: DbGitHubConfig = {
|
|
// Map username to owner field
|
|
owner: githubConfig.username,
|
|
type: "personal", // Default to personal, could be made configurable
|
|
token: githubConfig.token || "",
|
|
|
|
// Map checkbox fields with proper names
|
|
includeStarred: githubConfig.mirrorStarred,
|
|
includePrivate: githubConfig.privateRepositories,
|
|
includeForks: !advancedOptions.skipForks, // Note: UI has skipForks, DB has includeForks
|
|
skipForks: advancedOptions.skipForks, // Add skipForks field
|
|
includeArchived: false, // Not in UI yet, default to false
|
|
includePublic: true, // Not in UI yet, default to true
|
|
|
|
// Organization related fields
|
|
includeOrganizations: [], // Not in UI yet
|
|
|
|
// Starred repos organization
|
|
starredReposOrg: giteaConfig.starredReposOrg,
|
|
|
|
// Mirror strategy
|
|
mirrorStrategy: giteaConfig.mirrorStrategy || "preserve",
|
|
defaultOrg: giteaConfig.organization,
|
|
|
|
// Advanced options
|
|
starredCodeOnly: advancedOptions.starredCodeOnly,
|
|
};
|
|
|
|
// Map Gitea config to match database schema
|
|
const dbGiteaConfig: DbGiteaConfig = {
|
|
url: giteaConfig.url,
|
|
token: giteaConfig.token,
|
|
defaultOwner: giteaConfig.username, // Map username to defaultOwner
|
|
organization: giteaConfig.organization, // Add organization field
|
|
preserveOrgStructure: giteaConfig.mirrorStrategy === "preserve" || giteaConfig.mirrorStrategy === "mixed", // Add preserveOrgStructure field
|
|
|
|
// Mirror interval and options
|
|
mirrorInterval: "8h", // Default value, could be made configurable
|
|
lfs: mirrorOptions.mirrorLFS || false, // LFS mirroring option
|
|
wiki: mirrorOptions.mirrorMetadata && mirrorOptions.metadataComponents.wiki,
|
|
|
|
// Visibility settings
|
|
visibility: giteaConfig.visibility || "default",
|
|
preserveVisibility: false, // This should be a separate field, not the same as preserveOrgStructure
|
|
|
|
// Organization creation
|
|
createOrg: true, // Default to true
|
|
|
|
// Template settings (not in UI yet)
|
|
templateOwner: undefined,
|
|
templateRepo: undefined,
|
|
|
|
// Topics
|
|
addTopics: true, // Default to true
|
|
topicPrefix: undefined,
|
|
|
|
// Fork strategy
|
|
forkStrategy: advancedOptions.skipForks ? "skip" : "reference",
|
|
|
|
// Mirror options from UI
|
|
issueConcurrency: giteaConfig.issueConcurrency ?? 3,
|
|
pullRequestConcurrency: giteaConfig.pullRequestConcurrency ?? 5,
|
|
mirrorReleases: mirrorOptions.mirrorReleases,
|
|
releaseLimit: mirrorOptions.releaseLimit || 10,
|
|
mirrorMetadata: mirrorOptions.mirrorMetadata,
|
|
mirrorIssues: mirrorOptions.mirrorMetadata && mirrorOptions.metadataComponents.issues,
|
|
mirrorPullRequests: mirrorOptions.mirrorMetadata && mirrorOptions.metadataComponents.pullRequests,
|
|
mirrorLabels: mirrorOptions.mirrorMetadata && mirrorOptions.metadataComponents.labels,
|
|
mirrorMilestones: mirrorOptions.mirrorMetadata && mirrorOptions.metadataComponents.milestones,
|
|
};
|
|
|
|
return {
|
|
githubConfig: dbGithubConfig,
|
|
giteaConfig: dbGiteaConfig,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Maps database schema structure to UI config structure
|
|
*/
|
|
export function mapDbToUiConfig(dbConfig: any): {
|
|
githubConfig: GitHubConfig;
|
|
giteaConfig: GiteaConfig;
|
|
mirrorOptions: MirrorOptions;
|
|
advancedOptions: AdvancedOptions;
|
|
} {
|
|
// Map from database GitHub config to UI fields
|
|
const githubConfig: GitHubConfig = {
|
|
username: dbConfig.githubConfig?.owner || "", // Map owner to username
|
|
token: dbConfig.githubConfig?.token || "",
|
|
privateRepositories: dbConfig.githubConfig?.includePrivate || false, // Map includePrivate to privateRepositories
|
|
mirrorStarred: dbConfig.githubConfig?.includeStarred || false, // Map includeStarred to mirrorStarred
|
|
};
|
|
|
|
// Map from database Gitea config to UI fields
|
|
const giteaConfig: GiteaConfig = {
|
|
url: dbConfig.giteaConfig?.url || "",
|
|
username: dbConfig.giteaConfig?.defaultOwner || "", // Map defaultOwner to username
|
|
token: dbConfig.giteaConfig?.token || "",
|
|
organization: dbConfig.githubConfig?.defaultOrg || "github-mirrors", // Get from GitHub config
|
|
visibility: dbConfig.giteaConfig?.visibility === "default" ? "public" : dbConfig.giteaConfig?.visibility || "public",
|
|
starredReposOrg: dbConfig.githubConfig?.starredReposOrg || "starred", // Get from GitHub config
|
|
preserveOrgStructure: dbConfig.giteaConfig?.preserveVisibility || false, // Map preserveVisibility
|
|
mirrorStrategy: dbConfig.githubConfig?.mirrorStrategy || "preserve", // Get from GitHub config
|
|
personalReposOrg: undefined, // Not stored in current schema
|
|
issueConcurrency: dbConfig.giteaConfig?.issueConcurrency ?? 3,
|
|
pullRequestConcurrency: dbConfig.giteaConfig?.pullRequestConcurrency ?? 5,
|
|
};
|
|
|
|
// Map mirror options from various database fields
|
|
const mirrorOptions: MirrorOptions = {
|
|
mirrorReleases: dbConfig.giteaConfig?.mirrorReleases || false,
|
|
releaseLimit: dbConfig.giteaConfig?.releaseLimit || 10,
|
|
mirrorLFS: dbConfig.giteaConfig?.lfs || false,
|
|
mirrorMetadata: dbConfig.giteaConfig?.mirrorMetadata || false,
|
|
metadataComponents: {
|
|
issues: dbConfig.giteaConfig?.mirrorIssues || false,
|
|
pullRequests: dbConfig.giteaConfig?.mirrorPullRequests || false,
|
|
labels: dbConfig.giteaConfig?.mirrorLabels || false,
|
|
milestones: dbConfig.giteaConfig?.mirrorMilestones || false,
|
|
wiki: dbConfig.giteaConfig?.wiki || false,
|
|
},
|
|
};
|
|
|
|
// Map advanced options
|
|
const advancedOptions: AdvancedOptions = {
|
|
skipForks: !(dbConfig.githubConfig?.includeForks ?? true), // Invert includeForks to get skipForks
|
|
// Support both old (skipStarredIssues) and new (starredCodeOnly) field names for backward compatibility
|
|
starredCodeOnly: dbConfig.githubConfig?.starredCodeOnly ?? (dbConfig.githubConfig as any)?.skipStarredIssues ?? false,
|
|
};
|
|
|
|
return {
|
|
githubConfig,
|
|
giteaConfig,
|
|
mirrorOptions,
|
|
advancedOptions,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Maps UI schedule config to database schema
|
|
*/
|
|
export function mapUiScheduleToDb(uiSchedule: any, existing?: DbScheduleConfig): DbScheduleConfig {
|
|
// Preserve existing schedule config and only update fields controlled by the UI
|
|
const base: DbScheduleConfig = existing
|
|
? { ...(existing as unknown as DbScheduleConfig) }
|
|
: (scheduleConfigSchema.parse({}) as unknown as DbScheduleConfig);
|
|
|
|
// Store interval as seconds string to avoid lossy cron conversion
|
|
const intervalSeconds = typeof uiSchedule.interval === 'number' && uiSchedule.interval > 0
|
|
? String(uiSchedule.interval)
|
|
: (typeof base.interval === 'string' ? base.interval : String(86400));
|
|
|
|
return {
|
|
...base,
|
|
enabled: !!uiSchedule.enabled,
|
|
interval: intervalSeconds,
|
|
} as DbScheduleConfig;
|
|
}
|
|
|
|
/**
|
|
* Maps database schedule config to UI format
|
|
*/
|
|
export function mapDbScheduleToUi(dbSchedule: DbScheduleConfig): any {
|
|
// Handle null/undefined schedule config
|
|
if (!dbSchedule) {
|
|
return {
|
|
enabled: false,
|
|
interval: 86400, // Default to daily (24 hours)
|
|
lastRun: null,
|
|
nextRun: null,
|
|
};
|
|
}
|
|
|
|
// Parse interval supporting numbers (seconds), duration strings, and cron
|
|
let intervalSeconds = 86400; // Default to daily (24 hours)
|
|
try {
|
|
const ms = parseInterval(
|
|
typeof dbSchedule.interval === 'number'
|
|
? dbSchedule.interval
|
|
: (dbSchedule.interval as unknown as string)
|
|
);
|
|
intervalSeconds = Math.max(1, Math.floor(ms / 1000));
|
|
} catch (_e) {
|
|
// Fallback to default if unparsable
|
|
intervalSeconds = 86400;
|
|
}
|
|
|
|
return {
|
|
enabled: dbSchedule.enabled || false,
|
|
interval: intervalSeconds,
|
|
lastRun: dbSchedule.lastRun || null,
|
|
nextRun: dbSchedule.nextRun || null,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Maps UI cleanup config to database schema
|
|
*/
|
|
export function mapUiCleanupToDb(uiCleanup: any): DbCleanupConfig {
|
|
const parsedRetention =
|
|
typeof uiCleanup.retentionDays === "string"
|
|
? parseInt(uiCleanup.retentionDays, 10)
|
|
: uiCleanup.retentionDays;
|
|
const retentionSeconds = Number.isFinite(parsedRetention)
|
|
? parsedRetention
|
|
: 604800;
|
|
|
|
return {
|
|
enabled: Boolean(uiCleanup.enabled),
|
|
retentionDays: retentionSeconds,
|
|
deleteFromGitea: uiCleanup.deleteFromGitea ?? false,
|
|
deleteIfNotInGitHub: uiCleanup.deleteIfNotInGitHub ?? true,
|
|
protectedRepos: uiCleanup.protectedRepos ?? [],
|
|
dryRun: uiCleanup.dryRun ?? false,
|
|
orphanedRepoAction: (uiCleanup.orphanedRepoAction as DbCleanupConfig["orphanedRepoAction"]) || "archive",
|
|
batchSize: uiCleanup.batchSize ?? 10,
|
|
pauseBetweenDeletes: uiCleanup.pauseBetweenDeletes ?? 2000,
|
|
lastRun: uiCleanup.lastRun ?? null,
|
|
nextRun: uiCleanup.nextRun ?? null,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Maps database cleanup config to UI format
|
|
*/
|
|
export function mapDbCleanupToUi(dbCleanup: DbCleanupConfig): any {
|
|
// Handle null/undefined cleanup config
|
|
if (!dbCleanup) {
|
|
return {
|
|
enabled: false,
|
|
retentionDays: 604800, // Default to 7 days in seconds
|
|
lastRun: null,
|
|
nextRun: null,
|
|
};
|
|
}
|
|
|
|
return {
|
|
enabled: dbCleanup.enabled ?? false,
|
|
retentionDays: dbCleanup.retentionDays ?? 604800,
|
|
deleteFromGitea: dbCleanup.deleteFromGitea ?? false,
|
|
deleteIfNotInGitHub: dbCleanup.deleteIfNotInGitHub ?? true,
|
|
protectedRepos: dbCleanup.protectedRepos ?? [],
|
|
dryRun: dbCleanup.dryRun ?? false,
|
|
orphanedRepoAction: dbCleanup.orphanedRepoAction ?? "archive",
|
|
batchSize: dbCleanup.batchSize ?? 10,
|
|
pauseBetweenDeletes: dbCleanup.pauseBetweenDeletes ?? 2000,
|
|
lastRun: dbCleanup.lastRun ?? null,
|
|
nextRun: dbCleanup.nextRun ?? null,
|
|
};
|
|
}
|