diff --git a/go/cmd/dolt/commands/reflog.go b/go/cmd/dolt/commands/reflog.go index 14aa3bc71b0..bc1b85c6853 100644 --- a/go/cmd/dolt/commands/reflog.go +++ b/go/cmd/dolt/commands/reflog.go @@ -107,27 +107,17 @@ func (cmd ReflogCmd) Exec(ctx context.Context, commandStr string, args []string, // Also interpolates this query to prevent sql injection func constructInterpolatedDoltReflogQuery(apr *argparser.ArgParseResults) (string, error) { var params []interface{} - refPlaceholder := "" - allFlag := "" + var args []string if apr.NArg() == 1 { params = append(params, apr.Arg(0)) - refPlaceholder = "?" + args = append(args, "?") } if apr.Contains(cli.AllFlag) { - allFlag = "'--all'" + args = append(args, "'--all'") } - args := "" - if refPlaceholder == "" && allFlag != "" { - args = allFlag - } else if refPlaceholder != "" && allFlag == "" { - args = refPlaceholder - } else if refPlaceholder != "" && allFlag != "" { - args = strings.Join([]string{refPlaceholder, allFlag}, ", ") - } - - query := strings.Join([]string{"SELECT ref, commit_hash, commit_message FROM DOLT_REFLOG(", args, ")"}, "") + query := fmt.Sprintf("SELECT ref, commit_hash, commit_message FROM DOLT_REFLOG(%s)", strings.Join(args, ", ")) interpolatedQuery, err := dbr.InterpolateForDialect(query, params, dialect.MySQL) if err != nil { return "", err @@ -147,11 +137,12 @@ func printReflog(rows []sql.Row, queryist cli.Queryist, sqlCtx *sql.Context) int var reflogInfo []ReflogInfo // Get the current branch + curBranch := "" res, err := GetRowsForSql(queryist, sqlCtx, "SELECT active_branch()") - if err != nil { - return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), nil) + if err == nil { + // still print the reflog even if we can't get the current branch + curBranch = res[0][0].(string) } - curBranch := res[0][0].(string) for _, row := range rows { ref := row[0].(string) @@ -174,13 +165,13 @@ func reflogToStdOut(reflogInfo []ReflogInfo, curBranch string) { pager := outputpager.Start() defer pager.Stop() - for pos, info := range reflogInfo { + for _, info := range reflogInfo { // TODO: use short hash instead line := []string{fmt.Sprintf("\033[33m%s\033[0m", info.commitHash)} // commit hash in yellow (33m) processedRef := processRefForReflog(info.ref, curBranch) line = append(line, fmt.Sprintf("\033[33m(%s\033[33m)\033[0m", processedRef)) // () in yellow (33m) - line = append(line, fmt.Sprintf("HEAD@{%d}: %s\n", pos, info.commitMessage)) + line = append(line, fmt.Sprintf("%s\n", info.commitMessage)) pager.Writer.Write([]byte(strings.Join(line, " "))) } }) @@ -190,7 +181,7 @@ func reflogToStdOut(reflogInfo []ReflogInfo, curBranch string) { func processRefForReflog(fullRef string, curBranch string) string { if strings.HasPrefix(fullRef, "refs/heads/") { branch := strings.TrimPrefix(fullRef, "refs/heads/") - if branch == curBranch { + if curBranch != "" && branch == curBranch { return fmt.Sprintf("\033[36;1mHEAD -> \033[32;1m%s\033[0m", branch) // HEAD in cyan (36;1), branch in green (32;1m) } return fmt.Sprintf("\033[32;1m%s\033[0m", branch) // branch in green (32;1m) diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_queries.go b/go/libraries/doltcore/sqle/enginetest/dolt_queries.go index 206c9318eda..57e1d2ca708 100644 --- a/go/libraries/doltcore/sqle/enginetest/dolt_queries.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_queries.go @@ -4317,15 +4317,15 @@ var DoltReflogTestScripts = []queries.ScriptTest{ Assertions: []queries.ScriptTestAssertion{ { Query: "select * from dolt_reflog('foo', 'bar');", - ExpectedErrStr: "error: reflog has too many positional arguments. Expected at most 1, found 2: foo, bar", + ExpectedErrStr: "error: dolt_reflog has too many positional arguments. Expected at most 1, found 2: ['foo' 'bar']", }, { Query: "select * from dolt_reflog(NULL);", - ExpectedErrStr: "Invalid argument to dolt_reflog: NULL", + ExpectedErrStr: "argument () is not a string value, but a ", }, { Query: "select * from dolt_reflog(-100);", - ExpectedErrStr: "Invalid argument to dolt_reflog: -100", + ExpectedErrStr: "argument (-100) is not a string value, but a int8", }, }, }, diff --git a/go/libraries/doltcore/sqle/reflog_table_function.go b/go/libraries/doltcore/sqle/reflog_table_function.go index a8eb79ed8ef..f0124a84bf4 100644 --- a/go/libraries/doltcore/sqle/reflog_table_function.go +++ b/go/libraries/doltcore/sqle/reflog_table_function.go @@ -23,7 +23,6 @@ import ( "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/go-mysql-server/sql/types" - "github.com/dolthub/dolt/go/cmd/dolt/cli" "github.com/dolthub/dolt/go/libraries/doltcore/ref" "github.com/dolthub/dolt/go/libraries/doltcore/sqle/dsess" "github.com/dolthub/dolt/go/store/hash" @@ -32,7 +31,7 @@ import ( type ReflogTableFunction struct { ctx *sql.Context database sql.Database - refName string + refExpr sql.Expression showAll bool } @@ -66,6 +65,20 @@ func (rltf *ReflogTableFunction) RowIter(ctx *sql.Context, row sql.Row) (sql.Row return nil, fmt.Errorf("unexpected database type: %T", rltf.database) } + var refName string + if rltf.refExpr != nil { + target, err := rltf.refExpr.Eval(ctx, row) + if err != nil { + return nil, fmt.Errorf("error evaluating expression (%s): %s", + rltf.refExpr.String(), err.Error()) + } + + refName, ok = target.(string) + if !ok { + return nil, fmt.Errorf("argument (%v) is not a string value, but a %T", target, target) + } + } + ddb := sqlDb.DbData().Ddb journal := ddb.ChunkJournal() if journal == nil { @@ -105,15 +118,15 @@ func (rltf *ReflogTableFunction) RowIter(ctx *sql.Context, row sql.Row) (sql.Row } // If a ref expression to filter on was specified, see if we match the current ref - if rltf.refName != "" { + if refName != "" { // If the caller has supplied a branch or tag name, without the fully qualified ref path, // take the first match and use that as the canonical ref to filter on - if strings.HasSuffix(strings.ToLower(id), "/"+strings.ToLower(rltf.refName)) { - rltf.refName = id + if strings.HasSuffix(strings.ToLower(id), "/"+strings.ToLower(refName)) { + refName = id } // Skip refs that don't match the target we're looking for - if strings.ToLower(id) != strings.ToLower(rltf.refName) { + if strings.ToLower(id) != strings.ToLower(refName) { return nil } } @@ -166,11 +179,21 @@ func (rltf *ReflogTableFunction) Schema() sql.Schema { } func (rltf *ReflogTableFunction) Resolved() bool { + if rltf.refExpr != nil { + return rltf.refExpr.Resolved() + } return true } func (rltf *ReflogTableFunction) String() string { - return fmt.Sprintf("DOLT_REFLOG(%s)", rltf.refName) + var args []string + if rltf.showAll { + args = append(args, "'--all'") + } + if rltf.refExpr != nil { + args = append(args, rltf.refExpr.String()) + } + return fmt.Sprintf("DOLT_REFLOG(%s)", strings.Join(args, ", ")) } func (rltf *ReflogTableFunction) Children() []sql.Node { @@ -195,6 +218,9 @@ func (rltf *ReflogTableFunction) IsReadOnly() bool { } func (rltf *ReflogTableFunction) Expressions() []sql.Expression { + if rltf.refExpr != nil { + return []sql.Expression{rltf.refExpr} + } return []sql.Expression{} } @@ -204,20 +230,23 @@ func (rltf *ReflogTableFunction) WithExpressions(expression ...sql.Expression) ( } new := *rltf - args, err := getDoltArgs(rltf.ctx, expression, rltf.Name()) - if err != nil { - return nil, err - } - apr, err := cli.CreateReflogArgParser().Parse(args) - if err != nil { - return nil, err - } - if apr.NArg() > 0 { - new.refName = apr.Arg(0) + + if len(expression) == 2 { + if expression[0].String() == "'--all'" && expression[1].String() == "'--all'" { + return nil, fmt.Errorf("error: multiple values provided for `all`") + } + if expression[0].String() != "'--all'" && expression[1].String() != "'--all'" { + return nil, fmt.Errorf("error: %s has too many positional arguments. Expected at most %d, found %d: %s", rltf.Name(), 1, 2, expression) + } } - if apr.Contains(cli.AllFlag) { - new.showAll = true + for _, expr := range expression { + if expr.String() != "'--all'" { + new.refExpr = expr + } else { + new.showAll = true + } } + return &new, nil } diff --git a/integration-tests/bats/helper/local-remote.bash b/integration-tests/bats/helper/local-remote.bash index e799355407a..5b2ad0e6645 100644 --- a/integration-tests/bats/helper/local-remote.bash +++ b/integration-tests/bats/helper/local-remote.bash @@ -136,7 +136,6 @@ SKIP_SERVER_TESTS=$(cat <<-EOM ~profile.bats~ ~ls.bats~ ~reflog.bats~ -~sql-reflog.bats~ EOM ) diff --git a/integration-tests/bats/reflog.bats b/integration-tests/bats/reflog.bats index bad3273d50c..93d54fda02e 100755 --- a/integration-tests/bats/reflog.bats +++ b/integration-tests/bats/reflog.bats @@ -1,10 +1,6 @@ #!/usr/bin/env bats load $BATS_TEST_DIRNAME/helper/common.bash -setup() { - setup_common -} - teardown() { assert_feature_version teardown_common @@ -13,6 +9,8 @@ teardown() { # Asserts that when DOLT_DISABLE_REFLOG is set, dolt reflog returns nothing with no error. @test "reflog: disabled with DOLT_DISABLE_REFLOG" { export DOLT_DISABLE_REFLOG=true + setup_common # need to set env vars before setup_common for remote tests + dolt sql -q "create table t (i int primary key, j int);" dolt sql -q "insert into t values (1, 1), (2, 2), (3, 3)"; dolt commit -Am "initial commit" @@ -27,6 +25,8 @@ teardown() { # most recent entries and is limited by the env var's value. @test "reflog: set DOLT_REFLOG_RECORD_LIMIT" { export DOLT_REFLOG_RECORD_LIMIT=2 + setup_common # need to set env vars before setup_common for remote tests + dolt sql -q "create table t (i int primary key, j int);" dolt sql -q "insert into t values (1, 1), (2, 2), (3, 3)"; dolt commit -Am "initial commit" @@ -43,6 +43,8 @@ teardown() { } @test "reflog: simple reflog" { + setup_common + dolt sql -q "create table t (i int primary key, j int);" dolt sql -q "insert into t values (1, 1), (2, 2), (3, 3)"; dolt commit -Am "initial commit" @@ -51,11 +53,13 @@ teardown() { [ "$status" -eq 0 ] [ "${#lines[@]}" -eq 2 ] out=$(echo "$output" | sed -E 's/\x1b\[[0-9;]*m//g') # remove special characters for color - [[ "$out" =~ "(HEAD -> main) HEAD@{0}: initial commit" ]] || false - [[ "$out" =~ "HEAD@{1}: Initialize data repository" ]] || false + [[ "$out" =~ "(HEAD -> main) initial commit" ]] || false + [[ "$out" =~ "Initialize data repository" ]] || false } @test "reflog: reflog with ref given" { + setup_common + dolt sql < main) HEAD@{0}: inserting row 1" ]] || false - [[ "$out" =~ "HEAD@{1}: creating table t1" ]] || false - [[ "$out" =~ "HEAD@{2}: Initialize data repository" ]] || false + [[ "$out" =~ "(HEAD -> main) inserting row 1" ]] || false + [[ "$out" =~ "creating table t1" ]] || false + [[ "$out" =~ "Initialize data repository" ]] || false # ref is case-insensitive run dolt reflog rEFs/heAdS/MAIN [ "$status" -eq 0 ] [ "${#lines[@]}" -eq 3 ] out=$(echo "$output" | sed -E 's/\x1b\[[0-9;]*m//g') # remove special characters for color - [[ "$out" =~ "(HEAD -> main) HEAD@{0}: inserting row 1" ]] || false - [[ "$out" =~ "HEAD@{1}: creating table t1" ]] || false - [[ "$out" =~ "HEAD@{2}: Initialize data repository" ]] || false + [[ "$out" =~ "(HEAD -> main) inserting row 1" ]] || false + [[ "$out" =~ "creating table t1" ]] || false + [[ "$out" =~ "Initialize data repository" ]] || false run dolt reflog main [ "$status" -eq 0 ] [ "${#lines[@]}" -eq 3 ] out=$(echo "$output" | sed -E 's/\x1b\[[0-9;]*m//g') # remove special characters for color - [[ "$out" =~ "(HEAD -> main) HEAD@{0}: inserting row 1" ]] || false - [[ "$out" =~ "HEAD@{1}: creating table t1" ]] || false - [[ "$out" =~ "HEAD@{2}: Initialize data repository" ]] || false + [[ "$out" =~ "(HEAD -> main) inserting row 1" ]] || false + [[ "$out" =~ "creating table t1" ]] || false + [[ "$out" =~ "Initialize data repository" ]] || false # ref is case-insensitive run dolt reflog MaIn [ "$status" -eq 0 ] [ "${#lines[@]}" -eq 3 ] out=$(echo "$output" | sed -E 's/\x1b\[[0-9;]*m//g') # remove special characters for color - [[ "$out" =~ "(HEAD -> main) HEAD@{0}: inserting row 1" ]] || false - [[ "$out" =~ "HEAD@{1}: creating table t1" ]] || false - [[ "$out" =~ "HEAD@{2}: Initialize data repository" ]] || false + [[ "$out" =~ "(HEAD -> main) inserting row 1" ]] || false + [[ "$out" =~ "creating table t1" ]] || false + [[ "$out" =~ "Initialize data repository" ]] || false run dolt reflog refs/heads/branch1 [ "$status" -eq 0 ] [ "${#lines[@]}" -eq 3 ] out=$(echo "$output" | sed -E 's/\x1b\[[0-9;]*m//g') # remove special characters for color - [[ "$out" =~ "(branch1) HEAD@{0}: inserting row 3" ]] || false - [[ "$out" =~ "HEAD@{1}: inserting row 2" ]] || false - [[ "$out" =~ "HEAD@{2}: inserting row 1" ]] || false + [[ "$out" =~ "(branch1) inserting row 3" ]] || false + [[ "$out" =~ "inserting row 2" ]] || false + [[ "$out" =~ "inserting row 1" ]] || false run dolt reflog branch1 [ "$status" -eq 0 ] [ "${#lines[@]}" -eq 3 ] out=$(echo "$output" | sed -E 's/\x1b\[[0-9;]*m//g') # remove special characters for color - [[ "$out" =~ "(branch1) HEAD@{0}: inserting row 3" ]] || false - [[ "$out" =~ "HEAD@{1}: inserting row 2" ]] || false - [[ "$out" =~ "HEAD@{2}: inserting row 1" ]] || false + [[ "$out" =~ "(branch1) inserting row 3" ]] || false + [[ "$out" =~ "inserting row 2" ]] || false + [[ "$out" =~ "inserting row 1" ]] || false run dolt reflog refs/tags/tag1 [ "$status" -eq 0 ] [ "${#lines[@]}" -eq 2 ] out=$(echo "$output" | sed -E 's/\x1b\[[0-9;]*m//g') # remove special characters for color - [[ "$out" =~ "(tag: tag1) HEAD@{0}: inserting row 3" ]] || false - [[ "$out" =~ "HEAD@{1}: inserting row 1" ]] || false + [[ "$out" =~ "(tag: tag1) inserting row 3" ]] || false + [[ "$out" =~ "inserting row 1" ]] || false # ref is case-insensitive run dolt reflog Refs/tAGs/TaG1 [ "$status" -eq 0 ] [ "${#lines[@]}" -eq 2 ] out=$(echo "$output" | sed -E 's/\x1b\[[0-9;]*m//g') # remove special characters for color - [[ "$out" =~ "(tag: tag1) HEAD@{0}: inserting row 3" ]] || false - [[ "$out" =~ "HEAD@{1}: inserting row 1" ]] || false + [[ "$out" =~ "(tag: tag1) inserting row 3" ]] || false + [[ "$out" =~ "inserting row 1" ]] || false run dolt reflog tag1 [ "$status" -eq 0 ] [ "${#lines[@]}" -eq 2 ] out=$(echo "$output" | sed -E 's/\x1b\[[0-9;]*m//g') # remove special characters for color - [[ "$out" =~ "(tag: tag1) HEAD@{0}: inserting row 3" ]] || false - [[ "$out" =~ "HEAD@{1}: inserting row 1" ]] || false + [[ "$out" =~ "(tag: tag1) inserting row 3" ]] || false + [[ "$out" =~ "inserting row 1" ]] || false # ref is case-insensitive run dolt reflog TAg1 [ "$status" -eq 0 ] [ "${#lines[@]}" -eq 2 ] out=$(echo "$output" | sed -E 's/\x1b\[[0-9;]*m//g') # remove special characters for color - [[ "$out" =~ "(tag: tag1) HEAD@{0}: inserting row 3" ]] || false - [[ "$out" =~ "HEAD@{1}: inserting row 1" ]] || false + [[ "$out" =~ "(tag: tag1) inserting row 3" ]] || false + [[ "$out" =~ "inserting row 1" ]] || false dolt branch -D branch1 @@ -160,25 +164,27 @@ SQL [ "$status" -eq 0 ] [ "${#lines[@]}" -eq 3 ] out=$(echo "$output" | sed -E 's/\x1b\[[0-9;]*m//g') # remove special characters for color - [[ "$out" =~ "(branch1) HEAD@{0}: inserting row 3" ]] || false - [[ "$out" =~ "HEAD@{1}: inserting row 2" ]] || false - [[ "$out" =~ "HEAD@{2}: inserting row 1" ]] || false + [[ "$out" =~ "(branch1) inserting row 3" ]] || false + [[ "$out" =~ "inserting row 2" ]] || false + [[ "$out" =~ "inserting row 1" ]] || false dolt tag -d tag1 run dolt reflog tag1 [ "$status" -eq 0 ] [ "${#lines[@]}" -eq 2 ] out=$(echo "$output" | sed -E 's/\x1b\[[0-9;]*m//g') # remove special characters for color - [[ "$out" =~ "(tag: tag1) HEAD@{0}: inserting row 3" ]] || false - [[ "$out" =~ "HEAD@{1}: inserting row 1" ]] || false + [[ "$out" =~ "(tag: tag1) inserting row 3" ]] || false + [[ "$out" =~ "inserting row 1" ]] || false } @test "reflog: garbage collection with no newgen data" { + setup_common + run dolt reflog [ "$status" -eq 0 ] [ "${#lines[@]}" -eq 1 ] out=$(echo "$output" | sed -E 's/\x1b\[[0-9;]*m//g') # remove special characters for color - [[ "$out" =~ "(HEAD -> main) HEAD@{0}: Initialize data repository" ]] || false + [[ "$out" =~ "(HEAD -> main) Initialize data repository" ]] || false dolt gc @@ -188,6 +194,8 @@ SQL } @test "reflog: garbage collection with newgen data" { + setup_common + dolt sql < main) HEAD@{0}: inserting row 2" ]] || false - [[ "$out" =~ "HEAD@{1}: inserting row 1" ]] || false - [[ "$out" =~ "HEAD@{2}: creating table t1" ]] || false - [[ "$out" =~ "HEAD@{3}: Initialize data repository" ]] || false + [[ "$out" =~ "(HEAD -> main) inserting row 2" ]] || false + [[ "$out" =~ "inserting row 1" ]] || false + [[ "$out" =~ "creating table t1" ]] || false + [[ "$out" =~ "Initialize data repository" ]] || false dolt gc @@ -215,12 +223,16 @@ SQL } @test "reflog: too many arguments given" { + setup_common + run dolt reflog foo bar [ "$status" -eq 1 ] [[ "$output" =~ "error: reflog has too many positional arguments" ]] || false } @test "reflog: unknown ref returns nothing" { + setup_common + dolt sql -q "create table t (i int primary key, j int);" dolt sql -q "insert into t values (1, 1), (2, 2), (3, 3)"; dolt commit -Am "initial commit" diff --git a/integration-tests/bats/sql-local-remote.bats b/integration-tests/bats/sql-local-remote.bats index 95366a02391..41901246688 100644 --- a/integration-tests/bats/sql-local-remote.bats +++ b/integration-tests/bats/sql-local-remote.bats @@ -1270,3 +1270,27 @@ SQL [[ "$localOutput" == "$remoteOutput" ]] || false } + +@test "sql-local-remote: verify dolt reflog behavior" { + cd altDB + dolt sql -q "create table t (i int primary key, j int);" + dolt sql -q "insert into t values (1, 1), (2, 2), (3, 3)"; + dolt commit -Am "initial commit" + + run dolt --verbose-engine-setup reflog + [ $status -eq 0 ] + [[ "$output" =~ "starting local mode" ]] || false + [[ "$output" =~ "initial commit" ]] || false + run dolt reflog + localOutput=$output + + start_sql_server altDB + run dolt --verbose-engine-setup reflog + [ $status -eq 0 ] + [[ "$output" =~ "starting remote mode" ]] || false + [[ "$output" =~ "initial commit" ]] || false + run dolt reflog + remoteOutput=$output + + [[ "$localOutput" == "$remoteOutput" ]] || false +} diff --git a/integration-tests/bats/sql-reflog.bats b/integration-tests/bats/sql-reflog.bats index bac628f0161..6e52d0a3e16 100644 --- a/integration-tests/bats/sql-reflog.bats +++ b/integration-tests/bats/sql-reflog.bats @@ -1,10 +1,6 @@ #!/usr/bin/env bats load $BATS_TEST_DIRNAME/helper/common.bash -setup() { - setup_common -} - teardown() { assert_feature_version teardown_common @@ -14,6 +10,8 @@ teardown() { # function returns an empty result set with no error. @test "sql-reflog: disabled with DOLT_DISABLE_REFLOG" { export DOLT_DISABLE_REFLOG=true + setup_common # need to set env vars before setup_common for remote tests + dolt sql -q "create table t (i int primary key, j int);" dolt sql -q "insert into t values (1, 1), (2, 2), (3, 3)"; dolt commit -Am "initial commit" @@ -26,6 +24,8 @@ teardown() { # Sanity check for the most basic case of querying the Dolt reflog @test "sql-reflog: enabled by default" { + setup_common + dolt sql -q "create table t (i int primary key, j int);" dolt sql -q "insert into t values (1, 1), (2, 2), (3, 3)"; dolt commit -Am "initial commit" @@ -41,6 +41,8 @@ teardown() { # most recent entries and is limited by the env var's value. @test "sql-reflog: set DOLT_REFLOG_RECORD_LIMIT" { export DOLT_REFLOG_RECORD_LIMIT=2 + setup_common # need to set env vars before setup_common for remote tests + dolt sql -q "create table t (i int primary key, j int);" dolt sql -q "insert into t values (1, 1), (2, 2), (3, 3)"; dolt commit -Am "initial commit"