From bc31d9cc8f93a5efef958872f48f3f4370ed5e29 Mon Sep 17 00:00:00 2001 From: s Date: Wed, 19 Nov 2025 23:59:59 -0500 Subject: feat: add changelog display and version comparison to update command --- cmd/update.go | 200 +++++++++++++++++++++++++++++++++++++++++++++- internal/utils/version.go | 2 +- 2 files changed, 198 insertions(+), 4 deletions(-) diff --git a/cmd/update.go b/cmd/update.go index d664bf0..f7956ea 100644 --- a/cmd/update.go +++ b/cmd/update.go @@ -4,13 +4,17 @@ import ( "fmt" "os" "os/exec" + "regexp" + "runtime/debug" + "sort" "strings" + "git.db.org.ai/dborg/internal/utils" "github.com/spf13/cobra" ) func getLatestVersion() (string, error) { - cmd := exec.Command("git", "ls-remote", "--tags", "--refs", "--sort=-v:refname", "git@45.38.20.139:repos/dborg.git") + cmd := exec.Command("git", "ls-remote", "--tags", "--refs", "--sort=-v:refname", utils.RepositoryURL) output, err := cmd.Output() if err != nil { return "", err @@ -29,12 +33,179 @@ func getLatestVersion() (string, error) { return strings.TrimSpace(parts[1]), nil } +func getAllTags() ([]string, error) { + cmd := exec.Command("git", "ls-remote", "--tags", "--refs", utils.RepositoryURL) + output, err := cmd.Output() + if err != nil { + return nil, err + } + + var tags []string + lines := strings.Split(strings.TrimSpace(string(output)), "\n") + for _, line := range lines { + if line == "" { + continue + } + + parts := strings.Split(line, "refs/tags/") + if len(parts) < 2 { + continue + } + + tag := strings.TrimSpace(parts[1]) + tags = append(tags, tag) + } + + sort.Slice(tags, func(i, j int) bool { + return tags[i] > tags[j] + }) + + return tags, nil +} + +type Commit struct { + Type string + Scope string + Description string + Hash string +} + +func getCommitsBetweenVersions(fromVersion, toVersion string) ([]Commit, error) { + var commits []Commit + + fromTag := "" + if fromVersion != "" { + fromTag = fmt.Sprintf("v%s", strings.TrimPrefix(fromVersion, "v")) + } + toTag := fmt.Sprintf("v%s", strings.TrimPrefix(toVersion, "v")) + + var rangeSpec string + if fromTag == "" { + rangeSpec = toTag + } else { + rangeSpec = fmt.Sprintf("%s..%s", fromTag, toTag) + } + + cmd := exec.Command("git", "log", "--oneline", "--no-merges", rangeSpec, "--", utils.RepositoryURL) + output, err := cmd.Output() + if err != nil { + return nil, fmt.Errorf("failed to fetch commits: %w", err) + } + + lines := strings.Split(strings.TrimSpace(string(output)), "\n") + for _, line := range lines { + if line == "" { + continue + } + + parts := strings.SplitN(line, " ", 2) + if len(parts) < 2 { + continue + } + + hash := parts[0] + message := parts[1] + + commit := parseCommitMessage(hash, message) + commits = append(commits, commit) + } + + return commits, nil +} + +func parseCommitMessage(hash, message string) Commit { + re := regexp.MustCompile(`^(\w+)(?:\(([^)]+)\))?:\s*(.+)$`) + matches := re.FindStringSubmatch(message) + + if len(matches) == 4 { + return Commit{ + Type: matches[1], + Scope: matches[2], + Description: matches[3], + Hash: hash, + } + } + + return Commit{ + Type: "chore", + Description: message, + Hash: hash, + } +} + +func displayCommits(commits []Commit) { + if len(commits) == 0 { + fmt.Println("No changes found.") + return + } + + categories := make(map[string][]Commit) + for _, commit := range commits { + categories[commit.Type] = append(categories[commit.Type], commit) + } + + typeOrder := []string{"feat", "fix", "perf", "refactor", "docs", "style", "test", "chore", "build", "ci"} + + fmt.Println("\nšŸ“‹ What's new:") + fmt.Println(strings.Repeat("═", 50)) + + for _, commitType := range typeOrder { + if commits, exists := categories[commitType]; exists { + displayCategory(commitType, commits) + delete(categories, commitType) + } + } + + for commitType, commits := range categories { + displayCategory(commitType, commits) + } + + fmt.Println(strings.Repeat("═", 50)) +} + +func displayCategory(commitType string, commits []Commit) { + var icon string + switch commitType { + case "feat": + icon = "✨" + case "fix": + icon = "šŸ›" + case "perf": + icon = "⚔" + case "refactor": + icon = "ā™»ļø" + case "docs": + icon = "šŸ“" + case "style": + icon = "šŸ’„" + case "test": + icon = "āœ…" + case "chore": + icon = "šŸ”§" + case "build": + icon = "šŸ“¦" + case "ci": + icon = "šŸ¤–" + default: + icon = "šŸ“Œ" + } + + fmt.Printf("\n%s %s\n", icon, strings.ToUpper(commitType)) + for _, commit := range commits { + if commit.Scope != "" { + fmt.Printf(" • %s (%s): %s\n", commit.Description, commit.Scope, commit.Hash[:7]) + } else { + fmt.Printf(" • %s (%s)\n", commit.Description, commit.Hash[:7]) + } + } +} + var updateCmd = &cobra.Command{ Use: "update", Short: "Update dborg to the latest version", Long: `Update dborg by running go install git.db.org.ai/dborg@`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println("Updating dborg...") + fmt.Println("Checking for updates...") latestVersion, err := getLatestVersion() if err != nil { @@ -42,6 +213,29 @@ var updateCmd = &cobra.Command{ os.Exit(1) } + currentVersion := "dev" + if info, ok := debug.ReadBuildInfo(); ok { + if info.Main.Version != "" && info.Main.Version != "(devel)" { + currentVersion = info.Main.Version + } + } + + if currentVersion != "dev" && currentVersion == latestVersion { + fmt.Printf("You're already on the latest version: %s\n", latestVersion) + return + } + + fmt.Printf("Updating from %s to %s...\n", currentVersion, latestVersion) + + commits, err := getCommitsBetweenVersions(currentVersion, latestVersion) + if err != nil { + fmt.Fprintf(os.Stderr, "Warning: Could not fetch commit changes: %v\n", err) + } else { + displayCommits(commits) + } + + fmt.Printf("\nšŸš€ Installing dborg %s...\n", latestVersion) + installTarget := fmt.Sprintf("git.db.org.ai/dborg@%s", latestVersion) installCmd := exec.Command("go", "install", installTarget) installCmd.Stdout = os.Stdout @@ -52,7 +246,7 @@ var updateCmd = &cobra.Command{ os.Exit(1) } - fmt.Printf("dborg updated successfully to %s!\n", latestVersion) + fmt.Printf("\nāœ… dborg updated successfully to %s!\n", latestVersion) }, } diff --git a/internal/utils/version.go b/internal/utils/version.go index 847aeb6..b6ae282 100644 --- a/internal/utils/version.go +++ b/internal/utils/version.go @@ -13,7 +13,7 @@ import ( var ( Version = "dev" - RepositoryURL = "git@45.38.20.139:repos/dborg.git" + RepositoryURL = "https://git.db.org.ai/dborg.git" ) func init() { -- cgit v1.2.3