commit 741a08e98d89c720a08aa837b59313b9cb342f64 Author: William Dillon Date: Sun May 18 18:08:01 2025 -0400 first commit diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..33fbb43 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module code.wmdillon.com/GoApi/increment_version + +go 1.24.3 diff --git a/main.go b/main.go new file mode 100644 index 0000000..03c2393 --- /dev/null +++ b/main.go @@ -0,0 +1,143 @@ +package main + +import ( + "flag" + "fmt" + "os" + "strconv" + "strings" +) + +type VERSION struct { + Filename string + Major, Minor, Patch, Revision uint64 + HasMajor, HasMinor, HasPatch, HasRevision bool +} + +func (v *VERSION) Flush() error { + return os.WriteFile(v.Filename, []byte(v.String()), 0664) +} + +func (v VERSION) String() string { + var buffer strings.Builder + if v.HasMajor || v.HasMinor || v.HasPatch || v.HasRevision { + buffer.WriteString(fmt.Sprintf("%d", v.Major)) + } + if v.HasMinor || v.HasPatch || v.HasRevision { + buffer.WriteString(fmt.Sprintf(".%d", v.Minor)) + } + if v.HasPatch || v.HasRevision { + buffer.WriteString(fmt.Sprintf(".%d", v.Patch)) + } + if v.HasRevision { + buffer.WriteString(fmt.Sprintf("-%d", v.Revision)) + } + return buffer.String() +} + +func NewVersion(filename string) (VERSION, error) { + f, err := os.ReadFile(filename) + if err != nil { + return VERSION{}, fmt.Errorf("error reading %s: %w", filename, err) + } + fields := strings.FieldsFunc(string(f), func(r rune) bool { return r == '.' || r == '-' }) + if len(fields) > 4 { + return VERSION{}, fmt.Errorf("invalid VERSION file format - %d fields (expected 0-4)", len(fields)) + } + results := VERSION{ + Filename: filename, + } + if len(fields) > 0 { + results.Major, err = strconv.ParseUint(fields[0], 10, 64) + if err != nil { + return VERSION{}, fmt.Errorf("error parsing major version: %w", err) + } + results.HasMajor = true + } + if len(fields) > 1 { + results.Minor, err = strconv.ParseUint(fields[1], 10, 64) + if err != nil { + return VERSION{}, fmt.Errorf("error parsing minor version: %w", err) + } + results.HasMinor = true + } + if len(fields) > 2 { + results.Patch, err = strconv.ParseUint(fields[2], 10, 64) + if err != nil { + return VERSION{}, fmt.Errorf("error parsing patch version: %w", err) + } + results.HasPatch = true + } + if len(fields) > 3 { + results.Revision, err = strconv.ParseUint(fields[3], 10, 64) + if err != nil { + return VERSION{}, fmt.Errorf("error parsing revision: %w", err) + } + results.HasRevision = true + } + return results, nil +} + +func IncrementVersion(version VERSION, major, minor, patch, revision bool) VERSION { + if major { + version.Major++ + version.HasMajor = true + } + if minor { + version.Minor++ + version.HasMinor = true + } + if patch { + version.Patch++ + version.HasPatch = true + } + if revision { + version.Revision++ + version.HasRevision = true + } + return version +} + +func main() { + flag.Usage = func() { + fmt.Println("usage: increment_version ") + fmt.Println(" increment_version ") + fmt.Println("increment_version increments the version of a given VERSION file.") + fmt.Println("It accepts the following formats:") + fmt.Println("\t..-") + fmt.Println("\t..") + fmt.Println("\t.") + fmt.Println("\t") + fmt.Println("the following flags are used to determine which fields to increment.") + fmt.Println("using a flag without a corresponding value in the VERSION file will result") + fmt.Println("in that field, along with all the necessary fields to the left being") + fmt.Println("created inside that file.") + } + var major, minor, patch, revision, dry bool + flag.BoolVar(&major, "major", false, "increment major version") + flag.BoolVar(&minor, "minor", false, "increment minor version") + flag.BoolVar(&patch, "patch", false, "increment patch version") + flag.BoolVar(&revision, "revision", false, "increment revision") + flag.BoolVar(&dry, "dry", true, "do not change the file (just print the new version)") + flag.Parse() + args := flag.Args() + if len(args) == 0 { + fmt.Println("requires path to VERSION file") + flag.Usage() + os.Exit(1) + } + filename := strings.Join(args, " ") + oldversion, err := NewVersion(filename) + if err != nil { + fmt.Printf("error loading version file %s: %v\n", filename, err) + os.Exit(1) + } + newversion := IncrementVersion(oldversion, major, minor, patch, revision) + fmt.Printf("'%s' => '%s'\n", oldversion, newversion) + if !dry { + err = newversion.Flush() + if err != nil { + fmt.Printf("error writing updated VERSION to %s: %v\n", filename, err) + } + } +} diff --git a/main_test.go b/main_test.go new file mode 100644 index 0000000..1f1138b --- /dev/null +++ b/main_test.go @@ -0,0 +1,78 @@ +package main + +import ( + "os" + "testing" +) + +func TestIncrementVersion(t *testing.T) { + const TEST_VERSIONFILE = "main_test-VERSION" + err := os.WriteFile(TEST_VERSIONFILE, []byte("0.0.0-0"), 0664) + if err != nil { + t.Fatalf("error writing %s: %v\n", TEST_VERSIONFILE, err) + } + defer os.Remove(TEST_VERSIONFILE) + version, err := NewVersion(TEST_VERSIONFILE) + if err != nil { + t.Fatalf("error reading %s: %v\n", TEST_VERSIONFILE, err) + } + if want, got := "0.0.0-0", version.String(); want != got { + t.Fatalf("error: wanted %s; got %s\n", want, got) + } + version = IncrementVersion(version, false, false, false, true) + if want, got := "0.0.0-1", version.String(); want != got { + t.Fatalf("error: wanted %s; got %s\n", want, got) + } + err = version.Flush() + if err != nil { + t.Fatalf("error flushing: %v\n", err) + } + version, err = NewVersion(TEST_VERSIONFILE) + if err != nil { + t.Fatalf("error reading %s: %v\n", TEST_VERSIONFILE, err) + } else if want, got := "0.0.0-1", version.String(); want != got { + t.Fatalf("error: wanted %s; got %s\n", want, got) + } + version = IncrementVersion(version, false, false, true, false) + if want, got := "0.0.1-1", version.String(); want != got { + t.Fatalf("error: wanted %s; got %s\n", want, got) + } + err = version.Flush() + if err != nil { + t.Fatalf("error flushing: %v\n", err) + } + version, err = NewVersion(TEST_VERSIONFILE) + if err != nil { + t.Fatalf("error reading %s: %v\n", TEST_VERSIONFILE, err) + } else if want, got := "0.0.1-1", version.String(); want != got { + t.Fatalf("error: wanted %s; got %s\n", want, got) + } + version = IncrementVersion(version, false, true, false, false) + if want, got := "0.1.1-1", version.String(); want != got { + t.Fatalf("error: wanted %s; got %s\n", want, got) + } + err = version.Flush() + if err != nil { + t.Fatalf("error flushing: %v\n", err) + } + version, err = NewVersion(TEST_VERSIONFILE) + if err != nil { + t.Fatalf("error reading %s: %v\n", TEST_VERSIONFILE, err) + } else if want, got := "0.1.1-1", version.String(); want != got { + t.Fatalf("error: wanted %s; got %s\n", want, got) + } + version = IncrementVersion(version, true, false, false, false) + if want, got := "1.1.1-1", version.String(); want != got { + t.Fatalf("error: wanted %s; got %s\n", want, got) + } + err = version.Flush() + if err != nil { + t.Fatalf("error flushing: %v\n", err) + } + version, err = NewVersion(TEST_VERSIONFILE) + if err != nil { + t.Fatalf("error reading %s: %v\n", TEST_VERSIONFILE, err) + } else if want, got := "1.1.1-1", version.String(); want != got { + t.Fatalf("error: wanted %s; got %s\n", want, got) + } +}