diff --git a/src/components/config/GitHubMirrorSettings.tsx b/src/components/config/GitHubMirrorSettings.tsx index 0fbb475..9fd67c3 100644 --- a/src/components/config/GitHubMirrorSettings.tsx +++ b/src/components/config/GitHubMirrorSettings.tsx @@ -57,7 +57,7 @@ export function GitHubMirrorSettings({ onGitHubConfigChange({ ...githubConfig, [field]: value }); }; - const handleMirrorChange = (field: keyof MirrorOptions, value: boolean) => { + const handleMirrorChange = (field: keyof MirrorOptions, value: boolean | number) => { onMirrorOptionsChange({ ...mirrorOptions, [field]: value }); }; @@ -313,16 +313,41 @@ export function GitHubMirrorSettings({ onCheckedChange={(checked) => handleMirrorChange('mirrorReleases', !!checked)} />
- -

- Include GitHub releases, tags, and associated assets -

+
+
+ +

+ Include GitHub releases, tags, and associated assets +

+
+ {mirrorOptions.mirrorReleases && ( +
+ + { + const value = parseInt(e.target.value) || 10; + const clampedValue = Math.min(100, Math.max(1, value)); + handleMirrorChange('releaseLimit', clampedValue); + }} + className="w-16 px-2 py-1 text-xs border border-input rounded bg-background text-foreground" + /> + releases +
+ )} +
@@ -452,6 +477,31 @@ export function GitHubMirrorSettings({ > Pull Requests + + + + + + +
+

Pull Requests are mirrored as issues

+

+ Due to Gitea API limitations, PRs cannot be created as actual pull requests. + Instead, they are mirrored as issues with: +

+
    +
  • • [PR #number] prefix in title
  • +
  • • Full PR description and metadata
  • +
  • • Commit history (up to 10 commits)
  • +
  • • File changes summary
  • +
  • • Diff preview (first 5 files)
  • +
  • • Review comments preserved
  • +
  • • Merge/close status tracking
  • +
+
+
+
+
diff --git a/src/components/config/MirrorOptionsForm.tsx b/src/components/config/MirrorOptionsForm.tsx deleted file mode 100644 index 9a67ef8..0000000 --- a/src/components/config/MirrorOptionsForm.tsx +++ /dev/null @@ -1,282 +0,0 @@ -import React from "react"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { Checkbox } from "../ui/checkbox"; -import type { MirrorOptions } from "@/types/config"; -import { RefreshCw, Info } from "lucide-react"; -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger -} from "../ui/tooltip"; - -interface MirrorOptionsFormProps { - config: MirrorOptions; - setConfig: React.Dispatch>; - onAutoSave?: (config: MirrorOptions) => Promise; - isAutoSaving?: boolean; -} - -export function MirrorOptionsForm({ - config, - setConfig, - onAutoSave, - isAutoSaving = false, -}: MirrorOptionsFormProps) { - const handleChange = (name: string, checked: boolean) => { - let newConfig = { ...config }; - - if (name === "mirrorMetadata") { - newConfig.mirrorMetadata = checked; - // If disabling metadata, also disable all components - if (!checked) { - newConfig.metadataComponents = { - issues: false, - pullRequests: false, // Keep for backwards compatibility but not shown in UI - labels: false, - milestones: false, - wiki: false, - }; - } - } else if (name.startsWith("metadataComponents.")) { - const componentName = name.split(".")[1] as keyof typeof config.metadataComponents; - newConfig.metadataComponents = { - ...config.metadataComponents, - [componentName]: checked, - }; - } else { - newConfig = { - ...config, - [name]: checked, - }; - } - - setConfig(newConfig); - - // Auto-save - if (onAutoSave) { - onAutoSave(newConfig); - } - }; - - return ( - - - - Mirror Options - {isAutoSaving && ( -
- - Auto-saving... -
- )} -
-
- - {/* Repository Content */} -
-

Repository Content

- -
- - handleChange("mirrorReleases", Boolean(checked)) - } - /> - -
- -
- - handleChange("mirrorLFS", Boolean(checked)) - } - /> - -
- -
- - handleChange("mirrorMetadata", Boolean(checked)) - } - /> - -
- - {/* Metadata Components */} - {config.mirrorMetadata && ( -
-
- Metadata Components -
- -
-
- - handleChange("metadataComponents.issues", Boolean(checked)) - } - disabled={!config.mirrorMetadata} - /> - -
- -
- - handleChange("metadataComponents.pullRequests", Boolean(checked)) - } - disabled={!config.mirrorMetadata} - /> - - - - - - - -
-

Pull Requests are mirrored as issues

-

- Due to Gitea API limitations, PRs cannot be created as actual pull requests. - Instead, they are mirrored as issues with: -

-
    -
  • • [PR #number] prefix in title
  • -
  • • Full PR description and metadata
  • -
  • • Commit history (up to 10 commits)
  • -
  • • File changes summary
  • -
  • • Diff preview (first 5 files)
  • -
  • • Review comments preserved
  • -
  • • Merge/close status tracking
  • -
-
-
-
-
-
- -
- - handleChange("metadataComponents.labels", Boolean(checked)) - } - disabled={!config.mirrorMetadata} - /> - -
- -
- - handleChange("metadataComponents.milestones", Boolean(checked)) - } - disabled={!config.mirrorMetadata} - /> - -
- -
- - handleChange("metadataComponents.wiki", Boolean(checked)) - } - disabled={!config.mirrorMetadata} - /> - -
-
-
- )} -
-
-
- ); -} diff --git a/src/lib/db/schema.ts b/src/lib/db/schema.ts index e169b4b..de54210 100644 --- a/src/lib/db/schema.ts +++ b/src/lib/db/schema.ts @@ -53,6 +53,7 @@ export const giteaConfigSchema = z.object({ .default("reference"), // Mirror options mirrorReleases: z.boolean().default(false), + releaseLimit: z.number().default(10), mirrorMetadata: z.boolean().default(false), mirrorIssues: z.boolean().default(false), mirrorPullRequests: z.boolean().default(false), diff --git a/src/lib/gitea.ts b/src/lib/gitea.ts index abbc2bf..0463d1c 100644 --- a/src/lib/gitea.ts +++ b/src/lib/gitea.ts @@ -1399,12 +1399,16 @@ export async function mirrorGitHubReleasesToGitea({ throw new Error(`Repository ${repository.name} does not exist in Gitea at ${repoOwner}. Please ensure the repository is mirrored first.`); } + // Get release limit from config (default to 10) + const releaseLimit = config.giteaConfig?.releaseLimit || 10; + const releases = await octokit.rest.repos.listReleases({ owner: repository.owner, repo: repository.name, + per_page: releaseLimit, // Only fetch the latest N releases }); - console.log(`[Releases] Found ${releases.data.length} releases to mirror for ${repository.fullName}`); + console.log(`[Releases] Found ${releases.data.length} releases (limited to latest ${releaseLimit}) to mirror for ${repository.fullName}`); if (releases.data.length === 0) { console.log(`[Releases] No releases to mirror for ${repository.fullName}`); @@ -1414,7 +1418,12 @@ export async function mirrorGitHubReleasesToGitea({ let mirroredCount = 0; let skippedCount = 0; - for (const release of releases.data) { + // Sort releases by created_at to ensure we get the most recent ones + const sortedReleases = releases.data.sort((a, b) => + new Date(b.created_at).getTime() - new Date(a.created_at).getTime() + ).slice(0, releaseLimit); + + for (const release of sortedReleases) { try { // Check if release already exists const existingReleasesResponse = await httpGet( diff --git a/src/lib/utils/config-mapper.ts b/src/lib/utils/config-mapper.ts index 8328321..c4018f1 100644 --- a/src/lib/utils/config-mapper.ts +++ b/src/lib/utils/config-mapper.ts @@ -89,6 +89,7 @@ export function mapUiToDbConfig( // Mirror options from UI mirrorReleases: mirrorOptions.mirrorReleases, + releaseLimit: mirrorOptions.releaseLimit || 10, mirrorMetadata: mirrorOptions.mirrorMetadata, mirrorIssues: mirrorOptions.mirrorMetadata && mirrorOptions.metadataComponents.issues, mirrorPullRequests: mirrorOptions.mirrorMetadata && mirrorOptions.metadataComponents.pullRequests, @@ -135,6 +136,7 @@ export function mapDbToUiConfig(dbConfig: any): { // 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: { diff --git a/src/types/config.ts b/src/types/config.ts index 179c8fb..240ac76 100644 --- a/src/types/config.ts +++ b/src/types/config.ts @@ -38,6 +38,7 @@ export interface GitHubConfig { export interface MirrorOptions { mirrorReleases: boolean; + releaseLimit?: number; // Limit number of releases to mirror (default: 10) mirrorLFS: boolean; // Mirror Git LFS objects mirrorMetadata: boolean; metadataComponents: {