Skip to content

Commit a769045

Browse files
CodeLieutenantsoyacz
authored andcommitted
feature(cli): add discussion write commands (submit, update, delete)
Restructure comment write operations into a dedicated cmd/discussions sub-package with a proper service layer, extracting RunE closures into standalone named functions. Context helpers moved to internal/cmdctx to avoid circular imports between cmd and cmd/discussions. Also fixes the logging stderr filter to mirror the configured level (not just errors) and corrects the corresponding tests.
1 parent 8bd423d commit a769045

File tree

14 files changed

+1026
-863
lines changed

14 files changed

+1026
-863
lines changed

cli/cmd/context.go

Lines changed: 23 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -6,145 +6,76 @@ import (
66
"github.com/rs/zerolog"
77
"github.com/scylladb/argus/cli/internal/api"
88
"github.com/scylladb/argus/cli/internal/cache"
9+
"github.com/scylladb/argus/cli/internal/cmdctx"
910
"github.com/scylladb/argus/cli/internal/config"
1011
"github.com/scylladb/argus/cli/internal/logging"
1112
"github.com/scylladb/argus/cli/internal/output"
1213
)
1314

14-
// outputterKey is the context key used to store the [output.Outputter].
15-
type outputterKey struct{}
15+
// ---------------------------------------------------------------------------
16+
// Thin wrappers that delegate to the shared cmdctx package.
17+
//
18+
// The unexported contextWith* functions are kept for backward compatibility
19+
// with existing tests that export them via export_test.go. New sub-command
20+
// packages (e.g. cmd/discussions) should import cmdctx directly.
21+
// ---------------------------------------------------------------------------
1622

1723
// contextWithOutputter returns a copy of ctx carrying out.
1824
func contextWithOutputter(ctx context.Context, out output.Outputter) context.Context {
19-
if ctx == nil {
20-
ctx = context.Background()
21-
}
22-
23-
return context.WithValue(ctx, outputterKey{}, out)
25+
return cmdctx.WithOutputter(ctx, out)
2426
}
2527

26-
// OutputterFrom retrieves the [output.Outputter] stored in cmd's context.
27-
// It panics if no Outputter is present, which indicates that the command was
28-
// registered without going through the root PersistentPreRun chain.
28+
// OutputterFrom retrieves the [output.Outputter] stored in ctx.
2929
func OutputterFrom(ctx context.Context) output.Outputter {
30-
out, ok := ctx.Value(outputterKey{}).(output.Outputter)
31-
if !ok {
32-
panic("cmd: no output.Outputter in context; ensure PersistentPreRun propagates from root")
33-
}
34-
35-
return out
30+
return cmdctx.OutputterFrom(ctx)
3631
}
3732

38-
// apiClientKey is the context key used to store the [api.Client].
39-
type apiClientKey struct{}
40-
4133
// contextWithAPIClient returns a copy of ctx carrying client.
4234
func contextWithAPIClient(ctx context.Context, client *api.Client) context.Context {
43-
if ctx == nil {
44-
ctx = context.Background()
45-
}
46-
47-
return context.WithValue(ctx, apiClientKey{}, client)
35+
return cmdctx.WithAPIClient(ctx, client)
4836
}
4937

50-
// APIClientFrom retrieves the [api.Client] stored in cmd's context.
51-
// It panics if no client is present, which indicates that the command was
52-
// registered without going through the root PersistentPreRun chain.
38+
// APIClientFrom retrieves the [api.Client] stored in ctx.
5339
func APIClientFrom(ctx context.Context) *api.Client {
54-
client, ok := ctx.Value(apiClientKey{}).(*api.Client)
55-
if !ok {
56-
panic("cmd: no api.Client in context; ensure PersistentPreRun propagates from root")
57-
}
58-
59-
return client
40+
return cmdctx.APIClientFrom(ctx)
6041
}
6142

62-
// configKey is the context key used to store the [config.Config].
63-
type configKey struct{}
64-
6543
// contextWithConfig returns a copy of ctx carrying cfg.
6644
func contextWithConfig(ctx context.Context, cfg *config.Config) context.Context {
67-
if ctx == nil {
68-
ctx = context.Background()
69-
}
70-
71-
return context.WithValue(ctx, configKey{}, cfg)
45+
return cmdctx.WithConfig(ctx, cfg)
7246
}
7347

74-
// ConfigFrom retrieves the [config.Config] stored in cmd's context.
75-
// It panics if no Config is present, which indicates that the command was
76-
// registered without going through the root PersistentPreRun chain.
48+
// ConfigFrom retrieves the [config.Config] stored in ctx.
7749
func ConfigFrom(ctx context.Context) *config.Config {
78-
cfg, ok := ctx.Value(configKey{}).(*config.Config)
79-
if !ok {
80-
panic("cmd: no config.Config in context; ensure PersistentPreRun propagates from root")
81-
}
82-
83-
return cfg
50+
return cmdctx.ConfigFrom(ctx)
8451
}
8552

86-
// loggerKey is the context key used to store the root [zerolog.Logger].
87-
type loggerKey struct{}
88-
8953
// contextWithLogger returns a copy of ctx carrying logger.
9054
func contextWithLogger(ctx context.Context, logger zerolog.Logger) context.Context {
91-
if ctx == nil {
92-
ctx = context.Background()
93-
}
94-
95-
return context.WithValue(ctx, loggerKey{}, logger)
55+
return cmdctx.WithLogger(ctx, logger)
9656
}
9757

9858
// LoggerFrom retrieves the [zerolog.Logger] stored in ctx.
99-
// It panics if no logger is present, which indicates that the command was
100-
// registered without going through the root PersistentPreRun chain.
10159
func LoggerFrom(ctx context.Context) zerolog.Logger {
102-
logger, ok := ctx.Value(loggerKey{}).(zerolog.Logger)
103-
if !ok {
104-
panic("cmd: no zerolog.Logger in context; ensure PersistentPreRun propagates from root")
105-
}
106-
107-
return logger
60+
return cmdctx.LoggerFrom(ctx)
10861
}
10962

110-
// cleanupKey is the context key used to store the logging [logging.CleanupFunc].
111-
type cleanupKey struct{}
112-
11363
// contextWithCleanup returns a copy of ctx carrying cleanup.
11464
func contextWithCleanup(ctx context.Context, cleanup logging.CleanupFunc) context.Context {
115-
if ctx == nil {
116-
ctx = context.Background()
117-
}
118-
119-
return context.WithValue(ctx, cleanupKey{}, cleanup)
65+
return cmdctx.WithCleanup(ctx, cleanup)
12066
}
12167

12268
// CleanupFrom retrieves the [logging.CleanupFunc] stored in ctx.
123-
// Returns a no-op if none is present (e.g. when logging setup failed or in
124-
// tests that bypass PersistentPreRun).
12569
func CleanupFrom(ctx context.Context) logging.CleanupFunc {
126-
if fn, ok := ctx.Value(cleanupKey{}).(logging.CleanupFunc); ok {
127-
return fn
128-
}
129-
return func() {}
70+
return cmdctx.CleanupFrom(ctx)
13071
}
13172

132-
// cacheKey is the context key used to store the [cache.Cache].
133-
type cacheKey struct{}
134-
13573
// contextWithCache returns a copy of ctx carrying c.
13674
func contextWithCache(ctx context.Context, c *cache.Cache) context.Context {
137-
if ctx == nil {
138-
ctx = context.Background()
139-
}
140-
return context.WithValue(ctx, cacheKey{}, c)
75+
return cmdctx.WithCache(ctx, c)
14176
}
14277

14378
// CacheFrom retrieves the [cache.Cache] stored in ctx.
144-
// Returns a disabled cache if none is present so callers never need to nil-check.
14579
func CacheFrom(ctx context.Context) *cache.Cache {
146-
if c, ok := ctx.Value(cacheKey{}).(*cache.Cache); ok {
147-
return c
148-
}
149-
return cache.New("", cache.WithDisabled(true))
80+
return cmdctx.CacheFrom(ctx)
15081
}

0 commit comments

Comments
 (0)