pax_global_header 0000666 0000000 0000000 00000000064 14314555116 0014517 g ustar 00root root 0000000 0000000 52 comment=867ee0cca56a62f111942e51676663c8ae1ce77f
atlas-0.7.2/ 0000775 0000000 0000000 00000000000 14314555116 0012631 5 ustar 00root root 0000000 0000000 atlas-0.7.2/.github/ 0000775 0000000 0000000 00000000000 14314555116 0014171 5 ustar 00root root 0000000 0000000 atlas-0.7.2/.github/workflows/ 0000775 0000000 0000000 00000000000 14314555116 0016226 5 ustar 00root root 0000000 0000000 atlas-0.7.2/.github/workflows/build-docker.yaml 0000664 0000000 0000000 00000001735 14314555116 0021464 0 ustar 00root root 0000000 0000000 name: Build Docker
on:
pull_request:
push:
branches:
- master
env:
CRDB_VERSIONS: v21.2.11 v22.1.0
jobs:
build-services:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2.4.0
- uses: actions/setup-go@v2
with:
go-version: '1.18'
- name: Log in to registry
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin
- name: "build cockroach image"
run: |
VER="${{ env.CRDB_VERSIONS }}"
for i in $VER
do
:
if ! docker manifest inspect ghcr.io/ariga/cockroachdb-single-node:$i; then
go run internal/ci/cockroach/main.go $i > internal/ci/cockroach/Dockerfile
docker build -t ghcr.io/ariga/cockroachdb-single-node:$i internal/ci/cockroach/
docker push ghcr.io/ariga/cockroachdb-single-node:$i
else
echo image already exists
fi
done atlas-0.7.2/.github/workflows/ci-website.yaml 0000664 0000000 0000000 00000001273 14314555116 0021150 0 ustar 00root root 0000000 0000000 name: Docsite CI
on:
push:
branches-ignore:
- master
jobs:
docsite_ci:
name: verify build doesn't crash
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./doc/website
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2.1.5
with:
node-version: 16
- name: Cache dependecies
uses: actions/cache@v2.1.6
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install Dependencies
run: npm install
- name: Build website
run: npm run build
atlas-0.7.2/.github/workflows/ci.yml 0000664 0000000 0000000 00000040202 14314555116 0017342 0 ustar 00root root 0000000 0000000 # # # # # # # # # # # # # # # #
# CODE GENERATED - DO NOT EDIT
# # # # # # # # # # # # # # # #
name: Continuous Integration
on:
pull_request:
paths-ignore:
- 'doc/**'
push:
branches:
- master
paths-ignore:
- 'doc/**'
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@v2
with:
go-version: 1.18
- uses: actions/checkout@v2
- name: Run linters
uses: golangci/golangci-lint-action@v3
with:
args: --verbose
generate-cmp:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2.4.0
- uses: actions/setup-go@v2
with:
go-version: '1.19'
- uses: actions/cache@v2.1.5
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: run "go generate ./..."
run: go generate ./...
- name: go generate cmd/atlas
working-directory: cmd/atlas
run: go generate ./...
- name: Verify generated files are checked in properly
run: |
status=$(git status --porcelain | grep -v "go.\(sum\|mod\)" | cat)
if [ -n "$status" ]; then
echo "you need to run 'go generate ./...' and commit the changes"
echo "$status"
exit 1
fi
unit:
runs-on: ubuntu-latest
strategy:
matrix:
go: [ '1.18', '1.19' ]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go }}
- uses: actions/cache@v2.1.5
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Run sql tests
run: go test -race ./...
working-directory: sql
- name: Run schemahcl tests
run: go test -race ./...
working-directory: schemahcl
cli:
runs-on: ubuntu-latest
strategy:
matrix:
go: [ '1.19' ]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go }}
- uses: actions/cache@v2.1.5
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Run cli tests
run: go test -race ./...
working-directory: cmd/atlas
integration:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2.3.4
- uses: actions/setup-go@v2
with:
go-version: 1.19
- uses: actions/cache@v2.1.6
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Run integration tests for HCL
working-directory: internal/integration/hclsqlspec
run: go test -race -count=2 -v ./...
revisions:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2.3.4
with:
fetch-depth: 0
- uses: actions/setup-go@v2
with:
go-version: 1.19
- uses: actions/cache@v2.1.6
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Checkout origin/master
run: git checkout origin/master
- name: Create revisions from master
run: go run main.go migrate apply --dir file://internal/cmdapi/testdata/sqlite --url sqlite://db?_fk=1
working-directory: cmd/atlas
- name: Checkout previous HEAD
run: git checkout -
- name: Migrate revisions table to HEAD
run: go run main.go migrate apply --dir file://internal/cmdapi/testdata/sqlite --url sqlite://db?_fk=1
working-directory: cmd/atlas
integration-mysql56:
runs-on: ubuntu-latest
services:
mysql56:
image: mysql:5.6.35
env:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: pass
ports:
- 3306:3306
options: >-
--health-cmd "mysqladmin ping -ppass"
--health-interval 10s
--health-start-period 10s
--health-timeout 5s
--health-retries 10
steps:
- uses: actions/checkout@v2.3.4
- uses: actions/setup-go@v2
with:
go-version: 1.19
- uses: actions/cache@v2.1.6
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Run integration tests for mysql56
working-directory: internal/integration
run: go test -race -count=2 -v -run="MySQL" -version="mysql56" ./...
integration-mysql57:
runs-on: ubuntu-latest
services:
mysql57:
image: mysql:5.7.26
env:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: pass
ports:
- 3307:3306
options: >-
--health-cmd "mysqladmin ping -ppass"
--health-interval 10s
--health-start-period 10s
--health-timeout 5s
--health-retries 10
steps:
- uses: actions/checkout@v2.3.4
- uses: actions/setup-go@v2
with:
go-version: 1.19
- uses: actions/cache@v2.1.6
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Run integration tests for mysql57
working-directory: internal/integration
run: go test -race -count=2 -v -run="MySQL" -version="mysql57" ./...
integration-mysql8:
runs-on: ubuntu-latest
services:
mysql8:
image: mysql:8
env:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: pass
ports:
- 3308:3306
options: >-
--health-cmd "mysqladmin ping -ppass"
--health-interval 10s
--health-start-period 10s
--health-timeout 5s
--health-retries 10
steps:
- uses: actions/checkout@v2.3.4
- uses: actions/setup-go@v2
with:
go-version: 1.19
- uses: actions/cache@v2.1.6
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Run integration tests for mysql8
working-directory: internal/integration
run: go test -race -count=2 -v -run="MySQL" -version="mysql8" ./...
integration-maria107:
runs-on: ubuntu-latest
services:
maria107:
image: mariadb:10.7
env:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: pass
ports:
- 4306:3306
options: >-
--health-cmd "mysqladmin ping -ppass"
--health-interval 10s
--health-start-period 10s
--health-timeout 5s
--health-retries 10
steps:
- uses: actions/checkout@v2.3.4
- uses: actions/setup-go@v2
with:
go-version: 1.19
- uses: actions/cache@v2.1.6
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Run integration tests for maria107
working-directory: internal/integration
run: go test -race -count=2 -v -run="MySQL" -version="maria107" ./...
integration-maria102:
runs-on: ubuntu-latest
services:
maria102:
image: mariadb:10.2.32
env:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: pass
ports:
- 4307:3306
options: >-
--health-cmd "mysqladmin ping -ppass"
--health-interval 10s
--health-start-period 10s
--health-timeout 5s
--health-retries 10
steps:
- uses: actions/checkout@v2.3.4
- uses: actions/setup-go@v2
with:
go-version: 1.19
- uses: actions/cache@v2.1.6
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Run integration tests for maria102
working-directory: internal/integration
run: go test -race -count=2 -v -run="MySQL" -version="maria102" ./...
integration-maria103:
runs-on: ubuntu-latest
services:
maria103:
image: mariadb:10.3.13
env:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: pass
ports:
- 4308:3306
options: >-
--health-cmd "mysqladmin ping -ppass"
--health-interval 10s
--health-start-period 10s
--health-timeout 5s
--health-retries 10
steps:
- uses: actions/checkout@v2.3.4
- uses: actions/setup-go@v2
with:
go-version: 1.19
- uses: actions/cache@v2.1.6
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Run integration tests for maria103
working-directory: internal/integration
run: go test -race -count=2 -v -run="MySQL" -version="maria103" ./...
integration-postgres10:
runs-on: ubuntu-latest
services:
postgres10:
image: postgres:10
env:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
ports:
- 5430:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v2.3.4
- uses: actions/setup-go@v2
with:
go-version: 1.19
- uses: actions/cache@v2.1.6
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Run integration tests for postgres10
working-directory: internal/integration
run: go test -race -count=2 -v -run="Postgres" -version="postgres10" ./...
integration-postgres11:
runs-on: ubuntu-latest
services:
postgres11:
image: postgres:11
env:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
ports:
- 5431:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v2.3.4
- uses: actions/setup-go@v2
with:
go-version: 1.19
- uses: actions/cache@v2.1.6
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Run integration tests for postgres11
working-directory: internal/integration
run: go test -race -count=2 -v -run="Postgres" -version="postgres11" ./...
integration-postgres12:
runs-on: ubuntu-latest
services:
postgres12:
image: postgres:12.3
env:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v2.3.4
- uses: actions/setup-go@v2
with:
go-version: 1.19
- uses: actions/cache@v2.1.6
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Run integration tests for postgres12
working-directory: internal/integration
run: go test -race -count=2 -v -run="Postgres" -version="postgres12" ./...
integration-postgres13:
runs-on: ubuntu-latest
services:
postgres13:
image: postgres:13.1
env:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
ports:
- 5433:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v2.3.4
- uses: actions/setup-go@v2
with:
go-version: 1.19
- uses: actions/cache@v2.1.6
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Run integration tests for postgres13
working-directory: internal/integration
run: go test -race -count=2 -v -run="Postgres" -version="postgres13" ./...
integration-postgres14:
runs-on: ubuntu-latest
services:
postgres14:
image: postgres:14
env:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
ports:
- 5434:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v2.3.4
- uses: actions/setup-go@v2
with:
go-version: 1.19
- uses: actions/cache@v2.1.6
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Run integration tests for postgres14
working-directory: internal/integration
run: go test -race -count=2 -v -run="Postgres" -version="postgres14" ./...
integration-tidb5:
runs-on: ubuntu-latest
services:
tidb5:
image: pingcap/tidb:v5.4.0
ports:
- 4309:4000
steps:
- uses: actions/checkout@v2.3.4
- uses: actions/setup-go@v2
with:
go-version: 1.19
- uses: actions/cache@v2.1.6
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Run integration tests for tidb5
working-directory: internal/integration
run: go test -race -count=2 -v -run="TiDB" -version="tidb5" ./...
integration-tidb6:
runs-on: ubuntu-latest
services:
tidb6:
image: pingcap/tidb:v6.0.0
ports:
- 4310:4000
steps:
- uses: actions/checkout@v2.3.4
- uses: actions/setup-go@v2
with:
go-version: 1.19
- uses: actions/cache@v2.1.6
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Run integration tests for tidb6
working-directory: internal/integration
run: go test -race -count=2 -v -run="TiDB" -version="tidb6" ./...
integration-sqlite:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2.3.4
- uses: actions/setup-go@v2
with:
go-version: 1.19
- uses: actions/cache@v2.1.6
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Run integration tests for sqlite
working-directory: internal/integration
run: go test -race -count=2 -v -run="SQLite.*" -version="sqlite" ./...
integration-cockroach:
runs-on: ubuntu-latest
services:
cockroach:
image: ghcr.io/ariga/cockroachdb-single-node:v21.2.11
ports:
- 26257:26257
steps:
- uses: actions/checkout@v2.3.4
- uses: actions/setup-go@v2
with:
go-version: 1.19
- uses: actions/cache@v2.1.6
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Run integration tests for cockroach
working-directory: internal/integration
run: go test -race -count=2 -v -run="Cockroach" -version="cockroach" ./...
atlas-0.7.2/.github/workflows/website.yaml 0000664 0000000 0000000 00000002131 14314555116 0020551 0 ustar 00root root 0000000 0000000 name: Continuous Deployment
on:
push:
branches:
- master
paths:
- 'doc/**'
jobs:
docs:
name: deploy atlasgo.io
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./doc/website
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2.1.5
with:
node-version: 16
- name: Cache dependecies
uses: actions/cache@v2.1.6
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install Dependencies
run: npm install
- name: Build website
run: npm run build
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: Deploy Website
run: npm run upload
- name: Invalidate Cache
run: npm run invalidate-cdn
atlas-0.7.2/.golangci.yml 0000664 0000000 0000000 00000001011 14314555116 0015206 0 ustar 00root root 0000000 0000000 run:
timeout: 3m
issues:
include:
- EXC0012
exclude-rules:
- path: _test\.go
linters:
- gosec
- path: sql/migrate/dir.go
linters:
- gosec
linters-settings:
goheader:
template: |-
Copyright 2021-present The Atlas Authors. All rights reserved.
This source code is licensed under the Apache 2.0 license found
in the LICENSE file in the root directory of this source tree.
linters:
disable-all: true
enable:
- gosec
- revive
- goheader
atlas-0.7.2/LICENSE 0000664 0000000 0000000 00000026135 14314555116 0013645 0 ustar 00root root 0000000 0000000
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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. atlas-0.7.2/README.md 0000664 0000000 0000000 00000005167 14314555116 0014121 0 ustar 00root root 0000000 0000000
Manage your database schemas with Atlas CLI
Atlas CLI is an open source tool that helps developers manage their database schemas by applying modern DevOps principles. Contrary to existing tools, Atlas intelligently plans schema migrations for you. Atlas users can use the [Atlas DDL](https://atlasgo.io/guides/ddl#hcl) (data definition language) to describe their desired database schema and use the command-line tool to plan and apply the migrations to their systems.
## Quick Installation
On macOS:
```shell
brew install ariga/tap/atlas
```
Click [here](https://atlasgo.io/cli/getting-started/setting-up) to read instructions for other platforms.
## Getting Started
Get started with Atlas by following the [Getting Started](https://atlasgo.io/cli/getting-started/setting-up) docs.
This tutorial teaches you how to inspect a database, generate a migration plan and apply the migration to your database.
## Features
- **Inspecting a database**: easily inspect your database schema by providing a database URL.
```shell
atlas schema inspect -u "mysql://root:pass@localhost:3306/example" > atlas.hcl
```
- **Applying a migration**: generate a migration plan to apply on the database by providing an HCL file with the desired Atlas schema.
```shell
atlas schema apply -u "mysql://root:pass@localhost:3306/example" -f atlas.hcl
```
- **Declarative Migrations vs. Versioned Migrations**: Atlas offers two workflows. Declarative migrations allow the user to provide a desired state and Atlas gets the schema there instantly (simply using inspect and apply commands). Alternatively, versioned migrations are explicitly defined and assigned a version. Atlas can then bring a schema to the desired version by following the migrations between the current version and the specified one.
### About the Project
Read more about the motivation of the project [here](https://atlasgo.io/blog/2021/11/25/meet-atlas).
### Supported Databases
MySQL, MariaDB, PostgresSQL, SQLite, TiDB, CockroachDB
atlas-0.7.2/cmd/ 0000775 0000000 0000000 00000000000 14314555116 0013374 5 ustar 00root root 0000000 0000000 atlas-0.7.2/cmd/atlas/ 0000775 0000000 0000000 00000000000 14314555116 0014500 5 ustar 00root root 0000000 0000000 atlas-0.7.2/cmd/atlas/doc.go 0000664 0000000 0000000 00000002520 14314555116 0015573 0 ustar 00root root 0000000 0000000 // Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
//go:build ignore
// +build ignore
package main
import (
"log"
"os"
"strings"
"text/template"
"ariga.io/atlas/cmd/atlas/internal/cmdapi"
"github.com/spf13/cobra"
)
func main() {
f, err := os.Create("../../doc/md/reference.md")
if err != nil {
log.Fatal(err)
}
t, err := template.New("").
Funcs(template.FuncMap{
"header": func(depth int) string {
return strings.Repeat("#", depth+1)
},
"subheader": func(depth int) string {
return strings.Repeat("#", depth+2)
},
}).
ParseFiles("doc.tmpl")
if err != nil {
log.Fatal(err)
}
if err := t.ExecuteTemplate(f, "header", nil); err != nil {
log.Fatal(err)
}
blocks := prepare(cmdapi.Root, make([]*block, 0), 0)
if err := t.ExecuteTemplate(f, "body", struct {
Blocks []*block
}{Blocks: blocks}); err != nil {
log.Fatal(err)
}
}
type block struct {
Depth int
*cobra.Command
}
func prepare(cmd *cobra.Command, existing []*block, depth int) []*block {
if depth > 0 {
existing = append(existing, &block{
Depth: depth,
Command: cmd,
})
}
for _, child := range cmd.Commands() {
existing = prepare(child, existing, depth+1)
}
return existing
}
atlas-0.7.2/cmd/atlas/doc.tmpl 0000664 0000000 0000000 00000002404 14314555116 0016143 0 ustar 00root root 0000000 0000000 {{- define "header" -}}
---
title: CLI Reference
id: cli-reference
slug: cli-reference
---
{{- end }}
{{ define "body" }}
## Introduction
This document serves as reference documentation for all available commands in the Atlas CLI.
Similar information can be obtained by running any atlas command with the `-h` or `--help`
flags.
For a more detailed introduction to the CLI capabilities, head over to the
[Getting Started](/getting-started/) page.
## Distributed Binaries
The binaries distributed in official releases are released under the [Ariga End User License](https://ariga.io/legal/atlas/eula).
If you would like to build Atlas from source follow the instructions [here](https://atlasgo.io/cli-reference#building-from-source).
### Building from Source
If you would like to build Atlas from source without the UI code run:
```shell
go get ariga.io/atlas/cmd/atlas
```
{{ range .Blocks }}
{{ header .Depth }} {{ .CommandPath }}
{{ .Short }}
{{- if .UseLine }}
#### Usage
```
{{ .UseLine }}
```
{{- end }}
{{- if .Long }}
#### Details
{{ .Long }}
{{- end }}
{{ if .Example }}
#### Example
```
{{ .Example }}
```
{{- end }}
{{- $flags := .NonInheritedFlags }}
{{- if $flags.HasAvailableFlags }}
#### Flags
```
{{ $flags.FlagUsages }}
```
{{ end }}
{{ end }}
{{ end }}
atlas-0.7.2/cmd/atlas/generate.go 0000664 0000000 0000000 00000000362 14314555116 0016622 0 ustar 00root root 0000000 0000000 // Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package main
//go:generate go run doc.go
atlas-0.7.2/cmd/atlas/go.mod 0000664 0000000 0000000 00000006222 14314555116 0015610 0 ustar 00root root 0000000 0000000 module ariga.io/atlas/cmd/atlas
go 1.18
require (
ariga.io/atlas v0.7.1-0.20220925103247-db83ea0cd178
entgo.io/ent v0.11.1
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20220816024939-bc8df83d7b9d
github.com/auxten/postgresql-parser v1.0.1
github.com/fatih/color v1.13.0
github.com/go-sql-driver/mysql v1.6.0
github.com/hashicorp/hcl/v2 v2.13.0
github.com/lib/pq v1.10.6
github.com/manifoldco/promptui v0.9.0
github.com/mattn/go-sqlite3 v1.14.14
github.com/mitchellh/go-homedir v1.1.0
github.com/pingcap/tidb/parser v0.0.0-20220817134052-9709249e523a
github.com/spf13/cobra v1.5.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.8.0
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57
)
require (
github.com/agext/levenshtein v1.2.1 // indirect
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 // indirect
github.com/chzyer/readline v1.5.1 // indirect
github.com/cockroachdb/apd v1.1.1-0.20181017181144-bced77f817b4 // indirect
github.com/cockroachdb/errors v1.8.2 // indirect
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f // indirect
github.com/cockroachdb/redact v1.0.8 // indirect
github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 // indirect
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/getsentry/raven-go v0.2.0 // indirect
github.com/go-openapi/inflect v0.19.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.4.3 // indirect
github.com/google/go-cmp v0.5.6 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect
github.com/kr/pretty v0.2.0 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/mattn/go-colorable v0.1.9 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 // indirect
github.com/pingcap/log v0.0.0-20210625125904-98ed8e2eb1c7 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/sirupsen/logrus v1.6.0 // indirect
github.com/zclconf/go-cty v1.8.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.18.1 // indirect
golang.org/x/exp v0.0.0-20220428152302-39d4317da171 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 // indirect
golang.org/x/text v0.3.7 // indirect
google.golang.org/genproto v0.0.0-20200911024640-645f7a48b24f // indirect
google.golang.org/grpc v1.33.1 // indirect
google.golang.org/protobuf v1.25.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
atlas-0.7.2/cmd/atlas/go.sum 0000664 0000000 0000000 00000132125 14314555116 0015637 0 ustar 00root root 0000000 0000000 ariga.io/atlas v0.6.4-0.20220830111134-f2d233c99aa1 h1:/8U7e/qiVREcJHKltZptJoa10gltLcUBVlcqU8gk1V8=
ariga.io/atlas v0.6.4-0.20220830111134-f2d233c99aa1/go.mod h1:ft47uSh5hWGDCmQC9DsztZg6Xk+KagM5Ts/mZYKb9JE=
ariga.io/atlas v0.6.4-0.20220831192411-1e893f70cbe8 h1:BmgIAqhnFoem+8/jhVAwm+YDRdfeMgcrbOxf/6+3Teg=
ariga.io/atlas v0.6.4-0.20220831192411-1e893f70cbe8/go.mod h1:ft47uSh5hWGDCmQC9DsztZg6Xk+KagM5Ts/mZYKb9JE=
ariga.io/atlas v0.6.5-0.20220907135005-d80f5e6b79cf h1:sqRKqa3gdunWKmv4G7FC0j4ROKJ8rG+6YoMBPTVGlxo=
ariga.io/atlas v0.6.5-0.20220907135005-d80f5e6b79cf/go.mod h1:ft47uSh5hWGDCmQC9DsztZg6Xk+KagM5Ts/mZYKb9JE=
ariga.io/atlas v0.7.0 h1:daEFdUsyNm7EHyzcMfjWwq/fVv48fCfad+dIGyobY1k=
ariga.io/atlas v0.7.0/go.mod h1:ft47uSh5hWGDCmQC9DsztZg6Xk+KagM5Ts/mZYKb9JE=
ariga.io/atlas v0.7.1-0.20220925103247-db83ea0cd178 h1:/fhqvnyyi4h5epqhIsDQW9NLkklDnQ0GRgQqfUhl9Pw=
ariga.io/atlas v0.7.1-0.20220925103247-db83ea0cd178/go.mod h1:ft47uSh5hWGDCmQC9DsztZg6Xk+KagM5Ts/mZYKb9JE=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
entgo.io/ent v0.11.1 h1:im67R+2W3Nee2bNS2YnoYz8oAF0Qz4AOlIvKRIAEISY=
entgo.io/ent v0.11.1/go.mod h1:X5b1YfMayrRTgKGO//8IqpL7XJx0uqdeReEkxNpXROA=
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw=
github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w=
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM=
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8=
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20220816024939-bc8df83d7b9d h1:0xIrH2lJbraclvJT3pvTf3u2oCAL60cAqiv4qRpz4EI=
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20220816024939-bc8df83d7b9d/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/auxten/postgresql-parser v1.0.1 h1:x+qiEHAe2cH55Kly64dWh4tGvUKEQwMmJgma7a1kbj4=
github.com/auxten/postgresql-parser v1.0.1/go.mod h1:Nf27dtv8EU1C+xNkoLD3zEwfgJfDDVi8Zl86gznxPvI=
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI=
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM=
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04=
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cockroachdb/apd v1.1.1-0.20181017181144-bced77f817b4 h1:XWEdfNxDkZI3DXXlpo0hZJ1xdaH/f3CKuZpk93pS/Y0=
github.com/cockroachdb/apd v1.1.1-0.20181017181144-bced77f817b4/go.mod h1:mdGz2CnkJrefFtlLevmE7JpL2zB9tKofya/6w7wWzNA=
github.com/cockroachdb/datadriven v1.0.0/go.mod h1:5Ib8Meh+jk1RlHIXej6Pzevx/NLlNvQB9pmSBZErGA4=
github.com/cockroachdb/errors v1.6.1/go.mod h1:tm6FTP5G81vwJ5lC0SizQo374JNCOPrHyXGitRJoDqM=
github.com/cockroachdb/errors v1.8.2 h1:rnnWK9Nn5kEMOGz9531HuDx/FOleL4NVH20VsDexVC8=
github.com/cockroachdb/errors v1.8.2/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac=
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY=
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
github.com/cockroachdb/redact v1.0.8 h1:8QG/764wK+vmEYoOlfobpe12EQcS81ukx/a4hdVMxNw=
github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 h1:IKgmqgMQlVJIZj19CdocBeSfSaiCbEBZGKODaixqtHM=
github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ=
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 h1:iwZdTE0PVqJCos1vaoKsclOGD3ADKpshg3SRtYBbwso=
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
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/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs=
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4=
github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/hcl/v2 v2.13.0 h1:0Apadu1w6M11dyGFxWnmhhcMjkbAiKCv7G1r/2QgCNc=
github.com/hashicorp/hcl/v2 v2.13.0/go.mod h1:e4z5nxYlWNPdDSNYX+ph14EvWYMFm3eP0zIUqPc2jr0=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE=
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI=
github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0=
github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI=
github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk=
github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U=
github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw=
github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4=
github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g=
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs=
github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-sqlite3 v1.14.14 h1:qZgc/Rwetq+MtyE18WhzjokPD93dNqLGNT3QJuLvBGw=
github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg=
github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ=
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM=
github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ=
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o=
github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 h1:+FZIDR/D97YOPik4N4lPDaUcLDF/EQPogxtlHB2ZZRM=
github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63/go.mod h1:X2r9ueLEUZgtx2cIogM0v4Zj5uvvzhuuiu7Pn8HzMPg=
github.com/pingcap/log v0.0.0-20210625125904-98ed8e2eb1c7 h1:k2BbABz9+TNpYRwsCCFS8pEEnFVOdbgEjL/kTlLuzZQ=
github.com/pingcap/log v0.0.0-20210625125904-98ed8e2eb1c7/go.mod h1:8AanEdAHATuRurdGxZXBz0At+9avep+ub7U1AGYLIMM=
github.com/pingcap/tidb/parser v0.0.0-20220817134052-9709249e523a h1:KhEhzJLyVSFT13yk/M2BQ7eE6Ofs7jBnALjc0ICZbsQ=
github.com/pingcap/tidb/parser v0.0.0-20220817134052-9709249e523a/go.mod h1:wjvp+T3/T9XYt0nKqGX3Kc1AKuyUcfno6LTc6b2A6ew=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
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 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/zclconf/go-cty v1.8.0 h1:s4AvqaeQzJIu3ndv4gVIhplVD0krU+bgrcLSVUnaWuA=
github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.18.1 h1:CSUJ2mjFszzEWt4CdKISEuChVIXGBn3lAPwkRGyVrc4=
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20220428152302-39d4317da171 h1:TfdoLivD44QwvssI9Sv1xwa5DcL5XQr4au4sZ2F2NV4=
golang.org/x/exp v0.0.0-20220428152302-39d4317da171/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
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.20211013180041-c96bc1413d57 h1:LQmS1nU0twXLA96Kt7U9qtHJEbBk3z6Q0V4UXjZkpr4=
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
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-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY=
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.9-0.20211216111533-8d383106f7e7 h1:M1gcVrIb2lSn2FIL19DG0+/b8nNVKJ7W7b4WcAGZAYM=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200911024640-645f7a48b24f h1:Yv4xsIx7HZOoyUGSJ2ksDyWE2qIBXROsZKt2ny3hCGM=
google.golang.org/genproto v0.0.0-20200911024640-645f7a48b24f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.33.1 h1:DGeFlSan2f+WEtCERJ4J9GJWk15TxUi8QGagfI87Xyc=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
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=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
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-20200615113413-eeeca48fe776/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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
atlas-0.7.2/cmd/atlas/go.work 0000664 0000000 0000000 00000000067 14314555116 0016014 0 ustar 00root root 0000000 0000000 go 1.18
use (
./
)
replace ariga.io/atlas => ../../
atlas-0.7.2/cmd/atlas/go.work.sum 0000664 0000000 0000000 00000033547 14314555116 0016630 0 ustar 00root root 0000000 0000000 cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg=
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9 h1:HD8gA2tkByhMAwYaFAX9w2l7vxvBQ5NMoxDrkhqhtn4=
github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a h1:3SgJcK9l5uPdBC/X17wanyJAMxM33+4ZhEIV96MIH8U=
github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible h1:rZgFj+Gtf3NMi/U5FvCvhzaxzW/TaPYgUYx3bAPz9DE=
github.com/Joker/hpp v1.0.0 h1:65+iuJYdRXv/XyN62C1uEmmOx3432rNG/rKlX6V7Kkc=
github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7 h1:mreN1m/5VJ/Zc3b4pzj9qU6D9SRQ6Vm+3KfI328t3S8=
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398 h1:WDC6ySpJzbxGWFh4aMxFFC28wwGp5pEuoTtvA4q/qQ4=
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg=
github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3 h1:ZSTrOEhiM5J5RFxEaFvMZVEAM1KvT1YzbEOwB2EAGjA=
github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 h1:G1bPvciwNyF7IUmKXNt9Ak3m6u9DE1rF+RmtIkBpVdA=
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible h1:Ppm0npCCsmuR9oQaBtRuZcmILVE74aXE+AmrJj8L2ns=
github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f h1:WBZRG4aNOuI15bLRrCgN8fCq8E5Xuty6jGbmSNEvSsU=
github.com/cockroachdb/datadriven v1.0.0 h1:uhZrAfEayBecH2w2tZmhe20HJ7hDvrrA4x2Bg9YdZKM=
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q=
github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04=
github.com/coreos/go-etcd v2.0.0+incompatible h1:bXhRBIXoTm9BYHS3gE0TtQuyNZyeEMux2sDi4oo5YOo=
github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY=
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
github.com/cznic/sortutil v0.0.0-20181122101858-f5f958428db8 h1:LpMLYGyy67BoAFGda1NeOBQwqlv7nUXpm+rIVHGxZZ4=
github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186 h1:0rkFMAbn5KBKNpJyHQ6Prb95vIKanmAe62KxsrN+sqA=
github.com/dgraph-io/badger v1.6.0 h1:DshxFxZWXUcO0xX476VJC07Xsr6ZCBVRHKZ93Oh7Evo=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o=
github.com/envoyproxy/go-control-plane v0.9.4 h1:rEvIZUSZ3fx39WIi3JkQqQBitGwpELBIYWeBVh6wn+E=
github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=
github.com/etcd-io/bbolt v1.3.3 h1:gSJmxrs37LgTqR/oyJBWok6k6SvXEUerFTbltIhXkBM=
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072 h1:DddqAaWDpywytcG8w/qoQ5sAN8X12d3Z3koB0C3Rxsc=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4 h1:GY1+t5Dr9OKADM64SYnQjw/w99HMYvQ0A8/JoUkxVmc=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/gavv/httpexpect v2.0.0+incompatible h1:1X9kcRshkSKEjNJJxX9Y9mQ5BRfbxU5kORdjhlA1yX8=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 h1:t8FVkw33L+wilf2QiWkw0UV77qRpcH/JHPKGpKa2E8g=
github.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ=
github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI=
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab h1:xveKWz2iaueeTaUgdetzel+U7exyigDYBryyVfV/rZk=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a h1:dR8+Q0uO5S2ZBcs2IH6VBKYwSxPo2vYCYq0ot0mu7xA=
github.com/gogo/status v1.1.0 h1:+eIkrewn5q6b30y+g/BJINVVdi2xH7je5MPJ3ZPK3JA=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/mock v1.1.1 h1:G5FRp8JnTd7RQH5kemVNlMeyXQAztQ3mOWV95KxsXH8=
github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38 h1:y0Wmhvml7cGnzPa9nocn/fMraMH/lMDdeG+rkx4VgYY=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb h1:EPRgaDqXpLFUJLXZdGLnBTy1l6CLiNAPnvn2l+kHit0=
github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk=
github.com/iris-contrib/blackfriday v2.0.0+incompatible h1:o5sHQHHm0ToHUlAJSTjW9UWicjJSDDauOOQ2AHuIVp4=
github.com/iris-contrib/go.uuid v2.0.0+incompatible h1:XZubAYg61/JwnJNbZilGjf3b3pB80+OQg2qf6c8BfWE=
github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0 h1:Kyp9KiXwsyZRTeoNjgVCrWks7D8ht9+kg6yCjh8K97o=
github.com/iris-contrib/schema v0.0.1 h1:10g/WnoRR+U+XXHWKBHeNy/+tZmM2kcAVGLOsz+yaDA=
github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5 h1:rhqTjzJlm7EbkELJDKMTU7udov+Se0xZkWmugr6zGok=
github.com/juju/loggo v0.0.0-20180524022052-584905176618 h1:MK144iBQF9hTSwBW/9eJm034bVoG30IshVm688T2hi8=
github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073 h1:WQM1NildKThwdP7qWrNAFGzp4ijNLw8RlgENkaI4MJs=
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM=
github.com/kataras/golog v0.0.9 h1:J7Dl82843nbKQDrQM/abbNJZvQjS6PfmkkffhOTXEpM=
github.com/kataras/iris/v12 v12.0.1 h1:Wo5S7GMWv5OAzJmvFTvss/C4TS1W0uo6LkDlSymT4rM=
github.com/kataras/neffos v0.0.10 h1:O06dvQlxjdWvzWbm2Bq+Si6psUhvSmEctAMk9Xujqms=
github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d h1:V5Rs9ztEWdp58oayPq/ulmlqJJZeJP6pP79uP3qjcao=
github.com/kisielk/errcheck v1.5.0 h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHzY=
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
github.com/klauspost/compress v1.9.0 h1:GhthINjveNZAdFUD8QoQYfjxnOONZgztK/Yr6M23UTY=
github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w=
github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
github.com/labstack/echo/v4 v4.1.11 h1:z0BZoArY4FqdpUEl+wlHp4hnr/oSR6MTmQmv8OHSoww=
github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/goveralls v0.0.2 h1:7eJB6EqsPhRVxvwEXGnqdO2sJI0PTsrWoTMXEk9/OQc=
github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed h1:3dQJqqDouawQgl3gBE1PNHKFkJYGEuFb1DbSlaxdosE=
github.com/mediocregopher/radix/v3 v3.3.0 h1:oacPXPKHJg0hcngVVrdtTnfGJiS+PtwoQwTBZGFlV4k=
github.com/microcosm-cc/bluemonday v1.0.2 h1:5lPfLTTAvAbtS0VqT+94yOtFnGfUWYyx0+iToC3Os3s=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs=
github.com/nats-io/nats.go v1.8.1 h1:6lF/f1/NN6kzUDBz6pyvQDEXO39jqXcWRLu/tKjtOUQ=
github.com/nats-io/nkeys v0.0.2 h1:+qM7QpgXnvDDixitZtQUBDY9w/s9mu1ghS+JIbsrx6M=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/onsi/ginkgo v1.13.0 h1:M76yO2HkZASFjXL0HSoZJ1AYEmQxNJmY41Jx1zNUq1Y=
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/ryanuber/columnize v2.1.0+incompatible h1:j1Wcmh8OrK4Q7GXY+V7SVSY8nUWQxHW5TkBe7YUl+2s=
github.com/sclevine/agouti v3.0.0+incompatible h1:8IBJS6PWz3uTlMP3YBIR5f+KAldcGuOeFkFbUWfBgK4=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M=
github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8 h1:3SVOIvH7Ae1KRYyQWRjXWJEA9sS/c/pjvH++55Gr648=
github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/fasthttp v1.6.0 h1:uWF8lgKmeaIewWVPwi4GRq2P6+R46IgYZdxWtM+GtEY=
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a h1:0R4NLDRDZX6JcmhJgXi5E4b8Wg84ihbmUKp/GvSPEzc=
github.com/vmihailenco/msgpack/v4 v4.3.12 h1:07s4sz9IReOgdikxLTKNbBdqDMLsjPKXwvCazn8G65U=
github.com/vmihailenco/tagparser v0.1.1 h1:quXMXlA39OCbd2wAdTsGDlK9RkOk6Wuw+x37wVyIuWY=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77 h1:ESFSdwYZvkeru3RtdrYueztKhOBCSAAzS4Gf+k0tEow=
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY=
github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI=
github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM=
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b h1:FosyBZYxY34Wul7O/MSKey3txpPYyCqVO5ZyceuQJEI=
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
golang.org/x/crypto v0.0.0-20220517005047-85d78b3ac167 h1:O8uGbHCqlTp2P6QJSLmCojM4mN6UemYv8K+dCnmHmu0=
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 h1:LQmS1nU0twXLA96Kt7U9qtHJEbBk3z6Q0V4UXjZkpr4=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/tools v0.1.9-0.20211216111533-8d383106f7e7 h1:M1gcVrIb2lSn2FIL19DG0+/b8nNVKJ7W7b4WcAGZAYM=
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce h1:xcEWjVhvbDy+nHP67nPDDpbYrY+ILlfndk4bRioVHaU=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc h1:/hemPrYIhOhy8zYrNj+069zDB68us2sMGsfkFJO0iZs=
modernc.org/golex v1.0.1 h1:EYKY1a3wStt0RzHaH8mdSRNg78Ub0OHxYfCRWw35YtM=
modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8=
modernc.org/parser v1.0.2 h1:/qHLDn1ezrcRk9/XbErYp84bPPM4+w0kIDuvMdRk6Vc=
modernc.org/sortutil v1.0.0 h1:SUTM1sCR0Ldpv7dbB/KCPC2zHHsZ1KrSkhmGmmV22CQ=
modernc.org/strutil v1.1.0 h1:+1/yCzZxY2pZwwrsbH+4T7BQMoLQ9QiBshRC9eicYsc=
modernc.org/y v1.0.1 h1:+QT+MtLkwkvLkh3fYQq+YD5vw2s5paVE73jdl5R/Py8=
atlas-0.7.2/cmd/atlas/internal/ 0000775 0000000 0000000 00000000000 14314555116 0016314 5 ustar 00root root 0000000 0000000 atlas-0.7.2/cmd/atlas/internal/cmdapi/ 0000775 0000000 0000000 00000000000 14314555116 0017551 5 ustar 00root root 0000000 0000000 atlas-0.7.2/cmd/atlas/internal/cmdapi/cmdapi.go 0000664 0000000 0000000 00000010634 14314555116 0021341 0 ustar 00root root 0000000 0000000 // Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
// Package cmdapi holds the atlas commands used to build
// an atlas distribution.
package cmdapi
import (
"fmt"
"os"
"strings"
"ariga.io/atlas/cmd/atlas/internal/update"
"github.com/spf13/cobra"
"golang.org/x/mod/semver"
)
var (
// Root represents the root command when called without any subcommands.
Root = &cobra.Command{
Use: "atlas",
Short: "A database toolkit.",
SilenceUsage: true,
}
// GlobalFlags contains flags common to many Atlas sub-commands.
GlobalFlags struct {
// SelectedEnv contains the environment selected from the active
// project via the --env flag.
SelectedEnv string
// Vars contains the input variables passed from the CLI to
// Atlas DDL or project files.
Vars map[string]string
}
// version holds Atlas version. When built with cloud packages
// should be set by build flag. "-X 'ariga.io/atlas/cmd/atlas/internal/cmdapi.version=${version}'"
version string
// schemaCmd represents the subcommand 'atlas version'.
versionCmd = &cobra.Command{
Use: "version",
Short: "Prints this Atlas CLI version information.",
Run: func(cmd *cobra.Command, args []string) {
v, u := parse(version)
Root.Printf("atlas version %s\n%s\n", v, u)
},
}
// EnvCmd represents the subcommand 'atlas env'.
EnvCmd = &cobra.Command{
Use: "env",
Short: "Print atlas environment variables.",
Long: `'atlas env' prints atlas environment information.
Every set environment param will be printed in the form of NAME=VALUE.
List of supported environment parameters:
* ATLAS_NO_UPDATE_NOTIFIER: On any command, the CLI will check for new releases using the GitHub API.
This check will happen at most once every 24 hours. To cancel this behavior, set the environment
variable "ATLAS_NO_UPDATE_NOTIFIER".`,
Run: func(cmd *cobra.Command, args []string) {
keys := []string{update.AtlasNoUpdateNotifier}
for _, k := range keys {
if v, ok := os.LookupEnv(k); ok {
cmd.Println(fmt.Sprintf("%s=%s", k, v))
}
}
},
}
// license holds Atlas license. When built with cloud packages
// should be set by build flag. "-X 'ariga.io/atlas/cmd/atlas/internal/cmdapi.license=${license}'"
license = `LICENSE
Atlas is licensed under Apache 2.0 as found in https://github.com/ariga/atlas/blob/master/LICENSE.`
licenseCmd = &cobra.Command{
Use: "license",
Short: "Display license information",
Run: func(cmd *cobra.Command, _ []string) {
cmd.Println(license)
},
}
)
// CheckForUpdate exposes internal update logic to CLI.
func CheckForUpdate() {
update.Check(version, Root.PrintErrln)
}
func init() {
Root.AddCommand(EnvCmd)
Root.AddCommand(schemaCmd)
Root.AddCommand(versionCmd)
Root.AddCommand(licenseCmd)
}
// receivesEnv configures cmd to receive the common '--env' flag.
func receivesEnv(cmd *cobra.Command) {
cmd.PersistentFlags().StringVarP(&GlobalFlags.SelectedEnv, "env", "", "", "set which env from the project file to use")
cmd.PersistentFlags().StringToStringVarP(&GlobalFlags.Vars, varFlag, "", nil, "input variables")
}
// inputValsFromEnv populates GlobalFlags.Vars from the active environment. If we are working
// inside a project, the "var" flag is not propagated to the schema definition. Instead, it
// is used to evaluate the project file which can pass input values via the "values" block
// to the schema.
func inputValsFromEnv(cmd *cobra.Command) error {
activeEnv, err := selectEnv(GlobalFlags.SelectedEnv)
if err != nil {
return err
}
if fl := cmd.Flag(varFlag); fl == nil {
return nil
}
values, err := activeEnv.asMap()
if err != nil {
return err
}
if len(values) == 0 {
return nil
}
pairs := make([]string, 0, len(values))
for k, v := range values {
pairs = append(pairs, fmt.Sprintf("%s=%s", k, v))
}
vars := strings.Join(pairs, ",")
if err := cmd.Flags().Set(varFlag, vars); err != nil {
return err
}
return nil
}
// parse returns a user facing version and release notes url
func parse(version string) (string, string) {
u := "https://github.com/ariga/atlas/releases/latest"
if ok := semver.IsValid(version); !ok {
return "- development", u
}
s := strings.Split(version, "-")
if len(s) != 0 && s[len(s)-1] != "canary" {
u = fmt.Sprintf("https://github.com/ariga/atlas/releases/tag/%s", version)
}
return version, u
}
atlas-0.7.2/cmd/atlas/internal/cmdapi/cmdapi_test.go 0000664 0000000 0000000 00000003664 14314555116 0022405 0 ustar 00root root 0000000 0000000 // Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package cmdapi
import (
"bytes"
"os"
"os/exec"
"testing"
"ariga.io/atlas/cmd/atlas/internal/update"
"github.com/stretchr/testify/require"
)
func TestEnv(t *testing.T) {
out, err := runCmd(Root, "env")
require.NoError(t, err)
require.Empty(t, out)
}
func TestEnv_Set(t *testing.T) {
err := os.Setenv(update.AtlasNoUpdateNotifier, "test")
require.NoError(t, err)
out, err := runCmd(Root, "env")
require.NoError(t, err)
require.Equal(t, "ATLAS_NO_UPDATE_NOTIFIER=test\n", out)
}
func TestCLI_Version(t *testing.T) {
// Required to have a clean "stderr" while running first time.
tests := []struct {
name string
cmd *exec.Cmd
expected string
}{
{
name: "dev mode",
cmd: exec.Command("go", "run", "ariga.io/atlas/cmd/atlas",
"version",
),
expected: "atlas version - development\nhttps://github.com/ariga/atlas/releases/latest\n",
},
{
name: "release",
cmd: exec.Command("go", "run",
"-ldflags",
"-X ariga.io/atlas/cmd/atlas/internal/cmdapi.version=v1.2.3",
"ariga.io/atlas/cmd/atlas",
"version",
),
expected: "atlas version v1.2.3\nhttps://github.com/ariga/atlas/releases/tag/v1.2.3\n",
},
{
name: "canary",
cmd: exec.Command("go", "run",
"-ldflags",
"-X ariga.io/atlas/cmd/atlas/internal/cmdapi.version=v0.3.0-6539f2704b5d-canary",
"ariga.io/atlas/cmd/atlas",
"version",
),
expected: "atlas version v0.3.0-6539f2704b5d-canary\nhttps://github.com/ariga/atlas/releases/latest\n",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Setenv("ATLAS_NO_UPDATE_NOTIFIER", "true")
stdout := bytes.NewBuffer(nil)
tt.cmd.Stdout = stdout
require.NoError(t, tt.cmd.Run())
require.Equal(t, tt.expected, stdout.String())
})
}
}
atlas-0.7.2/cmd/atlas/internal/cmdapi/diff.go 0000664 0000000 0000000 00000006267 14314555116 0021023 0 ustar 00root root 0000000 0000000 // Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package cmdapi
import (
"fmt"
"strings"
"ariga.io/atlas/sql/schema"
"ariga.io/atlas/sql/sqlclient"
"github.com/spf13/cobra"
)
type diffCmdOpts struct {
fromURL string
toURL string
}
// newDiffCmd returns a new *cobra.Command that runs cmdDiffRun with the given flags and mux.
func newDiffCmd() *cobra.Command {
var opts diffCmdOpts
cmd := &cobra.Command{
Use: "diff",
Short: "Calculate and print the diff between two schemas.",
Long: `'atlas schema diff' connects to two given databases, inspects
them, calculates the difference in their schemas, and prints a plan of
SQL statements to migrate the "from" database to the schema of the "to" database.`,
Run: func(cmd *cobra.Command, args []string) {
cmdDiffRun(cmd, &opts)
},
}
cmd.Flags().StringVarP(&opts.fromURL, "from", "", "", "[driver://username:password@protocol(address)/dbname?param=value] select a database using the URL format")
cmd.Flags().StringVarP(&opts.toURL, "to", "", "", "[driver://username:password@protocol(address)/dbname?param=value] select a database using the URL format")
cobra.CheckErr(cmd.MarkFlagRequired("from"))
cobra.CheckErr(cmd.MarkFlagRequired("to"))
return cmd
}
func init() {
diffCmd := newDiffCmd()
schemaCmd.AddCommand(diffCmd)
}
// cmdDiffRun connects to the given databases, and prints an SQL plan to get from
// the "from" schema to the "to" schema.
func cmdDiffRun(cmd *cobra.Command, flags *diffCmdOpts) {
ctx := cmd.Context()
fromC, err := sqlclient.Open(cmd.Context(), flags.fromURL)
cobra.CheckErr(err)
defer fromC.Close()
toC, err := sqlclient.Open(cmd.Context(), flags.toURL)
cobra.CheckErr(err)
defer toC.Close()
fromS := fromC.URL.Schema
toS := toC.URL.Schema
var diff []schema.Change
switch {
case fromS == "" && toS == "":
// compare realm.
fromRealm, err := fromC.InspectRealm(ctx, nil)
cobra.CheckErr(err)
toRealm, err := toC.InspectRealm(ctx, nil)
cobra.CheckErr(err)
diff, err = toC.RealmDiff(fromRealm, toRealm)
cobra.CheckErr(err)
case fromS == "":
cobra.CheckErr(fmt.Errorf("cannot diff schema %q with a database connection", fromS))
case toS == "":
cobra.CheckErr(fmt.Errorf("cannot diff database connection with a schema %q", toS))
default:
// compare schemas.
fromSchema, err := fromC.InspectSchema(ctx, fromS, nil)
cobra.CheckErr(err)
toSchema, err := toC.InspectSchema(ctx, toS, nil)
cobra.CheckErr(err)
// SchemaDiff checks for name equality which is irrelevant in the case
// the user wants to compare their contents, if the names are different
// we reset them to allow the comparison.
if fromS != toS {
toSchema.Name = ""
fromSchema.Name = ""
}
diff, err = toC.SchemaDiff(fromSchema, toSchema)
cobra.CheckErr(err)
}
p, err := toC.PlanChanges(ctx, "plan", diff)
cobra.CheckErr(err)
if len(p.Changes) == 0 {
cmd.Println("Schemas are synced, no changes to be made.")
return
}
for _, c := range p.Changes {
if c.Comment != "" {
cmd.Println("--", strings.ToUpper(c.Comment[:1])+c.Comment[1:])
}
cmd.Println(c.Cmd)
}
}
atlas-0.7.2/cmd/atlas/internal/cmdapi/diff_test.go 0000664 0000000 0000000 00000003453 14314555116 0022054 0 ustar 00root root 0000000 0000000 // Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package cmdapi
import (
"bytes"
"context"
"database/sql"
"fmt"
"os"
"testing"
"ariga.io/atlas/sql/sqlite"
_ "github.com/mattn/go-sqlite3"
"github.com/spf13/cobra"
"github.com/stretchr/testify/require"
)
func TestDiffCmd_Diff(t *testing.T) {
from := openSQLite(t, "")
to := openSQLite(t, "create table t1 (id int);")
cmd := newDiffCmd()
s, err := runCmd(cmd, "schema", "diff", "--from", from, "--to", to)
require.NoError(t, err)
require.EqualValues(t, "-- Create \"t1\" table\nCREATE TABLE `t1` (`id` int NULL)\n", s)
}
func TestDiffCmd_Synced(t *testing.T) {
from := openSQLite(t, "")
to := openSQLite(t, "")
cmd := newDiffCmd()
s, err := runCmd(cmd, "schema", "diff", "--from", from, "--to", to)
require.NoError(t, err)
require.EqualValues(t, "Schemas are synced, no changes to be made.\n", s)
}
// openSQLite creates a sqlite db, seeds it with the seed query and returns the url to it.
func openSQLite(t *testing.T, seed string) string {
f, err := os.CreateTemp("", "sqlite.db")
require.NoError(t, err)
t.Cleanup(func() {
os.Remove(f.Name())
})
dsn := fmt.Sprintf("file:%s?cache=shared&_fk=1", f.Name())
db, err := sql.Open("sqlite3", dsn)
require.NoError(t, err)
t.Cleanup(func() {
db.Close()
})
drv, err := sqlite.Open(db)
require.NoError(t, err)
if len(seed) > 0 {
_, err := drv.ExecContext(context.Background(), seed)
require.NoError(t, err)
}
return fmt.Sprintf("sqlite://%s", dsn)
}
func runCmd(cmd *cobra.Command, args ...string) (string, error) {
var out bytes.Buffer
cmd.SetOut(&out)
cmd.SetErr(&out)
cmd.SetArgs(args)
err := cmd.Execute()
return out.String(), err
}
atlas-0.7.2/cmd/atlas/internal/cmdapi/migrate.go 0000664 0000000 0000000 00000145126 14314555116 0021541 0 ustar 00root root 0000000 0000000 // Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package cmdapi
import (
"context"
"database/sql"
"errors"
"fmt"
"io"
"io/fs"
"os"
"path/filepath"
"strconv"
"strings"
"text/template"
"time"
"ariga.io/atlas/cmd/atlas/internal/lint"
entmigrate "ariga.io/atlas/cmd/atlas/internal/migrate"
"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/schema"
"ariga.io/atlas/sql/sqlcheck"
"ariga.io/atlas/sql/sqlclient"
"ariga.io/atlas/sql/sqltool"
"github.com/fatih/color"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclparse"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
const (
migrateFlagURL = "url"
migrateFlagDevURL = "dev-url"
migrateFlagDir = "dir"
migrateFlagDirFormat = "dir-format"
migrateFlagLog = "log"
migrateFlagRevisionsSchema = "revisions-schema"
migrateFlagDryRun = "dry-run"
migrateFlagTo = "to"
migrateFlagFrom = "from"
migrateFlagSchema = "schema"
migrateLintLatest = "latest"
migrateLintGitDir = "git-dir"
migrateLintGitBase = "git-base"
migrateDiffQualifier = "qualifier"
migrateApplyAllowDirty = "allow-dirty"
migrateApplyBaselineVersion = "baseline"
migrateApplyTxMode = "tx-mode"
)
var (
// MigrateFlags are the flags used in MigrateCmd (and sub-commands).
MigrateFlags struct {
URL string
DevURL string
ToURLs []string
Schemas []string
DirURL string
DirFormat string
RevisionSchema string
Apply struct {
DryRun bool
LogFormat string
AllowDirty bool
FromVersion string
BaselineVersion string
TxMode string
}
Diff struct {
Qualifier string // optional table qualifier
}
Import struct {
FromURL string
ToURL string
}
Lint struct {
Format string // log formatting
Latest uint // latest N migration files
GitDir string // repository working dir
GitBase string // branch name to compare with
}
}
// MigrateCmd represents the migrate command. It wraps several other sub-commands.
MigrateCmd = &cobra.Command{
Use: "migrate",
Short: "Manage versioned migration files",
Long: "'atlas migrate' wraps several sub-commands for migration management.",
PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
if err := migrateFlagsFromEnv(cmd, nil); err != nil {
return err
}
dir, err := dir(false)
if err != nil {
return err
}
if err := migrate.Validate(dir); err != nil {
printChecksumErr(cmd.OutOrStderr())
cmd.SilenceUsage = true
return err
}
return nil
},
}
// MigrateApplyCmd represents the 'atlas migrate apply' subcommand.
MigrateApplyCmd = &cobra.Command{
Use: "apply [flags] [count]",
Short: "Applies pending migration files on the connected database.",
Long: `'atlas migrate apply' reads the migration state of the connected database and computes what migrations are pending.
It then attempts to apply the pending migration files in the correct order onto the database.
The first argument denotes the maximum number of migration files to apply.
As a safety measure 'atlas migrate apply' will abort with an error, if:
- the migration directory is not in sync with the 'atlas.sum' file
- the migration and database history do not match each other
If run with the "--dry-run" flag, atlas will not execute any SQL.`,
Example: ` atlas migrate apply -u mysql://user:pass@localhost:3306/dbname
atlas migrate apply --dir file:///path/to/migration/directory --url mysql://user:pass@localhost:3306/dbname 1
atlas migrate apply --env dev 1
atlas migrate apply --dry-run --env dev 1`,
Args: cobra.MaximumNArgs(1),
RunE: CmdMigrateApplyRun,
}
// MigrateDiffCmd represents the 'atlas migrate diff' subcommand.
MigrateDiffCmd = &cobra.Command{
Use: "diff [flags] [name]",
Short: "Compute the diff between the migration directory and a desired state and create a new migration file.",
Long: `'atlas migrate diff' uses the dev-database to re-run all migration files in the migration directory, compares
it to a given desired state and create a new migration file containing SQL statements to migrate the migration
directory state to the desired schema. The desired state can be another connected database or an HCL file.`,
Example: ` atlas migrate diff --dev-url mysql://user:pass@localhost:3306/dev --to file://atlas.hcl
atlas migrate diff --dev-url mysql://user:pass@localhost:3306/dev --to file://atlas.hcl add_users_table
atlas migrate diff --dev-url mysql://user:pass@localhost:3306/dev --to mysql://user:pass@localhost:3306/dbname
atlas migrate diff --env dev`,
Args: cobra.MaximumNArgs(1),
// If the migration directory does not exist on the validation attempt, this command will create it and
// consider the new migration directory "valid".
PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
if err := migrateFlagsFromEnv(cmd, nil); err != nil {
return err
}
dir, err := dir(true)
if err != nil {
return err
}
if err := migrate.Validate(dir); err != nil {
printChecksumErr(cmd.OutOrStderr())
cmd.SilenceUsage = true
return err
}
return nil
},
RunE: CmdMigrateDiffRun,
}
// MigrateHashCmd represents the 'atlas migrate hash' command.
MigrateHashCmd = &cobra.Command{
Use: "hash",
Short: "Hash (re-)creates an integrity hash file for the migration directory.",
Long: `'atlas migrate hash' computes the integrity hash sum of the migration directory and stores it in the atlas.sum file.
This command should be used whenever a manual change in the migration directory was made.`,
Example: ` atlas migrate hash`,
PersistentPreRunE: migrateFlagsFromEnv,
RunE: CmdMigrateHashRun,
}
// MigrateImportCmd represents the 'atlas migrate import' command.
MigrateImportCmd = &cobra.Command{
Use: "import",
Short: "Import a migration directory from another migration management tool to the Atlas format.",
Example: ` atlas migrate import --dir-format liquibase --from file:///path/to/source/directory --to file:///path/to/migration/directory`,
// Validate the source directory. Consider a directory with no sum file valid, since it might be an import
// from an existing project.
PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
if err := migrateFlagsFromEnv(cmd, nil); err != nil {
return err
}
MigrateFlags.DirURL = MigrateFlags.Import.FromURL
dir, err := dir(false)
if err != nil {
return err
}
if err := migrate.Validate(dir); err != nil && !errors.Is(err, migrate.ErrChecksumNotFound) {
printChecksumErr(cmd.OutOrStderr())
cmd.SilenceUsage = true
return err
}
return nil
},
RunE: CmdMigrateImportRun,
}
// MigrateNewCmd represents the 'atlas migrate new' command.
MigrateNewCmd = &cobra.Command{
Use: "new [name]",
Short: "Creates a new empty migration file in the migration directory.",
Long: `'atlas migrate new' creates a new migration according to the configured formatter without any statements in it.`,
Example: ` atlas migrate new my-new-migration`,
Args: cobra.MaximumNArgs(1),
RunE: CmdMigrateNewRun,
}
// MigrateSetCmd represents the 'atlas migrate set' command.
MigrateSetCmd = &cobra.Command{
Use: "set [flags]",
Short: "Set the current version of the migration history table.",
Long: `'atlas migrate set' edits the revision table to consider all migrations up to and including the given version
to be applied. This command is usually used after manually making changes to the managed database.`,
Example: ` atlas migrate set-revision 3 --url mysql://user:pass@localhost:3306/
atlas migrate set-revision 4 --env local
atlas migrate set-revision 1.2.4 --url mysql://user:pass@localhost:3306/my_db --revision-schema my_revisions`,
Args: cobra.ExactArgs(1),
RunE: CmdMigrateSetRun,
}
// MigrateStatusCmd represents the 'atlas migrate status' command.
MigrateStatusCmd = &cobra.Command{
Use: "status [flags]",
Short: "Get information about the current migration status.",
Long: `'atlas migrate status' reports information about the current status of a connected database compared to the migration directory.`,
Example: ` atlas migrate status --url mysql://user:pass@localhost:3306/
atlas migrate status --url mysql://user:pass@localhost:3306/ --dir file:///path/to/migration/directory`,
RunE: CmdMigrateStatusRun,
}
// MigrateValidateCmd represents the 'atlas migrate validate' command.
MigrateValidateCmd = &cobra.Command{
Use: "validate [flags]",
Short: "Validates the migration directories checksum and SQL statements.",
Long: `'atlas migrate validate' computes the integrity hash sum of the migration directory and compares it to the
atlas.sum file. If there is a mismatch it will be reported. If the --dev-url flag is given, the migration
files are executed on the connected database in order to validate SQL semantics.`,
Example: ` atlas migrate validate
atlas migrate validate --dir file:///path/to/migration/directory
atlas migrate validate --dir file:///path/to/migration/directory --dev-url mysql://user:pass@localhost:3306/dev
atlas migrate validate --env dev`,
RunE: CmdMigrateValidateRun,
}
// MigrateLintCmd represents the 'atlas migrate lint' command.
MigrateLintCmd = &cobra.Command{
Use: "lint",
Short: "Run analysis on the migration directory",
Example: ` atlas migrate lint --env dev
atlas migrate lint --dir file:///path/to/migration/directory --dev-url mysql://root:pass@localhost:3306 --latest 1
atlas migrate lint --dir file:///path/to/migration/directory --dev-url mysql://root:pass@localhost:3306 --git-base master
atlas migrate lint --dir file:///path/to/migration/directory --dev-url mysql://root:pass@localhost:3306 --log '{{ json .Files }}'`,
// Override the parent 'migrate' pre-run function to allow executing
// 'migrate lint' on directories that are not maintained by Atlas.
PersistentPreRunE: migrateFlagsFromEnv,
RunE: CmdMigrateLintRun,
}
)
func init() {
// Add sub-commands.
Root.AddCommand(MigrateCmd)
MigrateCmd.AddCommand(MigrateApplyCmd)
MigrateCmd.AddCommand(MigrateDiffCmd)
MigrateCmd.AddCommand(MigrateHashCmd)
MigrateCmd.AddCommand(MigrateNewCmd)
MigrateCmd.AddCommand(MigrateValidateCmd)
MigrateCmd.AddCommand(MigrateStatusCmd)
MigrateCmd.AddCommand(MigrateLintCmd)
MigrateCmd.AddCommand(MigrateImportCmd)
MigrateCmd.AddCommand(MigrateSetCmd)
// Reusable flags.
urlFlag := func(f *string, name, short string, set *pflag.FlagSet) {
set.StringVarP(f, name, short, "", "[driver://username:password@address/dbname?param=value] select a database using the URL format")
}
revisionsFlag := func(set *pflag.FlagSet) {
set.StringVarP(&MigrateFlags.RevisionSchema, migrateFlagRevisionsSchema, "", "", "schema name where the revisions table resides")
}
dirURLFlag := func(f *string, name, short string, set *pflag.FlagSet) {
set.StringVarP(f, name, short, "file://migrations", "select migration directory using URL format")
}
// Global flags.
dirURLFlag(&MigrateFlags.DirURL, migrateFlagDir, "", MigrateCmd.PersistentFlags())
MigrateCmd.PersistentFlags().StringSliceVarP(&MigrateFlags.Schemas, migrateFlagSchema, "", nil, "set schema names")
MigrateCmd.PersistentFlags().StringVarP(&MigrateFlags.DirFormat, migrateFlagDirFormat, "", formatAtlas, "set migration file format")
MigrateCmd.PersistentFlags().SortFlags = false
// Apply flags.
MigrateApplyCmd.Flags().StringVarP(&MigrateFlags.Apply.LogFormat, migrateFlagLog, "", logFormatTTY, "log format to use")
revisionsFlag(MigrateApplyCmd.Flags())
MigrateApplyCmd.Flags().BoolVarP(&MigrateFlags.Apply.DryRun, migrateFlagDryRun, "", false, "do not actually execute any SQL but show it on screen")
MigrateApplyCmd.Flags().StringVarP(&MigrateFlags.Apply.FromVersion, migrateFlagFrom, "", "", "calculate pending files from the given version (including it)")
MigrateApplyCmd.Flags().StringVarP(&MigrateFlags.Apply.BaselineVersion, migrateApplyBaselineVersion, "", "", "start the first migration after the given baseline version")
MigrateApplyCmd.Flags().StringVarP(&MigrateFlags.Apply.TxMode, migrateApplyTxMode, "", txModeFile, "set transaction mode [none, file, all]")
MigrateApplyCmd.Flags().BoolVarP(&MigrateFlags.Apply.AllowDirty, migrateApplyAllowDirty, "", false, "allow start working on a non-clean database")
urlFlag(&MigrateFlags.URL, migrateFlagURL, "u", MigrateApplyCmd.Flags())
MigrateApplyCmd.Flags().SortFlags = false
cobra.CheckErr(MigrateApplyCmd.MarkFlagRequired(migrateFlagURL))
MigrateApplyCmd.MarkFlagsMutuallyExclusive(migrateFlagFrom, migrateApplyBaselineVersion)
cobra.CheckErr(MigrateApplyCmd.Flags().MarkHidden(migrateFlagDirFormat))
cobra.CheckErr(MigrateApplyCmd.Flags().MarkHidden(migrateFlagSchema))
// Diff flags.
urlFlag(&MigrateFlags.DevURL, migrateFlagDevURL, "", MigrateDiffCmd.Flags())
MigrateDiffCmd.Flags().StringSliceVarP(&MigrateFlags.ToURLs, migrateFlagTo, "", nil, "[driver://username:password@address/dbname?param=value ...] select a desired state using the URL format")
MigrateDiffCmd.Flags().StringVarP(&MigrateFlags.Diff.Qualifier, migrateDiffQualifier, "", "", "qualify tables with custom qualifier when working on a single schema")
MigrateDiffCmd.Flags().SortFlags = false
cobra.CheckErr(MigrateDiffCmd.MarkFlagRequired(migrateFlagDevURL))
cobra.CheckErr(MigrateDiffCmd.MarkFlagRequired(migrateFlagTo))
// Import flags.
dirURLFlag(&MigrateFlags.Import.FromURL, migrateFlagFrom, "", MigrateImportCmd.Flags())
dirURLFlag(&MigrateFlags.Import.ToURL, migrateFlagTo, "", MigrateImportCmd.Flags())
MigrateImportCmd.Flags().SortFlags = false
// Validate flags.
urlFlag(&MigrateFlags.DevURL, migrateFlagDevURL, "", MigrateValidateCmd.Flags())
// Status flags.
urlFlag(&MigrateFlags.URL, migrateFlagURL, "u", MigrateStatusCmd.Flags())
revisionsFlag(MigrateStatusCmd.Flags())
// Set flags.
urlFlag(&MigrateFlags.URL, migrateFlagURL, "u", MigrateSetCmd.Flags())
// Hash flags.
MigrateHashCmd.Flags().Bool("force", false, "")
cobra.CheckErr(MigrateHashCmd.Flags().MarkDeprecated("force", "you can safely omit it."))
// Lint flags.
urlFlag(&MigrateFlags.DevURL, migrateFlagDevURL, "", MigrateLintCmd.Flags())
MigrateLintCmd.PersistentFlags().StringVarP(&MigrateFlags.Lint.Format, migrateFlagLog, "", "", "custom logging using a Go template")
MigrateLintCmd.PersistentFlags().UintVarP(&MigrateFlags.Lint.Latest, migrateLintLatest, "", 0, "run analysis on the latest N migration files")
MigrateLintCmd.PersistentFlags().StringVarP(&MigrateFlags.Lint.GitBase, migrateLintGitBase, "", "", "run analysis against the base Git branch")
MigrateLintCmd.PersistentFlags().StringVarP(&MigrateFlags.Lint.GitDir, migrateLintGitDir, "", ".", "path to the repository working directory")
cobra.CheckErr(MigrateLintCmd.MarkFlagRequired(migrateFlagDevURL))
receivesEnv(MigrateCmd)
}
const applyLockValue = "atlas_migrate_execute"
// CmdMigrateApplyRun is the command executed when running the CLI with 'migrate apply' args.
func CmdMigrateApplyRun(cmd *cobra.Command, args []string) error {
var (
n int
err error
)
if len(args) > 0 {
n, err = strconv.Atoi(args[0])
if err != nil {
return err
}
if n < 1 {
return fmt.Errorf("cannot apply '%d' migration files", n)
}
}
// Open the migration directory.
dir, err := dir(false)
if err != nil {
return err
}
// Open a client to the database.
c, err := sqlclient.Open(cmd.Context(), MigrateFlags.URL)
if err != nil {
return err
}
defer c.Close()
// Acquire a lock.
if l, ok := c.Driver.(schema.Locker); ok {
unlock, err := l.Lock(cmd.Context(), applyLockValue, 0)
if err != nil {
return fmt.Errorf("acquiring database lock: %w", err)
}
// If unlocking fails notify the user about it.
defer cobra.CheckErr(unlock())
}
if err := checkRevisionSchemaClarity(cmd, c); err != nil {
return err
}
// Get the correct log format and destination. Currently, only os.Stdout is supported.
l, err := logFormat(cmd.OutOrStdout())
if err != nil {
return err
}
var rrw migrate.RevisionReadWriter
rrw, err = entRevisions(cmd.Context(), c)
if err != nil {
return err
}
if err := rrw.(*entmigrate.EntRevisions).Migrate(cmd.Context()); err != nil {
return err
}
// Determine pending files and lock the database while working.
ex, err := migrate.NewExecutor(c.Driver, dir, rrw, executorOptions(l)...)
if err != nil {
return err
}
pending, err := ex.Pending(cmd.Context())
if err != nil && !errors.Is(err, migrate.ErrNoPendingFiles) {
return err
}
if errors.Is(err, migrate.ErrNoPendingFiles) {
cmd.Println("No migration files to execute")
return nil
}
if n > 0 {
// Cannot apply more than len(pending) files.
if n >= len(pending) {
n = len(pending)
}
pending = pending[:n]
}
revs, err := rrw.ReadRevisions(cmd.Context())
if err != nil {
return err
}
if err := migrate.LogIntro(l, revs, pending); err != nil {
return err
}
var (
mux = tx{c: c, rrw: rrw}
drv migrate.Driver
)
for _, f := range pending {
drv, rrw, err = mux.driver(cmd.Context())
if err != nil {
return err
}
ex, err := migrate.NewExecutor(drv, dir, rrw, executorOptions(l)...)
if err != nil {
return err
}
if err := mux.mayRollback(ex.Execute(cmd.Context(), f)); err != nil {
return err
}
if err := mux.mayCommit(); err != nil {
return err
}
}
if err := mux.commit(); err != nil {
return err
}
l.Log(migrate.LogDone{})
return mux.commit()
}
func checkRevisionSchemaClarity(cmd *cobra.Command, c *sqlclient.Client) error {
// The "old" default behavior for the revision schema location was to store the revision table in its own schema.
// Now, the table is saved in the connected schema, if any. To keep the backwards compatability, we now require
// for schema bound connections to have the schema-revision flag present if there is no revision table in the schema
// but the old default schema does have one.
if c.URL.Schema != "" && MigrateFlags.RevisionSchema == "" {
// If the schema does not contain a revision table, but we can find a table in the previous default schema,
// abort and tell the user to specify the intention.
opts := &schema.InspectOptions{Tables: []string{revision.Table}}
s, err := c.InspectSchema(cmd.Context(), "", opts)
var ok bool
switch {
case schema.IsNotExistError(err):
// If the schema does not exist, the table does not as well.
case err != nil:
return err
default:
// Connected schema does exist, check if the table does.
_, ok = s.Table(revision.Table)
}
if !ok { // Either schema or table does not exist.
// Check for the old default schema. If it does not exist, we have no problem.
s, err := c.InspectSchema(cmd.Context(), defaultRevisionSchema, opts)
switch {
case schema.IsNotExistError(err):
// Schema does not exist, we can proceed.
case err != nil:
return err
default:
if _, ok := s.Table(revision.Table); ok {
fmt.Fprintf(cmd.OutOrStderr(),
`We couldn't find a revision table in the connected schema but found one in
the schema 'atlas_schema_revisions' and cannot determine the desired behavior.
As a safety guard, we require you to specify whether to use the existing
table in 'atlas_schema_revisions' or create a new one in the connected schema
by providing the '--revisions-schema' flag or deleting the 'atlas_schema_revisions'
schema if it is unused.
`)
cmd.SilenceUsage = true
cmd.SilenceErrors = true
return errors.New("ambiguous revision table")
}
}
}
}
return nil
}
func entRevisions(ctx context.Context, c *sqlclient.Client) (*entmigrate.EntRevisions, error) {
return entmigrate.NewEntRevisions(ctx, c, entmigrate.WithSchema(revisionSchemaName(c)))
}
// defaultRevisionSchema is the default schema for storing revisions table.
const defaultRevisionSchema = "atlas_schema_revisions"
func revisionSchemaName(c *sqlclient.Client) string {
switch {
case MigrateFlags.RevisionSchema != "":
return MigrateFlags.RevisionSchema
case c.URL.Schema != "":
return c.URL.Schema
default:
return defaultRevisionSchema
}
}
// tx handles wrapping migration execution in transactions.
type tx struct {
c *sqlclient.Client
tx *sqlclient.TxClient
rrw migrate.RevisionReadWriter
}
// driver returns the migrate.Driver to use to execute migration statements.
func (tx *tx) driver(ctx context.Context) (migrate.Driver, migrate.RevisionReadWriter, error) {
if MigrateFlags.Apply.DryRun {
// If the --dry-run flag is given we don't want to execute any statements on the database.
return &dryRunDriver{tx.c.Driver}, &dryRunRevisions{tx.rrw}, nil
}
switch MigrateFlags.Apply.TxMode {
case txModeNone:
return tx.c.Driver, tx.rrw, nil
case txModeFile:
// In file-mode, this function is called each time a new file is executed. Open a transaction.
if tx.tx != nil {
return nil, nil, errors.New("unexpected active transaction")
}
var err error
tx.tx, err = tx.c.Tx(ctx, nil)
if err != nil {
return nil, nil, err
}
tx.rrw, err = entRevisions(ctx, tx.tx.Client)
if err != nil {
return nil, nil, err
}
return tx.tx.Driver, tx.rrw, nil
case txModeAll:
// In file-mode, this function is called each time a new file is executed. Since we wrap all files into one
// huge transaction, if there already is an opened one, use that.
if tx.tx == nil {
var err error
tx.tx, err = tx.c.Tx(ctx, nil)
if err != nil {
return nil, nil, err
}
tx.rrw, err = entRevisions(ctx, tx.tx.Client)
if err != nil {
return nil, nil, err
}
}
return tx.tx.Driver, tx.rrw, nil
default:
return nil, nil, fmt.Errorf("unknown tx-mode %q", MigrateFlags.Apply.TxMode)
}
}
// mayRollback may roll back a transaction depending on the given transaction mode.
func (tx *tx) mayRollback(err error) error {
if tx.tx != nil && err != nil {
if err2 := tx.tx.Rollback(); err2 != nil {
err = fmt.Errorf("%v: %w", err2, err)
}
}
return err
}
// mayCommit may commit a transaction depending on the given transaction mode.
func (tx *tx) mayCommit() error {
// Only commit if each file is wrapped in a transaction.
if !MigrateFlags.Apply.DryRun && MigrateFlags.Apply.TxMode == txModeFile {
return tx.commit()
}
return nil
}
// commit the transaction, if one is active.
func (tx *tx) commit() error {
if tx.tx == nil {
return nil
}
defer func() { tx.tx = nil }()
return tx.tx.Commit()
}
func executorOptions(l migrate.Logger) []migrate.ExecutorOption {
opts := []migrate.ExecutorOption{
migrate.WithLogger(l),
migrate.WithOperatorVersion(operatorVersion()),
}
if MigrateFlags.Apply.AllowDirty {
opts = append(opts, migrate.WithAllowDirty(true))
}
if v := MigrateFlags.Apply.BaselineVersion; v != "" {
opts = append(opts, migrate.WithBaselineVersion(v))
}
if v := MigrateFlags.Apply.FromVersion; v != "" {
opts = append(opts, migrate.WithFromVersion(v))
}
return opts
}
func operatorVersion() string {
v, _ := parse(version)
return "Atlas CLI - " + v
}
// CmdMigrateDiffRun is the command executed when running the CLI with 'migrate diff' args.
func CmdMigrateDiffRun(cmd *cobra.Command, args []string) error {
// Open a dev driver.
dev, err := sqlclient.Open(cmd.Context(), MigrateFlags.DevURL)
if err != nil {
return err
}
defer dev.Close()
// Acquire a lock.
if l, ok := dev.Driver.(schema.Locker); ok {
unlock, err := l.Lock(cmd.Context(), "atlas_migrate_diff", 0)
if err != nil {
return fmt.Errorf("acquiring database lock: %w", err)
}
// If unlocking fails notify the user about it.
defer cobra.CheckErr(unlock())
}
// Open the migration directory.
dir, err := dir(false)
if err != nil {
return err
}
// Get a state reader for the desired state.
desired, err := to(cmd.Context(), dev)
if err != nil {
return err
}
defer desired.Close()
f, err := formatter()
if err != nil {
return err
}
opts := []migrate.PlannerOption{migrate.PlanFormat(f)}
if dev.URL.Schema != "" {
// Disable tables qualifier in schema-mode.
opts = append(opts, migrate.PlanWithSchemaQualifier(MigrateFlags.Diff.Qualifier))
}
// Plan the changes and create a new migration file.
pl := migrate.NewPlanner(dev.Driver, dir, opts...)
var name string
if len(args) > 0 {
name = args[0]
}
plan, err := func() (*migrate.Plan, error) {
if dev.URL.Schema != "" {
return pl.PlanSchema(cmd.Context(), name, desired.StateReader)
}
return pl.Plan(cmd.Context(), name, desired.StateReader)
}()
var cerr migrate.NotCleanError
switch {
case errors.Is(err, migrate.ErrNoPlan):
cmd.Println("The migration directory is synced with the desired state, no changes to be made")
return nil
case errors.As(err, &cerr) && dev.URL.Schema == "" && desired.Schema != "":
return fmt.Errorf("dev database is not clean (%s). Add a schema to the URL to limit the scope of the connection", cerr.Reason)
case err != nil:
return err
default:
// Write the plan to a new file.
return pl.WritePlan(plan)
}
}
// CmdMigrateHashRun is the command executed when running the CLI with 'migrate hash' args.
func CmdMigrateHashRun(*cobra.Command, []string) error {
dir, err := dir(false)
if err != nil {
return err
}
sum, err := dir.Checksum()
if err != nil {
return err
}
return migrate.WriteSumFile(dir, sum)
}
// CmdMigrateImportRun is the command executed when running the CLI with 'migrate import' args.
func CmdMigrateImportRun(cmd *cobra.Command, _ []string) error {
if MigrateFlags.DirFormat == formatAtlas {
return fmt.Errorf("cannot import a migration directory already in %q format", formatAtlas)
}
MigrateFlags.DirURL = MigrateFlags.Import.FromURL
src, err := dir(false)
if err != nil {
return err
}
MigrateFlags.DirFormat = formatAtlas
MigrateFlags.DirURL = MigrateFlags.Import.ToURL
trgt, err := dir(true)
if err != nil {
return err
}
// Target must be empty.
ff, err := trgt.Files()
switch {
case err != nil:
return err
case len(ff) != 0:
return errors.New("target migration directory must be empty")
}
ff, err = src.Files()
switch {
case err != nil:
return err
case len(ff) == 0:
fmt.Fprint(cmd.OutOrStderr(), "nothing to import")
cmd.SilenceUsage = true
return nil
}
// Fix version numbers for Flyway repeatable migrations.
if _, ok := src.(*sqltool.FlywayDir); ok {
sqltool.SetRepeatableVersion(ff)
}
// Extract the statements for each of the migration files, add them to a plan to format with the
// migrate.DefaultFormatter.
for _, f := range ff {
stmts, err := f.StmtDecls()
if err != nil {
return err
}
plan := &migrate.Plan{
Version: f.Version(),
Name: f.Desc(),
Changes: make([]*migrate.Change, len(stmts)),
}
var buf strings.Builder
for i, s := range stmts {
for _, c := range s.Comments {
buf.WriteString(c)
if !strings.HasSuffix(c, "\n") {
buf.WriteString("\n")
}
}
buf.WriteString(strings.TrimSuffix(s.Text, ";"))
plan.Changes[i] = &migrate.Change{Cmd: buf.String()}
buf.Reset()
}
files, err := migrate.DefaultFormatter.Format(plan)
if err != nil {
return err
}
for _, f := range files {
if err := trgt.WriteFile(f.Name(), f.Bytes()); err != nil {
return err
}
}
}
sum, err := trgt.Checksum()
if err != nil {
return err
}
return migrate.WriteSumFile(trgt, sum)
}
// CmdMigrateNewRun is the command executed when running the CLI with 'migrate new' args.
func CmdMigrateNewRun(_ *cobra.Command, args []string) error {
dir, err := dir(true)
if err != nil {
return err
}
f, err := formatter()
if err != nil {
return err
}
var name string
if len(args) > 0 {
name = args[0]
}
return migrate.NewPlanner(nil, dir, migrate.PlanFormat(f)).WritePlan(&migrate.Plan{Name: name})
}
// CmdMigrateSetRun is the command executed when running the CLI with 'migrate set' args.
func CmdMigrateSetRun(cmd *cobra.Command, args []string) error {
dir, err := dir(false)
if err != nil {
return err
}
avail, err := dir.Files()
if err != nil {
return err
}
// Check if the target version does exist in the migration directory.
if idx := migrate.FilesLastIndex(avail, func(f migrate.File) bool {
return f.Version() == args[0]
}); idx == -1 {
return fmt.Errorf("migration with version %q not found", args[0])
}
client, err := sqlclient.Open(cmd.Context(), MigrateFlags.URL)
if err != nil {
return err
}
defer client.Close()
// Acquire a lock.
if l, ok := client.Driver.(schema.Locker); ok {
unlock, err := l.Lock(cmd.Context(), applyLockValue, 0)
if err != nil {
return fmt.Errorf("acquiring database lock: %w", err)
}
// If unlocking fails notify the user about it.
defer cobra.CheckErr(unlock())
}
if err := checkRevisionSchemaClarity(cmd, client); err != nil {
return err
}
// Ensure revision table exists.
rrw, err := entRevisions(cmd.Context(), client)
if err != nil {
return err
}
if err := rrw.Migrate(cmd.Context()); err != nil {
return err
}
// Wrap manipulation in a transaction.
tx, err := client.Tx(cmd.Context(), nil)
if err != nil {
return err
}
rrw, err = entRevisions(cmd.Context(), tx.Client)
if err != nil {
return err
}
revs, err := rrw.ReadRevisions(cmd.Context())
if err != nil {
return err
}
if err := func() error {
for _, r := range revs {
// Check all existing revisions and ensure they precede the given version. If we encounter a partially
// applied revision, or one with errors, mark them "fixed".
switch {
// remove revision to keep linear history
case r.Version > args[0]:
if err := rrw.DeleteRevision(cmd.Context(), r.Version); err != nil {
return err
}
// keep, but if with error mark "fixed"
case r.Version == args[0] && (r.Error != "" || r.Total != r.Applied):
r.Type = migrate.RevisionTypeExecute | migrate.RevisionTypeResolved
if err := rrw.WriteRevision(cmd.Context(), r); err != nil {
return err
}
}
}
revs, err = rrw.ReadRevisions(cmd.Context())
if err != nil {
return err
}
// If the target version succeeds the last revision, mark
// migrations applied, until we reach the target version.
var pending []migrate.File
switch {
case len(revs) == 0:
// Take every file until we reach target version.
for _, f := range avail {
if f.Version() > args[0] {
break
}
pending = append(pending, f)
}
case args[0] > revs[len(revs)-1].Version:
loop:
// Take every file succeeding the last revision until we reach target version.
for _, f := range avail {
switch {
case f.Version() <= revs[len(revs)-1].Version:
// Migration precedes last revision.
case f.Version() > args[0]:
// Migration succeeds target revision.
break loop
default: // between last revision and target
pending = append(pending, f)
}
}
}
// Mark every pending file as applied.
sum, err := dir.Checksum()
if err != nil {
return err
}
for _, f := range pending {
h, err := sum.SumByName(f.Name())
if err != nil {
return err
}
if err := rrw.WriteRevision(cmd.Context(), &migrate.Revision{
Version: f.Version(),
Description: f.Desc(),
Type: migrate.RevisionTypeResolved,
ExecutedAt: time.Now(),
Hash: h,
OperatorVersion: operatorVersion(),
}); err != nil {
return err
}
}
return nil
}(); err != nil {
if err2 := tx.Rollback(); err2 != nil {
err = fmt.Errorf("%v: %w", err2, err)
}
return err
}
return tx.Commit()
}
// CmdMigrateStatusRun is the command executed when running the CLI with 'migrate status' args.
func CmdMigrateStatusRun(cmd *cobra.Command, _ []string) error {
// Open the migration directory.
dir, err := dir(false)
if err != nil {
return err
}
avail, err := dir.Files()
if err != nil {
return err
}
// Open a client to the database.
client, err := sqlclient.Open(cmd.Context(), MigrateFlags.URL)
if err != nil {
return err
}
defer client.Close()
if err := checkRevisionSchemaClarity(cmd, client); err != nil {
return err
}
// Inspect schema and check if the table does already exist.
s, err := client.InspectSchema(
cmd.Context(),
revisionSchemaName(client),
&schema.InspectOptions{Tables: []string{revision.Table}},
)
switch {
case err != nil && !schema.IsNotExistError(err):
return err
case schema.IsNotExistError(err):
return statusPrint(cmd.OutOrStdout(), avail, avail, nil)
}
if _, ok := s.Table(revision.Table); !ok {
// Table does not exist.
return statusPrint(cmd.OutOrStdout(), avail, avail, nil)
}
// Currently, only in DB revisions are supported.
rrw, err := entRevisions(cmd.Context(), client)
if err != nil {
return err
}
// Executor can give us insights on the revision state.
ex, err := migrate.NewExecutor(client.Driver, dir, rrw)
if err != nil {
return err
}
pending, err := ex.Pending(cmd.Context())
if err != nil && !errors.Is(err, migrate.ErrNoPendingFiles) {
return err
}
revs, err := rrw.ReadRevisions(cmd.Context())
if err != nil {
return err
}
return statusPrint(cmd.OutOrStdout(), avail, pending, revs)
}
func statusPrint(out io.Writer, avail, pending []migrate.File, revs []*migrate.Revision) (err error) {
var (
cur, next, state string
applied = avail[: len(avail)-len(pending) : len(avail)-len(pending)]
partial = len(revs) != 0 && revs[len(revs)-1].Applied < revs[len(revs)-1].Total
)
switch len(pending) {
case len(avail):
cur = "No version applied yet"
default:
cur = cyan(applied[len(applied)-1].Version())
// If the last pending version is partially applied, tell so.
if partial {
cur += fmt.Sprintf(" (%d statements applied)", revs[len(revs)-1].Applied)
}
}
if len(pending) == 0 {
state = green("OK")
next = "Already at latest version"
} else {
state = yellow("PENDING")
next = cyan(pending[0].Version())
if partial {
next += fmt.Sprintf(" (%d statements left)", revs[len(revs)-1].Total-revs[len(revs)-1].Applied)
}
}
exec := cyan(strconv.Itoa(len(applied)))
if partial {
exec += " + 1 partially"
}
c := cyan
if len(pending) == 0 {
c = green
}
fmt.Fprintf(out, "Migration Status: %s\n", state)
fmt.Fprintf(out, "%s%s Current Version: %s\n", indent2, dash, cur)
fmt.Fprintf(out, "%s%s Next Version: %s\n", indent2, dash, next)
fmt.Fprintf(out, "%s%s Executed Files: %s\n", indent2, dash, exec)
fmt.Fprintf(out, "%s%s Pending Files: %s", indent2, dash, c(strconv.Itoa(len(pending))))
if partial {
fmt.Fprintf(out, " (partially)")
}
fmt.Fprintf(out, "\n")
return nil
}
// CmdMigrateValidateRun is the command executed when running the CLI with 'migrate validate' args.
func CmdMigrateValidateRun(cmd *cobra.Command, _ []string) error {
// Validating the integrity is done by the PersistentPreRun already.
if MigrateFlags.DevURL == "" {
// If there is no --dev-url given do not attempt to replay the migration directory.
return nil
}
// Open a client for the dev-db.
dev, err := sqlclient.Open(cmd.Context(), MigrateFlags.DevURL)
if err != nil {
return err
}
defer dev.Close()
// Currently, only our own migration file format is supported.
dir, err := dir(false)
if err != nil {
return err
}
ex, err := migrate.NewExecutor(dev.Driver, dir, migrate.NopRevisionReadWriter{})
if err != nil {
return err
}
if _, err := ex.Replay(cmd.Context(), func() migrate.StateReader {
if dev.URL.Schema != "" {
return migrate.SchemaConn(dev, "", nil)
}
return migrate.RealmConn(dev, nil)
}()); err != nil && !errors.Is(err, migrate.ErrNoPendingFiles) {
return fmt.Errorf("replaying the migration directory: %w", err)
}
return nil
}
// CmdMigrateLintRun is the command executed when running the CLI with 'migrate lint' args.
func CmdMigrateLintRun(cmd *cobra.Command, _ []string) error {
dev, err := sqlclient.Open(cmd.Context(), MigrateFlags.DevURL)
if err != nil {
return err
}
defer dev.Close()
dir, err := dir(false)
if err != nil {
return err
}
var detect lint.ChangeDetector
switch {
case MigrateFlags.Lint.Latest == 0 && MigrateFlags.Lint.GitBase == "":
return fmt.Errorf("--%s or --%s is required", migrateLintLatest, migrateLintGitBase)
case MigrateFlags.Lint.Latest > 0 && MigrateFlags.Lint.GitBase != "":
return fmt.Errorf("--%s and --%s are mutually exclusive", migrateLintLatest, migrateLintGitBase)
case MigrateFlags.Lint.Latest > 0:
detect = lint.LatestChanges(dir, int(MigrateFlags.Lint.Latest))
case MigrateFlags.Lint.GitBase != "":
detect, err = lint.NewGitChangeDetector(
dir,
lint.WithWorkDir(MigrateFlags.Lint.GitDir),
lint.WithBase(MigrateFlags.Lint.GitBase),
lint.WithMigrationsPath(dir.(interface{ Path() string }).Path()),
)
if err != nil {
return err
}
}
format := lint.DefaultTemplate
if f := MigrateFlags.Lint.Format; f != "" {
format, err = template.New("format").Funcs(lint.TemplateFuncs).Parse(f)
if err != nil {
return fmt.Errorf("parse log format: %w", err)
}
}
env, err := selectEnv(GlobalFlags.SelectedEnv)
if err != nil {
return err
}
az, err := sqlcheck.AnalyzerFor(dev.Name, env.Lint.Remain())
if err != nil {
return err
}
r := &lint.Runner{
Dev: dev,
Dir: dir,
ChangeDetector: detect,
ReportWriter: &lint.TemplateWriter{
T: format,
W: cmd.OutOrStdout(),
},
Analyzers: az,
}
err = r.Run(cmd.Context())
// Print the error in case it was not printed before.
cmd.SilenceErrors = errors.As(err, &lint.SilentError{})
return err
}
const (
txModeNone = "none"
txModeAll = "all"
txModeFile = "file"
)
func printChecksumErr(out io.Writer) {
fmt.Fprintf(out, `You have a checksum error in your migration directory.
This happens if you manually create or edit a migration file.
Please check your migration files and run
'atlas migrate hash'
to re-hash the contents and resolve the error
`)
}
// dir returns a migrate.Dir to use as migration directory. For now only local directories are supported.
func dir(create bool) (migrate.Dir, error) {
parts := strings.SplitN(MigrateFlags.DirURL, "://", 2)
if len(parts) != 2 {
return nil, fmt.Errorf("invalid dir url %q", MigrateFlags.DirURL)
}
if parts[0] != "file" {
return nil, fmt.Errorf("unsupported driver %q", parts[0])
}
f := func() (migrate.Dir, error) { return migrate.NewLocalDir(parts[1]) }
switch MigrateFlags.DirFormat {
case formatAtlas:
case formatGolangMigrate:
f = func() (migrate.Dir, error) { return sqltool.NewGolangMigrateDir(parts[1]) }
case formatGoose:
f = func() (migrate.Dir, error) { return sqltool.NewGooseDir(parts[1]) }
case formatFlyway:
f = func() (migrate.Dir, error) { return sqltool.NewFlywayDir(parts[1]) }
case formatLiquibase:
f = func() (migrate.Dir, error) { return sqltool.NewLiquibaseDir(parts[1]) }
case formatDBMate:
f = func() (migrate.Dir, error) { return sqltool.NewDBMateDir(parts[1]) }
default:
return nil, fmt.Errorf("unknown dir format %q", MigrateFlags.DirFormat)
}
d, err := f()
if create && errors.Is(err, fs.ErrNotExist) {
if err := os.MkdirAll(parts[1], 0755); err != nil {
return nil, err
}
d, err = f()
}
return d, err
}
type target struct {
migrate.StateReader // desired state.
io.Closer // optional close function.
Schema string // in case we work on a single schema.
}
// to returns a migrate.StateReader for the given to flag.
func to(ctx context.Context, dev *sqlclient.Client) (*target, error) {
scheme, err := selectScheme(MigrateFlags.ToURLs)
if err != nil {
return nil, err
}
schemas := MigrateFlags.Schemas
switch scheme {
case "file": // hcl file
realm := &schema.Realm{}
paths := make([]string, 0, len(MigrateFlags.ToURLs))
for _, u := range MigrateFlags.ToURLs {
paths = append(paths, strings.TrimPrefix(u, "file://"))
}
parsed, err := parseHCLPaths(paths...)
if err != nil {
return nil, err
}
if err := dev.Eval(parsed, realm, nil); err != nil {
return nil, err
}
if len(schemas) > 0 {
// Validate all schemas in file were selected by user.
sm := make(map[string]bool, len(schemas))
for _, s := range schemas {
sm[s] = true
}
for _, s := range realm.Schemas {
if !sm[s.Name] {
return nil, fmt.Errorf("schema %q from paths %q is not requested (all schemas in HCL must be requested)", s.Name, paths)
}
}
}
// In case the dev connection is bound to a specific schema, we require the
// desired schema to contain only one schema. Thus, executing diff will be
// done on the content of these two schema and not the whole realm.
if dev.URL.Schema != "" && len(realm.Schemas) > 1 {
return nil, fmt.Errorf("cannot use HCL with more than 1 schema when dev-url is limited to schema %q", dev.URL.Schema)
}
if norm, ok := dev.Driver.(schema.Normalizer); ok && len(realm.Schemas) > 0 {
realm, err = norm.NormalizeRealm(ctx, realm)
if err != nil {
return nil, err
}
}
t := &target{StateReader: migrate.Realm(realm), Closer: io.NopCloser(nil)}
if len(realm.Schemas) == 1 {
t.Schema = realm.Schemas[0].Name
}
return t, nil
default: // database connection
client, err := sqlclient.Open(ctx, MigrateFlags.ToURLs[0])
if err != nil {
return nil, err
}
t := &target{Closer: client}
switch s := client.URL.Schema; {
// Connection to a specific schema.
case s != "":
if len(schemas) > 1 || len(schemas) == 1 && schemas[0] != s {
return nil, fmt.Errorf("cannot specify schemas with a schema connection to %q", s)
}
t.Schema = s
t.StateReader = migrate.SchemaConn(client, s, &schema.InspectOptions{})
// A single schema is selected.
case len(schemas) == 1:
t.Schema = schemas[0]
t.StateReader = migrate.SchemaConn(client, schemas[0], &schema.InspectOptions{})
// Multiple or all schemas.
default:
// In case the dev connection is limited to a single schema,
// but we compare it to entire database.
if dev.URL.Schema != "" {
return nil, fmt.Errorf("cannot use database-url without a schema when dev-url is limited to %q", dev.URL.Schema)
}
t.StateReader = migrate.RealmConn(client, &schema.InspectRealmOption{Schemas: schemas})
}
return t, nil
}
}
// selectScheme validates the scheme of the provided to urls and returns the selected
// url scheme. Currently, all URLs must be of the same scheme, and only multiple
// "file://" URLs are allowed.
func selectScheme(urls []string) (string, error) {
var scheme string
if len(urls) == 0 {
return "", errors.New("at least one --to url is required")
}
for _, url := range urls {
parts := strings.SplitN(url, "://", 2)
switch current := parts[0]; {
case scheme == "":
scheme = current
case scheme != current:
return "", fmt.Errorf("got mixed --to url schemes: %q and %q, the desired state must be provided from a single kind of source", scheme, current)
case current != "file":
return "", fmt.Errorf("got multiple --to urls of scheme %q, only multiple 'file://' urls are supported", current)
}
}
return scheme, nil
}
// parseHCLPaths parses the HCL files in the given paths. If a path represents a directory,
// its direct descendants will be considered, skipping any subdirectories. If a project file
// is present in the input paths, an error is returned.
func parseHCLPaths(paths ...string) (*hclparse.Parser, error) {
p := hclparse.NewParser()
for _, path := range paths {
switch stat, err := os.Stat(path); {
case err != nil:
return nil, err
case stat.IsDir():
dir, err := os.ReadDir(path)
if err != nil {
return nil, err
}
for _, f := range dir {
// Skip nested dirs.
if f.IsDir() {
continue
}
if err := mayParse(p, filepath.Join(path, f.Name())); err != nil {
return nil, err
}
}
default:
if err := mayParse(p, path); err != nil {
return nil, err
}
}
}
if len(p.Files()) == 0 {
return nil, fmt.Errorf("no schema files found in: %s", paths)
}
return p, nil
}
// mayParse will parse the file in path if it is an HCL file. If the file is an Atlas
// project file an error is returned.
func mayParse(p *hclparse.Parser, path string) error {
if n := filepath.Base(path); filepath.Ext(n) != ".hcl" {
return nil
}
switch f, diag := p.ParseHCLFile(path); {
case diag.HasErrors():
return diag
case isProjectFile(f):
return fmt.Errorf("cannot parse project file %q as a schema file", path)
default:
return nil
}
}
func isProjectFile(f *hcl.File) bool {
for _, blk := range f.Body.(*hclsyntax.Body).Blocks {
if blk.Type == "env" {
return true
}
}
return false
}
const (
formatAtlas = "atlas"
formatGolangMigrate = "golang-migrate"
formatGoose = "goose"
formatFlyway = "flyway"
formatLiquibase = "liquibase"
formatDBMate = "dbmate"
)
func formatter() (migrate.Formatter, error) {
switch MigrateFlags.DirFormat {
case formatAtlas:
return migrate.DefaultFormatter, nil
case formatGolangMigrate:
return sqltool.GolangMigrateFormatter, nil
case formatGoose:
return sqltool.GooseFormatter, nil
case formatFlyway:
return sqltool.FlywayFormatter, nil
case formatLiquibase:
return sqltool.LiquibaseFormatter, nil
case formatDBMate:
return sqltool.DBMateFormatter, nil
default:
return nil, fmt.Errorf("unknown format %q", MigrateFlags.DirFormat)
}
}
const logFormatTTY = "tty"
// LogTTY is a migrate.Logger that pretty prints execution progress.
// If the connected out is not a tty, it will fall back to a non-colorful output.
type LogTTY struct {
out io.Writer
start time.Time
fileStart time.Time
fileCounter int
stmtCounter int
}
var (
cyan = color.CyanString
green = color.HiGreenString
red = color.HiRedString
redBgWhiteFg = color.New(color.FgHiWhite, color.BgHiRed).SprintFunc()
yellow = color.YellowString
dash = yellow("--")
arr = cyan("->")
indent2 = " "
indent4 = indent2 + indent2
)
// Log implements the migrate.Logger interface.
func (l *LogTTY) Log(e migrate.LogEntry) {
switch e := e.(type) {
case migrate.LogExecution:
l.start = time.Now()
fmt.Fprintf(l.out, "Migrating to version %v", cyan(e.To))
if e.From != "" {
fmt.Fprintf(l.out, " from %v", cyan(e.From))
}
fmt.Fprintf(l.out, " (%d migrations in total):\n", len(e.Files))
case migrate.LogFile:
l.fileCounter++
if !l.fileStart.IsZero() {
l.reportFileEnd()
}
l.fileStart = time.Now()
fmt.Fprintf(l.out, "\n%s%v migrating version %v", indent2, dash, cyan(e.Version))
if e.Skip > 0 {
fmt.Fprintf(l.out, " (partially applied - skipping %s statements)", yellow("%d", e.Skip))
}
fmt.Fprint(l.out, "\n")
case migrate.LogStmt:
l.stmtCounter++
fmt.Fprintf(l.out, "%s%v %s\n", indent4, arr, e.SQL)
case migrate.LogDone:
l.reportFileEnd()
fmt.Fprintf(l.out, "\n%s%v\n", indent2, cyan(strings.Repeat("-", 25)))
fmt.Fprintf(l.out, "%s%v %v\n", indent2, dash, time.Since(l.start))
fmt.Fprintf(l.out, "%s%v %v migrations\n", indent2, dash, l.fileCounter)
fmt.Fprintf(l.out, "%s%v %v sql statements\n", indent2, dash, l.stmtCounter)
case migrate.LogError:
fmt.Fprintf(l.out, "%s %s\n", indent4, redBgWhiteFg(e.Error.Error()))
fmt.Fprintf(l.out, "\n%s%v\n", indent2, cyan(strings.Repeat("-", 25)))
fmt.Fprintf(l.out, "%s%v %v\n", indent2, dash, time.Since(l.start))
fmt.Fprintf(l.out, "%s%v %v migrations ok (%s)\n", indent2, dash, zero(l.fileCounter-1), red("1 with errors"))
fmt.Fprintf(l.out, "%s%v %v sql statements ok (%s)\n", indent2, dash, zero(l.stmtCounter-1), red("1 with errors"))
fmt.Fprintf(l.out, "\n%s\n%v\n\n", red("Error: Execution had errors:"), redBgWhiteFg(e.Error.Error()))
default:
fmt.Fprintf(l.out, "%v", e)
}
}
func (l *LogTTY) reportFileEnd() {
fmt.Fprintf(l.out, "%s%v ok (%v)\n", indent2, dash, yellow("%s", time.Since(l.fileStart)))
}
func zero(v int) int {
if v < 0 {
return 0
}
return v
}
func logFormat(out io.Writer) (migrate.Logger, error) {
switch l := MigrateFlags.Apply.LogFormat; l {
case logFormatTTY:
return &LogTTY{out: out}, nil
default:
return nil, fmt.Errorf("unknown log-format %q", l)
}
}
func migrateFlagsFromEnv(cmd *cobra.Command, _ []string) error {
activeEnv, err := selectEnv(GlobalFlags.SelectedEnv)
if err != nil {
return err
}
if err := inputValsFromEnv(cmd); err != nil {
return err
}
if err := maySetFlag(cmd, migrateFlagDevURL, activeEnv.DevURL); err != nil {
return err
}
if err := maySetFlag(cmd, migrateFlagDirFormat, activeEnv.Migration.Format); err != nil {
return err
}
switch cmd.Name() {
case "lint":
if err := maySetFlag(cmd, migrateFlagLog, activeEnv.Lint.Log); err != nil {
return err
}
if err := maySetFlag(cmd, migrateLintLatest, strconv.Itoa(activeEnv.Lint.Latest)); err != nil {
return err
}
if err := maySetFlag(cmd, migrateLintGitDir, activeEnv.Lint.Git.Dir); err != nil {
return err
}
if err := maySetFlag(cmd, migrateLintGitBase, activeEnv.Lint.Git.Base); err != nil {
return err
}
default:
if err := maySetFlag(cmd, migrateFlagURL, activeEnv.URL); err != nil {
return err
}
if err := maySetFlag(cmd, migrateFlagRevisionsSchema, activeEnv.Migration.RevisionsSchema); err != nil {
return err
}
}
// Transform "src" to a URL.
srcs, err := activeEnv.Sources()
if err != nil {
return err
}
for i, s := range srcs {
if s, err = filepath.Abs(s); err != nil {
return fmt.Errorf("finding abs path to source: %q: %w", s, err)
}
srcs[i] = "file://" + s
}
if err := maySetFlag(cmd, migrateFlagTo, strings.Join(srcs, ",")); err != nil {
return err
}
if s := "[" + strings.Join(activeEnv.Schemas, "") + "]"; len(activeEnv.Schemas) > 0 {
if err := maySetFlag(cmd, migrateFlagSchema, s); err != nil {
return err
}
}
return nil
}
type (
// dryRunDriver wraps a migrate.Driver without executing any SQL statements.
dryRunDriver struct{ migrate.Driver }
// dryRunRevisions wraps a migrate.RevisionReadWriter without executing any SQL statements.
dryRunRevisions struct{ migrate.RevisionReadWriter }
)
// QueryContext overrides the wrapped schema.ExecQuerier to not execute any SQL.
func (dryRunDriver) QueryContext(context.Context, string, ...any) (*sql.Rows, error) {
return nil, nil
}
// ExecContext overrides the wrapped schema.ExecQuerier to not execute any SQL.
func (dryRunDriver) ExecContext(context.Context, string, ...any) (sql.Result, error) {
return nil, nil
}
// Lock implements the schema.Locker interface.
func (dryRunDriver) Lock(context.Context, string, time.Duration) (schema.UnlockFunc, error) {
// We dry-run, we don't execute anything. Locking is not required.
return func() error { return nil }, nil
}
// CheckClean implements the migrate.CleanChecker interface.
func (dryRunDriver) CheckClean(context.Context, *migrate.TableIdent) error {
return nil
}
// Snapshot implements the migrate.Snapshoter interface.
func (dryRunDriver) Snapshot(context.Context) (migrate.RestoreFunc, error) {
// We dry-run, we don't execute anything. Snapshotting not required.
return func(context.Context) error { return nil }, nil
}
// WriteRevision overrides the wrapped migrate.RevisionReadWriter to not saved any changes to revisions.
func (dryRunRevisions) WriteRevision(context.Context, *migrate.Revision) error {
return nil
}
atlas-0.7.2/cmd/atlas/internal/cmdapi/migrate_test.go 0000664 0000000 0000000 00000072270 14314555116 0022577 0 ustar 00root root 0000000 0000000 // Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package cmdapi
import (
"context"
"database/sql"
"errors"
"fmt"
"io"
"net/url"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"testing"
"time"
migrate2 "ariga.io/atlas/cmd/atlas/internal/migrate"
"ariga.io/atlas/sql/migrate"
"ariga.io/atlas/sql/schema"
"ariga.io/atlas/sql/sqlclient"
"ariga.io/atlas/sql/sqlite"
_ "ariga.io/atlas/sql/sqlite"
_ "ariga.io/atlas/sql/sqlite/sqlitecheck"
"github.com/fatih/color"
_ "github.com/mattn/go-sqlite3"
"github.com/stretchr/testify/require"
)
func TestMigrate(t *testing.T) {
_, err := runCmd(Root, "migrate")
require.NoError(t, err)
}
func TestMigrate_Import(t *testing.T) {
for _, tool := range []string{"dbmate", "flyway", "golang-migrate", "goose", "liquibase"} {
p := t.TempDir()
t.Run(tool, func(t *testing.T) {
path := filepath.FromSlash("testdata/import/" + tool)
out, err := runCmd(
Root, "migrate", "import",
"--from", "file://"+path,
"--to", "file://"+p,
"--dir-format", tool,
)
require.NoError(t, err)
require.Zero(t, out)
path += "_gold"
ex, err := os.ReadDir(path)
require.NoError(t, err)
ac, err := os.ReadDir(p)
require.NoError(t, err)
require.Equal(t, len(ex)+1, len(ac)) // sum file
for i := range ex {
e, err := os.ReadFile(filepath.Join(path, ex[i].Name()))
require.NoError(t, err)
a, err := os.ReadFile(filepath.Join(p, ex[i].Name()))
require.NoError(t, err)
require.Equal(t, string(e), string(a))
}
})
}
}
func TestMigrate_Apply(t *testing.T) {
var (
p = t.TempDir()
ctx = context.Background()
)
// Disable text coloring in testing
// to assert on string matching.
color.NoColor = true
// Fails on empty directory.
s, err := runCmd(
Root, "migrate", "apply",
"--dir", "file://"+p,
"-u", openSQLite(t, ""),
)
require.NoError(t, err)
require.Equal(t, "No migration files to execute\n", s)
// Fails on directory without sum file.
require.NoError(t, os.Rename(
filepath.FromSlash("testdata/sqlite/atlas.sum"),
filepath.FromSlash("testdata/sqlite/atlas.sum.bak"),
))
t.Cleanup(func() {
os.Rename(filepath.FromSlash("testdata/sqlite/atlas.sum.bak"), filepath.FromSlash("testdata/sqlite/atlas.sum"))
})
_, err = runCmd(
Root, "migrate", "apply",
"--dir", "file://testdata/sqlite",
"--url", openSQLite(t, ""),
)
require.ErrorIs(t, err, migrate.ErrChecksumNotFound)
require.NoError(t, os.Rename(
filepath.FromSlash("testdata/sqlite/atlas.sum.bak"),
filepath.FromSlash("testdata/sqlite/atlas.sum"),
))
// A lock will prevent execution.
sqlclient.Register(
"sqlitelockapply",
sqlclient.OpenerFunc(func(ctx context.Context, u *url.URL) (*sqlclient.Client, error) {
client, err := sqlclient.Open(ctx, strings.Replace(u.String(), u.Scheme, "sqlite", 1))
if err != nil {
return nil, err
}
client.Driver = &sqliteLockerDriver{client.Driver}
return client, nil
}),
sqlclient.RegisterDriverOpener(func(db schema.ExecQuerier) (migrate.Driver, error) {
drv, err := sqlite.Open(db)
if err != nil {
return nil, err
}
return &sqliteLockerDriver{drv}, nil
}),
)
f, err := os.Create(filepath.Join(p, "test.db"))
require.NoError(t, err)
require.NoError(t, f.Close())
s, err = runCmd(
Root, "migrate", "apply",
"--dir", "file://testdata/sqlite",
"--url", fmt.Sprintf("sqlitelockapply://file:%s?cache=shared&_fk=1", filepath.Join(p, "test.db")),
)
require.ErrorIs(t, err, errLock)
require.True(t, strings.HasPrefix(s, "Error: acquiring database lock: "+errLock.Error()))
// Apply zero throws error.
for _, n := range []string{"-1", "0"} {
_, err = runCmd(
Root, "migrate", "apply",
"--dir", "file://testdata/sqlite",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test.db")),
"--", n,
)
require.EqualError(t, err, fmt.Sprintf("cannot apply '%s' migration files", n))
}
// Will work and print stuff to the console.
s, err = runCmd(
Root, "migrate", "apply",
"--dir", "file://testdata/sqlite",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test.db")),
"1",
)
require.NoError(t, err)
require.Contains(t, s, "20220318104614") // log to version
require.Contains(t, s, "CREATE TABLE tbl (`col` int NOT NULL);") // logs statement
require.NotContains(t, s, "ALTER TABLE `tbl` ADD `col_2` bigint;") // does not execute second file
require.Contains(t, s, "1 migrations") // logs amount of migrations
require.Contains(t, s, "1 sql statements")
// Transactions will be wrapped per file. If the second file has an error, first still is applied.
s, err = runCmd(
Root, "migrate", "apply",
"--dir", "file://testdata/sqlite2",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test2.db")),
)
require.Error(t, err)
require.Contains(t, s, "20220318104614") // log to version
require.Contains(t, s, "CREATE TABLE tbl (`col` int NOT NULL);") // logs statement
require.Contains(t, s, "ALTER TABLE `tbl` ADD `col_2` bigint;") // does execute first stmt first second file
require.Contains(t, s, "ALTER TABLE `tbl` ADD `col_3` bigint;") // does execute second stmt first second file
require.NotContains(t, s, "ALTER TABLE `tbl` ADD `col_4` bigint;") // but not third
require.Contains(t, s, "1 migrations ok (1 with errors)") // logs amount of migrations
require.Contains(t, s, "2 sql statements ok (1 with errors)") // logs amount of statement
require.Contains(t, s, "Error: Execution had errors:") // logs error summary
require.Contains(t, s, "near \"asdasd\": syntax error") // logs error summary
c, err := sqlclient.Open(ctx, fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test2.db")))
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, c.Close())
})
sch, err := c.InspectSchema(ctx, "", nil)
tbl, ok := sch.Table("tbl")
require.True(t, ok)
_, ok = tbl.Column("col_2")
require.False(t, ok)
_, ok = tbl.Column("col_3")
require.False(t, ok)
rrw, err := migrate2.NewEntRevisions(ctx, c)
require.NoError(t, err)
revs, err := rrw.ReadRevisions(ctx)
require.NoError(t, err)
require.Len(t, revs, 1)
// Running again will pick up the failed statement and try it again.
s, err = runCmd(
Root, "migrate", "apply",
"--dir", "file://testdata/sqlite2",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test2.db")),
)
require.Error(t, err)
require.Contains(t, s, "20220318104614") // currently applied version
require.Contains(t, s, "20220318104615") // retry second (partially applied)
require.NotContains(t, s, "CREATE TABLE tbl (`col` int NOT NULL);") // will not attempt stmts from first file
require.Contains(t, s, "ALTER TABLE `tbl` ADD `col_2` bigint;") // picks up first statement
require.Contains(t, s, "ALTER TABLE `tbl` ADD `col_3` bigint;") // does execute second stmt first second file
require.NotContains(t, s, "ALTER TABLE `tbl` ADD `col_4` bigint;") // but not third
require.Contains(t, s, "0 migrations ok (1 with errors)") // logs amount of migrations
require.Contains(t, s, "1 sql statements ok (1 with errors)") // logs amount of statement
require.Contains(t, s, "Error: Execution had errors:") // logs error summary
require.Contains(t, s, "near \"asdasd\": syntax error") // logs error summary
// Editing an applied line will raise error.
s, err = runCmd(
Root, "migrate", "apply",
"--dir", "file://testdata/sqlite2",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test2.db")),
"--tx-mode", "none",
)
t.Cleanup(func() {
_ = os.RemoveAll("testdata/sqlite3")
})
require.NoError(t, exec.Command("cp", "-r", "testdata/sqlite2", "testdata/sqlite3").Run())
sed(t, "s/col_2/col_5/g", "testdata/sqlite3/20220318104615_second.sql")
_, err = runCmd(Root, "migrate", "hash", "--dir", "file://testdata/sqlite3")
require.NoError(t, err)
s, err = runCmd(
Root, "migrate", "apply",
"--dir", "file://testdata/sqlite3",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test2.db")),
)
require.ErrorAs(t, err, &migrate.HistoryChangedError{})
// Fixing the migration file will finish without errors.
sed(t, "s/col_5/col_2/g", "testdata/sqlite3/20220318104615_second.sql")
sed(t, "s/asdasd //g", "testdata/sqlite3/20220318104615_second.sql")
_, err = runCmd(Root, "migrate", "hash", "--dir", "file://testdata/sqlite3")
require.NoError(t, err)
s, err = runCmd(
Root, "migrate", "apply",
"--dir", "file://testdata/sqlite3",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test2.db")),
)
require.NoError(t, err)
require.Contains(t, s, "20220318104615") // retry second (partially applied)
require.Contains(t, s, "ALTER TABLE `tbl` ADD `col_3` bigint;") // does execute second stmt first second file
require.Contains(t, s, "ALTER TABLE `tbl` ADD `col_4` bigint;") // does execute second stmt first second file
require.Contains(t, s, "1 migrations") // logs amount of migrations
require.Contains(t, s, "2") // logs amount of statement
require.NotContains(t, s, "Error: Execution had errors:") // logs error summary
require.NotContains(t, s, "near \"asdasd\": syntax error") // logs error summary
// Running again will report database being in clean state.
s, err = runCmd(
Root, "migrate", "apply",
"--dir", "file://testdata/sqlite3",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test2.db")),
)
require.NoError(t, err)
require.Equal(t, "No migration files to execute\n", s)
// Dry run will print the statements in second migration file without executing them.
// No changes to the revisions will be done.
s, err = runCmd(
Root, "migrate", "apply",
"--dir", "file://testdata/sqlite",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test.db")),
"--dry-run",
"1",
)
require.NoError(t, err)
require.Contains(t, s, "20220318104615") // log to version
require.Contains(t, s, "ALTER TABLE `tbl` ADD `col_2` bigint;") // logs statement
c1, err := sqlclient.Open(ctx, fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test.db")))
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, c1.Close())
})
sch, err = c1.InspectSchema(ctx, "", nil)
tbl, ok = sch.Table("tbl")
require.True(t, ok)
_, ok = tbl.Column("col_2")
require.False(t, ok)
rrw, err = migrate2.NewEntRevisions(ctx, c1)
require.NoError(t, err)
revs, err = rrw.ReadRevisions(ctx)
require.NoError(t, err)
require.Len(t, revs, 1)
MigrateFlags.Apply.DryRun = false // global flag, undo for rest of tests
// Prerequisites for testing missing migration behavior.
c1, err = sqlclient.Open(ctx, fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test3.db")))
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, c1.Close())
})
require.NoError(t, os.Rename(
"testdata/sqlite3/20220318104615_second.sql",
"testdata/sqlite3/20220318104616_second.sql",
))
_, err = runCmd(Root, "migrate", "hash", "--dir", "file://testdata/sqlite3")
require.NoError(t, err)
rrw, err = migrate2.NewEntRevisions(ctx, c1)
require.NoError(t, err)
require.NoError(t, rrw.Migrate(ctx))
// No changes if the last revision has a greater version than the last migration.
require.NoError(t, rrw.WriteRevision(ctx, &migrate.Revision{Version: "zzz"}))
s, err = runCmd(
Root, "migrate", "apply",
"--dir", "file://testdata/sqlite3",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test3.db")),
)
require.NoError(t, err)
require.Equal(t, "No migration files to execute\n", s)
// If the revision is before the last but after the first migration, only the last one is pending.
_, err = c1.ExecContext(ctx, "DROP table `atlas_schema_revisions`")
require.NoError(t, err)
s, err = runCmd(
Root, "migrate", "apply", "1",
"--dir", "file://testdata/sqlite3",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test3.db")),
)
require.NoError(t, rrw.WriteRevision(ctx, &migrate.Revision{Version: "20220318104615"}))
require.NoError(t, err)
s, err = runCmd(
Root, "migrate", "apply",
"--dir", "file://testdata/sqlite3",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test3.db")),
)
require.NoError(t, err)
require.NotContains(t, s, "20220318104614") // log to version
require.Contains(t, s, "20220318104616") // log to version
require.Contains(t, s, "ALTER TABLE `tbl` ADD `col_2` bigint;") // logs statement
// If the revision is before every migration file, every file is pending.
_, err = c1.ExecContext(ctx, "DROP table `atlas_schema_revisions`; DROP table `tbl`;")
require.NoError(t, err)
require.NoError(t, rrw.Migrate(ctx))
require.NoError(t, rrw.WriteRevision(ctx, &migrate.Revision{Version: "1"}))
require.NoError(t, err)
s, err = runCmd(
Root, "migrate", "apply",
"--dir", "file://testdata/sqlite3",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test3.db")),
)
require.NoError(t, err)
require.Contains(t, s, "20220318104614") // log to version
require.Contains(t, s, "20220318104616") // log to version
require.Contains(t, s, "CREATE TABLE tbl (`col` int NOT NULL);") // logs statement
require.Contains(t, s, "ALTER TABLE `tbl` ADD `col_2` bigint;") // logs statement
// If the revision is partially applied, error out.
require.NoError(t, rrw.WriteRevision(ctx, &migrate.Revision{Version: "z", Description: "z", Total: 1}))
require.NoError(t, err)
_, err = runCmd(
Root, "migrate", "apply",
"--dir", "file://testdata/sqlite3",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test3.db")),
)
require.EqualError(t, err, migrate.MissingMigrationError{Version: "z", Description: "z"}.Error())
}
func TestMigrate_ApplyTxMode(t *testing.T) {
for _, mode := range []string{"none", "file", "all"} {
t.Run(mode, func(t *testing.T) {
p := t.TempDir()
// Apply the first 2 migrations.
s, err := runCmd(
Root, "migrate", "apply",
"--dir", "file://testdata/sqlitetx",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test.db")),
"--tx-mode", mode,
"2",
)
require.NoError(t, err)
require.NotEmpty(t, s)
db, err := sql.Open("sqlite3", fmt.Sprintf("file:%s?cache=shared&_fk=1", filepath.Join(p, "test.db")))
require.NoError(t, err)
var n int
require.NoError(t, db.QueryRow("SELECT COUNT(*) FROM `friendships`").Scan(&n))
require.Equal(t, 2, n)
// Apply the rest.
s, err = runCmd(
Root, "migrate", "apply",
"--dir", "file://testdata/sqlitetx",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test.db")),
"--tx-mode", mode,
)
require.NoError(t, err)
require.NoError(t, db.QueryRow("SELECT COUNT(*) FROM `friendships`").Scan(&n))
require.Equal(t, 2, n)
// For transactions check that the foreign keys are checked before the transaction is committed.
if mode != "none" {
// Apply the first 2 migrations for the faulty one.
s, err = runCmd(
Root, "migrate", "apply",
"--dir", "file://testdata/sqlitetx_2",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test_2.db")),
"--tx-mode", mode,
"2",
)
require.NoError(t, err)
require.NotEmpty(t, s)
db, err = sql.Open("sqlite3", fmt.Sprintf("file:%s?cache=shared&_fk=1", filepath.Join(p, "test_2.db")))
require.NoError(t, err)
require.NoError(t, db.QueryRow("SELECT COUNT(*) FROM `friendships`").Scan(&n))
require.Equal(t, 2, n)
// Add an existing constraint.
c, err := sqlclient.Open(context.Background(), fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test_2.db")))
require.NoError(t, err)
_, err = c.ExecContext(context.Background(), "PRAGMA foreign_keys = off; INSERT INTO `friendships` (`user_id`, `friend_id`) VALUES (3,3);PRAGMA foreign_keys = on;")
require.NoError(t, err)
require.NoError(t, db.QueryRow("SELECT COUNT(*) FROM `friendships`").Scan(&n))
require.Equal(t, 3, n)
// Apply the rest, expect it to fail due to constraint error, but only the new one is reported.
s, err = runCmd(
Root, "migrate", "apply",
"--dir", "file://testdata/sqlitetx_2",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test_2.db")),
"--tx-mode", mode,
)
require.EqualError(t, err, "sql/sqlite: foreign key mismatch: [{tbl:friendships ref:users row:4 index:1}]")
require.NoError(t, db.QueryRow("SELECT COUNT(*) FROM `friendships`").Scan(&n))
require.Equal(t, 3, n) // was rolled back
}
})
}
}
func TestMigrate_ApplyBaseline(t *testing.T) {
p := t.TempDir()
// Run migration with baseline should store this revision in the database.
s, err := runCmd(
Root, "migrate", "apply",
"--dir", "file://testdata/baseline1",
"--baseline", "1",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test.db")),
)
require.NoError(t, err)
require.Contains(t, s, "No migration files to execute")
// Next run without baseline should run the migration from the baseline.
s, err = runCmd(
Root, "migrate", "apply",
"--dir", "file://testdata/baseline2",
"--url", fmt.Sprintf("sqlite://file:%s?cache=shared&_fk=1", filepath.Join(p, "test.db")),
)
require.NoError(t, err)
require.Contains(t, s, "Migrating to version 20220318104615 from 1 (2 migrations in total)")
}
func TestMigrate_Diff(t *testing.T) {
p := t.TempDir()
to := hclURL(t)
// Will create migration directory if not existing.
_, err := runCmd(
Root, "migrate", "diff",
"name",
"--dir", "file://"+filepath.Join(p, "migrations"),
"--dev-url", openSQLite(t, ""),
"--to", to,
)
require.NoError(t, err)
require.FileExists(t, filepath.Join(p, "migrations", fmt.Sprintf("%s_name.sql", time.Now().UTC().Format("20060102150405"))))
// Expect no clean dev error.
p = t.TempDir()
s, err := runCmd(
Root, "migrate", "diff",
"name",
"--dir", "file://"+p,
"--dev-url", openSQLite(t, "create table t (c int);"),
"--to", to,
)
require.ErrorAs(t, err, &migrate.NotCleanError{})
require.ErrorContains(t, err, "found table \"t\"")
// Works (on empty directory).
s, err = runCmd(
Root, "migrate", "diff",
"name",
"--dir", "file://"+p,
"--dev-url", openSQLite(t, ""),
"--to", to,
)
require.NoError(t, err)
require.Zero(t, s)
require.FileExists(t, filepath.Join(p, fmt.Sprintf("%s_name.sql", time.Now().UTC().Format("20060102150405"))))
require.FileExists(t, filepath.Join(p, "atlas.sum"))
// A lock will prevent diffing.
sqlclient.Register("sqlitelockdiff", sqlclient.OpenerFunc(func(ctx context.Context, u *url.URL) (*sqlclient.Client, error) {
client, err := sqlclient.Open(ctx, strings.Replace(u.String(), u.Scheme, "sqlite", 1))
if err != nil {
return nil, err
}
client.Driver = &sqliteLockerDriver{Driver: client.Driver}
return client, nil
}))
f, err := os.Create(filepath.Join(p, "test.db"))
require.NoError(t, err)
require.NoError(t, f.Close())
s, err = runCmd(
Root, "migrate", "diff",
"name",
"--dir", "file://"+t.TempDir(),
"--dev-url", fmt.Sprintf("sqlitelockdiff://file:%s?cache=shared&_fk=1", filepath.Join(p, "test.db")),
"--to", to,
)
require.True(t, strings.HasPrefix(s, "Error: acquiring database lock: "+errLock.Error()))
require.ErrorIs(t, err, errLock)
}
func TestMigrate_New(t *testing.T) {
var (
p = t.TempDir()
v = time.Now().UTC().Format("20060102150405")
)
s, err := runCmd(Root, "migrate", "new", "--dir", "file://"+p)
require.Zero(t, s)
require.NoError(t, err)
require.FileExists(t, filepath.Join(p, v+".sql"))
require.FileExists(t, filepath.Join(p, "atlas.sum"))
require.Equal(t, 2, countFiles(t, p))
s, err = runCmd(Root, "migrate", "new", "my-migration-file", "--dir", "file://"+p)
require.Zero(t, s)
require.NoError(t, err)
require.FileExists(t, filepath.Join(p, v+"_my-migration-file.sql"))
require.FileExists(t, filepath.Join(p, "atlas.sum"))
require.Equal(t, 3, countFiles(t, p))
p = t.TempDir()
s, err = runCmd(Root, "migrate", "new", "golang-migrate", "--dir", "file://"+p, "--dir-format", formatGolangMigrate)
require.Zero(t, s)
require.NoError(t, err)
require.FileExists(t, filepath.Join(p, v+"_golang-migrate.up.sql"))
require.FileExists(t, filepath.Join(p, v+"_golang-migrate.down.sql"))
require.Equal(t, 3, countFiles(t, p))
p = t.TempDir()
s, err = runCmd(Root, "migrate", "new", "goose", "--dir", "file://"+p, "--dir-format", formatGoose)
require.Zero(t, s)
require.NoError(t, err)
require.FileExists(t, filepath.Join(p, v+"_goose.sql"))
require.Equal(t, 2, countFiles(t, p))
p = t.TempDir()
s, err = runCmd(Root, "migrate", "new", "flyway", "--dir", "file://"+p, "--dir-format", formatFlyway)
require.Zero(t, s)
require.NoError(t, err)
require.FileExists(t, filepath.Join(p, fmt.Sprintf("V%s__%s.sql", v, formatFlyway)))
require.FileExists(t, filepath.Join(p, fmt.Sprintf("U%s__%s.sql", v, formatFlyway)))
require.Equal(t, 3, countFiles(t, p))
p = t.TempDir()
s, err = runCmd(Root, "migrate", "new", "liquibase", "--dir", "file://"+p, "--dir-format", formatLiquibase)
require.Zero(t, s)
require.NoError(t, err)
require.FileExists(t, filepath.Join(p, v+"_liquibase.sql"))
require.Equal(t, 2, countFiles(t, p))
p = t.TempDir()
s, err = runCmd(Root, "migrate", "new", "dbmate", "--dir", "file://"+p, "--dir-format", formatDBMate)
require.Zero(t, s)
require.NoError(t, err)
require.FileExists(t, filepath.Join(p, v+"_dbmate.sql"))
require.Equal(t, 2, countFiles(t, p))
f := filepath.Join("testdata", "mysql", "new.sql")
require.NoError(t, os.WriteFile(f, []byte("contents"), 0600))
t.Cleanup(func() { os.Remove(f) })
s, err = runCmd(Root, "migrate", "new", "--dir", "file://testdata/mysql")
require.NotZero(t, s)
require.Error(t, err)
}
func TestMigrate_Validate(t *testing.T) {
// Without re-playing.
MigrateFlags.DevURL = "" // global flags are set from other tests ...
MigrateFlags.DirFormat = "atlas" // global flags are set from other tests ...
s, err := runCmd(Root, "migrate", "validate", "--dir", "file://testdata/mysql")
require.Zero(t, s)
require.NoError(t, err)
f := filepath.Join("testdata", "mysql", "new.sql")
require.NoError(t, os.WriteFile(f, []byte("contents"), 0600))
t.Cleanup(func() { os.Remove(f) })
s, err = runCmd(Root, "migrate", "validate", "--dir", "file://testdata/mysql")
require.NotZero(t, s)
require.Error(t, err)
require.NoError(t, os.Remove(f))
// Replay migration files if a dev-url is given.
p := t.TempDir()
require.NoError(t, os.WriteFile(filepath.Join(p, "1_initial.sql"), []byte("create table t1 (c1 int)"), 0644))
require.NoError(t, os.WriteFile(filepath.Join(p, "2_second.sql"), []byte("create table t2 (c2 int)"), 0644))
_, err = runCmd(Root, "migrate", "hash", "--dir", "file://"+p)
require.NoError(t, err)
s, err = runCmd(
Root, "migrate", "validate",
"--dir", "file://"+p,
"--dev-url", openSQLite(t, ""),
)
require.Zero(t, s)
require.NoError(t, err)
// Should fail since the files are not compatible with SQLite.
_, err = runCmd(Root, "migrate", "validate", "--dir", "file://testdata/mysql", "--dev-url", openSQLite(t, ""))
require.Error(t, err)
}
func TestMigrate_Hash(t *testing.T) {
s, err := runCmd(Root, "migrate", "hash", "--dir", "file://testdata/mysql")
require.Zero(t, s)
require.NoError(t, err)
// Prints a warning if --force flag is still used.
s, err = runCmd(Root, "migrate", "hash", "--dir", "file://testdata/mysql", "--force")
require.NoError(t, err)
require.Equal(t, "Flag --force has been deprecated, you can safely omit it.\n", s)
p := t.TempDir()
err = copyFile(filepath.Join("testdata", "mysql", "20220318104614_initial.sql"), filepath.Join(p, "20220318104614_initial.sql"))
require.NoError(t, err)
s, err = runCmd(Root, "migrate", "hash", "--dir", "file://"+p)
require.Zero(t, s)
require.NoError(t, err)
require.FileExists(t, filepath.Join(p, "atlas.sum"))
d, err := os.ReadFile(filepath.Join(p, "atlas.sum"))
require.NoError(t, err)
dir, err := migrate.NewLocalDir(p)
require.NoError(t, err)
sum, err := dir.Checksum()
require.NoError(t, err)
b, err := sum.MarshalText()
require.NoError(t, err)
require.Equal(t, d, b)
p = t.TempDir()
require.NoError(t, copyFile(
filepath.Join("testdata", "mysql", "20220318104614_initial.sql"),
filepath.Join(p, "20220318104614_initial.sql"),
))
s, err = runCmd(Root, "migrate", "hash", "--dir", "file://"+os.Getenv("MIGRATION_DIR"))
require.NotZero(t, s)
require.Error(t, err)
}
func TestMigrate_Lint(t *testing.T) {
p := t.TempDir()
s, err := runCmd(
Root, "migrate", "lint",
"--dir", "file://"+p,
"--dev-url", openSQLite(t, ""),
"--latest", "1",
)
require.NoError(t, err)
require.Empty(t, s)
err = os.WriteFile(filepath.Join(p, "1.sql"), []byte("CREATE TABLE t(c int);"), 0600)
require.NoError(t, err)
err = os.WriteFile(filepath.Join(p, "2.sql"), []byte("DROP TABLE t;"), 0600)
require.NoError(t, err)
s, err = runCmd(
Root, "migrate", "lint",
"--dir", "file://"+p,
"--dev-url", openSQLite(t, ""),
"--latest", "1",
)
require.Error(t, err)
require.Equal(t, "2.sql: destructive changes detected:\n\n\tL1: Dropping table \"t\"\n\n", s)
s, err = runCmd(
Root, "migrate", "lint",
"--dir", "file://"+p,
"--dev-url", openSQLite(t, ""),
"--latest", "1",
"--log", "{{ range .Files }}{{ .Name }}{{ end }}",
)
require.Error(t, err)
require.Equal(t, "2.sql", s)
// Change files to golang-migrate format.
require.NoError(t, os.Rename(filepath.Join(p, "1.sql"), filepath.Join(p, "1.up.sql")))
require.NoError(t, os.Rename(filepath.Join(p, "2.sql"), filepath.Join(p, "1.down.sql")))
s, err = runCmd(
Root, "migrate", "lint",
"--dir", "file://"+p,
"--dir-format", "golang-migrate",
"--dev-url", openSQLite(t, ""),
"--latest", "2",
"--log", "{{ range .Files }}{{ .Name }}:{{ len .Reports }}{{ end }}",
)
require.NoError(t, err)
require.Equal(t, "1.up.sql:0", s)
// Invalid files.
MigrateFlags.Lint.Format = ""
err = os.WriteFile(filepath.Join(p, "2.up.sql"), []byte("BORING"), 0600)
require.NoError(t, err)
s, err = runCmd(
Root, "migrate", "lint",
"--dir", "file://"+p,
"--dir-format", "golang-migrate",
"--dev-url", openSQLite(t, ""),
"--latest", "1",
)
require.Error(t, err)
require.Equal(t, "2.up.sql: executing statement: near \"BORING\": syntax error\n", s)
}
const testSchema = `
schema "main" {
}
table "table" {
schema = schema.main
column "col" {
type = int
comment = "column comment"
}
column "age" {
type = int
}
column "price1" {
type = int
}
column "price2" {
type = int
}
column "account_name" {
type = varchar(32)
null = true
}
column "created_at" {
type = datetime
default = sql("current_timestamp")
}
primary_key {
columns = [table.table.column.col]
}
index "index" {
unique = true
columns = [
table.table.column.col,
table.table.column.age,
]
comment = "index comment"
}
foreign_key "accounts" {
columns = [
table.table.column.account_name,
]
ref_columns = [
table.accounts.column.name,
]
on_delete = SET_NULL
on_update = "NO_ACTION"
}
check "positive price" {
expr = "price1 > 0"
}
check {
expr = "price1 <> price2"
enforced = true
}
check {
expr = "price2 <> price1"
enforced = false
}
comment = "table comment"
}
table "accounts" {
schema = schema.main
column "name" {
type = varchar(32)
}
column "unsigned_float" {
type = float(10)
unsigned = true
}
column "unsigned_decimal" {
type = decimal(10, 2)
unsigned = true
}
primary_key {
columns = [table.accounts.column.name]
}
}`
func hclURL(t *testing.T) string {
p := t.TempDir()
require.NoError(t, os.WriteFile(filepath.Join(p, "schema.hcl"), []byte(testSchema), 0600))
return "file://" + filepath.Join(p, "schema.hcl")
}
func copyFile(src, dst string) error {
sf, err := os.Open(src)
if err != nil {
return err
}
defer sf.Close()
df, err := os.Create(dst)
if err != nil {
return err
}
defer df.Close()
_, err = io.Copy(df, sf)
return err
}
type sqliteLockerDriver struct{ migrate.Driver }
var errLock = errors.New("lockErr")
func (d *sqliteLockerDriver) Lock(context.Context, string, time.Duration) (schema.UnlockFunc, error) {
return func() error { return nil }, errLock
}
func (d *sqliteLockerDriver) Snapshot(ctx context.Context) (migrate.RestoreFunc, error) {
return d.Driver.(migrate.Snapshoter).Snapshot(ctx)
}
func (d *sqliteLockerDriver) CheckClean(ctx context.Context, revT *migrate.TableIdent) error {
return d.Driver.(migrate.CleanChecker).CheckClean(ctx, revT)
}
func countFiles(t *testing.T, p string) int {
files, err := os.ReadDir(p)
require.NoError(t, err)
return len(files)
}
func sed(t *testing.T, r, p string) {
args := []string{"-i"}
if runtime.GOOS == "darwin" {
args = append(args, ".bk")
}
buf, err := exec.Command("sed", append(args, r, p)...).CombinedOutput()
require.NoError(t, err, string(buf))
}
atlas-0.7.2/cmd/atlas/internal/cmdapi/project.go 0000664 0000000 0000000 00000012245 14314555116 0021552 0 ustar 00root root 0000000 0000000 // Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package cmdapi
import (
"errors"
"fmt"
"os"
"ariga.io/atlas/schemahcl"
)
const projectFileName = "atlas.hcl"
type loadConfig struct {
inputVals map[string]string
}
// LoadOption configures the LoadEnv function.
type LoadOption func(*loadConfig)
// WithInput is a LoadOption that sets the input values for the LoadEnv function.
func WithInput(vals map[string]string) LoadOption {
return func(config *loadConfig) {
config.inputVals = vals
}
}
type (
// Project represents an atlas.hcl project file.
Project struct {
Envs []*Env `spec:"env"` // List of environments
Lint *Lint `spec:"lint"` // Optional global lint config
}
// Env represents an Atlas environment.
Env struct {
// Name for this environment.
Name string `spec:"name,name"`
// URL of the database.
URL string `spec:"url"`
// URL of the dev-database for this environment.
// See: https://atlasgo.io/dev-database
DevURL string `spec:"dev"`
// List of schemas in this database that are managed by Atlas.
Schemas []string `spec:"schemas"`
// Exclude defines a list of glob patterns used to filter
// resources on inspection.
Exclude []string `spec:"exclude"`
// Migration containing the migration configuration of the env.
Migration *Migration `spec:"migration"`
// Lint of the environment.
Lint *Lint `spec:"lint"`
schemahcl.DefaultExtension
}
// Migration represents the migration directory for the Env.
Migration struct {
Dir string `spec:"dir"`
Format string `spec:"format"`
RevisionsSchema string `spec:"revisions_schema"`
}
// Lint represents the configuration of migration linting.
Lint struct {
// Log configures the --log option.
Log string `spec:"log"`
// Latest configures the --latest option.
Latest int `spec:"latest"`
Git struct {
// Dir configures the --git-dir option.
Dir string `spec:"dir"`
// Base configures the --git-base option.
Base string `spec:"base"`
} `spec:"git"`
schemahcl.DefaultExtension
}
)
// Extend allows extending environment blocks with
// a global one. For example:
//
// lint {
// log = <