This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
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.
The project uses Task as its build tool. All commands are defined in Taskfile.yml.
# 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
# Run all tests with coverage and race detection
task test
# Drop test databases (PostgreSQL)
task drop-test-db
# 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
# 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 .
See docs/dev/local_development.md for complete setup instructions. Key steps:
custom/conf/app.ini with database configurationtask web --watch to start development serverImportant: Clone outside of $GOPATH (Go modules enabled).
The application uses a single binary deployment model with embedded assets. Entry point is gogs.go using urfave/cli.
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 operationsbackup/restore: Data backup/restoreimport: Import repositoriescert: Generate TLS certificatesRoutes 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 userreqSignOut: Requires unauthenticated (for login/register pages)reqAdmin: Requires site adminreqRepoAdmin/reqRepoWriter: Repository-level permissionsThree main context types in internal/context/:
context.Context: Main HTTP context
macaron.Contextc.Data mapcontext.APIContext: API-specific context
Repository Context (context.Repository):
GitRepo)Important: Macaron uses reflection to inject context into handlers:
func Handler(c *context.Context, repo *context.Repository) {
// Dependencies automatically injected
}
Dual ORM System (migration in progress):
internal/database/models.go): Legacy ORM, being phased outinternal/database/database.go): New ORM for modern featuresGlobal Database Handle:
// 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/:
context.Context as first parameterUsersStore.GetByID(), UsersStore.Create(), UsersStore.Authenticate()Models are defined alongside their stores in internal/database/:
users.go: User model + UsersStorerepositories.go: Repository model + RepositoriesStorepermissions.go: Access control logicissue.go, pull.go: Issue and PR modelswebhook.go: Webhook configurationMigrations: Located in internal/database/migrations/. Schema versioning via Version table.
Multi-Source Authentication via Provider pattern (internal/auth/):
Supported authentication types:
Authentication Flow:
login_sources tableProvider.Authenticate()Session Management:
github.com/go-macaron/sessionToken Authentication:
internal/database/access_tokens.goTwo-Factor Authentication:
internal/database/two_factors.goGit Command Execution:
github.com/gogs/git-module libraryinternal/process/ (timeouts, cancellation)Git over HTTP (internal/route/repo/http.go):
git-http-backendgit-upload-pack (fetch/pull), git-receive-pack (push), git-upload-archiveGit over SSH (internal/cmd/serv.go):
authorized_keysSSH_ORIGINAL_COMMANDGit Hooks (auto-generated per repository):
gogs hook pre-receive|update|post-receiveRepository Structure:
<REPO_ROOT>/<owner>/<repo>.git/
├── hooks/ # Git hooks (generated)
├── custom_hooks/ # User-defined hooks
├── objects/, refs/, etc.
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):
AppName(), AppURL(), AppVer()AvatarLink(), UserProfileLink()TimeSince(), DateFmtLong()ShortSHA1(), RenderCommitMessage()Str2HTML(), EllipsisString()Template Data Injection:
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
INI-based Configuration:
conf/app.ini (embedded in binary)custom/conf/app.ini (runtime)internal/conf/conf.goCustom Directory: Everything under custom/ overrides defaults:
custom/conf/app.ini: Configurationcustom/templates/: Template overridescustom/public/: Static file overridesDevelopment Config (custom/conf/app.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
Domain logic encapsulated in stores:
user, err := database.Handle.Users().GetByUsername(ctx, username)
Routes composed with middleware functions:
m.Group("/user/settings", func() {
m.Get("", user.Settings)
}, reqSignIn)
Authentication sources implement common Provider interface
HTTP forms automatically bound to structs with validation:
m.Post("/login", binding.Bind(form.SignIn{}), user.LoginPost)
Macaron injects dependencies via reflection based on parameter types
Background services for long-running operations:
internal/cron/): Repository statistics, cleanupCRITICAL: Never edit .css files directly! They are generated from .less files.
public/less/task less to regenerate CSStask less command uses lessc with clean-css pluginWhen actively developing templates/static files:
Enable in custom/conf/app.ini:
[server]
LOAD_ASSETS_FROM_DISK = true
No need to rebuild/restart after template changes
Still run task generate if you modify conf/, template/, or public/ structure
internal/dbtest helpers for database teststask drop-test-db to clean up test databases// 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")
Checking Permissions:
mode := database.Handle.Permissions().AccessMode(ctx, userID, repoID, options)
if mode < database.AccessModeWrite {
// Deny access
}
Database Transactions:
return db.Transaction(func(tx *gorm.DB) error {
// Operations
return nil
})
Redirecting:
c.Redirect("/user/login")
c.RedirectSubpath("/admin") // Respects EXTERNAL_URL subpath
gofmt and goimports.golangci.ymllog.Trace(), log.Info(), log.Error() (from unknwon.dev/clog/v2)From .github/CONTRIBUTING.md:
conf/locale_en-US.ini (use Crowdin instead)/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
Run tests with:
task test
Tests use:
internal/dbtest for database test helpersgo-mockgen (see mockgen.yaml)RUN_MODE = dev in config[log.xorm] MODE = console in config