golang根据语义化版本规则比较Go模块版本变更类型插件库modversemver的使用

Golang根据语义化版本规则比较Go模块版本变更类型插件库modver/mver的使用

Modver是一个帮助你在Go模块中遵循语义化版本规则的工具。它可以读取和比较同一模块的两个不同版本,并报告变更类型(主版本号、次版本号或补丁版本号)。

安装和使用

命令行界面

安装modver命令:

go install github.com/bobg/modver/v2/cmd/modver@latest

使用示例(假设当前目录是Git仓库根目录):

$ modver -git .git HEAD~1 HEAD

其中:

  • -git .git指定Git仓库路径(也可以是URL)
  • HEAD~1HEAD指定要比较的两个Git修订版本(可以是标签或提交哈希)

GitHub Action

.github/workflows目录下创建Yaml文件,内容如下:

name: Tests

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Set up Go
        uses: actions/setup-go@v4
        with:
          go-version: 1.19

      - name: Modver
        if: ${{ github.event_name == 'pull_request' }}
        uses: bobg/modver@v2.5.0
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          pull_request_url: https://github.com/${{ github.repository }}/pull/${{ github.event.number }}

注意:

  • fetch-depth: 0确保克隆完整历史记录
  • main改为你的默认分支名
  • 若非GitHub.com,需修改pull_request_url中的主机名

Go库

添加到项目中:

go get github.com/bobg/modver/v2@latest

使用示例代码:

package main

import (
	"fmt"
	"github.com/bobg/modver/v2"
)

func main() {
	// 比较两个目录中的模块版本
	result, err := modver.CompareDirs("/path/to/old", "/path/to/new")
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		return
	}
	
	// 输出变更类型
	switch result {
	case modver.Major:
		fmt.Println("需要主版本号变更")
	case modver.Minor:
		fmt.Println("需要次版本号变更")
	case modver.Patch:
		fmt.Println("需要补丁版本号变更")
	case modver.None:
		fmt.Println("无需版本变更")
	}
}

语义化版本规则

  • 主版本号变更:公共API的不兼容变更(如类型删除/重命名、函数参数/返回值变更)
  • 次版本号变更:公共API的新增功能(如新入口点、现有结构的新字段)
  • 补丁版本变更:其他不影响API的变更

Modver返回的是最小所需的变更类型。实际可能需要更大的变更,但可以保证:

  • 返回Major时,次版本变更不够
  • 返回Minor时,补丁版本变更不够

完整示例Demo

package main

import (
	"fmt"
	"github.com/bobg/modver/v2"
	"os"
)

func main() {
	if len(os.Args) != 3 {
		fmt.Println("Usage: go run main.go <old-dir> <new-dir>")
		os.Exit(1)
	}

	oldDir := os.Args[1]
	newDir := os.Args[2]

	// 比较两个目录中的模块版本
	result, err := modver.CompareDirs(oldDir, newDir)
	if err != nil {
		fmt.Printf("比较失败: %v\n", err)
		os.Exit(1)
	}

	// 输出结果
	fmt.Printf("比较 %s 和 %s 的结果:\n", oldDir, newDir)
	switch result {
	case modver.Major:
		fmt.Println("变更类型: MAJOR (主版本号变更)")
	case modver.Minor:
		fmt.Println("变更类型: MINOR (次版本号变更)")
	case modver.Patch:
		fmt.Println("变更类型: PATCH (补丁版本变更)")
	case modver.None:
		fmt.Println("变更类型: NONE (无需版本变更)")
	default:
		fmt.Println("未知变更类型")
	}
}

使用方式:

go run main.go /path/to/v1.0.0 /path/to/v1.1.0

更多关于golang根据语义化版本规则比较Go模块版本变更类型插件库modversemver的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang根据语义化版本规则比较Go模块版本变更类型插件库modversemver的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用modversemver比较Go模块版本变更类型

modversemver是一个用于分析Go模块版本变更类型的库,它基于语义化版本(SemVer)规则来判断版本变更属于哪种类型(主版本、次版本或修订版本)。

安装

go get github.com/icholy/modversemver

基本用法

比较两个版本

package main

import (
	"fmt"
	"github.com/icholy/modversemver"
)

func main() {
	// 比较两个版本
	change, err := modversemver.Compare("v1.2.3", "v1.2.4")
	if err != nil {
		panic(err)
	}
	
	fmt.Printf("Change type: %s\n", change.Type) // "patch"
	fmt.Printf("Is breaking: %v\n", change.Breaking) // false
}

版本变更类型

modversemver会返回以下变更类型:

  1. major - 主版本变更 (v1.0.0 → v2.0.0)
  2. minor - 次版本变更 (v1.0.0 → v1.1.0)
  3. patch - 修订版本变更 (v1.0.0 → v1.0.1)

高级用法

检查是否包含破坏性变更

func isBreakingChange(oldVer, newVer string) bool {
	change, err := modversemver.Compare(oldVer, newVer)
	if err != nil {
		return false
	}
	return change.Breaking
}

func main() {
	fmt.Println(isBreakingChange("v1.2.3", "v2.0.0")) // true
	fmt.Println(isBreakingChange("v1.2.3", "v1.3.0")) // false
}

分析模块版本历史

func analyzeModuleHistory(versions []string) {
	if len(versions) < 2 {
		return
	}
	
	for i := 1; i < len(versions); i++ {
		change, err := modversemver.Compare(versions[i-1], versions[i])
		if err != nil {
			fmt.Printf("Error comparing %s → %s: %v\n", versions[i-1], versions[i], err)
			continue
		}
		fmt.Printf("%s → %s: %s change (breaking: %v)\n", 
			versions[i-1], versions[i], change.Type, change.Breaking)
	}
}

func main() {
	versions := []string{"v1.0.0", "v1.0.1", "v1.1.0", "v2.0.0"}
	analyzeModuleHistory(versions)
}

处理Go模块的特殊情况

Go模块在主版本变更时会在模块路径中包含版本号(如/v2),modversemver也能正确处理这种情况:

func main() {
	// 处理带版本号的模块路径
	change, err := modversemver.Compare(
		"github.com/user/module/v1.2.3",
		"github.com/user/module/v2.0.0")
	if err != nil {
		panic(err)
	}
	fmt.Println(change.Type) // "major"
}

错误处理

modversemver会返回以下可能的错误:

  • 版本格式无效
  • 版本号缺失
  • 比较的版本不属于同一模块
func safeCompare(v1, v2 string) (modversemver.Change, error) {
	change, err := modversemver.Compare(v1, v2)
	if err != nil {
		switch err {
		case modversemver.ErrInvalidVersion:
			fmt.Println("Invalid version format")
		case modversemver.ErrMissingVersion:
			fmt.Println("Missing version number")
		case modversemver.ErrDifferentModules:
			fmt.Println("Comparing versions from different modules")
		default:
			fmt.Println("Unknown error:", err)
		}
		return modversemver.Change{}, err
	}
	return change, nil
}

modversemver是一个轻量级但功能强大的工具,特别适合在CI/CD流程中自动检查版本变更是否符合语义化版本规范,或在发布工具中自动确定下一个版本号。

回到顶部