mirror of
https://github.com/RayLabsHQ/gitea-mirror.git
synced 2026-08-10 19:03:24 +02:00
The "Auto-mirror new starred repositories" checkbox in the GitHub settings was a filter layered on top of scheduleConfig.autoMirror, which itself is only settable via the AUTO_MIRROR_REPOS env var (no UI). So users who checked the box saw their starred repos auto-imported but never mirrored. Treat autoMirror and autoMirrorStarred as independent triggers in the scheduler: autoMirror covers owned (and self-starred) repos, autoMirrorStarred covers repos starred from other owners. Either flag on its own is enough to enter the auto-mirror phase, and the filter scopes the work accordingly. Also normalize the owner comparison to lowercase since GitHub usernames are case-insensitive — previously a self-starred repo whose stored owner casing differed from the configured owner would be misclassified as a third-party star. Behavior change worth flagging in release notes: anyone who currently has the starred checkbox on (broken state) will start getting starred repos mirrored on upgrade. AUTO_MIRROR_REPOS=true users see no change.
This commit is contained in:
@@ -58,6 +58,51 @@ describe("Scheduler Service - Ignored Repository Handling", () => {
|
||||
expect(shouldMirrorRepository(oldSyncedRepo)).toBe(true);
|
||||
});
|
||||
|
||||
test("auto-mirror filter respects autoMirror and autoMirrorStarred independently", () => {
|
||||
// Mirrors the inline filter at scheduler-service.ts L228-233 / L609-614:
|
||||
// a repo is "starred from another owner" iff isStarred && owner !== githubOwner.
|
||||
// Such repos are gated by autoMirrorStarred; everything else is gated by autoMirror.
|
||||
const githubOwner = "Alice".toLowerCase();
|
||||
const filterRepos = (
|
||||
repos: Array<{ name: string; isStarred: boolean; owner: string }>,
|
||||
autoMirror: boolean,
|
||||
autoMirrorStarred: boolean,
|
||||
) =>
|
||||
repos.filter(repo => {
|
||||
const isStarredFromOther = repo.isStarred && repo.owner.toLowerCase() !== githubOwner;
|
||||
return isStarredFromOther ? autoMirrorStarred : autoMirror;
|
||||
});
|
||||
|
||||
// "ALICE" tests case-insensitive owner match — GitHub usernames are case-insensitive,
|
||||
// so a self-starred repo stored with different casing must still count as owned.
|
||||
const repos = [
|
||||
{ name: "owned-repo", isStarred: false, owner: "alice" },
|
||||
{ name: "self-starred", isStarred: true, owner: "ALICE" },
|
||||
{ name: "starred-from-bob", isStarred: true, owner: "bob" },
|
||||
];
|
||||
|
||||
// Both off: nothing mirrors
|
||||
expect(filterRepos(repos, false, false).map(r => r.name)).toEqual([]);
|
||||
|
||||
// Only autoMirror: owned + self-starred, not third-party stars
|
||||
expect(filterRepos(repos, true, false).map(r => r.name)).toEqual([
|
||||
"owned-repo",
|
||||
"self-starred",
|
||||
]);
|
||||
|
||||
// Only autoMirrorStarred: just third-party stars (the bug fix — used to be empty)
|
||||
expect(filterRepos(repos, false, true).map(r => r.name)).toEqual([
|
||||
"starred-from-bob",
|
||||
]);
|
||||
|
||||
// Both on: everything
|
||||
expect(filterRepos(repos, true, true).map(r => r.name)).toEqual([
|
||||
"owned-repo",
|
||||
"self-starred",
|
||||
"starred-from-bob",
|
||||
]);
|
||||
});
|
||||
|
||||
test("should validate all repository status enum values", () => {
|
||||
const validStatuses = [
|
||||
"imported",
|
||||
|
||||
@@ -203,10 +203,14 @@ async function runScheduledSync(config: any): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-mirror: Mirror imported/pending/failed repositories if enabled
|
||||
if (scheduleConfig.autoMirror) {
|
||||
// Auto-mirror: Mirror imported/pending/failed repositories if enabled.
|
||||
// autoMirror covers owned repos; autoMirrorStarred covers starred repos from other owners.
|
||||
// Either flag on its own is enough to enter this phase.
|
||||
const autoMirrorOwned = !!scheduleConfig.autoMirror;
|
||||
const autoMirrorStarred = !!config.githubConfig?.autoMirrorStarred;
|
||||
if (autoMirrorOwned || autoMirrorStarred) {
|
||||
try {
|
||||
console.log(`[Scheduler] Auto-mirror enabled - checking for repositories to mirror for user ${userId}...`);
|
||||
console.log(`[Scheduler] Auto-mirror enabled (owned=${autoMirrorOwned}, starred=${autoMirrorStarred}) - checking for repositories to mirror for user ${userId}...`);
|
||||
let reposNeedingMirror = await db
|
||||
.select()
|
||||
.from(repositories)
|
||||
@@ -221,17 +225,16 @@ async function runScheduledSync(config: any): Promise<void> {
|
||||
)
|
||||
);
|
||||
|
||||
// Filter out starred repos from auto-mirror when autoMirrorStarred is disabled
|
||||
if (!config.githubConfig?.autoMirrorStarred) {
|
||||
const githubOwner = config.githubConfig?.owner || '';
|
||||
const beforeCount = reposNeedingMirror.length;
|
||||
reposNeedingMirror = reposNeedingMirror.filter(
|
||||
repo => !repo.isStarred || repo.owner === githubOwner
|
||||
);
|
||||
const skippedCount = beforeCount - reposNeedingMirror.length;
|
||||
if (skippedCount > 0) {
|
||||
console.log(`[Scheduler] Skipped ${skippedCount} starred repositories from auto-mirror (autoMirrorStarred is disabled)`);
|
||||
}
|
||||
const githubOwner = (config.githubConfig?.owner || '').toLowerCase();
|
||||
const beforeCount = reposNeedingMirror.length;
|
||||
reposNeedingMirror = reposNeedingMirror.filter(repo => {
|
||||
// GitHub usernames are case-insensitive; lowercase both sides to avoid misclassifying self-starred repos.
|
||||
const isStarredFromOther = repo.isStarred && repo.owner.toLowerCase() !== githubOwner;
|
||||
return isStarredFromOther ? autoMirrorStarred : autoMirrorOwned;
|
||||
});
|
||||
const skippedCount = beforeCount - reposNeedingMirror.length;
|
||||
if (skippedCount > 0) {
|
||||
console.log(`[Scheduler] Skipped ${skippedCount} repositories from auto-mirror (autoMirror=${autoMirrorOwned}, autoMirrorStarred=${autoMirrorStarred})`);
|
||||
}
|
||||
|
||||
if (reposNeedingMirror.length > 0) {
|
||||
@@ -574,10 +577,12 @@ async function performInitialAutoStart(): Promise<void> {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Step 2: Trigger mirror for all repositories that need mirroring
|
||||
// Only auto-mirror if autoMirror is enabled in schedule config
|
||||
if (!config.scheduleConfig?.autoMirror) {
|
||||
console.log(`[Scheduler] Step 2: Skipping initial mirror - autoMirror is disabled for user ${config.userId}`);
|
||||
// Step 2: Trigger mirror for all repositories that need mirroring.
|
||||
// autoMirror covers owned repos; autoMirrorStarred covers starred repos from other owners.
|
||||
const autoMirrorOwned = !!config.scheduleConfig?.autoMirror;
|
||||
const autoMirrorStarred = !!config.githubConfig?.autoMirrorStarred;
|
||||
if (!autoMirrorOwned && !autoMirrorStarred) {
|
||||
console.log(`[Scheduler] Step 2: Skipping initial mirror - autoMirror and autoMirrorStarred are both disabled for user ${config.userId}`);
|
||||
|
||||
// Still update schedule config timestamps
|
||||
const currentTime2 = new Date();
|
||||
@@ -587,7 +592,7 @@ async function performInitialAutoStart(): Promise<void> {
|
||||
continue;
|
||||
}
|
||||
|
||||
console.log(`[Scheduler] Step 2: Triggering mirror for repositories that need mirroring...`);
|
||||
console.log(`[Scheduler] Step 2: Triggering mirror for repositories that need mirroring (owned=${autoMirrorOwned}, starred=${autoMirrorStarred})...`);
|
||||
let reposNeedingMirror = await db
|
||||
.select()
|
||||
.from(repositories)
|
||||
@@ -602,17 +607,16 @@ async function performInitialAutoStart(): Promise<void> {
|
||||
)
|
||||
);
|
||||
|
||||
// Filter out starred repos from auto-mirror when autoMirrorStarred is disabled
|
||||
if (!config.githubConfig?.autoMirrorStarred) {
|
||||
const githubOwner = config.githubConfig?.owner || '';
|
||||
const beforeCount = reposNeedingMirror.length;
|
||||
reposNeedingMirror = reposNeedingMirror.filter(
|
||||
repo => !repo.isStarred || repo.owner === githubOwner
|
||||
);
|
||||
const skippedCount = beforeCount - reposNeedingMirror.length;
|
||||
if (skippedCount > 0) {
|
||||
console.log(`[Scheduler] Skipped ${skippedCount} starred repositories from initial auto-mirror (autoMirrorStarred is disabled)`);
|
||||
}
|
||||
const githubOwner = (config.githubConfig?.owner || '').toLowerCase();
|
||||
const beforeCount = reposNeedingMirror.length;
|
||||
reposNeedingMirror = reposNeedingMirror.filter(repo => {
|
||||
// GitHub usernames are case-insensitive; lowercase both sides to avoid misclassifying self-starred repos.
|
||||
const isStarredFromOther = repo.isStarred && repo.owner.toLowerCase() !== githubOwner;
|
||||
return isStarredFromOther ? autoMirrorStarred : autoMirrorOwned;
|
||||
});
|
||||
const skippedCount = beforeCount - reposNeedingMirror.length;
|
||||
if (skippedCount > 0) {
|
||||
console.log(`[Scheduler] Skipped ${skippedCount} repositories from initial auto-mirror (autoMirror=${autoMirrorOwned}, autoMirrorStarred=${autoMirrorStarred})`);
|
||||
}
|
||||
|
||||
if (reposNeedingMirror.length > 0) {
|
||||
|
||||
Reference in New Issue
Block a user