diff --git a/docs/PRE-RELEASE-TASKS.md b/docs/PRE-RELEASE-TASKS.md index 17ccad7..9aff97e 100644 --- a/docs/PRE-RELEASE-TASKS.md +++ b/docs/PRE-RELEASE-TASKS.md @@ -82,7 +82,7 @@ These land together because both edit `domain/job.go` and `storage/store.go`. ### Phase 1 — Storage JSON + exit-code removal - [x] P1.1 — JSON struct tags - [x] P1.2 — `writeJSON` + JSON unmarshal -- [ ] P1.3 — `gosentry.json` / `jobs.json` paths; drop pysentry name +- [x] P1.3 — `gosentry.json` / `jobs.json` paths; drop pysentry name - [ ] P1.4 — One-time YAML import - [ ] P1.5 — Remove `SuccessExitCodes` across code - [ ] P1.6 — Update storage/runner/format tests + TESTS.md diff --git a/src/storage/paths.go b/src/storage/paths.go index 5c482e3..f3049fa 100644 --- a/src/storage/paths.go +++ b/src/storage/paths.go @@ -8,15 +8,16 @@ import ( const ( // The config file stays beside the executable so the portable build behaves // predictably: moving the program folder moves its settings with it. - ConfigFileName = "gosentry.yaml" - // Older builds were named PySentry. Keep the old config name readable during - // the rename window so portable installations can start once and rewrite the - // settings to gosentry.yaml without manual file copying. - LegacyConfigFileName = "pysentry.yaml" - // Jobs are kept in a separate YAML file because the user can choose a + ConfigFileName = "gosentry.json" + // Jobs are kept in a separate JSON file because the user can choose a // different jobs directory, while application settings remain local to the // installed/copied program. - JobsFileName = "jobs.yaml" + JobsFileName = "jobs.json" + + // Legacy YAML file names used by builds before the JSON migration. These are + // read once on first start (P1.4) and then replaced by the JSON equivalents. + legacyYAMLConfigFileName = "gosentry.yaml" + legacyYAMLJobsFileName = "jobs.yaml" ) // Paths contains both the physical program location and the resolved runtime diff --git a/src/storage/store.go b/src/storage/store.go index f8cb64f..08552b4 100644 --- a/src/storage/store.go +++ b/src/storage/store.go @@ -41,9 +41,9 @@ func OpenStore() (*Store, []domain.Job, error) { return nil, nil, err } normalizeJobs(jobs) - // Jobs are also rewritten after normalization. That keeps jobs.yaml compact: + // Jobs are also rewritten after normalization. That keeps jobs.json compact: // only durable job definitions remain, because runtime fields are tagged - // yaml:"-" in the model. + // json:"-" in the model. if err := store.SaveJobs(jobs); err != nil { return nil, nil, err } @@ -80,13 +80,11 @@ func loadOrCreateConfig(paths Paths) (domain.Config, error) { configPath := paths.ConfigPath if _, err := os.Stat(configPath); errors.Is(err, os.ErrNotExist) { - legacyPath := filepath.Join(paths.AppDir, LegacyConfigFileName) + legacyPath := filepath.Join(paths.AppDir, legacyYAMLConfigFileName) if _, legacyErr := os.Stat(legacyPath); legacyErr == nil { - // The rename from PySentry to GoSentry changed the preferred config - // filename. Read the old file once if it is still present so portable - // installs continue to start without a manual migration step. The - // caller later saves the loaded config back through SaveConfig, which - // naturally rewrites it under gosentry.yaml. + // gosentry.yaml is the pre-JSON-migration config file. Read it once + // when gosentry.json is absent so existing installs migrate without + // manual intervention. SaveConfig rewrites the result as gosentry.json. configPath = legacyPath } else { return config, writeJSON(paths.ConfigPath, config) diff --git a/src/storage/store_test.go b/src/storage/store_test.go index 9d14f03..02c2fd1 100644 --- a/src/storage/store_test.go +++ b/src/storage/store_test.go @@ -155,15 +155,14 @@ func TestNormalizeJobsFillsDefaults(t *testing.T) { } } -// TestLoadOrCreateConfigMigratesFromLegacy verifies that when gosentry.yaml is -// absent but pysentry.yaml exists the config is read from the legacy file. This -// lets portable installs that still carry a pysentry.yaml start without manual -// migration. +// TestLoadOrCreateConfigMigratesFromLegacy verifies that when gosentry.json is +// absent but gosentry.yaml exists the config is read from the legacy YAML file. +// This lets installs that pre-date the JSON migration start without manual steps. func TestLoadOrCreateConfigMigratesFromLegacy(t *testing.T) { dir := t.TempDir() paths := Paths{ AppDir: dir, - ConfigPath: filepath.Join(dir, ConfigFileName), // gosentry.yaml — not created + ConfigPath: filepath.Join(dir, ConfigFileName), // gosentry.json — not created } legacy := domain.Config{ @@ -173,7 +172,7 @@ func TestLoadOrCreateConfigMigratesFromLegacy(t *testing.T) { MaxLogAgeDays: 13, StartOnLogin: true, } - if err := writeYAML(filepath.Join(dir, LegacyConfigFileName), legacy); err != nil { + if err := writeYAML(filepath.Join(dir, legacyYAMLConfigFileName), legacy); err != nil { t.Fatal(err) } @@ -199,7 +198,7 @@ func TestLoadOrCreateConfigMigratesFromLegacy(t *testing.T) { } // TestLoadOrCreateConfigCreatesDefaultsOnFirstRun verifies that the first run -// (no config files present) writes gosentry.yaml and returns sensible defaults. +// (no config files present) writes gosentry.json and returns sensible defaults. func TestLoadOrCreateConfigCreatesDefaultsOnFirstRun(t *testing.T) { dir := t.TempDir() paths := Paths{ @@ -223,9 +222,9 @@ func TestLoadOrCreateConfigCreatesDefaultsOnFirstRun(t *testing.T) { if got.MaxLogAgeDays != 30 { t.Errorf("default MaxLogAgeDays = %d, want 30", got.MaxLogAgeDays) } - // The function must have written the defaults to gosentry.yaml. + // The function must have written the defaults to gosentry.json. if _, err := os.Stat(paths.ConfigPath); err != nil { - t.Errorf("gosentry.yaml should have been created: %v", err) + t.Errorf("gosentry.json should have been created: %v", err) } }