Example #1
0
File: cl.go Project: 4shome/go.jiri
func getDependencyPathFileName(ctx *tool.Context, branch string) (string, error) {
	topLevel, err := ctx.Git().TopLevel()
	if err != nil {
		return "", err
	}
	return filepath.Join(topLevel, project.MetadataDirName(), branch, dependencyPathFileName), nil
}
Example #2
0
File: cl.go Project: 4shome/go.jiri
func newCL(ctx *tool.Context, args []string) error {
	topLevel, err := ctx.Git().TopLevel()
	if err != nil {
		return err
	}
	originalBranch, err := ctx.Git().CurrentBranchName()
	if err != nil {
		return err
	}

	// Create a new branch using the current branch.
	newBranch := args[0]
	if err := ctx.Git().CreateAndCheckoutBranch(newBranch); err != nil {
		return err
	}

	// Register a cleanup handler in case of subsequent errors.
	cleanup := true
	defer func() {
		if cleanup {
			ctx.Git().CheckoutBranch(originalBranch, gitutil.ForceOpt(true))
			ctx.Git().DeleteBranch(newBranch, gitutil.ForceOpt(true))
		}
	}()

	// Record the dependent CLs for the new branch. The dependent CLs
	// are recorded in a <dependencyPathFileName> file as a
	// newline-separated list of branch names.
	branches, err := getDependentCLs(ctx, originalBranch)
	if err != nil {
		return err
	}
	branches = append(branches, originalBranch)
	newMetadataDir := filepath.Join(topLevel, project.MetadataDirName(), newBranch)
	if err := ctx.Run().MkdirAll(newMetadataDir, os.FileMode(0755)); err != nil {
		return err
	}
	file, err := getDependencyPathFileName(ctx, newBranch)
	if err != nil {
		return err
	}
	if err := ctx.Run().WriteFile(file, []byte(strings.Join(branches, "\n")), os.FileMode(0644)); err != nil {
		return err
	}

	cleanup = false
	return nil
}
Example #3
0
// createRepo creates a new repository in the given working directory.
func createRepo(t *testing.T, ctx *tool.Context, workingDir, prefix string) string {
	repoPath, err := ctx.Run().TempDir(workingDir, "repo-"+prefix)
	if err != nil {
		t.Fatalf("TempDir() failed: %v", err)
	}
	if err := os.Chmod(repoPath, 0777); err != nil {
		t.Fatalf("Chmod(%v) failed: %v", repoPath, err)
	}
	if err := ctx.Git().Init(repoPath); err != nil {
		t.Fatalf("%v", err)
	}
	if err := ctx.Run().MkdirAll(filepath.Join(repoPath, project.MetadataDirName()), os.FileMode(0755)); err != nil {
		t.Fatalf("%v", err)
	}
	return repoPath
}
Example #4
0
File: cl.go Project: 4shome/go.jiri
// updateReviewMessage writes the commit message to the given file.
func (review *review) updateReviewMessage(file string) error {
	if err := review.ctx.Git().CheckoutBranch(review.reviewBranch); err != nil {
		return err
	}
	newMessage, err := review.ctx.Git().LatestCommitMessage()
	if err != nil {
		return err
	}
	// For the initial commit where the commit message file doesn't exist,
	// add/remove labels after users finish editing the commit message.
	//
	// This behavior is consistent with how Change-ID is added for the
	// initial commit so we don't confuse users.
	if _, err := review.ctx.Run().Stat(file); err != nil {
		if os.IsNotExist(err) {
			newMessage = review.processLabels(newMessage)
			if err := review.ctx.Git().CommitAmendWithMessage(newMessage); err != nil {
				return err
			}
		} else {
			return err
		}
	}
	topLevel, err := review.ctx.Git().TopLevel()
	if err != nil {
		return err
	}
	newMetadataDir := filepath.Join(topLevel, project.MetadataDirName(), review.CLOpts.Branch)
	if err := review.ctx.Run().MkdirAll(newMetadataDir, os.FileMode(0755)); err != nil {
		return err
	}
	if err := review.ctx.Run().WriteFile(file, []byte(newMessage), 0644); err != nil {
		return err
	}
	return nil
}
Example #5
0
File: cl.go Project: 4shome/go.jiri
func cleanupBranch(ctx *tool.Context, branch string) error {
	if err := ctx.Git().CheckoutBranch(branch); err != nil {
		return err
	}
	if !forceFlag {
		trackingBranch := "origin/" + remoteBranchFlag
		if err := ctx.Git().Merge(trackingBranch); err != nil {
			return err
		}
		files, err := ctx.Git().ModifiedFiles(trackingBranch, branch)
		if err != nil {
			return err
		}
		if len(files) != 0 {
			return fmt.Errorf("unmerged changes in\n%s", strings.Join(files, "\n"))
		}
	}
	if err := ctx.Git().CheckoutBranch(remoteBranchFlag); err != nil {
		return err
	}
	if err := ctx.Git().DeleteBranch(branch, gitutil.ForceOpt(true)); err != nil {
		return err
	}
	reviewBranch := branch + "-REVIEW"
	if ctx.Git().BranchExists(reviewBranch) {
		if err := ctx.Git().DeleteBranch(reviewBranch, gitutil.ForceOpt(true)); err != nil {
			return err
		}
	}
	// Delete branch metadata.
	topLevel, err := ctx.Git().TopLevel()
	if err != nil {
		return err
	}
	metadataDir := filepath.Join(topLevel, project.MetadataDirName())
	if err := ctx.Run().RemoveAll(filepath.Join(metadataDir, branch)); err != nil {
		return err
	}
	// Remove the branch from all dependency paths.
	fileInfos, err := ctx.Run().ReadDir(metadataDir)
	if err != nil {
		return err
	}
	for _, fileInfo := range fileInfos {
		if !fileInfo.IsDir() {
			continue
		}
		file, err := getDependencyPathFileName(ctx, fileInfo.Name())
		if err != nil {
			return err
		}
		data, err := ctx.Run().ReadFile(file)
		if err != nil {
			if !os.IsNotExist(err) {
				return err
			}
			continue
		}
		branches := strings.Split(string(data), "\n")
		for i, tmpBranch := range branches {
			if branch == tmpBranch {
				data := []byte(strings.Join(append(branches[:i], branches[i+1:]...), "\n"))
				if err := ctx.Run().WriteFile(file, data, os.FileMode(0644)); err != nil {
					return err
				}
				break
			}
		}
	}
	return nil
}
Example #6
0
File: cl.go Project: 4shome/go.jiri
	return nil
}

// cmdCLNew represents the "jiri cl new" command.
var cmdCLNew = &cmdline.Command{
	Runner: cmdline.RunnerFunc(runCLNew),
	Name:   "new",
	Short:  "Create a new local branch for a changelist",
	Long: fmt.Sprintf(`
Command "new" creates a new local branch for a changelist. In
particular, it forks a new branch with the given name from the current
branch and records the relationship between the current branch and the
new branch in the %v metadata directory. The information recorded in
the %v metadata directory tracks dependencies between CLs and is used
by the "jiri cl sync" and "jiri cl mail" commands.
`, project.MetadataDirName(), project.MetadataDirName()),
	ArgsName: "<name>",
	ArgsLong: "<name> is the changelist name.",
}

func runCLNew(env *cmdline.Env, args []string) error {
	if got, want := len(args), 1; got != want {
		return env.UsageErrorf("unexpected number of arguments: got %v, want %v", got, want)
	}
	ctx := tool.NewContextFromEnv(env)
	return newCL(ctx, args)
}

func newCL(ctx *tool.Context, args []string) error {
	topLevel, err := ctx.Git().TopLevel()
	if err != nil {