This commit is contained in:
Nicolas
2026-05-31 21:55:33 +02:00
parent b49ade87fc
commit 0a8344836a
15 changed files with 544 additions and 354 deletions
+9 -32
View File
@@ -4,10 +4,12 @@ This document explains how to contribute changes to the Gitea project. Topic-spe
| Topic | Document |
| :---- | :------- |
| Development environment, building | [docs/development.md](docs/development.md) |
| Setup and requirements | [docs/setup.md](docs/setup.md) |
| Building and the development workflow | [docs/development.md](docs/development.md) |
| Running the tests | [docs/testing.md](docs/testing.md) |
| Backend (Go modules, API v1) | [docs/guideline-backend.md](docs/guideline-backend.md) |
| Frontend (npm, UI guidelines) | [docs/guideline-frontend.md](docs/guideline-frontend.md) |
| Backend architecture and API v1 | [docs/guidelines-backend.md](docs/guidelines-backend.md) |
| Frontend architecture and UI guidelines | [docs/guidelines-frontend.md](docs/guidelines-frontend.md) |
| Refactoring | [docs/guidelines-refactoring.md](docs/guidelines-refactoring.md) |
| Maintainers, TOC, labels, merge queue, commit format for mergers | [docs/community-governance.md](docs/community-governance.md) |
| Release cycle, backports, tagging releases | [docs/release-management.md](docs/release-management.md) |
@@ -45,7 +47,7 @@ This document explains how to contribute changes to the Gitea project. Topic-spe
It assumes you have followed the [installation instructions](https://docs.gitea.com/category/installation). \
Sensitive security-related issues should be reported to [security@gitea.io](mailto:security@gitea.io).
For configuring IDEs for Gitea development, see the [contributed IDE configurations](contrib/ide/).
For configuring IDEs for Gitea development, see the [IDE setup notes](docs/development.md#ide-configuration) and the [contributed configurations](contrib/development/).
## AI Contribution Policy
@@ -108,7 +110,8 @@ If further discussion is needed, we encourage you to open a new issue instead an
## Building Gitea
See the [development setup instructions](https://docs.gitea.com/development/hacking-on-gitea).
See [docs/setup.md](docs/setup.md) for prerequisites and [docs/development.md](docs/development.md)
for building Gitea and the development workflow.
## Styleguide
@@ -127,33 +130,7 @@ Afterwards, copyright should only be modified when the copyright author changes.
## Testing
Before submitting a pull request, run all tests to make sure your changes don't cause a regression elsewhere.
Here's how to run the test suite:
- code lint
| | |
| :-------------------- | :--------------------------------------------------------------------------- |
|``make lint`` | lint everything (not needed if you only change the front- **or** backend) |
|``make lint-frontend`` | lint frontend files |
|``make lint-backend`` | lint backend files |
- run tests (we suggest running them on Linux)
| Command | Action | |
|:----------------------------------------------|:-----------------------------------------------------| ------------------------------------------- |
| ``make test-backend[\#SpecificTestName]`` | run unit test(s) | |
| ``make test-integration[\#SpecificTestName]`` | run [integration](tests/integration) test(s) | [More details](tests/integration/README.md) |
| ``make test-e2e`` | run [end-to-end](tests/e2e) test(s) using Playwright | |
- E2E test environment variables
| Variable | Description |
| :-------------------------------- | :---------------------------------------------------------- |
| ``GITEA_TEST_E2E_DEBUG`` | When set, show Gitea server output |
| ``GITEA_TEST_E2E_FLAGS`` | Additional flags passed to Playwright, for example ``--ui`` |
| ``GITEA_TEST_E2E_TIMEOUT_FACTOR`` | Timeout multiplier (default: 4 on CI, 1 locally) |
Before submitting a pull request, run the linters (`make lint`, or the scoped `make lint-backend` / `make lint-frontend`) and the tests to make sure your changes don't cause a regression elsewhere. See [docs/testing.md](docs/testing.md) for how to run the unit, integration, end-to-end, and migration tests.
## Translation
+2 -8
View File
@@ -44,17 +44,11 @@ From the root of the source tree, run:
TAGS="bindata" make build
The `build` target is split into two sub-targets:
- `make backend` which requires [Go Stable](https://go.dev/dl/), the required version is defined in [go.mod](/go.mod).
- `make frontend` which requires [Node.js LTS](https://nodejs.org/en/download/) or greater and [pnpm](https://pnpm.io/installation).
Internet connectivity is required to download the go and npm modules. When building from the official source tarballs which include pre-built frontend files, the `frontend` target will not be triggered, making it possible to build without Node.js.
See [docs/setup.md](docs/setup.md) for prerequisites and [docs/development.md](docs/development.md)
for setting up a local development environment, continuous builds, linting, and testing.
More info: https://docs.gitea.com/installation/install-from-source
For setting up a local development environment, continuous builds, linting, and testing, see [docs/development.md](docs/development.md).
## Using
After building, a binary file named `gitea` will be generated in the root of the source tree by default. To run it, use:
+3 -1
View File
@@ -1,12 +1,14 @@
# IDE and code editor configuration
## Table of Contents
- [IDE and code editor configuration](#ide-and-code-editor-configuration)
- [Microsoft Visual Studio Code](#microsoft-visual-studio-code)
## Microsoft Visual Studio Code
Download Microsoft Visual Studio Code at https://code.visualstudio.com/ and follow instructions at https://code.visualstudio.com/docs/languages/go to setup Go extension for it.
Create new directory `.vscode` in Gitea root folder and copy contents of folder [contrib/ide/vscode](vscode/) to it. You can now use `Ctrl`+`Shift`+`B` to build gitea executable and `F5` to run it in debug mode.
Create new directory `.vscode` in Gitea root folder and copy contents of folder [contrib/development/vscode](vscode/) to it. You can now use `Ctrl`+`Shift`+`B` to build gitea executable and `F5` to run it in debug mode.
Supported on Debian, Ubuntu, Red Hat, Fedora, SUSE Linux, MacOS and Microsoft Windows.
+76 -124
View File
@@ -1,189 +1,141 @@
# Developing Gitea
# Development
This document describes how to set up a local development environment and build Gitea from source. For the contribution workflow and review process, see [CONTRIBUTING.md](../CONTRIBUTING.md).
This document describes how to build Gitea from source and the day-to-day
development workflow. For prerequisites and how to obtain the code, see
[setup.md](setup.md). For running tests, see [testing.md](testing.md). For the
contribution workflow and review process, see [CONTRIBUTING.md](../CONTRIBUTING.md).
## Installing dependencies
Area-specific guidelines:
### Go
- [Backend development guidelines](guidelines-backend.md)
- [Frontend development guidelines](guidelines-frontend.md)
- [Refactoring guidelines](guidelines-refactoring.md)
[Install Go](https://go.dev/doc/install) and set up your Go environment correctly. The required version is the one declared in [`go.mod`](../go.mod).
## Building
Gitea uses `gofmt` to format source code. The results of `gofmt` can differ between Go versions, so it is recommended to install the same version that our continuous integration runs.
> [!NOTE]
> When running make tasks that require external tools, such as `make watch-backend`, Gitea downloads and builds them as needed. To use them you must have the `"$GOPATH"/bin` directory on your executable path. If you don't, you will have to manage these tools yourself.
### Node.js
[Install Node.js](https://nodejs.org/en/download/), which is required to build the JavaScript and CSS files. The minimum supported version is the one declared in [`package.json`](../package.json); the latest LTS version is recommended. Gitea uses [pnpm](https://pnpm.io/) to manage frontend dependencies; the `make` targets invoke it for you, so a manual install is only needed if you want to run `pnpm` commands directly.
### Python (optional)
To lint the template files, ensure [Python](https://www.python.org/) and [Poetry](https://python-poetry.org/) are installed.
### Make
Gitea makes heavy use of Make to automate tasks and improve development. On Linux and macOS it is usually preinstalled or available from the system package manager.
#### On Windows
Make can be provided on Windows by either of these:
- [MinGW-w64](https://www.mingw-w64.org) / [MSYS2](https://www.msys2.org/).
- MSYS2 is a collection of tools and libraries providing an easy-to-use environment for building, installing and running native Windows software; it includes MinGW-w64.
- In MinGW-w64, the binary is called `mingw32-make.exe` instead of `make.exe`. Add the `bin` folder to `PATH`.
- In MSYS2, you can use `make` directly. See [MSYS2 Porting](https://www.msys2.org/wiki/Porting/).
- [Chocolatey package](https://chocolatey.org/packages/make). Run `choco install make`.
> [!NOTE]
> If you are building with make from the Windows Command Prompt, you may run into issues. The prompts above (Git Bash or MinGW) are recommended. If you only have Command Prompt (or PowerShell) you can set environment variables using the [set](https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/set_1) command, e.g. `set TAGS=bindata`.
## Downloading and cloning the Gitea source code
The recommended method of obtaining the source code is by using `git clone`.
To build Gitea for development, run:
```bash
git clone https://github.com/go-gitea/gitea
make build
```
## Forking Gitea
No build tags are required: SQLite support is compiled in by default, which is
enough for local development. The `build` target runs two sub-targets, `frontend`
and `backend`. The `bindata` tag embeds the frontend assets into the binary and is
only needed when packaging a self-contained build, so leave it out during
development.
To contribute changes, [fork the Gitea repository](https://github.com/go-gitea/gitea) on GitHub and add your fork as a git remote so you can push branches and open pull requests. See GitHub's [working with forks](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks) documentation for the details.
See `make help` for all available targets, and the workflows in
[`.github/workflows`](https://github.com/go-gitea/gitea/tree/main/.github/workflows)
to see how continuous integration builds and checks Gitea.
## Building Gitea
## Building continuously
See the [build from source instructions](https://docs.gitea.com/installation/install-from-source) for the full details.
The simplest recommended way to build from source for development is:
To rebuild automatically when source files change:
```bash
TAGS="sqlite" make build
```
The default `sqlite` tag uses the pure-Go [modernc](https://modernc.org/sqlite) driver, so no C compiler or extra tags are needed. To use the CGO-based mattn driver instead, build with `TAGS="sqlite sqlite_mattn sqlite_unlock_notify"`.
The `build` target executes both the `frontend` and `backend` sub-targets. The `bindata` tag embeds the frontend files into the binary; it is only needed for packaging a self-contained build and should be left out during development so that frontend changes are picked up without rebuilding.
See `make help` for all available `make` targets, and the workflows in [`.github/workflows`](https://github.com/go-gitea/gitea/tree/main/.github/workflows) to see how our continuous integration works.
### Building continuously
To run and continuously rebuild when source files change:
```bash
# for both frontend and backend
# watch both frontend and backend
make watch
# or: watch frontend files (html/js/css) only
# or watch only the frontend (starts the Vite dev server)
make watch-frontend
# or: watch backend files (go) only
# or watch only the backend (Go)
make watch-backend
```
On macOS, watching all backend source files may hit the default open files limit, which can be raised via `ulimit -n 12288` for the current shell or in your shell startup file for all future shells.
Watching all backend source files may hit the default open-files limit on macOS or
Linux; raise it with `ulimit -n 12288` for the current shell, or in your shell
startup file to make it permanent.
### Formatting, code analysis and spell check
## Formatting, linting and checks
Our continuous integration will reject PRs that fail the linters (including format check, code analysis and spell check).
Format your code:
Continuous integration rejects pull requests that fail formatting, linting, or
consistency checks. Format your code first:
```bash
make fmt
```
and lint the source code:
Then lint:
```bash
# lint both frontend and backend code
# lint everything
make lint
# lint only backend code
# or only one side
make lint-backend
```
### Working on JS and CSS
Frontend development should follow the [Guidelines for Frontend Development](https://docs.gitea.com/contributing/guidelines-frontend).
Before committing, make sure the linters pass:
```bash
make lint-frontend
```
### Building and adding SVGs
Many linters can fix issues automatically with `make lint-fix` (or the scoped
`make lint-backend-fix` / `make lint-frontend-fix`). The combined consistency
checks that CI runs are available as `make checks`.
SVG icons are built using the `make svg` target, which compiles the icon sources into the output directory `public/assets/img/svg`. Custom icons can be added in the `web_src/svg` directory.
## Building and adding SVGs
### Building the logo
SVG icons are built with `make svg`, which compiles the icon sources into
`public/assets/img/svg`. Custom icons can be added under `web_src/svg`.
The PNG and SVG versions of the Gitea logo are built from a single SVG source file `assets/logo.svg` using the `TAGS="gitea" make generate-images` target. Node.js and pnpm must be available to run it.
## Updating the API
The same process can generate custom logo PNGs from an SVG source file by updating `assets/logo.svg` and running `make generate-images`. Omitting the `gitea` tag updates only the user-designated logo files.
When you create or change API routes, you **must** update the
[Swagger](https://swagger.io/docs/specification/2-0/what-is-swagger/) documentation
using [go-swagger](https://goswagger.io/) comments. See the
[backend development guidelines](guidelines-backend.md) for how API routes,
request/response structs, and swagger definitions fit together.
### Updating the API
When creating or modifying API routes, you **MUST** update and/or create [Swagger](https://swagger.io/docs/specification/2-0/what-is-swagger/) documentation for them using [go-swagger](https://goswagger.io/) comments. The structure of these comments is described in the [specification](https://goswagger.io/use/spec.html#annotation-syntax). For more information about the Swagger structure, see the [Swagger 2.0 Documentation](https://swagger.io/docs/specification/2-0/basic-structure/), or compare with a previous PR adding a new API endpoint, e.g. [PR #5483](https://github.com/go-gitea/gitea/pull/5843/files#diff-2e0a7b644cf31e1c8ef7d76b444fe3aaR20).
Be careful not to break the API for downstream users who depend on a stable API. In general, additions are acceptable, but deletions or fundamental changes to the API will be rejected.
Once you have created or changed an API endpoint, regenerate the Swagger documentation:
Regenerate and validate the spec after changing an endpoint, then commit the
updated JSON:
```bash
make generate-swagger
```
Validate your generated Swagger file:
```bash
make swagger-validate
```
Commit the changed Swagger JSON file. The continuous integration server checks that this has been done using:
CI verifies the committed spec is up to date with:
```bash
make swagger-check
```
### Creating new configuration options
## Creating new configuration options
When creating new configuration options, it is not enough to add them to the `modules/setting` files. You should also add information to the [configuration cheat sheet](https://docs.gitea.com/administration/config-cheat-sheet), which lives in the [documentation repository](https://gitea.com/gitea/docs).
When adding configuration options it is not enough to add them to the
`modules/setting` files. Also update
[`custom/conf/app.example.ini`](../custom/conf/app.example.ini), and document them in
the [configuration cheat sheet](https://docs.gitea.com/administration/config-cheat-sheet),
which lives in the [documentation repository](https://gitea.com/gitea/docs).
### Database migrations
## Database migrations
If you make breaking changes to any of the database-persisted structs in the `models/` directory, you will need to add a new migration in `models/migrations/`.
If you make breaking changes to a database-persisted struct under `models/`, add a
new migration in `models/migrations/`. See [testing.md](testing.md#migration-tests)
for running the migration tests.
## Testing
For how to run the backend, integration, e2e, and migration tests, see [docs/testing.md](testing.md).
For unit, integration, end-to-end, and migration tests, see [testing.md](testing.md).
## Documentation for the website
## IDE configuration
Documentation for the website lives in the [documentation repository](https://gitea.com/gitea/docs). The `docs/` directory in this repository holds contributor-facing documents only; if you change them you can check that they pass continuous integration using:
### Visual Studio Code
```bash
make lint-md
```
A `launch.json` and `tasks.json` are provided in
[`contrib/development/vscode`](../contrib/development/vscode). See
[`contrib/development/README.md`](../contrib/development/README.md) for details.
## Visual Studio Code
### GoLand
A `launch.json` and `tasks.json` are provided in [`contrib/development/vscode`](../contrib/development/vscode). See [`contrib/development/README.md`](../contrib/development/README.md) for more information.
Clicking the `Run Application` arrow on `func main()` in `/main.go` starts a
debuggable Gitea instance.
## GoLand
The `Output Directory` in `Run/Debug Configuration` **must** be set to the Gitea
project directory (the one containing `main.go` and `go.mod`). Otherwise the working
directory is a GoLand temporary directory, which prevents Gitea from loading dynamic
resources (such as templates) in development.
Clicking the `Run Application` arrow on the function `func main()` in `/main.go` can quickly start a debuggable Gitea instance.
## Submitting your changes
The `Output Directory` in `Run/Debug Configuration` MUST be set to the Gitea project directory (which contains `main.go` and `go.mod`). Otherwise the started instance's working directory is a GoLand temporary directory, which prevents Gitea from loading dynamic resources (e.g. templates) in a development environment.
To run unit tests with SQLite in GoLand, set `-tags sqlite` in `Go tool arguments` of `Run/Debug Configuration`.
## Submitting PRs
Once you're happy with your changes, push them up and open a pull request. It is recommended that you allow Gitea Managers and Owners to modify your PR branches, as we will need to update it to main before merging and may be able to help fix issues directly.
Any PR requires two approvals from the Gitea maintainers and needs to pass continuous integration. See the [CONTRIBUTING.md](../CONTRIBUTING.md) document.
If you need more help, pop on to [Discord](https://discord.gg/gitea) #Develop and chat there.
That's it! You are ready to start developing Gitea.
Push your branch and open a pull request. See [CONTRIBUTING.md](../CONTRIBUTING.md)
for the review process and PR requirements. For help, join the `#Develop` channel on
[Discord](https://discord.gg/gitea).
-63
View File
@@ -1,63 +0,0 @@
# Backend development
This document covers backend-specific contribution expectations. For general contribution workflow, see [CONTRIBUTING.md](../CONTRIBUTING.md).
For coding style and architecture, see also the [backend development guideline](https://docs.gitea.com/contributing/guidelines-backend) on the documentation site.
## Dependencies
Go dependencies are managed using [Go Modules](https://go.dev/cmd/go/#hdr-Module_maintenance). \
You can find more details in the [go mod documentation](https://go.dev/ref/mod) and the [Go Modules Wiki](https://github.com/golang/go/wiki/Modules).
Pull requests should only modify `go.mod` and `go.sum` where it is related to your change, be it a bugfix or a new feature. \
Apart from that, these files should only be modified by Pull Requests whose only purpose is to update dependencies.
The `go.mod`, `go.sum` update needs to be justified as part of the PR description,
and must be verified by the reviewers and/or merger to always reference
an existing upstream commit.
## API v1
The API is documented by [swagger](https://gitea.com/api/swagger) and is based on [the GitHub API](https://docs.github.com/en/rest).
### GitHub API compatibility
Gitea's API should use the same endpoints and fields as the GitHub API as far as possible, unless there are good reasons to deviate. \
If Gitea provides functionality that GitHub does not, a new endpoint can be created. \
If information is provided by Gitea that is not provided by the GitHub API, a new field can be used that doesn't collide with any GitHub fields. \
Updating an existing API should not remove existing fields unless there is a really good reason to do so. \
The same applies to status responses. If you notice a problem, feel free to leave a comment in the code for future refactoring to API v2 (which is currently not planned).
### Adding/Maintaining API routes
All expected results (errors, success, fail messages) must be documented ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L319-L327)). \
All JSON input types must be defined as a struct in [modules/structs/](modules/structs/) ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/modules/structs/issue.go#L76-L91)) \
and referenced in [routers/api/v1/swagger/options.go](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/swagger/options.go). \
They can then be used like [this example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L318). \
All JSON responses must be defined as a struct in [modules/structs/](modules/structs/) ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/modules/structs/issue.go#L36-L68)) \
and referenced in its category in [routers/api/v1/swagger/](routers/api/v1/swagger/) ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/swagger/issue.go#L11-L16)) \
They can be used like [this example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L277-L279).
### When to use what HTTP method
In general, HTTP methods are chosen as follows:
- **GET** endpoints return the requested object(s) and status **OK (200)**
- **DELETE** endpoints return the status **No Content (204)** and no content either
- **POST** endpoints are used to **create** new objects (e.g. a User) and return the status **Created (201)** and the created object
- **PUT** endpoints are used to **add/assign** existing Objects (e.g. a user to a team) and return the status **No Content (204)** and no content either
- **PATCH** endpoints are used to **edit/change** an existing object and return the changed object and the status **OK (200)**
### Requirements for API routes
All parameters of endpoints changing/editing an object must be optional (except the ones to identify the object, which are required).
Endpoints returning lists must
- support pagination (`page` & `limit` options in query)
- set `X-Total-Count` header via **SetTotalCountHeader** ([example](https://github.com/go-gitea/gitea/blob/7aae98cc5d4113f1e9918b7ee7dd09f67c189e3e/routers/api/v1/repo/issue.go#L444))
### Knowledge
- Partially database table migration must use `SyncWithOptions(IgnoreDrop...)`
- Template variables with "camelCase" or "snake_case" are used for restoring the form values from a submitted form
-17
View File
@@ -1,17 +0,0 @@
# Frontend development
This document covers frontend-specific contribution expectations. For general contribution workflow, see [CONTRIBUTING.md](../CONTRIBUTING.md).
## Dependencies
For the frontend, we use [npm](https://www.npmjs.com/).
The same restrictions apply for frontend dependencies as for [backend dependencies](guideline-backend.md#dependencies), with the exceptions that the files for it are `package.json` and `package-lock.json`, and that new versions must always reference an existing version.
## Design guideline
Depending on your change, please read the
- [backend development guideline](https://docs.gitea.com/contributing/guidelines-backend)
- [frontend development guideline](https://docs.gitea.com/contributing/guidelines-frontend)
- [refactoring guideline](https://docs.gitea.com/contributing/guidelines-refactoring)
+137
View File
@@ -0,0 +1,137 @@
# Backend development guidelines
This document covers backend-specific architecture and contribution expectations.
For the general workflow see [CONTRIBUTING.md](../CONTRIBUTING.md), and for building
and testing see [development.md](development.md) and [testing.md](testing.md).
## Background
The backend is written in Go. Web routing is handled by
[chi](https://github.com/go-chi/chi) and database access goes through the
[XORM](https://xorm.io/) ORM. Understanding how the packages depend on each other is
essential before contributing backend code.
## Package design
### Package layout
The backend is split into top-level packages, each with a focused responsibility:
- `build`: helper scripts used at compile time
- `cmd`: subcommands such as `web`, `serv`, `hooks`, `doctor`, and admin utilities
- `models`: data structures and database operations (XORM); keeps external
dependencies to a minimum
- `models/db`: core database operations
- `models/fixtures`: sample data used by tests
- `models/migrations`: schema migration scripts
- `modules`: standalone functionality with few dependencies
- `modules/setting`: configuration handling
- `modules/git`: interaction with the Git command line
- `routers`: request handlers, split into `api`, `web`, `install`, and `private`
- `services`: business logic that ties routers and models together
- `templates`: Go HTML templates
- `public`: compiled frontend assets
- `tests`: integration and end-to-end test helpers
### Dependency direction
Dependencies only flow in one direction:
```text
cmd → routers → services → models → modules
```
A package on the left may import a package on its right, but never the reverse.
### Naming conventions
- Top-level packages use the plural form: `services`, `models`, `routers`.
- Subpackages use the singular form: `services/user`, `models/repository`.
When packages from different layers share a name, use a snake_case import alias to
disambiguate:
```go
import user_service "gitea.dev/services/user"
```
### Database transactions
Operations that must roll back together should run inside `db.WithTx()` (or
`db.WithTx2()` when a value must be returned), defined in `models/db/context.go`.
Functions that participate in a transaction take a `context.Context` as their first
parameter so the transaction can be propagated.
### Implementing `io.Closer`
Types that implement `io.Closer` must tolerate `Close()` being called more than once
without panicking.
### XORM gotchas
- Never call `x.Update(exemplar)` without an explicit `WHERE` clause — it updates
every row in the table.
- Partial table migrations must use `SyncWithOptions(IgnoreDrop...)` rather than a
plain `Sync`.
- When inserting rows with preset IDs, MSSQL requires `SET IDENTITY_INSERT` to be
enabled and PostgreSQL requires the sequence to be updated afterwards.
## Dependencies
Go dependencies are managed with [Go Modules](https://go.dev/ref/mod).
Pull requests should only modify `go.mod` and `go.sum` where it relates to the
change at hand, be it a bug fix or a new feature. Otherwise, these files should only
be touched by pull requests whose sole purpose is updating dependencies. Run
`make tidy` after any change to `go.mod`.
Any `go.mod` / `go.sum` update must be justified in the PR description and must be
verified by reviewers and the merger to reference an existing upstream commit.
## API v1
The API is documented with [Swagger](https://gitea.com/api/swagger) and is modelled
on [the GitHub API](https://docs.github.com/en/rest).
### GitHub API compatibility
Gitea's API should use the same endpoints and fields as the GitHub API where
possible, unless there is a good reason to deviate.
- If Gitea offers functionality GitHub does not, a new endpoint may be added.
- If Gitea exposes information the GitHub API does not, a new field may be added as
long as it does not collide with a GitHub field.
- Existing fields should not be removed unless there is a strong reason; the same
applies to status responses.
If you notice a problem that would require a breaking change, leave a comment in the
code for a future refactor to API v2 (which is currently not planned) rather than
breaking v1.
### Adding and maintaining API routes
- All possible results (errors, success, and failure messages) must be documented in
the swagger comments on the route.
- Every JSON request body must be defined as a struct in `modules/structs/` and
registered in [`routers/api/v1/swagger/options.go`](../routers/api/v1/swagger/options.go).
- Every JSON response must be defined as a struct in `modules/structs/` and
registered with its category under [`routers/api/v1/swagger/`](../routers/api/v1/swagger).
### HTTP methods and status codes
In general, choose HTTP methods as follows:
- **GET** returns the requested object(s) with status **200 OK**.
- **POST** creates a new object (e.g. a user) and returns **201 Created** with the
created object.
- **PUT** adds or assigns an existing object (e.g. a user to a team) and returns
**204 No Content** with no body.
- **PATCH** edits an existing object and returns the changed object with **200 OK**.
- **DELETE** removes an object and returns **204 No Content** with no body.
### Requirements for API routes
- All parameters of endpoints that edit an object must be optional, except those
needed to identify the object, which are required.
- Endpoints returning lists must support pagination (`page` and `limit` query
options) and set the `X-Total-Count` header via `ctx.SetTotalCountHeader(...)`.
+106
View File
@@ -0,0 +1,106 @@
# Frontend development guidelines
This document covers frontend-specific architecture and contribution expectations.
For the general workflow see [CONTRIBUTING.md](../CONTRIBUTING.md), and for building
and testing see [development.md](development.md) and [testing.md](testing.md).
## Background
The frontend uses [Vue 3](https://vuejs.org/), [Fomantic-UI](https://fomantic-ui.com/)
(built on jQuery), [htmx](https://htmx.org/) for partial page updates, and
[Tailwind CSS](https://tailwindcss.com/). Pages are rendered with Go HTML templates.
Source files live in:
- `web_src/css/`: CSS styles
- `web_src/js/`: JavaScript and TypeScript
- `web_src/js/components/`: Vue components
- `web_src/js/features/`: feature modules wired up at page load
- `templates/`: Go HTML templates
## Dependencies
Frontend dependencies are managed with [pnpm](https://pnpm.io/). The same rules as
for [backend dependencies](guidelines-backend.md#dependencies) apply, except the
relevant files are `package.json` and `pnpm-lock.yaml`, and new versions must always
reference an existing published version.
## Framework usage
Mixing frameworks arbitrarily makes code hard to maintain. Recommended combinations:
- Vue with vanilla JavaScript
- Fomantic-UI (jQuery)
- htmx for partial page reloads
- Vanilla JavaScript
Avoid combinations such as Vue with Fomantic-UI, jQuery with htmx, or htmx with heavy
JavaScript dependencies. Vue components may reuse Fomantic-UI CSS classes for visual
consistency. Use Go templates for simple or SEO-relevant pages and Vue for complex,
interactive pages. Gitea uses Vue 3 **without** JSX to keep HTML and JavaScript
separate.
> [!NOTE]
> Fomantic-UI is not an accessibility-friendly framework. Gitea patches some ARIA
> behavior, but accessibility work is ongoing — prefer semantic HTML and test
> keyboard/screen-reader behavior where you can.
## Gitea-specific conventions
- Keep features in their own files or directories.
- Use kebab-case for HTML `id`s and classes, ideally with 2-3 feature keywords.
- Prefix classes used only as JavaScript hooks with `js-`, and keep them unique
across the project.
- Create a new class name when overriding framework styles instead of editing the
framework's own classes.
- Pass complex data to the frontend via `ctx.PageData["myModuleData"]` rather than
embedding models directly, to avoid leaking sensitive fields.
- Prefer semantic elements such as `<button>` over generic `<div>`s.
- Avoid `!important`; when it is unavoidable, document why.
- Prefix custom DOM events with `ce-`.
## CSS
Prefer Tailwind utility classes with the `tw-` prefix, and the `flex-*` layout
helpers over per-child margins. Gitea also ships a small set of custom helpers:
`gt-` for general helpers and `g-` for framework-level helpers (see
`web_src/css/helpers.css`); use these only when a Tailwind utility does not exist.
Write class attributes as a single readable unit in templates:
```html
<div class="tw-flex tw-items-center {{if .IsFoo}}tw-hidden{{end}}"></div>
```
## TypeScript
- Use `import type` for type-only imports.
- Prefer `@ts-expect-error` over `@ts-ignore`.
- Use the `!` non-null assertion (rather than `?.`/`??`) when a value is known to
always exist.
- Only mark a function `async` when it actually uses `await` or returns a `Promise`.
Avoid async event listeners; if unavoidable, call `e.preventDefault()` before the
first `await`. For a deliberately un-awaited call, assign it: `const _promise = asyncFoo()`.
## Data fetching
Use the `GET`, `POST`, `PUT`, `PATCH`, and `DELETE` wrappers from
[`web_src/js/modules/fetch.ts`](../web_src/js/modules/fetch.ts); they add the CSRF
token automatically.
## DOM attributes
Avoid `node.dataset` because of its camel-casing behavior; use `node.getAttribute`
in new code. Never bind user-provided data directly onto DOM nodes.
## Showing and hiding elements
- In Vue, use `v-if` and `v-show`.
- In Go templates and plain JavaScript, use the `.tw-hidden` class together with the
`showElem()`, `hideElem()`, and `toggleElem()` helpers from
[`web_src/js/utils/dom.ts`](../web_src/js/utils/dom.ts).
## UI component gallery
When running Gitea in development mode, standardized UI components are available at
`/devtest` (for example `http://localhost:3000/devtest`). These pages are also used
by the e2e tests.
+38
View File
@@ -0,0 +1,38 @@
# Refactoring guidelines
This document covers expectations for refactoring work. For the general workflow see
[CONTRIBUTING.md](../CONTRIBUTING.md).
## Background
Gitea is a large, long-lived project. Over time the codebase has accumulated
outdated mechanisms, mixed frameworks, and legacy code that can cause bugs or slow
down new features. Refactoring keeps the codebase maintainable, but it needs to be
done carefully so it improves things without introducing regressions.
## Writing a refactoring PR
- Be forward-looking: address the root cause, not just the immediate symptom.
- Aim to reduce ambiguity and conflicts and to improve maintainability.
- Explain the rationale in the PR description: why the refactor is necessary, how it
resolves the legacy problem, and its advantages and disadvantages.
- Keep the scope tight: preserve existing behavior where feasible and avoid bundling
unrelated changes.
- Break large refactors into intermediate steps across multiple PRs so each one is
easy to review.
- Include tests that verify the behavior stays correct.
- Prefer scheduling non-bugfix refactoring early in a milestone, so any issues
surface well before a release.
- If there is disagreement about a refactor, escalate to the Technical Oversight
Committee (TOC) for a decision.
## Reviewing and merging
- Keep refactoring PRs short-lived (typically no more than 7 days) with quick review
cycles, and merge them promptly so they do not block on unrelated work.
- A non-author core member may approve and merge a refactoring PR after 7 days if the
TOC has raised no objection.
- Accept imperfect intermediate implementations as long as the final result improves
the codebase.
- A temporary regression caused by a necessary refactor is acceptable if it is fixed
promptly afterwards.
+67
View File
@@ -0,0 +1,67 @@
# Setup and requirements
This document lists the tools you need to build Gitea from source and how to get
the code. Once your environment is ready, see [development.md](development.md) for
the build and development workflow, and [testing.md](testing.md) for running tests.
For the contribution workflow and review process, see [CONTRIBUTING.md](../CONTRIBUTING.md).
## Requirements
### Go
[Install Go](https://go.dev/doc/install) and set up your Go environment. The
required version is the one declared in [`go.mod`](../go.mod); installing the same
version your continuous integration uses avoids `gofmt` differences between Go
releases.
> [!NOTE]
> Some `make` tasks build external Go tools on demand (for example `make
> watch-backend`). To use them, the `"$GOPATH"/bin` directory must be on your
> executable `PATH`; otherwise you have to manage those tools yourself.
### Node.js and pnpm
[Install Node.js](https://nodejs.org/en/download/) to build the JavaScript and CSS
files. The minimum supported version is the one declared in
[`package.json`](../package.json) (`engines.node`); the latest LTS is recommended.
Gitea manages frontend dependencies with [pnpm](https://pnpm.io/). The `make`
targets invoke it for you, so installing pnpm manually is only needed if you want
to run `pnpm` commands directly.
### Make
Gitea uses [Make](https://www.gnu.org/software/make/) to drive builds, linting, and
tests. On Windows it can be installed via [MSYS2](https://www.msys2.org/) or
[Chocolatey](https://chocolatey.org/packages/make).
### Python with uv (optional)
Linting the templates, workflow files, and YAML requires Python tooling that Gitea
runs through [uv](https://docs.astral.sh/uv/). After installing uv, `make` creates
the environment automatically (`uv sync`); you only need this if you run
`make lint-templates`, `make lint-yaml`, or `make lint-actions` locally.
### Git LFS
The integration tests require [Git LFS](https://git-lfs.com/) to be installed.
## Getting the source code
Clone the repository:
```bash
git clone https://github.com/go-gitea/gitea
```
To contribute changes, [fork the repository](https://github.com/go-gitea/gitea) on
GitHub and add your fork as a git remote so you can push branches and open pull
requests. See GitHub's [working with forks](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks)
documentation for the details.
## Installing dependencies
Most build and test targets install the dependencies they need on their own. To
fetch everything up front, run `make deps` (or the per-group `make deps-frontend`,
`make deps-backend`, `make deps-tools`, `make deps-py`).
+100 -9
View File
@@ -1,37 +1,115 @@
# Testing Gitea
# Testing
Gitea has three kinds of automated tests: backend unit tests, integration tests, and end-to-end (e2e) tests. The default database for local test runs is SQLite (pure-Go modernc driver), so no extra services are required to get started.
Gitea has four kinds of automated tests: backend unit tests, integration tests,
end-to-end (e2e) tests, and migration tests. Local runs default to SQLite, so no
extra services are required to get started.
For prerequisites see [setup.md](setup.md); for the build workflow see
[development.md](development.md).
## Unit tests
Unit tests live in `*_test.go` files next to the code they cover and run through `go test`. Set `GITEA_TEST_LOG_SQL=1` to log all SQL statements executed during the tests.
Backend unit tests live in `*_test.go` files next to the code they cover. Set
`GITEA_TEST_LOG_SQL=1` to log all SQL statements executed during the tests.
```bash
make test-backend
```
To run a single test, use `go test` directly or the `#` selector:
To run a single backend test, use `go test` directly or the `#` selector:
```bash
go test -run '^TestName$' ./modulepath/
make test-backend#TestName
```
Frontend unit tests run with:
Frontend unit tests run with [Vitest](https://vitest.dev/):
```bash
make test-frontend
# single file:
pnpm exec vitest <path-filter>
```
## Integration tests
Integration tests exercise Gitea against a real database. They live in `tests/integration/` and require `git lfs` to be installed. With an empty `GITEA_TEST_DATABASE` they default to SQLite:
Integration tests exercise Gitea against a real database. They live in
`tests/integration/` and require [Git LFS](https://git-lfs.com/) to be installed.
The database is selected with `GITEA_TEST_DATABASE`; an empty value defaults to
SQLite, which needs no external service:
```bash
make test-integration
```
Use `GITEA_TEST_DATABASE` to run against MySQL, PostgreSQL, or MSSQL instead. The required connection environment variables and ready-to-use Docker commands for each database are documented in [`tests/integration/README.md`](../tests/integration/README.md), which also explains how to run a single integration test.
Run a single integration test with the `#` selector:
```bash
make test-integration#TestName
```
If you hit errors such as a mismatched database version or SSH push failures, try a
clean rebuild first:
```bash
make clean build
```
### Running against other databases
Set `GITEA_TEST_DATABASE` together with the matching `TEST_*` connection variables.
The commands below start a throwaway database container (press `Ctrl-C` to stop and
remove it) and then run the tests against it.
#### MySQL
```bash
docker run -e "MYSQL_DATABASE=test" -e "MYSQL_ALLOW_EMPTY_PASSWORD=yes" -p 3306:3306 --rm --name mysql mysql:latest
```
```bash
GITEA_TEST_DATABASE=mysql TEST_MYSQL_HOST=localhost:3306 TEST_MYSQL_DBNAME=test TEST_MYSQL_USERNAME=root TEST_MYSQL_PASSWORD='' make test-integration
```
#### PostgreSQL
PostgreSQL tests also use a MinIO container for object storage:
```bash
docker run -e "POSTGRES_DB=test" -e "POSTGRES_USER=postgres" -e "POSTGRES_PASSWORD=postgres" -p 5432:5432 --rm --name pgsql postgres:latest
docker run --rm -p 9000:9000 -e MINIO_ROOT_USER=123456 -e MINIO_ROOT_PASSWORD=12345678 --name minio bitnamilegacy/minio:2023.8.31
```
```bash
GITEA_TEST_DATABASE=pgsql TEST_MINIO_ENDPOINT=localhost:9000 TEST_PGSQL_HOST=localhost:5432 TEST_PGSQL_DBNAME=postgres TEST_PGSQL_USERNAME=postgres TEST_PGSQL_PASSWORD=postgres make test-integration
```
#### MSSQL
```bash
docker run -e "ACCEPT_EULA=Y" -e "MSSQL_PID=Standard" -e "SA_PASSWORD=MwantsaSecurePassword1" -p 1433:1433 --rm --name mssql microsoft/mssql-server-linux:latest
```
```bash
GITEA_TEST_DATABASE=mssql TEST_MSSQL_HOST=localhost:1433 TEST_MSSQL_DBNAME=gitea_test TEST_MSSQL_USERNAME=sa TEST_MSSQL_PASSWORD=MwantsaSecurePassword1 make test-integration
```
### Running the database test workflow with act_runner
The CI database test jobs can be run locally with
[act_runner](https://gitea.com/gitea/act_runner). Running every job is
resource-intensive and not recommended:
```bash
act_runner exec -W ./.github/workflows/pull-db-tests.yml --event=pull_request --default-actions-url="https://github.com" -i catthehacker/ubuntu:runner-latest
```
List the available job names, then run a single one:
```bash
act_runner exec -W ./.github/workflows/pull-db-tests.yml --event=pull_request --default-actions-url="https://github.com" -i catthehacker/ubuntu:runner-latest -l
act_runner exec -W ./.github/workflows/pull-db-tests.yml --event=pull_request --default-actions-url="https://github.com" -i catthehacker/ubuntu:runner-latest -j <job_name>
```
## End-to-end tests
@@ -47,9 +125,18 @@ To run a single e2e test file, pass it via `GITEA_TEST_E2E_FLAGS`:
GITEA_TEST_E2E_FLAGS='<filepath>' make test-e2e
```
Useful environment variables:
| Variable | Description |
| :--- | :--- |
| `GITEA_TEST_E2E_DEBUG` | When set, show the Gitea server output. |
| `GITEA_TEST_E2E_FLAGS` | Additional flags passed to Playwright, e.g. `--ui`. |
| `GITEA_TEST_E2E_TIMEOUT_FACTOR` | Timeout multiplier (default: 4 on CI, 1 locally). |
## Migration tests
If you change a database-persisted struct in `models/` you will usually need a new migration in `models/migrations/`. Run the migration tests with:
If you change a database-persisted struct under `models/` you will usually need a
new migration in `models/migrations/`. Run the migration tests with:
```bash
make test-migration
@@ -57,4 +144,8 @@ make test-migration
## Continuous integration
Our continuous integration runs the unit tests and runs the integration tests against every supported database, and also tests migration from several recent Gitea versions. Please submit your pull request with additional unit and integration tests as appropriate; prefer unit tests when the logic can be tested in isolation, and keep local integration and e2e tests fast (aim for sub-2s).
CI runs the unit tests, runs the integration tests against every supported database,
and tests migration from several recent Gitea versions. Please submit your pull
request with additional unit and integration tests as appropriate. Prefer unit tests
when the logic can be tested in isolation, and keep local integration and e2e tests
fast (aim for sub-2s runtime).
-94
View File
@@ -1,94 +0,0 @@
# Integration tests
Integration tests can be run with command `make test-integration`.
Environment variable `GITEA_TEST_DATABASE` can be used to specify the database type for testing.
If you encounter some errors like mismatched database version, SSH push errors, etc.,
you can try to perform a clean build by: `make clean build`.
## Run sqlite integration tests
Start tests directly (empty `GITEA_TEST_DATABASE` defaults to sqlite):
```
make test-integration
```
## Run MySQL integration tests
Set up a MySQL database inside docker:
```
docker run -e "MYSQL_DATABASE=test" -e "MYSQL_ALLOW_EMPTY_PASSWORD=yes" -p 3306:3306 --rm --name mysql mysql:latest #(just ctrl-c to stop db and clean the container)
docker run -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" --rm --name elasticsearch elasticsearch:7.6.0 #(in a second terminal, just ctrl-c to stop db and clean the container)
```
Start tests based on the database container:
```
GITEA_TEST_DATABASE=mysql TEST_MYSQL_HOST=localhost:3306 TEST_MYSQL_DBNAME=test TEST_MYSQL_USERNAME=root TEST_MYSQL_PASSWORD='' make test-integration
```
## Run pgsql integration tests
Set up a pgsql database inside docker:
```
docker run -e "POSTGRES_DB=test" -e "POSTGRES_USER=postgres" -e "POSTGRES_PASSWORD=postgres" -p 5432:5432 --rm --name pgsql postgres:latest #(just ctrl-c to stop db and clean the container)
```
Set up minio inside docker:
```
docker run --rm -p 9000:9000 -e MINIO_ROOT_USER=123456 -e MINIO_ROOT_PASSWORD=12345678 --name minio bitnamilegacy/minio:2023.8.31
```
Start tests based on the database container:
```
GITEA_TEST_DATABASE=pgsql TEST_MINIO_ENDPOINT=localhost:9000 TEST_PGSQL_HOST=localhost:5432 TEST_PGSQL_DBNAME=postgres TEST_PGSQL_USERNAME=postgres TEST_PGSQL_PASSWORD=postgres make test-integration
```
## Run mssql integration tests
Set up a mssql database inside docker:
```
docker run -e "ACCEPT_EULA=Y" -e "MSSQL_PID=Standard" -e "SA_PASSWORD=MwantsaSecurePassword1" -p 1433:1433 --rm --name mssql microsoft/mssql-server-linux:latest #(just ctrl-c to stop db and clean the container)
```
Start tests based on the database container:
```
GITEA_TEST_DATABASE=mssql TEST_MSSQL_HOST=localhost:1433 TEST_MSSQL_DBNAME=gitea_test TEST_MSSQL_USERNAME=sa TEST_MSSQL_PASSWORD=MwantsaSecurePassword1 make test-integration
```
## Running individual tests
Example command to run GPG test:
```
GITEA_TEST_DATABASE=... make test-integration#GPG
```
## Run Gitea Actions tests via local act_runner
### Run all jobs
```
act_runner exec -W ./.github/workflows/pull-db-tests.yml --event=pull_request --default-actions-url="https://github.com" -i catthehacker/ubuntu:runner-latest
```
Warning: This file defines many jobs, so it will be resource-intensive and therefore not recommended.
### Run single job
```SHELL
act_runner exec -W ./.github/workflows/pull-db-tests.yml --event=pull_request --default-actions-url="https://github.com" -i catthehacker/ubuntu:runner-latest -j <job_name>
```
You can list all job names via:
```SHELL
act_runner exec -W ./.github/workflows/pull-db-tests.yml --event=pull_request --default-actions-url="https://github.com" -i catthehacker/ubuntu:runner-latest -l
```
+2 -2
View File
@@ -50,10 +50,10 @@ func TestAPIUpdateOrgAvatar(t *testing.T) {
MakeRequest(t, req, http.StatusBadRequest)
// Test what happens if you use a file that is not an image
text, err := os.ReadFile(filepath.Join(setting.GetGiteaTestSourceRoot(), "tests/integration/README.md"))
text, err := os.ReadFile(filepath.Join(setting.GetGiteaTestSourceRoot(), "go.mod"))
assert.NoError(t, err)
if err != nil {
assert.FailNow(t, "Unable to open README.md")
assert.FailNow(t, "Unable to open go.mod")
}
opts = api.UpdateUserAvatarOption{
+2 -2
View File
@@ -54,10 +54,10 @@ func TestAPIUpdateRepoAvatar(t *testing.T) {
MakeRequest(t, req, http.StatusBadRequest)
// Test what happens if you use a file that is not an image
text, err := os.ReadFile(filepath.Join(setting.GetGiteaTestSourceRoot(), "tests/integration/README.md"))
text, err := os.ReadFile(filepath.Join(setting.GetGiteaTestSourceRoot(), "go.mod"))
assert.NoError(t, err)
if err != nil {
assert.FailNow(t, "Unable to open README.md")
assert.FailNow(t, "Unable to open go.mod")
}
opts = api.UpdateRepoAvatarOption{
+2 -2
View File
@@ -50,10 +50,10 @@ func TestAPIUpdateUserAvatar(t *testing.T) {
MakeRequest(t, req, http.StatusBadRequest)
// Test what happens if you use a file that is not an image
text, err := os.ReadFile(filepath.Join(setting.GetGiteaTestSourceRoot(), "tests/integration/README.md"))
text, err := os.ReadFile(filepath.Join(setting.GetGiteaTestSourceRoot(), "go.mod"))
assert.NoError(t, err)
if err != nil {
assert.FailNow(t, "Unable to open README.md")
assert.FailNow(t, "Unable to open go.mod")
}
opts = api.UpdateUserAvatarOption{