Skip to content

Commit 3458891

Browse files
committed
Updates for starred and personal repos
1 parent d388f2e commit 3458891

File tree

6 files changed

+117
-16
lines changed

6 files changed

+117
-16
lines changed

CLAUDE.md

Lines changed: 95 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
44

5+
DONT HALLUCIATE THINGS. IF YOU DONT KNOW LOOK AT THE CODE OR ASK FOR DOCS
6+
57
## Project Overview
68

79
Gitea Mirror is a web application that automatically mirrors repositories from GitHub to self-hosted Gitea instances. It uses Astro for SSR, React for UI, SQLite for data storage, and Bun as the JavaScript runtime.
@@ -40,7 +42,7 @@ bun run start # Start production server
4042
- **Frontend**: Astro (SSR) + React + Tailwind CSS v4 + Shadcn UI
4143
- **Backend**: Bun runtime + SQLite + Drizzle ORM
4244
- **APIs**: GitHub (Octokit) and Gitea APIs
43-
- **Auth**: JWT tokens with bcryptjs password hashing
45+
- **Auth**: Better Auth with email/password, SSO, and OIDC provider support
4446

4547
### Project Structure
4648
- `/src/pages/api/` - API endpoints (Astro API routes)
@@ -68,22 +70,34 @@ export async function POST({ request }: APIContext) {
6870

6971
3. **Real-time Updates**: Server-Sent Events (SSE) endpoint at `/api/events` for live dashboard updates
7072

71-
4. **Authentication Flow**:
73+
4. **Authentication System**:
74+
- Built on Better Auth library
75+
- Three authentication methods:
76+
- Email & Password (traditional auth)
77+
- SSO (authenticate via external OIDC providers)
78+
- OIDC Provider (act as OIDC provider for other apps)
79+
- Session-based authentication with secure cookies
7280
- First user signup creates admin account
73-
- JWT tokens stored in cookies
74-
- Protected routes check auth via `getUserFromCookie()`
81+
- Protected routes use Better Auth session validation
7582

7683
5. **Mirror Process**:
7784
- Discovers repos from GitHub (user/org)
7885
- Creates/updates mirror in Gitea
7986
- Tracks status in database
8087
- Supports scheduled automatic mirroring
8188

82-
6. **Mirror Strategies**: Three ways to organize repositories in Gitea:
89+
6. **Mirror Strategies**: Four ways to organize repositories in Gitea:
8390
- **preserve**: Maintains GitHub structure (default)
91+
- Organization repos → Same organization name in Gitea
92+
- Personal repos → Under your Gitea username
8493
- **single-org**: All repos go to one organization
94+
- All repos → Single configured organization
8595
- **flat-user**: All repos go under user account
86-
- Starred repos always go to separate organization (starredReposOrg)
96+
- All repos → Under your Gitea username
97+
- **mixed**: Hybrid approach
98+
- Organization repos → Preserve structure
99+
- Personal repos → Single configured organization
100+
- Starred repos always go to separate organization (starredReposOrg, default: "starred")
87101
- Routing logic in `getGiteaRepoOwner()` function
88102

89103
### Database Schema (SQLite)
@@ -102,11 +116,18 @@ export async function POST({ request }: APIContext) {
102116

103117
### Development Tips
104118
- Environment variables in `.env` (copy from `.env.example`)
105-
- JWT_SECRET auto-generated if not provided
119+
- BETTER_AUTH_SECRET required for session signing
106120
- Database auto-initializes on first run
107121
- Use `bun run dev:clean` for fresh database start
108122
- Tailwind CSS v4 configured with Vite plugin
109123

124+
### Authentication Setup
125+
- **Better Auth** handles all authentication
126+
- Configuration in `/src/lib/auth.ts` (server) and `/src/lib/auth-client.ts` (client)
127+
- Auth endpoints available at `/api/auth/*`
128+
- SSO providers configured through the web UI
129+
- OIDC provider functionality for external applications
130+
110131
### Common Tasks
111132

112133
**Adding a new API endpoint:**
@@ -125,6 +146,73 @@ export async function POST({ request }: APIContext) {
125146
2. Run `bun run init-db` to recreate database
126147
3. Update related queries in `/src/lib/db/queries/`
127148

149+
## Configuration Options
150+
151+
### GitHub Configuration (UI Fields)
152+
153+
#### Basic Settings (`githubConfig`)
154+
- **username**: GitHub username
155+
- **token**: GitHub personal access token (requires repo and admin:org scopes)
156+
- **privateRepositories**: Include private repositories
157+
- **mirrorStarred**: Mirror starred repositories
158+
159+
### Gitea Configuration (UI Fields)
160+
- **url**: Gitea instance URL
161+
- **username**: Gitea username
162+
- **token**: Gitea access token
163+
- **organization**: Destination organization (for single-org/mixed strategies)
164+
- **starredReposOrg**: Organization for starred repositories (default: "starred")
165+
- **visibility**: Organization visibility - "public", "private", "limited"
166+
- **mirrorStrategy**: Repository organization strategy (set via UI)
167+
- **preserveOrgStructure**: Automatically set based on mirrorStrategy
168+
169+
### Schedule Configuration (`scheduleConfig`)
170+
- **enabled**: Enable automatic mirroring (default: false)
171+
- **interval**: Cron expression or seconds (default: "0 2 * * *" - 2 AM daily)
172+
- **concurrent**: Allow concurrent mirror operations (default: false)
173+
- **batchSize**: Number of repos to process in parallel (default: 10)
174+
175+
### Database Cleanup Configuration (`cleanupConfig`)
176+
- **enabled**: Enable automatic cleanup (default: false)
177+
- **retentionDays**: Days to keep events (stored as seconds internally)
178+
179+
### Mirror Options (UI Fields)
180+
- **mirrorReleases**: Mirror GitHub releases to Gitea
181+
- **mirrorMetadata**: Enable metadata mirroring (master toggle)
182+
- **metadataComponents** (only available when mirrorMetadata is enabled):
183+
- **issues**: Mirror issues
184+
- **pullRequests**: Mirror pull requests
185+
- **labels**: Mirror labels
186+
- **milestones**: Mirror milestones
187+
- **wiki**: Mirror wiki content
188+
189+
### Advanced Options (UI Fields)
190+
- **skipForks**: Skip forked repositories (default: false)
191+
- **skipStarredIssues**: Skip issues for starred repositories (default: false) - enables "Lightweight mode" for starred repos
192+
193+
### Authentication Configuration
194+
195+
#### SSO Provider Configuration
196+
- **issuerUrl**: OIDC issuer URL (e.g., https://accounts.google.com)
197+
- **domain**: Email domain for this provider
198+
- **providerId**: Unique identifier for the provider
199+
- **clientId**: OAuth client ID from provider
200+
- **clientSecret**: OAuth client secret from provider
201+
- **authorizationEndpoint**: OAuth authorization URL (auto-discovered if supported)
202+
- **tokenEndpoint**: OAuth token exchange URL (auto-discovered if supported)
203+
- **jwksEndpoint**: JSON Web Key Set URL (optional, auto-discovered)
204+
- **userInfoEndpoint**: User information endpoint (optional, auto-discovered)
205+
206+
#### OIDC Provider Settings (for external apps)
207+
- **allowedRedirectUris**: Comma-separated list of allowed redirect URIs
208+
- **clientId**: Generated client ID for the application
209+
- **clientSecret**: Generated client secret for the application
210+
- **scopes**: Available scopes (openid, profile, email)
211+
212+
#### Environment Variables
213+
- **BETTER_AUTH_SECRET**: Secret key for signing sessions (required)
214+
- **BETTER_AUTH_URL**: Base URL for authentication (default: http://localhost:4321)
215+
128216
## Security Guidelines
129217

130218
- **Confidentiality Guidelines**:

src/components/config/ConfigTabs.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export function ConfigTabs() {
4646
token: '',
4747
organization: 'github-mirrors',
4848
visibility: 'public',
49-
starredReposOrg: 'github',
49+
starredReposOrg: 'starred',
5050
preserveOrgStructure: false,
5151
},
5252
scheduleConfig: {

src/lib/gitea.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,19 @@ describe("getGiteaRepoOwner - Organization Override Tests", () => {
354354
expect(result).toBe("starred");
355355
});
356356

357+
test("starred repos default to 'starred' org when starredReposOrg is not configured", () => {
358+
const repo = { ...baseRepo, isStarred: true };
359+
const configWithoutStarredOrg = {
360+
...baseConfig,
361+
giteaConfig: {
362+
...baseConfig.giteaConfig,
363+
starredReposOrg: undefined
364+
}
365+
};
366+
const result = getGiteaRepoOwner({ config: configWithoutStarredOrg, repository: repo });
367+
expect(result).toBe("starred");
368+
});
369+
357370
// Removed test for personalReposOrg as this field no longer exists
358371

359372
test("preserve strategy: personal repos fallback to username when no override", () => {

src/lib/gitea.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ export const getGiteaRepoOwnerAsync = async ({
7373
}
7474

7575
// Check if repository is starred - starred repos always go to starredReposOrg (highest priority)
76-
if (repository.isStarred && config.giteaConfig.starredReposOrg) {
77-
return config.giteaConfig.starredReposOrg;
76+
if (repository.isStarred) {
77+
return config.giteaConfig.starredReposOrg || "starred";
7878
}
7979

8080
// Check for repository-specific override (second highest priority)
@@ -118,8 +118,8 @@ export const getGiteaRepoOwner = ({
118118
}
119119

120120
// Check if repository is starred - starred repos always go to starredReposOrg
121-
if (repository.isStarred && config.giteaConfig.starredReposOrg) {
122-
return config.giteaConfig.starredReposOrg;
121+
if (repository.isStarred) {
122+
return config.giteaConfig.starredReposOrg || "starred";
123123
}
124124

125125
// Get the mirror strategy - use preserveOrgStructure for backward compatibility
@@ -352,8 +352,8 @@ export const mirrorGithubRepoToGitea = async ({
352352

353353
const apiUrl = `${config.giteaConfig.url}/api/v1/repos/migrate`;
354354

355-
// Handle organization creation if needed for single-org or preserve strategies
356-
if (repoOwner !== config.giteaConfig.defaultOwner && !repository.isStarred) {
355+
// Handle organization creation if needed for single-org, preserve strategies, or starred repos
356+
if (repoOwner !== config.giteaConfig.defaultOwner) {
357357
// Need to create the organization if it doesn't exist
358358
await getOrCreateGiteaOrg({
359359
orgName: repoOwner,

src/lib/utils/config-mapper.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ export function mapDbToUiConfig(dbConfig: any): {
120120
token: dbConfig.giteaConfig?.token || "",
121121
organization: dbConfig.githubConfig?.defaultOrg || "github-mirrors", // Get from GitHub config
122122
visibility: dbConfig.giteaConfig?.visibility === "default" ? "public" : dbConfig.giteaConfig?.visibility || "public",
123-
starredReposOrg: dbConfig.githubConfig?.starredReposOrg || "github", // Get from GitHub config
123+
starredReposOrg: dbConfig.githubConfig?.starredReposOrg || "starred", // Get from GitHub config
124124
preserveOrgStructure: dbConfig.giteaConfig?.preserveVisibility || false, // Map preserveVisibility
125125
mirrorStrategy: dbConfig.githubConfig?.mirrorStrategy || "preserve", // Get from GitHub config
126126
personalReposOrg: undefined, // Not stored in current schema

src/pages/api/config/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ export const GET: APIRoute = async ({ request }) => {
200200
includePrivate: false,
201201
includePublic: true,
202202
includeOrganizations: [],
203-
starredReposOrg: "github",
203+
starredReposOrg: "starred",
204204
mirrorStrategy: "preserve",
205205
defaultOrg: "github-mirrors",
206206
},

0 commit comments

Comments
 (0)