-
Notifications
You must be signed in to change notification settings - Fork 522
cmd/krel/cmd/ff: Initial commit of Go-based branchff tool #869
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
Conversation
(...and yes, the finished product will have tests 😅 ) |
0b14acd
to
ad43a85
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey 👋, generally LGTM, but I have some comments. Regarding the many TODO
s still left in the code I'd suggest to bring this in as soon as possible and then we can resolve them together. :)
.golangci.yml
Outdated
@@ -0,0 +1,32 @@ | |||
linters-settings: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest in adding golangci-lint as build target / verification script somewhere inside the CI.
pkg/util/common.go
Outdated
} | ||
*/ | ||
|
||
func AskYesOrNo(question string) (string, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would return a bool
here to make the usage more straight forward.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
@@ -0,0 +1,203 @@ | |||
/* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We may unify this file with the one from pkg/notes/git.go
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed here, git
related things feel like they would be worthy of their own package
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1! That was exactly what I had in mind. :)
pkg/util/git.go
Outdated
|
||
func GetMergeBase(masterRefShort, releaseRefShort string, repo *git.Repository) (string, error) { | ||
masterRef := fmt.Sprintf("origin/%s", masterRefShort) | ||
releaseRef := fmt.Sprintf("origin/%s", releaseRefShort) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default remote origin
may be a const
value somewhere since it's used in many places.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed!
pkg/util/git.go
Outdated
} | ||
|
||
if len(res) == 0 { | ||
os.Exit(1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest exit'ing in the main path and return an error here instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed!
cmd/branchff/cmd/root.go
Outdated
log.Println(err) | ||
os.Exit(1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
log.Println(err) | |
os.Exit(1) | |
log.Fatal(err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed!
@saschagrunert -- sounds like a plan! I'll work on this this week. |
/test pull-release-test |
/assign @saschagrunert @hasheddan |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is awesome @justaugustus, thanks for leading this effort :) A few comments below. Not sure at what state we should deem this mergeable, but I am fine moving forward with something that isn't perfect given we intend to iterate on this more.
) | ||
|
||
// Run wraps the exec.Cmd.Run() command and sets the standard output. | ||
// TODO: Should this take an error code argument/return an error code? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This a great thing to point out and I definitely think Run()
should be returning error here. Otherwise, any user of this package is unable to determine whether to exit or continue as they see fit based on the outcome of calling this function. While it doesn't make a huge difference for ff
, it could prove difficult to work with if any other tool consumes it.
@@ -0,0 +1,203 @@ | |||
/* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed here, git
related things feel like they would be worthy of their own package
pkg/util/git.go
Outdated
// We can then use every Remote functions to retrieve wanted information | ||
refs, err := rem.List(&git.ListOptions{}) | ||
if err != nil { | ||
log.Fatal(err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be useful to return an informative error here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Later: We could use something like wrapping errors with additional context to provide some sort of error stack.
pkg/util/common.go
Outdated
*/ | ||
|
||
func Ask(question, expectedResponse string) (string, bool, error) { | ||
retries := 3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How would you feel about making retries
a parameter here?
cmd/krel/cmd/ff.go
Outdated
} | ||
|
||
log.Printf( | ||
`Go look around in %s to make sure things look okay before pushing... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick: it might be more readable to move this to a separate variable outside the main function execution
@@ -0,0 +1,32 @@ | |||
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’m wondering if we need bazel at all if we stick to go modules and a recent version (>1.12).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@saschagrunert -- Though I grumble on occasion about bazel, we get the advantage of leveraging the verify tests from k/repo-infra.
Updating & verifying all things is now simple:
- update:
./hack/update-all.sh
- verify:
./hack/verify-all.sh
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It, being the verify, does not seem to work for me: #908
It might well be an issue on my side, could someone maybe check if that actually works for you?
cmd/krel/cmd/ff.go
Outdated
dryRunFlag = "--dry-run" | ||
} | ||
|
||
re := regexp.MustCompile(util.BranchRE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would add this as a stand alone function to the utils and avoid making BranchRE
public, like: util.IsReleaseBranch(string)
log.Fatalf("%s is not a release branch\n", branch) | ||
} | ||
|
||
branchExists, err := util.BranchExists(branch) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we return either a bool
or an error
here? Because the value of err
is unhandled and it could be that we return nil
below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still returning both, but the error is handled now.
cmd/krel/cmd/ff.go
Outdated
defer cleanupTmpDir(baseDir) | ||
} | ||
|
||
workingDir := fmt.Sprintf("%s/%s", baseDir, branch) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would stick to filepath.Join
for path manipulations.
cmd/krel/cmd/ff.go
Outdated
|
||
currentPath := fmt.Sprintf("%s", os.Getenv("PATH")) | ||
etcdPath := fmt.Sprintf("%s/third_party/etcd:%s", gitRoot, currentPath) | ||
os.Setenv("PATH", os.Getenv("PATH")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should set it to etcdPath
here, right?
) | ||
|
||
// rootCmd represents the base command when called without any subcommands | ||
var rootCmd = &cobra.Command{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is more a question to which style we want to stick:
Do we want to avoid global variables and init functions by moving them into main?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@saschagrunert -- I think I like the layout for this iteration, but we can talk style more once this merges. :)
Signed-off-by: Stephen Augustus <[email protected]>
@hasheddan @saschagrunert -- I've addressed all of your comments, so this should be good to approve/merge now! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assuming we are good with deferring tests to a future iteration (which seems fine considering we don't plan to be using this in a production setting until the tool is more robust) then LGTM!
/lgtm /approve
@hasheddan -- As a heads up,
|
@justaugustus: you cannot LGTM your own PR. In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
(haha, I knew it was going to say that.) |
In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
/lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: hasheddan, justaugustus The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While I really appreciate all the work and thoughts that are going into re-writing the tools in go, I am abit concerned about the general direction:
This seems to be generally go int o a direction of a monolithic tool for all the release things. I think it would be more useful to break the release tools apart. What do I mean by that:
In short: don't implement things & "wiring" that other tools can do for us, just implement our specifics. Specifically In the case of branchff
: really only implement our fast forwarding and merging business, push and pull and other stuff should be done elsewhere.
Why?
- We can leverage other tools (GCB) to wire the things together
- It's easier to change / adapt / ... e.g. we can just run other steps before/after the thing (
branchff
in this case) and the thing (branchff
in this case) doesn't need to know or change
Consider this:
# "monostep" / bakcbox-ish step
- name: gcr.io/k8s-release-tools/krel
args: [ "branchff", "--some-arg" ]
vs.
# get a thing, maybe not even git.k8s.io/kubernetes but some downstream vendor's repo
- name: gcr.io/cloud-builders/git
dir: src/k8s
args: [ "pull", "$_K8S_RPEO", "--branch", "$_K8S_REPO" ]
# only do the FF, nothing else
- name: gcr.io/k8s-release-tools/branchff
dir: src.k8s
args: [ "$_FF_BRANCH" ]
# push it upstream, wherever that is
- name: gcr.io/cloud-builders/git
dir: src/k8s
args: [ "push", "upstream", "$_FF_BRANCH" ]
Now I want to run some tests on the branchff'ed branch (e.g. run e2e on kind or whatnot). Ideally that would be just adding a new GCB task, and not changing any code in branchff
/krel
/...
[....]
# only do the FF, nothing else
- name: gcr.io/k8s-release-tools/branchff
dir: src.k8s
args: [ "$_FF_BRANCH" ]
# run some tests with the branchff'ed code
- name: gcr.io/k8s-release-tools/kind-e2e
args: [ "--k8s-src", "src/k8s" ]
# push it upstream, wherever that is -- IFF the last step succeeded
- name: gcr.io/cloud-builders/git
dir: src/k8s
args: [ "push", "upstream", "$_FF_BRANCH" ]
To summarise:
- I am not saying the idea of
krel
is bad, I am merely questioning the direction it seems to go a bit. - I am concerned we might be on a path were we pack too much responsibility & wiring into the tool, and not leveraging enough of the other tools we are using already anyway.
- I'd rather have some small sharp tools with a defined interface between each other. In the case of GCB the interface between multiple steps are directories to be consumed and produced. That's an easy enough thing to
- run/wire locally
- extract, reshuffle, extend, run single, ... steps
- move to another system somewhen (e.g. if we find we need tekton).
@@ -0,0 +1,32 @@ | |||
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It, being the verify, does not seem to work for me: #908
It might well be an issue on my side, could someone maybe check if that actually works for you?
We're chatting in Slack (https://kubernetes.slack.com/archives/CJH2GBF7Y/p1572605765115500) w.r.t. @hoegaarden's review. |
I think @hoegaarden 's concerns are valid. As new things are built there definitely should also be refactoring common things out of existing tools and instituting new splits in the tools and flow (as in the pull, branchff, push example). Those are more testable. It's totally conceivable one person wont see a pattern and other reviewers will, and ask for a refactor. We'll have to decide on a case by case basis if the refactor should happen before merge, be done by the original change proposer, or if it can follow and if somebody else can do it. The latter path will likely lead to more merge conflicts and rebase issues if folks aren't communicating. |
Introducing
krel
(the Kubernetes Release toolbox), and the first draft of the branch fast-forward subcommand,ff
!Here's the directory structure:
After mulling this over for a bit, I decided we should get at least two things out of this:
pkg/util/common.go
andpkg/util/git.go
are the first of these)--cleanup
and--nomock
) and common patternsThis is still pretty rough, but it's at least in a good place to merge the structure in and iterate! :)
Signed-off-by: Stephen Augustus [email protected]