Skip to content

Commit 048f163

Browse files
wesmclaude
andauthored
Rename sync-incremental to sync, fix sync elapsed time, TUI and build polish (#2)
## Summary - Rename `sync-incremental` command to `sync` for brevity (`sync-incremental` kept as hidden alias) - Fix sync elapsed time, TUI cache rebuild, and release build polish ## Test plan - [x] `msgvault sync you@gmail.com` works - [x] `msgvault sync-incremental you@gmail.com` still works (alias) - [x] `msgvault --help` shows `sync` not `sync-incremental` 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent f7c7a7c commit 048f163

File tree

12 files changed

+109
-28
lines changed

12 files changed

+109
-28
lines changed

.github/workflows/ci.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
8+
jobs:
9+
test:
10+
runs-on: macos-15
11+
steps:
12+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
13+
14+
- uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
15+
with:
16+
go-version-file: go.mod
17+
18+
- name: Install golangci-lint
19+
run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.64.8
20+
21+
- name: Test
22+
run: make test
23+
24+
- name: Lint
25+
run: make lint

.github/workflows/release.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ jobs:
5353
VERSION=${GITHUB_REF#refs/tags/v}
5454
5555
mkdir -p dist
56-
LDFLAGS="-s -w -X github.com/wesm/msgvault/cmd/msgvault/cmd.Version=v${VERSION} -X github.com/wesm/msgvault/cmd/msgvault/cmd.Commit=$(echo $GITHUB_SHA | cut -c1-8) -X github.com/wesm/msgvault/cmd/msgvault/cmd.BuildDate=$(date -u +%Y-%m-%dT%H:%M:%SZ) -extldflags '-lstdc++ -lm'"
56+
LDFLAGS="-s -w -X github.com/wesm/msgvault/cmd/msgvault/cmd.Version=v${VERSION} -X github.com/wesm/msgvault/cmd/msgvault/cmd.Commit=$(printf '%s' "$GITHUB_SHA" | cut -c1-8) -X github.com/wesm/msgvault/cmd/msgvault/cmd.BuildDate=$(date -u +%Y-%m-%dT%H:%M:%SZ) -extldflags '-lstdc++ -lm'"
5757
go build -tags fts5 -trimpath -buildvcs=false -ldflags="$LDFLAGS" -o dist/msgvault ./cmd/msgvault
5858
5959
echo "--- Binary info ---"
@@ -106,7 +106,7 @@ jobs:
106106
VERSION=${GITHUB_REF#refs/tags/v}
107107
108108
mkdir -p dist
109-
LDFLAGS="-s -w -X github.com/wesm/msgvault/cmd/msgvault/cmd.Version=v${VERSION} -X github.com/wesm/msgvault/cmd/msgvault/cmd.Commit=$(echo $GITHUB_SHA | cut -c1-8) -X github.com/wesm/msgvault/cmd/msgvault/cmd.BuildDate=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
109+
LDFLAGS="-s -w -X github.com/wesm/msgvault/cmd/msgvault/cmd.Version=v${VERSION} -X github.com/wesm/msgvault/cmd/msgvault/cmd.Commit=$(printf '%s' "$GITHUB_SHA" | cut -c1-8) -X github.com/wesm/msgvault/cmd/msgvault/cmd.BuildDate=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
110110
go build -tags fts5 -trimpath -ldflags="$LDFLAGS" -o dist/msgvault ./cmd/msgvault
111111
112112
echo "--- Binary info ---"
@@ -162,7 +162,7 @@ jobs:
162162
VERSION="${GITHUB_REF#refs/tags/v}"
163163
164164
mkdir -p dist
165-
LDFLAGS="-s -w -X github.com/wesm/msgvault/cmd/msgvault/cmd.Version=v${VERSION} -X github.com/wesm/msgvault/cmd/msgvault/cmd.Commit=$(echo $GITHUB_SHA | cut -c1-8) -X github.com/wesm/msgvault/cmd/msgvault/cmd.BuildDate=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
165+
LDFLAGS="-s -w -X github.com/wesm/msgvault/cmd/msgvault/cmd.Version=v${VERSION} -X github.com/wesm/msgvault/cmd/msgvault/cmd.Commit=$(printf '%s' "$GITHUB_SHA" | cut -c1-8) -X github.com/wesm/msgvault/cmd/msgvault/cmd.BuildDate=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
166166
go build -tags fts5 -trimpath -ldflags="$LDFLAGS" -o dist/msgvault.exe ./cmd/msgvault
167167
168168
# Smoke test

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ See the **[Setup Guide](https://msgvault.io/guides/oauth-setup/)** for step-by-s
6363
| `init-db` | Create the database |
6464
| `add-account EMAIL` | Authorize a Gmail account (use `--headless` for servers) |
6565
| `sync-full EMAIL` | Full sync (`--limit N`, `--after`/`--before` for date ranges) |
66-
| `sync-incremental EMAIL` | Sync only new/changed messages |
66+
| `sync EMAIL` | Sync only new/changed messages |
6767
| `tui` | Launch the interactive TUI (`--account` to filter) |
6868
| `search QUERY` | Search messages (`--json` for machine output) |
6969
| `mcp` | Start the MCP server for AI assistant integration |
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package cmd
2+
3+
import (
4+
"testing"
5+
"time"
6+
)
7+
8+
func TestCLIProgress_OnLatestDateBeforeOnStart(t *testing.T) {
9+
p := &CLIProgress{}
10+
p.OnLatestDate(time.Date(2024, 1, 15, 0, 0, 0, 0, time.UTC))
11+
12+
if p.startTime.IsZero() {
13+
t.Fatal("startTime should be initialized when OnLatestDate is called before OnStart")
14+
}
15+
if time.Since(p.startTime) > time.Second {
16+
t.Fatalf("startTime should be recent, got %v ago", time.Since(p.startTime))
17+
}
18+
}
19+
20+
func TestCLIProgress_OnProgressBeforeOnStart(t *testing.T) {
21+
p := &CLIProgress{}
22+
p.OnProgress(10, 5, 3)
23+
24+
if p.startTime.IsZero() {
25+
t.Fatal("startTime should be initialized when OnProgress is called before OnStart")
26+
}
27+
if time.Since(p.startTime) > time.Second {
28+
t.Fatalf("startTime should be recent, got %v ago", time.Since(p.startTime))
29+
}
30+
}
31+
32+
func TestCLIProgress_OnStartResetsForReuse(t *testing.T) {
33+
p := &CLIProgress{}
34+
p.OnStart(100)
35+
first := p.startTime
36+
37+
time.Sleep(5 * time.Millisecond)
38+
p.OnStart(200)
39+
40+
if !p.startTime.After(first) {
41+
t.Fatal("OnStart should reset startTime on subsequent calls")
42+
}
43+
}
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ import (
1717
)
1818

1919
var syncIncrementalCmd = &cobra.Command{
20-
Use: "sync-incremental <email>",
21-
Short: "Perform an incremental sync of a Gmail account",
20+
Use: "sync <email>",
21+
Aliases: []string{"sync-incremental"},
22+
Short: "Sync new and changed messages from a Gmail account",
2223
Long: `Perform an incremental synchronization using the Gmail History API.
2324
2425
This is faster than a full sync as it only fetches changes since the last sync.
@@ -27,7 +28,7 @@ Requires a prior full sync to establish the history ID baseline.
2728
If history is too old (Gmail returns 404), falls back to suggesting a full sync.
2829
2930
Examples:
30-
msgvault sync-incremental you@gmail.com`,
31+
msgvault sync you@gmail.com`,
3132
Args: cobra.ExactArgs(1),
3233
RunE: func(cmd *cobra.Command, args []string) error {
3334
email := args[0]

cmd/msgvault/cmd/syncfull.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -192,19 +192,30 @@ type CLIProgress struct {
192192
}
193193

194194
func (p *CLIProgress) OnStart(total int64) {
195-
p.startTime = time.Now()
196-
p.lastPrint = time.Now()
195+
now := time.Now()
196+
p.startTime = now
197+
p.lastPrint = now
197198
// Don't print Gmail's estimate - it's often wildly inaccurate
198199
}
199200

200201
func (p *CLIProgress) OnProgress(processed, added, skipped int64) {
202+
if p.startTime.IsZero() {
203+
now := time.Now()
204+
p.startTime = now
205+
p.lastPrint = now
206+
}
201207
p.processed = processed
202208
p.added = added
203209
p.skipped = skipped
204210
p.printProgress()
205211
}
206212

207213
func (p *CLIProgress) OnLatestDate(date time.Time) {
214+
if p.startTime.IsZero() {
215+
now := time.Now()
216+
p.startTime = now
217+
p.lastPrint = now
218+
}
208219
p.latestDate = date
209220
p.printProgress()
210221
}
@@ -217,7 +228,10 @@ func (p *CLIProgress) printProgress() {
217228
p.lastPrint = time.Now()
218229

219230
elapsed := time.Since(p.startTime)
220-
rate := float64(p.added) / elapsed.Seconds()
231+
rate := 0.0
232+
if elapsed.Seconds() >= 1 {
233+
rate = float64(p.added) / elapsed.Seconds()
234+
}
221235

222236
// Format elapsed time nicely
223237
elapsedStr := formatDuration(elapsed)

cmd/msgvault/cmd/tui.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ Performance:
6565
needsBuild, reason := cacheNeedsBuild(dbPath, analyticsDir)
6666
if needsBuild {
6767
fmt.Printf("Building analytics cache (%s)...\n", reason)
68-
result, err := buildCache(dbPath, analyticsDir, false)
68+
result, err := buildCache(dbPath, analyticsDir, true)
6969
if err != nil {
7070
fmt.Fprintf(os.Stderr, "Warning: Failed to build cache: %v\n", err)
7171
fmt.Fprintf(os.Stderr, "Falling back to SQLite (may be slow for large archives)\n")

cmd/msgvault/cmd/update.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ official release over a dev build.`,
7676
if !yes {
7777
fmt.Print("\nProceed with update? [y/N] ")
7878
var response string
79-
fmt.Scanln(&response)
79+
_, _ = fmt.Scanln(&response)
8080
if strings.ToLower(response) != "y" && strings.ToLower(response) != "yes" {
8181
fmt.Println("Update cancelled")
8282
return nil

internal/mcp/server_test.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -386,9 +386,13 @@ func TestGetAttachment(t *testing.T) {
386386
tmpDir := t.TempDir()
387387
hash := "abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
388388
hashDir := filepath.Join(tmpDir, hash[:2])
389-
os.MkdirAll(hashDir, 0o755)
389+
if err := os.MkdirAll(hashDir, 0o755); err != nil {
390+
t.Fatal(err)
391+
}
390392
content := []byte("hello world PDF content")
391-
os.WriteFile(filepath.Join(hashDir, hash), content, 0o644)
393+
if err := os.WriteFile(filepath.Join(hashDir, hash), content, 0o644); err != nil {
394+
t.Fatal(err)
395+
}
392396

393397
eng := &stubEngine{
394398
attachments: map[int64]*query.AttachmentInfo{
@@ -500,7 +504,9 @@ func TestGetAttachment(t *testing.T) {
500504
t.Run("oversized attachment", func(t *testing.T) {
501505
bigHash := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
502506
bigDir := filepath.Join(tmpDir, bigHash[:2])
503-
os.MkdirAll(bigDir, 0o755)
507+
if err := os.MkdirAll(bigDir, 0o755); err != nil {
508+
t.Fatal(err)
509+
}
504510
bigFile, err := os.Create(filepath.Join(bigDir, bigHash))
505511
if err != nil {
506512
t.Fatal(err)

internal/tui/model_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3405,6 +3405,7 @@ func TestHeaderShowsTitleBar(t *testing.T) {
34053405
{"tagged version", "v0.1.0", true, "[v0.1.0]"},
34063406
{"dev version hidden", "dev", false, ""},
34073407
{"empty version hidden", "", false, ""},
3408+
{"unknown version hidden", "unknown", false, ""},
34083409
{"prerelease version", "v1.0.0-rc1", true, "[v1.0.0-rc1]"},
34093410
}
34103411

0 commit comments

Comments
 (0)