Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/dependency pinning and update automation #5451

Merged
2 changes: 2 additions & 0 deletions cmd/gorepomod/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ do nothing but log commands
unless you add the `--doIt` flag,
allowing the change._

_If you want to run `gorepomod` on your fork or outside of `$GOSRC` directory, add `--local` flag to your command._

#### `gorepomod list`

Lists modules and intra-repo dependencies.
Expand Down
25 changes: 24 additions & 1 deletion cmd/gorepomod/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,27 @@ module sigs.k8s.io/kustomize/cmd/gorepomod

go 1.20

require golang.org/x/mod v0.9.0
require golang.org/x/mod v0.12.0

require (
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/sagikazarmark/locafero v0.3.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.10.0 // indirect
github.com/spf13/cast v1.5.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.17.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/sys v0.12.0 // indirect
golang.org/x/text v0.13.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
483 changes: 483 additions & 0 deletions cmd/gorepomod/go.sum

Large diffs are not rendered by default.

86 changes: 86 additions & 0 deletions cmd/gorepomod/gorepomod_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright 2023 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0

package main

import (
"os/exec"
"testing"

"github.com/stretchr/testify/assert"
)

func TestListCommand(t *testing.T) {
// Assuming gorepomod is installed
var testCases = map[string]struct {
isFork bool
cmd string
expected string
}{
"upstreamWithLocalFlag": {
isFork: false,
cmd: "cd ../.. && gorepomod list --local",
},
"upstreamWithNoLocalFlag": {
isFork: false,
cmd: "cd ../.. && gorepomod list",
},
"forkWithLocalFlag": {
isFork: true,
cmd: "cd ../.. && gorepomod list --local",
},
"forkWithNoLocalFlag": {
isFork: true,
cmd: "cd ../.. && gorepomod list",
},
}

for _, tc := range testCases {
bash, err := exec.LookPath("bash")
if err != nil {
t.Error("bash not found")
}
out, err := exec.Command(bash, "-c", tc.cmd).Output()
if err != nil {
assert.Error(t, err, "exit status 1")
}
assert.Greater(t, len(string(out)), 1)
}
}

func TestPinCommand(t *testing.T) {
// Assuming gorepomod is installed
var testCases = map[string]struct {
isFork bool
cmd string
}{
"upstreamWithLocalFlag": {
isFork: false,
cmd: "cd ../.. && gorepomod pin kyaml --local",
},
"upstreamWithNoLocalFlag": {
isFork: false,
cmd: "cd ../.. && gorepomod pin kyaml",
},
"forkWithLocalFlag": {
isFork: true,
cmd: "cd ../.. && gorepomod pin kyaml --local",
},
"forkWithNoLocalFlag": {
isFork: true,
cmd: "cd ../.. && gorepomod pin kyaml",
},
}

for _, tc := range testCases {
bash, err := exec.LookPath("bash")
if err != nil {
t.Error("bash not found")
}
out, err := exec.Command(bash, "-c", tc.cmd).Output()
if err != nil {
assert.Error(t, err, "exit status 1")
}
assert.Greater(t, len(string(out)), 1)
}
}
14 changes: 12 additions & 2 deletions cmd/gorepomod/internal/arguments/args.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (

const (
doItFlag = "--doIt"
localFlag = "--local"
cmdPin = "pin"
cmdUnPin = "unpin"
cmdTidy = "tidy"
Expand Down Expand Up @@ -64,6 +65,7 @@ type Args struct {
version semver.SemVer
bump semver.SvBump
doIt bool
localFlag bool
}

func (a *Args) GetCommand() Command {
Expand Down Expand Up @@ -106,9 +108,14 @@ func (a *Args) DoIt() bool {
return a.doIt
}

func (a *Args) LocalFlag() bool {
return a.localFlag
}

type myArgs struct {
args []string
doIt bool
args []string
doIt bool
localFlag bool
}

func (a *myArgs) next() (result string) {
Expand All @@ -129,6 +136,8 @@ func newArgs() *myArgs {
for _, a := range os.Args[1:] {
if a == doItFlag {
result.doIt = true
} else if a == localFlag {
result.localFlag = true
} else {
result.args = append(result.args, a)
}
Expand All @@ -140,6 +149,7 @@ func Parse() (result *Args, err error) {
result = &Args{}
clArgs := newArgs()
result.doIt = clArgs.doIt
result.localFlag = clArgs.localFlag

result.moduleName = misc.ModuleUnknown
result.conditionalModule = misc.ModuleUnknown
Expand Down
12 changes: 6 additions & 6 deletions cmd/gorepomod/internal/edit/editor.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,19 +57,19 @@ func (e *Editor) Tidy() error {
func (e *Editor) Pin(target misc.LaModule, oldV, newV semver.SemVer) error {
err := e.run(
"edit",
"-dropreplace="+target.ImportPath(),
"-dropreplace="+target.ImportPath()+"@"+oldV.String(),
"-require="+target.ImportPath()+"@"+newV.String(),
"-dropreplace=sigs.k8s.io/kustomize/"+string(target.ShortName()),
"-dropreplace=sigs.k8s.io/kustomize/"+string(target.ShortName())+"@"+oldV.String(),
"-require=sigs.k8s.io/kustomize/"+string(target.ShortName())+"@"+newV.String(),
)
if err != nil {
return err
return fmt.Errorf("%w", err)
}
return e.run("tidy")
}

func (e *Editor) UnPin(target misc.LaModule, oldV semver.SemVer) error {
var r strings.Builder
r.WriteString(target.ImportPath())
r.WriteString("sigs.k8s.io/kustomize/" + string(target.ShortName()))
// Don't specify the old version.
// r.WriteString("@")
// r.WriteString(oldV.String())
Expand All @@ -81,7 +81,7 @@ func (e *Editor) UnPin(target misc.LaModule, oldV semver.SemVer) error {
"-replace="+r.String(),
)
if err != nil {
return err
return fmt.Errorf("%w", err)
}
return e.run("tidy")
}
62 changes: 54 additions & 8 deletions cmd/gorepomod/internal/git/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,22 @@ type Runner struct {
workDir string
// Run commands, or merely print commands.
doIt bool
// Indicate local execution to adapt with path.
localFlag bool
// Run commands, or merely print commands.
verbosity Verbosity
}

func NewLoud(wd string, doIt bool) *Runner {
return newRunner(wd, doIt, High)
func NewLoud(wd string, doIt bool, localFlag bool) *Runner {
return newRunner(wd, doIt, High, localFlag)
}

func NewQuiet(wd string, doIt bool) *Runner {
return newRunner(wd, doIt, Low)
func NewQuiet(wd string, doIt bool, localFlag bool) *Runner {
return newRunner(wd, doIt, Low, localFlag)
}

func newRunner(wd string, doIt bool, v Verbosity) *Runner {
return &Runner{workDir: wd, doIt: doIt, verbosity: v}
func newRunner(wd string, doIt bool, v Verbosity, localFlag bool) *Runner {
return &Runner{workDir: wd, doIt: doIt, verbosity: v, localFlag: localFlag}
}

func (gr *Runner) comment(f string) {
Expand Down Expand Up @@ -165,8 +167,20 @@ func (gr *Runner) LoadLocalTags() (result misc.VersionMap, err error) {

func (gr *Runner) LoadRemoteTags(
remote misc.TrackedRepo) (result misc.VersionMap, err error) {
gr.comment("loading remote tags")
var out string

// Update latest tags from upstream
gr.comment("updating tags from upstream")
_, err = gr.run(noHarmDone, "fetch", "-t", string(remoteUpstream), string(mainBranch))
if err != nil {
// Handle if repo is not a fork
_, err = gr.run(noHarmDone, "fetch", "-t", string(mainBranch))
if err != nil {
_ = fmt.Errorf("failed to fetch tags from %s", string(mainBranch))
}
}

gr.comment("loading remote tags")
out, err = gr.run(noHarmDone, "ls-remote", "--ref", string(remote))
if err != nil {
return nil, err
Expand Down Expand Up @@ -250,7 +264,15 @@ func (gr *Runner) CheckoutMainBranch() error {
// FetchRemote does that.
func (gr *Runner) FetchRemote(remote misc.TrackedRepo) error {
gr.comment("fetching remote")
return gr.runNoOut(noHarmDone, "fetch", string(remote))
err := gr.runNoOut(noHarmDone, "fetch", string(remote))
if err != nil {
// If current repo is fork
err = gr.runNoOut(noHarmDone, "fetch", string(remoteUpstream))
if err != nil {
return fmt.Errorf("%w", err)
}
}
return nil
}

// MergeFromRemoteMain does a fast forward only merge with main branch.
Expand Down Expand Up @@ -342,3 +364,27 @@ func (gr *Runner) DeleteTagFromRemote(
gr.comment("deleting tags from remote")
return gr.runNoOut(undoPainful, "push", string(remote), ":"+refsTags+tag)
}

func (gr *Runner) GetLatestTag(releaseBranch string) (string, error) {
var latestTag string
// Assuming release branch has this format: release-path/to/module-vX.Y.Z
// and each release branch maintains tags, extract version from latest `releaseBranch`
gr.comment("extract version from latest release branch")
filteredBranchList, err := gr.run(noHarmDone, "branch", "-a", "--list", "*"+releaseBranch+"*", "--sort=-committerdate")
if len(filteredBranchList) < 1 {
_ = fmt.Errorf("latest tag not found for %s", releaseBranch)
return "", err
}
newestBranch := strings.Split(strings.ReplaceAll(filteredBranchList, "\r\n", "\n"), "\n")
split := strings.Split(newestBranch[0], "-")
latestTag = split[len(split)-1]
if err != nil {
_ = fmt.Errorf("error getting latest tag for %s", releaseBranch)
}

return latestTag, nil
}

func (gr *Runner) GetMainBranch() string {
return string(mainBranch)
}
3 changes: 2 additions & 1 deletion cmd/gorepomod/internal/mod/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ func (m *Module) AbsPath() string {

func (m *Module) DependsOn(target misc.LaModule) (bool, semver.SemVer) {
for _, r := range m.mf.Require {
if r.Mod.Path == target.ImportPath() {
targetImportPath := fmt.Sprintf("sigs.k8s.io/kustomize/%s", string(target.ShortName()))
if r.Mod.Path == targetImportPath {
v, err := semver.Parse(r.Mod.Version)
if err != nil {
panic(err)
Expand Down
Loading
Loading