From 4569a7f47564cc377c6a6480ce8507919d58a45f Mon Sep 17 00:00:00 2001 From: mpl Date: Tue, 13 May 2014 23:04:17 +0200 Subject: [PATCH] devcam review: submit changes for review Context: http://camlistore.org/issue/408 Change-Id: I587de65c9dc8d87c02541096e1f4f7765e644962 --- HACKING | 2 +- dev/devcam/devcam.go | 7 ++- dev/devcam/review.go | 126 +++++++++++++++++++++++++++++++++++++++++ misc/review | 33 +++++------ pkg/cmdmain/cmdmain.go | 4 ++ website/content/code | 2 +- 6 files changed, 151 insertions(+), 23 deletions(-) create mode 100644 dev/devcam/review.go diff --git a/HACKING b/HACKING index fcfbf955f..fff0dac29 100644 --- a/HACKING +++ b/HACKING @@ -93,6 +93,6 @@ $ ln -s ../../misc/pre-commit.githook pre-commit Finally, submit your code to gerrit with: -$ ./misc/review +$ devcam review Please update this file as appropriate. diff --git a/dev/devcam/devcam.go b/dev/devcam/devcam.go index 4729d977a..737c0b35b 100644 --- a/dev/devcam/devcam.go +++ b/dev/devcam/devcam.go @@ -148,6 +148,11 @@ func handleSignals(camliProc *os.Process) { } func checkCamliSrcRoot() { + args := flag.Args() + if len(args) > 0 && args[0] == "review" { + // exception for devcam review, which does its own check. + return + } if _, err := os.Stat("make.go"); err != nil { if !os.IsNotExist(err) { log.Fatalf("Could not stat make.go: %v", err) @@ -198,7 +203,7 @@ func build(path string) error { } func main() { - checkCamliSrcRoot() + cmdmain.CheckCwd = checkCamliSrcRoot // TODO(mpl): usage error is not really correct for devcam. // See if I can reimplement it while still using cmdmain.Main(). cmdmain.Main() diff --git a/dev/devcam/review.go b/dev/devcam/review.go new file mode 100644 index 000000000..5fd0b4fee --- /dev/null +++ b/dev/devcam/review.go @@ -0,0 +1,126 @@ +/* +Copyright 2014 The Camlistore Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// This file adds the "review" subcommand to devcam, to send changes for peer review. + +package main + +import ( + "bufio" + "flag" + "fmt" + "io/ioutil" + "log" + "os" + "os/exec" + "path/filepath" + + "camlistore.org/pkg/cmdmain" +) + +var ( + defaultHook = filepath.FromSlash("misc/commit-msg.githook") + hookFile = filepath.FromSlash(".git/hooks/commit-msg") +) + +type reviewCmd struct{} + +func init() { + cmdmain.RegisterCommand("review", func(flags *flag.FlagSet) cmdmain.CommandRunner { + return new(reviewCmd) + }) +} + +func (c *reviewCmd) Usage() { + fmt.Fprintf(cmdmain.Stderr, "Usage: devcam review\n") +} + +func (c *reviewCmd) Describe() string { + return "Submit your git commits for review." +} + +func (c *reviewCmd) RunCommand(args []string) error { + if len(args) > 0 { + return cmdmain.UsageError("too many arguments.") + } + goToCamliRoot() + c.checkHook() + gitPush() + return nil +} + +func goToCamliRoot() { + prevDir, err := os.Getwd() + if err != nil { + log.Fatalf("could not get current directory: %v", err) + } + for { + if _, err := os.Stat(defaultHook); err == nil { + return + } + if err := os.Chdir(".."); err != nil { + log.Fatalf("Could not chdir: %v", err) + } + currentDir, err := os.Getwd() + if err != nil { + log.Fatalf("Could not get current directory: %v", err) + } + if currentDir == prevDir { + log.Fatal("Camlistore tree root not found. Run from within the Camlistore tree please.") + } + prevDir = currentDir + } +} + +func (c *reviewCmd) checkHook() { + _, err := os.Stat(hookFile) + if err == nil { + return + } + if !os.IsNotExist(err) { + log.Fatal(err) + } + fmt.Fprintf(cmdmain.Stdout, "Presubmit hook to add Change-Id to commit messages is missing.\nNow automatically creating it at %v from %v\n\n", hookFile, defaultHook) + data, err := ioutil.ReadFile(defaultHook) + if err != nil { + log.Fatal(err) + } + if err := ioutil.WriteFile(hookFile, data, 0700); err != nil { + log.Fatal(err) + } + fmt.Fprintf(cmdmain.Stdout, "Amending last commit to add Change-Id.\nPlease re-save description without making changes.\n\n") + fmt.Fprintf(cmdmain.Stdout, "Press Enter to continue.\n") + if _, _, err := bufio.NewReader(cmdmain.Stdin).ReadLine(); err != nil { + log.Fatal(err) + } + + cmd := exec.Command("git", []string{"commit", "--amend"}...) + cmd.Stdout = cmdmain.Stdout + cmd.Stderr = cmdmain.Stderr + if err := cmd.Run(); err != nil { + log.Fatal(err) + } +} + +func gitPush() { + cmd := exec.Command("git", + []string{"push", "https://camlistore.googlesource.com/camlistore", "HEAD:refs/for/master"}...) + cmd.Stdout = cmdmain.Stdout + cmd.Stderr = cmdmain.Stderr + if err := cmd.Run(); err != nil { + log.Fatalf("Could not git push: %v", err) + } +} diff --git a/misc/review b/misc/review index a1351b133..9e5466cd4 100755 --- a/misc/review +++ b/misc/review @@ -3,26 +3,19 @@ use strict; use FindBin qw($Bin); -my $hook_file = "$Bin/../.git/hooks/commit-msg"; +my $devcam_binpath = ""; +my $gopath = $ENV{'GOPATH'}; -unless (-e $hook_file) { - print <); - - system("git", "commit", "--amend") and die "git commit --amend fail\n"; +if (-e "$Bin/../bin/devcam") { + $devcam_binpath = "$Bin/../bin/devcam"; +} elsif (-e "$gopath/bin/devcam") { + $devcam_binpath = "$gopath/bin/devcam"; +} elsif (-e "$Bin\\..\\bin\\devcam.exe") { + $devcam_binpath = "$Bin\\..\\bin\\devcam.exe"; +} elsif (-e "$gopath\\bin\\devcam.exe") { + $devcam_binpath = "$gopath\\bin\\devcam.exe"; +} else { + die "devcam binary not found\n"; } -exec("git", "push", "https://camlistore.googlesource.com/camlistore", "HEAD:refs/for/master"); +exec($devcam_binpath, "review"); diff --git a/pkg/cmdmain/cmdmain.go b/pkg/cmdmain/cmdmain.go index 870fed6b9..3e9b5b938 100644 --- a/pkg/cmdmain/cmdmain.go +++ b/pkg/cmdmain/cmdmain.go @@ -47,6 +47,9 @@ var ( // ExitWithFailure determines whether the command exits // with a non-zero exit status. ExitWithFailure bool + // CheckCwd checks the current working directory, and possibly + // changes it, or aborts the run if needed. + CheckCwd = func() {} ) var ErrUsage = UsageError("invalid command") @@ -233,6 +236,7 @@ func Main() { setCommandLineOutput(Stderr) } flag.Parse() + CheckCwd() args := flag.Args() if *FlagVersion { diff --git a/website/content/code b/website/content/code index 196eb1ff2..abac0fd1d 100644 --- a/website/content/code +++ b/website/content/code @@ -37,7 +37,7 @@