Commit Graph

16 Commits

Author SHA1 Message Date
mix 1242b22e4f fix: Windows command quoting, atomic JSON/log writes, restore dropped test
Implements items 1-3 of the whole-project review's suggested order
(docs/PROJECT_REVIEW_PLAN.md):

- Restore TestJobListViewIsCompact, accidentally dropped by 5b0e6fe;
  drop the redundant TestDefaultConfigUsesDetailedJobList row from
  TESTS.md and document the two other doc gaps the review found.
- Fix quoteLeadingWindowsProgramPath to find the earliest file-extension
  match at a word boundary instead of the first extension in list order,
  so a .bat/.cmd command whose argument ends in .exe no longer has its
  whole command line mistaken for the program path.
- Write gosentry.json, jobs.json, and run log files atomically (temp
  file + rename) so a crash or power loss mid-write can no longer leave
  a truncated file. Wire Service.Stop() into the app shutdown path so
  it actually runs, cancelling the run context for in-flight runs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-06 16:53:59 +03:00
mix 5b0e6fe51b Wire KeepRunningInTray to runtime so tray, close, and autostart follow the saved setting.
Autostart entries pass --start-in-tray only when the tray is enabled; Settings warns that the notification icon needs a restart (Fyne limitation).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-05 22:44:02 +03:00
mix a735bfd116 docs: retire the test review plan, keep its durable findings
Every item in TEST_REVIEW_PLAN.md is done or decided, so the working
document goes as its own header instructed. What outlives it moves to
where a later reviewer will actually look:

- TESTS.md gains the -coverpkg command and the 84.4% baseline (per-package
  figures understate the suite), design principle 9 (redundancy is judged
  by comparing coverage profiles, and identical coverage alone is not
  grounds for deletion), a table of the look-alike tests that are kept
  with the reason each survives, and the list of functions deliberately
  at 0%.
- STANDARDS.md's "Intentional behavior" section points at both lists, so
  the mechanism REVIEW.md describes still reaches them.

Dropped as spent: the per-item checklists, the suggested order, and the
model-selection table.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 22:53:13 +03:00
mix 28f0a0d8e2 test: resolve the thin-test item, decline the runner merge
Item 4 of the test-suite review:

- Delete TestEmitWithNoObserversIsNoop (no assertion; ranging a nil slice
  cannot panic) and TestStoreReturnsWiredStore (a getter returning its
  own field).
- Collapse the four TestFilteredJobIndexes* tests into one table-driven
  TestFilteredJobIndexes, matching TestFilterValue above it.
- Replace the TestMainViewBuilds smoke test with
  TestMainViewRecordStartupAddsHistoryRow, which calls the recordStartup
  closure for both wordings run.go selects between and asserts the rows
  reach the History table through its own cell callbacks. Keeps the
  unique coverage the review identified and adds the !windowShown branch.

Item 5 is declined with measurements: the three RunJob tests cost 0.14 s
combined, so merging them saves ~90 ms while forcing their three
fixtures (including the only Manual trigger) into one. The runner
package's runtime is the two timeout tests, not subprocess spawns.

go vet and go test -race pass for src/app and src/ui.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 22:46:26 +03:00
mix 2ef18e759c test: delete duplicate-coverage tests, fix TESTS.md drift, drop hand-rolled itoa
Items 1-3 of the 2026-08-04 test-suite review: TestCleanupLogsKeepsFilesWithinAgeLimit,
TestRunDueEmptyOverlapInheritsGlobal, and TestSameWindowsPathHandlesSpaces had
byte-identical coverage to an existing test and no assertion the survivor lacked.
storage.defaultJobs, the one accidental 0% coverage gap the review found, is now
covered and TESTS.md corrected to match. seed_test.go's itoa is replaced with
strconv.FormatInt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-04 22:30:27 +03:00
mix b2402f4c72 Rename the Default theme option to System.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-04 21:49:06 +03:00
mix 276539c383 Make the branded GoSentry theme the default.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-04 19:18:48 +03:00
mixeme f11fee10e9 docs: sync TESTS.md with the suite it describes
The document had drifted well past the point of being useful as an index:
it listed 130 tests against 170 in the tree, described four test files that
were never added to it at all (domain/config_test.go, runner/seed_test.go,
ui/layout_test.go, ui/theme_test.go), attributed runner's Windows
invocation tests to the wrong file, kept two tests that no longer exist
(TestParseRegistryRunValue, TestLinuxAutostartRemovesLegacyDesktopEntry),
and filed three activity-panel tests under jobs_view_test.go when they live
in history_view_test.go.

Most of the gap is the work of the last few releases: the per-job timeout's
three states, the persisted pause and jobs-list density, SeedStats, and the
whole GUI-geometry set the layout review produced.

Three claims were false rather than merely missing. The ui test files are
no longer "pure helpers, no Fyne widget construction" — they build views
under test.NewApp() and measure them, which is now stated as its own design
principle, because that measurement is what makes the STANDARDS rule about
theme-derived sizes enforceable. layout.go is no longer an open coverage
gap. And the coverage-gap list now names the real remaining one: Fyne's
headless driver cannot report a maximized window, which is the reason
window-size persistence is frozen.

Verified mechanically: every test function in the tree appears exactly once
in the document, under the file it actually lives in, and the document
names no test that does not exist.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 17:24:27 +03:00
mixeme 721b049100 feat: select the jobs file itself in Settings
The Jobs directory row named a folder and assumed the file inside it was
called jobs.json. It is now a Jobs file row: Browse opens a file picker
filtered to .json, the field stays editable so a file that does not exist yet
can be typed, and the job list can live under any name.

Config.JobsDir/jobs_dir becomes Config.JobsFile/jobs_file, holding the whole
path; Paths.JobsDir is derived from it so saves still create the folder. An
older gosentry.json is migrated on load by joining its jobs_dir with
jobs.json — the exact file that version used — and the retired key is dropped
when the config is rewritten. The default clears before unmarshalling, or a
file that omits jobs_file and a file that sets it would be indistinguishable
and the migration would never run.

Saving used to write the current job list over whatever was at the new path,
which made switching to an existing jobs file impossible: its contents were
destroyed. An existing file now wins. Its jobs are loaded, normalized, and
adopted, with runtimes, schedule cache, next-run times and log-seeded
statistics rebuilt around them by adoptJobsLocked — the same helper NewService
now uses, so construction and adoption cannot drift. A path with no file
behind it still receives the current jobs, which is how the file is renamed or
relocated. The new file is read before anything is written, so an unparsable
one leaves both the config and the jobs untouched.

Adoption drops every runtime, and a run finishing afterwards would write its
result onto whichever job inherited its ID, so the switch is refused while a
job is running. Unrelated settings still save during a run. Because the
replacement happens without a prompt, the Service emits JobsLoaded with the
path and count, and History carries the receipt.

A path that names only a folder (trailing separator, a dot, or two dots) is
rejected with a validation error instead of failing later with an opaque OS
error.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 23:43:56 +03:00
mixeme 5e09ba1d58 feat: open the logs folder from the Settings tab
Reading a log file meant copying the configured path out of Settings and
pasting it into a file manager. The Logs directory row now carries an Open
button beside Browse that reveals the folder directly.

The new src/platform/filemanager package holds the platform split — explorer
on Windows, xdg-open on Linux, an "unsupported" error elsewhere — and starts
the handler without waiting on it, since Explorer exits non-zero even after it
opens the window and blocking would stall the UI thread. A missing path, a
path that is a file, and a handler that will not start are all reported to the
user; the logs directory does not exist until the first run, so that case is
reachable.

The button opens whatever the field currently holds rather than the saved
config, so an edit can be checked before Save. Resolving a relative directory
against the application folder is the store's rule, so resolveConfiguredDir is
now exported as storage.ResolveConfiguredDir instead of being duplicated in
the UI.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 23:09:33 +03:00
mixeme 9216f01bf6 release: bump version to 0.11.5
Replace interim FUTURE_WORK.md with slim STANDARDS.md and update doc links.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 23:16:24 +03:00
mixeme aed83b91b9 docs: add FUTURE_WORK quality standard and close polish gaps
Replace CODE_REVIEW.md with a living maturity checklist, document
session-only History, inject Service into newMainView for testability,
add UI and scheduler regression tests, and fix RunNow error surfacing
plus empty jobs view handling.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 23:14:09 +03:00
mixeme e9fc9eaba0 fix: harden run persistence and error surfacing from code review
Snapshot store paths under lock before async runs, roll back failed
start/save state, emit UI events only after successful persistence,
surface log write failures, and sync stale YAML docs to JSON.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 21:33:50 +03:00
mixeme 9af279e28f P1.6: update tests and docs for JSON storage + exit-code removal
- storage/store_test.go: switch TestJobsYAMLDoesNotPersistRuntimeNoise to
  json.Marshal (renamed to TestJobsJSONDoesNotPersistRuntimeNoise); add
  TestLoadOrCreateJobsMigratesFromLegacy to cover the jobs YAML import path
- app/operations_test.go: update newTempService paths to .json filenames
- docs/TESTS.md: reflect JSON round-trip, drop SuccessExitCodes tests, remove
  Exit Code Flexibility design-principle entry
- docs/PRE-RELEASE-TASKS.md: mark P1.6 complete

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 21:57:39 +03:00
mix 01fd572a89 Refactoring complete: v0.4.0 architectural milestone (#1)
## Summary

Completed Phase 5 refactoring and reached the target architecture.

**Architectural milestone achieved:**
- Service layer owns all state and is the sole writer
- UI is a thin Fyne view, all widget updates marshaled via `fyne.Do`
- Core engines are stateless and injectable
- Domain types are pure (no `yaml:"-"` fields)
- Full module builds and `go vet ./...` clean

## Changes

- Bump version: 0.3.6 → 0.4.0
- Update CHANGELOG with Phase 5 summary
- Add ROADMAP "Refactoring Follow-Ups" section

## Known follow-up work

1. **Linux test build broken** — `runner_test.go` needs `//go:build windows` tag
2. **File-size limits exceeded** — `operations.go` (486 lines), `jobs_view.go` (415 lines)

See ROADMAP.md for details.

---------

Co-authored-by: mixeme <mix.public@ya.ru>
Reviewed-on: #1
2026-06-22 08:05:10 +03:00
mixeme 0c2c9f1f67 Add comprehensive test suite documentation
Created docs/TESTS.md documenting all 25 tests across 5 test files:
- store_test.go: YAML serialization tests
- scheduler_test.go: Schedule parsing and invocation output tests
- runner_test.go: Command execution, exit codes, and Windows process tests
- autostart_windows_test.go: Windows startup folder shortcut creation tests
- autostart_linux_test.go: Linux XDG Desktop Entry autostart tests

Includes test descriptions, platform requirements, and usage instructions.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-18 00:21:33 +03:00