diff --git a/README.md b/README.md index d49457f..9db16a8 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,25 @@ 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 +go install gitea.alterminal.com/alterminal/teai/cmd/teai@v0.1.0 # 指定版本 +teai version # 驗證:teai version v0.1.0 +``` + +本 module 為公開倉庫,預設 `GOPROXY`/`GOSUMDB` 即可解析(已於乾淨環境驗證)。 +若所在網路環境無法經公用 proxy 抓取,可改設 `GOPRIVATE=gitea.alterminal.com` +(略過 proxy 與 checksum database,直接從 Gitea 抓取)。 + +`teai version` 會顯示建入的 module 版本(tag 安裝為 `v0.1.0`;clone 建置為開發版 `0.1.0-dev`)。 + +### 從原始碼建置(開發用) + +開發、離線或想鎖定特定 commit 時,clone 後自行建置: ```sh git clone https://gitea.alterminal.com/alterminal/teai.git @@ -27,16 +45,12 @@ install -Dm755 teai ~/.local/bin/teai # 或複製到任何 PATH 內目錄 teai version # 驗證:teai version 0.1.0-dev ``` -也可以直接裝進 `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@` 安裝路徑。 - ### 登入設定(首次使用) teai 與 `tea` 共用同一份組態檔;若 `tea whoami` 已可正常輸出,可跳過本節。 diff --git a/internal/cli/cli.go b/internal/cli/cli.go index da2eb54..20c7eb5 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,22 @@ 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);本機 go build 則為 "(devel)" 或空, +// 此時退回開發版本號 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 +452,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..51870c6 --- /dev/null +++ b/internal/cli/version_test.go @@ -0,0 +1,32 @@ +// version_test.go 驗證版本字串解析:go test 環境 Main.Version 為 "(devel)" +// 時應退回開發版本號;-ldflags 覆寫測試 tag 行為則由建置驗證涵蓋。 +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) + } +}