package main import ( "context" "errors" "fmt" "dehub.dev/src/dehub.git" "dehub.dev/src/dehub.git/cmd/dehub/dcmd" "gopkg.in/src-d/go-git.v4/plumbing" ) func cmdCommit(ctx context.Context, cmd *dcmd.Cmd) { flag := cmd.FlagSet() accountID := flag.String("account-id", "", "Account to accredit commit with") repo := ctxRepo(ctx) accreditAndCommit := func(commit dehub.Commit) error { cfg, err := repo.LoadConfig() if err != nil { return err } var account dehub.Account var ok bool for _, account = range cfg.Accounts { if account.ID == *accountID { ok = true break } } if !ok { return fmt.Errorf("account ID %q not found in config", *accountID) } else if l := len(account.Signifiers); l == 0 || l > 1 { return fmt.Errorf("account %q has %d signifiers, only one is supported right now", *accountID, l) } sig := account.Signifiers[0] sigInt, err := sig.Interface(*accountID) if err != nil { return fmt.Errorf("casting %#v to SignifierInterface: %w", sig, err) } else if commit, err = repo.AccreditCommit(commit, sigInt); err != nil { return fmt.Errorf("accrediting commit: %w", err) } gitCommit, err := repo.Commit(commit, *accountID) if err != nil { return fmt.Errorf("committing to git: %w", err) } fmt.Printf("committed to HEAD as %s\n", gitCommit.GitCommit.Hash) return nil } var hasStaged bool body := func() (context.Context, error) { if *accountID == "" { return nil, errors.New("-account-id is required") } var err error if hasStaged, err = repo.HasStagedChanges(); err != nil { return nil, fmt.Errorf("determining if any changes have been staged: %w", err) } return ctx, nil } cmd.SubCmd("change", "Commit file changes", func(ctx context.Context, cmd *dcmd.Cmd) { flag := cmd.FlagSet() msg := flag.String("msg", "", "Commit message") cmd.Run(func() (context.Context, error) { if !hasStaged { return nil, errors.New("no changes have been staged for commit") } if *msg == "" { var err error if *msg, err = tmpFileMsg(); err != nil { return nil, fmt.Errorf("error collecting commit message from user: %w", err) } else if *msg == "" { return nil, errors.New("empty commit message, not doing anything") } } commit, err := repo.NewCommitChange(*msg) if err != nil { return nil, fmt.Errorf("could not construct change commit: %w", err) } else if err := accreditAndCommit(commit); err != nil { return nil, err } return nil, nil }) }, ) cmd.SubCmd("credential", "Commit credential of one or more change commits", func(ctx context.Context, cmd *dcmd.Cmd) { flag := cmd.FlagSet() startRev := flag.String("start", "", "Revision of the starting commit to accredit (when accrediting a range of changes)") endRev := flag.String("end", "HEAD", "Revision of the ending commit to accredit (when accrediting a range of changes)") rev := flag.String("rev", "", "Revision of commit to accredit (when accrediting a single commit)") cmd.Run(func() (context.Context, error) { if *rev == "" && *startRev == "" { return nil, errors.New("-rev or -start is required") } else if hasStaged { return nil, errors.New("credential commit cannot have any files changed") } var credCommit dehub.Commit if *rev != "" { gitCommit, err := repo.GetGitRevision(plumbing.Revision(*rev)) if err != nil { return nil, fmt.Errorf("resolving revision %q: %w", *rev, err) } gitCommits := []dehub.GitCommit{gitCommit} if credCommit, err = repo.NewCommitCredentialFromChanges(gitCommits); err != nil { return nil, fmt.Errorf("constructing credential commit: %w", err) } } else { gitCommits, err := repo.GetGitRevisionRange( plumbing.Revision(*startRev), plumbing.Revision(*endRev), ) if err != nil { return nil, fmt.Errorf("resolving revisions %q to %q: %w", *startRev, *endRev, err) } else if credCommit, err = repo.NewCommitCredentialFromChanges(gitCommits); err != nil { return nil, fmt.Errorf("constructing credential commit: %w", err) } } if err := accreditAndCommit(credCommit); err != nil { return nil, err } return nil, nil }) }, ) cmd.SubCmd("comment", "Commit a comment to a branch", func(ctx context.Context, cmd *dcmd.Cmd) { flag := cmd.FlagSet() msg := flag.String("msg", "", "Comment message") cmd.Run(func() (context.Context, error) { if *msg == "" { var err error if *msg, err = tmpFileMsg(); err != nil { return nil, fmt.Errorf("collecting comment message from user: %w", err) } else if *msg == "" { return nil, errors.New("empty comment message, not doing anything") } } commit, err := repo.NewCommitComment(*msg) if err != nil { return nil, fmt.Errorf("constructing comment commit: %w", err) } return nil, accreditAndCommit(commit) }) }, ) cmd.Run(body) } func cmdCombine(ctx context.Context, cmd *dcmd.Cmd) { flag := cmd.FlagSet() onto := flag.String("onto", "", "Branch the new commit should be put onto") startRev := flag.String("start", "", "Revision of the starting commit to combine") endRev := flag.String("end", "", "Revision of the ending commit to combine") cmd.Run(func() (context.Context, error) { if *onto == "" || *startRev == "" || *endRev == "" { return nil, errors.New("-onto, -start, and -end are required") } repo := ctxRepo(ctx) commits, err := repo.GetGitRevisionRange( plumbing.Revision(*startRev), plumbing.Revision(*endRev), ) if err != nil { return nil, fmt.Errorf("error getting commits %q to %q: %w", *startRev, *endRev, err) } ontoBranch := plumbing.NewBranchReferenceName(*onto) gitCommit, err := repo.CombineCommitChanges(commits, ontoBranch) if err != nil { return nil, err } fmt.Printf("new commit %q added to branch %q\n", gitCommit.GitCommit.Hash, ontoBranch.Short()) return nil, nil }) }