Skip to content

Commit

Permalink
refactor code organization (#3)
Browse files Browse the repository at this point in the history
Signed-off-by: Hector Fernandez <[email protected]>
  • Loading branch information
hectorj2f authored Dec 19, 2023
1 parent 0342e9e commit 56fa50c
Show file tree
Hide file tree
Showing 12 changed files with 300 additions and 160 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
*.dylib

# binary tool
gobump
./gobump

# Test binary, built with `go test -c`
*.test
Expand All @@ -22,3 +22,5 @@ gobump

# Go workspace file
go.work

bin*
52 changes: 51 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,21 @@
SHELL=/bin/bash -o pipefail
ifeq (,$(shell echo $$DEBUG))
else
SHELL = bash -x
endif

GIT_TAG ?= dirty-tag
GIT_VERSION ?= $(shell git describe --tags --always --dirty)
GIT_HASH ?= $(shell git rev-parse HEAD)
GIT_TREESTATE = "clean"
DATE_FMT = +%Y-%m-%dT%H:%M:%SZ
SOURCE_DATE_EPOCH ?= $(shell git log -1 --no-show-signature --pretty=%ct)
ifdef SOURCE_DATE_EPOCH
BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "$(DATE_FMT)" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "$(DATE_FMT)" 2>/dev/null || date -u "$(DATE_FMT)")
else
BUILD_DATE ?= $(shell date "$(DATE_FMT)")
endif

SRCS = $(shell find cmd -iname "*.go") $(shell find pkg -iname "*.go")

# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN))
Expand All @@ -7,11 +24,44 @@ else
GOBIN=$(shell go env GOBIN)
endif

LDFLAGS=-buildid= -X sigs.k8s.io/release-utils/version.gitVersion=$(GIT_VERSION) \
-X sigs.k8s.io/release-utils/version.gitCommit=$(GIT_HASH) \
-X sigs.k8s.io/release-utils/version.gitTreeState=$(GIT_TREESTATE) \
-X sigs.k8s.io/release-utils/version.buildDate=$(BUILD_DATE)

PLATFORMS=darwin linux
ARCHITECTURES=amd64
GOLANGCI_LINT_DIR = $(shell pwd)/bin
GOLANGCI_LINT_BIN = $(GOLANGCI_LINT_DIR)/golangci-lint

GO ?= go
TEST_FLAGS ?= -v -cover

.PHONY: all lint test clean gobump cross
all: clean lint test gobump

clean:
rm -rf gobump

gobump:
CGO_ENABLED=0 $(GO) build -trimpath -ldflags "$(LDFLAGS)" -o $@ .

.PHONY: cross
cross:
$(foreach GOOS, $(PLATFORMS),\
$(foreach GOARCH, $(ARCHITECTURES), $(shell export GOOS=$(GOOS); export GOARCH=$(GOARCH); \
$(GO) build -trimpath -ldflags "$(LDFLAGS)" -o gobump-$(GOOS)-$(GOARCH) .; \
shasum -a 256 gobump-$(GOOS)-$(GOARCH) > gobump-$(GOOS)-$(GOARCH).sha256 ))) \

.PHONY: test
test:
$(GO) vet ./...
$(GO) test ${TEST_FLAGS} ./...

golangci-lint:
rm -f $(GOLANGCI_LINT_BIN) || :
set -e ;\
GOBIN=$(GOLANGCI_LINT_DIR) $(GO) install github.com/golangci/golangci-lint/cmd/[email protected] ;\

lint: golangci-lint
$(GOLANGCI_LINT_BIN) run -n
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Go 1.20 or later
To install gobump, you can use go install:

```shell
go install github.com/dlorenc/gobump@latest
go install github.com/chainguard-dev/gobump@latest
```

## Contributing
Expand Down
76 changes: 76 additions & 0 deletions cmd/gobump/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package cmd

import (
"fmt"
"log"
"os"
"strings"

"github.com/chainguard-dev/gobump/pkg/types"
"github.com/chainguard-dev/gobump/pkg/update"
"github.com/spf13/cobra"
"sigs.k8s.io/release-utils/version"
)

type rootCLIFlags struct {
packages string
modroot string
replaces string
tidy bool
}

var rootFlags rootCLIFlags

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "gobump",
Short: "gobump cli",
Args: cobra.NoArgs,
// Uncomment the following line if your bare application
// has an action associated with it:
Run: func(cmd *cobra.Command, args []string) {
if rootFlags.packages == "" {
log.Println("Usage: gobump -packages=<package@version>,...")
os.Exit(1)
}
packages := strings.Split(rootFlags.packages, ",")
pkgVersions := []*types.Package{}
for _, pkg := range packages {
parts := strings.Split(pkg, "@")
if len(parts) != 2 {
fmt.Println("Usage: gobump -packages=<package@version>,...")
os.Exit(1)
}
pkgVersions = append(pkgVersions, &types.Package{
Name: parts[0],
Version: parts[1],
})
}

var replaces []string
if len(rootFlags.replaces) != 0 {
replaces = strings.Split(rootFlags.replaces, " ")
}

if _, err := update.DoUpdate(pkgVersions, replaces, rootFlags.modroot); err != nil {
fmt.Println("Error running update: ", err)
os.Exit(1)
}
},
}

func RootCmd() *cobra.Command {
return rootCmd
}

func init() {
rootCmd.AddCommand(version.WithFont("starwars"))

rootCmd.DisableAutoGenTag = true

flagSet := rootCmd.Flags()
flagSet.StringVar(&rootFlags.packages, "packages", "", "A space-separated list of packages to update")
flagSet.StringVar(&rootFlags.modroot, "modroot", "", "path to the go.mod root")
flagSet.StringVar(&rootFlags.replaces, "replaces", "", "A space-separated list of packages to replace")
flagSet.BoolVar(&rootFlags.tidy, "tidy", false, "Run 'go mod tidy' command")
}
14 changes: 12 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
module github.com/dlorenc/gobump
module github.com/chainguard-dev/gobump

go 1.21

require golang.org/x/mod v0.14.0
require (
github.com/spf13/cobra v1.8.0
golang.org/x/mod v0.14.0
sigs.k8s.io/release-utils v0.7.7
)

require (
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
)
21 changes: 21 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +1,23 @@
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL2kskAlV9ckgEsNQXscjIaLiOYiZ75d4e94E6dcQ=
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
sigs.k8s.io/release-utils v0.7.7 h1:JKDOvhCk6zW8ipEOkpTGDH/mW3TI+XqtPp16aaQ79FU=
sigs.k8s.io/release-utils v0.7.7/go.mod h1:iU7DGVNi3umZJ8q6aHyUFzsDUIaYwNnNKGHo3YE5E3s=
148 changes: 4 additions & 144 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,153 +1,13 @@
package main

import (
"flag"
"fmt"
"os"
"os/exec"
"path"
"strings"
"log"

"golang.org/x/mod/modfile"
"golang.org/x/mod/semver"
cmd "github.com/chainguard-dev/gobump/cmd/gobump"
)

var packagesFlag = flag.String("packages", "", "A space-separated list of packages to update")
var modrootFlag = flag.String("modroot", "", "path to the go.mod root")
var replacesFlag = flag.String("replaces", "", "A space-separated list of packages to replace")

func main() {
flag.Parse()

if *packagesFlag == "" {
fmt.Println("Usage: gobump -packages=<package@version>,...")
os.Exit(1)
}

var replaces []string
if len(*replacesFlag) != 0 {
replaces = strings.Split(*replacesFlag, " ")
}

packages := strings.Split(*packagesFlag, " ")
pkgVersions := []pkgVersion{}
for _, pkg := range packages {
parts := strings.Split(pkg, "@")
if len(parts) != 2 {
fmt.Println("Usage: gobump -packages=<package@version>,...")
os.Exit(1)
}
pkgVersions = append(pkgVersions, pkgVersion{
Name: parts[0],
Version: parts[1],
})
}

if _, err := doUpdate(pkgVersions, replaces, *modrootFlag); err != nil {
fmt.Println("Error running update: ", err)
os.Exit(1)
if err := cmd.RootCmd().Execute(); err != nil {
log.Fatal(err)
}
}

func doUpdate(pkgVersions []pkgVersion, replaces []string, modroot string) (*modfile.File, error) {
modpath := path.Join(modroot, "go.mod")
modFileContent, err := os.ReadFile(modpath)
if err != nil {
return nil, fmt.Errorf("error reading go.mod: %w", err)
}

modFile, err := modfile.Parse("go.mod", modFileContent, nil)
if err != nil {
return nil, fmt.Errorf("error parsing go.mod: %w", err)
}

// Do replaces in the beginning
for _, replace := range replaces {
cmd := exec.Command("go", "mod", "edit", "-replace", replace)
cmd.Dir = modroot
if err := cmd.Run(); err != nil {
return nil, fmt.Errorf("error running go mod edit -replace %s: %w", replace, err)
}
}

for _, pkg := range pkgVersions {
currentVersion := getVersion(modFile, pkg.Name)
if currentVersion == "" {
return nil, fmt.Errorf("package %s not found in go.mod", pkg.Name)
}
// Sometimes we request to pin to a specific commit.
// In that case, skip the compare check.
if semver.IsValid(pkg.Version) {
if semver.Compare(currentVersion, pkg.Version) > 0 {
return nil, fmt.Errorf("package %s is already at version %s", pkg.Name, pkg.Version)
}
} else {
fmt.Printf("Requesting pin to %s\n. This is not a valid SemVer, so skipping version check.", pkg.Version)
}

if err := updatePackage(modFile, pkg.Name, pkg.Version, modroot); err != nil {
return nil, fmt.Errorf("error updating package: %w", err)
}
}

// Read the entire go.mod one more time into memory and check that all the version constraints are met.
newFileContent, err := os.ReadFile(modpath)
if err != nil {
return nil, fmt.Errorf("error reading go.mod: %w", err)
}
newModFile, err := modfile.Parse("go.mod", newFileContent, nil)
if err != nil {
return nil, fmt.Errorf("error parsing go.mod: %w", err)
}
for _, pkg := range pkgVersions {
verStr := getVersion(newModFile, pkg.Name)
if semver.Compare(verStr, pkg.Version) < 0 {
return nil, fmt.Errorf("package %s is less than the desired version %s", pkg.Name, pkg.Version)
}
}

return newModFile, nil
}

func updatePackage(modFile *modfile.File, name, version, modroot string) error {
// Check if the package is replaced first
for _, replace := range modFile.Replace {
if replace.Old.Path == name {
cmd := exec.Command("go", "mod", "edit", "-replace", fmt.Sprintf("%s=%s@%s", replace.Old.Path, name, version)) //nolint:gosec
cmd.Dir = modroot
return cmd.Run()
}
}

// No replace, just update!
cmd := exec.Command("go", "get", fmt.Sprintf("%s@%s", name, version)) //nolint:gosec
cmd.Dir = modroot
if err := cmd.Run(); err != nil {
return err
}
return nil
}

func getVersion(modFile *modfile.File, packageName string) string {
// Handle package update, including 'replace' clause

// Replace checks have to come first!
for _, replace := range modFile.Replace {
if replace.Old.Path == packageName {
return replace.New.Version
}
}

for _, req := range modFile.Require {
if req.Mod.Path == packageName {
return req.Mod.Version
}
}

return ""
}

type pkgVersion struct {
Name string
Version string
}
8 changes: 8 additions & 0 deletions pkg/types/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package types

type Package struct {
Name string
Version string
Replace bool
Require bool
}
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 56fa50c

Please sign in to comment.