|
| 1 | +package dev_server |
| 2 | + |
| 3 | +import ( |
| 4 | + "context" |
| 5 | + "fmt" |
| 6 | + "log" |
| 7 | + |
| 8 | + "github.com/adrg/xdg" |
| 9 | + "github.com/spf13/cobra" |
| 10 | + "github.com/spf13/viper" |
| 11 | + |
| 12 | + "github.com/launchdarkly/ldcli/cmd/cliflags" |
| 13 | + resourcescmd "github.com/launchdarkly/ldcli/cmd/resources" |
| 14 | + "github.com/launchdarkly/ldcli/cmd/validators" |
| 15 | + "github.com/launchdarkly/ldcli/internal/dev_server/db" |
| 16 | + "github.com/launchdarkly/ldcli/internal/dev_server/model" |
| 17 | +) |
| 18 | + |
| 19 | +const ImportFileFlag = "file" |
| 20 | + |
| 21 | +func NewImportProjectCmd() *cobra.Command { |
| 22 | + cmd := &cobra.Command{ |
| 23 | + GroupID: "projects", |
| 24 | + Args: validators.Validate(), |
| 25 | + Long: `Import a project into the dev server database from a JSON file. |
| 26 | +
|
| 27 | +The JSON file format matches the output from: |
| 28 | + ldcli dev-server get-project --project=<key> \ |
| 29 | + --expand=overrides --expand=availableVariations |
| 30 | +
|
| 31 | +Examples: |
| 32 | + # Export project data (while dev server is running) |
| 33 | + ldcli dev-server get-project --project=my-project \ |
| 34 | + --expand=overrides --expand=availableVariations > backup.json |
| 35 | +
|
| 36 | + # Later, import the project from backup |
| 37 | + ldcli dev-server import-project --project=my-project --file=backup.json`, |
| 38 | + RunE: importProject(), |
| 39 | + Short: "import project from file", |
| 40 | + Use: "import-project", |
| 41 | + } |
| 42 | + |
| 43 | + cmd.SetUsageTemplate(resourcescmd.SubcommandUsageTemplate()) |
| 44 | + |
| 45 | + cmd.Flags().String(cliflags.ProjectFlag, "", "The project key to create") |
| 46 | + _ = cmd.MarkFlagRequired(cliflags.ProjectFlag) |
| 47 | + _ = cmd.Flags().SetAnnotation(cliflags.ProjectFlag, "required", []string{"true"}) |
| 48 | + _ = viper.BindPFlag(cliflags.ProjectFlag, cmd.Flags().Lookup(cliflags.ProjectFlag)) |
| 49 | + |
| 50 | + cmd.Flags().String(ImportFileFlag, "", "Path to JSON file containing project data") |
| 51 | + _ = cmd.MarkFlagRequired(ImportFileFlag) |
| 52 | + _ = cmd.Flags().SetAnnotation(ImportFileFlag, "required", []string{"true"}) |
| 53 | + _ = viper.BindPFlag(ImportFileFlag, cmd.Flags().Lookup(ImportFileFlag)) |
| 54 | + |
| 55 | + return cmd |
| 56 | +} |
| 57 | + |
| 58 | +func importProject() func(*cobra.Command, []string) error { |
| 59 | + return func(cmd *cobra.Command, args []string) error { |
| 60 | + ctx := context.Background() |
| 61 | + projectKey := viper.GetString(cliflags.ProjectFlag) |
| 62 | + filepath := viper.GetString(ImportFileFlag) |
| 63 | + |
| 64 | + // Get database path (same logic as dev_server.go) |
| 65 | + dbFilePath, err := xdg.StateFile("ldcli/dev_server.db") |
| 66 | + if err != nil { |
| 67 | + return fmt.Errorf("unable to get database path: %w", err) |
| 68 | + } |
| 69 | + |
| 70 | + // Open database |
| 71 | + sqlStore, err := db.NewSqlite(ctx, dbFilePath) |
| 72 | + if err != nil { |
| 73 | + return fmt.Errorf("unable to open database: %w", err) |
| 74 | + } |
| 75 | + |
| 76 | + // Set store on context |
| 77 | + ctx = model.ContextWithStore(ctx, sqlStore) |
| 78 | + |
| 79 | + // Import project from file |
| 80 | + err = model.ImportProjectFromFile(ctx, projectKey, filepath) |
| 81 | + if err != nil { |
| 82 | + return fmt.Errorf("unable to import project: %w", err) |
| 83 | + } |
| 84 | + |
| 85 | + log.Printf("Successfully imported project '%s' from %s", projectKey, filepath) |
| 86 | + fmt.Fprintf(cmd.OutOrStdout(), "Successfully imported project '%s' from %s\n", projectKey, filepath) |
| 87 | + |
| 88 | + return nil |
| 89 | + } |
| 90 | +} |
0 commit comments