feat: console help, examples and named loggers (SummerCMS v0.4.0)
Every command gets long help and examples, descriptions in imperative sentence case, and a warn-only TestCommandsDocumented over bonfire.CheckDocs. The plugin logs through a diary component logger instead of the process default logger. Requires SummerCMS v0.4.0; command names and flags unchanged.
This commit is contained in:
@@ -24,11 +24,26 @@ const translatableExportFields = "title,slug,content,content_html,excerpt,metada
|
||||
func ExportPosts(app *backpack.App) bonfire.Command {
|
||||
return bonfire.Command{
|
||||
Name: "journal:export-posts",
|
||||
Description: "Export all journal posts with translations to JSON files (one per post).",
|
||||
Description: "Export every journal post with its translations to JSON files, one per post",
|
||||
Long: `Writes one JSON file per post (named after its slug) into the export
|
||||
directory: title, slug, content, excerpt, metadata, sources, the published
|
||||
state and date, the category slugs and names, the author's e-mail and every
|
||||
translation of the enabled locales. File attachments (featured and content
|
||||
images) are not exported.
|
||||
|
||||
Use it to move posts between applications or to keep a copy in version
|
||||
control; journal:import-posts reads the same files. --dry-run lists the posts
|
||||
with their status and translation count and writes nothing. It ends with
|
||||
"Exported N posts to: <path>".`,
|
||||
Flags: []bonfire.Flag{
|
||||
{Name: "path", Description: "Export directory (default: journal-export)"},
|
||||
{Name: "dry-run", Description: "Show what would be exported without writing files", Bare: true},
|
||||
},
|
||||
Examples: []bonfire.Example{
|
||||
{Command: "journal:export-posts", Description: "Export every post into journal-export/"},
|
||||
{Command: "journal:export-posts --path backups/journal", Description: "Export into another directory"},
|
||||
{Command: "journal:export-posts --dry-run", Description: "List the posts that would be exported"},
|
||||
},
|
||||
Run: func(ctx context.Context, in bonfire.Input, out bonfire.Output) error {
|
||||
path := flagOrDefault(in, "path", defaultExportPath)
|
||||
dry := flagOn(in, "dry-run")
|
||||
@@ -88,10 +103,10 @@ func ExportToDir(ctx context.Context, gdb *gorm.DB, dir string, dry bool, out bo
|
||||
}
|
||||
exported := 0
|
||||
attachments := false
|
||||
for i := range posts {
|
||||
exportOne := func(i int) error {
|
||||
data, err := buildPostFile(ctx, gdb, &posts[i])
|
||||
if err != nil {
|
||||
return exported, attachments, err
|
||||
return err
|
||||
}
|
||||
if dry {
|
||||
status := "draft"
|
||||
@@ -102,7 +117,7 @@ func ExportToDir(ctx context.Context, gdb *gorm.DB, dir string, dry bool, out bo
|
||||
} else {
|
||||
raw, err := json.MarshalIndent(data, "", " ")
|
||||
if err != nil {
|
||||
return exported, attachments, err
|
||||
return err
|
||||
}
|
||||
name := posts[i].Slug
|
||||
if name == "" {
|
||||
@@ -110,13 +125,33 @@ func ExportToDir(ctx context.Context, gdb *gorm.DB, dir string, dry bool, out bo
|
||||
}
|
||||
filePath := filepath.Join(dir, name+".json")
|
||||
if err := os.MkdirAll(filepath.Dir(filePath), 0o755); err != nil {
|
||||
return exported, attachments, err
|
||||
return err
|
||||
}
|
||||
if err := os.WriteFile(filePath, raw, 0o644); err != nil {
|
||||
return exported, attachments, err
|
||||
return err
|
||||
}
|
||||
}
|
||||
exported++
|
||||
return nil
|
||||
}
|
||||
if out != nil && !dry {
|
||||
// A real export prints nothing per post, so a progress bar over the
|
||||
// posts shows how far it got (hidden under -q).
|
||||
err := out.Progress(len(posts), func(p bonfire.Progress) error {
|
||||
for i := range posts {
|
||||
if err := exportOne(i); err != nil {
|
||||
return err
|
||||
}
|
||||
p.Advance(1)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return exported, attachments, err
|
||||
}
|
||||
for i := range posts {
|
||||
if err := exportOne(i); err != nil {
|
||||
return exported, attachments, err
|
||||
}
|
||||
}
|
||||
return exported, attachments, nil
|
||||
}
|
||||
|
||||
@@ -39,12 +39,28 @@ type ImportStats struct {
|
||||
func ImportPosts(app *backpack.App) bonfire.Command {
|
||||
return bonfire.Command{
|
||||
Name: "journal:import-posts",
|
||||
Description: "Import journal posts with translations from JSON files.",
|
||||
Description: "Import journal posts with their translations from JSON files",
|
||||
Long: `Reads every *.json file of the import directory (the files
|
||||
journal:export-posts writes) and creates a post for each slug that does not
|
||||
exist yet, with its translations and categories (missing categories are
|
||||
created). A post whose slug already exists is skipped unless --force is
|
||||
given, which updates it from the file. Titles lose the draft lock mark.
|
||||
|
||||
The whole import runs in one transaction; each post prints one line
|
||||
(created, updated or skipped) and a file that is not valid JSON or has no
|
||||
slug is reported and counted as failed. --dry-run walks the files without
|
||||
writing anything. It ends with "Results: N created, N updated, N skipped, N
|
||||
failed".`,
|
||||
Flags: []bonfire.Flag{
|
||||
{Name: "path", Description: "Import directory (default: journal-export)"},
|
||||
{Name: "force", Description: "Update existing posts (default: skip existing)", Bare: true},
|
||||
{Name: "dry-run", Description: "Show what would be imported without making changes", Bare: true},
|
||||
},
|
||||
Examples: []bonfire.Example{
|
||||
{Command: "journal:import-posts --dry-run", Description: "Show what journal-export/ would create or skip"},
|
||||
{Command: "journal:import-posts --path backups/journal", Description: "Create the posts that do not exist yet"},
|
||||
{Command: "journal:import-posts --force", Description: "Also update the posts that already exist"},
|
||||
},
|
||||
Run: func(ctx context.Context, in bonfire.Input, out bonfire.Output) error {
|
||||
path := flagOrDefault(in, "path", defaultExportPath)
|
||||
force := flagOn(in, "force")
|
||||
@@ -56,7 +72,7 @@ func ImportPosts(app *backpack.App) bonfire.Command {
|
||||
if dry {
|
||||
out.Info("Dry run complete (no changes made).")
|
||||
}
|
||||
out.Info(fmt.Sprintf("Results: %d created, %d updated, %d skipped, %d failed",
|
||||
out.Success(fmt.Sprintf("Results: %d created, %d updated, %d skipped, %d failed",
|
||||
stats.Created, stats.Updated, stats.Skipped, stats.Failed))
|
||||
return nil
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user