|
|
@@ -0,0 +1,495 @@
|
|
|
+# CLAUDE.md
|
|
|
+
|
|
|
+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
+
|
|
|
+## Project Overview
|
|
|
+
|
|
|
+Gogs (Go Git Service) is a painless self-hosted Git service written in Go. It provides a GitHub-like web interface for managing Git repositories with minimal resource requirements.
|
|
|
+
|
|
|
+- **Language**: Go 1.20+
|
|
|
+- **Web Framework**: Macaron (v1)
|
|
|
+- **Database**: Dual ORM system - XORM (legacy) transitioning to GORM (new)
|
|
|
+- **Supported Databases**: PostgreSQL, MySQL, SQLite3, MSSQL, TiDB
|
|
|
+- **Version**: 0.14.0+dev
|
|
|
+
|
|
|
+## Common Development Commands
|
|
|
+
|
|
|
+The project uses [Task](https://taskfile.dev) as its build tool. All commands are defined in `Taskfile.yml`.
|
|
|
+
|
|
|
+### Building and Running
|
|
|
+
|
|
|
+```bash
|
|
|
+# Build the binary
|
|
|
+task build
|
|
|
+
|
|
|
+# Build and start the web server
|
|
|
+task web
|
|
|
+
|
|
|
+# Build and start with auto-reload on file changes
|
|
|
+task web --watch
|
|
|
+
|
|
|
+# Run a release build (creates ZIP in release/ directory)
|
|
|
+task release
|
|
|
+```
|
|
|
+
|
|
|
+### Testing
|
|
|
+
|
|
|
+```bash
|
|
|
+# Run all tests with coverage and race detection
|
|
|
+task test
|
|
|
+
|
|
|
+# Drop test databases (PostgreSQL)
|
|
|
+task drop-test-db
|
|
|
+```
|
|
|
+
|
|
|
+### Code Generation
|
|
|
+
|
|
|
+```bash
|
|
|
+# Run all go:generate commands (including mocks)
|
|
|
+task generate
|
|
|
+
|
|
|
+# Generate database schema documentation
|
|
|
+task generate-schemadoc
|
|
|
+
|
|
|
+# Regenerate CSS from LESS files (IMPORTANT: Never edit .css files directly!)
|
|
|
+task less
|
|
|
+```
|
|
|
+
|
|
|
+### Code Quality
|
|
|
+
|
|
|
+```bash
|
|
|
+# Show all FIXME comments
|
|
|
+task fixme
|
|
|
+
|
|
|
+# Show all TODO comments
|
|
|
+task todo
|
|
|
+
|
|
|
+# Show legacy/deprecated code
|
|
|
+task legacy
|
|
|
+
|
|
|
+# Run linter
|
|
|
+golangci-lint run
|
|
|
+
|
|
|
+# Format code
|
|
|
+goimports -w .
|
|
|
+```
|
|
|
+
|
|
|
+### Development Setup
|
|
|
+
|
|
|
+See `docs/dev/local_development.md` for complete setup instructions. Key steps:
|
|
|
+
|
|
|
+1. Install dependencies: Go 1.20+, Git, PostgreSQL/MySQL/SQLite, Task, Less.js, goimports, go-mockgen
|
|
|
+2. Create database and user
|
|
|
+3. Create `custom/conf/app.ini` with database configuration
|
|
|
+4. Run `task web --watch` to start development server
|
|
|
+
|
|
|
+**Important**: Clone outside of `$GOPATH` (Go modules enabled).
|
|
|
+
|
|
|
+## High-Level Architecture
|
|
|
+
|
|
|
+### Application Structure
|
|
|
+
|
|
|
+The application uses a **single binary deployment model** with embedded assets. Entry point is `gogs.go` using `urfave/cli`.
|
|
|
+
|
|
|
+#### Main Commands
|
|
|
+
|
|
|
+- **`web`**: HTTP/HTTPS server (primary mode)
|
|
|
+- **`serv`**: Git operations over SSH (called by SSH server)
|
|
|
+- **`hook`**: Git hooks delegation (pre-receive, update, post-receive)
|
|
|
+- **`admin`**: CLI admin operations
|
|
|
+- **`backup`/`restore`**: Data backup/restore
|
|
|
+- **`import`**: Import repositories
|
|
|
+- **`cert`**: Generate TLS certificates
|
|
|
+
|
|
|
+### Routing Layer (Macaron-based)
|
|
|
+
|
|
|
+Routes are organized by feature domain in `internal/route/`:
|
|
|
+
|
|
|
+```
|
|
|
+internal/route/
|
|
|
+โโโ home.go # Home page
|
|
|
+โโโ install.go # Installation wizard
|
|
|
+โโโ admin/ # Admin panel routes
|
|
|
+โโโ api/v1/ # REST API v1
|
|
|
+โโโ org/ # Organization management
|
|
|
+โโโ repo/ # Repository routes (issues, PRs, settings, etc.)
|
|
|
+โโโ user/ # User routes (login, settings, profile)
|
|
|
+โโโ lfs/ # Git LFS routes
|
|
|
+```
|
|
|
+
|
|
|
+**Middleware Chain** (applied globally):
|
|
|
+```
|
|
|
+Logger โ Recovery โ GZIP โ Static โ Renderer โ i18n โ Session โ CSRF โ Contexter
|
|
|
+```
|
|
|
+
|
|
|
+**Authentication Middleware**:
|
|
|
+- `reqSignIn`: Requires authenticated user
|
|
|
+- `reqSignOut`: Requires unauthenticated (for login/register pages)
|
|
|
+- `reqAdmin`: Requires site admin
|
|
|
+- `reqRepoAdmin`/`reqRepoWriter`: Repository-level permissions
|
|
|
+
|
|
|
+### Context System
|
|
|
+
|
|
|
+Three main context types in `internal/context/`:
|
|
|
+
|
|
|
+1. **`context.Context`**: Main HTTP context
|
|
|
+ - Wraps `macaron.Context`
|
|
|
+ - User authentication state
|
|
|
+ - Flash messages, localization
|
|
|
+ - Template data management via `c.Data` map
|
|
|
+
|
|
|
+2. **`context.APIContext`**: API-specific context
|
|
|
+ - JSON response helpers
|
|
|
+ - API error handling
|
|
|
+
|
|
|
+3. **Repository Context** (`context.Repository`):
|
|
|
+ - Git repository handle (`GitRepo`)
|
|
|
+ - Access mode (read/write/admin/owner)
|
|
|
+ - Current branch/commit/tag
|
|
|
+
|
|
|
+**Important**: Macaron uses reflection to inject context into handlers:
|
|
|
+```go
|
|
|
+func Handler(c *context.Context, repo *context.Repository) {
|
|
|
+ // Dependencies automatically injected
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### Database Architecture
|
|
|
+
|
|
|
+**Dual ORM System** (migration in progress):
|
|
|
+- **XORM** (`internal/database/models.go`): Legacy ORM, being phased out
|
|
|
+- **GORM** (`internal/database/database.go`): New ORM for modern features
|
|
|
+
|
|
|
+**Global Database Handle**:
|
|
|
+```go
|
|
|
+// Access via database.Handle
|
|
|
+database.Handle.Users() // *UsersStore
|
|
|
+database.Handle.Repositories() // *RepositoriesStore
|
|
|
+database.Handle.Permissions() // *PermissionsStore
|
|
|
+database.Handle.AccessTokens() // *AccessTokensStore
|
|
|
+database.Handle.LoginSources() // *LoginSourcesStore
|
|
|
+database.Handle.TwoFactors() // *TwoFactorsStore
|
|
|
+```
|
|
|
+
|
|
|
+**Store Pattern**: Each domain has a dedicated "Store" (repository pattern) in `internal/database/`:
|
|
|
+- Stores encapsulate database operations for a domain
|
|
|
+- Methods accept `context.Context` as first parameter
|
|
|
+- Example: `UsersStore.GetByID()`, `UsersStore.Create()`, `UsersStore.Authenticate()`
|
|
|
+
|
|
|
+**Models** are defined alongside their stores in `internal/database/`:
|
|
|
+- `users.go`: User model + UsersStore
|
|
|
+- `repositories.go`: Repository model + RepositoriesStore
|
|
|
+- `permissions.go`: Access control logic
|
|
|
+- `issue.go`, `pull.go`: Issue and PR models
|
|
|
+- `webhook.go`: Webhook configuration
|
|
|
+
|
|
|
+**Migrations**: Located in `internal/database/migrations/`. Schema versioning via `Version` table.
|
|
|
+
|
|
|
+### Authentication System
|
|
|
+
|
|
|
+**Multi-Source Authentication** via Provider pattern (`internal/auth/`):
|
|
|
+
|
|
|
+Supported authentication types:
|
|
|
+1. **Plain**: Local database (bcrypt hashed passwords)
|
|
|
+2. **LDAP**: LDAP via BindDN
|
|
|
+3. **DLDAP**: LDAP simple auth (direct bind)
|
|
|
+4. **SMTP**: SMTP server authentication
|
|
|
+5. **PAM**: Linux PAM authentication
|
|
|
+6. **GitHub**: GitHub OAuth
|
|
|
+
|
|
|
+**Authentication Flow**:
|
|
|
+1. Check if local account (password hash validation)
|
|
|
+2. If external auth: Query login source from `login_sources` table
|
|
|
+3. Call `Provider.Authenticate()`
|
|
|
+4. Create/update user record
|
|
|
+5. Create session
|
|
|
+
|
|
|
+**Session Management**:
|
|
|
+- Configurable backend: file, Redis, memcache
|
|
|
+- Library: `github.com/go-macaron/session`
|
|
|
+
|
|
|
+**Token Authentication**:
|
|
|
+- Access tokens (SHA1 hashed) in `internal/database/access_tokens.go`
|
|
|
+- Priority: Session cookie โ HTTP Basic Auth โ Access token
|
|
|
+
|
|
|
+**Two-Factor Authentication**:
|
|
|
+- TOTP-based (Time-based One-Time Password)
|
|
|
+- Implementation in `internal/database/two_factors.go`
|
|
|
+
|
|
|
+### Git Operations
|
|
|
+
|
|
|
+**Git Command Execution**:
|
|
|
+- Wraps `github.com/gogs/git-module` library
|
|
|
+- Process management in `internal/process/` (timeouts, cancellation)
|
|
|
+
|
|
|
+**Git over HTTP** (`internal/route/repo/http.go`):
|
|
|
+- Proxies to `git-http-backend`
|
|
|
+- Operations: `git-upload-pack` (fetch/pull), `git-receive-pack` (push), `git-upload-archive`
|
|
|
+
|
|
|
+**Git over SSH** (`internal/cmd/serv.go`):
|
|
|
+- Called by SSH server via forced commands in `authorized_keys`
|
|
|
+- Parses `SSH_ORIGINAL_COMMAND`
|
|
|
+- Authenticates via public key
|
|
|
+- Executes Git commands directly
|
|
|
+
|
|
|
+**Git Hooks** (auto-generated per repository):
|
|
|
+- Scripts call `gogs hook pre-receive|update|post-receive`
|
|
|
+- Pre-receive: Branch protection, force push prevention
|
|
|
+- Post-receive: Trigger webhooks, update repository statistics
|
|
|
+
|
|
|
+**Repository Structure**:
|
|
|
+```
|
|
|
+<REPO_ROOT>/<owner>/<repo>.git/
|
|
|
+โโโ hooks/ # Git hooks (generated)
|
|
|
+โโโ custom_hooks/ # User-defined hooks
|
|
|
+โโโ objects/, refs/, etc.
|
|
|
+```
|
|
|
+
|
|
|
+### Template & View Rendering
|
|
|
+
|
|
|
+**Template Engine**: Go's `html/template` via Macaron renderer
|
|
|
+
|
|
|
+**Template Organization** (`templates/`):
|
|
|
+```
|
|
|
+templates/
|
|
|
+โโโ base/ # Layout and base components (head, header, footer)
|
|
|
+โโโ user/ # User-related pages (auth, settings)
|
|
|
+โโโ repo/ # Repository pages (home, issues, PRs, settings)
|
|
|
+โโโ admin/ # Admin panel
|
|
|
+โโโ org/ # Organization pages
|
|
|
+โโโ install.tmpl # Installation wizard
|
|
|
+โโโ status/ # Error pages (404, 500)
|
|
|
+```
|
|
|
+
|
|
|
+**Custom Template Functions** (`internal/template/template.go`):
|
|
|
+- Config: `AppName()`, `AppURL()`, `AppVer()`
|
|
|
+- User: `AvatarLink()`, `UserProfileLink()`
|
|
|
+- Time: `TimeSince()`, `DateFmtLong()`
|
|
|
+- Git: `ShortSHA1()`, `RenderCommitMessage()`
|
|
|
+- String: `Str2HTML()`, `EllipsisString()`
|
|
|
+
|
|
|
+**Template Data Injection**:
|
|
|
+```go
|
|
|
+c.Data["Title"] = "Page Title"
|
|
|
+c.Data["User"] = user
|
|
|
+c.Success("user/page") // renders templates/user/page.tmpl
|
|
|
+```
|
|
|
+
|
|
|
+**Localization**: Uses `github.com/go-macaron/i18n` with locale files in `conf/locale/*.ini`
|
|
|
+
|
|
|
+### Configuration System
|
|
|
+
|
|
|
+**INI-based Configuration**:
|
|
|
+- Default: `conf/app.ini` (embedded in binary)
|
|
|
+- User overrides: `custom/conf/app.ini` (runtime)
|
|
|
+- Loaded via `internal/conf/conf.go`
|
|
|
+
|
|
|
+**Custom Directory**: Everything under `custom/` overrides defaults:
|
|
|
+- `custom/conf/app.ini`: Configuration
|
|
|
+- `custom/templates/`: Template overrides
|
|
|
+- `custom/public/`: Static file overrides
|
|
|
+
|
|
|
+**Development Config** (`custom/conf/app.ini`):
|
|
|
+```ini
|
|
|
+RUN_MODE = dev
|
|
|
+
|
|
|
+[server]
|
|
|
+LOAD_ASSETS_FROM_DISK = true # Load templates/public from disk (no rebuild needed)
|
|
|
+OFFLINE_MODE = true # Work without internet
|
|
|
+
|
|
|
+[log.xorm]
|
|
|
+MODE = console # Enable SQL query logging
|
|
|
+```
|
|
|
+
|
|
|
+## Key Design Patterns
|
|
|
+
|
|
|
+### 1. Repository/Store Pattern
|
|
|
+Domain logic encapsulated in stores:
|
|
|
+```go
|
|
|
+user, err := database.Handle.Users().GetByUsername(ctx, username)
|
|
|
+```
|
|
|
+
|
|
|
+### 2. Middleware Chain Pattern
|
|
|
+Routes composed with middleware functions:
|
|
|
+```go
|
|
|
+m.Group("/user/settings", func() {
|
|
|
+ m.Get("", user.Settings)
|
|
|
+}, reqSignIn)
|
|
|
+```
|
|
|
+
|
|
|
+### 3. Provider Pattern
|
|
|
+Authentication sources implement common `Provider` interface
|
|
|
+
|
|
|
+### 4. Form Binding
|
|
|
+HTTP forms automatically bound to structs with validation:
|
|
|
+```go
|
|
|
+m.Post("/login", binding.Bind(form.SignIn{}), user.LoginPost)
|
|
|
+```
|
|
|
+
|
|
|
+### 5. Context Injection
|
|
|
+Macaron injects dependencies via reflection based on parameter types
|
|
|
+
|
|
|
+### 6. Service Layer
|
|
|
+Background services for long-running operations:
|
|
|
+- Cron jobs (`internal/cron/`): Repository statistics, cleanup
|
|
|
+- Mirror sync: Sync mirror repositories periodically
|
|
|
+- Webhook delivery: Async webhook delivery with retries
|
|
|
+
|
|
|
+## Important Development Notes
|
|
|
+
|
|
|
+### CSS Modifications
|
|
|
+**CRITICAL**: Never edit `.css` files directly! They are generated from `.less` files.
|
|
|
+
|
|
|
+1. Edit files in `public/less/`
|
|
|
+2. Run `task less` to regenerate CSS
|
|
|
+3. The `task less` command uses lessc with clean-css plugin
|
|
|
+
|
|
|
+### Template and Static Asset Development
|
|
|
+When actively developing templates/static files:
|
|
|
+
|
|
|
+1. Enable in `custom/conf/app.ini`:
|
|
|
+ ```ini
|
|
|
+ [server]
|
|
|
+ LOAD_ASSETS_FROM_DISK = true
|
|
|
+ ```
|
|
|
+2. No need to rebuild/restart after template changes
|
|
|
+3. Still run `task generate` if you modify `conf/`, `template/`, or `public/` structure
|
|
|
+
|
|
|
+### Database Testing
|
|
|
+- Use `internal/dbtest` helpers for database tests
|
|
|
+- In-memory SQLite for fast unit tests
|
|
|
+- PostgreSQL for integration tests
|
|
|
+- Run `task drop-test-db` to clean up test databases
|
|
|
+
|
|
|
+### Error Handling Patterns
|
|
|
+```go
|
|
|
+// Check specific error types
|
|
|
+if database.IsErrUserNotExist(err) {
|
|
|
+ c.NotFound()
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// Generic error handling
|
|
|
+c.NotFoundOrError(err, "get user")
|
|
|
+
|
|
|
+// Always wrap errors with context
|
|
|
+return errors.Wrap(err, "description")
|
|
|
+```
|
|
|
+
|
|
|
+### Common Operations
|
|
|
+
|
|
|
+**Checking Permissions**:
|
|
|
+```go
|
|
|
+mode := database.Handle.Permissions().AccessMode(ctx, userID, repoID, options)
|
|
|
+if mode < database.AccessModeWrite {
|
|
|
+ // Deny access
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**Database Transactions**:
|
|
|
+```go
|
|
|
+return db.Transaction(func(tx *gorm.DB) error {
|
|
|
+ // Operations
|
|
|
+ return nil
|
|
|
+})
|
|
|
+```
|
|
|
+
|
|
|
+**Redirecting**:
|
|
|
+```go
|
|
|
+c.Redirect("/user/login")
|
|
|
+c.RedirectSubpath("/admin") // Respects EXTERNAL_URL subpath
|
|
|
+```
|
|
|
+
|
|
|
+## Code Style
|
|
|
+
|
|
|
+- **Formatting**: Use `gofmt` and `goimports`
|
|
|
+- **Linting**: Configured via `.golangci.yml`
|
|
|
+- **Error Wrapping**: Always wrap errors with context
|
|
|
+- **Logging**: Use `log.Trace()`, `log.Info()`, `log.Error()` (from `unknwon.dev/clog/v2`)
|
|
|
+- **Comments**: English only in code comments and docstrings
|
|
|
+- **Style Guide**: Follow Sourcegraph's [Go style guide](https://docs.sourcegraph.com/dev/background-information/languages/go)
|
|
|
+
|
|
|
+## Contributing Guidelines
|
|
|
+
|
|
|
+From `.github/CONTRIBUTING.md`:
|
|
|
+
|
|
|
+- **Talk, then code**: Post proposals for new features to [Discussions - Proposal](https://github.com/gogs/gogs/discussions/categories/proposal)
|
|
|
+- **Self-review**: Always self-review before requesting reviews
|
|
|
+- **Incremental changes**: Make self-contained changes, avoid huge diffs
|
|
|
+- **No force push**: Unless absolutely necessary (makes review harder)
|
|
|
+- **English**: Use English in code comments and docstrings
|
|
|
+- **DO NOT** update locale files except `conf/locale_en-US.ini` (use [Crowdin](https://crowdin.com/project/gogs) instead)
|
|
|
+- **DO NOT** submit Docker compose files
|
|
|
+
|
|
|
+## Directory Structure Reference
|
|
|
+
|
|
|
+```
|
|
|
+/data/gogs/
|
|
|
+โโโ gogs.go # Main entry point
|
|
|
+โโโ gen.go # go:generate directives
|
|
|
+โโโ Taskfile.yml # Build tasks
|
|
|
+โโโ conf/ # Embedded default configuration and locales
|
|
|
+โโโ internal/ # Private application code
|
|
|
+โ โโโ cmd/ # CLI commands (web, serv, hook, admin, etc.)
|
|
|
+โ โโโ route/ # HTTP route handlers (admin, api, org, repo, user)
|
|
|
+โ โโโ context/ # Request context types
|
|
|
+โ โโโ database/ # ORM models and stores
|
|
|
+โ โ โโโ migrations/ # Database migrations
|
|
|
+โ โ โโโ schemadoc/ # Schema documentation generator
|
|
|
+โ โโโ auth/ # Authentication providers (LDAP, SMTP, PAM, GitHub)
|
|
|
+โ โโโ conf/ # Configuration loading and validation
|
|
|
+โ โโโ template/ # Template functions
|
|
|
+โ โโโ form/ # Form definitions and validation
|
|
|
+โ โโโ gitutil/ # Git utilities
|
|
|
+โ โโโ markup/ # Markdown/markup rendering
|
|
|
+โ โโโ email/ # Email service
|
|
|
+โ โโโ cron/ # Scheduled tasks
|
|
|
+โ โโโ ssh/ # Built-in SSH server
|
|
|
+โ โโโ ...util/ # Utility packages (cryptoutil, strutil, pathutil, etc.)
|
|
|
+โโโ public/ # Static assets
|
|
|
+โ โโโ css/ # Generated CSS (DO NOT EDIT)
|
|
|
+โ โโโ less/ # LESS source files (EDIT THESE)
|
|
|
+โ โโโ js/
|
|
|
+โ โโโ img/
|
|
|
+โโโ templates/ # Go templates
|
|
|
+โโโ scripts/ # Init scripts (systemd, supervisor, etc.)
|
|
|
+โโโ docs/ # Developer documentation
|
|
|
+ โโโ dev/local_development.md
|
|
|
+```
|
|
|
+
|
|
|
+## Architectural Decisions
|
|
|
+
|
|
|
+### Single Binary Deployment
|
|
|
+- All assets embedded (CSS, JS, templates, locales)
|
|
|
+- SQLite support for zero external dependencies
|
|
|
+- Prioritizes simplicity for self-hosting
|
|
|
+
|
|
|
+### Dual ORM Migration
|
|
|
+- Migrating from XORM to GORM gradually
|
|
|
+- GORM offers better maintenance, features (hooks, preloading), cleaner API
|
|
|
+- Both coexist during transition to avoid breaking changes
|
|
|
+
|
|
|
+### Macaron Framework
|
|
|
+- Lightweight, fast, excellent middleware support
|
|
|
+- Good i18n/session ecosystem
|
|
|
+- Familiar API (similar to Martini)
|
|
|
+
|
|
|
+## Testing
|
|
|
+
|
|
|
+Run tests with:
|
|
|
+```bash
|
|
|
+task test
|
|
|
+```
|
|
|
+
|
|
|
+Tests use:
|
|
|
+- Standard Go testing framework
|
|
|
+- `internal/dbtest` for database test helpers
|
|
|
+- Mock generation via `go-mockgen` (see `mockgen.yaml`)
|
|
|
+- Race detection enabled by default
|
|
|
+
|
|
|
+## Debugging
|
|
|
+
|
|
|
+- **Development Mode**: Set `RUN_MODE = dev` in config
|
|
|
+- **SQL Logging**: Set `[log.xorm] MODE = console` in config
|
|
|
+- **Template Debugging**: Logs template name on render
|
|
|
+- **Logging Levels**: TRACE, INFO, WARN, ERROR, FATAL (configured in app.ini)
|