mirror of
https://github.com/dolthub/dolt.git
synced 2026-02-24 10:29:01 -06:00
Merge pull request #10532 from dolthub/macneale4-claude/verification-resolution
Adding --continue flag to cherry-pick
This commit is contained in:
@@ -193,6 +193,7 @@ func CreateCheckoutArgParser() *argparser.ArgParser {
|
||||
func CreateCherryPickArgParser() *argparser.ArgParser {
|
||||
ap := argparser.NewArgParserWithMaxArgs("cherrypick", 1)
|
||||
ap.SupportsFlag(AbortParam, "", "Abort the current conflict resolution process, and revert all changes from the in-process cherry-pick operation.")
|
||||
ap.SupportsFlag(ContinueFlag, "", "Continue the current cherry-pick operation after conflicts have been resolved.")
|
||||
ap.SupportsFlag(AllowEmptyFlag, "", "Allow empty commits to be cherry-picked. "+
|
||||
"Note that use of this option only keeps commits that were initially empty. "+
|
||||
"Commits which become empty, due to a previous commit, will cause cherry-pick to fail.")
|
||||
|
||||
@@ -47,7 +47,7 @@ If any data conflicts, schema conflicts, or constraint violations are detected d
|
||||
|
||||
var ErrCherryPickConflictsOrViolations = errors.NewKind("error: Unable to apply commit cleanly due to conflicts " +
|
||||
"or constraint violations. Please resolve the conflicts and/or constraint violations, then use `dolt add` " +
|
||||
"to add the tables to the staged set, and `dolt commit` to commit the changes and finish cherry-picking. \n" +
|
||||
"to add the tables to the staged set, and `dolt cherry-pick --continue` to complete the cherry-pick. \n" +
|
||||
"To undo all changes from this cherry-pick operation, use `dolt cherry-pick --abort`.\n" +
|
||||
"For more information on handling conflicts, see: https://docs.dolthub.com/concepts/dolt/git/conflicts")
|
||||
|
||||
@@ -96,8 +96,19 @@ func (cmd CherryPickCmd) Exec(ctx context.Context, commandStr string, args []str
|
||||
return 1
|
||||
}
|
||||
|
||||
// Check for mutually exclusive flags
|
||||
if apr.Contains(cli.AbortParam) && apr.Contains(cli.ContinueFlag) {
|
||||
err = fmt.Errorf("error: --continue and --abort are mutually exclusive")
|
||||
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
|
||||
}
|
||||
|
||||
if apr.Contains(cli.AbortParam) {
|
||||
err = cherryPickAbort(queryist.Queryist, queryist.Context)
|
||||
err = cherryPickAbort(queryist.Context, queryist.Queryist)
|
||||
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
|
||||
}
|
||||
|
||||
if apr.Contains(cli.ContinueFlag) {
|
||||
err = cherryPickContinue(queryist.Context, queryist.Queryist)
|
||||
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
|
||||
}
|
||||
|
||||
@@ -117,11 +128,11 @@ func (cmd CherryPickCmd) Exec(ctx context.Context, commandStr string, args []str
|
||||
return HandleVErrAndExitCode(errhand.BuildDError("cherry-picking multiple commits is not supported yet").SetPrintUsage().Build(), usage)
|
||||
}
|
||||
|
||||
err = cherryPick(queryist.Queryist, queryist.Context, apr, args)
|
||||
err = cherryPick(queryist.Context, queryist.Queryist, apr, args)
|
||||
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
|
||||
}
|
||||
|
||||
func cherryPick(queryist cli.Queryist, sqlCtx *sql.Context, apr *argparser.ArgParseResults, args []string) error {
|
||||
func cherryPick(sqlCtx *sql.Context, queryist cli.Queryist, apr *argparser.ArgParseResults, args []string) error {
|
||||
cherryStr := apr.Arg(0)
|
||||
if len(cherryStr) == 0 {
|
||||
return fmt.Errorf("error: cannot cherry-pick empty string")
|
||||
@@ -201,7 +212,7 @@ hint: commit your changes (dolt commit -am \"<message>\") or reset them (dolt re
|
||||
|
||||
if succeeded {
|
||||
// on success, print the commit info
|
||||
commit, err := getCommitInfo(queryist, sqlCtx, commitHash)
|
||||
commit, err := getCommitInfo(sqlCtx, queryist, commitHash)
|
||||
if commit == nil || err != nil {
|
||||
return fmt.Errorf("error: failed to get commit metadata for ref '%s': %v", commitHash, err)
|
||||
}
|
||||
@@ -220,7 +231,7 @@ hint: commit your changes (dolt commit -am \"<message>\") or reset them (dolt re
|
||||
}
|
||||
}
|
||||
|
||||
func cherryPickAbort(queryist cli.Queryist, sqlCtx *sql.Context) error {
|
||||
func cherryPickAbort(sqlCtx *sql.Context, queryist cli.Queryist) error {
|
||||
query := "call dolt_cherry_pick('--abort')"
|
||||
_, err := cli.GetRowsForSql(queryist, sqlCtx, query)
|
||||
if err != nil {
|
||||
@@ -235,6 +246,58 @@ func cherryPickAbort(queryist cli.Queryist, sqlCtx *sql.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func cherryPickContinue(sqlCtx *sql.Context, queryist cli.Queryist) error {
|
||||
query := "call dolt_cherry_pick('--continue')"
|
||||
rows, err := cli.GetRowsForSql(queryist, sqlCtx, query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(rows) != 1 {
|
||||
return fmt.Errorf("error: unexpected number of rows returned from dolt_cherry_pick: %d", len(rows))
|
||||
}
|
||||
if len(rows[0]) != 4 {
|
||||
return fmt.Errorf("error: unexpected number of columns returned from dolt_cherry_pick: %d", len(rows[0]))
|
||||
}
|
||||
|
||||
row := rows[0]
|
||||
|
||||
// We expect to get an error if there were problems, but we also could get any of the conflicts and
|
||||
// vacation counts being greater than 0 if there were problems. If we got here without an error,
|
||||
// but we have conflicts or violations, we should report and stop.
|
||||
dataConflicts, err := getInt64ColAsInt64(row[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to parse data_conflicts column: %w", err)
|
||||
}
|
||||
schemaConflicts, err := getInt64ColAsInt64(row[2])
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to parse schema_conflicts column: %w", err)
|
||||
}
|
||||
constraintViolations, err := getInt64ColAsInt64(row[3])
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to parse constraint_violations column: %w", err)
|
||||
}
|
||||
if dataConflicts > 0 || schemaConflicts > 0 || constraintViolations > 0 {
|
||||
return ErrCherryPickConflictsOrViolations.New()
|
||||
}
|
||||
|
||||
commitHash := fmt.Sprintf("%v", row[0])
|
||||
|
||||
commit, err := getCommitInfo(sqlCtx, queryist, commitHash)
|
||||
if commit == nil || err != nil {
|
||||
return fmt.Errorf("error: failed to get commit metadata for ref '%s': %v", commitHash, err)
|
||||
}
|
||||
|
||||
cli.ExecuteWithStdioRestored(func() {
|
||||
pager := outputpager.Start()
|
||||
defer pager.Stop()
|
||||
|
||||
PrintCommitInfo(pager, 0, false, false, "auto", commit)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func hasStagedAndUnstagedChanged(queryist cli.Queryist, sqlCtx *sql.Context) (hasStagedChanges bool, hasUnstagedChanges bool, err error) {
|
||||
stagedTables, unstagedTables, err := GetDoltStatus(queryist, sqlCtx)
|
||||
if err != nil {
|
||||
|
||||
@@ -173,7 +173,7 @@ func performCommit(ctx context.Context, commandStr string, args []string, cliCtx
|
||||
return 0, true
|
||||
}
|
||||
|
||||
commit, err := getCommitInfo(queryist.Queryist, queryist.Context, "HEAD")
|
||||
commit, err := getCommitInfo(queryist.Context, queryist.Queryist, "HEAD")
|
||||
if cli.ExecuteWithStdioRestored != nil {
|
||||
cli.ExecuteWithStdioRestored(func() {
|
||||
pager := outputpager.Start()
|
||||
|
||||
@@ -302,7 +302,7 @@ func logCommits(apr *argparser.ArgParseResults, commitHashes []sql.Row, queryist
|
||||
var commitsInfo []CommitInfo
|
||||
for _, hash := range commitHashes {
|
||||
cmHash := hash[0].(string)
|
||||
commit, err := getCommitInfoWithOptions(queryist, sqlCtx, cmHash, opts)
|
||||
commit, err := getCommitInfoWithOptions(sqlCtx, queryist, cmHash, opts)
|
||||
if commit == nil {
|
||||
return fmt.Errorf("no commits found for ref %s", cmHash)
|
||||
}
|
||||
|
||||
@@ -391,7 +391,7 @@ func printMergeStats(fastForward bool,
|
||||
}
|
||||
|
||||
if !apr.Contains(cli.NoCommitFlag) && !apr.Contains(cli.NoFFParam) && !fastForward && noConflicts {
|
||||
commit, err := getCommitInfo(queryist, sqlCtx, "HEAD")
|
||||
commit, err := getCommitInfo(sqlCtx, queryist, "HEAD")
|
||||
if err != nil {
|
||||
cli.Println("merge finished, but failed to get commit info")
|
||||
cli.Println(err.Error())
|
||||
|
||||
@@ -182,7 +182,7 @@ func (cmd PullCmd) Exec(ctx context.Context, commandStr string, args []string, d
|
||||
if remoteHash != "" && headHash != "" {
|
||||
cli.Println("Updating", headHash+".."+remoteHash)
|
||||
}
|
||||
commit, err := getCommitInfo(queryist.Queryist, queryist.Context, "HEAD")
|
||||
commit, err := getCommitInfo(queryist.Context, queryist.Queryist, "HEAD")
|
||||
if err != nil {
|
||||
cli.Println("pull finished, but failed to get commit info")
|
||||
cli.Println(err.Error())
|
||||
|
||||
@@ -128,7 +128,7 @@ func (cmd RevertCmd) Exec(ctx context.Context, commandStr string, args []string,
|
||||
return 1
|
||||
}
|
||||
|
||||
commit, err := getCommitInfo(queryist.Queryist, queryist.Context, "HEAD")
|
||||
commit, err := getCommitInfo(queryist.Context, queryist.Queryist, "HEAD")
|
||||
if err != nil {
|
||||
cli.Printf("Revert completed, but failure to get commit details occurred: %s\n", err.Error())
|
||||
return 1
|
||||
|
||||
@@ -319,7 +319,7 @@ func getCommitSpecPretty(queryist cli.Queryist, sqlCtx *sql.Context, commitRef s
|
||||
commitRef = strings.TrimPrefix(commitRef, "#")
|
||||
}
|
||||
|
||||
commit, err = getCommitInfo(queryist, sqlCtx, commitRef)
|
||||
commit, err = getCommitInfo(sqlCtx, queryist, commitRef)
|
||||
if err != nil {
|
||||
return commit, fmt.Errorf("error: failed to get commit metadata for ref '%s': %v", commitRef, err)
|
||||
}
|
||||
|
||||
@@ -701,11 +701,11 @@ type commitInfoOptions struct {
|
||||
}
|
||||
|
||||
// getCommitInfo returns the commit info for the given ref.
|
||||
func getCommitInfo(queryist cli.Queryist, sqlCtx *sql.Context, ref string) (*CommitInfo, error) {
|
||||
return getCommitInfoWithOptions(queryist, sqlCtx, ref, commitInfoOptions{})
|
||||
func getCommitInfo(sqlCtx *sql.Context, queryist cli.Queryist, ref string) (*CommitInfo, error) {
|
||||
return getCommitInfoWithOptions(sqlCtx, queryist, ref, commitInfoOptions{})
|
||||
}
|
||||
|
||||
func getCommitInfoWithOptions(queryist cli.Queryist, sqlCtx *sql.Context, ref string, opts commitInfoOptions) (*CommitInfo, error) {
|
||||
func getCommitInfoWithOptions(sqlCtx *sql.Context, queryist cli.Queryist, ref string, opts commitInfoOptions) (*CommitInfo, error) {
|
||||
hashOfHead, err := getHashOf(queryist, sqlCtx, "HEAD")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting hash of HEAD: %v", err)
|
||||
|
||||
@@ -231,6 +231,110 @@ func AbortCherryPick(ctx *sql.Context, dbName string) error {
|
||||
return doltSession.SetWorkingSet(ctx, dbName, newWs)
|
||||
}
|
||||
|
||||
// ContinueCherryPick continues a cherry-pick merge that was paused due to conflicts.
|
||||
// It checks that conflicts have been resolved and creates the final commit with the
|
||||
// original commit's metadata.
|
||||
func ContinueCherryPick(ctx *sql.Context, dbName string) (string, int, int, int, error) {
|
||||
doltSession := dsess.DSessFromSess(ctx.Session)
|
||||
|
||||
ws, err := doltSession.WorkingSet(ctx, dbName)
|
||||
if err != nil {
|
||||
return "", 0, 0, 0, fmt.Errorf("fatal: unable to load working set: %w", err)
|
||||
}
|
||||
|
||||
if !ws.MergeActive() {
|
||||
return "", 0, 0, 0, fmt.Errorf("error: There is no cherry-pick merge to continue")
|
||||
}
|
||||
mergeState := ws.MergeState()
|
||||
|
||||
// Count conflicts and violations similar to the first pass
|
||||
workingRoot := ws.WorkingRoot()
|
||||
stagedRoot := ws.StagedRoot()
|
||||
|
||||
// Count data conflicts
|
||||
conflictTables, err := doltdb.TablesWithDataConflicts(ctx, workingRoot)
|
||||
if err != nil {
|
||||
return "", 0, 0, 0, fmt.Errorf("error: unable to check for conflicts: %w", err)
|
||||
}
|
||||
dataConflictCount := len(conflictTables)
|
||||
|
||||
// Count schema conflicts from merge state
|
||||
schemaConflictCount := len(mergeState.TablesWithSchemaConflicts())
|
||||
|
||||
// Count constraint violations
|
||||
violationTables, err := doltdb.TablesWithConstraintViolations(ctx, workingRoot)
|
||||
if err != nil {
|
||||
return "", 0, 0, 0, fmt.Errorf("error: unable to check for constraint violations: %w", err)
|
||||
}
|
||||
constraintViolationCount := len(violationTables)
|
||||
|
||||
// If there are any conflicts or violations, return the counts with an error
|
||||
if dataConflictCount > 0 || schemaConflictCount > 0 || constraintViolationCount > 0 {
|
||||
return "", dataConflictCount, schemaConflictCount, constraintViolationCount, nil
|
||||
}
|
||||
|
||||
// This is a little strict. Technically, you could use the dolt_workspace table to stage something
|
||||
// and result in different roots.
|
||||
// TODO: test with ignored and local tables - because this strictness will probably cause issues.
|
||||
isClean, err := rootsEqual(stagedRoot, workingRoot)
|
||||
if err != nil {
|
||||
return "", 0, 0, 0, fmt.Errorf("error: unable to compare staged and working roots: %w", err)
|
||||
}
|
||||
if !isClean {
|
||||
return "", 0, 0, 0, fmt.Errorf("error: cannot continue cherry-pick with unstaged changes")
|
||||
}
|
||||
|
||||
cherryCommit := mergeState.Commit()
|
||||
if cherryCommit == nil {
|
||||
return "", 0, 0, 0, fmt.Errorf("error: unable to get original commit from merge state")
|
||||
}
|
||||
|
||||
cherryCommitMeta, err := cherryCommit.GetCommitMeta(ctx)
|
||||
if err != nil {
|
||||
return "", 0, 0, 0, fmt.Errorf("error: unable to get commit metadata: %w", err)
|
||||
}
|
||||
|
||||
// Create the commit with the original commit's metadata
|
||||
commitProps := actions.CommitStagedProps{
|
||||
Message: cherryCommitMeta.Description,
|
||||
Date: cherryCommitMeta.Time(),
|
||||
AllowEmpty: false, // in a conflict workflow, never will be 'true'
|
||||
Name: cherryCommitMeta.Name,
|
||||
Email: cherryCommitMeta.Email,
|
||||
}
|
||||
|
||||
roots, ok := doltSession.GetRoots(ctx, dbName)
|
||||
if !ok {
|
||||
return "", 0, 0, 0, fmt.Errorf("fatal: unable to load roots for %s", dbName)
|
||||
}
|
||||
|
||||
pendingCommit, err := doltSession.NewPendingCommit(ctx, dbName, roots, commitProps)
|
||||
if err != nil {
|
||||
return "", 0, 0, 0, fmt.Errorf("error: failed to create pending commit: %w", err)
|
||||
}
|
||||
if pendingCommit == nil {
|
||||
return "", 0, 0, 0, fmt.Errorf("error: no changes to commit")
|
||||
}
|
||||
|
||||
clearedWs := ws.ClearMerge()
|
||||
err = doltSession.SetWorkingSet(ctx, dbName, clearedWs)
|
||||
if err != nil {
|
||||
return "", 0, 0, 0, fmt.Errorf("error: failed to clear merge state: %w", err)
|
||||
}
|
||||
|
||||
commit, err := doltSession.DoltCommit(ctx, dbName, doltSession.GetTransaction(), pendingCommit)
|
||||
if err != nil {
|
||||
return "", 0, 0, 0, fmt.Errorf("error: failed to execute commit: %w", err)
|
||||
}
|
||||
|
||||
commitHash, err := commit.HashOf()
|
||||
if err != nil {
|
||||
return "", 0, 0, 0, fmt.Errorf("error: failed to get commit hash: %w", err)
|
||||
}
|
||||
|
||||
return commitHash.String(), 0, 0, 0, nil
|
||||
}
|
||||
|
||||
// cherryPick checks that the current working set is clean, verifies the cherry-pick commit is not a merge commit
|
||||
// or a commit without parent commit, performs merge and returns the new working set root value and
|
||||
// the commit message of cherry-picked commit as the commit message of the new commit created during this command.
|
||||
@@ -371,22 +475,35 @@ func cherryPick(ctx *sql.Context, dSess *dsess.DoltSession, roots doltdb.Roots,
|
||||
|
||||
// If any of the merge stats show a data or schema conflict or a constraint
|
||||
// violation, record that a merge is in progress.
|
||||
hasArtifacts := false
|
||||
for _, stats := range result.Stats {
|
||||
if stats.HasArtifacts() {
|
||||
ws, err := dSess.WorkingSet(ctx, dbName)
|
||||
if err != nil {
|
||||
return nil, "", nil, err
|
||||
}
|
||||
newWorkingSet := ws.StartCherryPick(cherryCommit, cherryStr)
|
||||
err = dSess.SetWorkingSet(ctx, dbName, newWorkingSet)
|
||||
if err != nil {
|
||||
return nil, "", nil, err
|
||||
}
|
||||
|
||||
hasArtifacts = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Also check if there are any constraint violations in the result root
|
||||
// This handles the case where violations weren't tracked in stats
|
||||
if !hasArtifacts && result.Root != nil {
|
||||
violationTables, err := doltdb.TablesWithConstraintViolations(ctx, result.Root)
|
||||
if err == nil && len(violationTables) > 0 {
|
||||
hasArtifacts = true
|
||||
}
|
||||
}
|
||||
|
||||
if hasArtifacts {
|
||||
ws, err := dSess.WorkingSet(ctx, dbName)
|
||||
if err != nil {
|
||||
return nil, "", nil, err
|
||||
}
|
||||
newWorkingSet := ws.StartCherryPick(cherryCommit, cherryStr)
|
||||
err = dSess.SetWorkingSet(ctx, dbName, newWorkingSet)
|
||||
if err != nil {
|
||||
return nil, "", nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return result, cherryCommitMeta.Description, cherryCommit, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -80,10 +80,18 @@ func doDoltCherryPick(ctx *sql.Context, args []string) (string, int, int, int, e
|
||||
return "", 0, 0, 0, err
|
||||
}
|
||||
|
||||
if apr.Contains(cli.AbortParam) && apr.Contains(cli.ContinueFlag) {
|
||||
return "", 0, 0, 0, fmt.Errorf("error: --continue and --abort are mutually exclusive")
|
||||
}
|
||||
|
||||
if apr.Contains(cli.AbortParam) {
|
||||
return "", 0, 0, 0, cherry_pick.AbortCherryPick(ctx, dbName)
|
||||
}
|
||||
|
||||
if apr.Contains(cli.ContinueFlag) {
|
||||
return cherry_pick.ContinueCherryPick(ctx, dbName)
|
||||
}
|
||||
|
||||
// we only support cherry-picking a single commit for now.
|
||||
if apr.NArg() == 0 {
|
||||
return "", 0, 0, 0, ErrEmptyCherryPick
|
||||
|
||||
@@ -7225,590 +7225,6 @@ var DoltAutoIncrementTests = []queries.ScriptTest{
|
||||
},
|
||||
}
|
||||
|
||||
var DoltCherryPickTests = []queries.ScriptTest{
|
||||
{
|
||||
Name: "error cases: basic validation",
|
||||
SetUpScript: []string{
|
||||
"create table t (pk int primary key, v varchar(100));",
|
||||
"call dolt_commit('-Am', 'create table t');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"insert into t values (1, \"one\");",
|
||||
"call dolt_commit('-am', 'adding row 1');",
|
||||
"set @commit1 = hashof('HEAD');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "CALL Dolt_Cherry_Pick('HEAD~100');",
|
||||
ExpectedErrStr: "invalid ancestor spec",
|
||||
},
|
||||
{
|
||||
Query: "CALL Dolt_Cherry_Pick('abcdaaaaaaaaaaaaaaaaaaaaaaaaaaaa');",
|
||||
ExpectedErrStr: "target commit not found",
|
||||
},
|
||||
{
|
||||
Query: "CALL Dolt_Cherry_Pick('--abort');",
|
||||
ExpectedErrStr: "error: There is no cherry-pick merge to abort",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "error cases: merge commits cannot be cherry-picked",
|
||||
SetUpScript: []string{
|
||||
"create table t (pk int primary key, v varchar(100));",
|
||||
"call dolt_commit('-Am', 'create table t');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"insert into t values (1, \"one\");",
|
||||
"call dolt_commit('-am', 'adding row 1');",
|
||||
"set @commit1 = hashof('HEAD');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "CALL dolt_merge('--no-ff', 'branch1');",
|
||||
Expected: []sql.Row{{doltCommit, 0, 0, "merge successful"}},
|
||||
},
|
||||
{
|
||||
Query: "CALL dolt_cherry_pick('HEAD');",
|
||||
ExpectedErrStr: "cherry-picking a merge commit is not supported",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "error cases: error with staged or unstaged changes ",
|
||||
SetUpScript: []string{
|
||||
"create table t (pk int primary key, v varchar(100));",
|
||||
"call dolt_commit('-Am', 'create table t');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"insert into t values (1, \"one\");",
|
||||
"call dolt_commit('-am', 'adding row 1');",
|
||||
"set @commit1 = hashof('HEAD');",
|
||||
"call dolt_checkout('main');",
|
||||
"INSERT INTO t VALUES (100, 'onehundy');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "CALL Dolt_Cherry_Pick(@commit1);",
|
||||
ExpectedErrStr: "cannot cherry-pick with uncommitted changes",
|
||||
},
|
||||
{
|
||||
Query: "call dolt_add('t');",
|
||||
Expected: []sql.Row{{0}},
|
||||
},
|
||||
{
|
||||
Query: "CALL Dolt_Cherry_Pick(@commit1);",
|
||||
ExpectedErrStr: "cannot cherry-pick with uncommitted changes",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "error cases: different primary keys",
|
||||
SetUpScript: []string{
|
||||
"create table t (pk int primary key, v varchar(100));",
|
||||
"call dolt_commit('-Am', 'create table t');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"ALTER TABLE t DROP PRIMARY KEY, ADD PRIMARY KEY (pk, v);",
|
||||
"call dolt_commit('-am', 'adding row 1');",
|
||||
"set @commit1 = hashof('HEAD');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "CALL Dolt_Cherry_Pick(@commit1);",
|
||||
ExpectedErrStr: "error: cannot merge because table t has different primary keys",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "basic case",
|
||||
SetUpScript: []string{
|
||||
"create table t (pk int primary key, v varchar(100));",
|
||||
"call dolt_commit('-Am', 'create table t');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"insert into t values (1, \"one\");",
|
||||
"call dolt_commit('-am', 'adding row 1');",
|
||||
"set @commit1 = hashof('HEAD');",
|
||||
"insert into t values (2, \"two\");",
|
||||
"call dolt_commit('-am', 'adding row 2');",
|
||||
"set @commit2 = hashof('HEAD');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "SELECT * FROM t;",
|
||||
Expected: []sql.Row{},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_cherry_pick(@commit2);",
|
||||
Expected: []sql.Row{{doltCommit, 0, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "SELECT * FROM t;",
|
||||
Expected: []sql.Row{{2, "two"}},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_cherry_pick(@commit1);",
|
||||
Expected: []sql.Row{{doltCommit, 0, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "SELECT * FROM t order by pk;",
|
||||
Expected: []sql.Row{{1, "one"}, {2, "two"}},
|
||||
},
|
||||
{
|
||||
// Assert that our new commit only has one parent (i.e. not a merge commit)
|
||||
Query: "select count(*) from dolt_commit_ancestors where commit_hash = hashof('HEAD');",
|
||||
Expected: []sql.Row{{1}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "keyless table",
|
||||
SetUpScript: []string{
|
||||
"call dolt_checkout('main');",
|
||||
"CREATE TABLE keyless (id int, name varchar(10));",
|
||||
"call dolt_commit('-Am', 'create table keyless on main');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"INSERT INTO keyless VALUES (1,'1'), (2,'3');",
|
||||
"call dolt_commit('-am', 'insert rows into keyless table on branch1');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "SELECT * FROM keyless;",
|
||||
Expected: []sql.Row{},
|
||||
},
|
||||
{
|
||||
Query: "CALL DOLT_CHERRY_PICK('branch1');",
|
||||
Expected: []sql.Row{{doltCommit, 0, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "SELECT * FROM keyless;",
|
||||
Expected: []sql.Row{{1, "1"}, {2, "3"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "schema change: CREATE TABLE",
|
||||
SetUpScript: []string{
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"CREATE TABLE table_a (pk BIGINT PRIMARY KEY, v varchar(10));",
|
||||
"INSERT INTO table_a VALUES (11, 'aa'), (22, 'ab');",
|
||||
"call dolt_commit('-Am', 'create table table_a');",
|
||||
"set @commit1 = hashof('HEAD');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "SHOW TABLES;",
|
||||
Expected: []sql.Row{},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_cherry_pick(@commit1);",
|
||||
Expected: []sql.Row{{doltCommit, 0, 0, 0}},
|
||||
},
|
||||
{
|
||||
// Assert that our new commit only has one parent (i.e. not a merge commit)
|
||||
Query: "select count(*) from dolt_commit_ancestors where commit_hash = hashof('HEAD');",
|
||||
Expected: []sql.Row{{1}},
|
||||
},
|
||||
{
|
||||
Query: "SHOW TABLES;",
|
||||
Expected: []sql.Row{{"table_a"}},
|
||||
},
|
||||
{
|
||||
Query: "SELECT * FROM table_a;",
|
||||
Expected: []sql.Row{{11, "aa"}, {22, "ab"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "schema change: DROP TABLE",
|
||||
SetUpScript: []string{
|
||||
"CREATE TABLE dropme (pk BIGINT PRIMARY KEY, v varchar(10));",
|
||||
"INSERT INTO dropme VALUES (11, 'aa'), (22, 'ab');",
|
||||
"call dolt_commit('-Am', 'create table dropme');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"drop table dropme;",
|
||||
"call dolt_commit('-Am', 'drop table dropme');",
|
||||
"set @commit1 = hashof('HEAD');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "SHOW TABLES;",
|
||||
Expected: []sql.Row{{"dropme"}},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_cherry_pick(@commit1);",
|
||||
Expected: []sql.Row{{doltCommit, 0, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "SHOW TABLES;",
|
||||
Expected: []sql.Row{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "schema change: ALTER TABLE ADD COLUMN",
|
||||
SetUpScript: []string{
|
||||
"create table test(pk int primary key);",
|
||||
"call dolt_commit('-Am', 'create table test on main');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"ALTER TABLE test ADD COLUMN v VARCHAR(100);",
|
||||
"call dolt_commit('-am', 'add column v to test on branch1');",
|
||||
"set @commit1 = hashof('HEAD');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "call dolt_cherry_pick(@commit1);",
|
||||
Expected: []sql.Row{{doltCommit, 0, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "SHOW CREATE TABLE test;",
|
||||
Expected: []sql.Row{{"test", "CREATE TABLE `test` (\n `pk` int NOT NULL,\n `v` varchar(100),\n PRIMARY KEY (`pk`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "schema change: ALTER TABLE DROP COLUMN",
|
||||
SetUpScript: []string{
|
||||
"create table test(pk int primary key, v varchar(100));",
|
||||
"call dolt_commit('-Am', 'create table test on main');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"ALTER TABLE test DROP COLUMN v;",
|
||||
"call dolt_commit('-am', 'drop column v from test on branch1');",
|
||||
"set @commit1 = hashof('HEAD');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "call dolt_cherry_pick(@commit1);",
|
||||
Expected: []sql.Row{{doltCommit, 0, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "SHOW CREATE TABLE test;",
|
||||
Expected: []sql.Row{{"test", "CREATE TABLE `test` (\n `pk` int NOT NULL,\n PRIMARY KEY (`pk`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "schema change: ALTER TABLE RENAME COLUMN",
|
||||
SetUpScript: []string{
|
||||
"create table test(pk int primary key, v1 varchar(100));",
|
||||
"call dolt_commit('-Am', 'create table test on main');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"ALTER TABLE test RENAME COLUMN v1 to v2;",
|
||||
"call dolt_commit('-am', 'rename column v1 to v2 in test on branch1');",
|
||||
"set @commit1 = hashof('HEAD');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "call dolt_cherry_pick(@commit1);",
|
||||
Expected: []sql.Row{{doltCommit, 0, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "SHOW CREATE TABLE test;",
|
||||
Expected: []sql.Row{{"test", "CREATE TABLE `test` (\n `pk` int NOT NULL,\n `v2` varchar(100),\n PRIMARY KEY (`pk`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "abort (@@autocommit=0)",
|
||||
SetUpScript: []string{
|
||||
"SET @@autocommit=0;",
|
||||
"create table t (pk int primary key, v varchar(100));",
|
||||
"insert into t values (1, 'one');",
|
||||
"call dolt_commit('-Am', 'create table t');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"update t set v=\"uno\" where pk=1;",
|
||||
"call dolt_commit('-Am', 'updating row 1 -> uno');",
|
||||
"alter table t drop column v;",
|
||||
"call dolt_commit('-am', 'drop column v');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "call dolt_cherry_pick(hashof('branch1'));",
|
||||
Expected: []sql.Row{{"", 1, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "select * from dolt_conflicts;",
|
||||
Expected: []sql.Row{{"t", uint64(1)}},
|
||||
},
|
||||
{
|
||||
Query: "select base_pk, base_v, our_pk, our_diff_type, their_pk, their_diff_type from dolt_conflicts_t;",
|
||||
Expected: []sql.Row{
|
||||
{1, "uno", 1, "modified", 1, "modified"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_cherry_pick('--abort');",
|
||||
Expected: []sql.Row{{"", 0, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "select * from dolt_conflicts;",
|
||||
Expected: []sql.Row{},
|
||||
},
|
||||
{
|
||||
Query: "select * from t;",
|
||||
Expected: []sql.Row{{1, "one"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "abort (@@autocommit=1)",
|
||||
SetUpScript: []string{
|
||||
"SET @@autocommit=1;",
|
||||
"SET @@dolt_allow_commit_conflicts=1;",
|
||||
"create table t (pk int primary key, v varchar(100));",
|
||||
"insert into t values (1, 'one');",
|
||||
"call dolt_commit('-Am', 'create table t');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"update t set v=\"uno\" where pk=1;",
|
||||
"call dolt_commit('-Am', 'updating row 1 -> uno');",
|
||||
"alter table t drop column v;",
|
||||
"call dolt_commit('-am', 'drop column v');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "call dolt_cherry_pick(hashof('branch1'));",
|
||||
Expected: []sql.Row{{"", 1, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "select * from dolt_conflicts;",
|
||||
Expected: []sql.Row{{"t", uint64(1)}},
|
||||
},
|
||||
{
|
||||
Query: "select base_pk, base_v, our_pk, our_diff_type, their_pk, their_diff_type from dolt_conflicts_t;",
|
||||
Expected: []sql.Row{
|
||||
{1, "uno", 1, "modified", 1, "modified"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_cherry_pick('--abort');",
|
||||
Expected: []sql.Row{{"", 0, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "select * from dolt_conflicts;",
|
||||
Expected: []sql.Row{},
|
||||
},
|
||||
{
|
||||
Query: "select * from t;",
|
||||
Expected: []sql.Row{{1, "one"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "conflict resolution (@@autocommit=0)",
|
||||
SetUpScript: []string{
|
||||
"SET @@autocommit=0;",
|
||||
"create table t (pk int primary key, v varchar(100));",
|
||||
"insert into t values (1, 'one');",
|
||||
"call dolt_commit('-Am', 'create table t');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"update t set v=\"uno\" where pk=1;",
|
||||
"call dolt_commit('-Am', 'updating row 1 -> uno');",
|
||||
"alter table t drop column v;",
|
||||
"call dolt_commit('-am', 'drop column v');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "call dolt_cherry_pick(hashof('branch1'));",
|
||||
Expected: []sql.Row{{"", 1, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "select * from dolt_conflicts;",
|
||||
Expected: []sql.Row{{"t", uint64(1)}},
|
||||
},
|
||||
{
|
||||
Query: "select * from dolt_status",
|
||||
Expected: []sql.Row{{"t", byte(0), "modified"}, {"t", byte(0), "conflict"}},
|
||||
},
|
||||
{
|
||||
Query: "select base_pk, base_v, our_pk, our_diff_type, their_pk, their_diff_type from dolt_conflicts_t;",
|
||||
Expected: []sql.Row{
|
||||
{1, "uno", 1, "modified", 1, "modified"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_conflicts_resolve('--ours', 't');",
|
||||
Expected: []sql.Row{{0}},
|
||||
},
|
||||
{
|
||||
Query: "select * from dolt_status",
|
||||
Expected: []sql.Row{{"t", byte(0), "modified"}},
|
||||
},
|
||||
{
|
||||
Query: "select * from dolt_conflicts;",
|
||||
Expected: []sql.Row{},
|
||||
},
|
||||
{
|
||||
Query: "select * from t;",
|
||||
Expected: []sql.Row{{1}},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_commit('-am', 'committing cherry-pick');",
|
||||
Expected: []sql.Row{{doltCommit}},
|
||||
},
|
||||
{
|
||||
// Assert that our new commit only has one parent (i.e. not a merge commit)
|
||||
Query: "select count(*) from dolt_commit_ancestors where commit_hash = hashof('HEAD');",
|
||||
Expected: []sql.Row{{1}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "conflict resolution (@@autocommit=1)",
|
||||
SetUpScript: []string{
|
||||
"set @@autocommit=1;",
|
||||
"SET @@dolt_allow_commit_conflicts=1;",
|
||||
"create table t (pk int primary key, c1 varchar(100));",
|
||||
"call dolt_commit('-Am', 'creating table t');",
|
||||
"insert into t values (1, \"one\");",
|
||||
"call dolt_commit('-Am', 'inserting row 1');",
|
||||
"SET @commit1 = hashof('HEAD');",
|
||||
"update t set c1=\"uno\" where pk=1;",
|
||||
"call dolt_commit('-Am', 'updating row 1 -> uno');",
|
||||
"update t set c1=\"ein\" where pk=1;",
|
||||
"call dolt_commit('-Am', 'updating row 1 -> ein');",
|
||||
"SET @commit2 = hashof('HEAD');",
|
||||
"call dolt_reset('--hard', @commit1);",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "SELECT * from dolt_status;",
|
||||
Expected: []sql.Row{},
|
||||
},
|
||||
{
|
||||
Query: "SELECT * from t;",
|
||||
Expected: []sql.Row{{1, "one"}},
|
||||
},
|
||||
{
|
||||
Query: `CALL dolt_cherry_pick(@commit2);`,
|
||||
Expected: []sql.Row{{"", 1, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: `SELECT * FROM dolt_conflicts;`,
|
||||
Expected: []sql.Row{{"t", uint64(1)}},
|
||||
},
|
||||
{
|
||||
Query: `commit;`,
|
||||
Expected: []sql.Row{},
|
||||
},
|
||||
{
|
||||
Query: `SELECT * FROM dolt_conflicts;`,
|
||||
Expected: []sql.Row{{"t", uint64(1)}},
|
||||
},
|
||||
{
|
||||
Query: `SELECT base_pk, base_c1, our_pk, our_c1, their_diff_type, their_pk, their_c1 FROM dolt_conflicts_t;`,
|
||||
Expected: []sql.Row{{1, "uno", 1, "one", "modified", 1, "ein"}},
|
||||
},
|
||||
{
|
||||
Query: `SELECT * FROM t;`,
|
||||
Expected: []sql.Row{{1, "one"}},
|
||||
},
|
||||
{
|
||||
Query: `call dolt_conflicts_resolve('--theirs', 't');`,
|
||||
Expected: []sql.Row{{0}},
|
||||
},
|
||||
{
|
||||
Query: `SELECT * FROM t;`,
|
||||
Expected: []sql.Row{{1, "ein"}},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_commit('-am', 'committing cherry-pick');",
|
||||
Expected: []sql.Row{{doltCommit}},
|
||||
},
|
||||
{
|
||||
// Assert that our new commit only has one parent (i.e. not a merge commit)
|
||||
Query: "select count(*) from dolt_commit_ancestors where commit_hash = hashof('HEAD');",
|
||||
Expected: []sql.Row{{1}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "abort (@@autocommit=1) with ignored table",
|
||||
SetUpScript: []string{
|
||||
"INSERT INTO dolt_ignore VALUES ('generated_*', 1);",
|
||||
"CREATE TABLE generated_foo (pk int PRIMARY KEY);",
|
||||
"CREATE TABLE generated_bar (pk int PRIMARY KEY);",
|
||||
"insert into generated_foo values (1);",
|
||||
"insert into generated_bar values (1);",
|
||||
"SET @@autocommit=1;",
|
||||
"SET @@dolt_allow_commit_conflicts=1;",
|
||||
"create table t (pk int primary key, v varchar(100));",
|
||||
"insert into t values (1, 'one');",
|
||||
"call dolt_add('--force', 'generated_bar');",
|
||||
"call dolt_commit('-Am', 'create table t');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"update t set v=\"uno\" where pk=1;",
|
||||
"call dolt_commit('-Am', 'updating row 1 -> uno');",
|
||||
"alter table t drop column v;",
|
||||
"call dolt_commit('-am', 'drop column v');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "call dolt_cherry_pick(hashof('branch1'));",
|
||||
Expected: []sql.Row{{"", 1, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "select * from dolt_conflicts;",
|
||||
Expected: []sql.Row{{"t", uint64(1)}},
|
||||
},
|
||||
{
|
||||
Query: "select base_pk, base_v, our_pk, our_diff_type, their_pk, their_diff_type from dolt_conflicts_t;",
|
||||
Expected: []sql.Row{
|
||||
{1, "uno", 1, "modified", 1, "modified"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Query: "insert into generated_foo values (2);",
|
||||
},
|
||||
/*
|
||||
// TODO: https://github.com/dolthub/dolt/issues/7411
|
||||
// see below
|
||||
{
|
||||
Query: "insert into generated_bar values (2);",
|
||||
},
|
||||
*/
|
||||
{
|
||||
Query: "call dolt_cherry_pick('--abort');",
|
||||
Expected: []sql.Row{{"", 0, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "select * from dolt_conflicts;",
|
||||
Expected: []sql.Row{},
|
||||
},
|
||||
{
|
||||
Query: "select * from t;",
|
||||
Expected: []sql.Row{{1, "one"}},
|
||||
},
|
||||
{
|
||||
// An ignored table should still be present (and unstaged) after aborting the merge.
|
||||
Query: "select * from dolt_status_ignored;",
|
||||
Expected: []sql.Row{{"generated_foo", byte(0), "new table", true}},
|
||||
},
|
||||
{
|
||||
// Changes made to the table during the merge should not be reverted.
|
||||
Query: "select * from generated_foo;",
|
||||
Expected: []sql.Row{{1}, {2}},
|
||||
},
|
||||
/*{
|
||||
// TODO: https://github.com/dolthub/dolt/issues/7411
|
||||
// The table that was force-added should be treated like any other table
|
||||
// and reverted to its state before the merge began.
|
||||
Query: "select * from generated_bar;",
|
||||
Expected: []sql.Row{{1}},
|
||||
},*/
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var DoltCommitTests = []queries.ScriptTest{
|
||||
{
|
||||
Name: "CALL DOLT_COMMIT('-ALL') adds all tables (including new ones) to the commit.",
|
||||
|
||||
@@ -0,0 +1,968 @@
|
||||
// Copyright 2021 Dolthub, Inc.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package enginetest
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/dolthub/go-mysql-server/enginetest"
|
||||
"github.com/dolthub/go-mysql-server/enginetest/queries"
|
||||
"github.com/dolthub/go-mysql-server/sql"
|
||||
"github.com/dolthub/go-mysql-server/sql/plan"
|
||||
"github.com/dolthub/go-mysql-server/sql/types"
|
||||
)
|
||||
|
||||
// timeValidator validates that a value is a time.Time with the expected date/time
|
||||
type timeValidator struct {
|
||||
expectedTime time.Time
|
||||
}
|
||||
|
||||
var _ enginetest.CustomValueValidator = &timeValidator{}
|
||||
|
||||
func (tv *timeValidator) Validate(val interface{}) (bool, error) {
|
||||
t, ok := val.(time.Time)
|
||||
if !ok {
|
||||
return false, nil
|
||||
}
|
||||
return t.Equal(tv.expectedTime), nil
|
||||
}
|
||||
|
||||
func timeEquals(dateStr string) *timeValidator {
|
||||
t, _ := time.Parse("2006-01-02T15:04:05Z", dateStr)
|
||||
return &timeValidator{expectedTime: t}
|
||||
}
|
||||
|
||||
var DoltCherryPickTests = []queries.ScriptTest{
|
||||
{
|
||||
Name: "error cases: basic validation",
|
||||
SetUpScript: []string{
|
||||
"create table t (pk int primary key, v varchar(100));",
|
||||
"call dolt_commit('-Am', 'create table t');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"insert into t values (1, \"one\");",
|
||||
"call dolt_commit('-am', 'adding row 1');",
|
||||
"set @commit1 = dolt_hashof('HEAD');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "CALL Dolt_Cherry_Pick('HEAD~100');",
|
||||
ExpectedErrStr: "invalid ancestor spec",
|
||||
},
|
||||
{
|
||||
Query: "CALL Dolt_Cherry_Pick('abcdaaaaaaaaaaaaaaaaaaaaaaaaaaaa');",
|
||||
ExpectedErrStr: "target commit not found",
|
||||
},
|
||||
{
|
||||
Query: "CALL Dolt_Cherry_Pick('--abort');",
|
||||
ExpectedErrStr: "error: There is no cherry-pick merge to abort",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "error cases: merge commits cannot be cherry-picked",
|
||||
SetUpScript: []string{
|
||||
"create table t (pk int primary key, v varchar(100));",
|
||||
"call dolt_commit('-Am', 'create table t');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"insert into t values (1, \"one\");",
|
||||
"call dolt_commit('-am', 'adding row 1');",
|
||||
"set @commit1 = dolt_hashof('HEAD');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "CALL dolt_merge('--no-ff', 'branch1');",
|
||||
Expected: []sql.Row{{doltCommit, 0, 0, "merge successful"}},
|
||||
},
|
||||
{
|
||||
Query: "CALL dolt_cherry_pick('HEAD');",
|
||||
ExpectedErrStr: "cherry-picking a merge commit is not supported",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "error cases: error with staged or unstaged changes ",
|
||||
SetUpScript: []string{
|
||||
"create table t (pk int primary key, v varchar(100));",
|
||||
"call dolt_commit('-Am', 'create table t');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"insert into t values (1, \"one\");",
|
||||
"call dolt_commit('-am', 'adding row 1');",
|
||||
"set @commit1 = dolt_hashof('HEAD');",
|
||||
"call dolt_checkout('main');",
|
||||
"INSERT INTO t VALUES (100, 'onehundy');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "CALL Dolt_Cherry_Pick(@commit1);",
|
||||
ExpectedErrStr: "cannot cherry-pick with uncommitted changes",
|
||||
},
|
||||
{
|
||||
Query: "call dolt_add('t');",
|
||||
Expected: []sql.Row{{0}},
|
||||
},
|
||||
{
|
||||
Query: "CALL Dolt_Cherry_Pick(@commit1);",
|
||||
ExpectedErrStr: "cannot cherry-pick with uncommitted changes",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "error cases: different primary keys",
|
||||
SetUpScript: []string{
|
||||
"create table t (pk int primary key, v varchar(100));",
|
||||
"call dolt_commit('-Am', 'create table t');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"ALTER TABLE t DROP PRIMARY KEY, ADD PRIMARY KEY (pk, v);",
|
||||
"call dolt_commit('-am', 'adding row 1');",
|
||||
"set @commit1 = dolt_hashof('HEAD');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "CALL Dolt_Cherry_Pick(@commit1);",
|
||||
ExpectedErrStr: "error: cannot merge because table t has different primary keys",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "basic case",
|
||||
SetUpScript: []string{
|
||||
"create table t (pk int primary key, v varchar(100));",
|
||||
"call dolt_commit('-Am', 'create table t');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"insert into t values (1, \"one\");",
|
||||
"call dolt_commit('-am', 'adding row 1');",
|
||||
"set @commit1 = dolt_hashof('HEAD');",
|
||||
"insert into t values (2, \"two\");",
|
||||
"call dolt_commit('-am', 'adding row 2');",
|
||||
"set @commit2 = dolt_hashof('HEAD');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "SELECT * FROM t;",
|
||||
Expected: []sql.Row{},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_cherry_pick(@commit2);",
|
||||
Expected: []sql.Row{{doltCommit, 0, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "SELECT * FROM t;",
|
||||
Expected: []sql.Row{{2, "two"}},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_cherry_pick(@commit1);",
|
||||
Expected: []sql.Row{{doltCommit, 0, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "SELECT * FROM t order by pk;",
|
||||
Expected: []sql.Row{{1, "one"}, {2, "two"}},
|
||||
},
|
||||
{
|
||||
// Assert that our new commit only has one parent (i.e. not a merge commit)
|
||||
Query: "select count(*) from dolt_commit_ancestors where commit_hash = dolt_hashof('HEAD');",
|
||||
Expected: []sql.Row{{1}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "keyless table",
|
||||
SetUpScript: []string{
|
||||
"call dolt_checkout('main');",
|
||||
"CREATE TABLE keyless (id int, name varchar(10));",
|
||||
"call dolt_commit('-Am', 'create table keyless on main');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"INSERT INTO keyless VALUES (1,'1'), (2,'3');",
|
||||
"call dolt_commit('-am', 'insert rows into keyless table on branch1');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "SELECT * FROM keyless;",
|
||||
Expected: []sql.Row{},
|
||||
},
|
||||
{
|
||||
Query: "CALL DOLT_CHERRY_PICK('branch1');",
|
||||
Expected: []sql.Row{{doltCommit, 0, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "SELECT * FROM keyless;",
|
||||
Expected: []sql.Row{{1, "1"}, {2, "3"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "schema change: CREATE TABLE",
|
||||
SetUpScript: []string{
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"CREATE TABLE table_a (pk BIGINT PRIMARY KEY, v varchar(10));",
|
||||
"INSERT INTO table_a VALUES (11, 'aa'), (22, 'ab');",
|
||||
"call dolt_commit('-Am', 'create table table_a');",
|
||||
"set @commit1 = dolt_hashof('HEAD');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "SHOW TABLES;",
|
||||
Expected: []sql.Row{},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_cherry_pick(@commit1);",
|
||||
Expected: []sql.Row{{doltCommit, 0, 0, 0}},
|
||||
},
|
||||
{
|
||||
// Assert that our new commit only has one parent (i.e. not a merge commit)
|
||||
Query: "select count(*) from dolt_commit_ancestors where commit_hash = dolt_hashof('HEAD');",
|
||||
Expected: []sql.Row{{1}},
|
||||
},
|
||||
{
|
||||
Query: "SHOW TABLES;",
|
||||
Expected: []sql.Row{{"table_a"}},
|
||||
},
|
||||
{
|
||||
Query: "SELECT * FROM table_a;",
|
||||
Expected: []sql.Row{{11, "aa"}, {22, "ab"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "schema change: DROP TABLE",
|
||||
SetUpScript: []string{
|
||||
"CREATE TABLE dropme (pk BIGINT PRIMARY KEY, v varchar(10));",
|
||||
"INSERT INTO dropme VALUES (11, 'aa'), (22, 'ab');",
|
||||
"call dolt_commit('-Am', 'create table dropme');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"drop table dropme;",
|
||||
"call dolt_commit('-Am', 'drop table dropme');",
|
||||
"set @commit1 = dolt_hashof('HEAD');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "SHOW TABLES;",
|
||||
Expected: []sql.Row{{"dropme"}},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_cherry_pick(@commit1);",
|
||||
Expected: []sql.Row{{doltCommit, 0, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "SHOW TABLES;",
|
||||
Expected: []sql.Row{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "schema change: ALTER TABLE ADD COLUMN",
|
||||
SetUpScript: []string{
|
||||
"create table test(pk int primary key);",
|
||||
"call dolt_commit('-Am', 'create table test on main');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"ALTER TABLE test ADD COLUMN v VARCHAR(100);",
|
||||
"call dolt_commit('-am', 'add column v to test on branch1');",
|
||||
"set @commit1 = dolt_hashof('HEAD');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "call dolt_cherry_pick(@commit1);",
|
||||
Expected: []sql.Row{{doltCommit, 0, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "SHOW CREATE TABLE test;",
|
||||
Expected: []sql.Row{{"test", "CREATE TABLE `test` (\n `pk` int NOT NULL,\n `v` varchar(100),\n PRIMARY KEY (`pk`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "schema change: ALTER TABLE DROP COLUMN",
|
||||
SetUpScript: []string{
|
||||
"create table test(pk int primary key, v varchar(100));",
|
||||
"call dolt_commit('-Am', 'create table test on main');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"ALTER TABLE test DROP COLUMN v;",
|
||||
"call dolt_commit('-am', 'drop column v from test on branch1');",
|
||||
"set @commit1 = dolt_hashof('HEAD');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "call dolt_cherry_pick(@commit1);",
|
||||
Expected: []sql.Row{{doltCommit, 0, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "SHOW CREATE TABLE test;",
|
||||
Expected: []sql.Row{{"test", "CREATE TABLE `test` (\n `pk` int NOT NULL,\n PRIMARY KEY (`pk`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "schema change: ALTER TABLE RENAME COLUMN",
|
||||
SetUpScript: []string{
|
||||
"create table test(pk int primary key, v1 varchar(100));",
|
||||
"call dolt_commit('-Am', 'create table test on main');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"ALTER TABLE test RENAME COLUMN v1 to v2;",
|
||||
"call dolt_commit('-am', 'rename column v1 to v2 in test on branch1');",
|
||||
"set @commit1 = dolt_hashof('HEAD');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "call dolt_cherry_pick(@commit1);",
|
||||
Expected: []sql.Row{{doltCommit, 0, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "SHOW CREATE TABLE test;",
|
||||
Expected: []sql.Row{{"test", "CREATE TABLE `test` (\n `pk` int NOT NULL,\n `v2` varchar(100),\n PRIMARY KEY (`pk`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "abort (@@autocommit=0)",
|
||||
SetUpScript: []string{
|
||||
"SET @@autocommit=0;",
|
||||
"create table t (pk int primary key, v varchar(100));",
|
||||
"insert into t values (1, 'one');",
|
||||
"call dolt_commit('-Am', 'create table t');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"update t set v=\"uno\" where pk=1;",
|
||||
"call dolt_commit('-Am', 'updating row 1 -> uno');",
|
||||
"alter table t drop column v;",
|
||||
"call dolt_commit('-am', 'drop column v');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "call dolt_cherry_pick(dolt_hashof('branch1'));",
|
||||
Expected: []sql.Row{{"", 1, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "select * from dolt_conflicts;",
|
||||
Expected: []sql.Row{{"t", uint64(1)}},
|
||||
},
|
||||
{
|
||||
Query: "select base_pk, base_v, our_pk, our_diff_type, their_pk, their_diff_type from dolt_conflicts_t;",
|
||||
Expected: []sql.Row{
|
||||
{1, "uno", 1, "modified", 1, "modified"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_cherry_pick('--abort');",
|
||||
Expected: []sql.Row{{"", 0, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "select * from dolt_conflicts;",
|
||||
Expected: []sql.Row{},
|
||||
},
|
||||
{
|
||||
Query: "select * from t;",
|
||||
Expected: []sql.Row{{1, "one"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "abort (@@autocommit=1)",
|
||||
SetUpScript: []string{
|
||||
"SET @@autocommit=1;",
|
||||
"SET @@dolt_allow_commit_conflicts=1;",
|
||||
"create table t (pk int primary key, v varchar(100));",
|
||||
"insert into t values (1, 'one');",
|
||||
"call dolt_commit('-Am', 'create table t');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"update t set v=\"uno\" where pk=1;",
|
||||
"call dolt_commit('-Am', 'updating row 1 -> uno');",
|
||||
"alter table t drop column v;",
|
||||
"call dolt_commit('-am', 'drop column v');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "call dolt_cherry_pick(dolt_hashof('branch1'));",
|
||||
Expected: []sql.Row{{"", 1, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "select * from dolt_conflicts;",
|
||||
Expected: []sql.Row{{"t", uint64(1)}},
|
||||
},
|
||||
{
|
||||
Query: "select base_pk, base_v, our_pk, our_diff_type, their_pk, their_diff_type from dolt_conflicts_t;",
|
||||
Expected: []sql.Row{
|
||||
{1, "uno", 1, "modified", 1, "modified"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_cherry_pick('--abort');",
|
||||
Expected: []sql.Row{{"", 0, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "select * from dolt_conflicts;",
|
||||
Expected: []sql.Row{},
|
||||
},
|
||||
{
|
||||
Query: "select * from t;",
|
||||
Expected: []sql.Row{{1, "one"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "conflict resolution (@@autocommit=0)",
|
||||
SetUpScript: []string{
|
||||
"SET @@autocommit=0;",
|
||||
"create table t (pk int primary key, v varchar(100));",
|
||||
"insert into t values (1, 'one');",
|
||||
"call dolt_commit('-Am', 'create table t');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"update t set v=\"uno\" where pk=1;",
|
||||
"call dolt_commit('-Am', 'updating row 1 -> uno');",
|
||||
"alter table t drop column v;",
|
||||
"call dolt_commit('-am', 'drop column v');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "call dolt_cherry_pick(dolt_hashof('branch1'));",
|
||||
Expected: []sql.Row{{"", 1, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "select * from dolt_conflicts;",
|
||||
Expected: []sql.Row{{"t", uint64(1)}},
|
||||
},
|
||||
{
|
||||
Query: "select * from dolt_status",
|
||||
Expected: []sql.Row{{"t", byte(0), "modified"}, {"t", byte(0), "conflict"}},
|
||||
},
|
||||
{
|
||||
Query: "select base_pk, base_v, our_pk, our_diff_type, their_pk, their_diff_type from dolt_conflicts_t;",
|
||||
Expected: []sql.Row{
|
||||
{1, "uno", 1, "modified", 1, "modified"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_conflicts_resolve('--ours', 't');",
|
||||
Expected: []sql.Row{{0}},
|
||||
},
|
||||
{
|
||||
Query: "select * from dolt_status",
|
||||
Expected: []sql.Row{{"t", byte(0), "modified"}},
|
||||
},
|
||||
{
|
||||
Query: "select * from dolt_conflicts;",
|
||||
Expected: []sql.Row{},
|
||||
},
|
||||
{
|
||||
Query: "select * from t;",
|
||||
Expected: []sql.Row{{1}},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_commit('-am', 'committing cherry-pick');",
|
||||
Expected: []sql.Row{{doltCommit}},
|
||||
},
|
||||
{
|
||||
// Assert that our new commit only has one parent (i.e. not a merge commit)
|
||||
Query: "select count(*) from dolt_commit_ancestors where commit_hash = dolt_hashof('HEAD');",
|
||||
Expected: []sql.Row{{1}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "conflict resolution (@@autocommit=1)",
|
||||
SetUpScript: []string{
|
||||
"set @@autocommit=1;",
|
||||
"SET @@dolt_allow_commit_conflicts=1;",
|
||||
"create table t (pk int primary key, c1 varchar(100));",
|
||||
"call dolt_commit('-Am', 'creating table t');",
|
||||
"insert into t values (1, \"one\");",
|
||||
"call dolt_commit('-Am', 'inserting row 1');",
|
||||
"SET @commit1 = hashof('HEAD');",
|
||||
"update t set c1=\"uno\" where pk=1;",
|
||||
"call dolt_commit('-Am', 'updating row 1 -> uno');",
|
||||
"update t set c1=\"ein\" where pk=1;",
|
||||
"call dolt_commit('-Am', 'updating row 1 -> ein');",
|
||||
"SET @commit2 = hashof('HEAD');",
|
||||
"call dolt_reset('--hard', @commit1);",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "SELECT * from dolt_status;",
|
||||
Expected: []sql.Row{},
|
||||
},
|
||||
{
|
||||
Query: "SELECT * from t;",
|
||||
Expected: []sql.Row{{1, "one"}},
|
||||
},
|
||||
{
|
||||
Query: `CALL dolt_cherry_pick(@commit2);`,
|
||||
Expected: []sql.Row{{"", 1, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: `SELECT * FROM dolt_conflicts;`,
|
||||
Expected: []sql.Row{{"t", uint64(1)}},
|
||||
},
|
||||
{
|
||||
Query: `commit;`,
|
||||
Expected: []sql.Row{},
|
||||
},
|
||||
{
|
||||
Query: `SELECT * FROM dolt_conflicts;`,
|
||||
Expected: []sql.Row{{"t", uint64(1)}},
|
||||
},
|
||||
{
|
||||
Query: `SELECT base_pk, base_c1, our_pk, our_c1, their_diff_type, their_pk, their_c1 FROM dolt_conflicts_t;`,
|
||||
Expected: []sql.Row{{1, "uno", 1, "one", "modified", 1, "ein"}},
|
||||
},
|
||||
{
|
||||
Query: `SELECT * FROM t;`,
|
||||
Expected: []sql.Row{{1, "one"}},
|
||||
},
|
||||
{
|
||||
Query: `call dolt_conflicts_resolve('--theirs', 't');`,
|
||||
Expected: []sql.Row{{0}},
|
||||
},
|
||||
{
|
||||
Query: `SELECT * FROM t;`,
|
||||
Expected: []sql.Row{{1, "ein"}},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_commit('-am', 'committing cherry-pick');",
|
||||
Expected: []sql.Row{{doltCommit}},
|
||||
},
|
||||
{
|
||||
// Assert that our new commit only has one parent (i.e. not a merge commit)
|
||||
Query: "select count(*) from dolt_commit_ancestors where commit_hash = dolt_hashof('HEAD');",
|
||||
Expected: []sql.Row{{1}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "abort (@@autocommit=1) with ignored table",
|
||||
SetUpScript: []string{
|
||||
"INSERT INTO dolt_ignore VALUES ('generated_*', 1);",
|
||||
"CREATE TABLE generated_foo (pk int PRIMARY KEY);",
|
||||
"CREATE TABLE generated_bar (pk int PRIMARY KEY);",
|
||||
"insert into generated_foo values (1);",
|
||||
"insert into generated_bar values (1);",
|
||||
"SET @@autocommit=1;",
|
||||
"SET @@dolt_allow_commit_conflicts=1;",
|
||||
"create table t (pk int primary key, v varchar(100));",
|
||||
"insert into t values (1, 'one');",
|
||||
"call dolt_add('--force', 'generated_bar');",
|
||||
"call dolt_commit('-Am', 'create table t');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"update t set v=\"uno\" where pk=1;",
|
||||
"call dolt_commit('-Am', 'updating row 1 -> uno');",
|
||||
"alter table t drop column v;",
|
||||
"call dolt_commit('-am', 'drop column v');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "call dolt_cherry_pick(dolt_hashof('branch1'));",
|
||||
Expected: []sql.Row{{"", 1, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "select * from dolt_conflicts;",
|
||||
Expected: []sql.Row{{"t", uint64(1)}},
|
||||
},
|
||||
{
|
||||
Query: "select base_pk, base_v, our_pk, our_diff_type, their_pk, their_diff_type from dolt_conflicts_t;",
|
||||
Expected: []sql.Row{
|
||||
{1, "uno", 1, "modified", 1, "modified"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Query: "insert into generated_foo values (2);",
|
||||
},
|
||||
/*
|
||||
// TODO: https://github.com/dolthub/dolt/issues/7411
|
||||
// see below
|
||||
{
|
||||
Query: "insert into generated_bar values (2);",
|
||||
},
|
||||
*/
|
||||
{
|
||||
Query: "call dolt_cherry_pick('--abort');",
|
||||
Expected: []sql.Row{{"", 0, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "select * from dolt_conflicts;",
|
||||
Expected: []sql.Row{},
|
||||
},
|
||||
{
|
||||
Query: "select * from t;",
|
||||
Expected: []sql.Row{{1, "one"}},
|
||||
},
|
||||
{
|
||||
// An ignored table should still be present (and unstaged) after aborting the merge.
|
||||
Query: "select * from dolt_status_ignored;",
|
||||
Expected: []sql.Row{{"generated_foo", byte(0), "new table", true}},
|
||||
},
|
||||
{
|
||||
// Changes made to the table during the merge should not be reverted.
|
||||
Query: "select * from generated_foo;",
|
||||
Expected: []sql.Row{{1}, {2}},
|
||||
},
|
||||
/*{
|
||||
// TODO: https://github.com/dolthub/dolt/issues/7411
|
||||
// The table that was force-added should be treated like any other table
|
||||
// and reverted to its state before the merge began.
|
||||
Query: "select * from generated_bar;",
|
||||
Expected: []sql.Row{{1}},
|
||||
},*/
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "cherry-pick --continue: successful conflict resolution workflow",
|
||||
SetUpScript: []string{
|
||||
"create table t (pk int primary key, v varchar(100));",
|
||||
"call dolt_commit('-Am', 'create table t');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"insert into t values (1, 'branch1_value');",
|
||||
"call dolt_commit('-am', 'add row from branch1', '--author', 'Test User <test@example.com>', '--date', '2022-01-01T12:00:00');",
|
||||
"set @commit1 = dolt_hashof('HEAD');",
|
||||
"call dolt_checkout('main');",
|
||||
"insert into t values (1, 'main_value');",
|
||||
"call dolt_commit('-am', 'add row from main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "set @@dolt_allow_commit_conflicts = 1;",
|
||||
Expected: []sql.Row{{types.OkResult{}}},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_cherry_pick(@commit1);",
|
||||
Expected: []sql.Row{{"", 1, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "select * from dolt_conflicts;",
|
||||
Expected: []sql.Row{{"t", uint64(1)}},
|
||||
},
|
||||
{
|
||||
Query: "select our_pk, our_v, their_pk, their_v from dolt_conflicts_t;",
|
||||
Expected: []sql.Row{
|
||||
{1, "main_value", 1, "branch1_value"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_cherry_pick('--continue');",
|
||||
Expected: []sql.Row{{"", 1, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "delete from dolt_conflicts_t",
|
||||
SkipResultsCheck: true,
|
||||
},
|
||||
{
|
||||
Query: "update t set v = 'resolved_value' where pk = 1;",
|
||||
Expected: []sql.Row{{types.OkResult{RowsAffected: 1, Info: plan.UpdateInfo{Matched: 1, Updated: 1}}}},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_add('t');",
|
||||
Expected: []sql.Row{{0}},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_cherry_pick('--continue');",
|
||||
Expected: []sql.Row{{doltCommit, 0, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "select * from t;",
|
||||
Expected: []sql.Row{{1, "resolved_value"}},
|
||||
},
|
||||
{
|
||||
Query: "select committer, email, message, date from dolt_log limit 1;",
|
||||
Expected: []sql.Row{{"Test User", "test@example.com", "add row from branch1", timeEquals("2022-01-01T12:00:00Z")}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "cherry-pick --continue not in a cherry-pick state",
|
||||
SetUpScript: []string{
|
||||
"create table t (pk int primary key, v varchar(100));",
|
||||
"call dolt_commit('-Am', 'create table t');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"insert into t values (1, 'one');",
|
||||
"call dolt_commit('-am', 'add row from branch1');",
|
||||
"set @commit1 = dolt_hashof('HEAD');",
|
||||
"call dolt_checkout('main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "call dolt_cherry_pick('--continue');",
|
||||
ExpectedErrStr: "error: There is no cherry-pick merge to continue",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "cherry-pick --continue: multiple table conflicts",
|
||||
SetUpScript: []string{
|
||||
"create table t1 (pk int primary key, v varchar(100));",
|
||||
"create table t2 (pk int primary key, v varchar(100));",
|
||||
"call dolt_commit('-Am', 'create tables');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"insert into t1 values (1, 'branch1_t1');",
|
||||
"insert into t2 values (1, 'branch1_t2');",
|
||||
"call dolt_commit('-am', 'add rows from branch1', '--author', 'Branch User <branch@example.com>', '--date', '2022-02-01T10:30:00');",
|
||||
"set @commit1 = dolt_hashof('HEAD');",
|
||||
"call dolt_checkout('main');",
|
||||
"insert into t1 values (1, 'main_t1');",
|
||||
"insert into t2 values (1, 'main_t2');",
|
||||
"call dolt_commit('-am', 'add rows from main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "set @@dolt_allow_commit_conflicts = 1;",
|
||||
Expected: []sql.Row{{types.OkResult{}}},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_cherry_pick(@commit1);",
|
||||
Expected: []sql.Row{{"", 2, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "select `table` from dolt_conflicts order by `table`;",
|
||||
Expected: []sql.Row{{"t1"}, {"t2"}},
|
||||
},
|
||||
{
|
||||
Query: "update t1 set v = 'resolved_t1' where pk = 1;",
|
||||
SkipResultsCheck: true,
|
||||
},
|
||||
{
|
||||
Query: "delete from dolt_conflicts_t1;",
|
||||
SkipResultsCheck: true,
|
||||
},
|
||||
{
|
||||
Query: "call dolt_add('t1');",
|
||||
SkipResultsCheck: true,
|
||||
},
|
||||
{
|
||||
// Should still have one remaining conflict in t2.
|
||||
Query: "call dolt_cherry_pick('--continue');",
|
||||
Expected: []sql.Row{{"", 1, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "update t2 set v = 'resolved_t2' where pk = 1;",
|
||||
SkipResultsCheck: true,
|
||||
},
|
||||
{
|
||||
Query: "delete from dolt_conflicts_t2;",
|
||||
SkipResultsCheck: true,
|
||||
},
|
||||
{
|
||||
Query: "call dolt_add('t2');",
|
||||
SkipResultsCheck: true,
|
||||
},
|
||||
{
|
||||
Query: "call dolt_cherry_pick('--continue');",
|
||||
Expected: []sql.Row{{doltCommit, 0, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "select * from t1;",
|
||||
Expected: []sql.Row{{1, "resolved_t1"}},
|
||||
},
|
||||
{
|
||||
Query: "select * from t2;",
|
||||
Expected: []sql.Row{{1, "resolved_t2"}},
|
||||
},
|
||||
{
|
||||
Query: "select * from dolt_conflicts;",
|
||||
Expected: []sql.Row{},
|
||||
},
|
||||
{
|
||||
Query: "select committer, email, message, date from dolt_log limit 1;",
|
||||
Expected: []sql.Row{{"Branch User", "branch@example.com", "add rows from branch1", timeEquals("2022-02-01T10:30:00Z")}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "cherry-pick --continue: mutually exclusive with --abort",
|
||||
SetUpScript: []string{
|
||||
"create table t (pk int primary key, v varchar(100));",
|
||||
"call dolt_commit('-Am', 'create table t');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"insert into t values (1, 'branch1_value');",
|
||||
"call dolt_commit('-am', 'add row from branch1');",
|
||||
"set @commit1 = dolt_hashof('HEAD');",
|
||||
"call dolt_checkout('main');",
|
||||
"insert into t values (1, 'main_value');",
|
||||
"call dolt_commit('-am', 'add row from main');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "set @@dolt_allow_commit_conflicts = 1;",
|
||||
Expected: []sql.Row{{types.OkResult{}}},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_cherry_pick(@commit1);",
|
||||
Expected: []sql.Row{{"", 1, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_cherry_pick('--continue', '--abort');",
|
||||
ExpectedErrStr: "error: --continue and --abort are mutually exclusive",
|
||||
},
|
||||
{
|
||||
Query: "call dolt_cherry_pick('--abort', '--continue');",
|
||||
ExpectedErrStr: "error: --continue and --abort are mutually exclusive",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "cherry-pick: constraint violations only (no merge state)",
|
||||
SetUpScript: []string{
|
||||
"create table t (pk int primary key, v varchar(100));",
|
||||
"call dolt_commit('-Am', 'create table t');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
// On branch1, insert a value that will violate constraint"
|
||||
"insert into t values (1, 'forbidden');",
|
||||
"call dolt_commit('-am', 'add forbidden value');",
|
||||
"set @commit1 = dolt_hashof('HEAD');",
|
||||
"call dolt_checkout('main');",
|
||||
// Add constraint on main after the branch
|
||||
"alter table t add CONSTRAINT chk_not_forbidden CHECK (v != 'forbidden');",
|
||||
"call dolt_commit('-am', 'add check constraint');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "set @@dolt_allow_commit_conflicts = 1;",
|
||||
Expected: []sql.Row{{types.OkResult{}}},
|
||||
},
|
||||
{
|
||||
Query: "set @@dolt_force_transaction_commit = 1;",
|
||||
Expected: []sql.Row{{types.OkResult{}}},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_cherry_pick(@commit1);",
|
||||
Expected: []sql.Row{{"", 0, 0, 1}}, // 1 constraint violation
|
||||
},
|
||||
{
|
||||
Query: "select violation_type, pk, v from dolt_constraint_violations_t;",
|
||||
Expected: []sql.Row{{"check constraint", 1, "forbidden"}},
|
||||
},
|
||||
{
|
||||
// Try to continue with constraint violations still present
|
||||
Query: "call dolt_cherry_pick('--continue');",
|
||||
Expected: []sql.Row{{"", 0, 0, 1}}, // Still has constraint violation
|
||||
},
|
||||
{
|
||||
// Fix the violation
|
||||
Query: "update t set v = 'allowed' where pk = 1;",
|
||||
Expected: []sql.Row{{types.OkResult{RowsAffected: 1, Info: plan.UpdateInfo{Matched: 1, Updated: 1}}}},
|
||||
},
|
||||
{
|
||||
Query: "delete from dolt_constraint_violations_t;",
|
||||
SkipResultsCheck: true,
|
||||
},
|
||||
{
|
||||
Query: "call dolt_add('t');",
|
||||
Expected: []sql.Row{{0}},
|
||||
},
|
||||
{
|
||||
// Now continue should succeed and preserve original commit metadata
|
||||
Query: "call dolt_cherry_pick('--continue');",
|
||||
Expected: []sql.Row{{doltCommit, 0, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "select * from t;",
|
||||
Expected: []sql.Row{{1, "allowed"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "cherry-pick --continue: with both conflicts and constraint violations",
|
||||
SetUpScript: []string{
|
||||
"create table t (pk int primary key, v varchar(100));",
|
||||
"insert into t values (1, 'initial');",
|
||||
"call dolt_commit('-Am', 'create table t and row');",
|
||||
"call dolt_checkout('-b', 'branch1');",
|
||||
"-- On branch1, modify existing row and add new row with value that will violate constraint",
|
||||
"update t set v = 'branch1_value' where pk = 1;",
|
||||
"insert into t values (2, 'forbidden');",
|
||||
"call dolt_commit('-am', 'modify row 1 and add row 2 with forbidden value');",
|
||||
"set @commit1 = dolt_hashof('HEAD');",
|
||||
"call dolt_checkout('main');",
|
||||
"-- On main, change row 1 to create conflict and add constraint",
|
||||
"update t set v = 'main_value' where pk = 1;",
|
||||
"alter table t add CONSTRAINT chk_not_forbidden CHECK (v != 'forbidden');",
|
||||
"call dolt_commit('-am', 'main changes and add constraint');",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "set @@dolt_allow_commit_conflicts = 1;",
|
||||
Expected: []sql.Row{{types.OkResult{}}},
|
||||
},
|
||||
{
|
||||
Query: "set @@dolt_force_transaction_commit = 1;",
|
||||
Expected: []sql.Row{{types.OkResult{}}},
|
||||
},
|
||||
{
|
||||
Query: "call dolt_cherry_pick(@commit1);",
|
||||
Expected: []sql.Row{{"", 1, 0, 1}}, // 1 data conflict, 1 constraint violation
|
||||
},
|
||||
{
|
||||
Query: "select * from dolt_conflicts;",
|
||||
Expected: []sql.Row{{"t", uint64(1)}},
|
||||
},
|
||||
{
|
||||
Query: "select violation_type, pk, v from dolt_constraint_violations_t;",
|
||||
Expected: []sql.Row{{"check constraint", 2, "forbidden"}},
|
||||
},
|
||||
{
|
||||
// Try to continue with both conflicts and violations
|
||||
Query: "call dolt_cherry_pick('--continue');",
|
||||
Expected: []sql.Row{{"", 1, 0, 1}}, // Still has both issues
|
||||
},
|
||||
{
|
||||
// Resolve the conflict
|
||||
Query: "update t set v = 'resolved_value' where pk = 1;",
|
||||
SkipResultsCheck: true,
|
||||
},
|
||||
{
|
||||
Query: "delete from dolt_conflicts_t;",
|
||||
SkipResultsCheck: true,
|
||||
},
|
||||
{
|
||||
Query: "call dolt_add('t');",
|
||||
SkipResultsCheck: true,
|
||||
},
|
||||
{
|
||||
// Try again - still has constraint violation
|
||||
Query: "call dolt_cherry_pick('--continue');",
|
||||
Expected: []sql.Row{{"", 0, 0, 1}}, // Only constraint violation remains
|
||||
},
|
||||
{
|
||||
// Fix the constraint violation
|
||||
Query: "delete from t where pk = 2;",
|
||||
SkipResultsCheck: true,
|
||||
},
|
||||
{
|
||||
Query: "delete from dolt_constraint_violations_t;",
|
||||
SkipResultsCheck: true,
|
||||
},
|
||||
{
|
||||
Query: "call dolt_add('t');",
|
||||
SkipResultsCheck: true,
|
||||
},
|
||||
{
|
||||
// Now continue should succeed
|
||||
Query: "call dolt_cherry_pick('--continue');",
|
||||
Expected: []sql.Row{{doltCommit, 0, 0, 0}},
|
||||
},
|
||||
{
|
||||
Query: "select * from t;",
|
||||
Expected: []sql.Row{{1, "resolved_value"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -662,3 +662,72 @@ teardown() {
|
||||
[[ "$output" =~ "Integration Manager,integration@company.com" ]] || false
|
||||
[[ "$output" =~ "Merge integration_branch" ]] || false
|
||||
}
|
||||
@test "cherry-pick: --continue after resolving conflicts" {
|
||||
dolt branch continue_test
|
||||
dolt --branch continue_test sql -q "INSERT INTO test VALUES (100, 'branch1')"
|
||||
dolt --branch continue_test add .
|
||||
dolt --branch continue_test commit --author="Feature Dev <feature@example.com>" --date="2022-01-01T12:00:00" -m "Add row from branch1"
|
||||
COMMIT1=$(get_head_commit continue_test)
|
||||
|
||||
dolt sql -q "INSERT INTO test VALUES (100, 'main')"
|
||||
dolt add .
|
||||
dolt commit -am "Add row from main"
|
||||
|
||||
run dolt cherry-pick $COMMIT1
|
||||
[ $status -eq 1 ]
|
||||
[[ $output =~ "Unable to apply commit cleanly due to conflicts" ]] || false
|
||||
|
||||
# Resolve the conflict (need to disable autocommit for conflict resolution)
|
||||
dolt sql -q "SET autocommit = 0; UPDATE test SET v = 'resolved' WHERE pk = 100; DELETE FROM dolt_conflicts_test; COMMIT;"
|
||||
dolt add test
|
||||
|
||||
run dolt cherry-pick --continue --abort
|
||||
[ $status -eq 1 ]
|
||||
[[ $output =~ "--continue and --abort are mutually exclusive" ]] || false
|
||||
|
||||
run dolt cherry-pick --continue
|
||||
[ $status -eq 0 ]
|
||||
|
||||
# Verify the commit was created with original metadata
|
||||
run dolt log -n 1
|
||||
[ $status -eq 0 ]
|
||||
[[ $output =~ "Feature Dev" ]] || false
|
||||
[[ $output =~ "feature@example.com" ]] || false
|
||||
[[ $output =~ "Add row from branch1" ]] || false
|
||||
|
||||
# Verify the resolved data is present
|
||||
run dolt sql -q "SELECT * FROM test WHERE pk = 100" -r csv
|
||||
[ $status -eq 0 ]
|
||||
[[ $output =~ "100,resolved" ]] || false
|
||||
}
|
||||
|
||||
@test "cherry-pick: --continue with no active cherry-pick" {
|
||||
run dolt cherry-pick --continue
|
||||
[ $status -eq 1 ]
|
||||
[[ $output =~ "There is no cherry-pick merge to continue" ]] || false
|
||||
}
|
||||
|
||||
@test "cherry-pick: --continue with unresolved conflicts" {
|
||||
# Create a branch with a conflicting change
|
||||
dolt branch continue_test2
|
||||
dolt --branch continue_test2 sql -q "INSERT INTO test VALUES (100, 'branch1')"
|
||||
dolt --branch continue_test2 add .
|
||||
dolt --branch continue_test2 commit -am "Add row from branch1"
|
||||
COMMIT1=$(get_head_commit continue_test2)
|
||||
|
||||
# Create a conflicting change on main
|
||||
dolt sql -q "INSERT INTO test VALUES (100, 'main')"
|
||||
dolt add .
|
||||
dolt commit -am "Add row from main"
|
||||
|
||||
# Cherry-pick should create a conflict
|
||||
run dolt cherry-pick $COMMIT1
|
||||
[ $status -eq 1 ]
|
||||
[[ $output =~ "Unable to apply commit cleanly due to conflicts" ]] || false
|
||||
|
||||
# Try to continue without resolving conflicts
|
||||
run dolt cherry-pick --continue
|
||||
[ $status -eq 1 ]
|
||||
[[ $output =~ "Unable to apply commit cleanly due to conflicts" ]] || false
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user