Skip to content

Commit 10a205b

Browse files
authored
Merge pull request #7 from git-calendar/metadata
Tags + read-only
2 parents a287c21 + 84fb6f0 commit 10a205b

20 files changed

Lines changed: 982 additions & 139 deletions

cmd/wasm/main.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func RegisterCallbacks(api *api.Api) {
2727
}),
2828
"cloneCalendar": js.FuncOf(func(this js.Value, args []js.Value) any {
2929
return wrapPromise(func() (any, error) {
30-
return nil, api.CloneCalendar(args[0].String(), args[1].String())
30+
return nil, api.CloneCalendar(args[0].String(), args[1].String(), args[2].Bool())
3131
})
3232
}),
3333
"removeCalendar": js.FuncOf(func(this js.Value, args []js.Value) any {
@@ -52,7 +52,7 @@ func RegisterCallbacks(api *api.Api) {
5252
}),
5353
"updateRemote": js.FuncOf(func(this js.Value, args []js.Value) any {
5454
return wrapPromise(func() (any, error) {
55-
return nil, api.UpdateRemote(args[0].String(), args[1].String())
55+
return nil, api.UpdateRemote(args[0].String(), args[1].String(), args[2].Bool())
5656
})
5757
}),
5858
"createEvent": js.FuncOf(func(this js.Value, args []js.Value) any {
@@ -90,6 +90,21 @@ func RegisterCallbacks(api *api.Api) {
9090
return api.GetEvents(args[0].String(), args[1].String())
9191
})
9292
}),
93+
"createTag": js.FuncOf(func(this js.Value, args []js.Value) any {
94+
return wrapPromise(func() (any, error) {
95+
return api.CreateTag(args[0].String(), args[1].String())
96+
})
97+
}),
98+
"updateTag": js.FuncOf(func(this js.Value, args []js.Value) any {
99+
return wrapPromise(func() (any, error) {
100+
return api.UpdateTag(args[0].String(), args[1].String())
101+
})
102+
}),
103+
"removeTag": js.FuncOf(func(this js.Value, args []js.Value) any {
104+
return wrapPromise(func() (any, error) {
105+
return nil, api.RemoveTag(args[0].String(), args[1].String())
106+
})
107+
}),
93108
"setCorsProxy": js.FuncOf(func(this js.Value, args []js.Value) any {
94109
return wrapPromise(func() (any, error) {
95110
return nil, api.SetCorsProxy(args[0].String())

e2e/calendars_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import (
1111
"github.com/git-calendar/core/pkg/filesystem"
1212
)
1313

14+
const TestCalendarName = "test"
15+
1416
func TestCreateCalendar(t *testing.T) {
1517
c := core.NewCore()
1618

@@ -98,7 +100,7 @@ func TestListCalendars_WithRemote(t *testing.T) {
98100

99101
remoteUrl := "https://github.com/git-calendar/calendar.git"
100102

101-
err = c.UpdateRemote(TestCalendarName, mustParseUrl(remoteUrl))
103+
err = c.UpdateRemote(TestCalendarName, mustParseUrl(remoteUrl), false)
102104
if err != nil {
103105
t.Fatalf("failed to update remotes: %v", err)
104106
}

e2e/events_repeating_test.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ import (
99
"github.com/google/uuid"
1010
)
1111

12-
const TestCalendarName = "test"
13-
1412
func TestRepeatingEvent_GetEvents_UntilWeekly_GeneratesOccurrencesInRange(t *testing.T) {
1513
c := newTestCore(t)
1614

@@ -150,7 +148,7 @@ func TestRepeatingEvent_Update_Current_DetachesOnlyTargetChild(t *testing.T) {
150148
if detached.Repeat != nil {
151149
t.Fatalf("detached event should not repeat")
152150
}
153-
if detached.ParentId != uuid.Nil {
151+
if detached.ParentId != nil {
154152
t.Fatalf("detached event should not have parent id, got %s", detached.ParentId)
155153
}
156154
if detached.Title != updated.Title {
@@ -226,7 +224,7 @@ func TestRepeatingEvent_Update_Following_SplitsSeriesFromTargetChild(t *testing.
226224
t.Fatalf("failed to update child event with Following strategy: %v", err)
227225
}
228226

229-
if newParent.ParentId != uuid.Nil {
227+
if newParent.ParentId != nil {
230228
t.Fatalf("new event should be a parent, got ParentId %s", newParent.ParentId)
231229
}
232230
if newParent.Title != updated.Title {
@@ -282,7 +280,7 @@ func TestRepeatingEvent_Update_Following_SecondChild_DoesNotLeaveInvalidOldParen
282280
if err != nil {
283281
t.Fatalf("failed to update second child with Following strategy: %v", err)
284282
}
285-
if newParent.ParentId != uuid.Nil {
283+
if newParent.ParentId != nil {
286284
t.Fatalf("new event should be a parent, got ParentId %s", newParent.ParentId)
287285
}
288286

e2e/git_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ func TestUpdateRemote_ReplacesExistingRemote(t *testing.T) {
2121
oldCalRemote := "https://github.com/git-calendar/old-calendar.git"
2222
newCalRemote := "https://github.com/git-calendar/new-calendar.git"
2323

24-
err = c.UpdateRemote(TestCalendarName, mustParseUrl(oldCalRemote))
24+
err = c.UpdateRemote(TestCalendarName, mustParseUrl(oldCalRemote), false)
2525
if err != nil {
2626
t.Fatalf("failed to set initial remotes: %v", err)
2727
}
2828

29-
err = c.UpdateRemote(TestCalendarName, mustParseUrl(newCalRemote))
29+
err = c.UpdateRemote(TestCalendarName, mustParseUrl(newCalRemote), false)
3030
if err != nil {
3131
t.Fatalf("failed to replace remotes: %v", err)
3232
}
@@ -69,12 +69,12 @@ func TestUpdateRemote_DeletesWhenEmpty(t *testing.T) {
6969
_ = c.RemoveCalendar(TestCalendarName)
7070
})
7171

72-
err = c.UpdateRemote(TestCalendarName, mustParseUrl("https://github.com/git-calendar/calendar.git"))
72+
err = c.UpdateRemote(TestCalendarName, mustParseUrl("https://github.com/git-calendar/calendar.git"), false)
7373
if err != nil {
7474
t.Fatalf("failed to set remotes: %v", err)
7575
}
7676

77-
err = c.UpdateRemote(TestCalendarName, nil)
77+
err = c.UpdateRemote(TestCalendarName, nil, false)
7878
if err != nil {
7979
t.Fatalf("failed to clear remotes: %v", err)
8080
}
@@ -113,7 +113,7 @@ func TestUpdateRemote_MissingCalendar(t *testing.T) {
113113
t.Fatal(err)
114114
}
115115

116-
err = c.UpdateRemote(TestCalendarName, mustParseUrl("https://github.com/git-calendar/calendar.git"))
116+
err = c.UpdateRemote(TestCalendarName, mustParseUrl("https://github.com/git-calendar/calendar.git"), false)
117117
if err == nil {
118118
t.Fatal("expected error, got nil")
119119
}

e2e/tags_test.go

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
package e2e
2+
3+
import (
4+
"testing"
5+
6+
"github.com/git-calendar/core/pkg/core"
7+
"github.com/google/uuid"
8+
)
9+
10+
const TestTagName = "test"
11+
12+
func TestTag_CreateTag_CreatesTag(t *testing.T) {
13+
c := newTestCore(t)
14+
15+
tag := newTestTag("work", "blue")
16+
17+
created, err := c.CreateTag(TestTagName, tag)
18+
if err != nil {
19+
t.Fatalf("CreateTag failed: %v", err)
20+
}
21+
if created == nil {
22+
t.Fatalf("expected created tag")
23+
}
24+
25+
assertTagEqual(t, tag, *created)
26+
}
27+
28+
func TestTag_CreateTag_DuplicateReturnsError(t *testing.T) {
29+
c := newTestCore(t)
30+
31+
tag := newTestTag("work", "blue")
32+
33+
if _, err := c.CreateTag(TestTagName, tag); err != nil {
34+
t.Fatalf("CreateTag failed: %v", err)
35+
}
36+
37+
created, err := c.CreateTag(TestTagName, tag)
38+
if err == nil {
39+
t.Fatalf("expected duplicate tag error")
40+
}
41+
if created != nil {
42+
t.Fatalf("expected nil created tag, got %+v", created)
43+
}
44+
}
45+
46+
func TestTag_CreateTag_InvalidTagReturnsError(t *testing.T) {
47+
c := newTestCore(t)
48+
49+
tag := core.Tag{
50+
Name: "",
51+
Color: "blue",
52+
}
53+
54+
created, err := c.CreateTag(TestTagName, tag)
55+
if err == nil {
56+
t.Fatalf("expected invalid tag error")
57+
}
58+
if created != nil {
59+
t.Fatalf("expected nil created tag, got %+v", created)
60+
}
61+
}
62+
63+
func TestTag_UpdateTag_UpdatesExistingTag(t *testing.T) {
64+
c := newTestCore(t)
65+
66+
tag := newTestTag("work", "blue")
67+
68+
if _, err := c.CreateTag(TestTagName, tag); err != nil {
69+
t.Fatalf("CreateTag failed: %v", err)
70+
}
71+
72+
updated := core.Tag{
73+
Id: tag.Id,
74+
Name: "personal",
75+
Color: "blue",
76+
}
77+
78+
got, err := c.UpdateTag(TestTagName, updated)
79+
if err != nil {
80+
t.Fatalf("UpdateTag failed: %v", err)
81+
}
82+
if got == nil {
83+
t.Fatalf("expected updated tag")
84+
}
85+
86+
assertTagEqual(t, updated, *got)
87+
}
88+
89+
func TestTag_UpdateTag_InvalidTagReturnsError(t *testing.T) {
90+
c := newTestCore(t)
91+
92+
tag := core.Tag{
93+
Name: "work",
94+
Color: "red",
95+
}
96+
97+
updated, err := c.UpdateTag(TestTagName, tag)
98+
if err == nil {
99+
t.Fatalf("expected invalid tag error")
100+
}
101+
if updated != nil {
102+
t.Fatalf("expected nil updated tag, got %+v", updated)
103+
}
104+
}
105+
106+
func TestTag_UpdateTag_MissingTagReturnsErrorInsteadOfPanicking(t *testing.T) {
107+
c := newTestCore(t)
108+
109+
tag := newTestTag("missing", "blue")
110+
111+
defer func() {
112+
if r := recover(); r != nil {
113+
t.Fatalf("expected error for missing tag, got panic: %v", r)
114+
}
115+
}()
116+
117+
updated, err := c.UpdateTag(TestTagName, tag)
118+
if err == nil {
119+
t.Fatalf("expected missing tag error")
120+
}
121+
if updated != nil {
122+
t.Fatalf("expected nil updated tag, got %+v", updated)
123+
}
124+
}
125+
126+
func TestTag_RemoveTag_RemovesTag(t *testing.T) {
127+
c := newTestCore(t)
128+
129+
tag := newTestTag("work", "blue")
130+
131+
if _, err := c.CreateTag(TestTagName, tag); err != nil {
132+
t.Fatalf("CreateTag failed: %v", err)
133+
}
134+
135+
if err := c.RemoveTag(TestTagName, tag.Id); err != nil {
136+
t.Fatalf("RemoveTag failed: %v", err)
137+
}
138+
139+
// creating the same id again proves it was removed from the in-memory tag list
140+
recreated := core.Tag{
141+
Id: tag.Id,
142+
Name: "recreated",
143+
Color: "blue",
144+
}
145+
146+
got, err := c.CreateTag(TestTagName, recreated)
147+
if err != nil {
148+
t.Fatalf("CreateTag after RemoveTag failed: %v", err)
149+
}
150+
if got == nil {
151+
t.Fatalf("expected recreated tag")
152+
}
153+
154+
assertTagEqual(t, recreated, *got)
155+
}
156+
157+
func TestTag_RemoveTag_InvalidIdReturnsError(t *testing.T) {
158+
c := newTestCore(t)
159+
160+
err := c.RemoveTag(TestTagName, uuid.Nil)
161+
if err == nil {
162+
t.Fatalf("expected invalid tag id error")
163+
}
164+
}
165+
166+
func TestTag_InvalidCalendarReturnsError(t *testing.T) {
167+
c := newTestCore(t)
168+
169+
tag := newTestTag("work", "green")
170+
171+
if _, err := c.CreateTag("missing", tag); err == nil {
172+
t.Fatalf("expected CreateTag invalid calendar error")
173+
}
174+
175+
if _, err := c.UpdateTag("missing", tag); err == nil {
176+
t.Fatalf("expected UpdateTag invalid calendar error")
177+
}
178+
179+
if err := c.RemoveTag("missing", tag.Id); err == nil {
180+
t.Fatalf("expected RemoveTag invalid calendar error")
181+
}
182+
}
183+
184+
func newTestTag(name string, color string) core.Tag {
185+
return core.Tag{
186+
Id: uuid.New(),
187+
Name: name,
188+
Color: color,
189+
}
190+
}
191+
192+
func assertTagEqual(t *testing.T, want core.Tag, got core.Tag) {
193+
t.Helper()
194+
195+
if got.Id != want.Id {
196+
t.Fatalf("tag id mismatch: expected %s, got %s", want.Id, got.Id)
197+
}
198+
if got.Name != want.Name {
199+
t.Fatalf("tag name mismatch: expected %q, got %q", want.Name, got.Name)
200+
}
201+
if got.Color != want.Color {
202+
t.Fatalf("tag color mismatch: expected %q, got %q", want.Color, got.Color)
203+
}
204+
}

notes.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
- [x] connect repeating event exceptions
1717
- exception needs to have uuid
1818
- time encoded inside uuidv8
19-
- [ ] config file per repo
19+
- [ ] config file per repo?
2020
- tags
2121
- [ ] better tests
2222
- [x] load repositories
@@ -29,7 +29,7 @@
2929
- github-pages?
3030
- custom http file server?
3131
- [x] encryption
32-
- [x] storing a key (in opfs?)
32+
- [x] storing a key
3333
- values-only
3434
- deterministic? (same input <=> same output)
3535
- +good git diffs
@@ -44,25 +44,30 @@
4444

4545
```
4646
.git-calendar-data/
47-
├── main/
47+
├── default/
4848
│ ├── .git/
4949
│ ├── events/
5050
│ │ └── <UUID>.json
51+
│ ├── tags/
52+
│ │ └── <UUID>.json
5153
│ ├── index.jsonl
5254
│ └── index-rich.jsonl
5355
├── shared/
5456
│ ├── .git/
5557
│ ├── events/
5658
│ │ └── <UUID>.json
59+
│ ├── tags/
60+
│ │ └── <UUID>.json
5761
│ ├── index.jsonl
5862
│ └── index-rich.jsonl
59-
├── main.key
63+
├── default.key
64+
├── shared.readonly
6065
└── shared.key
6166
```
6267

6368

6469
### Testing Web/Wasm parts:
65-
(there are no wasm only test at this time, but could be useful)
70+
(there are no wasm-only tests at this time, but could be useful)
6671

6772
Install [wasmbrowsertest](https://github.com/agnivade/wasmbrowsertest):
6873
```sh

0 commit comments

Comments
 (0)