Dolt CI Becomes More CLI Friendly
Dolt is Git for data. And DoltHub is GitHub for Dolt. At the end of last year we announced our new DoltHub actions, analogous to GitHub actions. The first set of actions we implemented was Continuous Integration called Dolt CI. Who doesn't love tests on their database?
Our initial version had a couple pain points, however. There was no local system to run tests, so you needed to push to DoltHub to run CI. You could also only view the steps after exporting to yaml files, cluttering your directory. The command line needed some love, so we've added some additional functionality. Let's explore how it works.
New Features for CI
First, let's check that we have the right version of Dolt installed. That should be, for this post, v1.57.4
.
% dolt version
dolt version 1.57.4
Then we'll clone the same dolthub/options
database we've used in several blogs now.
% dolt clone dolthub/options
cloning https://doltremoteapi.dolthub.com/dolthub/options
3,893,224 of 3,893,224 chunks complete.
% cd options
% dolt status
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean
Finally, we can use dolt ci ls
to see the workflows we've defined for this database:
% dolt ci ls
my first DoltHub workflow
my second DoltHub workflow
Okay, we can see our two workflows. How do we use them?
Viewing Workflows
You can now see the steps and jobs for a workflow without exporting to a yaml file. We can do this with the new view
command:
% dolt ci view "my first DoltHub workflow"
name: "my first DoltHub workflow"
"on":
push:
branches:
- "master"
jobs:
- name: "validate tables"
steps:
- name: "assert expected tables exist"
saved_query_name: "show tables"
saved_query_statement: "SHOW TABLES;"
expected_rows: "== 2"
- name: "assert table option_chain exists"
saved_query_name: "option_chain exists"
saved_query_statement: "select * from option_chain limit 1;"
- name: "assert table volatility_history"
saved_query_name: "volatility_history exists"
saved_query_statement: "select * from volatility_history limit 1;"
- name: "check data"
steps:
- name: "assert option_chain table has data"
saved_query_name: "check option_chain data"
saved_query_statement: "select * from option_chain limit 1;"
expected_rows: "> 0"
- name: "assert volatility_history table has data"
saved_query_name: "check volatility_history data"
saved_query_statement: "select * from volatility_history limit 1;"
expected_rows: "> 0"
- name: "validate schema"
steps:
- name: "assert 13 option_chain columns exist"
saved_query_name: "check option_chain column length"
saved_query_statement: "select * from option_chain limit 1;"
expected_columns: "<= 13"
- name: "assert call_put column exist"
saved_query_name: "check option_chain.call_put exists"
saved_query_statement: "select call_put from option_chain limit 1;"
expected_columns: "== 1"
- name: "assert 16 volatility_history columns exist"
saved_query_name: "check volatility_history column length"
saved_query_statement: "select * from volatility_history limit 1;"
expected_columns: ">= 16"
- name: "assert act_symbol column exist"
saved_query_name: "check volatility_history.act_symbol exists"
saved_query_statement: "select act_symbol from volatility_history limit 1;"
expected_columns: "== 1"
That's a lot though. If we just want to see what a certain job does, we can use the --job
option:
% dolt ci view "my first DoltHub workflow" --job "validate tables"
name: "validate tables"
steps:
- name: "assert expected tables exist"
saved_query_name: "show tables"
saved_query_statement: "SHOW TABLES;"
expected_rows: "== 2"
- name: "assert table option_chain exists"
saved_query_name: "option_chain exists"
saved_query_statement: "select * from option_chain limit 1;"
- name: "assert table volatility_history"
saved_query_name: "volatility_history exists"
saved_query_statement: "select * from volatility_history limit 1;"
Now that we know what our workflows do, we might want to run the queries against our branch, so lets do that.
Running Workflows
You can also now run workflows locally, so pushing to DoltHub is no longer necessary to test your changes. Let's use the second workflow now:
% dolt ci view "my second DoltHub workflow"
name: "my second DoltHub workflow"
"on":
pull_request:
branches:
- "master"
activities: []
jobs:
- name: "check volatility_history data"
steps:
- name: "assert volatility_history has only increased"
saved_query_name: "check volatility_history data has only increased"
saved_query_statement: "select 1 where (select count(*) from volatility_history) >= (select count(*) from volatility_history as of hashof('master'));"
expected_rows: "== 1"
- name: "check options_chain data"
steps:
- name: "assert option_chain table has not changed"
saved_query_name: "check no changes to option_chain"
saved_query_statement: "select * from dolt_diff('master', 'HEAD', 'option_chain');"
expected_rows: "== 0"
Now let's run the jobs:
% dolt ci run "my second DoltHub workflow"
Running workflow: my second DoltHub workflow
Running job: check volatility_history data
Step: assert volatility_history has only increased - PASS
Running job: check options_chain data
Step: assert option_chain table has not changed - PASS
Perfect! Everything passed as expected. We can also see what happens if the database has been modified poorly:
% dolt checkout -b newFeatureBranch
Switched to branch 'newFeatureBranch'
% dolt sql -q "insert into option_chain (date, act_symbol, expiration, strike, call_put) values ('2025-01-01', 'TEST', '2025-01-02', 1.0, 'Call')"
% dolt sql -q "drop table volatility_history"
% dolt commit -am "Bad changes to db"
Author: Nathan <nathan@dolthub.com>
Date: Thu Jul 31 14:59:46 -0700 2025
Bad changes to db
Now if we run our workflow, we should see some errors.
% dolt ci run "my second DoltHub workflow"
Running workflow: my second DoltHub workflow
Running job: check volatility_history data
Step: assert volatility_history has only increased - FAIL
Ran query: select 1 where (select count(*) from volatility_history) >= (select count(*) from volatility_history as of hashof('master'));
Query error: table not found: volatility_history
Running job: check options_chain data
Step: assert option_chain table has not changed - FAIL
Ran query: select * from dolt_diff('master', 'HEAD', 'option_chain');
Assertion failed: expected row count 0, got 1
Okay, we can see that both the tests failed. Why? The first failed while running the query since it couldn't find the table volatility_history
after we dropped it.
The second step failed on assertion. We added a row to option_chain, which we weren't supposed to do.
What's Next
Dolt's CI has a lot more to come, so stay tuned in the coming weeks. We hope to soon add stored procedures to enable CI functionality within Dolt's database server and expand its support within Dolt Workbench.
Do you have features you want to see for CI? Come tell us on discord. We'd love to chat.