Skip to content

Commit ec66fb2

Browse files
authored
Merge pull request #117 from keyxmakerx/claude/fix-navbar-features-page-8RZuE
fix: migration status showing 0/0 — store LatestVersion in health reg…
2 parents fac1bdf + 4b7026c commit ec66fb2

4 files changed

Lines changed: 34 additions & 31 deletions

File tree

cmd/server/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ func main() {
6060
pluginHealth := database.NewPluginHealthRegistry()
6161
pluginResults := database.RunPluginMigrations(db, database.RegisteredPlugins())
6262
for _, r := range pluginResults {
63-
pluginHealth.Register(r.Slug, r.Healthy, r.Error, r.Version)
63+
pluginHealth.Register(r.Slug, r.Healthy, r.Error, r.Version, r.LatestVersion)
6464
}
6565
if degraded := pluginHealth.DegradedPlugins(); len(degraded) > 0 {
6666
slog.Warn("some plugins are degraded — features disabled",

internal/database/plugin_health.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ type PluginHealth struct {
2020
// Version is the highest applied migration version for this plugin.
2121
Version int
2222

23+
// LatestVersion is the highest available migration version from disk.
24+
LatestVersion int
25+
2326
// UpdatedAt is when this status was last set.
2427
UpdatedAt time.Time
2528
}
@@ -41,14 +44,15 @@ func NewPluginHealthRegistry() *PluginHealthRegistry {
4144

4245
// Register records the health status of a plugin. Called once per plugin
4346
// during startup after migrations complete (or fail).
44-
func (r *PluginHealthRegistry) Register(slug string, healthy bool, err error, version int) {
47+
func (r *PluginHealthRegistry) Register(slug string, healthy bool, err error, version int, latestVersion int) {
4548
r.mu.Lock()
4649
defer r.mu.Unlock()
4750

4851
h := PluginHealth{
49-
Healthy: healthy,
50-
Version: version,
51-
UpdatedAt: time.Now(),
52+
Healthy: healthy,
53+
Version: version,
54+
LatestVersion: latestVersion,
55+
UpdatedAt: time.Now(),
5256
}
5357
if err != nil {
5458
h.Error = err.Error()

internal/database/plugin_schema.go

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@ type PluginSchema struct {
3131
// PluginMigrationResult holds the outcome of running a single plugin's
3232
// schema migrations.
3333
type PluginMigrationResult struct {
34-
Slug string
35-
Healthy bool
36-
Error error
37-
Version int
34+
Slug string
35+
Healthy bool
36+
Error error
37+
Version int
38+
LatestVersion int
3839
}
3940

4041
// pluginMigration represents a single numbered migration for a plugin.
@@ -130,15 +131,19 @@ func runSinglePluginMigrations(db *sql.DB, plugin PluginSchema) PluginMigrationR
130131
}
131132

132133
if len(migrations) == 0 {
133-
return PluginMigrationResult{Slug: plugin.Slug, Healthy: true, Version: 0}
134+
return PluginMigrationResult{Slug: plugin.Slug, Healthy: true, Version: 0, LatestVersion: 0}
134135
}
135136

137+
// Compute the highest available migration version from files.
138+
latestVersion := migrations[len(migrations)-1].Version
139+
136140
// Get already-applied versions.
137141
applied, err := getPluginAppliedVersions(ctx, db, plugin.Slug)
138142
if err != nil {
139143
return PluginMigrationResult{
140-
Slug: plugin.Slug,
141-
Error: fmt.Errorf("reading applied versions: %w", err),
144+
Slug: plugin.Slug,
145+
LatestVersion: latestVersion,
146+
Error: fmt.Errorf("reading applied versions: %w", err),
142147
}
143148
}
144149
appliedSet := make(map[int]bool, len(applied))
@@ -165,9 +170,10 @@ func runSinglePluginMigrations(db *sql.DB, plugin PluginSchema) PluginMigrationR
165170
// code, so we skip the SQL validator (unlike user extensions).
166171
if err := execPluginMigration(ctx, db, plugin.Slug, m); err != nil {
167172
return PluginMigrationResult{
168-
Slug: plugin.Slug,
169-
Error: err,
170-
Version: highestVersion,
173+
Slug: plugin.Slug,
174+
Error: err,
175+
Version: highestVersion,
176+
LatestVersion: latestVersion,
171177
}
172178
}
173179

@@ -179,9 +185,10 @@ func runSinglePluginMigrations(db *sql.DB, plugin PluginSchema) PluginMigrationR
179185
}
180186

181187
return PluginMigrationResult{
182-
Slug: plugin.Slug,
183-
Healthy: true,
184-
Version: highestVersion,
188+
Slug: plugin.Slug,
189+
Healthy: true,
190+
Version: highestVersion,
191+
LatestVersion: latestVersion,
185192
}
186193
}
187194

internal/plugins/admin/database_service.go

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -229,23 +229,15 @@ func (e *databaseExplorer) GetMigrationStatus(ctx context.Context) ([]PluginMigr
229229
Healthy: true,
230230
}
231231

232-
// Get health from registry.
232+
// Get health and version info from registry (populated at startup
233+
// when migration files are scanned — avoids re-reading disk at runtime).
233234
if h := e.pluginHealth.Get(p.Slug); h != nil {
234235
status.Healthy = h.Healthy
235236
status.CurrentVersion = h.Version
237+
status.LatestVersion = h.LatestVersion
236238
status.Error = h.Error
237239
}
238-
239-
// Get latest available version from migration files.
240-
latest, err := database.LatestMigrationVersion(p.MigrationsDir)
241-
if err != nil {
242-
slog.Warn("failed to read migration files",
243-
slog.String("plugin", p.Slug),
244-
slog.Any("error", err),
245-
)
246-
}
247-
status.LatestVersion = latest
248-
status.Pending = latest - status.CurrentVersion
240+
status.Pending = status.LatestVersion - status.CurrentVersion
249241
if status.Pending < 0 {
250242
status.Pending = 0
251243
}
@@ -298,7 +290,7 @@ func (e *databaseExplorer) ApplyPendingMigrations(ctx context.Context) ([]databa
298290

299291
// Update the health registry with new results.
300292
for _, r := range results {
301-
e.pluginHealth.Register(r.Slug, r.Healthy, r.Error, r.Version)
293+
e.pluginHealth.Register(r.Slug, r.Healthy, r.Error, r.Version, r.LatestVersion)
302294
}
303295

304296
return results, nil

0 commit comments

Comments
 (0)