feat: add mixed strategy for repository mirroring, enhancing organization handling for personal and organizational repos

This commit is contained in:
Arunavo Ray
2025-06-24 13:51:43 +05:30
parent 4d8d75c8a6
commit b660d2dd9a
7 changed files with 131 additions and 9 deletions

View File

@@ -44,7 +44,7 @@ export const configSchema = z.object({
visibility: z.enum(["public", "private", "limited"]).default("public"),
starredReposOrg: z.string().default("github"),
preserveOrgStructure: z.boolean().default(false),
mirrorStrategy: z.enum(["preserve", "single-org", "flat-user"]).optional(),
mirrorStrategy: z.enum(["preserve", "single-org", "flat-user", "mixed"]).optional(),
personalReposOrg: z.string().optional(), // Override destination for personal repos
}),
include: z.array(z.string()).default(["*"]),

View File

@@ -378,4 +378,47 @@ describe("getGiteaRepoOwner - Organization Override Tests", () => {
const result = getGiteaRepoOwner({ config: baseConfig, repository: repo });
expect(result).toBe("myorg");
});
test("mixed strategy: personal repos go to organization", () => {
const configWithMixed = {
...baseConfig,
giteaConfig: {
...baseConfig.giteaConfig!,
mirrorStrategy: "mixed" as const,
organization: "github-mirrors"
}
};
const repo = { ...baseRepo, organization: undefined };
const result = getGiteaRepoOwner({ config: configWithMixed, repository: repo });
expect(result).toBe("github-mirrors");
});
test("mixed strategy: org repos preserve their structure", () => {
const configWithMixed = {
...baseConfig,
giteaConfig: {
...baseConfig.giteaConfig!,
mirrorStrategy: "mixed" as const,
organization: "github-mirrors"
}
};
const repo = { ...baseRepo, organization: "myorg" };
const result = getGiteaRepoOwner({ config: configWithMixed, repository: repo });
expect(result).toBe("myorg");
});
test("mixed strategy: fallback to username if no org configs", () => {
const configWithMixed = {
...baseConfig,
giteaConfig: {
...baseConfig.giteaConfig!,
mirrorStrategy: "mixed" as const,
organization: undefined,
personalReposOrg: undefined
}
};
const repo = { ...baseRepo, organization: undefined };
const result = getGiteaRepoOwner({ config: configWithMixed, repository: repo });
expect(result).toBe("giteauser");
});
});

View File

@@ -136,6 +136,19 @@ export const getGiteaRepoOwner = ({
// All non-starred repos go under the user account
return config.giteaConfig.username;
case "mixed":
// Mixed mode: personal repos to single org, organization repos preserve structure
if (repository.organization) {
// Organization repos preserve their structure
return repository.organization;
}
// Personal repos go to configured organization (same as single-org)
if (config.giteaConfig.organization) {
return config.giteaConfig.organization;
}
// Fallback to username if no organization specified
return config.giteaConfig.username;
default:
// Default fallback
return config.giteaConfig.username;

View File

@@ -35,7 +35,7 @@ interface DbGiteaConfig {
visibility: "public" | "private" | "limited";
starredReposOrg: string;
preserveOrgStructure: boolean;
mirrorStrategy?: "preserve" | "single-org" | "flat-user";
mirrorStrategy?: "preserve" | "single-org" | "flat-user" | "mixed";
personalReposOrg?: string;
}