0
0
mirror of https://gitea.com/gitea/docs.git synced 2025-05-04 15:51:33 +00:00
Files
appleboy dbfa0ba454 docs: add zh-tw folder (#195)
Signed-off-by: appleboy <appleboy.tw@gmail.com>
Reviewed-on: https://gitea.com/gitea/docs/pulls/195
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: appleboy <appleboy.tw@gmail.com>
Co-committed-by: appleboy <appleboy.tw@gmail.com>
2025-04-04 23:28:16 +00:00

113 lines
6.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
date: "2023-05-25T23:41:00+08:00"
slug: "guidelines-backend"
sidebar_position: 20
aliases:
- /zh-tw/guidelines-backend
---
# 后端开发指南
## 背景
Gitea 使用 Golang 作为后端编程语言。它使用了许多第三方包,并且自己也编写了一些包。
例如Gitea 使用[Chi](https://github.com/go-chi/chi)作为基本的 Web 框架。[Xorm](https://xorm.io)是一个用于与数据库交互的 ORM 框架。
因此,管理这些包非常重要。在开始编写后端代码之前,请参考以下准则。
## 包设计准则
### 包列表
为了保持易于理解的代码并避免循环依赖拥有良好的代码结构是很重要的。Gitea 后端分为以下几个部分:
- `build`:帮助构建 Gitea 的脚本。
- `cmd`:包含所有 Gitea 的实际子命令,包括 web、doctor、serv、hooks、admin 等。`web`将启动 Web 服务。`serv``hooks`将被 Git 或 OpenSSH 调用。其他子命令可以帮助维护 Gitea。
- `tests`:常用的测试函数
- `tests/integration`:集成测试,用于测试后端回归。
- `tests/e2e`:端到端测试,用于测试前端和后端的兼容性和视觉回归。
- `models`:包含由 xorm 用于构建数据库表的数据结构。它还包含查询和更新数据库的函数。应避免与其他 Gitea 代码的依赖关系。在某些情况下,比如日志记录时可以例外。
- `models/db`:基本的数据库操作。所有其他`models/xxx`包都应依赖于此包。`GetEngine`函数只能从 models/中调用。
- `models/fixtures`:单元测试和集成测试中使用的示例数据。一个`yml`文件表示一个将在测试开始时加载到数据库中的表。
- `models/migrations`:存储不同版本之间的数据库迁移。修改数据库结构的 PR**必须**包含一个迁移步骤。
- `modules`:在 Gitea 中处理特定功能的不同模块。工作正在进行中:其中一些模块应该移到`services`中,特别是那些依赖于 models 的模块,因为它们依赖于数据库。
- `modules/setting`:存储从 ini 文件中读取的所有系统配置,并在各处引用。但是在可能的情况下,应将其作为函数参数使用。
- `modules/git`:用于与`Git`命令行或 Gogit 包交互的包。
- `public`编译后的前端文件JavaScript、图像、CSS 等)
- `routers`:处理服务器请求。由于它使用其他 Gitea 包来处理请求因此其他包models、modules 或 services不能依赖于 routers。
- `routers/api`:包含`/api/v1`相关路由,用于处理 RESTful API 请求。
- `routers/install`只能在系统处于安装模式INSTALL_LOCK=false时响应。
- `routers/private`:仅由内部子命令调用,特别是`serv``hooks`
- `routers/web`:处理来自 Web 浏览器或 Git SMART HTTP 协议的 HTTP 请求。
- `services`:用于常见路由操作或命令执行的支持函数。使用`models``modules`来处理请求。
- `templates`:用于生成 HTML 输出的 Golang 模板。
### 包依赖关系
由于 Golang 不支持导入循环,我们必须仔细决定包之间的依赖关系。这些包之间有一些级别。以下是理想的包依赖关系方向。
`cmd` -> `routers` -> `services` -> `models` -> `modules`
从左到右,左侧的包可以依赖于右侧的包,但右侧的包不能依赖于左侧的包。在同一级别的子包中,可以根据该级别的规则进行依赖。
**注意事项**
为什么我们需要在`models`之外使用数据库事务?以及如何使用?
某些操作在数据库记录插入/更新/删除失败时应该允许回滚。
因此,服务必须能够创建数据库事务。以下是一些示例:
```go
// services/repository/repository.go
func CreateXXXX() error {
return db.WithTx(func(ctx context.Context) error {
// do something, if err is returned, it will rollback automatically
if err := issues.UpdateIssue(ctx, repoID); err != nil {
// ...
return err
}
// ...
return nil
})
}
```
`services`中**不应该**直接使用`db.GetEngine(ctx)`,而是应该在`models/`下编写一个函数。
如果该函数将在事务中使用,请将`context.Context`作为函数的第一个参数。
```go
// models/issues/issue.go
func UpdateIssue(ctx context.Context, repoID int64) error {
e := db.GetEngine(ctx)
// ...
}
```
### 包名称
对于顶层包,请使用复数作为包名,例如`services``models`,对于子包,请使用单数,例如`services/user``models/repository`
### 导入别名
由于有一些使用相同包名的包,例如`modules/user``models/user``services/user`,当这些包在一个 Go 文件中被导入时,很难知道我们使用的是哪个包以及它是变量名还是导入名。因此,我们始终建议使用导入别名。为了与常见的驼峰命名法的包变量区分开,建议使用**snake_case**作为导入别名的命名规则。
例如:`import user_service "code.gitea.io/gitea/services/user"`
### 重要注意事项
- 永远不要写成`x.Update(exemplar)`,而没有明确的`WHERE`子句:
- 这将导致表中的所有行都被使用 exemplar 的非零值进行更新,包括 ID。
- 通常应该写成`x.ID(id).Update(exemplar)`
- 如果在迁移过程中使用`x.Insert(exemplar)`向表中插入记录,而 ID 是预设的:
- 对于 MSSQL 变体,你将需要执行`` SET IDENTITY_INSERT `table` ON ``(否则迁移将失败)
- 对于 PostgreSQL你还需要更新 ID 序列,否则迁移将悄无声息地通过,但后续的插入将失败:
`` SELECT setval('table_name_id_seq', COALESCE((SELECT MAX(id)+1 FROM `table_name`), 1), false) ``
### 未来的任务
目前,我们正在进行一些重构,以完成以下任务:
- 纠正不符合规则的代码。
- `models`中的文件太多了,所以我们正在将其中的一些移动到子包`models/xxx`中。
- 由于它们依赖于`models`,因此应将某些`modules`子包移动到`services`中。