diff --git a/README.md b/README.md index decd33f..e898189 100644 --- a/README.md +++ b/README.md @@ -17,25 +17,45 @@ teai 是 Gitea 的命令列(CLI)工具,以更完整、更可靠的方式 - **git** - Gitea 帳號的 **API token**(設定階段使用;在 Gitea「設定 → 應用程式」產生) -### 從原始碼建置 +### 以 go install 安裝(建議) + +自 v0.1.0 起 module 已發佈 tag,可直接以版本安裝(二元檔裝進 `GOBIN`,預設 `~/go/bin`): + +```sh +go install gitea.alterminal.com/alterminal/teai/cmd/teai@latest # 最新 tag(亦可 @v<版本> 指定) +teai version # 驗證:顯示安裝的 tag 版本(見下方說明) +``` + +本 module 為公開倉庫,預設 `GOPROXY`/`GOSUMDB` 即可解析(已於乾淨環境驗證)。 +若所在網路環境無法經公用 proxy 抓取,可改設 `GOPRIVATE=gitea.alterminal.com` +(略過 proxy 與 checksum database,直接從 Gitea 抓取)。 + +`teai version` 顯示建入的 module 版本,即安裝指定的 tag(如 `v0.1.1`)。 +注意:讀 build info 顯示安裝版本的支援,自包含該變更的 tag 起(v0.1.1)才生效—— +v0.1.0 早於此變更,以 `@v0.1.0` 安裝(或此變更前的 `@latest`)仍顯示舊行為 `0.1.0-dev`。 + +### 從原始碼建置(開發用) + +開發、離線或想鎖定特定 commit 時,clone 後自行建置: ```sh git clone https://gitea.alterminal.com/alterminal/teai.git cd teai go build -o teai ./cmd/teai install -Dm755 teai ~/.local/bin/teai # 或複製到任何 PATH 內目錄 -teai version # 驗證:teai version 0.1.0-dev +teai version # 驗證:teai version v0.1.1-0.<時間戳>-(見下方說明) ``` -也可以直接裝進 `GOBIN`(預設 `~/go/bin`;該目錄已在 PATH 時最省事): +也可以在 clone 目錄內直接裝進 `GOBIN`: ```sh go install ./cmd/teai ``` -> **注意:** `go install gitea.alterminal.com/alterminal/teai/cmd/teai@latest` 目前**不可用**—— -> module 尚未發佈任何 tag,`@latest` 會解析到任意中繼 commit(且 #21 修復前 main 建置失敗)。 -> 請在 clone 目錄內以版本控制的方式建置;發佈 tag 後再提供 `teai@` 安裝路徑。 +clone 建置時 Go 會把 VCS 狀態寫進 build info:位於 tag 上顯示該 tag、 +其後的 commit 顯示 pseudo-version(如 `v0.1.1-0.20260912160956-5a48fdd590b2`)、 +工作樹有修改再附加 `+dirty`;無 VCS 資訊(如從 tarball 解壓建置)時 +`Main.Version` 為 `(devel)`,此時退回開發版本號 `0.1.0-dev`。 ### 登入設定(首次使用) diff --git a/internal/cli/cli.go b/internal/cli/cli.go index da2eb54..aa22c83 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -15,6 +15,7 @@ import ( "flag" "fmt" "io" + "runtime/debug" "sort" "strings" "time" @@ -23,8 +24,24 @@ import ( ) // Version 是目前開發中的版本號。採用語意化版本;正式發佈前以 0 開頭。 +// 僅作為 fallback:以 `go install module@version` 或納入其他 module 建置時, +// buildVersion 會改用 build info 內的 module 版本(見 runVersion)。 var Version = "0.1.0-dev" +// buildVersion 回傳應顯示的版本字串。go install pkg@tag 建置的二元檔 +// 會在 Main.Version 帶入 tag(如 v0.1.0);clone 目錄內本機建置則帶 +// pseudo-version(如 v0.1.1-0.<時間戳>-,工作樹有修改時再附加 +// "+dirty"),同樣直接顯示。Main.Version 為 "(devel)" 或空(go test 環境、 +// 無 VCS 資訊的 tarball 建置)時,才退回開發版本號 Version。 +func buildVersion() string { + if info, ok := debug.ReadBuildInfo(); ok { + if v := info.Main.Version; v != "" && v != "(devel)" { + return v + } + } + return Version +} + // ExitCode 是 Run 回傳的行程結束碼。 type ExitCode int @@ -437,7 +454,7 @@ func runVersion(env *Env, args []string) error { if len(args) > 0 { return &ErrUsage{Msg: "version 不接受參數"} } - fmt.Fprintf(env.Out, "teai version %s\n", Version) + fmt.Fprintf(env.Out, "teai version %s\n", buildVersion()) return nil } diff --git a/internal/cli/version_test.go b/internal/cli/version_test.go new file mode 100644 index 0000000..f1b988b --- /dev/null +++ b/internal/cli/version_test.go @@ -0,0 +1,33 @@ +// version_test.go 驗證版本字串解析:go test 環境 Main.Version 為 "(devel)" +// 時應退回開發版本號;tag 與 pseudo-version 行為由建置驗證涵蓋 +// (go install pkg@tag 顯示 tag;clone 建置顯示 pseudo-version)。 +package cli + +import ( + "strings" + "testing" +) + +// TestBuildVersionFallsBackToDev 確認本地測試環境(Main.Version == "(devel)") +// 退回 Version;同時確保輸出是可讀版本字串(非空、無括號)。 +func TestBuildVersionFallsBackToDev(t *testing.T) { + v := buildVersion() + if v == "" { + t.Fatalf("buildVersion 不應為空") + } + if strings.ContainsAny(v, "()") { + t.Errorf("buildVersion 不應含內部佔位(括號),得到:%q", v) + } +} + +// TestRunVersionUsesBuildVersion 確認 version 命令輸出 buildVersion 的結果。 +func TestRunVersionUsesBuildVersion(t *testing.T) { + stdout, _, code := run("version") + if code != 0 { + t.Fatalf("version 應回 0,得到 %d", code) + } + want := "teai version " + buildVersion() + if !strings.Contains(stdout, want) { + t.Errorf("version 輸出應含 %q,得到:%q", want, stdout) + } +}