Compare commits

3 Commits

Author SHA1 Message Date
mix 6a03ea4a20 release: v1.0.3
Bump version, update CHANGELOG, and retake README screenshots
(Jobs, History, Settings) to match the current GUI.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-07 04:14:10 +03:00
mix 4fb9bf6ff3 docs: reconcile the documentation with the code
An audit of every document against the source turned up drift that had
accumulated since the 1.0.2 passes. The screenshot paths README and
DEVELOPMENT still point at are deliberately left alone - the images move
again when they are retaken.

ARCHITECTURE: the jobs_view.go split is six files, not five, since
extracting jobs_view_state.go was never counted; the statistics table
lists TimedRunCount, which the AvgDurationMS formula already referenced;
the store edge of the diagram names methods that exist (LoadJobs and
LoadConfig never did); and startup says that Service.Start is called from
newMainView rather than from Run.

TESTS: three tests had no entry, the latter two being regression tests
for 1.0.2 fixes:

  TestLoadOrCreateConfigPreservesZeroRetentionLimits
  TestWriteJSONReplacesFileAtomically
  TestQuoteLeadingWindowsProgramPathPicksEarliestBoundedExtension

The deliberately-uncovered list now covers everything the profile
actually reports at 0%, so the next redundancy pass does not flag Config,
Paths, SaveJobs, or the isEvent markers as gaps. The coverage section
measures through -coverprofile and says outright that the per-package
percentages -coverpkg prints are not the total - 2.6/8.9/25.5/1.0/61.5
against a real 84.1%.

ROADMAP: the over-the-guideline table was re-measured (service.go is over
it too now, making six), with a note to re-measure rather than trust it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 03:59:48 +03:00
mix 9b7a0565ba Rename 2026-08-07 03:43:32 +03:00
13 changed files with 187 additions and 73 deletions
+5 -2
View File
@@ -14,8 +14,11 @@ creating, grouping, pausing, running, and monitoring scheduled shell commands.
<table>
<tr>
<td align="center"><img src="images/screenshot_jobs.PNG" alt="Jobs tab"><br><em>Jobs tab — job list with details panel and run statistics.</em></td>
<td align="center"><img src="images/screenshot_settings.PNG" alt="Settings tab"><br><em>Settings tab — application, queue, storage, and version info.</em></td>
<td align="center"><img src="docs/screenshots/screenshot_jobs.PNG" alt="Jobs tab"><br><em>Jobs tab — job list with details panel and run statistics.</em></td>
<td align="center"><img src="docs/screenshots/screenshot_history.PNG" alt="History tab"><br><em>History tab — past runs with trigger, state, and log file.</em></td>
</tr>
<tr>
<td align="center" colspan="2"><img src="docs/screenshots/screenshot_settings.PNG" alt="Settings tab"><br><em>Settings tab — application, queue, storage, and version info.</em></td>
</tr>
</table>
+1 -1
View File
@@ -17,7 +17,7 @@ import (
// The hard constraint: Fyne's a.SetIcon and SetSystemTrayIcon each take ONE
// image, which the OS then scales to every size it needs — titlebar (~16px),
// taskbar/dock (~32-48px), and tray. Neither source survives that scaling:
// downscaling the 1254px gosentry-icon-big.png to 16px is muddy, and upscaling
// downscaling the 1254px gosentry-icon-large.png to 16px is muddy, and upscaling
// the 16px icon to 32px is blurry. The fix is to feed each surface a
// size-appropriate source — which differs per platform because each platform
// exposes different icon channels.
+10 -6
View File
@@ -41,7 +41,7 @@ flowchart LR
user -->|"edits jobs, settings, runs commands"| ui
ui -->|"CreateJob, UpdateJob, DeleteJob, RunNow, UpdateSettings, AutostartStatus, …"| svc
svc -->|"SaveJobs, SaveConfig, LoadJobs, LoadConfig"| store
svc -->|"OpenStore, PrepareSaveJobs, PrepareSaveConfig, LoadJobsFile"| store
store -->|"read/write"| config
store -->|"read/write"| jobs
@@ -119,10 +119,13 @@ example window-maximized detection, which would need per-OS native calls).
## Main Flows
1. Startup:
`cmd/gosentry` calls `ui.Run`, which creates an `app.Service`, opens the
store, loads `gosentry.json` and `jobs.json`, subscribes the UI to service
events, builds the main window, and calls `Service.Start` to begin the
scheduler loop. On every launch the service seeds per-job run-time statistics
`cmd/gosentry` calls `ui.Run`, which owns the process lifecycle: it calls
`app.Open()` to open the store, load `gosentry.json` and `jobs.json`, and
build the `app.Service`, then hands that Service to `newMainView`
(`mainwindow.go`), which subscribes the UI to service events and calls
`Service.Start` to begin the scheduler loop before assembling the tabs.
`Run` shows the window and, on quit, calls `Service.Stop`.
On every launch the service seeds per-job run-time statistics
from existing log files so the details panel reflects accumulated history
immediately (see §Statistics below).
@@ -239,6 +242,7 @@ applies to them — and so measure launch latency only.
| `LastDurationMS` | wall-clock time of the most recent run (launch latency for `StartOnly`) |
| `AvgDurationMS` | mean over all runs with a recorded duration, computed as `DurationSumMS / TimedRunCount` on every update rather than folded incrementally, so it never disagrees with the exact sum/count average `runner.aggregateLogStats` computes when seeding from logs |
| `MaxDurationMS` | longest recorded run |
| `TimedRunCount` | runs that carried a duration, and so contributed to the aggregates above; a legacy log without a `duration` header counts toward `RunCount` but not this |
| `DurationSumMS` | running total of every timed run's duration; the source `AvgDurationMS` is divided from |
`runner.RunJob` measures the wall-clock start→finish and sets `DurationMS` on
@@ -271,7 +275,7 @@ the moment the window opens.
### `jobs_view.go` file structure
The size guideline for a file in this project is ~250 lines.
`src/ui/jobs_view.go` is split across five files along these seams:
`src/ui/jobs_view.go` is split across six files along these seams:
| File | Contents |
|------|----------|
+122 -39
View File
@@ -2,25 +2,13 @@
All notable GoSentry changes are recorded in this file.
## 1.0.2 - 2026-08-05
## 1.0.3 - 2026-08-07
**KeepRunningInTray is wired to runtime; Windows failure notifications can show
the app icon (experimental).**
**The findings of a whole-project review: durable JSON and log writes, bounded
History and overlap queues, and a Jobs selection that follows the job.**
**Application:**
- **Keep running in the system tray** now controls behaviour: with the tray on
(default), closing the window hides it and autostart uses `--start-in-tray`;
with the tray off, closing quits the app and autostart opens the main window.
- Saving a tray change updates close behaviour and the autostart entry
immediately. The notification-area icon follows the saved value after a
restart; Settings shows a hint when a restart is needed (Fyne cannot add or
remove the icon mid-session).
- A stale autostart shortcut that still passes `--start-in-tray` no longer hides
the window when the tray setting is off — saved config wins over the CLI flag.
- On Windows, failure toasts can show the app icon: after `NewWindow`,
`AppMetadata.Icon` is registered so Fyne picks up artwork without calling
`SetIcon`, which would override the PE multi-size window/taskbar icon.
- Fixed a Windows quoting bug where a job whose **Command** field held a whole
command line (a `.bat`/`.cmd` wrapper followed by an argument that itself
ended in `.exe`) had its entire command line mistaken for the program path,
@@ -51,17 +39,132 @@ the app icon (experimental).**
gets slower the longer the app has been running. Measured on 5000 accumulated
records, one History redraw went from **15.8 ms to 0.9 ms**; at the new cap
the width rescan alone accounted for 1.5 ms of every redraw.
- Two runs of the same job that start within the same second no longer share a
log file name. The later one gets a `-2`, `-3`, … suffix instead of silently
overwriting the earlier one's log — reachable with a fast manual re-run or a
sub-second queue drain.
- A hand-edited `jobs.json` in which two entries carry the same `id` no longer
leaves them sharing one runtime, one parsed schedule, and one statistics
bucket; the duplicate is reassigned a free ID on load, as an absent ID always
was.
- The **average run duration** shown in Statistics is now the exact sum divided
by the timed-run count rather than an incrementally folded integer mean. The
old form truncated on every run and the error compounded over a job's life,
so the live figure drifted away from the one rebuilt from log files after a
restart.
- On Linux, a failure to install the `.desktop` file or icon is now reported in
History instead of being discarded, so the visible symptom — a generic dock
icon — has an explanation.
**Jobs:**
- **The Jobs tab keeps its selection on the job, not on the row.** Selecting a
different jobs file in Settings replaces the whole job list; the details pane
then described whichever job happened to land on the previously selected row —
or went blank if the new list was shorter — while the highlight in the list
stayed where it was. The selection now follows the job itself, and the
highlight and the details pane always describe the same one.
- Switching the **Folder** filter now keeps the current selection when the new
filter still shows that job, instead of always jumping to the folder's first
job.
**Settings:**
- **Max log files and max log age days now accept 0, meaning "keep
everything."** Log cleanup already supported disabling either policy; the
Settings form and the Service validator rejected the value that would have
turned it on. A config that already set either to 0 is no longer silently
rewritten back to the 100/30 defaults on load.
- Opening the tab and saving no longer block the window while the autostart
status is read — on Windows that check shells out to PowerShell, and it now
runs off the UI thread.
- Two spellings of the same absolute **Jobs file** path (mixed separators, a
trailing separator) no longer read as a change of file, so saving no longer
triggers a spurious reload of the file already in use.
**Documentation:**
- Documentation audited against the code. `ARCHITECTURE.md` — the `jobs_view.go`
split is six files, not five (the state extraction was never counted), the
statistics table lists `TimedRunCount`, the store edge of the diagram names
the methods that exist, and startup says where `Service.Start` is actually
called. `TESTS.md` — three tests that had no entry are described
(`TestLoadOrCreateConfigPreservesZeroRetentionLimits`,
`TestWriteJSONReplacesFileAtomically`,
`TestQuoteLeadingWindowsProgramPathPicksEarliestBoundedExtension`), the
deliberately-uncovered list covers everything the profile reports at 0%, and
the coverage figure records how to read the total rather than the per-package
lines. `ROADMAP.md` — the over-the-guideline table was re-measured.
- README's scheduler wording caught up with the 0.11.2 rename of "Pause all" to
**Disable auto**, and its notification description matches what the app sends.
- `STANDARDS.md` records the rules the review settled: no file I/O under
`Service.mu`, the History and pending-run caps, the zero-retention meaning,
that a start-only process outlives GoSentry, the single-instance fallback's
consequence, and the unauthenticated instance-channel port.
- `docs/REVIEW.md` (the whole-project review agenda) and the working plan it
produced are retired now that every item is either landed here or recorded in
`ROADMAP.md`, the way the test review plan was in 1.0.1. `STANDARDS.md` is the
surviving reference.
- The screenshots moved to `docs/screenshots/`.
**Internal:**
- The failure-notification timing diagnostic added in 1.0.2 is now written to
`logs/notify-timing.tsv`. The `.tsv` extension keeps it out of `CleanupLogs`,
which manages only `.log` files, so it is neither deleted by age nor counted
against **Max log files**, and the append now runs off the UI thread.
- `jobs.json` is no longer rewritten twice per run. Starting and finishing a run
touch only `JobRuntime`, which is never persisted, so both saves re-serialised
identical bytes; `SetGlobalPause` did the same alongside its real `SaveConfig`.
Removing them also removes the run-start rollback path and the save failure it
reported, so `RunDue` no longer has a start error to surface at all.
- File I/O no longer happens while `Service.mu` is held — that is the lock the
UI thread takes on every job and runtime read, so a JSON write, the
post-run log cleanup, or the startup log scan used to make a UI refresh wait
on the disk. Saves are now prepared under the lock and written after it is
released, in preparation order, so `jobs.json` still ends up matching the
in-memory list. Seeding statistics from logs also opens each log file once
instead of twice.
- The Jobs tab was split into `jobs_view.go` (construction, refresh, layout),
`jobs_view_state.go` (the job/runtime snapshot, folder filter, and selection),
`jobs_view_list.go`, and `jobs_view_toolbar.go`, joining the existing
`jobs_view_details.go` and `jobs_view_helpers.go`. What used to be one
330-line constructor whose dozen closures shared seven mutable locals is now
widgets reading one named state object — which is what made the selection fix
above a change in one place instead of five.
- `Service.Store()` is replaced by typed `Service.Config()` and `Service.Paths()`
accessors that copy under the lock, so the UI no longer reaches into a shared
`*storage.Store`. The Jobs pause control is now driven by `refreshView`
reading `svc.Config().Paused` on every event, making it a real consumer of
`SchedulerStateChanged`, and the main window's event listener is a type switch.
- Dead code removed: `collectActivity`, the `yaml` tags on `RunRecord`, the
`logArguments`/`LogArguments` alias, the redundant package-level
`SetAutostart`/`AutostartStatus` functions, and the Settings Save handler's
second copy of the Service's validation rules. The
`systemTrayRegistered`/`mainWindowHidden` globals are one `trayState` value
that `Run` owns and threads through.
- `scripts/test.bat` no longer prints mojibake for its checkmarks under a
non-UTF-8 code page.
## 1.0.2 - 2026-08-05
**KeepRunningInTray is wired to runtime; Windows failure notifications can show
the app icon (experimental).**
**Application:**
- **Keep running in the system tray** now controls behaviour: with the tray on
(default), closing the window hides it and autostart uses `--start-in-tray`;
with the tray off, closing quits the app and autostart opens the main window.
- Saving a tray change updates close behaviour and the autostart entry
immediately. The notification-area icon follows the saved value after a
restart; Settings shows a hint when a restart is needed (Fyne cannot add or
remove the icon mid-session).
- A stale autostart shortcut that still passes `--start-in-tray` no longer hides
the window when the tray setting is off — saved config wins over the CLI flag.
- On Windows, failure toasts can show the app icon: after `NewWindow`,
`AppMetadata.Icon` is registered so Fyne picks up artwork without calling
`SetIcon`, which would override the PE multi-size window/taskbar icon.
**Jobs:**
@@ -77,30 +180,10 @@ the app icon (experimental).**
**Internal:**
- App-side failure-notification timing is appended to `logs/notify-timing.tsv`
for diagnosing toast delay (OS latency excluded). The `.tsv` extension keeps
the diagnostic file out of `CleanupLogs`, which manages only `.log` files, so
it is neither deleted by age nor counted against **Max log files**. The append
runs off the UI thread. `scripts/measure-windows-toast.ps1` measures the
PowerShell baseline on Windows.
- `jobs.json` is no longer rewritten twice per run. Starting and finishing a run
touch only `JobRuntime`, which is never persisted, so both saves re-serialised
identical bytes; `SetGlobalPause` did the same alongside its real `SaveConfig`.
Removing them also removes the run-start rollback path and the save failure it
reported, so `RunDue` no longer has a start error to surface at all.
- File I/O no longer happens while `Service.mu` is held — that is the lock the
UI thread takes on every job and runtime read, so a JSON write, the
post-run log cleanup, or the startup log scan used to make a UI refresh wait
on the disk. Saves are now prepared under the lock and written after it is
released, in preparation order, so `jobs.json` still ends up matching the
in-memory list. Seeding statistics from logs also opens each log file once
instead of twice.
- The Jobs tab was split into `jobs_view.go` (construction, refresh, layout),
`jobs_view_state.go` (the job/runtime snapshot, folder filter, and selection),
`jobs_view_list.go`, and `jobs_view_toolbar.go`. What used to be one 330-line
constructor whose dozen closures shared seven mutable locals is now widgets
reading one named state object — which is what made the selection fix above a
change in one place instead of five.
- App-side failure-notification timing is appended to `logs/notify-timing.log`
for diagnosing toast delay (OS latency excluded).
`scripts/measure-windows-toast.ps1` measures the PowerShell baseline on
Windows.
## 1.0.1 - 2026-08-04
+3 -2
View File
@@ -280,8 +280,9 @@ Before tagging:
1. Bump `src/app/version.go`. The tag must match it exactly.
2. Add the version's [CHANGELOG.md](CHANGELOG.md) section.
3. Retake the README screenshots (`images/screenshot_jobs.PNG`,
`images/screenshot_settings.PNG`) if the GUI changed its appearance. This is
3. Retake the README screenshots (`docs/screenshots/screenshot_jobs.PNG`,
`docs/screenshots/screenshot_settings.PNG`,
`docs/screenshots/screenshot_history.PNG`) if the GUI changed its appearance. This is
easy to forget because nothing fails without it: `README.md` is packaged
inside every release archive and is what the forge shows on the project page,
so a stale shot advertises an application that no longer exists. Take them
+16 -13
View File
@@ -143,24 +143,25 @@ Design notes / open questions:
[ARCHITECTURE.md](ARCHITECTURE.md) sets a ~250-line guideline per source file
and records the `jobs_view.go` and `settings_view.go` splits as the worked
examples. `jobs_view.go` was split again in 1.0.2 — into view, state, list, and
examples. `jobs_view.go` was split again in 1.0.3 — into view, state, list, and
toolbar — because the selection defect it carried was a symptom of the size
(one 330-line constructor over seven shared locals). Five non-test files are
over the guideline as of that pass:
(one 330-line constructor over seven shared locals). Six non-test files are
over the guideline:
| File | Lines |
|------|-------|
| `src/app/operations.go` | 529 |
| `src/ui/history_view.go` | 373 |
| `src/storage/store.go` | 365 |
| `src/ui/settings_view.go` | 318 |
| `src/app/run.go` | 274 |
| `src/storage/store.go` | 382 |
| `src/ui/history_view.go` | 355 |
| `src/ui/settings_view.go` | 326 |
| `src/app/run.go` | 275 |
| `src/app/service.go` | 252 |
The remaining five are deliberately deferred rather than done piecemeal: a
The remaining six are deliberately deferred rather than done piecemeal: a
split touches every reader of the file, and doing them in one pass keeps the
seams consistent instead of settling them five different ways. Splitting is
seams consistent instead of settling each one its own way. Splitting is
also the kind of change that reads as pure movement while quietly dropping a
function, so it wants one careful pass, not five hurried ones.
function, so it wants one careful pass, not a hurried one per file.
Seams visible today, as a starting point rather than a decision:
@@ -174,9 +175,11 @@ Seams visible today, as a starting point rather than a decision:
table they size.
- **`store.go`** — path resolution, the config load/normalize path, and the jobs
load/normalize path are three separate concerns in one file.
- **`run.go`**, **`settings_view.go`** — barely over. Worth re-measuring at the
time; if a pass elsewhere has shrunk them, leave them alone rather than
splitting for the sake of the number.
- **`run.go`**, **`settings_view.go`**, **`service.go`** — barely over. Worth
re-measuring at the time; if a pass elsewhere has shrunk them, leave them
alone rather than splitting for the sake of the number. The counts above move
a few lines either way with any edit, so re-measure before acting on them
rather than treating the table as current.
The `jobs_view.go` pass is the worked example for the rest: the constructor was
broken up along the state it shared, not along line count, and the split landed
+29 -9
View File
@@ -66,20 +66,31 @@ exercised from another one's tests — `domain.NewRuntime`, for instance, is
covered by the `app` tests. Measure the engine packages together instead:
```bash
go test -coverpkg=./src/domain,./src/storage,./src/runner,./src/scheduler,./src/app ./src/domain ./src/storage ./src/runner ./src/scheduler ./src/app
go test -coverprofile=cover.out -coverpkg=./src/domain,./src/storage,./src/runner,./src/scheduler,./src/app ./src/domain ./src/storage ./src/runner ./src/scheduler ./src/app
```
In the PowerShell environment DEVELOPMENT.md prescribes on Windows, PowerShell
splits the comma-separated `-coverpkg` list on its own and the command fails
with `directory not found`. Use the stop-parsing token, or quote the whole
flag:
flag — and note that `--%` swallows the rest of the line, so the profile has to
be read by a second command:
```powershell
go test --% -coverpkg=./src/domain,./src/storage,./src/runner,./src/scheduler,./src/app ./src/domain ./src/storage ./src/runner ./src/scheduler ./src/app
go test --% -coverprofile=cover.out -coverpkg=./src/domain,./src/storage,./src/runner,./src/scheduler,./src/app ./src/domain ./src/storage ./src/runner ./src/scheduler ./src/app
```
That figure was 84.4% at the 2026-08-04 review, which is the number to compare
against before concluding that coverage has slipped.
The total is the last line of the profile summary. It is **not** any of the
per-package lines `go test` prints: with `-coverpkg` spanning five packages,
each of those reports only what that one package's tests reached across the
whole set, so all five are far below the real figure.
```powershell
go tool cover -func=cover.out | Select-Object -Last 1
```
That total was 84.4% at the 2026-08-04 review and 84.1% at the 2026-08-07
documentation audit — the number to compare against before concluding that
coverage has slipped.
---
@@ -238,8 +249,8 @@ Tests display-formatting helpers used by the UI.
| `TestStatusText` | Verifies that job status codes map to the correct display strings. |
| `TestEventText` | Verifies trigger-type labels for scheduled, manual, and UI triggers. |
| `TestEventLine` | Verifies the one-line activity rendering of a `RunRecord`, including the log basename and the `Unknown` fallback for a blank trigger. |
| `TestDisplayFolder` | Verifies that an empty folder string shows "No folder". |
| `TestDisplayArguments` | Verifies that an empty arguments string shows "None". |
| `TestDisplayFolder` | Verifies that an empty folder string shows "(No folder)". |
| `TestDisplayArguments` | Verifies that an empty arguments string shows "(none)". |
| `TestDisplayRunMode` | Verifies run-mode labels for normal and start-only modes. |
| `TestDisplayInvocation` | Verifies that the full invocation display string combines command and arguments with spacing. |
| `TestDisplayIndex` | Verifies the list position of a job index in a filtered index slice. |
@@ -265,12 +276,14 @@ Tests JSON round-tripping, default generation, and backward compatibility.
| `TestLoadOrCreateConfigCreatesDefaultsOnFirstRun` | Verifies that a missing config file is created with sane defaults. |
| `TestLoadOrCreateJobsSeedsSampleJobsOnFirstRun` | Verifies that a missing jobs file is created with the sample jobs from `defaultJobs`. |
| `TestLoadOrCreateConfigKeepsZeroTimeoutOnReload` | Verifies that `default_timeout_seconds: 0` survives a reload rather than being normalized away — 0 is a value, not a missing field. |
| `TestLoadOrCreateConfigPreservesZeroRetentionLimits` | Verifies that `max_log_files` / `max_log_age_days` of 0 read back as 0 ("keep everything") instead of being backfilled to the 100 / 30 defaults — a field the file sets is not the missing-field case. |
| `TestLoadOrCreateConfigMigratesJobsDir` | Verifies that a pre-0.15 `jobs_dir` becomes `jobs_file` pointing at the same `jobs.json`, and that the retired key is not written back. |
| `TestLoadOrCreateConfigMigratesLegacyThemeDefault` | Verifies that a config storing the retired `"default"` theme value is normalized to `system` on load. |
| `TestLoadJobsFileReportsMissingWithoutCreating` | Verifies that `LoadJobsFile` reports a missing file as not-found without creating or seeding it, and normalizes the jobs it does load. |
| `TestApplyConfigPathsDerivesJobsDir` | Verifies that the configured jobs file resolves against the program folder and that `Paths.JobsDir` is derived from it. |
| `TestJobTimeoutRoundTripsThreeStates` | Verifies the on-disk encoding that keeps "inherit" and "no timeout" distinguishable: `nil` is omitted entirely, an explicit `0` is written and read back as set. |
| `TestJobsJSONDoesNotPersistRuntimeNoise` | Verifies that `jobs.json` does not persist runtime state (LastRun, NextRun, etc.). Only durable job fields are stored. |
| `TestWriteJSONReplacesFileAtomically` | Pins the durability fix: `writeJSON` replaces the destination through a temp file and a rename rather than truncating it in place, and leaves no temp file behind. |
---
@@ -355,6 +368,7 @@ Tests the Windows shell invocation and hidden-window flags.
| `TestShellCommandHidesWindow` | Verifies that shell commands request hidden-window startup to prevent console flash. |
| `TestShellCommandUsesWindowsSafeQuoting` | Verifies `cmd.exe /S /C` quoting for paths with spaces and special characters. |
| `TestWindowsShellCommandLineQuotesUnquotedProgramPath` | Verifies that unquoted program paths in shell commands are quoted while preserving already-quoted arguments. |
| `TestQuoteLeadingWindowsProgramPathPicksEarliestBoundedExtension` | Regression: the program path ends at the *earliest* extension match sitting at a token boundary — not the first extension in `.exe`/`.cmd`/`.bat`/`.com` list order, and not a substring inside another word — so a `.bat` wrapper followed by an `.exe` argument still quotes only the wrapper. |
---
@@ -674,6 +688,12 @@ A coverage run over the non-UI packages reports these as uncovered. All are
intentional; none is an oversight to be "fixed" with a test.
- The real `Clock` — a fake is injected everywhere it is used.
- `storage.OpenStore`, `storage.ResolvePaths`, `storage.PeekKeepRunningInTray`, `app.Service.Start`, `app.Service.Open` — process entry points, exercised by running the app.
- The autostart and desktop-icon wrappers — OS integration, driven only on a real desktop.
- `storage.OpenStore`, `storage.ResolvePaths`, `storage.PeekKeepRunningInTray`, `app.Service.Start`, `app.Open` — process entry points, exercised by running the app.
- The autostart and desktop-icon wrappers (`app.Service.InstallDesktopIcon`, `AutostartStatus`, `ApplyAutostart`) — OS integration, driven only on a real desktop.
- `app.Service.ShouldNotifyOnFailure` — a getter under the mutex.
- `app.Service.Config` and `app.Service.Paths` — read only from `src/ui`, which
this run excludes, so they are covered by the suite but not by this profile.
The same applies to `storage.Store.SaveJobs`: the engine writes through
`PrepareSaveJobs`, and the one-shot wrapper is what `OpenStore` uses.
- The five `isEvent` marker methods in `app/events.go` — empty bodies that exist
only to close the `Event` interface.
Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

+1 -1
View File
@@ -3,4 +3,4 @@ package app
// Version is the application version shown in the GUI and used by build
// scripts in artifact names. It is a var rather than a const so release builds
// can override it with Go ldflags when CI tags a build.
var Version = "1.0.2"
var Version = "1.0.3"