Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 112 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Contributing to Utopia

[中文](CONTRIBUTING.zh-CN.md)

Welcome. This file covers what is specific to this repository; general open-source etiquette is assumed.

## Branches and how changes land

| Branch | What it is |
|---|---|
| `main` | Stable, matches the released version. Only maintainers merge into it, from `dev` |
| `dev` | Integration branch. Every contribution lands here first |

Your path as a contributor:

```bash
git switch dev && git pull
git switch -c fix/some-thing # branch off dev, not main
# make changes, commit with -s (see DCO below)
git push -u origin fix/some-thing
```

Then open a PR with **base `dev`, not `main`**. A maintainer merges once CI and review pass.

Merging `dev → main` is done by maintainers on their own schedule; contributors don't need to think about it.

Both branches are protected: pull request required, CI (`backend` and `web`) must pass, no force pushes, no deletions, and admins are held to the same rules.

## Issue first, or straight to a PR

| Change | What to do |
|---|---|
| Bug fixes, docs, i18n strings, tests | Open a PR directly |
| New features, dependency changes | Open an [issue](https://github.com/deeplethe/utopia/issues) first and describe the use case |
| Data model, ontology contract, public API | Discuss in an issue, then land an [ADR](docs/decisions/) before writing code |

`docs/decisions/` is where this project's reasoning lives. An ADR records **why this and not that**, including the approaches that were tried and failed. For a change of any size, that document outlives the code.

## Local setup

Requires Docker, Rust 1.85+, Node 20+, pnpm.

```bash
docker compose up -d db # Postgres with pgvector
cargo run -p utopia-server # runs migrations, :1516
cd web && pnpm install && pnpm dev # :5173, proxies /api to the backend
```

## Before you push

CI runs exactly this. Green locally means green in CI:

```bash
cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
cd web && pnpm install --frozen-lockfile && pnpm build # build type-checks
```

### Database-backed tests **skip** without the env var

This is the easiest thing to get wrong here. A green `cargo test --workspace` does not mean everything ran. A number of tests begin like this:

```rust
let Ok(url) = std::env::var("UTOPIA_DATABASE_URL") else {
eprintln!("skipping: UTOPIA_DATABASE_URL not set");
return Ok(());
};
```

They guard what the compiler cannot see: table aliases inside SQL strings, how `NULL` behaves in a comparison, rows an `INNER JOIN` silently drops, whether a recursive CTE expands the same ancestor twice under diamond inheritance. `cargo check` and clippy say nothing about any of it.

If you touched SQL under `crates/utopia-store/`, set it and run again:

```bash
export UTOPIA_DATABASE_URL=postgres://utopia:utopia@localhost:5432/utopia
cargo test --workspace
```

## Things review will send back

**Don't collide migration numbers.** `migrations/` rolls forward by number. Check the latest number on `main` before opening a PR — two branches each writing an `0011_` has happened, and after the merge neither one runs.

**UI strings go in i18n.** Add to both `web/src/i18n/en.ts` and `zh.ts`; no hard-coded strings in components.

**Comments explain why.** This repository comments densely and deliberately records the traps it fell into ("the first version used OR, and the Elon Musk article then produced a snapshot every 6KB"). Follow that. A comment restating what the code does will be asked to go.

**Commit messages: one English sentence, stating the motivation.** No long body. Skim `git log` for the register.

## DCO: sign off every commit

We use the [DCO](https://developercertificate.org/), not a CLA. You keep the copyright on your code; you are certifying that you have the right to submit it under Apache-2.0.

Commit with `-s` and git adds the line for you:

```bash
git commit -s -m "Fix the thing"
```

which appends:

```
Signed-off-by: Your Name <your@email>
```

Forgot? `git commit --amend -s` for the last commit, or `git rebase --signoff HEAD~3` for several (adjust the count), then `git push -f`.

Use a real name and a reachable email address.

## License

By contributing you agree that your work is released under [Apache-2.0](LICENSE).
112 changes: 112 additions & 0 deletions CONTRIBUTING.zh-CN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# 参与 Utopia

[English](CONTRIBUTING.md)

欢迎。这份文件只写这个仓库特有的规矩 —— 通用的开源礼仪就不重复了。

## 分支与合并流程

| 分支 | 是什么 |
|---|---|
| `main` | 稳定分支,对应已发布的版本。只由仓库管理者从 `dev` 合入 |
| `dev` | 集成分支,所有贡献先到这里 |

贡献者的路径:

```bash
git switch dev && git pull
git switch -c fix/some-thing # 从 dev 开新分支,不要从 main
# 改代码,提交时带 -s(见下面 DCO)
git push -u origin fix/some-thing
```

然后开 PR,**base 选 `dev`,不是 `main`**。CI 通过、review 通过之后由维护者合并。

`dev → main` 的合并由仓库管理者择期发起,贡献者不需要管。

两个分支都开了保护:必须走 PR,CI(`backend` 与 `web`)必须通过,禁止强推与删除,管理员同样受约束。

## 先开 issue 还是直接提 PR

| 改动 | 怎么做 |
|---|---|
| Bug 修复、文档、i18n 文案、测试 | 直接提 PR |
| 新功能、依赖变更 | 先开 [issue](https://github.com/deeplethe/utopia/issues) 说清场景 |
| 动数据模型、本体契约、公开 API | 先开 issue 讨论,落一篇 [ADR](docs/decisions/) 再动手 |

`docs/decisions/` 是这个项目主要的决策载体。里面记的不是「改了什么」,是**「为什么这样而不是那样」**,以及当时试过、失败了的做法。改动够大时,那篇文档比代码本身更值钱。

## 起本地环境

依赖:Docker、Rust 1.85+、Node 20+、pnpm。

```bash
docker compose up -d db # pgvector 版 Postgres
cargo run -p utopia-server # 自动跑迁移,:1516
cd web && pnpm install && pnpm dev # :5173,/api 代理到后端
```

## 提交前跑什么

CI 就是下面这几条,本地过了 CI 基本不会红:

```bash
cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
cd web && pnpm install --frozen-lockfile && pnpm build # build 含类型检查
```

### 带库的测试没设环境变量会**跳过**,不是失败

这是这个仓库最容易误判的一点。`cargo test --workspace` 全绿不等于全跑了 —— 一批测试开头长这样:

```rust
let Ok(url) = std::env::var("UTOPIA_DATABASE_URL") else {
eprintln!("跳过:未设 UTOPIA_DATABASE_URL");
return Ok(());
};
```

它们守的是**编译器看不见的东西**:SQL 里的表别名、`NULL` 参与比较时的行为、`INNER JOIN` 悄悄滤掉的行、递归 CTE 在菱形继承下会不会把同一个祖先展开两次。`cargo check` 和 clippy 对这些一个字都不说。

碰了 `crates/utopia-store/` 里的 SQL,请把它设上再跑一遍:

```bash
export UTOPIA_DATABASE_URL=postgres://utopia:utopia@localhost:5432/utopia
cargo test --workspace
```

## 几条会被 review 拦下来的

**迁移编号别撞。** `migrations/` 按序号前滚。开 PR 前看一眼 `main` 上最新的号 —— 两个分支各写一个 `0011_` 已经发生过一次,合并之后谁都跑不起来。

**UI 文案进 i18n。** `web/src/i18n/en.ts` 与 `zh.ts` 两边都要加,不要在组件里硬编码字符串。

**代码注释写「为什么」。** 这个仓库的注释密度偏高,而且刻意记录踩过的坑(「第一版写的是『或』,结果 Elon Musk 那篇每 6KB 就取一张」)。跟着这个风格走 —— 复述代码在做什么的注释会被要求删掉。

**提交信息一句英文,说清动机。** 不写长 body。看一眼 `git log` 就知道调子。

## DCO:每个提交要签

我们用 [DCO](https://developercertificate.org/)(开发者原创声明),不用 CLA。你保留自己代码的著作权,只是声明你有权按 Apache-2.0 提交它。

用 `-s` 提交即可,git 会自动加上署名行:

```bash
git commit -s -m "Fix the thing"
```

提交末尾会多出:

```
Signed-off-by: 你的名字 <你的邮箱>
```

忘了签的话,最后一个提交用 `git commit --amend -s`,多个提交用 `git rebase --signoff HEAD~3`(数字换成实际条数),然后 `git push -f`。

署名用的名字和邮箱要是真实可联系的。

## 许可

提交即表示你的贡献按 [Apache-2.0](LICENSE) 发布。
Loading