diff --git a/.changeset/ten-readers-dance.md b/.changeset/ten-readers-dance.md new file mode 100644 index 000000000..22b8bf18f --- /dev/null +++ b/.changeset/ten-readers-dance.md @@ -0,0 +1,5 @@ +--- +"chainlink-deployments-framework": minor +--- + +feat: adds 'all' datastore config option diff --git a/engine/cld/config/domain/domain.go b/engine/cld/config/domain/domain.go index 526273b89..cdcd4f4b9 100644 --- a/engine/cld/config/domain/domain.go +++ b/engine/cld/config/domain/domain.go @@ -17,6 +17,9 @@ const ( DatastoreTypeFile DatastoreType = "file" // DatastoreTypeCatalog indicates data should be persisted to the remote catalog service. DatastoreTypeCatalog DatastoreType = "catalog" + // DatastoreTypeAll indicates data should be persisted to both local JSON files and the remote catalog service. + // This is useful to keep backward compatibility during the transition period from file-based to remote catalog. + DatastoreTypeAll DatastoreType = "all" ) // String returns the string representation of the DatastoreType. @@ -26,7 +29,7 @@ func (d DatastoreType) String() string { // IsValid checks if the DatastoreType is a valid value. func (d DatastoreType) IsValid() bool { - return d == DatastoreTypeFile || d == DatastoreTypeCatalog + return d == DatastoreTypeFile || d == DatastoreTypeCatalog || d == DatastoreTypeAll } // Environment represents a single environment configuration. @@ -59,7 +62,7 @@ func (e *Environment) validate() error { // Validate datastore field if provided if e.Datastore != "" && !e.Datastore.IsValid() { - return fmt.Errorf("invalid datastore value: %s (must be 'file' or 'catalog')", e.Datastore) + return fmt.Errorf("invalid datastore value: %s (must be 'file', 'catalog', or 'all')", e.Datastore) } return nil diff --git a/engine/cld/config/domain/domain_test.go b/engine/cld/config/domain/domain_test.go index 247ede974..4682d6a78 100644 --- a/engine/cld/config/domain/domain_test.go +++ b/engine/cld/config/domain/domain_test.go @@ -66,6 +66,11 @@ func TestDatastoreType_IsValid(t *testing.T) { datastore: DatastoreTypeCatalog, expected: true, }, + { + name: "all is valid", + datastore: DatastoreTypeAll, + expected: true, + }, { name: "invalid value", datastore: DatastoreType("invalid"), @@ -133,6 +138,14 @@ func TestEnvironment_Validate(t *testing.T) { }, wantErr: false, }, + { + name: "valid environment with all datastore", + environment: Environment{ + NetworkTypes: []string{"testnet"}, + Datastore: DatastoreTypeAll, + }, + wantErr: false, + }, { name: "valid environment without datastore (optional field)", environment: Environment{ diff --git a/engine/cld/legacy/cli/commands/migration.go b/engine/cld/legacy/cli/commands/migration.go index 0bf6a5129..c99942e95 100644 --- a/engine/cld/legacy/cli/commands/migration.go +++ b/engine/cld/legacy/cli/commands/migration.go @@ -497,17 +497,17 @@ func (Commands) newMigrationDataStoreMerge(domain domain.Domain) *cobra.Command } // Determine which merge method to use based on datastore configuration - if cfg.DatastoreType == cfgdomain.DatastoreTypeCatalog { - ctx := cmd.Context() + switch cfg.DatastoreType { + case cfgdomain.DatastoreTypeCatalog: // Catalog mode - merge to catalog service cmd.Printf("📡 Using catalog datastore mode (endpoint: %s)\n", cfg.Env.Catalog.GRPC) - catalog, catalogErr := cldcatalog.LoadCatalog(ctx, envKey, cfg, domain) + catalog, catalogErr := cldcatalog.LoadCatalog(cmd.Context(), envKey, cfg, domain) if catalogErr != nil { return fmt.Errorf("failed to load catalog: %w", catalogErr) } - if err := envDir.MergeMigrationDataStoreCatalog(ctx, migrationName, timestamp, catalog); err != nil { + if err := envDir.MergeMigrationDataStoreCatalog(cmd.Context(), migrationName, timestamp, catalog); err != nil { return fmt.Errorf("error during data store merge to catalog for %s %s %s: %w", domain, envKey, migrationName, err, ) @@ -516,7 +516,7 @@ func (Commands) newMigrationDataStoreMerge(domain domain.Domain) *cobra.Command cmd.Printf("✅ Merged data stores to catalog for %s %s %s\n", domain, envKey, migrationName, ) - } else { + case cfgdomain.DatastoreTypeFile: // File mode - merge to local files cmd.Printf("📁 Using file-based datastore mode\n") @@ -529,6 +529,32 @@ func (Commands) newMigrationDataStoreMerge(domain domain.Domain) *cobra.Command cmd.Printf("✅ Merged data stores to local files for %s %s %s\n", domain, envKey, migrationName, ) + case cfgdomain.DatastoreTypeAll: + // All mode - merge to both catalog and local files + cmd.Printf("📡 Using all datastore mode (catalog: %s, file: %s)\n", cfg.Env.Catalog.GRPC, envDir.DataStoreDirPath()) + + catalog, catalogErr := cldcatalog.LoadCatalog(cmd.Context(), envKey, cfg, domain) + if catalogErr != nil { + return fmt.Errorf("failed to load catalog: %w", catalogErr) + } + + if err := envDir.MergeMigrationDataStoreCatalog(cmd.Context(), migrationName, timestamp, catalog); err != nil { + return fmt.Errorf("error during data store merge to catalog for %s %s %s: %w", + domain, envKey, migrationName, err, + ) + } + + if err := envDir.MergeMigrationDataStore(migrationName, timestamp); err != nil { + return fmt.Errorf("error during data store merge to file for %s %s %s: %w", + domain, envKey, migrationName, err, + ) + } + + cmd.Printf("✅ Merged data stores to both catalog and local files for %s %s %s\n", + domain, envKey, migrationName, + ) + default: + return fmt.Errorf("invalid datastore type: %s", cfg.DatastoreType) } return nil