mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-14 17:02:49 +03:00
cli: add migrate
and metadata
packages
> ### Description > This PR adds two new packages which implement the CLI requirements specified in RFC:https://github.com/hasura/lux/blob/cloud/docs/rfcs/20210614_github_integration.md 1. `pkg/metadata` ![image](https://user-images.githubusercontent.com/8335904/122384828-b4757d80-cf89-11eb-9e21-ef116fb928e9.png) 2. `pkg/migrate` ![image](https://user-images.githubusercontent.com/8335904/122510554-68771700-d023-11eb-9f5d-046d2c0cf18a.png) ### Changelog - [x] `CHANGELOG.md` is updated with user-facing content relevant to this PR. If no changelog is required, then add the `no-changelog-required` label. ### Affected components - [x] CLI https://github.com/hasura/graphql-engine-mono/pull/1598 GitOrigin-RevId: 0e2bce498386c5aae68dbca0fe383a6afff9d1a9
This commit is contained in:
parent
8a77386fcf
commit
c7ac1ede3f
13
cli/cli.go
13
cli/cli.go
@ -12,6 +12,7 @@ import (
|
|||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@ -354,7 +355,8 @@ type Config struct {
|
|||||||
type ExecutionContext struct {
|
type ExecutionContext struct {
|
||||||
// CMDName is the name of CMD (os.Args[0]). To be filled in later to
|
// CMDName is the name of CMD (os.Args[0]). To be filled in later to
|
||||||
// correctly render example strings etc.
|
// correctly render example strings etc.
|
||||||
CMDName string
|
CMDName string
|
||||||
|
Stderr, Stdout io.Writer
|
||||||
|
|
||||||
// ID is a unique ID for this Execution
|
// ID is a unique ID for this Execution
|
||||||
ID string
|
ID string
|
||||||
@ -456,7 +458,10 @@ type Source struct {
|
|||||||
|
|
||||||
// NewExecutionContext returns a new instance of execution context
|
// NewExecutionContext returns a new instance of execution context
|
||||||
func NewExecutionContext() *ExecutionContext {
|
func NewExecutionContext() *ExecutionContext {
|
||||||
ec := &ExecutionContext{}
|
ec := &ExecutionContext{
|
||||||
|
Stderr: os.Stderr,
|
||||||
|
Stdout: os.Stdout,
|
||||||
|
}
|
||||||
ec.Telemetry = telemetry.BuildEvent()
|
ec.Telemetry = telemetry.BuildEvent()
|
||||||
ec.Telemetry.Version = version.BuildVersion
|
ec.Telemetry.Version = version.BuildVersion
|
||||||
return ec
|
return ec
|
||||||
@ -880,7 +885,7 @@ func (ec *ExecutionContext) readConfig() error {
|
|||||||
func (ec *ExecutionContext) setupSpinner() {
|
func (ec *ExecutionContext) setupSpinner() {
|
||||||
if ec.Spinner == nil {
|
if ec.Spinner == nil {
|
||||||
spnr := spinner.New(spinner.CharSets[7], 100*time.Millisecond)
|
spnr := spinner.New(spinner.CharSets[7], 100*time.Millisecond)
|
||||||
spnr.Writer = os.Stderr
|
spnr.Writer = ec.Stderr
|
||||||
ec.Spinner = spnr
|
ec.Spinner = spnr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -920,7 +925,7 @@ func (ec *ExecutionContext) setupLogger() {
|
|||||||
if ec.Logger == nil {
|
if ec.Logger == nil {
|
||||||
logger := logrus.New()
|
logger := logrus.New()
|
||||||
ec.Logger = logger
|
ec.Logger = logger
|
||||||
ec.Logger.SetOutput(os.Stderr)
|
ec.Logger.SetOutput(ec.Stderr)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ec.LogLevel != "" {
|
if ec.LogLevel != "" {
|
||||||
|
@ -62,7 +62,7 @@ func (o *MetadataApplyOptions) Run() error {
|
|||||||
if !o.DryRun {
|
if !o.DryRun {
|
||||||
o.EC.Spin("Applying metadata...")
|
o.EC.Spin("Applying metadata...")
|
||||||
if o.EC.Config.Version == cli.V2 {
|
if o.EC.Config.Version == cli.V2 {
|
||||||
err := metadataHandler.V1ApplyMetadata()
|
_, err := metadataHandler.V1ApplyMetadata()
|
||||||
o.EC.Spinner.Stop()
|
o.EC.Spinner.Stop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errorApplyingMetadata(err)
|
return errorApplyingMetadata(err)
|
||||||
|
@ -2,12 +2,13 @@ package commands
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/aryann/difflib"
|
"io"
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/aryann/difflib"
|
||||||
|
|
||||||
"github.com/hasura/graphql-engine/cli/v2/internal/metadataobject"
|
"github.com/hasura/graphql-engine/cli/v2/internal/metadataobject"
|
||||||
|
|
||||||
"github.com/hasura/graphql-engine/cli/v2"
|
"github.com/hasura/graphql-engine/cli/v2"
|
||||||
@ -21,10 +22,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type MetadataDiffOptions struct {
|
type MetadataDiffOptions struct {
|
||||||
EC *cli.ExecutionContext
|
EC *cli.ExecutionContext
|
||||||
Output io.Writer
|
Output io.Writer
|
||||||
Args []string
|
Args []string
|
||||||
DiffType string
|
DiffType string
|
||||||
|
DisableColor bool
|
||||||
// two Metadata to diff, 2nd is server if it's empty
|
// two Metadata to diff, 2nd is server if it's empty
|
||||||
Metadata [2]string
|
Metadata [2]string
|
||||||
}
|
}
|
||||||
@ -146,9 +148,9 @@ func (o *MetadataDiffOptions) runv2(args []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if o.Metadata[1] != "" {
|
if o.Metadata[1] != "" {
|
||||||
err = printDiff(string(oldYaml), string(newYaml), o.Metadata[0], o.Metadata[1], o.Output, o.DiffType)
|
err = printDiff(string(oldYaml), string(newYaml), o.Metadata[0], o.Metadata[1], o.Output, o.DiffType, o.DisableColor)
|
||||||
} else {
|
} else {
|
||||||
err = printDiff(string(oldYaml), string(newYaml), o.Metadata[0], "server", o.Output, o.DiffType)
|
err = printDiff(string(oldYaml), string(newYaml), o.Metadata[0], "server", o.Output, o.DiffType, o.DisableColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -164,35 +166,42 @@ func (o *MetadataDiffOptions) Run() error {
|
|||||||
return fmt.Errorf("metadata diff for config %d not supported", o.EC.Config.Version)
|
return fmt.Errorf("metadata diff for config %d not supported", o.EC.Config.Version)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Difftype string
|
type Difftype string
|
||||||
|
|
||||||
const DifftypeUnifiedCommon Difftype = "unified-common"
|
const DifftypeUnifiedCommon Difftype = "unified-common"
|
||||||
|
|
||||||
func printDiff(before, after, firstArg, SecondArg string, to io.Writer, difftype string) error {
|
func printDiff(before, after, firstArg, SecondArg string, to io.Writer, difftype string, disableColor bool) error {
|
||||||
diffType := Difftype(difftype)
|
diffType := Difftype(difftype)
|
||||||
switch diffType {
|
switch diffType {
|
||||||
case DifftypeUnifiedCommon:
|
case DifftypeUnifiedCommon:
|
||||||
printDiffv1(before, after, to)
|
printDiffv1(before, after, to)
|
||||||
default:
|
default:
|
||||||
return printDiffv2(before, after, firstArg, SecondArg, to)
|
return printDiffv2(before, after, firstArg, SecondArg, to, disableColor)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func printDiffv2(before, after, firstArg, SecondArg string, to io.Writer) error {
|
func printDiffv2(before, after, firstArg, SecondArg string, to io.Writer, disableColor bool) error {
|
||||||
edits := myers.ComputeEdits(span.URIFromPath("a.txt"), before, after)
|
edits := myers.ComputeEdits(span.URIFromPath("a.txt"), before, after)
|
||||||
text := fmt.Sprint(gotextdiff.ToUnified(firstArg, SecondArg, before, edits))
|
text := fmt.Sprint(gotextdiff.ToUnified(firstArg, SecondArg, before, edits))
|
||||||
|
makeDiffLine := func(line, color string) string {
|
||||||
|
if disableColor {
|
||||||
|
return line
|
||||||
|
}
|
||||||
|
return ansi.Color(line, color)
|
||||||
|
}
|
||||||
lines := strings.Split(text, "\n")
|
lines := strings.Split(text, "\n")
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
if line == "" {
|
if line == "" {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if (string)(line[0]) == "-" {
|
if (string)(line[0]) == "-" {
|
||||||
fmt.Fprintf(to, "%s\n", ansi.Color(line, "red"))
|
fmt.Fprintf(to, "%s\n", makeDiffLine(line, "red"))
|
||||||
} else if (string)(line[0]) == "+" {
|
} else if (string)(line[0]) == "+" {
|
||||||
fmt.Fprintf(to, "%s\n", ansi.Color(line, "yellow"))
|
fmt.Fprintf(to, "%s\n", makeDiffLine(line, "yellow"))
|
||||||
} else if (string)(line[0]) == "@" {
|
} else if (string)(line[0]) == "@" {
|
||||||
fmt.Fprintf(to, "%s\n", ansi.Color(line, "cyan"))
|
fmt.Fprintf(to, "%s\n", makeDiffLine(line, "cyan"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,19 +209,19 @@ func printDiffv2(before, after, firstArg, SecondArg string, to io.Writer) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
func printDiffv1(before, after string, to io.Writer) {
|
func printDiffv1(before, after string, to io.Writer) {
|
||||||
diffs := difflib.Diff(strings.Split(before, "\n"), strings.Split(after, "\n"))
|
diffs := difflib.Diff(strings.Split(before, "\n"), strings.Split(after, "\n"))
|
||||||
|
|
||||||
for _, diff := range diffs {
|
for _, diff := range diffs {
|
||||||
text := diff.Payload
|
text := diff.Payload
|
||||||
switch diff.Delta {
|
switch diff.Delta {
|
||||||
case difflib.RightOnly:
|
case difflib.RightOnly:
|
||||||
fmt.Fprintf(to, "%s\n", ansi.Color(text, "green"))
|
fmt.Fprintf(to, "%s\n", ansi.Color(text, "green"))
|
||||||
case difflib.LeftOnly:
|
case difflib.LeftOnly:
|
||||||
fmt.Fprintf(to, "%s\n", ansi.Color(text, "red"))
|
fmt.Fprintf(to, "%s\n", ansi.Color(text, "red"))
|
||||||
case difflib.Common:
|
case difflib.Common:
|
||||||
fmt.Fprintf(to, "%s\n", text)
|
fmt.Fprintf(to, "%s\n", text)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkDir(path string) error {
|
func checkDir(path string) error {
|
||||||
|
@ -47,7 +47,7 @@ func (o *metadataReloadOptions) run() error {
|
|||||||
|
|
||||||
var err error
|
var err error
|
||||||
metadataHandler := metadataobject.NewHandlerFromEC(ec)
|
metadataHandler := metadataobject.NewHandlerFromEC(ec)
|
||||||
err = metadataHandler.ReloadMetadata()
|
_, err = metadataHandler.ReloadMetadata()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Cannot reload metadata")
|
return errors.Wrap(err, "Cannot reload metadata")
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/hasura/graphql-engine/cli/v2/internal/hasura"
|
||||||
|
|
||||||
"github.com/hasura/graphql-engine/cli/v2/internal/metadatautil"
|
"github.com/hasura/graphql-engine/cli/v2/internal/metadatautil"
|
||||||
|
|
||||||
"github.com/hasura/graphql-engine/cli/v2"
|
"github.com/hasura/graphql-engine/cli/v2"
|
||||||
@ -61,80 +63,7 @@ func newMigrateApplyCmd(ec *cli.ExecutionContext) *cobra.Command {
|
|||||||
return validateConfigV3Flags(cmd, ec)
|
return validateConfigV3Flags(cmd, ec)
|
||||||
},
|
},
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
opts.Source = ec.Source
|
return opts.Run()
|
||||||
if opts.dryRun && opts.SkipExecution {
|
|
||||||
return errors.New("both --skip-execution and --dry-run flags cannot be used together")
|
|
||||||
}
|
|
||||||
if opts.allDatabases {
|
|
||||||
opts.EC.Spin("getting lists of databases from server ")
|
|
||||||
sourcesAndKind, err := metadatautil.GetSourcesAndKind(ec.APIClient.V1Metadata.ExportMetadata)
|
|
||||||
opts.EC.Spinner.Stop()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("determing list of connected sources and kind: %w", err)
|
|
||||||
}
|
|
||||||
for _, source := range sourcesAndKind {
|
|
||||||
opts.Source.Kind = source.Kind
|
|
||||||
opts.Source.Name = source.Name
|
|
||||||
if !opts.dryRun {
|
|
||||||
opts.EC.Spin(fmt.Sprintf("Applying migrations on database: %s ", opts.Source.Name))
|
|
||||||
}
|
|
||||||
err := opts.Run()
|
|
||||||
opts.EC.Spinner.Stop()
|
|
||||||
if err != nil {
|
|
||||||
if err == migrate.ErrNoChange {
|
|
||||||
opts.EC.Logger.Infof("nothing to apply on database: %s", opts.Source.Name)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if e, ok := err.(*os.PathError); ok {
|
|
||||||
// If Op is first, then log No migrations to apply
|
|
||||||
if e.Op == "first" {
|
|
||||||
opts.EC.Logger.Infof("nothing to apply on database: %s", opts.Source.Name)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// check if the returned error is a directory not found error
|
|
||||||
// ie might be because a migrations/<source_name> directory is not found
|
|
||||||
// if so skip this
|
|
||||||
if e, ok := err.(*errDatabaseMigrationDirectoryNotFound); ok {
|
|
||||||
opts.EC.Logger.Errorf("skipping applying migrations for database %s, encountered: \n%s", opts.Source.Name, e.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
opts.EC.Logger.Errorf("skipping applying migrations for database %s, encountered: \n%v", opts.Source.Name, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
opts.EC.Logger.Infof("applied migrations on database: %s", opts.Source.Name)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if !opts.dryRun {
|
|
||||||
opts.EC.Spin("Applying migrations...")
|
|
||||||
}
|
|
||||||
err := opts.Run()
|
|
||||||
opts.EC.Spinner.Stop()
|
|
||||||
if err != nil {
|
|
||||||
if err == migrate.ErrNoChange {
|
|
||||||
opts.EC.Logger.Info("nothing to apply")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// check if the returned error is a directory not found error
|
|
||||||
// ie might be because a migrations/<source_name> directory is not found
|
|
||||||
// if so skip this
|
|
||||||
if e, ok := err.(*errDatabaseMigrationDirectoryNotFound); ok {
|
|
||||||
return fmt.Errorf("applying migrations on database %s: %w", opts.Source.Name, e)
|
|
||||||
}
|
|
||||||
if e, ok := err.(*os.PathError); ok {
|
|
||||||
// If Op is first, then log No migrations to apply
|
|
||||||
if e.Op == "first" {
|
|
||||||
opts.EC.Logger.Info("nothing to apply")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fmt.Errorf("apply failed\n%w", err)
|
|
||||||
}
|
|
||||||
if !opts.dryRun {
|
|
||||||
opts.EC.Logger.Info("migrations applied")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
f := migrateApplyCmd.Flags()
|
f := migrateApplyCmd.Flags()
|
||||||
@ -148,8 +77,8 @@ func newMigrateApplyCmd(ec *cli.ExecutionContext) *cobra.Command {
|
|||||||
f.BoolVar(&opts.SkipExecution, "skip-execution", false, "skip executing the migration action, but mark them as applied")
|
f.BoolVar(&opts.SkipExecution, "skip-execution", false, "skip executing the migration action, but mark them as applied")
|
||||||
f.StringVar(&opts.MigrationType, "type", "up", "type of migration (up, down) to be used with version flag")
|
f.StringVar(&opts.MigrationType, "type", "up", "type of migration (up, down) to be used with version flag")
|
||||||
|
|
||||||
f.BoolVar(&opts.dryRun, "dry-run", false, "print the names of migrations which are going to be applied")
|
f.BoolVar(&opts.DryRun, "dry-run", false, "print the names of migrations which are going to be applied")
|
||||||
f.BoolVar(&opts.allDatabases, "all-databases", false, "set this flag to attempt to apply migrations on all databases present on server")
|
f.BoolVar(&opts.AllDatabases, "all-databases", false, "set this flag to attempt to apply migrations on all databases present on server")
|
||||||
return migrateApplyCmd
|
return migrateApplyCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,10 +92,42 @@ type MigrateApplyOptions struct {
|
|||||||
// version up to which migration chain has to be applied
|
// version up to which migration chain has to be applied
|
||||||
GotoVersion string
|
GotoVersion string
|
||||||
SkipExecution bool
|
SkipExecution bool
|
||||||
dryRun bool
|
DryRun bool
|
||||||
Source cli.Source
|
Source cli.Source
|
||||||
allDatabases bool
|
AllDatabases bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *MigrateApplyOptions) Validate() error {
|
||||||
|
if o.EC.Config.Version == cli.V2 {
|
||||||
|
o.Source.Kind = hasura.SourceKindPG
|
||||||
|
o.Source.Name = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.EC.Config.Version >= cli.V3 {
|
||||||
|
if !o.AllDatabases && len(o.Source.Name) == 0 {
|
||||||
|
return fmt.Errorf("unable to determine database on which migration should be applied")
|
||||||
|
}
|
||||||
|
if !o.AllDatabases {
|
||||||
|
if len(o.Source.Name) == 0 {
|
||||||
|
return fmt.Errorf("empty database name")
|
||||||
|
}
|
||||||
|
if len(o.Source.Kind) == 0 {
|
||||||
|
// find out the database kind by making a API call to server
|
||||||
|
// and update ec to include the database name and kind
|
||||||
|
sourceKind, err := metadatautil.GetSourceKind(o.EC.APIClient.V1Metadata.ExportMetadata, o.Source.Name)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("determining database kind of %s: %w", o.Source.Name, err)
|
||||||
|
}
|
||||||
|
if sourceKind == nil {
|
||||||
|
return fmt.Errorf("error determining database kind for %s, check if database exists on hasura", o.Source.Name)
|
||||||
|
}
|
||||||
|
o.Source.Kind = *sourceKind
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type errDatabaseMigrationDirectoryNotFound struct {
|
type errDatabaseMigrationDirectoryNotFound struct {
|
||||||
message string
|
message string
|
||||||
}
|
}
|
||||||
@ -175,6 +136,87 @@ func (e *errDatabaseMigrationDirectoryNotFound) Error() string {
|
|||||||
return e.message
|
return e.message
|
||||||
}
|
}
|
||||||
func (o *MigrateApplyOptions) Run() error {
|
func (o *MigrateApplyOptions) Run() error {
|
||||||
|
if len(o.Source.Name) == 0 {
|
||||||
|
o.Source = o.EC.Source
|
||||||
|
}
|
||||||
|
if err := o.Validate(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if o.DryRun && o.SkipExecution {
|
||||||
|
return errors.New("both --skip-execution and --dry-run flags cannot be used together")
|
||||||
|
}
|
||||||
|
if o.AllDatabases && o.EC.Config.Version >= cli.V3 {
|
||||||
|
o.EC.Spin("getting lists of databases from server ")
|
||||||
|
sourcesAndKind, err := metadatautil.GetSourcesAndKind(o.EC.APIClient.V1Metadata.ExportMetadata)
|
||||||
|
o.EC.Spinner.Stop()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("determing list of connected sources and kind: %w", err)
|
||||||
|
}
|
||||||
|
for _, source := range sourcesAndKind {
|
||||||
|
o.Source.Kind = source.Kind
|
||||||
|
o.Source.Name = source.Name
|
||||||
|
if !o.DryRun {
|
||||||
|
o.EC.Spin(fmt.Sprintf("Applying migrations on database: %s ", o.Source.Name))
|
||||||
|
}
|
||||||
|
err := o.Exec()
|
||||||
|
o.EC.Spinner.Stop()
|
||||||
|
if err != nil {
|
||||||
|
if err == migrate.ErrNoChange {
|
||||||
|
o.EC.Logger.Infof("nothing to apply on database: %s", o.Source.Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if e, ok := err.(*os.PathError); ok {
|
||||||
|
// If Op is first, then log No migrations to apply
|
||||||
|
if e.Op == "first" {
|
||||||
|
o.EC.Logger.Infof("nothing to apply on database: %s", o.Source.Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check if the returned error is a directory not found error
|
||||||
|
// ie might be because a migrations/<source_name> directory is not found
|
||||||
|
// if so skip this
|
||||||
|
if e, ok := err.(*errDatabaseMigrationDirectoryNotFound); ok {
|
||||||
|
o.EC.Logger.Errorf("skipping applying migrations for database %s, encountered: \n%s", o.Source.Name, e.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
o.EC.Logger.Errorf("skipping applying migrations for database %s, encountered: \n%v", o.Source.Name, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
o.EC.Logger.Infof("applied migrations on database: %s", o.Source.Name)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if !o.DryRun {
|
||||||
|
o.EC.Spin("Applying migrations...")
|
||||||
|
}
|
||||||
|
err := o.Exec()
|
||||||
|
o.EC.Spinner.Stop()
|
||||||
|
if err != nil {
|
||||||
|
if err == migrate.ErrNoChange {
|
||||||
|
o.EC.Logger.Info("nothing to apply")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// check if the returned error is a directory not found error
|
||||||
|
// ie might be because a migrations/<source_name> directory is not found
|
||||||
|
// if so skip this
|
||||||
|
if e, ok := err.(*errDatabaseMigrationDirectoryNotFound); ok {
|
||||||
|
return fmt.Errorf("applying migrations on database %s: %w", o.Source.Name, e)
|
||||||
|
}
|
||||||
|
if e, ok := err.(*os.PathError); ok {
|
||||||
|
// If Op is first, then log No migrations to apply
|
||||||
|
if e.Op == "first" {
|
||||||
|
o.EC.Logger.Info("nothing to apply")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Errorf("apply failed\n%w", err)
|
||||||
|
}
|
||||||
|
if !o.DryRun {
|
||||||
|
o.EC.Logger.Info("migrations applied")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (o *MigrateApplyOptions) Exec() error {
|
||||||
if o.EC.Config.Version >= cli.V3 {
|
if o.EC.Config.Version >= cli.V3 {
|
||||||
// check if a migrations directory exists for source in project
|
// check if a migrations directory exists for source in project
|
||||||
migrationDirectory := filepath.Join(o.EC.MigrationDir, o.Source.Name)
|
migrationDirectory := filepath.Join(o.EC.MigrationDir, o.Source.Name)
|
||||||
@ -182,7 +224,7 @@ func (o *MigrateApplyOptions) Run() error {
|
|||||||
return &errDatabaseMigrationDirectoryNotFound{fmt.Sprintf("expected to find a migrations directory for database %s in %s, but encountered error: %s", o.Source.Name, o.EC.MigrationDir, err.Error())}
|
return &errDatabaseMigrationDirectoryNotFound{fmt.Sprintf("expected to find a migrations directory for database %s in %s, but encountered error: %s", o.Source.Name, o.EC.MigrationDir, err.Error())}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if o.allDatabases && (len(o.GotoVersion) > 0 || len(o.VersionMigration) > 0) {
|
if o.AllDatabases && (len(o.GotoVersion) > 0 || len(o.VersionMigration) > 0) {
|
||||||
return fmt.Errorf("cannot use --goto or --version in conjunction with --all-databases")
|
return fmt.Errorf("cannot use --goto or --version in conjunction with --all-databases")
|
||||||
}
|
}
|
||||||
migrationType, step, err := getMigrationTypeAndStep(o.UpMigration, o.DownMigration, o.VersionMigration, o.MigrationType, o.GotoVersion, o.SkipExecution)
|
migrationType, step, err := getMigrationTypeAndStep(o.UpMigration, o.DownMigration, o.VersionMigration, o.MigrationType, o.GotoVersion, o.SkipExecution)
|
||||||
@ -195,7 +237,7 @@ func (o *MigrateApplyOptions) Run() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
migrateDrv.SkipExecution = o.SkipExecution
|
migrateDrv.SkipExecution = o.SkipExecution
|
||||||
migrateDrv.DryRun = o.dryRun
|
migrateDrv.DryRun = o.DryRun
|
||||||
|
|
||||||
return ExecuteMigration(migrationType, migrateDrv, step)
|
return ExecuteMigration(migrationType, migrateDrv, step)
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
|
|
||||||
|
"github.com/hasura/graphql-engine/cli/v2/internal/hasura"
|
||||||
|
|
||||||
"github.com/hasura/graphql-engine/cli/v2/util"
|
"github.com/hasura/graphql-engine/cli/v2/util"
|
||||||
|
|
||||||
"github.com/hasura/graphql-engine/cli/v2"
|
"github.com/hasura/graphql-engine/cli/v2"
|
||||||
@ -52,6 +54,10 @@ type MigrateStatusOptions struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (o *MigrateStatusOptions) Run() (*migrate.Status, error) {
|
func (o *MigrateStatusOptions) Run() (*migrate.Status, error) {
|
||||||
|
if o.EC.Config.Version <= cli.V2 {
|
||||||
|
o.Source.Name = ""
|
||||||
|
o.Source.Kind = hasura.SourceKindPG
|
||||||
|
}
|
||||||
migrateDrv, err := migrate.NewMigrate(o.EC, true, o.Source.Name, o.Source.Kind)
|
migrateDrv, err := migrate.NewMigrate(o.EC, true, o.Source.Name, o.Source.Kind)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -46,7 +46,6 @@ require (
|
|||||||
github.com/ory/dockertest/v3 v3.6.3
|
github.com/ory/dockertest/v3 v3.6.3
|
||||||
github.com/parnurzeal/gorequest v0.2.16
|
github.com/parnurzeal/gorequest v0.2.16
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/pmezard/go-difflib v1.0.0
|
|
||||||
github.com/qor/admin v0.0.0-20191205023516-9032e7fec172 // indirect
|
github.com/qor/admin v0.0.0-20191205023516-9032e7fec172 // indirect
|
||||||
github.com/qor/assetfs v0.0.0-20170713023933-ff57fdc13a14 // indirect
|
github.com/qor/assetfs v0.0.0-20170713023933-ff57fdc13a14 // indirect
|
||||||
github.com/qor/audited v0.0.0-20171228121055-b52c9c2f0571 // indirect
|
github.com/qor/audited v0.0.0-20171228121055-b52c9c2f0571 // indirect
|
||||||
|
39
cli/go.sum
39
cli/go.sum
@ -176,8 +176,6 @@ github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG
|
|||||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/gobuffalo/here v0.6.0 h1:hYrd0a6gDmWxBM4TnrGw8mQg24iSVoIkHEk7FodQcBI=
|
|
||||||
github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM=
|
|
||||||
github.com/goccy/go-yaml v1.8.8 h1:MGfRB1GeSn/hWXYWS2Pt67iC2GJNnebdIro01ddyucA=
|
github.com/goccy/go-yaml v1.8.8 h1:MGfRB1GeSn/hWXYWS2Pt67iC2GJNnebdIro01ddyucA=
|
||||||
github.com/goccy/go-yaml v1.8.8/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA=
|
github.com/goccy/go-yaml v1.8.8/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA=
|
||||||
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
@ -313,7 +311,6 @@ github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v
|
|||||||
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
@ -379,7 +376,6 @@ github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9
|
|||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
|
github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
|
||||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||||
@ -414,8 +410,6 @@ github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtb
|
|||||||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
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.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
@ -472,17 +466,13 @@ github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYe
|
|||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
|
||||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||||
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
||||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
|
||||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
|
||||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
@ -549,12 +539,8 @@ github.com/yosssi/gohtml v0.0.0-20190915184251-7ff6f235ecaf h1:VA200mPTYh9FWY8zK
|
|||||||
github.com/yosssi/gohtml v0.0.0-20190915184251-7ff6f235ecaf/go.mod h1:+ccdNT0xMY1dtc5XBxumbYfOUhmduiGudqaDgD2rVRE=
|
github.com/yosssi/gohtml v0.0.0-20190915184251-7ff6f235ecaf/go.mod h1:+ccdNT0xMY1dtc5XBxumbYfOUhmduiGudqaDgD2rVRE=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
|
||||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
|
||||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
|
||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
|
||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
@ -622,7 +608,6 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/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-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
@ -667,11 +652,8 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/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-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@ -725,7 +707,6 @@ golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBn
|
|||||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
@ -751,13 +732,9 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK
|
|||||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
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-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-20191204190536-9bdfabe68543/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 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||||
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=
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
@ -771,12 +748,8 @@ google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/
|
|||||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
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.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
|
||||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
@ -800,12 +773,8 @@ google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfG
|
|||||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
@ -827,7 +796,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
|
|||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
|
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
|
||||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||||
@ -852,11 +820,8 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/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.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.3.0/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 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
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.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
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-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||||
@ -869,13 +834,9 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh
|
|||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
|
||||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
moul.io/http2curl v1.0.0 h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8=
|
moul.io/http2curl v1.0.0 h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8=
|
||||||
moul.io/http2curl v1.0.0 h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8=
|
|
||||||
moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE=
|
moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE=
|
||||||
moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE=
|
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||||
|
@ -27,7 +27,7 @@ func TestMigrateCmd(t *testing.T, ec *cli.ExecutionContext) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to copy migrations directory %v", err)
|
t.Fatalf("unable to copy migrations directory %v", err)
|
||||||
}
|
}
|
||||||
|
ec.Source.Kind = hasura.SourceKindPG
|
||||||
tt := []struct {
|
tt := []struct {
|
||||||
name string
|
name string
|
||||||
opts migrateInterface
|
opts migrateInterface
|
||||||
|
@ -27,7 +27,8 @@ func TestMigrateCmd(t *testing.T, ec *cli.ExecutionContext) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to copy migrations directory %v", err)
|
t.Fatalf("unable to copy migrations directory %v", err)
|
||||||
}
|
}
|
||||||
|
ec.Source.Name = "default"
|
||||||
|
ec.Source.Kind = hasura.SourceKindPG
|
||||||
tt := []struct {
|
tt := []struct {
|
||||||
name string
|
name string
|
||||||
opts migrateInterface
|
opts migrateInterface
|
||||||
|
@ -88,10 +88,10 @@ func (h *Handler) ResetMetadata() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ReloadMetadata - Reload Hasura GraphQL Engine metadata on the database
|
// ReloadMetadata - Reload Hasura GraphQL Engine metadata on the database
|
||||||
func (h *Handler) ReloadMetadata() error {
|
func (h *Handler) ReloadMetadata() (io.Reader, error) {
|
||||||
var err error
|
var err error
|
||||||
_, err = h.v1MetadataOps.ReloadMetadata()
|
r, err := h.v1MetadataOps.ReloadMetadata()
|
||||||
return err
|
return r, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) BuildMetadata() (yaml.MapSlice, error) {
|
func (h *Handler) BuildMetadata() (yaml.MapSlice, error) {
|
||||||
@ -125,16 +125,16 @@ func (h *Handler) MakeJSONMetadata() ([]byte, error) {
|
|||||||
return jbyt, nil
|
return jbyt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) V1ApplyMetadata() error {
|
func (h *Handler) V1ApplyMetadata() (io.Reader, error) {
|
||||||
jbyt, err := h.MakeJSONMetadata()
|
jbyt, err := h.MakeJSONMetadata()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
_, err = h.v1MetadataOps.ReplaceMetadata(bytes.NewReader(jbyt))
|
r, err := h.v1MetadataOps.ReplaceMetadata(bytes.NewReader(jbyt))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
return nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) V2ApplyMetadata() (*hasura.V2ReplaceMetadataResponse, error) {
|
func (h *Handler) V2ApplyMetadata() (*hasura.V2ReplaceMetadataResponse, error) {
|
||||||
|
@ -16,6 +16,8 @@ var (
|
|||||||
return ""
|
return ""
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
TestAdminSecret = os.Getenv("HASURA_GRAPHQL_TEST_ADMIN_SECRET")
|
||||||
|
|
||||||
DockerSwitchIP = func() string {
|
DockerSwitchIP = func() string {
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "darwin", "windows":
|
case "darwin", "windows":
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
"github.com/briandowns/spinner"
|
"github.com/briandowns/spinner"
|
||||||
"github.com/mattn/go-colorable"
|
"github.com/mattn/go-colorable"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"io/ioutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type spinnerHook struct {
|
type spinnerHook struct {
|
||||||
@ -14,7 +15,8 @@ type spinnerHook struct {
|
|||||||
|
|
||||||
func newSpinnerHandlerHook(parent *logrus.Logger, spinner *spinner.Spinner, isTerminal, noColor bool) *spinnerHook {
|
func newSpinnerHandlerHook(parent *logrus.Logger, spinner *spinner.Spinner, isTerminal, noColor bool) *spinnerHook {
|
||||||
logger := logrus.New()
|
logger := logrus.New()
|
||||||
if parent.Out != ioutil.Discard {
|
logger.Out = parent.Out
|
||||||
|
if parent.Out != io.Discard {
|
||||||
if isTerminal {
|
if isTerminal {
|
||||||
if noColor {
|
if noColor {
|
||||||
logger.Formatter = &logrus.TextFormatter{
|
logger.Formatter = &logrus.TextFormatter{
|
||||||
@ -27,12 +29,12 @@ func newSpinnerHandlerHook(parent *logrus.Logger, spinner *spinner.Spinner, isTe
|
|||||||
DisableTimestamp: true,
|
DisableTimestamp: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
logger.Out = colorable.NewColorableStderr()
|
||||||
} else {
|
} else {
|
||||||
logger.Formatter = &logrus.JSONFormatter{
|
logger.Formatter = &logrus.JSONFormatter{
|
||||||
PrettyPrint: false,
|
PrettyPrint: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.Out = colorable.NewColorableStderr()
|
|
||||||
logger.Level = parent.GetLevel()
|
logger.Level = parent.GetLevel()
|
||||||
}
|
}
|
||||||
return &spinnerHook{
|
return &spinnerHook{
|
||||||
|
113
cli/pkg/metadata/project_metadata.go
Normal file
113
cli/pkg/metadata/project_metadata.go
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
package metadata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/hasura/graphql-engine/cli/v2/commands"
|
||||||
|
|
||||||
|
"github.com/hasura/graphql-engine/cli/v2/internal/metadataobject"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
|
"github.com/hasura/graphql-engine/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProjectMetadata struct {
|
||||||
|
ec *cli.ExecutionContext
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse metadata in project as JSON
|
||||||
|
func (p *ProjectMetadata) Parse() (io.Reader, error) {
|
||||||
|
metadataHandler := metadataobject.NewHandlerFromEC(p.ec)
|
||||||
|
jsonMetadata, err := metadataHandler.MakeJSONMetadata()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("parsing project metadata to json failed: %w", err)
|
||||||
|
}
|
||||||
|
return bytes.NewReader(jsonMetadata), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply metadata from in the project and provide raw response from hge server
|
||||||
|
func (p *ProjectMetadata) Apply() (io.Reader, error) {
|
||||||
|
metadataHandler := metadataobject.NewHandlerFromEC(p.ec)
|
||||||
|
if p.ec.Config.Version == cli.V2 {
|
||||||
|
r, err := metadataHandler.V1ApplyMetadata()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
if p.ec.Config.Version >= cli.V3 {
|
||||||
|
replaceMetadataResponse, err := metadataHandler.V2ApplyMetadata()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b := new(bytes.Buffer)
|
||||||
|
if err := json.NewEncoder(b).Encode(replaceMetadataResponse); err != nil {
|
||||||
|
return nil, fmt.Errorf("encoding json reponse from server: %w", err)
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reload metadata on hge server and provides raw response from hge server
|
||||||
|
func (p *ProjectMetadata) Reload() (io.Reader, error) {
|
||||||
|
metadataHandler := metadataobject.NewHandlerFromEC(p.ec)
|
||||||
|
return metadataHandler.ReloadMetadata()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Diff will return the differences between metadata in the project (in JSON) and on the server
|
||||||
|
func (p *ProjectMetadata) Diff() (io.Reader, error) {
|
||||||
|
w := new(bytes.Buffer)
|
||||||
|
opts := &commands.MetadataDiffOptions{
|
||||||
|
EC: p.ec,
|
||||||
|
Output: w,
|
||||||
|
DisableColor: true,
|
||||||
|
}
|
||||||
|
if err := opts.Run(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return w, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProjectMetadataOption func(*ProjectMetadata)
|
||||||
|
|
||||||
|
func WithAdminSecret(adminSecret string) ProjectMetadataOption {
|
||||||
|
return func(m *ProjectMetadata) {
|
||||||
|
m.ec.Viper.Set("admin_secret", adminSecret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithEndpoint(endpoint string) ProjectMetadataOption {
|
||||||
|
return func(m *ProjectMetadata) {
|
||||||
|
m.ec.Viper.Set("endpoint", endpoint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewProjectMetadata(projectDirectory string, opts ...ProjectMetadataOption) (*ProjectMetadata, error) {
|
||||||
|
ec := cli.NewExecutionContext()
|
||||||
|
ec.ExecutionDirectory = projectDirectory
|
||||||
|
ec.Viper = viper.New()
|
||||||
|
ec.IsTerminal = false
|
||||||
|
ec.Stdout = io.Discard
|
||||||
|
ec.Stderr = io.Discard
|
||||||
|
|
||||||
|
if err := ec.Prepare(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
p := &ProjectMetadata{ec}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ec.Validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if ec.Config.Version <= cli.V1 {
|
||||||
|
return nil, fmt.Errorf("config %v is not supported", ec.Config.Version)
|
||||||
|
}
|
||||||
|
return p, nil
|
||||||
|
}
|
206
cli/pkg/metadata/project_metadata_test.go
Normal file
206
cli/pkg/metadata/project_metadata_test.go
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
package metadata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/hasura/graphql-engine/cli/v2/internal/testutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestProjectMetadataOps_Apply(t *testing.T) {
|
||||||
|
port, teardown := testutil.StartHasura(t, testutil.HasuraDockerImage)
|
||||||
|
hgeEndpoint := fmt.Sprintf("http://localhost:%s", port)
|
||||||
|
defer teardown()
|
||||||
|
type fields struct {
|
||||||
|
projectDirectory string
|
||||||
|
endpointString string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
want string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"can apply metadata from config v3 project",
|
||||||
|
fields{
|
||||||
|
projectDirectory: "testdata/projectv3",
|
||||||
|
endpointString: hgeEndpoint,
|
||||||
|
},
|
||||||
|
`{"is_consistent":false,"inconsistent_objects":[{"definition":{"name":"t1","schema":"public"},"name":"table t1 in source default","reason":"Inconsistent object: no such table/view exists in source: \"t1\"","type":"table"},{"definition":{"name":"t2","schema":"public"},"name":"table t2 in source default","reason":"Inconsistent object: no such table/view exists in source: \"t2\"","type":"table"},{"definition":{"name":"t4","schema":"pub"},"name":"table pub.t4 in source default","reason":"Inconsistent object: no such table/view exists in source: \"pub.t4\"","type":"table"},{"definition":{"name":"t3","schema":"pub"},"name":"table pub.t3 in source default","reason":"Inconsistent object: no such table/view exists in source: \"pub.t3\"","type":"table"}]}`,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"can apply metadata from config v2 project",
|
||||||
|
fields{
|
||||||
|
projectDirectory: "testdata/projectv2",
|
||||||
|
endpointString: hgeEndpoint,
|
||||||
|
},
|
||||||
|
"",
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
p, err := NewProjectMetadata(tt.fields.projectDirectory, WithAdminSecret(testutil.TestAdminSecret), WithEndpoint(tt.fields.endpointString))
|
||||||
|
require.NoError(t, err)
|
||||||
|
got, err := p.Apply()
|
||||||
|
if tt.wantErr {
|
||||||
|
require.Error(t, err)
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, got)
|
||||||
|
|
||||||
|
gotb, err := ioutil.ReadAll(got)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.JSONEq(t, tt.want, string(gotb))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProjectMetadataOps_Parse(t *testing.T) {
|
||||||
|
port, teardown := testutil.StartHasura(t, testutil.HasuraDockerImage)
|
||||||
|
hgeEndpoint := fmt.Sprintf("http://localhost:%s", port)
|
||||||
|
defer teardown()
|
||||||
|
type fields struct {
|
||||||
|
projectDirectory string
|
||||||
|
adminSecret string
|
||||||
|
endpointString string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
wantGolden string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"can generate json metadata from config v3 project",
|
||||||
|
fields{
|
||||||
|
projectDirectory: "testdata/projectv3",
|
||||||
|
},
|
||||||
|
"testdata/metadata_parse_test/config-v3.golden.json",
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"can generate json metadata from config v2 project",
|
||||||
|
fields{
|
||||||
|
projectDirectory: "testdata/projectv2",
|
||||||
|
},
|
||||||
|
"testdata/metadata_parse_test/config-v2.golden.json",
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
p, err := NewProjectMetadata(tt.fields.projectDirectory, WithEndpoint(hgeEndpoint), WithAdminSecret(testutil.TestAdminSecret))
|
||||||
|
require.NoError(t, err)
|
||||||
|
got, err := p.Parse()
|
||||||
|
if tt.wantErr {
|
||||||
|
require.Error(t, err)
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, got)
|
||||||
|
gotb, err := ioutil.ReadAll(got)
|
||||||
|
require.NoError(t, err)
|
||||||
|
wantb, err := ioutil.ReadFile(tt.wantGolden)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.JSONEq(t, string(wantb), string(gotb))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProjectMetadataOps_Diff(t *testing.T) {
|
||||||
|
port, teardown := testutil.StartHasura(t, testutil.HasuraDockerImage)
|
||||||
|
hgeEndpoint := fmt.Sprintf("http://localhost:%s", port)
|
||||||
|
defer teardown()
|
||||||
|
type fields struct {
|
||||||
|
projectDirectory string
|
||||||
|
adminSecret string
|
||||||
|
endpointString string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
wantGolden string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"can generate diff on config v3 project",
|
||||||
|
fields{
|
||||||
|
projectDirectory: "testdata/projectv3",
|
||||||
|
},
|
||||||
|
"testdata/metadata_diff_test/config_v3_diff",
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"can generate diff on config v2 project",
|
||||||
|
fields{
|
||||||
|
projectDirectory: "testdata/projectv2",
|
||||||
|
},
|
||||||
|
"testdata/metadata_diff_test/config_v2_diff",
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
p, err := NewProjectMetadata(tt.fields.projectDirectory, WithEndpoint(hgeEndpoint), WithAdminSecret(testutil.TestAdminSecret))
|
||||||
|
require.NoError(t, err)
|
||||||
|
got, err := p.Diff()
|
||||||
|
if tt.wantErr {
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
||||||
|
gotb, err := ioutil.ReadAll(got)
|
||||||
|
require.NoError(t, err)
|
||||||
|
wantb, err := ioutil.ReadFile(tt.wantGolden)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, string(wantb), string(gotb))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProjectMetadata_Reload(t *testing.T) {
|
||||||
|
port, teardown := testutil.StartHasura(t, testutil.HasuraDockerImage)
|
||||||
|
hgeEndpoint := fmt.Sprintf("http://localhost:%s", port)
|
||||||
|
defer teardown()
|
||||||
|
type fields struct {
|
||||||
|
projectDirectory string
|
||||||
|
adminSecret string
|
||||||
|
endpointString string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
want string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"can reload metadata",
|
||||||
|
fields{
|
||||||
|
projectDirectory: "testdata/projectv3",
|
||||||
|
endpointString: hgeEndpoint,
|
||||||
|
},
|
||||||
|
`{"message": "success"}`,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
p, err := NewProjectMetadata(tt.fields.projectDirectory, WithEndpoint(hgeEndpoint), WithAdminSecret(testutil.TestAdminSecret))
|
||||||
|
require.NoError(t, err)
|
||||||
|
got, err := p.Reload()
|
||||||
|
if tt.wantErr {
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
||||||
|
require.NoError(t, err)
|
||||||
|
gotb, err := ioutil.ReadAll(got)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.JSONEq(t, tt.want, string(gotb))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
17
cli/pkg/metadata/testdata/metadata_diff_test/config_v2_diff
vendored
Normal file
17
cli/pkg/metadata/testdata/metadata_diff_test/config_v2_diff
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
--- testdata/projectv2/metadata
|
||||||
|
+++ server
|
||||||
|
@@ -1,14 +1,2 @@
|
||||||
|
-tables:
|
||||||
|
-- table:
|
||||||
|
- name: t3
|
||||||
|
- schema: pub
|
||||||
|
-- table:
|
||||||
|
- name: t4
|
||||||
|
- schema: pub
|
||||||
|
-- table:
|
||||||
|
- name: t1
|
||||||
|
- schema: public
|
||||||
|
-- table:
|
||||||
|
- name: t2
|
||||||
|
- schema: public
|
||||||
|
+tables: []
|
17
cli/pkg/metadata/testdata/metadata_diff_test/config_v3_diff
vendored
Normal file
17
cli/pkg/metadata/testdata/metadata_diff_test/config_v3_diff
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
--- testdata/projectv3/metadata
|
||||||
|
+++ server
|
||||||
|
@@ -13,16 +13,4 @@
|
||||||
|
- tables:
|
||||||
|
- - table:
|
||||||
|
- name: t3
|
||||||
|
- schema: pub
|
||||||
|
- - table:
|
||||||
|
- name: t4
|
||||||
|
- schema: pub
|
||||||
|
- - table:
|
||||||
|
- name: t1
|
||||||
|
- schema: public
|
||||||
|
- - table:
|
||||||
|
- name: t2
|
||||||
|
- schema: public
|
||||||
|
+ tables: []
|
29
cli/pkg/metadata/testdata/metadata_parse_test/config-v2.golden.json
vendored
Normal file
29
cli/pkg/metadata/testdata/metadata_parse_test/config-v2.golden.json
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"table": {
|
||||||
|
"name": "t3",
|
||||||
|
"schema": "pub"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": {
|
||||||
|
"name": "t4",
|
||||||
|
"schema": "pub"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": {
|
||||||
|
"name": "t1",
|
||||||
|
"schema": "public"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": {
|
||||||
|
"name": "t2",
|
||||||
|
"schema": "public"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
50
cli/pkg/metadata/testdata/metadata_parse_test/config-v3.golden.json
vendored
Normal file
50
cli/pkg/metadata/testdata/metadata_parse_test/config-v3.golden.json
vendored
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"configuration": {
|
||||||
|
"connection_info": {
|
||||||
|
"database_url": {
|
||||||
|
"from_env": "HASURA_GRAPHQL_DATABASE_URL"
|
||||||
|
},
|
||||||
|
"isolation_level": "read-committed",
|
||||||
|
"pool_settings": {
|
||||||
|
"connection_lifetime": 600,
|
||||||
|
"idle_timeout": 180,
|
||||||
|
"max_connections": 50,
|
||||||
|
"retries": 1
|
||||||
|
},
|
||||||
|
"use_prepared_statements": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"kind": "postgres",
|
||||||
|
"name": "default",
|
||||||
|
"tables": [
|
||||||
|
{
|
||||||
|
"table": {
|
||||||
|
"name": "t3",
|
||||||
|
"schema": "pub"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": {
|
||||||
|
"name": "t4",
|
||||||
|
"schema": "pub"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": {
|
||||||
|
"name": "t1",
|
||||||
|
"schema": "public"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": {
|
||||||
|
"name": "t2",
|
||||||
|
"schema": "public"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
6
cli/pkg/metadata/testdata/projectv2/config.yaml
vendored
Normal file
6
cli/pkg/metadata/testdata/projectv2/config.yaml
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
version: 2
|
||||||
|
endpoint: http://localhost:8080
|
||||||
|
metadata_directory: metadata
|
||||||
|
actions:
|
||||||
|
kind: synchronous
|
||||||
|
handler_webhook_baseurl: http://localhost:3000
|
0
cli/pkg/metadata/testdata/projectv2/metadata/actions.graphql
vendored
Normal file
0
cli/pkg/metadata/testdata/projectv2/metadata/actions.graphql
vendored
Normal file
6
cli/pkg/metadata/testdata/projectv2/metadata/actions.yaml
vendored
Normal file
6
cli/pkg/metadata/testdata/projectv2/metadata/actions.yaml
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
actions: []
|
||||||
|
custom_types:
|
||||||
|
enums: []
|
||||||
|
input_objects: []
|
||||||
|
objects: []
|
||||||
|
scalars: []
|
1
cli/pkg/metadata/testdata/projectv2/metadata/allow_list.yaml
vendored
Normal file
1
cli/pkg/metadata/testdata/projectv2/metadata/allow_list.yaml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[]
|
1
cli/pkg/metadata/testdata/projectv2/metadata/cron_triggers.yaml
vendored
Normal file
1
cli/pkg/metadata/testdata/projectv2/metadata/cron_triggers.yaml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[]
|
1
cli/pkg/metadata/testdata/projectv2/metadata/functions.yaml
vendored
Normal file
1
cli/pkg/metadata/testdata/projectv2/metadata/functions.yaml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[]
|
1
cli/pkg/metadata/testdata/projectv2/metadata/query_collections.yaml
vendored
Normal file
1
cli/pkg/metadata/testdata/projectv2/metadata/query_collections.yaml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[]
|
1
cli/pkg/metadata/testdata/projectv2/metadata/remote_schemas.yaml
vendored
Normal file
1
cli/pkg/metadata/testdata/projectv2/metadata/remote_schemas.yaml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[]
|
12
cli/pkg/metadata/testdata/projectv2/metadata/tables.yaml
vendored
Normal file
12
cli/pkg/metadata/testdata/projectv2/metadata/tables.yaml
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
- table:
|
||||||
|
schema: pub
|
||||||
|
name: t3
|
||||||
|
- table:
|
||||||
|
schema: pub
|
||||||
|
name: t4
|
||||||
|
- table:
|
||||||
|
schema: public
|
||||||
|
name: t1
|
||||||
|
- table:
|
||||||
|
schema: public
|
||||||
|
name: t2
|
1
cli/pkg/metadata/testdata/projectv2/metadata/version.yaml
vendored
Normal file
1
cli/pkg/metadata/testdata/projectv2/metadata/version.yaml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
version: 2
|
1
cli/pkg/metadata/testdata/projectv2/migrations/1623842054907_create_table_public_t1/down.sql
vendored
Normal file
1
cli/pkg/metadata/testdata/projectv2/migrations/1623842054907_create_table_public_t1/down.sql
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE "public"."t1";
|
1
cli/pkg/metadata/testdata/projectv2/migrations/1623842054907_create_table_public_t1/up.sql
vendored
Normal file
1
cli/pkg/metadata/testdata/projectv2/migrations/1623842054907_create_table_public_t1/up.sql
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
CREATE TABLE "public"."t1" ("id" serial NOT NULL, "created_at" timestamptz NOT NULL DEFAULT now(), PRIMARY KEY ("id") );
|
1
cli/pkg/metadata/testdata/projectv2/migrations/1623842062104_create_table_public_t2/down.sql
vendored
Normal file
1
cli/pkg/metadata/testdata/projectv2/migrations/1623842062104_create_table_public_t2/down.sql
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE "public"."t2";
|
1
cli/pkg/metadata/testdata/projectv2/migrations/1623842062104_create_table_public_t2/up.sql
vendored
Normal file
1
cli/pkg/metadata/testdata/projectv2/migrations/1623842062104_create_table_public_t2/up.sql
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
CREATE TABLE "public"."t2" ("id" serial NOT NULL, "created_at" timestamptz NOT NULL DEFAULT now(), PRIMARY KEY ("id") );
|
1
cli/pkg/metadata/testdata/projectv2/migrations/1623842069725_create_schema_pub/down.sql
vendored
Normal file
1
cli/pkg/metadata/testdata/projectv2/migrations/1623842069725_create_schema_pub/down.sql
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
drop schema "pub" cascade;
|
1
cli/pkg/metadata/testdata/projectv2/migrations/1623842069725_create_schema_pub/up.sql
vendored
Normal file
1
cli/pkg/metadata/testdata/projectv2/migrations/1623842069725_create_schema_pub/up.sql
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
create schema "pub";
|
1
cli/pkg/metadata/testdata/projectv2/migrations/1623842076537_create_table_pub_t3/down.sql
vendored
Normal file
1
cli/pkg/metadata/testdata/projectv2/migrations/1623842076537_create_table_pub_t3/down.sql
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE "pub"."t3";
|
1
cli/pkg/metadata/testdata/projectv2/migrations/1623842076537_create_table_pub_t3/up.sql
vendored
Normal file
1
cli/pkg/metadata/testdata/projectv2/migrations/1623842076537_create_table_pub_t3/up.sql
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
CREATE TABLE "pub"."t3" ("id" serial NOT NULL, "created_at" timestamptz NOT NULL DEFAULT now(), PRIMARY KEY ("id") );
|
1
cli/pkg/metadata/testdata/projectv2/migrations/1623842087940_create_table_pub_t4/down.sql
vendored
Normal file
1
cli/pkg/metadata/testdata/projectv2/migrations/1623842087940_create_table_pub_t4/down.sql
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE "pub"."t4";
|
1
cli/pkg/metadata/testdata/projectv2/migrations/1623842087940_create_table_pub_t4/up.sql
vendored
Normal file
1
cli/pkg/metadata/testdata/projectv2/migrations/1623842087940_create_table_pub_t4/up.sql
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
CREATE TABLE "pub"."t4" ("id" serial NOT NULL, "created_at" timestamptz NOT NULL DEFAULT now(), PRIMARY KEY ("id") );
|
6
cli/pkg/metadata/testdata/projectv3/config.yaml
vendored
Normal file
6
cli/pkg/metadata/testdata/projectv3/config.yaml
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
version: 3
|
||||||
|
endpoint: http://localhost:8080
|
||||||
|
metadata_directory: metadata
|
||||||
|
actions:
|
||||||
|
kind: synchronous
|
||||||
|
handler_webhook_baseurl: http://localhost:3000
|
0
cli/pkg/metadata/testdata/projectv3/metadata/actions.graphql
vendored
Normal file
0
cli/pkg/metadata/testdata/projectv3/metadata/actions.graphql
vendored
Normal file
6
cli/pkg/metadata/testdata/projectv3/metadata/actions.yaml
vendored
Normal file
6
cli/pkg/metadata/testdata/projectv3/metadata/actions.yaml
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
actions: []
|
||||||
|
custom_types:
|
||||||
|
enums: []
|
||||||
|
input_objects: []
|
||||||
|
objects: []
|
||||||
|
scalars: []
|
1
cli/pkg/metadata/testdata/projectv3/metadata/allow_list.yaml
vendored
Normal file
1
cli/pkg/metadata/testdata/projectv3/metadata/allow_list.yaml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[]
|
1
cli/pkg/metadata/testdata/projectv3/metadata/cron_triggers.yaml
vendored
Normal file
1
cli/pkg/metadata/testdata/projectv3/metadata/cron_triggers.yaml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[]
|
14
cli/pkg/metadata/testdata/projectv3/metadata/databases/databases.yaml
vendored
Normal file
14
cli/pkg/metadata/testdata/projectv3/metadata/databases/databases.yaml
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
- name: default
|
||||||
|
kind: postgres
|
||||||
|
configuration:
|
||||||
|
connection_info:
|
||||||
|
database_url:
|
||||||
|
from_env: HASURA_GRAPHQL_DATABASE_URL
|
||||||
|
isolation_level: read-committed
|
||||||
|
pool_settings:
|
||||||
|
connection_lifetime: 600
|
||||||
|
idle_timeout: 180
|
||||||
|
max_connections: 50
|
||||||
|
retries: 1
|
||||||
|
use_prepared_statements: true
|
||||||
|
tables: "!include default/tables/tables.yaml"
|
3
cli/pkg/metadata/testdata/projectv3/metadata/databases/default/tables/pub_t3.yaml
vendored
Normal file
3
cli/pkg/metadata/testdata/projectv3/metadata/databases/default/tables/pub_t3.yaml
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
table:
|
||||||
|
name: t3
|
||||||
|
schema: pub
|
3
cli/pkg/metadata/testdata/projectv3/metadata/databases/default/tables/pub_t4.yaml
vendored
Normal file
3
cli/pkg/metadata/testdata/projectv3/metadata/databases/default/tables/pub_t4.yaml
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
table:
|
||||||
|
name: t4
|
||||||
|
schema: pub
|
3
cli/pkg/metadata/testdata/projectv3/metadata/databases/default/tables/public_t1.yaml
vendored
Normal file
3
cli/pkg/metadata/testdata/projectv3/metadata/databases/default/tables/public_t1.yaml
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
table:
|
||||||
|
name: t1
|
||||||
|
schema: public
|
3
cli/pkg/metadata/testdata/projectv3/metadata/databases/default/tables/public_t2.yaml
vendored
Normal file
3
cli/pkg/metadata/testdata/projectv3/metadata/databases/default/tables/public_t2.yaml
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
table:
|
||||||
|
name: t2
|
||||||
|
schema: public
|
4
cli/pkg/metadata/testdata/projectv3/metadata/databases/default/tables/tables.yaml
vendored
Normal file
4
cli/pkg/metadata/testdata/projectv3/metadata/databases/default/tables/tables.yaml
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
- "!include pub_t3.yaml"
|
||||||
|
- "!include pub_t4.yaml"
|
||||||
|
- "!include public_t1.yaml"
|
||||||
|
- "!include public_t2.yaml"
|
1
cli/pkg/metadata/testdata/projectv3/metadata/query_collections.yaml
vendored
Normal file
1
cli/pkg/metadata/testdata/projectv3/metadata/query_collections.yaml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[]
|
1
cli/pkg/metadata/testdata/projectv3/metadata/remote_schemas.yaml
vendored
Normal file
1
cli/pkg/metadata/testdata/projectv3/metadata/remote_schemas.yaml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[]
|
1
cli/pkg/metadata/testdata/projectv3/metadata/rest_endpoints.yaml
vendored
Normal file
1
cli/pkg/metadata/testdata/projectv3/metadata/rest_endpoints.yaml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[]
|
1
cli/pkg/metadata/testdata/projectv3/metadata/version.yaml
vendored
Normal file
1
cli/pkg/metadata/testdata/projectv3/metadata/version.yaml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
version: 3
|
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE "public"."t1";
|
@ -0,0 +1 @@
|
|||||||
|
CREATE TABLE "public"."t1" ("id" serial NOT NULL, "created_at" timestamptz NOT NULL DEFAULT now(), PRIMARY KEY ("id") );
|
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE "public"."t2";
|
@ -0,0 +1 @@
|
|||||||
|
CREATE TABLE "public"."t2" ("id" serial NOT NULL, "created_at" timestamptz NOT NULL DEFAULT now(), PRIMARY KEY ("id") );
|
@ -0,0 +1 @@
|
|||||||
|
drop schema "pub" cascade;
|
@ -0,0 +1 @@
|
|||||||
|
create schema "pub";
|
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE "pub"."t3";
|
@ -0,0 +1 @@
|
|||||||
|
CREATE TABLE "pub"."t3" ("id" serial NOT NULL, "created_at" timestamptz NOT NULL DEFAULT now(), PRIMARY KEY ("id") );
|
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE "pub"."t4";
|
@ -0,0 +1 @@
|
|||||||
|
CREATE TABLE "pub"."t4" ("id" serial NOT NULL, "created_at" timestamptz NOT NULL DEFAULT now(), PRIMARY KEY ("id") );
|
49
cli/pkg/migrate/apply.go
Normal file
49
cli/pkg/migrate/apply.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package migrate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hasura/graphql-engine/cli/v2"
|
||||||
|
"github.com/hasura/graphql-engine/cli/v2/commands"
|
||||||
|
)
|
||||||
|
|
||||||
|
type projectMigrationsApplier struct {
|
||||||
|
ec *cli.ExecutionContext
|
||||||
|
opts commands.MigrateApplyOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
func newProjectMigrationsApplier(ec *cli.ExecutionContext) *projectMigrationsApplier {
|
||||||
|
p := &projectMigrationsApplier{ec: ec, opts: commands.MigrateApplyOptions{EC: ec}}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProjectMigrationApplierOption func(applier *projectMigrationsApplier)
|
||||||
|
|
||||||
|
func ApplyOnAllDatabases() ProjectMigrationApplierOption {
|
||||||
|
return func(p *projectMigrationsApplier) {
|
||||||
|
p.opts.AllDatabases = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ApplyOnDatabaseName(databaseName string) ProjectMigrationApplierOption {
|
||||||
|
return func(p *projectMigrationsApplier) {
|
||||||
|
p.opts.Source.Name = databaseName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type MigrationDirection string
|
||||||
|
|
||||||
|
const MigrationDirectionUp MigrationDirection = "up"
|
||||||
|
const MigrationDirectionDown MigrationDirection = "down"
|
||||||
|
|
||||||
|
func ApplyVersion(version string, direction MigrationDirection) ProjectMigrationApplierOption {
|
||||||
|
return func(p *projectMigrationsApplier) {
|
||||||
|
p.opts.VersionMigration = version
|
||||||
|
p.opts.MigrationType = string(direction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *projectMigrationsApplier) Apply(opts ...ProjectMigrationApplierOption) error {
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(p)
|
||||||
|
}
|
||||||
|
return p.opts.Run()
|
||||||
|
}
|
72
cli/pkg/migrate/project_migrate.go
Normal file
72
cli/pkg/migrate/project_migrate.go
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
package migrate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/hasura/graphql-engine/cli/v2"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProjectMigrate struct {
|
||||||
|
ec *cli.ExecutionContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ProjectMigrate) status(opts ...ProjectMigrationStatusOption) ([]databaseMigration, error) {
|
||||||
|
lister := newProjectMigrationsStatus(p.ec)
|
||||||
|
if len(opts) == 0 {
|
||||||
|
opts = append(opts, StatusAllDatabases())
|
||||||
|
}
|
||||||
|
return lister.Status(opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ProjectMigrate) StatusJSON(opts ...ProjectMigrationStatusOption) (io.Reader, error) {
|
||||||
|
lister := newProjectMigrationsStatus(p.ec)
|
||||||
|
if len(opts) == 0 {
|
||||||
|
opts = append(opts, StatusAllDatabases())
|
||||||
|
}
|
||||||
|
return lister.StatusJSON(opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ProjectMigrate) Apply(opts ...ProjectMigrationApplierOption) error {
|
||||||
|
applier := newProjectMigrationsApplier(p.ec)
|
||||||
|
return applier.Apply(opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewProjectMigrate(projectDirectory string, opts ...ProjectMigrateOption) (*ProjectMigrate, error) {
|
||||||
|
p := &ProjectMigrate{}
|
||||||
|
ec := cli.NewExecutionContext()
|
||||||
|
ec.ExecutionDirectory = projectDirectory
|
||||||
|
ec.Viper = viper.New()
|
||||||
|
|
||||||
|
ec.IsTerminal = false
|
||||||
|
ec.Stderr = io.Discard
|
||||||
|
ec.Stdout = io.Discard
|
||||||
|
if err := ec.Prepare(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
p.ec = ec
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(p)
|
||||||
|
}
|
||||||
|
if err := ec.Validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if ec.Config.Version <= cli.V1 {
|
||||||
|
return nil, fmt.Errorf("config %v is not supported", ec.Config.Version)
|
||||||
|
}
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProjectMigrateOption func(*ProjectMigrate)
|
||||||
|
|
||||||
|
func WithEndpoint(endpoint string) ProjectMigrateOption {
|
||||||
|
return func(m *ProjectMigrate) {
|
||||||
|
m.ec.Viper.Set("endpoint", endpoint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func WithAdminSecret(adminSecret string) ProjectMigrateOption {
|
||||||
|
return func(m *ProjectMigrate) {
|
||||||
|
m.ec.Viper.Set("admin_secret", adminSecret)
|
||||||
|
}
|
||||||
|
}
|
541
cli/pkg/migrate/project_migrate_test.go
Normal file
541
cli/pkg/migrate/project_migrate_test.go
Normal file
@ -0,0 +1,541 @@
|
|||||||
|
package migrate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/hasura/graphql-engine/cli/v2/internal/testutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestProjectMigrate_ApplyConfig_v3(t *testing.T) {
|
||||||
|
port, teardown := testutil.StartHasuraWithMetadataDatabase(t, testutil.HasuraDockerImage)
|
||||||
|
hasuraEndpoint := fmt.Sprintf("%s:%s", testutil.BaseURL, port)
|
||||||
|
connectionStringSource1, teardownPG1 := testutil.StartPGContainer(t)
|
||||||
|
connectionStringSource2, teardownPG2 := testutil.StartPGContainer(t)
|
||||||
|
testutil.AddPGSourceToHasura(t, hasuraEndpoint, connectionStringSource1, "s1")
|
||||||
|
testutil.AddPGSourceToHasura(t, hasuraEndpoint, connectionStringSource2, "s2")
|
||||||
|
defer func() {
|
||||||
|
teardownPG2()
|
||||||
|
teardownPG1()
|
||||||
|
teardown()
|
||||||
|
}()
|
||||||
|
hgeEndpoint := fmt.Sprintf("http://localhost:%s", port)
|
||||||
|
type fields struct {
|
||||||
|
projectDirectory string
|
||||||
|
endpointString string
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
opts []ProjectMigrationApplierOption
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"can apply migrations in config v3 project",
|
||||||
|
fields{
|
||||||
|
projectDirectory: "testdata/projectv3",
|
||||||
|
endpointString: hgeEndpoint,
|
||||||
|
},
|
||||||
|
args{
|
||||||
|
[]ProjectMigrationApplierOption{ApplyOnAllDatabases()},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"can apply a version in config v3 project",
|
||||||
|
fields{
|
||||||
|
projectDirectory: "testdata/projectv3",
|
||||||
|
endpointString: hgeEndpoint,
|
||||||
|
},
|
||||||
|
args{
|
||||||
|
[]ProjectMigrationApplierOption{ApplyOnDatabaseName("s1"), ApplyVersion("1623841477474", MigrationDirectionDown)},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"can apply a version in config v3 project",
|
||||||
|
fields{
|
||||||
|
projectDirectory: "testdata/projectv3",
|
||||||
|
endpointString: hgeEndpoint,
|
||||||
|
},
|
||||||
|
args{
|
||||||
|
[]ProjectMigrationApplierOption{ApplyOnDatabaseName("s1"), ApplyVersion("1623841477474", MigrationDirectionUp)},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
p, err := NewProjectMigrate(tt.fields.projectDirectory, WithAdminSecret(testutil.TestAdminSecret), WithEndpoint(tt.fields.endpointString))
|
||||||
|
require.NoError(t, err)
|
||||||
|
err = p.Apply(tt.args.opts...)
|
||||||
|
if tt.wantErr {
|
||||||
|
require.Error(t, err)
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProjectMigrate_Apply_Configv2(t *testing.T) {
|
||||||
|
port, teardown := testutil.StartHasura(t, testutil.HasuraDockerImage)
|
||||||
|
defer teardown()
|
||||||
|
hgeEndpoint := fmt.Sprintf("http://localhost:%s", port)
|
||||||
|
type fields struct {
|
||||||
|
projectDirectory string
|
||||||
|
adminSecret string
|
||||||
|
endpointString string
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
opts []ProjectMigrationApplierOption
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"can apply migrations in config v2 project",
|
||||||
|
fields{
|
||||||
|
projectDirectory: "testdata/projectv2",
|
||||||
|
adminSecret: "",
|
||||||
|
endpointString: hgeEndpoint,
|
||||||
|
},
|
||||||
|
args{
|
||||||
|
[]ProjectMigrationApplierOption{ApplyOnAllDatabases()},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"can apply down migration on a version in config v2 project",
|
||||||
|
fields{
|
||||||
|
projectDirectory: "testdata/projectv2",
|
||||||
|
adminSecret: "",
|
||||||
|
endpointString: hgeEndpoint,
|
||||||
|
},
|
||||||
|
args{
|
||||||
|
[]ProjectMigrationApplierOption{ApplyVersion("1623842054907", MigrationDirectionDown)},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"throws error when trying to do a down migration which is not applied",
|
||||||
|
fields{
|
||||||
|
projectDirectory: "testdata/projectv2",
|
||||||
|
adminSecret: "",
|
||||||
|
endpointString: hgeEndpoint,
|
||||||
|
},
|
||||||
|
args{
|
||||||
|
[]ProjectMigrationApplierOption{ApplyVersion("1623842054907", MigrationDirectionDown)},
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"can apply up migrations of a version on a config v2 project",
|
||||||
|
fields{
|
||||||
|
projectDirectory: "testdata/projectv2",
|
||||||
|
adminSecret: "",
|
||||||
|
endpointString: hgeEndpoint,
|
||||||
|
},
|
||||||
|
args{
|
||||||
|
[]ProjectMigrationApplierOption{ApplyVersion("1623842054907", MigrationDirectionUp)},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
p, err := NewProjectMigrate(tt.fields.projectDirectory, WithAdminSecret(testutil.TestAdminSecret), WithEndpoint(tt.fields.endpointString))
|
||||||
|
require.NoError(t, err)
|
||||||
|
err = p.Apply(tt.args.opts...)
|
||||||
|
if tt.wantErr {
|
||||||
|
require.Error(t, err)
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProjectMigrate_Status_ConfigV2(t *testing.T) {
|
||||||
|
port, teardown := testutil.StartHasura(t, testutil.HasuraDockerImage)
|
||||||
|
defer teardown()
|
||||||
|
hgeEndpoint := fmt.Sprintf("http://localhost:%s", port)
|
||||||
|
type fields struct {
|
||||||
|
projectDirectory string
|
||||||
|
adminSecret string
|
||||||
|
endpointString string
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
opts []ProjectMigrationStatusOption
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
want string
|
||||||
|
wantErr bool
|
||||||
|
before func(t *testing.T, p *ProjectMigrate)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"can get status of migrations",
|
||||||
|
fields{
|
||||||
|
projectDirectory: "testdata/projectv2",
|
||||||
|
adminSecret: "",
|
||||||
|
endpointString: hgeEndpoint,
|
||||||
|
},
|
||||||
|
args{
|
||||||
|
opts: []ProjectMigrationStatusOption{},
|
||||||
|
},
|
||||||
|
`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"databaseName": "default",
|
||||||
|
"status": {
|
||||||
|
"migrations": [
|
||||||
|
1623842054907,
|
||||||
|
1623842062104,
|
||||||
|
1623842069725,
|
||||||
|
1623842076537,
|
||||||
|
1623842087940
|
||||||
|
],
|
||||||
|
"status": {
|
||||||
|
"1623842054907": {
|
||||||
|
"database_status": false,
|
||||||
|
"source_status": true
|
||||||
|
},
|
||||||
|
"1623842062104": {
|
||||||
|
"database_status": false,
|
||||||
|
"source_status": true
|
||||||
|
},
|
||||||
|
"1623842069725": {
|
||||||
|
"database_status": false,
|
||||||
|
"source_status": true
|
||||||
|
},
|
||||||
|
"1623842076537": {
|
||||||
|
"database_status": false,
|
||||||
|
"source_status": true
|
||||||
|
},
|
||||||
|
"1623842087940": {
|
||||||
|
"database_status": false,
|
||||||
|
"source_status": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]`,
|
||||||
|
false,
|
||||||
|
func(t *testing.T, p *ProjectMigrate) {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"can get status of migrations",
|
||||||
|
fields{
|
||||||
|
projectDirectory: "testdata/projectv2",
|
||||||
|
adminSecret: "",
|
||||||
|
endpointString: hgeEndpoint,
|
||||||
|
},
|
||||||
|
args{
|
||||||
|
opts: []ProjectMigrationStatusOption{},
|
||||||
|
},
|
||||||
|
`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"databaseName": "default",
|
||||||
|
"status": {
|
||||||
|
"migrations": [
|
||||||
|
1623842054907,
|
||||||
|
1623842062104,
|
||||||
|
1623842069725,
|
||||||
|
1623842076537,
|
||||||
|
1623842087940
|
||||||
|
],
|
||||||
|
"status": {
|
||||||
|
"1623842054907": {
|
||||||
|
"database_status": true,
|
||||||
|
"source_status": true
|
||||||
|
},
|
||||||
|
"1623842062104": {
|
||||||
|
"database_status": true,
|
||||||
|
"source_status": true
|
||||||
|
},
|
||||||
|
"1623842069725": {
|
||||||
|
"database_status": true,
|
||||||
|
"source_status": true
|
||||||
|
},
|
||||||
|
"1623842076537": {
|
||||||
|
"database_status": true,
|
||||||
|
"source_status": true
|
||||||
|
},
|
||||||
|
"1623842087940": {
|
||||||
|
"database_status": true,
|
||||||
|
"source_status": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]`,
|
||||||
|
false,
|
||||||
|
func(t *testing.T, p *ProjectMigrate) {
|
||||||
|
assert.NoError(t, p.Apply(ApplyOnAllDatabases()))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
p, err := NewProjectMigrate(tt.fields.projectDirectory, WithAdminSecret(testutil.TestAdminSecret), WithEndpoint(tt.fields.endpointString))
|
||||||
|
require.NoError(t, err)
|
||||||
|
applier, err := NewProjectMigrate(tt.fields.projectDirectory, WithAdminSecret(testutil.TestAdminSecret), WithEndpoint(tt.fields.endpointString))
|
||||||
|
require.NoError(t, err)
|
||||||
|
tt.before(t, applier)
|
||||||
|
got, err := p.status(tt.args.opts...)
|
||||||
|
if tt.wantErr {
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
||||||
|
require.NoError(t, err)
|
||||||
|
gotJSON, err := json.Marshal(got)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.JSONEq(t, tt.want, string(gotJSON))
|
||||||
|
|
||||||
|
statusJson, err := p.StatusJSON(tt.args.opts...)
|
||||||
|
require.NoError(t, err)
|
||||||
|
statusJsonb, err := ioutil.ReadAll(statusJson)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.JSONEq(t, tt.want, string(statusJsonb))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProjectMigrate_Status_ConfigV3(t *testing.T) {
|
||||||
|
port, teardown := testutil.StartHasuraWithMetadataDatabase(t, testutil.HasuraDockerImage)
|
||||||
|
hasuraEndpoint := fmt.Sprintf("%s:%s", testutil.BaseURL, port)
|
||||||
|
connectionStringSource1, teardownPG1 := testutil.StartPGContainer(t)
|
||||||
|
connectionStringSource2, teardownPG2 := testutil.StartPGContainer(t)
|
||||||
|
testutil.AddPGSourceToHasura(t, hasuraEndpoint, connectionStringSource1, "s1")
|
||||||
|
testutil.AddPGSourceToHasura(t, hasuraEndpoint, connectionStringSource2, "s2")
|
||||||
|
defer func() {
|
||||||
|
teardownPG2()
|
||||||
|
teardownPG1()
|
||||||
|
teardown()
|
||||||
|
}()
|
||||||
|
hgeEndpoint := fmt.Sprintf("http://localhost:%s", port)
|
||||||
|
type fields struct {
|
||||||
|
projectDirectory string
|
||||||
|
adminSecret string
|
||||||
|
endpointString string
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
opts []ProjectMigrationStatusOption
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
want string
|
||||||
|
wantErr bool
|
||||||
|
before func(t *testing.T, p *ProjectMigrate)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"can get status of migrations",
|
||||||
|
fields{
|
||||||
|
projectDirectory: "testdata/projectv3",
|
||||||
|
adminSecret: "",
|
||||||
|
endpointString: hgeEndpoint,
|
||||||
|
},
|
||||||
|
args{
|
||||||
|
opts: []ProjectMigrationStatusOption{},
|
||||||
|
},
|
||||||
|
`[
|
||||||
|
{
|
||||||
|
"databaseName": "s1",
|
||||||
|
"status": {
|
||||||
|
"migrations": [
|
||||||
|
1623841477474,
|
||||||
|
1623841485323,
|
||||||
|
1623841492743,
|
||||||
|
1623841500466,
|
||||||
|
1623841510619
|
||||||
|
],
|
||||||
|
"status": {
|
||||||
|
"1623841477474": {
|
||||||
|
"database_status": false,
|
||||||
|
"source_status": true
|
||||||
|
},
|
||||||
|
"1623841485323": {
|
||||||
|
"database_status": false,
|
||||||
|
"source_status": true
|
||||||
|
},
|
||||||
|
"1623841492743": {
|
||||||
|
"database_status": false,
|
||||||
|
"source_status": true
|
||||||
|
},
|
||||||
|
"1623841500466": {
|
||||||
|
"database_status": false,
|
||||||
|
"source_status": true
|
||||||
|
},
|
||||||
|
"1623841510619": {
|
||||||
|
"database_status": false,
|
||||||
|
"source_status": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"databaseName": "s2",
|
||||||
|
"status": {
|
||||||
|
"migrations": [
|
||||||
|
1623841477474,
|
||||||
|
1623841485323,
|
||||||
|
1623841492743,
|
||||||
|
1623841500466,
|
||||||
|
1623841510619
|
||||||
|
],
|
||||||
|
"status": {
|
||||||
|
"1623841477474": {
|
||||||
|
"database_status": false,
|
||||||
|
"source_status": true
|
||||||
|
},
|
||||||
|
"1623841485323": {
|
||||||
|
"database_status": false,
|
||||||
|
"source_status": true
|
||||||
|
},
|
||||||
|
"1623841492743": {
|
||||||
|
"database_status": false,
|
||||||
|
"source_status": true
|
||||||
|
},
|
||||||
|
"1623841500466": {
|
||||||
|
"database_status": false,
|
||||||
|
"source_status": true
|
||||||
|
},
|
||||||
|
"1623841510619": {
|
||||||
|
"database_status": false,
|
||||||
|
"source_status": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]`,
|
||||||
|
false,
|
||||||
|
func(t *testing.T, p *ProjectMigrate) {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"can get status of migrations",
|
||||||
|
fields{
|
||||||
|
projectDirectory: "testdata/projectv3",
|
||||||
|
adminSecret: "",
|
||||||
|
endpointString: hgeEndpoint,
|
||||||
|
},
|
||||||
|
args{
|
||||||
|
opts: []ProjectMigrationStatusOption{},
|
||||||
|
},
|
||||||
|
`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"databaseName": "s1",
|
||||||
|
"status": {
|
||||||
|
"migrations": [
|
||||||
|
1623841477474,
|
||||||
|
1623841485323,
|
||||||
|
1623841492743,
|
||||||
|
1623841500466,
|
||||||
|
1623841510619
|
||||||
|
],
|
||||||
|
"status": {
|
||||||
|
"1623841477474": {
|
||||||
|
"database_status": true,
|
||||||
|
"source_status": true
|
||||||
|
},
|
||||||
|
"1623841485323": {
|
||||||
|
"database_status": true,
|
||||||
|
"source_status": true
|
||||||
|
},
|
||||||
|
"1623841492743": {
|
||||||
|
"database_status": true,
|
||||||
|
"source_status": true
|
||||||
|
},
|
||||||
|
"1623841500466": {
|
||||||
|
"database_status": true,
|
||||||
|
"source_status": true
|
||||||
|
},
|
||||||
|
"1623841510619": {
|
||||||
|
"database_status": true,
|
||||||
|
"source_status": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"databaseName": "s2",
|
||||||
|
"status": {
|
||||||
|
"migrations": [
|
||||||
|
1623841477474,
|
||||||
|
1623841485323,
|
||||||
|
1623841492743,
|
||||||
|
1623841500466,
|
||||||
|
1623841510619
|
||||||
|
],
|
||||||
|
"status": {
|
||||||
|
"1623841477474": {
|
||||||
|
"database_status": true,
|
||||||
|
"source_status": true
|
||||||
|
},
|
||||||
|
"1623841485323": {
|
||||||
|
"database_status": true,
|
||||||
|
"source_status": true
|
||||||
|
},
|
||||||
|
"1623841492743": {
|
||||||
|
"database_status": true,
|
||||||
|
"source_status": true
|
||||||
|
},
|
||||||
|
"1623841500466": {
|
||||||
|
"database_status": true,
|
||||||
|
"source_status": true
|
||||||
|
},
|
||||||
|
"1623841510619": {
|
||||||
|
"database_status": true,
|
||||||
|
"source_status": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]`,
|
||||||
|
false,
|
||||||
|
func(t *testing.T, p *ProjectMigrate) {
|
||||||
|
assert.NoError(t, p.Apply(ApplyOnAllDatabases()))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
p, err := NewProjectMigrate(tt.fields.projectDirectory, WithAdminSecret(testutil.TestAdminSecret), WithEndpoint(tt.fields.endpointString))
|
||||||
|
require.NoError(t, err)
|
||||||
|
applier, err := NewProjectMigrate(tt.fields.projectDirectory, WithAdminSecret(testutil.TestAdminSecret), WithEndpoint(tt.fields.endpointString))
|
||||||
|
require.NoError(t, err)
|
||||||
|
tt.before(t, applier)
|
||||||
|
got, err := p.status(tt.args.opts...)
|
||||||
|
if tt.wantErr {
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
||||||
|
require.NoError(t, err)
|
||||||
|
gotJSON, err := json.Marshal(got)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.JSONEq(t, tt.want, string(gotJSON))
|
||||||
|
|
||||||
|
statusJson, err := p.StatusJSON(tt.args.opts...)
|
||||||
|
require.NoError(t, err)
|
||||||
|
statusJsonb, err := ioutil.ReadAll(statusJson)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.JSONEq(t, tt.want, string(statusJsonb))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
82
cli/pkg/migrate/status.go
Normal file
82
cli/pkg/migrate/status.go
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
package migrate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/hasura/graphql-engine/cli/v2"
|
||||||
|
"github.com/hasura/graphql-engine/cli/v2/commands"
|
||||||
|
"github.com/hasura/graphql-engine/cli/v2/internal/metadatautil"
|
||||||
|
"github.com/hasura/graphql-engine/cli/v2/migrate"
|
||||||
|
)
|
||||||
|
|
||||||
|
type databaseMigration struct {
|
||||||
|
DatabaseName string `json:"databaseName"`
|
||||||
|
Status migrate.Status `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type projectMigrationsStatus struct {
|
||||||
|
ec *cli.ExecutionContext
|
||||||
|
allDatabases bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *projectMigrationsStatus) Status(opts ...ProjectMigrationStatusOption) ([]databaseMigration, error) {
|
||||||
|
var migrateStatus []databaseMigration
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(p)
|
||||||
|
}
|
||||||
|
if p.allDatabases {
|
||||||
|
metadataOps := cli.GetCommonMetadataOps(p.ec)
|
||||||
|
sources, err := metadatautil.GetSourcesAndKind(metadataOps.ExportMetadata)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, source := range sources {
|
||||||
|
opts := commands.MigrateStatusOptions{
|
||||||
|
EC: p.ec,
|
||||||
|
Source: cli.Source{
|
||||||
|
Name: source.Name,
|
||||||
|
Kind: source.Kind,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
status, err := opts.Run()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
migrateStatus = append(
|
||||||
|
migrateStatus,
|
||||||
|
databaseMigration{
|
||||||
|
DatabaseName: source.Name,
|
||||||
|
Status: *status,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return migrateStatus, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *projectMigrationsStatus) StatusJSON(opts ...ProjectMigrationStatusOption) (io.Reader, error) {
|
||||||
|
d, err := p.Status(opts...)
|
||||||
|
b := new(bytes.Buffer)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := json.NewEncoder(b).Encode(d); err != nil {
|
||||||
|
return nil, fmt.Errorf("error encoding migration status as json: %w", err)
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProjectMigrationStatusOption func(applier *projectMigrationsStatus)
|
||||||
|
|
||||||
|
func newProjectMigrationsStatus(ec *cli.ExecutionContext) *projectMigrationsStatus {
|
||||||
|
p := &projectMigrationsStatus{ec: ec}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
func StatusAllDatabases() ProjectMigrationStatusOption {
|
||||||
|
return func(p *projectMigrationsStatus) {
|
||||||
|
p.allDatabases = true
|
||||||
|
}
|
||||||
|
}
|
6
cli/pkg/migrate/testdata/projectv2/config.yaml
vendored
Normal file
6
cli/pkg/migrate/testdata/projectv2/config.yaml
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
version: 2
|
||||||
|
endpoint: http://localhost:8080
|
||||||
|
metadata_directory: metadata
|
||||||
|
actions:
|
||||||
|
kind: synchronous
|
||||||
|
handler_webhook_baseurl: http://localhost:3000
|
0
cli/pkg/migrate/testdata/projectv2/metadata/actions.graphql
vendored
Normal file
0
cli/pkg/migrate/testdata/projectv2/metadata/actions.graphql
vendored
Normal file
6
cli/pkg/migrate/testdata/projectv2/metadata/actions.yaml
vendored
Normal file
6
cli/pkg/migrate/testdata/projectv2/metadata/actions.yaml
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
actions: []
|
||||||
|
custom_types:
|
||||||
|
enums: []
|
||||||
|
input_objects: []
|
||||||
|
objects: []
|
||||||
|
scalars: []
|
1
cli/pkg/migrate/testdata/projectv2/metadata/allow_list.yaml
vendored
Normal file
1
cli/pkg/migrate/testdata/projectv2/metadata/allow_list.yaml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[]
|
1
cli/pkg/migrate/testdata/projectv2/metadata/cron_triggers.yaml
vendored
Normal file
1
cli/pkg/migrate/testdata/projectv2/metadata/cron_triggers.yaml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[]
|
1
cli/pkg/migrate/testdata/projectv2/metadata/functions.yaml
vendored
Normal file
1
cli/pkg/migrate/testdata/projectv2/metadata/functions.yaml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[]
|
1
cli/pkg/migrate/testdata/projectv2/metadata/query_collections.yaml
vendored
Normal file
1
cli/pkg/migrate/testdata/projectv2/metadata/query_collections.yaml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[]
|
1
cli/pkg/migrate/testdata/projectv2/metadata/remote_schemas.yaml
vendored
Normal file
1
cli/pkg/migrate/testdata/projectv2/metadata/remote_schemas.yaml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[]
|
12
cli/pkg/migrate/testdata/projectv2/metadata/tables.yaml
vendored
Normal file
12
cli/pkg/migrate/testdata/projectv2/metadata/tables.yaml
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
- table:
|
||||||
|
schema: pub
|
||||||
|
name: t3
|
||||||
|
- table:
|
||||||
|
schema: pub
|
||||||
|
name: t4
|
||||||
|
- table:
|
||||||
|
schema: public
|
||||||
|
name: t1
|
||||||
|
- table:
|
||||||
|
schema: public
|
||||||
|
name: t2
|
1
cli/pkg/migrate/testdata/projectv2/metadata/version.yaml
vendored
Normal file
1
cli/pkg/migrate/testdata/projectv2/metadata/version.yaml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
version: 2
|
1
cli/pkg/migrate/testdata/projectv2/migrations/1623842054907_create_table_public_t1/down.sql
vendored
Normal file
1
cli/pkg/migrate/testdata/projectv2/migrations/1623842054907_create_table_public_t1/down.sql
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE "public"."t1";
|
1
cli/pkg/migrate/testdata/projectv2/migrations/1623842054907_create_table_public_t1/up.sql
vendored
Normal file
1
cli/pkg/migrate/testdata/projectv2/migrations/1623842054907_create_table_public_t1/up.sql
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
CREATE TABLE "public"."t1" ("id" serial NOT NULL, "created_at" timestamptz NOT NULL DEFAULT now(), PRIMARY KEY ("id") );
|
1
cli/pkg/migrate/testdata/projectv2/migrations/1623842062104_create_table_public_t2/down.sql
vendored
Normal file
1
cli/pkg/migrate/testdata/projectv2/migrations/1623842062104_create_table_public_t2/down.sql
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE "public"."t2";
|
1
cli/pkg/migrate/testdata/projectv2/migrations/1623842062104_create_table_public_t2/up.sql
vendored
Normal file
1
cli/pkg/migrate/testdata/projectv2/migrations/1623842062104_create_table_public_t2/up.sql
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
CREATE TABLE "public"."t2" ("id" serial NOT NULL, "created_at" timestamptz NOT NULL DEFAULT now(), PRIMARY KEY ("id") );
|
1
cli/pkg/migrate/testdata/projectv2/migrations/1623842069725_create_schema_pub/down.sql
vendored
Normal file
1
cli/pkg/migrate/testdata/projectv2/migrations/1623842069725_create_schema_pub/down.sql
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
drop schema "pub" cascade;
|
1
cli/pkg/migrate/testdata/projectv2/migrations/1623842069725_create_schema_pub/up.sql
vendored
Normal file
1
cli/pkg/migrate/testdata/projectv2/migrations/1623842069725_create_schema_pub/up.sql
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
create schema "pub";
|
1
cli/pkg/migrate/testdata/projectv2/migrations/1623842076537_create_table_pub_t3/down.sql
vendored
Normal file
1
cli/pkg/migrate/testdata/projectv2/migrations/1623842076537_create_table_pub_t3/down.sql
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE "pub"."t3";
|
1
cli/pkg/migrate/testdata/projectv2/migrations/1623842076537_create_table_pub_t3/up.sql
vendored
Normal file
1
cli/pkg/migrate/testdata/projectv2/migrations/1623842076537_create_table_pub_t3/up.sql
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
CREATE TABLE "pub"."t3" ("id" serial NOT NULL, "created_at" timestamptz NOT NULL DEFAULT now(), PRIMARY KEY ("id") );
|
1
cli/pkg/migrate/testdata/projectv2/migrations/1623842087940_create_table_pub_t4/down.sql
vendored
Normal file
1
cli/pkg/migrate/testdata/projectv2/migrations/1623842087940_create_table_pub_t4/down.sql
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE "pub"."t4";
|
1
cli/pkg/migrate/testdata/projectv2/migrations/1623842087940_create_table_pub_t4/up.sql
vendored
Normal file
1
cli/pkg/migrate/testdata/projectv2/migrations/1623842087940_create_table_pub_t4/up.sql
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
CREATE TABLE "pub"."t4" ("id" serial NOT NULL, "created_at" timestamptz NOT NULL DEFAULT now(), PRIMARY KEY ("id") );
|
6
cli/pkg/migrate/testdata/projectv3/config.yaml
vendored
Normal file
6
cli/pkg/migrate/testdata/projectv3/config.yaml
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
version: 3
|
||||||
|
endpoint: http://localhost:8080
|
||||||
|
metadata_directory: metadata
|
||||||
|
actions:
|
||||||
|
kind: synchronous
|
||||||
|
handler_webhook_baseurl: http://localhost:3000
|
0
cli/pkg/migrate/testdata/projectv3/metadata/actions.graphql
vendored
Normal file
0
cli/pkg/migrate/testdata/projectv3/metadata/actions.graphql
vendored
Normal file
6
cli/pkg/migrate/testdata/projectv3/metadata/actions.yaml
vendored
Normal file
6
cli/pkg/migrate/testdata/projectv3/metadata/actions.yaml
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
actions: []
|
||||||
|
custom_types:
|
||||||
|
enums: []
|
||||||
|
input_objects: []
|
||||||
|
objects: []
|
||||||
|
scalars: []
|
1
cli/pkg/migrate/testdata/projectv3/metadata/allow_list.yaml
vendored
Normal file
1
cli/pkg/migrate/testdata/projectv3/metadata/allow_list.yaml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[]
|
1
cli/pkg/migrate/testdata/projectv3/metadata/cron_triggers.yaml
vendored
Normal file
1
cli/pkg/migrate/testdata/projectv3/metadata/cron_triggers.yaml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[]
|
14
cli/pkg/migrate/testdata/projectv3/metadata/databases/databases.yaml
vendored
Normal file
14
cli/pkg/migrate/testdata/projectv3/metadata/databases/databases.yaml
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
- name: default
|
||||||
|
kind: postgres
|
||||||
|
configuration:
|
||||||
|
connection_info:
|
||||||
|
database_url:
|
||||||
|
from_env: HASURA_GRAPHQL_DATABASE_URL
|
||||||
|
isolation_level: read-committed
|
||||||
|
pool_settings:
|
||||||
|
connection_lifetime: 600
|
||||||
|
idle_timeout: 180
|
||||||
|
max_connections: 50
|
||||||
|
retries: 1
|
||||||
|
use_prepared_statements: true
|
||||||
|
tables: "!include default/tables/tables.yaml"
|
3
cli/pkg/migrate/testdata/projectv3/metadata/databases/default/tables/pub_t3.yaml
vendored
Normal file
3
cli/pkg/migrate/testdata/projectv3/metadata/databases/default/tables/pub_t3.yaml
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
table:
|
||||||
|
name: t3
|
||||||
|
schema: pub
|
3
cli/pkg/migrate/testdata/projectv3/metadata/databases/default/tables/pub_t4.yaml
vendored
Normal file
3
cli/pkg/migrate/testdata/projectv3/metadata/databases/default/tables/pub_t4.yaml
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
table:
|
||||||
|
name: t4
|
||||||
|
schema: pub
|
3
cli/pkg/migrate/testdata/projectv3/metadata/databases/default/tables/public_t1.yaml
vendored
Normal file
3
cli/pkg/migrate/testdata/projectv3/metadata/databases/default/tables/public_t1.yaml
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
table:
|
||||||
|
name: t1
|
||||||
|
schema: public
|
3
cli/pkg/migrate/testdata/projectv3/metadata/databases/default/tables/public_t2.yaml
vendored
Normal file
3
cli/pkg/migrate/testdata/projectv3/metadata/databases/default/tables/public_t2.yaml
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
table:
|
||||||
|
name: t2
|
||||||
|
schema: public
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user