accept a json or yaml file for metadata apply command (close #1698) (#1746)

This commit is contained in:
Aravind Shankar 2019-03-20 10:40:06 +05:30 committed by Shahidh K Muhammed
parent a01ec9b2e2
commit 8043ddeebf
26 changed files with 120 additions and 65 deletions

View File

@ -9,6 +9,7 @@ package cli
import (
"encoding/json"
"fmt"
"net/url"
"os"
"path/filepath"
@ -142,8 +143,8 @@ type ExecutionContext struct {
MigrationDir string
// ConfigFile is the file where endpoint etc. are stored.
ConfigFile string
// MetadataFile (optional) is a yaml file where Hasura metadata is stored.
MetadataFile string
// MetadataFile (optional) is a yaml|json file where Hasura metadata is stored.
MetadataFile []string
// ServerConfig is the configuration object storing the endpoint and admin secret
// information after reading from config file or env var.
@ -252,7 +253,8 @@ func (ec *ExecutionContext) Validate() error {
// set names of files and directories
ec.MigrationDir = filepath.Join(ec.ExecutionDirectory, "migrations")
ec.ConfigFile = filepath.Join(ec.ExecutionDirectory, "config.yaml")
ec.MetadataFile = filepath.Join(ec.MigrationDir, "metadata.yaml")
ec.MetadataFile = append(ec.MetadataFile, filepath.Join(ec.MigrationDir, "metadata.yaml"))
ec.MetadataFile = append(ec.MetadataFile, filepath.Join(ec.MigrationDir, "metadata.json"))
// read config and parse the values into Config
err = ec.readConfig()
@ -371,3 +373,15 @@ func (ec *ExecutionContext) setVersion() {
ec.Version = version.New()
}
}
// GetMetadataPath returns the file path based on the format.
func (ec *ExecutionContext) GetMetadataFilePath(format string) (string, error) {
ext := fmt.Sprintf(".%s", format)
for _, filePath := range ec.MetadataFile {
switch p := filepath.Ext(filePath); p {
case ext:
return filePath, nil
}
}
return "", errors.New("unsupported file type")
}

View File

@ -98,7 +98,12 @@ func (o *consoleOptions) run() error {
return errors.New("cannot validate version, object is nil")
}
router.setRoutes(o.EC.ServerConfig.ParsedEndpoint, o.EC.ServerConfig.AdminSecret, o.EC.MigrationDir, o.EC.MetadataFile, o.EC.Logger, o.EC.Version)
metadataPath, err := o.EC.GetMetadataFilePath("yaml")
if err != nil {
return err
}
router.setRoutes(o.EC.ServerConfig.ParsedEndpoint, o.EC.ServerConfig.AdminSecret, o.EC.MigrationDir, metadataPath, o.EC.Logger, o.EC.Version)
consoleTemplateVersion := o.EC.Version.GetConsoleTemplateVersion()
consoleAssetsVersion := o.EC.Version.GetConsoleAssetsVersion()

View File

@ -21,6 +21,7 @@ func TestConsoleCmd(t *testing.T) {
Endpoint: "http://localhost:8080",
AdminSecret: "",
}
ec.MetadataFile = []string{"metadata.yaml"}
ec.Version = version.New()
v, err := version.FetchServerVersion(ec.ServerConfig.Endpoint)

View File

@ -3,6 +3,7 @@ package commands
import (
"encoding/json"
"io/ioutil"
"os"
"github.com/ghodss/yaml"
"github.com/hasura/graphql-engine/cli"
@ -26,17 +27,17 @@ func NewMetadataCmd(ec *cli.ExecutionContext) *cobra.Command {
return metadataCmd
}
func executeMetadata(cmd string, t *migrate.Migrate, metadataPath string) error {
func executeMetadata(cmd string, t *migrate.Migrate, ec *cli.ExecutionContext) error {
switch cmd {
case "export":
metaData, err := t.ExportMetadata()
if err != nil {
return errors.Wrap(err, "Cannot export metadata")
return errors.Wrap(err, "cannot export metadata")
}
t, err := json.Marshal(metaData)
if err != nil {
return errors.Wrap(err, "Cannot Marshal metadata")
return errors.Wrap(err, "cannot Marshal metadata")
}
data, err := yaml.JSONToYAML(t)
@ -44,6 +45,11 @@ func executeMetadata(cmd string, t *migrate.Migrate, metadataPath string) error
return err
}
metadataPath, err := ec.GetMetadataFilePath("yaml")
if err != nil {
return errors.Wrap(err, "cannot save metadata")
}
err = ioutil.WriteFile(metadataPath, data, 0644)
if err != nil {
return errors.Wrap(err, "cannot save metadata")
@ -51,29 +57,46 @@ func executeMetadata(cmd string, t *migrate.Migrate, metadataPath string) error
case "reset":
err := t.ResetMetadata()
if err != nil {
return errors.Wrap(err, "Cannot reset Metadata")
return errors.Wrap(err, "cannot reset Metadata")
}
case "reload":
err := t.ReloadMetadata()
if err != nil {
return errors.Wrap(err, "Cannot reload Metadata")
return errors.Wrap(err, "cannot reload Metadata")
}
case "apply":
data, err := ioutil.ReadFile(metadataPath)
if err != nil {
return errors.Wrap(err, "cannot read metadata file")
var data interface{}
var metadataContent []byte
for _, format := range []string{"yaml", "json"} {
metadataPath, err := ec.GetMetadataFilePath(format)
if err != nil {
return errors.Wrap(err, "cannot apply metadata")
}
metadataContent, err = ioutil.ReadFile(metadataPath)
if err != nil {
if os.IsNotExist(err) {
continue
}
return err
}
break
}
var q interface{}
err = yaml.Unmarshal(data, &q)
if metadataContent == nil {
return errors.New("Unable to locate metadata.[yaml|json] file under migrations directory")
}
err := yaml.Unmarshal(metadataContent, &data)
if err != nil {
return errors.Wrap(err, "cannot parse metadata file")
}
err = t.ApplyMetadata(q)
err = t.ApplyMetadata(data)
if err != nil {
return errors.Wrap(err, "cannot apply metadata on the database")
}
return nil
}
return nil
}

View File

@ -16,7 +16,7 @@ func newMetadataApplyCmd(ec *cli.ExecutionContext) *cobra.Command {
metadataApplyCmd := &cobra.Command{
Use: "apply",
Short: "Apply Hasura metadata on a database",
Example: ` # Apply Hasura GraphQL Engine metadata present in metadata.yaml file:
Example: ` # Apply Hasura GraphQL Engine metadata present in metadata.[yaml|json] file:
hasura metadata apply`,
SilenceUsage: true,
PreRunE: func(cmd *cobra.Command, args []string) error {
@ -53,5 +53,5 @@ func (o *metadataApplyOptions) run() error {
if err != nil {
return err
}
return executeMetadata(o.actionType, migrateDrv, o.EC.MetadataFile)
return executeMetadata(o.actionType, migrateDrv, o.EC)
}

View File

@ -18,7 +18,7 @@ func testMetadataApply(t *testing.T, metadataFile string, endpoint *url.URL) {
EC: &cli.ExecutionContext{
Logger: logger,
Spinner: spinner.New(spinner.CharSets[7], 100*time.Millisecond),
MetadataFile: metadataFile,
MetadataFile: []string{metadataFile},
ServerConfig: &cli.ServerConfig{
Endpoint: endpoint.String(),
AdminSecret: os.Getenv("HASURA_GRAPHQL_TEST_ADMIN_SECRET"),
@ -37,6 +37,6 @@ func testMetadataApply(t *testing.T, metadataFile string, endpoint *url.URL) {
err = opts.run()
if err != nil {
t.Fatalf("failed exporting metadata: %v", err)
t.Fatalf("failed applying metadata: %v", err)
}
}

View File

@ -60,5 +60,5 @@ func (o *metadataExportOptions) run() error {
if err != nil {
return err
}
return executeMetadata(o.actionType, migrateDrv, o.EC.MetadataFile)
return executeMetadata(o.actionType, migrateDrv, o.EC)
}

View File

@ -18,7 +18,7 @@ func testMetadataExport(t *testing.T, metadataFile string, endpoint *url.URL) {
EC: &cli.ExecutionContext{
Logger: logger,
Spinner: spinner.New(spinner.CharSets[7], 100*time.Millisecond),
MetadataFile: metadataFile,
MetadataFile: []string{metadataFile},
ServerConfig: &cli.ServerConfig{
Endpoint: endpoint.String(),
AdminSecret: os.Getenv("HASURA_GRAPHQL_TEST_ADMIN_SECRET"),

View File

@ -54,7 +54,7 @@ func (o *metadataReloadOptions) run() error {
if err != nil {
return err
}
err = executeMetadata(o.actionType, migrateDrv, o.EC.MetadataFile)
err = executeMetadata(o.actionType, migrateDrv, o.EC)
if err != nil {
return errors.Wrap(err, "Cannot reload metadata")
}

View File

@ -18,7 +18,7 @@ func testMetadataReload(t *testing.T, metadataFile string, endpoint *url.URL) {
EC: &cli.ExecutionContext{
Logger: logger,
Spinner: spinner.New(spinner.CharSets[7], 100*time.Millisecond),
MetadataFile: metadataFile,
MetadataFile: []string{metadataFile},
ServerConfig: &cli.ServerConfig{
Endpoint: endpoint.String(),
AdminSecret: os.Getenv("HASURA_GRAPHQL_TEST_ADMIN_SECRET"),

View File

@ -54,7 +54,7 @@ func (o *metadataResetOptions) run() error {
if err != nil {
return err
}
err = executeMetadata(o.actionType, migrateDrv, o.EC.MetadataFile)
err = executeMetadata(o.actionType, migrateDrv, o.EC)
if err != nil {
return errors.Wrap(err, "Cannot reset metadata")
}

View File

@ -18,7 +18,7 @@ func testMetadataReset(t *testing.T, metadataFile string, endpoint *url.URL) {
EC: &cli.ExecutionContext{
Logger: logger,
Spinner: spinner.New(spinner.CharSets[7], 100*time.Millisecond),
MetadataFile: metadataFile,
MetadataFile: []string{metadataFile},
ServerConfig: &cli.ServerConfig{
Endpoint: endpoint.String(),
AdminSecret: os.Getenv("HASURA_GRAPHQL_TEST_ADMIN_SECRET"),

View File

@ -31,7 +31,7 @@ func newMigrateStatusCmd(ec *cli.ExecutionContext) *cobra.Command {
if err != nil {
return err
}
buf := PrintStatus(status)
buf := printStatus(status)
fmt.Println(buf.String())
return nil
},
@ -67,7 +67,7 @@ func (o *migrateStatusOptions) run() (*migrate.Status, error) {
return status, nil
}
func PrintStatus(status *migrate.Status) *bytes.Buffer {
func printStatus(status *migrate.Status) *bytes.Buffer {
out := new(tabwriter.Writer)
buf := &bytes.Buffer{}
out.Init(buf, 0, 8, 2, ' ', 0)

View File

@ -9,7 +9,7 @@ import (
"github.com/spf13/cobra"
)
const HasuraASCIIText = `
const hasuraASCIIText = `
__
/ /_ ____ _ _____ __ __ _____ ____ _
/ __ \ / __ ` + "`" + `// ___// / / // ___// __ ` + "`" + `/
@ -25,7 +25,7 @@ var ec *cli.ExecutionContext
var rootCmd = &cobra.Command{
Use: "hasura",
Short: "Hasura GraphQL Engine command line tool",
Long: HasuraASCIIText,
Long: hasuraASCIIText,
SilenceUsage: true,
SilenceErrors: true,
PersistentPreRun: func(cmd *cobra.Command, args []string) {

View File

@ -20,7 +20,7 @@ Examples
::
# Bash
# Bash
# Linux
# Add Bash completion file using:
$ sudo hasura completion bash --file=/etc/bash.completion.d/hasura
@ -63,8 +63,9 @@ Options inherited from parent commands
::
--log-level string log level (DEBUG, INFO, WARN, ERROR, FATAL) (default "INFO")
--project string directory where commands are executed. (default: current dir)
--log-level string log level (DEBUG, INFO, WARN, ERROR, FATAL) (default "INFO")
--project string directory where commands are executed (default: current dir)
--skip-update-check Skip automatic update check on command execution
SEE ALSO
~~~~~~~~

View File

@ -31,8 +31,8 @@ Options
::
--admin-secret string admin secret key for Hasura GraphQL Engine
--address string address to serve console and migration API from (default "localhost")
--admin-secret string admin secret for Hasura GraphQL Engine
--api-port string port for serving migrate api (default "9693")
--console-port string port for serving console (default "9695")
--endpoint string http(s) endpoint for Hasura GraphQL Engine
@ -45,8 +45,9 @@ Options inherited from parent commands
::
--log-level string log level (DEBUG, INFO, WARN, ERROR, FATAL) (default "INFO")
--project string directory where commands are executed. (default: current dir)
--log-level string log level (DEBUG, INFO, WARN, ERROR, FATAL) (default "INFO")
--project string directory where commands are executed (default: current dir)
--skip-update-check Skip automatic update check on command execution
SEE ALSO
~~~~~~~~

View File

@ -23,9 +23,9 @@ Examples
# Create a directory to store migrations
hasura init
# Now, edit <my-directory>/config.yaml to add endpoint and admin secret key
# Now, edit <my-directory>/config.yaml to add endpoint and admin secret
# Create a directory with endpoint and admin secret key configured:
# Create a directory with endpoint and admin secret configured:
hasura init --directory <my-project> --endpoint https://my-graphql-engine.com --admin-secret adminsecretkey
# See https://docs.hasura.io/1.0/graphql/manual/migrations/index.html for more details
@ -35,7 +35,7 @@ Options
::
--admin-secret string admin secret key for Hasura GraphQL Engine
--admin-secret string admin secret for Hasura GraphQL Engine
--directory string name of directory where files will be created
--endpoint string http(s) endpoint for Hasura GraphQL Engine
-h, --help help for init
@ -45,8 +45,9 @@ Options inherited from parent commands
::
--log-level string log level (DEBUG, INFO, WARN, ERROR, FATAL) (default "INFO")
--project string directory where commands are executed. (default: current dir)
--log-level string log level (DEBUG, INFO, WARN, ERROR, FATAL) (default "INFO")
--project string directory where commands are executed (default: current dir)
--skip-update-check Skip automatic update check on command execution
SEE ALSO
~~~~~~~~

View File

@ -23,8 +23,9 @@ Options inherited from parent commands
::
--log-level string log level (DEBUG, INFO, WARN, ERROR, FATAL) (default "INFO")
--project string directory where commands are executed. (default: current dir)
--log-level string log level (DEBUG, INFO, WARN, ERROR, FATAL) (default "INFO")
--project string directory where commands are executed (default: current dir)
--skip-update-check Skip automatic update check on command execution
SEE ALSO
~~~~~~~~

View File

@ -20,7 +20,7 @@ Examples
::
# Apply Hasura GraphQL Engine metadata present in metadata.yaml file:
# Apply Hasura GraphQL Engine metadata present in metadata.[yaml|json] file:
hasura metadata apply
Options
@ -28,7 +28,7 @@ Options
::
--admin-secret string admin secret key for Hasura GraphQL Engine
--admin-secret string admin secret for Hasura GraphQL Engine
--endpoint string http(s) endpoint for Hasura GraphQL Engine
-h, --help help for apply
@ -37,8 +37,9 @@ Options inherited from parent commands
::
--log-level string log level (DEBUG, INFO, WARN, ERROR, FATAL) (default "INFO")
--project string directory where commands are executed. (default: current dir)
--log-level string log level (DEBUG, INFO, WARN, ERROR, FATAL) (default "INFO")
--project string directory where commands are executed (default: current dir)
--skip-update-check Skip automatic update check on command execution
SEE ALSO
~~~~~~~~

View File

@ -10,9 +10,9 @@ Synopsis
Export Hasura metadata and save it in migrations/metadata.yaml file.
The output is a yaml file which captures all the metadata required
The output is a yaml file which captures all the metadata required
by GraphQL Engine. This includes info about tables that are tracked,
permission rules, relationships and event triggers that are defined
permission rules, relationships and event triggers that are defined
on those tables.
::
@ -32,7 +32,7 @@ Options
::
--admin-secret string admin secret key for Hasura GraphQL Engine
--admin-secret string admin secret for Hasura GraphQL Engine
--endpoint string http(s) endpoint for Hasura GraphQL Engine
-h, --help help for export
@ -41,8 +41,9 @@ Options inherited from parent commands
::
--log-level string log level (DEBUG, INFO, WARN, ERROR, FATAL) (default "INFO")
--project string directory where commands are executed. (default: current dir)
--log-level string log level (DEBUG, INFO, WARN, ERROR, FATAL) (default "INFO")
--project string directory where commands are executed (default: current dir)
--skip-update-check Skip automatic update check on command execution
SEE ALSO
~~~~~~~~

View File

@ -28,7 +28,7 @@ Options
::
--admin-secret string admin secret key for Hasura GraphQL Engine
--admin-secret string admin secret for Hasura GraphQL Engine
--endpoint string http(s) endpoint for Hasura GraphQL Engine
-h, --help help for reload
@ -37,8 +37,9 @@ Options inherited from parent commands
::
--log-level string log level (DEBUG, INFO, WARN, ERROR, FATAL) (default "INFO")
--project string directory where commands are executed. (default: current dir)
--log-level string log level (DEBUG, INFO, WARN, ERROR, FATAL) (default "INFO")
--project string directory where commands are executed (default: current dir)
--skip-update-check Skip automatic update check on command execution
SEE ALSO
~~~~~~~~

View File

@ -37,8 +37,9 @@ Options inherited from parent commands
::
--log-level string log level (DEBUG, INFO, WARN, ERROR, FATAL) (default "INFO")
--project string directory where commands are executed. (default: current dir)
--log-level string log level (DEBUG, INFO, WARN, ERROR, FATAL) (default "INFO")
--project string directory where commands are executed (default: current dir)
--skip-update-check Skip automatic update check on command execution
SEE ALSO
~~~~~~~~

View File

@ -23,8 +23,9 @@ Options inherited from parent commands
::
--log-level string log level (DEBUG, INFO, WARN, ERROR, FATAL) (default "INFO")
--project string directory where commands are executed. (default: current dir)
--log-level string log level (DEBUG, INFO, WARN, ERROR, FATAL) (default "INFO")
--project string directory where commands are executed (default: current dir)
--skip-update-check Skip automatic update check on command execution
SEE ALSO
~~~~~~~~

View File

@ -20,7 +20,7 @@ Options
::
--admin-secret string admin secret key for Hasura GraphQL Engine
--admin-secret string admin secret for Hasura GraphQL Engine
--endpoint string http(s) endpoint for Hasura GraphQL Engine
-h, --help help for status
@ -29,8 +29,9 @@ Options inherited from parent commands
::
--log-level string log level (DEBUG, INFO, WARN, ERROR, FATAL) (default "INFO")
--project string directory where commands are executed. (default: current dir)
--log-level string log level (DEBUG, INFO, WARN, ERROR, FATAL) (default "INFO")
--project string directory where commands are executed (default: current dir)
--skip-update-check Skip automatic update check on command execution
SEE ALSO
~~~~~~~~

View File

@ -40,8 +40,9 @@ Options inherited from parent commands
::
--log-level string log level (DEBUG, INFO, WARN, ERROR, FATAL) (default "INFO")
--project string directory where commands are executed. (default: current dir)
--log-level string log level (DEBUG, INFO, WARN, ERROR, FATAL) (default "INFO")
--project string directory where commands are executed (default: current dir)
--skip-update-check Skip automatic update check on command execution
SEE ALSO
~~~~~~~~

View File

@ -27,8 +27,9 @@ Options inherited from parent commands
::
--log-level string log level (DEBUG, INFO, WARN, ERROR, FATAL) (default "INFO")
--project string directory where commands are executed. (default: current dir)
--log-level string log level (DEBUG, INFO, WARN, ERROR, FATAL) (default "INFO")
--project string directory where commands are executed (default: current dir)
--skip-update-check Skip automatic update check on command execution
SEE ALSO
~~~~~~~~