mirror of
https://github.com/hanzoai/migrate.git
synced 2026-09-30 22:55:10 +00:00
Merge branch 'master' into scylladb_support
This commit is contained in:
+13
-13
@@ -9,10 +9,10 @@ jobs:
|
||||
name: lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/setup-go@v3
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: "1.20.x"
|
||||
- uses: actions/checkout@v3
|
||||
go-version: "1.21.x"
|
||||
- uses: actions/checkout@v4
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
with:
|
||||
@@ -22,11 +22,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go: ["1.19.x", "1.20.x"]
|
||||
go: ["1.20.x", "1.21.x"]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-go@v3
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
|
||||
@@ -60,19 +60,19 @@ jobs:
|
||||
# 3. When the workflow is triggered by a tag with `v` prefix
|
||||
if: ${{ success() && github.repository == 'golang-migrate/migrate' && startsWith(github.ref, 'refs/tags/v') }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 2.7
|
||||
- uses: actions/setup-go@v3
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: "1.19.x"
|
||||
go-version: "1.21.x"
|
||||
|
||||
- uses: docker/setup-qemu-action@v1
|
||||
- uses: docker/setup-buildx-action@v1
|
||||
- uses: docker/login-action@v1
|
||||
- uses: docker/setup-qemu-action@v3
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
username: golangmigrate
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
@@ -80,7 +80,7 @@ jobs:
|
||||
- run: echo "SOURCE=$(make echo-source)" >> $GITHUB_ENV
|
||||
- run: echo "DATABASE=$(make echo-database)" >> $GITHUB_ENV
|
||||
|
||||
- uses: goreleaser/goreleaser-action@v2
|
||||
- uses: goreleaser/goreleaser-action@v5
|
||||
with:
|
||||
version: latest
|
||||
args: release --rm-dist
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.20-alpine3.18 AS builder
|
||||
FROM golang:1.21-alpine3.19 AS builder
|
||||
ARG VERSION
|
||||
|
||||
RUN apk add --no-cache git gcc musl-dev make
|
||||
@@ -15,7 +15,7 @@ COPY . ./
|
||||
|
||||
RUN make build-docker
|
||||
|
||||
FROM alpine:3.18
|
||||
FROM alpine:3.19
|
||||
|
||||
RUN apk add --no-cache ca-certificates
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM alpine:3.18
|
||||
FROM alpine:3.19
|
||||
|
||||
RUN apk add --no-cache ca-certificates
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
and whenever we want, not just once at the beginning of all tests.
|
||||
|
||||
#### Can I maintain my driver in my own repository?
|
||||
Yes, technically thats possible. We want to encourage you to contribute your driver to this respository though.
|
||||
Yes, technically thats possible. We want to encourage you to contribute your driver to this repository though.
|
||||
The driver's functionality is dictated by migrate's interfaces. That means there should really
|
||||
just be one driver for a database/ source. We want to prevent a future where several drivers doing the exact same thing,
|
||||
just implemented a bit differently, co-exist somewhere on GitHub. If users have to do research first to find the
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ migrate -database YOUR_DATABASE_URL -path PATH_TO_YOUR_MIGRATIONS up
|
||||
|
||||
Just add the code to your app and you're ready to go!
|
||||
|
||||
Before commiting your migrations you should run your migrations up, down, and then up again to see if migrations are working properly both ways.
|
||||
Before committing your migrations you should run your migrations up, down, and then up again to see if migrations are working properly both ways.
|
||||
(e.g. if you created a table in a migration but reverse migration did not delete it, you will encounter an error when running the forward migration again)
|
||||
It's also worth checking your migrations in a separate, containerized environment. You can find some tools at the [end of this document](#further-reading).
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
SOURCE ?= file go_bindata github github_ee bitbucket aws_s3 google_cloud_storage godoc_vfs gitlab
|
||||
DATABASE ?= postgres mysql redshift cassandra spanner cockroachdb yugabytedb clickhouse mongodb sqlserver firebird neo4j pgx pgx5
|
||||
DATABASE ?= postgres mysql redshift cassandra spanner cockroachdb yugabytedb clickhouse mongodb sqlserver firebird neo4j pgx pgx5 rqlite
|
||||
DATABASE_TEST ?= $(DATABASE) sqlite sqlite3 sqlcipher
|
||||
VERSION ?= $(shell git describe --tags 2>/dev/null | cut -c 2-)
|
||||
TEST_FLAGS ?=
|
||||
|
||||
@@ -44,6 +44,7 @@ Database drivers run migrations. [Add a new database?](database/driver.go)
|
||||
* [ClickHouse](database/clickhouse)
|
||||
* [Firebird](database/firebird)
|
||||
* [MS SQL Server](database/sqlserver)
|
||||
* [RQLite](database/rqlite)
|
||||
|
||||
### Database URLs
|
||||
|
||||
|
||||
@@ -8,13 +8,15 @@ import (
|
||||
)
|
||||
|
||||
const reservedChars = "!#$%&'()*+,/:;=?@[]"
|
||||
const reservedCharTestNamePrefix = "reserved char "
|
||||
|
||||
const baseUsername = "username"
|
||||
|
||||
const scheme = "database://"
|
||||
|
||||
// TestUserUnencodedReservedURLChars documents the behavior of using unencoded reserved characters in usernames with
|
||||
// net/url Parse()
|
||||
func TestUserUnencodedReservedURLChars(t *testing.T) {
|
||||
scheme := "database://"
|
||||
urlSuffix := "password@localhost:12345/myDB?someParam=true"
|
||||
urlSuffixAndSep := ":" + urlSuffix
|
||||
|
||||
@@ -64,7 +66,7 @@ func TestUserUnencodedReservedURLChars(t *testing.T) {
|
||||
testedChars := make([]string, 0, len(reservedChars))
|
||||
for _, tc := range testcases {
|
||||
testedChars = append(testedChars, tc.char)
|
||||
t.Run("reserved char "+tc.char, func(t *testing.T) {
|
||||
t.Run(reservedCharTestNamePrefix+tc.char, func(t *testing.T) {
|
||||
s := scheme + baseUsername + tc.char + urlSuffixAndSep
|
||||
u, err := url.Parse(s)
|
||||
if err == nil {
|
||||
@@ -98,13 +100,12 @@ func TestUserUnencodedReservedURLChars(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUserEncodedReservedURLChars(t *testing.T) {
|
||||
scheme := "database://"
|
||||
urlSuffix := "password@localhost:12345/myDB?someParam=true"
|
||||
urlSuffixAndSep := ":" + urlSuffix
|
||||
|
||||
for _, c := range reservedChars {
|
||||
c := string(c)
|
||||
t.Run("reserved char "+c, func(t *testing.T) {
|
||||
t.Run(reservedCharTestNamePrefix+c, func(t *testing.T) {
|
||||
encodedChar := "%" + hex.EncodeToString([]byte(c))
|
||||
s := scheme + baseUsername + encodedChar + urlSuffixAndSep
|
||||
expectedUsername := baseUsername + c
|
||||
@@ -126,7 +127,7 @@ func TestUserEncodedReservedURLChars(t *testing.T) {
|
||||
// with net/url Parse()
|
||||
func TestPasswordUnencodedReservedURLChars(t *testing.T) {
|
||||
username := baseUsername
|
||||
schemeAndUsernameAndSep := "database://" + username + ":"
|
||||
schemeAndUsernameAndSep := scheme + username + ":"
|
||||
basePassword := "password"
|
||||
urlSuffixAndSep := "@localhost:12345/myDB?someParam=true"
|
||||
|
||||
@@ -174,7 +175,7 @@ func TestPasswordUnencodedReservedURLChars(t *testing.T) {
|
||||
testedChars := make([]string, 0, len(reservedChars))
|
||||
for _, tc := range testcases {
|
||||
testedChars = append(testedChars, tc.char)
|
||||
t.Run("reserved char "+tc.char, func(t *testing.T) {
|
||||
t.Run(reservedCharTestNamePrefix+tc.char, func(t *testing.T) {
|
||||
s := schemeAndUsernameAndSep + basePassword + tc.char + urlSuffixAndSep
|
||||
u, err := url.Parse(s)
|
||||
if err == nil {
|
||||
@@ -213,13 +214,13 @@ func TestPasswordUnencodedReservedURLChars(t *testing.T) {
|
||||
|
||||
func TestPasswordEncodedReservedURLChars(t *testing.T) {
|
||||
username := baseUsername
|
||||
schemeAndUsernameAndSep := "database://" + username + ":"
|
||||
schemeAndUsernameAndSep := scheme + username + ":"
|
||||
basePassword := "password"
|
||||
urlSuffixAndSep := "@localhost:12345/myDB?someParam=true"
|
||||
|
||||
for _, c := range reservedChars {
|
||||
c := string(c)
|
||||
t.Run("reserved char "+c, func(t *testing.T) {
|
||||
t.Run(reservedCharTestNamePrefix+c, func(t *testing.T) {
|
||||
encodedChar := "%" + hex.EncodeToString([]byte(c))
|
||||
s := schemeAndUsernameAndSep + basePassword + encodedChar + urlSuffixAndSep
|
||||
expectedPassword := basePassword + c
|
||||
|
||||
@@ -27,7 +27,7 @@ If there were no errors, we should have two files available under `db/migrations
|
||||
Note the `sql` extension that we provided.
|
||||
|
||||
In the `.up.sql` file let's create the table:
|
||||
```
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS users(
|
||||
user_id serial PRIMARY KEY,
|
||||
username VARCHAR (50) UNIQUE NOT NULL,
|
||||
@@ -36,7 +36,7 @@ CREATE TABLE IF NOT EXISTS users(
|
||||
);
|
||||
```
|
||||
And in the `.down.sql` let's delete it:
|
||||
```
|
||||
```sql
|
||||
DROP TABLE IF EXISTS users;
|
||||
```
|
||||
By adding `IF EXISTS/IF NOT EXISTS` we are making migrations idempotent - you can read more about idempotency in [getting started](../../GETTING_STARTED.md#create-migrations)
|
||||
@@ -79,7 +79,7 @@ Again, it should create for us two migrations files:
|
||||
In Postgres, when we want our queries to be done in a transaction, we need to wrap it with `BEGIN` and `COMMIT` commands.
|
||||
In our example, we are going to add a column to our database that can only accept enumerable values or NULL.
|
||||
Migration up:
|
||||
```
|
||||
```sql
|
||||
BEGIN;
|
||||
|
||||
CREATE TYPE enum_mood AS ENUM (
|
||||
@@ -92,7 +92,7 @@ ALTER TABLE users ADD COLUMN mood enum_mood;
|
||||
COMMIT;
|
||||
```
|
||||
Migration down:
|
||||
```
|
||||
```sql
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE users DROP COLUMN mood;
|
||||
@@ -124,7 +124,7 @@ Indexes:
|
||||
|
||||
## Optional: Run migrations within your Go app
|
||||
Here is a very simple app running migrations for the above configuration:
|
||||
```
|
||||
```go
|
||||
import (
|
||||
"log"
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# rqlite
|
||||
|
||||
`rqlite://admin:[email protected]:4001/?level=strong&timeout=5`
|
||||
|
||||
The `rqlite` url scheme is used for both secure and insecure connections. If connecting to an insecure database, pass `x-connect-insecure` in your URL query, or use `WithInstance` to pass an established connection.
|
||||
|
||||
The migrations table name is configurable through the `x-migrations-table` URL query parameter, or by using `WithInstance` and passing `MigrationsTable` through `Config`.
|
||||
|
||||
Other connect parameters are directly passed through to the database driver. For examples of connection strings, see https://github.com/rqlite/gorqlite#examples.
|
||||
|
||||
| URL Query | WithInstance Config | Description |
|
||||
|------------|---------------------|-------------|
|
||||
| `x-connect-insecure` | n/a: set on instance | Boolean to indicate whether to use an insecure connection. Defaults to `false`. |
|
||||
| `x-migrations-table` | `MigrationsTable` | Name of the migrations table. Defaults to `schema_migrations`. |
|
||||
|
||||
## Notes
|
||||
|
||||
* Uses the https://github.com/rqlite/gorqlite driver
|
||||
@@ -0,0 +1 @@
|
||||
DROP TABLE IF EXISTS pets;
|
||||
@@ -0,0 +1,3 @@
|
||||
CREATE TABLE pets (
|
||||
name string
|
||||
);
|
||||
@@ -0,0 +1 @@
|
||||
DROP TABLE IF EXISTS pets;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE pets ADD predator bool;
|
||||
@@ -0,0 +1,334 @@
|
||||
package rqlite
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
nurl "net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"go.uber.org/atomic"
|
||||
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
"github.com/golang-migrate/migrate/v4/database"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rqlite/gorqlite"
|
||||
)
|
||||
|
||||
func init() {
|
||||
database.Register("rqlite", &Rqlite{})
|
||||
}
|
||||
|
||||
const (
|
||||
// DefaultMigrationsTable defines the default rqlite migrations table
|
||||
DefaultMigrationsTable = "schema_migrations"
|
||||
|
||||
// DefaultConnectInsecure defines the default setting for connect insecure
|
||||
DefaultConnectInsecure = false
|
||||
)
|
||||
|
||||
// ErrNilConfig is returned if no configuration was passed to WithInstance
|
||||
var ErrNilConfig = fmt.Errorf("no config")
|
||||
|
||||
// ErrBadConfig is returned if configuration was invalid
|
||||
var ErrBadConfig = fmt.Errorf("bad parameter")
|
||||
|
||||
// Config defines the driver configuration
|
||||
type Config struct {
|
||||
// ConnectInsecure sets whether the connection uses TLS. Ineffectual when using WithInstance
|
||||
ConnectInsecure bool
|
||||
// MigrationsTable configures the migrations table name
|
||||
MigrationsTable string
|
||||
}
|
||||
|
||||
type Rqlite struct {
|
||||
db *gorqlite.Connection
|
||||
isLocked atomic.Bool
|
||||
|
||||
config *Config
|
||||
}
|
||||
|
||||
// WithInstance creates a rqlite database driver with an existing gorqlite database connection
|
||||
// and a Config struct
|
||||
func WithInstance(instance *gorqlite.Connection, config *Config) (database.Driver, error) {
|
||||
if config == nil {
|
||||
return nil, ErrNilConfig
|
||||
}
|
||||
|
||||
// we use the consistency level check as a database ping
|
||||
if _, err := instance.ConsistencyLevel(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(config.MigrationsTable) == 0 {
|
||||
config.MigrationsTable = DefaultMigrationsTable
|
||||
}
|
||||
|
||||
driver := &Rqlite{
|
||||
db: instance,
|
||||
config: config,
|
||||
}
|
||||
|
||||
if err := driver.ensureVersionTable(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return driver, nil
|
||||
}
|
||||
|
||||
// OpenURL creates a rqlite database driver from a connect URL
|
||||
func OpenURL(url string) (database.Driver, error) {
|
||||
d := &Rqlite{}
|
||||
return d.Open(url)
|
||||
}
|
||||
|
||||
func (r *Rqlite) ensureVersionTable() (err error) {
|
||||
if err = r.Lock(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if e := r.Unlock(); e != nil {
|
||||
if err == nil {
|
||||
err = e
|
||||
} else {
|
||||
err = multierror.Append(err, e)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
stmts := []string{
|
||||
fmt.Sprintf(`CREATE TABLE IF NOT EXISTS %s (version uint64, dirty bool)`, r.config.MigrationsTable),
|
||||
fmt.Sprintf(`CREATE UNIQUE INDEX IF NOT EXISTS version_unique ON %s (version)`, r.config.MigrationsTable),
|
||||
}
|
||||
|
||||
if _, err := r.db.Write(stmts); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Open returns a new driver instance configured with parameters
|
||||
// coming from the URL string. Migrate will call this function
|
||||
// only once per instance.
|
||||
func (r *Rqlite) Open(url string) (database.Driver, error) {
|
||||
dburl, config, err := parseUrl(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r.config = config
|
||||
|
||||
r.db, err = gorqlite.Open(dburl.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := r.ensureVersionTable(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// Close closes the underlying database instance managed by the driver.
|
||||
// Migrate will call this function only once per instance.
|
||||
func (r *Rqlite) Close() error {
|
||||
r.db.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Lock should acquire a database lock so that only one migration process
|
||||
// can run at a time. Migrate will call this function before Run is called.
|
||||
// If the implementation can't provide this functionality, return nil.
|
||||
// Return database.ErrLocked if database is already locked.
|
||||
func (r *Rqlite) Lock() error {
|
||||
if !r.isLocked.CAS(false, true) {
|
||||
return database.ErrLocked
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unlock should release the lock. Migrate will call this function after
|
||||
// all migrations have been run.
|
||||
func (r *Rqlite) Unlock() error {
|
||||
if !r.isLocked.CAS(true, false) {
|
||||
return database.ErrNotLocked
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run applies a migration to the database. migration is guaranteed to be not nil.
|
||||
func (r *Rqlite) Run(migration io.Reader) error {
|
||||
migr, err := io.ReadAll(migration)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
query := string(migr[:])
|
||||
if _, err := r.db.WriteOne(query); err != nil {
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetVersion saves version and dirty state.
|
||||
// Migrate will call this function before and after each call to Run.
|
||||
// version must be >= -1. -1 means NilVersion.
|
||||
func (r *Rqlite) SetVersion(version int, dirty bool) error {
|
||||
deleteQuery := fmt.Sprintf(`DELETE FROM %s`, r.config.MigrationsTable)
|
||||
statements := []gorqlite.ParameterizedStatement{
|
||||
{
|
||||
Query: deleteQuery,
|
||||
},
|
||||
}
|
||||
|
||||
// Also re-write the schema version for nil dirty versions to prevent
|
||||
// empty schema version for failed down migration on the first migration
|
||||
// See: https://github.com/golang-migrate/migrate/issues/330
|
||||
insertQuery := fmt.Sprintf(`INSERT INTO %s (version, dirty) VALUES (?, ?)`, r.config.MigrationsTable)
|
||||
if version >= 0 || (version == database.NilVersion && dirty) {
|
||||
statements = append(statements, gorqlite.ParameterizedStatement{
|
||||
Query: insertQuery,
|
||||
Arguments: []interface{}{
|
||||
version,
|
||||
dirty,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
wr, err := r.db.WriteParameterized(statements)
|
||||
if err != nil {
|
||||
for i, res := range wr {
|
||||
if res.Err != nil {
|
||||
return &database.Error{OrigErr: err, Query: []byte(statements[i].Query)}
|
||||
}
|
||||
}
|
||||
|
||||
// if somehow we're still here, return the original error with combined queries
|
||||
return &database.Error{OrigErr: err, Query: []byte(deleteQuery + "\n" + insertQuery)}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Version returns the currently active version and if the database is dirty.
|
||||
// When no migration has been applied, it must return version -1.
|
||||
// Dirty means, a previous migration failed and user interaction is required.
|
||||
func (r *Rqlite) Version() (version int, dirty bool, err error) {
|
||||
query := "SELECT version, dirty FROM " + r.config.MigrationsTable + " LIMIT 1"
|
||||
|
||||
qr, err := r.db.QueryOne(query)
|
||||
if err != nil {
|
||||
return database.NilVersion, false, nil
|
||||
}
|
||||
|
||||
if !qr.Next() {
|
||||
return database.NilVersion, false, nil
|
||||
}
|
||||
|
||||
if err := qr.Scan(&version, &dirty); err != nil {
|
||||
return database.NilVersion, false, &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
|
||||
return version, dirty, nil
|
||||
}
|
||||
|
||||
// Drop deletes everything in the database.
|
||||
// Note that this is a breaking action, a new call to Open() is necessary to
|
||||
// ensure subsequent calls work as expected.
|
||||
func (r *Rqlite) Drop() error {
|
||||
query := `SELECT name FROM sqlite_master WHERE type = 'table'`
|
||||
|
||||
tables, err := r.db.QueryOne(query)
|
||||
if err != nil {
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
|
||||
statements := make([]string, 0)
|
||||
for tables.Next() {
|
||||
var tableName string
|
||||
if err := tables.Scan(&tableName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(tableName) > 0 {
|
||||
statement := fmt.Sprintf(`DROP TABLE %s`, tableName)
|
||||
statements = append(statements, statement)
|
||||
}
|
||||
}
|
||||
|
||||
// return if nothing to do
|
||||
if len(statements) <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
wr, err := r.db.Write(statements)
|
||||
if err != nil {
|
||||
for i, res := range wr {
|
||||
if res.Err != nil {
|
||||
return &database.Error{OrigErr: err, Query: []byte(statements[i])}
|
||||
}
|
||||
}
|
||||
|
||||
// if somehow we're still here, return the original error with combined queries
|
||||
return &database.Error{OrigErr: err, Query: []byte(strings.Join(statements, "\n"))}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseUrl(url string) (*nurl.URL, *Config, error) {
|
||||
parsedUrl, err := nurl.Parse(url)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
config, err := parseConfigFromQuery(parsedUrl.Query())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if parsedUrl.Scheme != "rqlite" {
|
||||
return nil, nil, errors.Wrap(ErrBadConfig, "bad scheme")
|
||||
}
|
||||
|
||||
// adapt from rqlite to http/https schemes
|
||||
if config.ConnectInsecure {
|
||||
parsedUrl.Scheme = "http"
|
||||
} else {
|
||||
parsedUrl.Scheme = "https"
|
||||
}
|
||||
|
||||
filteredUrl := migrate.FilterCustomQuery(parsedUrl)
|
||||
|
||||
return filteredUrl, config, nil
|
||||
}
|
||||
|
||||
func parseConfigFromQuery(queryVals nurl.Values) (*Config, error) {
|
||||
c := Config{
|
||||
ConnectInsecure: DefaultConnectInsecure,
|
||||
MigrationsTable: DefaultMigrationsTable,
|
||||
}
|
||||
|
||||
migrationsTable := queryVals.Get("x-migrations-table")
|
||||
if migrationsTable != "" {
|
||||
if strings.HasPrefix(migrationsTable, "sqlite_") {
|
||||
return nil, errors.Wrap(ErrBadConfig, "invalid value for x-migrations-table")
|
||||
}
|
||||
c.MigrationsTable = migrationsTable
|
||||
}
|
||||
|
||||
connectInsecureStr := queryVals.Get("x-connect-insecure")
|
||||
if connectInsecureStr != "" {
|
||||
connectInsecure, err := strconv.ParseBool(connectInsecureStr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ErrBadConfig, "invalid value for x-connect-insecure")
|
||||
}
|
||||
c.ConnectInsecure = connectInsecure
|
||||
}
|
||||
|
||||
return &c, nil
|
||||
}
|
||||
@@ -0,0 +1,324 @@
|
||||
package rqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/dhui/dktest"
|
||||
"github.com/rqlite/gorqlite"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
dt "github.com/golang-migrate/migrate/v4/database/testing"
|
||||
"github.com/golang-migrate/migrate/v4/dktesting"
|
||||
_ "github.com/golang-migrate/migrate/v4/source/file"
|
||||
)
|
||||
|
||||
var defaultPort uint16 = 4001
|
||||
|
||||
var opts = dktest.Options{
|
||||
Env: map[string]string{"NODE_ID": "1"},
|
||||
PortRequired: true,
|
||||
ReadyFunc: isReady,
|
||||
}
|
||||
var specs = []dktesting.ContainerSpec{
|
||||
{ImageName: "rqlite/rqlite:7.21.4", Options: opts},
|
||||
{ImageName: "rqlite/rqlite:8.0.6", Options: opts},
|
||||
{ImageName: "rqlite/rqlite:8.11.1", Options: opts},
|
||||
{ImageName: "rqlite/rqlite:8.12.3", Options: opts},
|
||||
}
|
||||
|
||||
func isReady(ctx context.Context, c dktest.ContainerInfo) bool {
|
||||
ip, port, err := c.Port(defaultPort)
|
||||
if err != nil {
|
||||
fmt.Println("error getting port")
|
||||
return false
|
||||
}
|
||||
|
||||
statusString := fmt.Sprintf("http://%s:%s/status", ip, port)
|
||||
fmt.Println(statusString)
|
||||
|
||||
var readyResp struct {
|
||||
Store struct {
|
||||
Ready bool `json:"ready"`
|
||||
} `json:"store"`
|
||||
}
|
||||
|
||||
resp, err := http.Get(statusString)
|
||||
if err != nil {
|
||||
fmt.Println("error getting status")
|
||||
return false
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
fmt.Println("statusCode != 200")
|
||||
return false
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
fmt.Println("error reading body")
|
||||
return false
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(body, &readyResp); err != nil {
|
||||
fmt.Println("error unmarshaling body")
|
||||
return false
|
||||
}
|
||||
|
||||
return readyResp.Store.Ready
|
||||
}
|
||||
|
||||
func Test(t *testing.T) {
|
||||
dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) {
|
||||
ip, port, err := c.Port(defaultPort)
|
||||
assert.NoError(t, err)
|
||||
|
||||
connectString := fmt.Sprintf("rqlite://%s:%s?level=strong&disableClusterDiscovery=true&x-connect-insecure=true", ip, port)
|
||||
t.Logf("DB connect string : %s\n", connectString)
|
||||
|
||||
r := &Rqlite{}
|
||||
d, err := r.Open(connectString)
|
||||
assert.NoError(t, err)
|
||||
|
||||
dt.Test(t, d, []byte("CREATE TABLE t (Qty int, Name string);"))
|
||||
})
|
||||
}
|
||||
|
||||
func TestMigrate(t *testing.T) {
|
||||
dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) {
|
||||
ip, port, err := c.Port(defaultPort)
|
||||
assert.NoError(t, err)
|
||||
|
||||
connectString := fmt.Sprintf("rqlite://%s:%s?level=strong&disableClusterDiscovery=true&x-connect-insecure=true", ip, port)
|
||||
t.Logf("DB connect string : %s\n", connectString)
|
||||
|
||||
driver, err := OpenURL(connectString)
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
if err := driver.Close(); err != nil {
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
m, err := migrate.NewWithDatabaseInstance(
|
||||
"file://./examples/migrations",
|
||||
"ql", driver)
|
||||
assert.NoError(t, err)
|
||||
|
||||
dt.TestMigrate(t, m)
|
||||
})
|
||||
}
|
||||
|
||||
func TestBadConnectInsecureParam(t *testing.T) {
|
||||
dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) {
|
||||
ip, port, err := c.Port(defaultPort)
|
||||
assert.NoError(t, err)
|
||||
|
||||
connectString := fmt.Sprintf("rqlite://%s:%s?x-connect-insecure=foo", ip, port)
|
||||
t.Logf("DB connect string : %s\n", connectString)
|
||||
|
||||
_, err = OpenURL(connectString)
|
||||
assert.ErrorIs(t, err, ErrBadConfig)
|
||||
})
|
||||
}
|
||||
|
||||
func TestBadProtocol(t *testing.T) {
|
||||
dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) {
|
||||
ip, port, err := c.Port(defaultPort)
|
||||
assert.NoError(t, err)
|
||||
|
||||
connectString := fmt.Sprintf("postgres://%s:%s/database", ip, port)
|
||||
t.Logf("DB connect string : %s\n", connectString)
|
||||
|
||||
_, err = OpenURL(connectString)
|
||||
assert.ErrorIs(t, err, ErrBadConfig)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNoConfig(t *testing.T) {
|
||||
dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) {
|
||||
ip, port, err := c.Port(defaultPort)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// gorqlite expects http(s) schemes
|
||||
connectString := fmt.Sprintf("http://%s:%s?level=strong&disableClusterDiscovery=true", ip, port)
|
||||
t.Logf("DB connect string : %s\n", connectString)
|
||||
db, err := gorqlite.Open(connectString)
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = WithInstance(db, nil)
|
||||
assert.ErrorIs(t, err, ErrNilConfig)
|
||||
})
|
||||
}
|
||||
|
||||
func TestWithInstanceEmptyConfig(t *testing.T) {
|
||||
dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) {
|
||||
ip, port, err := c.Port(defaultPort)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// gorqlite expects http(s) schemes
|
||||
connectString := fmt.Sprintf("http://%s:%s?level=strong&disableClusterDiscovery=true", ip, port)
|
||||
t.Logf("DB connect string : %s\n", connectString)
|
||||
db, err := gorqlite.Open(connectString)
|
||||
assert.NoError(t, err)
|
||||
|
||||
driver, err := WithInstance(db, &Config{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
defer func() {
|
||||
if err := driver.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
m, err := migrate.NewWithDatabaseInstance(
|
||||
"file://./examples/migrations",
|
||||
"ql", driver)
|
||||
assert.NoError(t, err)
|
||||
|
||||
t.Log("UP")
|
||||
err = m.Up()
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = db.QueryOne(fmt.Sprintf("SELECT * FROM %s", DefaultMigrationsTable))
|
||||
assert.NoError(t, err)
|
||||
|
||||
t.Log("DOWN")
|
||||
err = m.Down()
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestMigrationTable(t *testing.T) {
|
||||
dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) {
|
||||
ip, port, err := c.Port(defaultPort)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// gorqlite expects http(s) schemes
|
||||
connectString := fmt.Sprintf("http://%s:%s?level=strong&disableClusterDiscovery=true", ip, port)
|
||||
t.Logf("DB connect string : %s\n", connectString)
|
||||
db, err := gorqlite.Open(connectString)
|
||||
assert.NoError(t, err)
|
||||
|
||||
config := Config{MigrationsTable: "my_migration_table"}
|
||||
driver, err := WithInstance(db, &config)
|
||||
assert.NoError(t, err)
|
||||
|
||||
defer func() {
|
||||
if err := driver.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
m, err := migrate.NewWithDatabaseInstance(
|
||||
"file://./examples/migrations",
|
||||
"ql", driver)
|
||||
assert.NoError(t, err)
|
||||
|
||||
t.Log("UP")
|
||||
err = m.Up()
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = db.QueryOne(fmt.Sprintf("SELECT * FROM %s", config.MigrationsTable))
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = db.WriteOne(`INSERT INTO pets (name, predator) VALUES ("franklin", true)`)
|
||||
assert.NoError(t, err)
|
||||
|
||||
res, err := db.QueryOne(`SELECT name, predator FROM pets LIMIT 1`)
|
||||
assert.NoError(t, err)
|
||||
|
||||
_ = res.Next()
|
||||
|
||||
// make sure we can use the migrated table
|
||||
var petName string
|
||||
var petPredator int
|
||||
err = res.Scan(&petName, &petPredator)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, petName, "franklin")
|
||||
assert.Equal(t, petPredator, 1)
|
||||
|
||||
t.Log("DOWN")
|
||||
err = m.Down()
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = db.QueryOne(fmt.Sprintf("SELECT * FROM %s", config.MigrationsTable))
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestParseUrl(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
passedUrl string
|
||||
expectedUrl string
|
||||
expectedConfig *Config
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
"defaults",
|
||||
"rqlite://localhost:4001",
|
||||
"https://localhost:4001",
|
||||
&Config{ConnectInsecure: DefaultConnectInsecure, MigrationsTable: DefaultMigrationsTable},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"configure migration table",
|
||||
"rqlite://localhost:4001?x-migrations-table=foo",
|
||||
"https://localhost:4001",
|
||||
&Config{ConnectInsecure: DefaultConnectInsecure, MigrationsTable: "foo"},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"configure connect insecure",
|
||||
"rqlite://localhost:4001?x-connect-insecure=true",
|
||||
"http://localhost:4001",
|
||||
&Config{ConnectInsecure: true, MigrationsTable: DefaultMigrationsTable},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"invalid migration table",
|
||||
"rqlite://localhost:4001?x-migrations-table=sqlite_bar",
|
||||
"",
|
||||
nil,
|
||||
"invalid value for x-migrations-table: bad parameter",
|
||||
},
|
||||
{
|
||||
"invalid connect insecure",
|
||||
"rqlite://localhost:4001?x-connect-insecure=baz",
|
||||
"",
|
||||
nil,
|
||||
"invalid value for x-connect-insecure: bad parameter",
|
||||
},
|
||||
{
|
||||
"invalid url",
|
||||
string([]byte{0x7f}),
|
||||
"",
|
||||
nil,
|
||||
"parse \"\\x7f\": net/url: invalid control character in URL",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
actualUrl, actualConfig, actualErr := parseUrl(tt.passedUrl)
|
||||
if tt.expectedUrl != "" {
|
||||
assert.Equal(t, tt.expectedUrl, actualUrl.String())
|
||||
} else {
|
||||
assert.Nil(t, actualUrl)
|
||||
}
|
||||
|
||||
assert.Equal(t, tt.expectedConfig, actualConfig)
|
||||
|
||||
if tt.expectedErr == "" {
|
||||
assert.NoError(t, actualErr)
|
||||
} else {
|
||||
assert.EqualError(t, actualErr, tt.expectedErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,8 @@ require (
|
||||
github.com/aws/aws-sdk-go v1.34.0
|
||||
github.com/cenkalti/backoff/v4 v4.1.2
|
||||
github.com/cockroachdb/cockroach-go/v2 v2.1.1
|
||||
github.com/dhui/dktest v0.3.16
|
||||
github.com/docker/docker v20.10.24+incompatible
|
||||
github.com/dhui/dktest v0.4.0
|
||||
github.com/docker/docker v24.0.7+incompatible
|
||||
github.com/docker/go-connections v0.4.0
|
||||
github.com/fsouza/fake-gcs-server v1.17.0
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
@@ -22,7 +22,7 @@ require (
|
||||
github.com/jackc/pgx/v4 v4.18.1
|
||||
github.com/jackc/pgx/v5 v5.3.1
|
||||
github.com/ktrysmt/go-bitbucket v0.6.4
|
||||
github.com/lib/pq v1.10.2
|
||||
github.com/lib/pq v1.10.9
|
||||
github.com/markbates/pkger v0.15.1
|
||||
github.com/mattn/go-sqlite3 v1.14.16
|
||||
github.com/microsoft/go-mssqldb v1.0.0
|
||||
@@ -30,7 +30,7 @@ require (
|
||||
github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8
|
||||
github.com/neo4j/neo4j-go-driver v1.8.1-0.20200803113522-b626aa943eba
|
||||
github.com/snowflakedb/gosnowflake v1.6.19
|
||||
github.com/stretchr/testify v1.8.1
|
||||
github.com/stretchr/testify v1.8.3
|
||||
github.com/xanzy/go-gitlab v0.15.0
|
||||
go.mongodb.org/mongo-driver v1.7.5
|
||||
go.uber.org/atomic v1.7.0
|
||||
@@ -78,7 +78,7 @@ require (
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 // indirect
|
||||
github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 // indirect
|
||||
github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369 // indirect
|
||||
github.com/danieljoos/wincred v1.1.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
@@ -86,8 +86,8 @@ require (
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/dvsekhvalnov/jose2go v1.5.0 // indirect
|
||||
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 // indirect
|
||||
github.com/envoyproxy/go-control-plane v0.11.0 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v0.10.0 // indirect
|
||||
github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v0.10.1 // indirect
|
||||
github.com/form3tech-oss/jwt-go v3.2.5+incompatible // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.1 // indirect
|
||||
github.com/go-stack/stack v1.8.0 // indirect
|
||||
@@ -139,9 +139,10 @@ require (
|
||||
github.com/opencontainers/image-spec v1.0.2 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.16 // indirect
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
||||
github.com/rqlite/gorqlite v0.0.0-20230708021416-2acd02b70b79
|
||||
github.com/shopspring/decimal v1.2.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.2 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
@@ -151,20 +152,20 @@ require (
|
||||
github.com/zeebo/xxh3 v1.0.2 // indirect
|
||||
gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
golang.org/x/crypto v0.9.0 // indirect
|
||||
golang.org/x/crypto v0.17.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 // indirect
|
||||
golang.org/x/mod v0.10.0 // indirect
|
||||
golang.org/x/net v0.10.0 // indirect
|
||||
golang.org/x/net v0.17.0 // indirect
|
||||
golang.org/x/sync v0.2.0 // indirect
|
||||
golang.org/x/sys v0.8.0 // indirect
|
||||
golang.org/x/term v0.8.0 // indirect
|
||||
golang.org/x/text v0.9.0 // indirect
|
||||
golang.org/x/sys v0.15.0 // indirect
|
||||
golang.org/x/term v0.15.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect
|
||||
google.golang.org/grpc v1.55.0 // indirect
|
||||
google.golang.org/grpc v1.56.3 // indirect
|
||||
google.golang.org/protobuf v1.30.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
||||
@@ -142,8 +142,8 @@ github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XP
|
||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195 h1:58f1tJ1ra+zFINPlwLWvQsR9CzAKt2e+EWV2yX9oXQ4=
|
||||
github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k=
|
||||
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
github.com/cockroachdb/cockroach-go/v2 v2.1.1 h1:3XzfSMuUT0wBe1a3o5C0eOTcArhmmFAg2Jzh/7hhKqo=
|
||||
@@ -161,15 +161,15 @@ github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnG
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dhui/dktest v0.3.16 h1:i6gq2YQEtcrjKbeJpBkWjE8MmLZPYllcjOFbTZuPDnw=
|
||||
github.com/dhui/dktest v0.3.16/go.mod h1:gYaA3LRmM8Z4vJl2MA0THIigJoZrwOansEOsp+kqxp0=
|
||||
github.com/dhui/dktest v0.4.0 h1:z05UmuXZHO/bgj/ds2bGMBu8FI4WA+Ag/m3ghL+om7M=
|
||||
github.com/dhui/dktest v0.4.0/go.mod h1:v/Dbz1LgCBOi2Uki2nUqLBGa83hWBGFMu5MrgMDCc78=
|
||||
github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
|
||||
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
|
||||
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
|
||||
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v20.10.24+incompatible h1:Ugvxm7a8+Gz6vqQYQQ2W7GYq5EUPaAiuPgIfVyI3dYE=
|
||||
github.com/docker/docker v20.10.24+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM=
|
||||
github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
@@ -186,11 +186,11 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/go-control-plane v0.11.0 h1:jtLewhRR2vMRNnq2ZZUoCjUlgut+Y0+sDDWPOfwOi1o=
|
||||
github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI=
|
||||
github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f h1:7T++XKzy4xg7PKy+bM+Sa9/oe1OC88yz2hXQUISoXfA=
|
||||
github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.10.0 h1:oIfnZFdC0YhpNNEX+SuIqko4cqqVZeN9IGTrhZje83Y=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.10.1 h1:c0g45+xCJhdgFGw7a5QAfdS4byAbud7miNWJ1WwEVf8=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss=
|
||||
github.com/form3tech-oss/jwt-go v3.2.5+incompatible h1:/l4kBbb4/vGSsdtB5nUe8L7B9mImVMaBPw9L/0TBHU8=
|
||||
github.com/form3tech-oss/jwt-go v3.2.5+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
@@ -444,8 +444,9 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
|
||||
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/markbates/pkger v0.15.1 h1:3MPelV53RnGSW07izx5xGxl4e/sdRD6zqseIk0rMASY=
|
||||
github.com/markbates/pkger v0.15.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
@@ -527,6 +528,8 @@ github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qq
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rqlite/gorqlite v0.0.0-20230708021416-2acd02b70b79 h1:V7x0hCAgL8lNGezuex1RW1sh7VXXCqfw8nXZti66iFg=
|
||||
github.com/rqlite/gorqlite v0.0.0-20230708021416-2acd02b70b79/go.mod h1:xF/KoXmrRyahPfo5L7Szb5cAAUl53dMWBh9cMruGEZg=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
||||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
||||
@@ -538,7 +541,6 @@ github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFR
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y=
|
||||
github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/snowflakedb/gosnowflake v1.6.19 h1:KSHXrQ5o7uso25hNIzi/RObXtnSGkFgie91X82KcvMY=
|
||||
@@ -558,8 +560,9 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/xanzy/go-gitlab v0.15.0 h1:rWtwKTgEnXyNUGrOArN7yyc3THRkpYcKXIXia9abywQ=
|
||||
@@ -626,8 +629,9 @@ golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0
|
||||
golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -655,6 +659,7 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
|
||||
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -689,9 +694,9 @@ golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@@ -709,6 +714,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
|
||||
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180224232135-f6cff0780e54/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -754,14 +760,18 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
|
||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -773,8 +783,10 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs=
|
||||
@@ -813,6 +825,7 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo=
|
||||
golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -873,8 +886,8 @@ google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTp
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
|
||||
google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
|
||||
google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
|
||||
google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc=
|
||||
google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
@@ -913,6 +926,7 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/driver/postgres v1.0.8/go.mod h1:4eOzrI1MUfm6ObJU/UcmbXyiHSs8jSwH95G5P5dxcAg=
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
//go:build rqlite
|
||||
// +build rqlite
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
_ "github.com/golang-migrate/migrate/v4/database/rqlite"
|
||||
)
|
||||
@@ -11,6 +11,8 @@ import (
|
||||
st "github.com/golang-migrate/migrate/v4/source/testing"
|
||||
)
|
||||
|
||||
const scheme = "file://"
|
||||
|
||||
func Test(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
@@ -29,7 +31,7 @@ func Test(t *testing.T) {
|
||||
mustWriteFile(t, tmpDir, "7_foobar.down.sql", "7 down")
|
||||
|
||||
f := &File{}
|
||||
d, err := f.Open("file://" + tmpDir)
|
||||
d, err := f.Open(scheme + tmpDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -48,7 +50,7 @@ func TestOpen(t *testing.T) {
|
||||
}
|
||||
|
||||
f := &File{}
|
||||
_, err := f.Open("file://" + tmpDir) // absolute path
|
||||
_, err := f.Open(scheme + tmpDir) // absolute path
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -108,7 +110,7 @@ func TestOpenDefaultsToCurrentDirectory(t *testing.T) {
|
||||
}
|
||||
|
||||
f := &File{}
|
||||
d, err := f.Open("file://")
|
||||
d, err := f.Open(scheme)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -125,7 +127,7 @@ func TestOpenWithDuplicateVersion(t *testing.T) {
|
||||
mustWriteFile(t, tmpDir, "1_bar.up.sql", "") // 1 up
|
||||
|
||||
f := &File{}
|
||||
_, err := f.Open("file://" + tmpDir)
|
||||
_, err := f.Open(scheme + tmpDir)
|
||||
if err == nil {
|
||||
t.Fatal("expected err")
|
||||
}
|
||||
@@ -135,7 +137,7 @@ func TestClose(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
f := &File{}
|
||||
d, err := f.Open("file://" + tmpDir)
|
||||
d, err := f.Open(scheme + tmpDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -172,7 +174,7 @@ func BenchmarkOpen(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
f := &File{}
|
||||
_, err := f.Open("file://" + dir)
|
||||
_, err := f.Open(scheme + dir)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
@@ -188,7 +190,7 @@ func BenchmarkNext(b *testing.B) {
|
||||
}
|
||||
}()
|
||||
f := &File{}
|
||||
d, _ := f.Open("file://" + dir)
|
||||
d, _ := f.Open(scheme + dir)
|
||||
b.ResetTimer()
|
||||
v, err := d.First()
|
||||
for n := 0; n < b.N; n++ {
|
||||
|
||||
Reference in New Issue
Block a user