Skip to content

Commit 4e39cd1

Browse files
committed
feat: init cli structure
1 parent 5ae7bfe commit 4e39cd1

File tree

2 files changed

+106
-1
lines changed

2 files changed

+106
-1
lines changed

backend/Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LOAD_ENV := doppler run --
77
LLM_URL := http://127.0.0.1:11434
88

99
.PHONY: all build run dev test format tidy download clean docker-build docker-run \
10-
migrate-new migrate-up migrate-down migrate-status migrate-reset db-start db-stop db-reset swagger swagger-fmt docker-build docker-run llm-start genkit-run seed
10+
migrate-new migrate-up migrate-down migrate-status migrate-reset db-start db-stop db-reset swagger swagger-fmt docker-build docker-run llm-start genkit-run seed cli
1111

1212
all: build
1313

@@ -42,6 +42,9 @@ genkit-run: llm-start db-start
4242
@$(LOAD_ENV) \
4343
genkit start -- go run $(CMD_PATH)
4444

45+
cli:
46+
@$(LOAD_ENV) go run ./cmd/cli $(filter-out $@,$(MAKECMDGOALS))
47+
4548
sync-users:
4649
@$(LOAD_ENV) go run ./cmd/clerk/sync.go
4750

backend/cmd/cli/main.go

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"flag"
6+
"fmt"
7+
"log"
8+
"os"
9+
10+
"github.com/generate/selfserve/config"
11+
"github.com/generate/selfserve/internal/repository"
12+
"github.com/generate/selfserve/internal/service/clerk"
13+
storage "github.com/generate/selfserve/internal/service/storage/postgres"
14+
"github.com/sethvargo/go-envconfig"
15+
)
16+
17+
// command is a runnable CLI subcommand.
18+
type command struct {
19+
description string
20+
run func(ctx context.Context, cfg config.Config, args []string) error
21+
}
22+
23+
// commands is the registry of all available CLI subcommands.
24+
// To add a new command: add an entry here and implement its run func below.
25+
var commands = map[string]command{
26+
"sync-users": {
27+
description: "Sync users from Clerk into the database",
28+
run: runSyncUsers,
29+
},
30+
// "my-new-command": {
31+
// description: "What this command does",
32+
// run: runMyNewCommand,
33+
// },
34+
}
35+
36+
func main() {
37+
flag.Usage = printUsage
38+
flag.Parse()
39+
40+
args := flag.Args()
41+
if len(args) == 0 {
42+
printUsage()
43+
os.Exit(1)
44+
}
45+
46+
name := args[0]
47+
cmd, ok := commands[name]
48+
if !ok {
49+
fmt.Fprintf(os.Stderr, "unknown command: %q\n\n", name)
50+
printUsage()
51+
os.Exit(1)
52+
}
53+
54+
ctx := context.Background()
55+
var cfg config.Config
56+
if err := envconfig.Process(ctx, &cfg); err != nil {
57+
log.Fatal("failed to process config:", err)
58+
}
59+
60+
if err := cmd.run(ctx, cfg, args[1:]); err != nil {
61+
log.Fatalf("%s: %v", name, err)
62+
}
63+
}
64+
65+
func printUsage() {
66+
fmt.Fprintf(os.Stderr, "Usage: cli <command> [args]\n\nAvailable commands:\n")
67+
for name, cmd := range commands {
68+
fmt.Fprintf(os.Stderr, " %-20s %s\n", name, cmd.description)
69+
}
70+
fmt.Fprintln(os.Stderr)
71+
}
72+
73+
// =============================================================================
74+
// Command implementations
75+
// =============================================================================
76+
77+
func runSyncUsers(ctx context.Context, cfg config.Config, _ []string) error {
78+
repo, err := storage.NewRepository(cfg.DB)
79+
if err != nil {
80+
return fmt.Errorf("failed to connect to db: %w", err)
81+
}
82+
defer repo.Close()
83+
84+
usersRepo := repository.NewUsersRepository(repo.DB)
85+
86+
users, err := clerk.FetchUsersFromClerk(cfg.BaseURL+"/users", cfg.SecretKey)
87+
if err != nil {
88+
return err
89+
}
90+
91+
transformed, err := clerk.ValidateAndReformatUserData(users)
92+
if err != nil {
93+
return err
94+
}
95+
96+
if err := usersRepo.BulkInsertUsers(ctx, transformed); err != nil {
97+
return fmt.Errorf("failed to insert users: %w", err)
98+
}
99+
100+
fmt.Println("sync-users completed successfully")
101+
return nil
102+
}

0 commit comments

Comments
 (0)