Exemple #1
0
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
}
Exemple #3
0
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
}
Exemple #4
0
// 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
}
Exemple #5
0
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
}
Exemple #6
0
// 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
}