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
61 changes: 61 additions & 0 deletions RELEASING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Releasing(照 Parity 的形狀)

## 流程

1. 更新 `CHANGELOG.md`:新增版本段落。**Release notes 直接取自這一節**,
所以這裡寫得夠不夠好,就等於 GitHub Releases 頁上的品質。
2. 推 tag:

```bash
git tag v1.2.0
git push origin v1.2.0
```

3. `.github/workflows/release.yml` 接手:從 tag 導出版本 → restore → build → test →
`dotnet pack` → 以 **NuGet Trusted Publishing**(OIDC,無長期 API key)發佈
`Cornhsu.Labeling` 與 `Cornhsu.Labeling.EntityFrameworkCore` → **自動建 GitHub Release**

> 版號**只從 tag 來**。csproj 裡沒有寫死的 `<Version>`,不需要(也不該)事先改任何檔案的版號。

## 版本規則

自 1.0.0 起 API 穩定:

- **major**:公開 API 的破壞性變更、或抬高相依樓地板(見下)
- **minor**:新增 API、或對外可見文字的改變(例外訊息、analyzer 診斷 —— 有人在斷言這些)
- **patch**:修正,對外行為不變

## 抬高相依樓地板 = major

README 承諾「支援 EF Core 8+,消費端用 9/10 會自動 unify」。把
`src/Cornhsu.Labeling.EntityFrameworkCore` 的 `Microsoft.EntityFrameworkCore.Relational`
往上抬,會讓還在 EF 8 的使用者直接裝不起來 —— 那是破壞性變更。

同理,`Cornhsu.Labeling.Analyzers` 的 `Microsoft.CodeAnalysis.CSharp` 版本
決定了消費端需要的最低 VS/SDK 世代(目前 4.8 = VS2022 17.8 / SDK 8,相容範圍最大)。

⚠ 真的要抬樓地板時,記得 `tests/Cornhsu.Labeling.Tests.csproj` 的 `CornhsuEfVersion`
預設值必須跟著改成同一個版本 —— 它的意義就是「測我們對外承諾的最低版本」。
但那個值目前**卡在 8.0.11**:它同時餵三個 provider,而 Npgsql 的 EF 8 線只到 8.0.11
(Microsoft 走到 8.0.29)。詳見該 csproj 的註解。

dependabot 已對這幾項設 `ignore`,不會自動提出 —— 抬樓地板要有意識地改 csproj +
README + CHANGELOG,不是按 merge。

## CI 矩陣

每次 push 都跑:三資料庫(SQLite / SQL Server / PostgreSQL)× EF Core 8 / 9 / 10。
EF 9/10 是**真的引用新版 EF 跑同一套測試**,不是只換 SDK:

```bash
dotnet test tests/Cornhsu.Labeling.Tests -p:CornhsuTestTfm=net10.0 -p:CornhsuEfVersion=10.0.*
```

`samples/MinimalConsole` 也在 CI 跑 —— 它是「抽象是否成立」的哨兵,不只是示範。

## 首次發佈前的一次性設定(已完成)

- NuGet.org:兩個套件都設定 Trusted Publishing
(repo `HSU-YU-MING/cornhsu-labeling`、workflow `release.yml`)
- `Cornhsu.*` 前綴已獲 NuGet 官方保留
- workflow 已宣告 `id-token: write`(OIDC)與 `contents: write`(建 Release)
44 changes: 44 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Roadmap

「已完成」看 [README](README.md) 與 [CHANGELOG](CHANGELOG.md)。這裡只記**還沒做的**。

這份文件存在的理由:README 的 Limitations 混了兩種東西 —— 「這是泛型主鍵的必然代價,
你得認了」和「這個以後會有」。讀者分不出來。前者留在 README,後者收在這裡。

## 明文不做(不是遺漏)

- **`LabelHit.EntityId` 改成強型別**。跨型別查詢的命中本來就可能來自不同主鍵型別
(`Note` 是 Guid、`TodoItem` 是 int),`object` 是泛型主鍵的必然代價,
不是偷懶。要強型別用 `EntityIdAs<TKey>()`。
- **`Label` 加業務欄位**(標籤型別、模組/租戶隔離、權限…)。套件無法理解、
也無法替你把關這些概念,加了只是假裝支援。用 1:1 伴生表,見 README「擴充 Label」。

## 有觸發條件才做

- **跨型別查詢合併成 `UNION ALL`**。現在是「每個註冊型別一次查詢」的樸素策略。
benchmark 顯示 5 型別 × 10,000 筆、12 萬連結時仍在 ~18 ms —— 這個規模下不值得
換複雜度。**觸發條件**:有人回報實測瓶頸,或註冊型別數成長到兩位數。
- **多租戶:各租戶不同的可標記型別**。EF Core 的 model cache 以 DbContext 型別為 key,
要支援得自訂 `IModelCacheKeyFactory`。**觸發條件**:出現真實需求 ——
這會把 registry 從「全 App 單例」變成「每租戶一份」,是核心假設的改動,不能為想像中的
使用者先做。
- **Analyzer 的 code fix**。`CHSU001` 現在只警告不修。技術上卡在兩點:它是
`CompilationEnd` 診斷(要完整建置才出現,IDE 的即時分析不產生,燈泡幾乎不會亮),
而且修法要動到「另一個檔案的 `AddLabeling` lambda」,跨檔案的 code fix 既脆弱又難預測。
`CHSU002` 倒是可以做(純本地改寫:讀 `Id` 型別、把 `ILabelable` 改成 `ILabelable<TKey>`),
但它只會在每個型別上發生一次,而診斷訊息已經明說該怎麼改。
**觸發條件**:有人回報訊息不夠清楚。目前的解法是
[docs/analyzer-rules.md](docs/analyzer-rules.md) 加上 `helpLinkUri`。

## v2 範疇(會破壞 API)

- **標籤名稱改為「每父層唯一」**。現在是全域唯一,含跨階層 ——「工作/雜項」和
「生活/雜項」不能各有一個「雜項」。這是刻意取捨:整個 API 以名稱定址
(`AttachAsync`、`FindByLabelAsync` 都吃名稱字串),允許同名會讓所有名稱定址的呼叫變歧義。
真要支援,勢必伴隨路徑定址(`"生活/雜項"`)的 API 改版 —— 那是 major。
在那之前,把限定詞放進名稱本身(如「生活·雜項」)。

## 1.0 之後的維護原則

API 已凍結。相依樓地板(EF Core 8、Roslyn 4.8)也是對外承諾的一部分,
抬高它等同破壞性變更 —— 見 [RELEASING.md](RELEASING.md)。
16 changes: 11 additions & 5 deletions tests/Cornhsu.Labeling.Tests/Cornhsu.Labeling.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@
<!-- EF 版本矩陣(CI 用):-p:CornhsuTestTfm=net10.0 -p:CornhsuEfVersion=10.0.*
真的引用 EF 9/10 跑同一套測試,不是只換 SDK -->
<CornhsuTestTfm Condition="'$(CornhsuTestTfm)' == ''">net8.0</CornhsuTestTfm>
<!-- ⚠ 8.0.11 是天花板,不要往上調。這個變數同時餵三個 provider,而兩家的 patch
節奏不同:Microsoft 的 EF 8 線走到 8.0.29,Npgsql 只到 8.0.11。推過 8.0.11,
Npgsql 解析不到對應版本 → NuGet 浮動到 9.0.0 → 把 EF Relational 9 拖進相依圖
→ 撞上釘住的 8.x,NU1603 + NU1605 全紅(dependabot #10 實測)。
想解開就要把 Npgsql 拆成獨立變數 —— 那是有意識的改動,不是順手升版。 -->
<!-- ⚠ 這個值必須等於 src 的相依樓地板(EntityFrameworkCore.Relational 8.0.11)。
它的意義是「測我們對外承諾的最低版本」—— CI 矩陣另外用 9.0.* / 10.0.* 測更新的線。
讓它浮動到 8.0.29 會變成「承諾支援 8.0.11,卻從來沒測過 8.0.11」,是退步。

另外剛好有一道天花板重合在同一個數字上:這個變數同時餵三個 provider,而
Microsoft 的 EF 8 線走到 8.0.29、Npgsql 只到 8.0.11。推過 8.0.11 的話 Npgsql
解析不到對應版本 → NuGet 浮動到 9.0.0 → 把 EF Relational 9 拖進相依圖 →
撞上釘住的 8.x,NU1603 + NU1605 全紅(dependabot #10 實測)。

所以真正會咬人的時機是「哪天要抬高 src 樓地板」—— 那時要嘛 Npgsql 已有對應版本,
要嘛得把它拆成獨立變數。見 RELEASING.md。 -->
<CornhsuEfVersion Condition="'$(CornhsuEfVersion)' == ''">8.0.11</CornhsuEfVersion>
<CornhsuDiVersion Condition="'$(CornhsuDiVersion)' == ''">8.0.1</CornhsuDiVersion>

Expand Down