func SetConfigString(key string, value string) error { task := fmt.Sprintf("Run 'git config %v %v'", key, value) _, stderr, err := shell.Run("git", "config", key, value) if err != nil { return errs.NewErrorWithHint(task, err, stderr.String()) } return nil }
func ensureRbtVersion() error { hint := ` You need to install RBTools version 0.7. Please run $ pip install rbtools==0.7 --allow-external rbtools --allow-unverified rbtools to install the correct version. ` // Load configuration and check the RBTools version only if Review Board is being used. config, err := common.LoadConfig() if err != nil { return err } if config.CodeReviewToolId() != Id { return nil } // Check the RBTools version being used. task := "Check the RBTools version being used" log.Run(task) // rbt 0.5.x prints the version string to stdout, // rbt 0.6.x prints the version string to stderr. stdout, stderr, err := shell.Run("rbt", "--version") if err != nil { // Return the hint instead of stderr. // Failing to run rbt --version probably means that it's not installed. return errs.NewErrorWithHint(task, err, hint) } var outputBuffer *bytes.Buffer if stdout.Len() != 0 { outputBuffer = stdout } else { outputBuffer = stderr } output := outputBuffer.String() pattern := regexp.MustCompile("^RBTools (([0-9]+)[.]([0-9]+).*)") parts := pattern.FindStringSubmatch(output) if len(parts) != 4 { err := fmt.Errorf("failed to parse 'rbt --version' output: %v", output) return errs.NewError(task, err) } rbtVersion := parts[1] // No need to check errors, we know the format is correct. major, _ := strconv.Atoi(parts[2]) minor, _ := strconv.Atoi(parts[3]) if !(major == 0 && minor == 7) { return errs.NewErrorWithHint( task, errors.New("unsupported rbt version detected: "+rbtVersion), hint) } return nil }
func RunCommand(command string, args ...string) (stdout *bytes.Buffer, err error) { argsList := make([]string, 2, 2+len(args)) argsList[0], argsList[1] = "--no-pager", command argsList = append(argsList, args...) task := fmt.Sprintf("Run 'git %v' with args = %#v", command, args) log.V(log.Debug).Log(task) stdout, stderr, err := shell.Run("git", argsList...) if err != nil { return nil, errs.NewErrorWithHint(task, err, stderr.String()) } return stdout, nil }
// RefExistsStrict requires the whole ref path to be specified, // e.g. refs/remotes/origin/master. func RefExistsStrict(ref string) (exists bool, err error) { task := fmt.Sprintf("Run 'git show-ref --quiet --verify %v'", ref) _, stderr, err := shell.Run("git", "show-ref", "--verify", "--quiet", ref) if err != nil { if stderr.Len() != 0 { // Non-empty error output means that there was an error. return false, errs.NewErrorWithHint(task, err, stderr.String()) } // Otherwise the ref does not exist. return false, nil } // No error means that the ref exists. return true, nil }
func GetConfigString(key string) (value string, err error) { task := fmt.Sprintf("Run 'git config %v'", key) stdout, stderr, err := shell.Run("git", "config", key) if err != nil { if stderr.Len() == 0 { // git config returns exit code 1 when the key is not set. // This can be detected by stderr being of zero length. // We treat this as the key being set to "". return "", nil } // Otherwise there is an error. return "", errs.NewErrorWithHint(task, err, stderr.String()) } // Just return what was printed to stdout. return strings.TrimSpace(stdout.String()), nil }
// Check whether SalsaFlow git hook is used. Prompts user to install our hook if it isn't. // // When the force argument is set to true, the hook is replaced when though the version matches. func CheckAndUpsert(hookType HookType, force bool) error { // Declade some variables so that we can use goto. var confirmed bool // Ping the git hook with our secret argument. repoRoot, err := gitutil.RepositoryRootAbsolutePath() if err != nil { return err } hookDestPath := filepath.Join(repoRoot, ".git", "hooks", string(hookType)) // Try to get the hook version. stdout, _, _ := shell.Run(hookDestPath, "-"+versionFlag) // In case the versions match, we are done here (unless force). installedVersion, err := version.Parse(strings.TrimSpace(stdout.String())) if !force && installedVersion != nil && installedVersion.String() == metadata.Version { return nil } // Get the hook executable absolute path. It's supposed to be installed // in the same directory as the salsaflow executable itself. task := "Get the executable folder absolute path" binDir, err := osext.ExecutableFolder() if err != nil { return errs.NewError(task, err) } hookExecutable := filepath.Join(binDir, getHookFileName(hookType)) // Check whether there is a hook already present in the repository. // If there is no hook or there is a SalsaFlow hook returning a different version string, // we don't have to ask the user, we can just install the hook. task = fmt.Sprintf("Check whether there is a git %v hook already installed", hookType) if _, err := os.Stat(hookDestPath); err != nil { if os.IsNotExist(err) { return copyHook(hookType, hookExecutable, hookDestPath) } return errs.NewError(task, err) } if installedVersion != nil || force { return copyHook(hookType, hookExecutable, hookDestPath) } // Prompt the user to confirm the SalsaFlow git commit-task hook. task = fmt.Sprintf("Prompt the user to confirm the %v hook", hookType) confirmed, err = prompt.Confirm(` I need my own git ` + string(hookType) + ` hook to be placed in the repository. Shall I create or replace your current ` + string(hookType) + ` hook?`) fmt.Println() if err != nil { return errs.NewError(task, err) } if !confirmed { // User stubbornly refuses to let us overwrite their webhook. // Inform the init has failed and let them do their thing. fmt.Printf(`I need the hook in order to do my job! Please make sure the executable located at %v runs as your `+string(hookType)+` hook and run me again! `, hookExecutable) return errs.NewError(task, fmt.Errorf("SalsaFlow git %v hook not detected", hookType)) } return copyHook(hookType, hookExecutable, hookDestPath) }
func postReviewRequestForCommit( ctx *common.ReviewContext, opts map[string]interface{}, ) error { var ( commit = ctx.Commit story = ctx.Story ) // Assert that certain field are set. switch { case commit.SHA == "": panic("SHA not set for the commit being posted") case commit.StoryIdTag == "": panic("story ID not set for the commit being posted") } // Load the RB config. config, err := LoadConfig() if err != nil { return err } // Parse the options. var ( fixes = formatOptInteger(opts["fixes"]) update = formatOptInteger(opts["update"]) open bool ) if _, ok := opts["open"]; ok { open = true } // Post the review request. args := []string{"post", "--server", config.ServerURL().String(), "--guess-fields", "yes", } if story != nil { args = append(args, "--bugs-closed", commit.StoryIdTag) } if fixes != "" { args = append(args, "--depends-on", fixes) } if update != "" { args = append(args, "--review-request-id", update) } if open { args = append(args, "--open") } args = append(args, commit.SHA) var task string if update != "" { task = "Update a Review Board review request with commit " + commit.SHA } else { task = "Create a Review Board review request for commit " + commit.SHA } log.Run(task) stdout, stderr, err := shell.Run("rbt", args...) if err != nil { // rbt is retarded and sometimes prints stderr to stdout. // That is why we return stdout when stderr is empty. if stderr.Len() == 0 { return errs.NewErrorWithHint(task, err, stdout.String()) } else { return errs.NewErrorWithHint(task, err, stderr.String()) } } logger := log.V(log.Info) logger.Lock() logger.UnsafeNewLine("") logger.UnsafeOk(task) fmt.Print(stdout) logger.Unlock() return nil }