Skip to content

Commit ecd243b

Browse files
committed
test: Fix lychee setup and links. Fix ox breakages.
1 parent 492fb42 commit ecd243b

7 files changed

Lines changed: 89 additions & 87 deletions

File tree

.github/workflows/linkcheck.yml

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,35 @@
11
name: Link check
22

3-
on: [push, pull_request]
3+
on:
4+
push:
5+
pull_request:
6+
workflow_dispatch:
7+
schedule:
8+
- cron: "03 22 * * *"
49

510
jobs:
611
linkcheck:
712
runs-on: ubuntu-latest
13+
permissions:
14+
issues: write
815
steps:
9-
- uses: actions/checkout@v4
16+
- uses: actions/checkout@v5
1017
- name: Check links with Lychee
18+
id: lychee
1119
uses: lycheeverse/lychee-action@v2
1220
with:
13-
fail: true
21+
fail: false
1422
args: >-
23+
--root-dir "$(pwd)"
1524
--timeout 20
1625
--max-retries 3
17-
'**/*.md'
18-
'**/*.rst'
26+
--cache
27+
--max-cache-age 14d
28+
.
29+
- name: Create Issue From File
30+
if: steps.lychee.outputs.exit_code != 0
31+
uses: peter-evans/create-issue-from-file@v5
32+
with:
33+
title: Link Checker Report
34+
content-filepath: ./lychee/out.md
35+
labels: report, automated issue

.lycheeignore

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ https?://.*\.example\.com/.*
44

55
# Localhost URLs for test servers (not accessible in CI)
66
http://localhost:\d+/.*
7+
http://localhost/.*
78

89
# CalDAV endpoints that require authentication (401/403 expected)
910
https://caldav\.fastmail\.com/.*
@@ -16,5 +17,17 @@ https://webmail\.all-inkl\.com/.*
1617
https://www\.google\.com/calendar/dav/.*
1718
https://caldav-jp\.larksuite\.com/.*
1819

19-
# Apple namespace URL (returns 404 but is a valid XML namespace reference)
20+
# Misc old namespace URLs, few of them works
2021
http://apple\.com/ns/ical/
22+
http://cal.me.com/_namespace/
23+
http://nextcloud.org/ns
24+
http://owncloud.org/ns
25+
26+
27+
# Other junk that was never meant to be followed
28+
# lychee converts unknown schemes to file:// URLs before matching ignore patterns
29+
file://.*/scheme:.*
30+
/17149682/.*
31+
http://x/
32+
https://ecloud\.global/remote\.php/.*
33+
https://tobixen@e\.email/remote\.php/dav

.pre-commit-config.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@ repos:
2424
rev: lychee-v0.22.0
2525
hooks:
2626
- id: lychee
27-
args: ["--no-progress", "--timeout", "10"]
28-
types: [markdown, rst]
29-
stages: [manual] # Run with: pre-commit run lychee --hook-stage manual
27+
args: ["--no-progress", "--timeout", "10", "--exclude-path", ".lycheeignore"]
28+
stages: [pre-push]
29+
exclude: ^tests/test_caldav_unit\.py$

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ Additionally, direct `DAVClient()` instantiation should migrate to `get_davclien
198198

199199
### Changed
200200
* Optimilizations on data conversions in the `CalendarObjectResource` properties (https://github.com/python-caldav/caldav/issues/613 )
201-
* Lazy imports (PEP 562) -- `import caldav` is now significantly faster. Heavy dependencies (lxml, niquests, icalendar) are deferred until first use. https://github.com/python-caldav/caldav/pull/621
201+
* Lazy imports (PEP 562) -- `import caldav` is now significantly faster. Heavy dependencies (lxml, niquests, icalendar) are deferred until first use. https://github.com/python-caldav/caldav/issues/621
202202
* Search refactored to use generator-based Sans-I/O pattern -- `_search_impl` yields `(SearchAction, data)` tuples consumed by sync or async wrappers
203203
* Configuration system expanded: `get_connection_params()` provides unified config discovery with clear priority (explicit params > test server config > env vars > config file)
204204
* `${VAR}` and `${VAR:-default}` environment variable expansion in config values

CONTRIBUTING.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ The `compatibility_hints.py` has been moved from the test directory to the codeb
2525

2626
This is not set in stone. If you feel strongly for using something else, use something else in the commit message and update this file in the same commit.
2727

28-
"Imperative mood" is to be used in commit messages.
28+
"Imperative presens" or "imperative mood" is to be used in commit messages.
2929

3030
The boundaries of breaking changes vs "non-breaking" changes [may be blurry](https://xkcd.com/1172/). In the CHANGELOG I've used the concept "potentially breaking changes" for things that most likely won't break anything for anyone. Potentially breaking changes should be marked with `!` in the commit header. Breaking changes should be marked both with `!` and `BREAKING CHANGE:`
3131

@@ -62,11 +62,9 @@ Consider this procedures to be a more of a guideline than a rigid procedure. Us
6262

6363
* Write up your changes
6464

65-
* Run `pytest` for a quick run of the tests. They should still pass.
65+
* Run `pytest`. The tests should still pass. (Beware: tests may take very long time to run and may consume a lot of memory and disk space if the tests have the permissions to start docker containers).
6666

67-
* Run `tox -e style` to verify a consistent code style (this may modify your code).
68-
69-
* Consider to write some lines in the documentation and/or examples covering your change
67+
* Consider to write some lines in the documentation, changelog and/or examples covering your change
7068

7169
* Add an entry in the `CHANGELOG.md` file.
7270

caldav/compatibility_hints.py

Lines changed: 41 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -855,42 +855,33 @@ def dotted_feature_set_list(self, compact=False):
855855
]
856856
}
857857

858-
xandikos_v0_3 = {
858+
xandikos = {
859+
## We've sometimes been observing internal server errors on freebusy-requests.
860+
## Should do more research on it next time it shows up.
861+
862+
## Component type filtering is required - searches must specify event=True or todo=True
863+
"search.comp-type.optional": "unsupported",
864+
865+
## Principal property search returns 403 (not implemented)
866+
"principal-search": "ungraceful",
867+
868+
## Server-side recurrence expansion is buggy for tasks and event exceptions
869+
"search.recurrences.expanded.todo": "unsupported",
870+
"search.recurrences.expanded.exception": "unsupported",
871+
859872
## this only applies for very simple installations
860873
"auto-connect.url": {"domain": "localhost", "scheme": "http", "basepath": "/"},
861-
'search.comp-type.optional': {'support': 'unsupported'},
862-
## This suddenly disappeared. Should probably look more into the checks ...
863-
#"search.recurrences.includes-implicit.todo.pending": {"support": "unsupported"},
864-
'search.recurrences.expanded.todo': {'support': 'unsupported'},
865-
'search.recurrences.expanded.exception': {'support': 'unsupported'},
866-
'principal-search': {'support': 'ungraceful'},
867-
'freebusy-query.rfc4791': {'support': 'ungraceful', 'behaviour': '500 internal server error'},
874+
868875
"old_flags": [
869876
## https://github.com/jelmer/xandikos/issues/8
870877
'date_todo_search_ignores_duration',
871878
'vtodo_datesearch_nostart_future_tasks_delivered',
872879

873880
## scheduling is not supported
874881
"no_scheduling",
875-
876-
## The test with an rrule and an overridden event passes as
877-
## long as it's with timestamps. With dates, xandikos gets
878-
## into troubles. I've chosen to edit the test to use timestamp
879-
## rather than date, just to have the test exercised ... but we
880-
## should report this upstream
881-
#'broken_expand_on_exceptions',
882-
883882
]
884883
}
885884

886-
xandikos_main = xandikos_v0_3.copy()
887-
## woot ... a regression?
888-
## xandikos did support freebusy-query.rfc4791 for a while, now it trips on a traceback
889-
## TODO: do research into this and report
890-
#xandikos_main.pop('freebusy-query.rfc4791')
891-
892-
xandikos = xandikos_main
893-
894885
## This seems to work as of version 3.5.4 of Radicale.
895886
## There is much development going on at Radicale as of summar 2025,
896887
## so I'm expecting this list to shrink a lot soon.
@@ -928,6 +919,7 @@ def dotted_feature_set_list(self, compact=False):
928919
'search.comp-type.optional': {'support': 'ungraceful'},
929920
'search.recurrences.expanded.todo': {'support': 'unsupported'},
930921
'search.recurrences.expanded.exception': {'support': 'unsupported'}, ## TODO: verify
922+
"search.recurrences.includes-implicit.infinite-scope": False,
931923
'delete-calendar': {
932924
'support': 'fragile',
933925
'behaviour': 'Deleting a recently created calendar fails'},
@@ -979,6 +971,7 @@ def dotted_feature_set_list(self, compact=False):
979971
'sync-token': {'support': 'fragile'},
980972
'search.is-not-defined': {'support': 'unsupported'},
981973
'search.text': {'support': 'unsupported'},
974+
"search.recurrences.includes-implicit.infinite-scope": False,
982975
# sometimes throws a 500
983976
'search.text.category': {'support': 'ungraceful'},
984977
'search.recurrences.expanded.todo': { "support": "unsupported" },
@@ -1011,60 +1004,35 @@ def dotted_feature_set_list(self, compact=False):
10111004
}
10121005

10131006
bedework = {
1014-
'search.comp-type': {'support': 'broken', 'behaviour': 'Server returns everything when searching for events and nothing when searching for todos'},
1015-
'search.comp-type.optional': {'support': 'ungraceful'},
1016-
#'search.time-range.event': {'support': 'unsupported'}, ## TODO: flapping??
1017-
#"search.combined-is-logical-and": { "support": "unsupported" },
1018-
## TODO: play with this and see if it's needed
1007+
## If tests are yielding unexpected results, try to increase this:
10191008
'search-cache': {'behaviour': 'delay', 'delay': 1.5},
1020-
## TODO: play with this and see if it's needed
1021-
'old_flags': [
1022-
'propfind_allprop_failure',
1023-
'duplicates_not_allowed',
1024-
],
1025-
# Ephemeral Docker container: wipe objects (delete-calendar not supported)
1009+
10261010
'test-calendar': {'cleanup-regime': 'wipe-calendar'},
10271011
'auto-connect.url': {'basepath': '/ucaldav/'},
10281012
'save-load.journal': {'support': 'ungraceful'},
10291013
'save-load.todo.recurrences.thisandfuture': {'support': 'ungraceful'},
10301014
'save-load.event.recurrences.exception': False,
1031-
## search.time-range.alarm: not checked by the server tester
10321015
'search.time-range.alarm': {'support': 'unsupported'},
1033-
## Huh? Non-deterministic behaviour of the checking script?
1034-
#"save.duplicate-uid.cross-calendar": {
1035-
# "support": "unsupported",
1036-
# "behaviour": "silently-ignored"
1037-
#},
1038-
"freebusy-query.rfc4791": {
1039-
"support": "full"
1040-
},
1041-
"search.time-range.todo": {
1042-
"support": "unsupported"
1043-
},
1016+
"freebusy-query.rfc4791": True,
1017+
"search.time-range.todo": False,
10441018
"search.text": False, ## sometimes ungraceful
1045-
"search.is-not-defined": {
1046-
"support": "fragile"
1047-
},
1048-
"search.recurrences.includes-implicit": {
1049-
"support": "unsupported",
1050-
"behaviour": "cannot reliably test due to broken comp-type filtering"
1051-
},
1052-
"sync-token": {
1053-
"support": "fragile"
1054-
},
1055-
## Check results are non-deterministic!?
1056-
"search.recurrences.expanded.exception": {
1057-
"support": "unsupported"
1058-
},
1059-
"search.recurrences.expanded.event": {
1060-
"support": "unsupported"
1061-
},
1062-
"search.recurrences.expanded.todo": {
1063-
"support": "unsupported"
1064-
},
1065-
"principal-search": {
1066-
"support": "ungraceful",
1067-
},
1019+
"search.recurrences.includes-implicit": False,
1020+
"sync-token": { "support": "fragile" },
1021+
"search.recurrences.expanded.exception": False,
1022+
"search.recurrences.expanded.event": False,
1023+
"search.recurrences.expanded.todo": False,
1024+
'search.comp-type': {'support': 'broken', 'behaviour': 'Server returns everything when searching for events and nothing when searching for todos'},
1025+
'search.comp-type.optional': {'support': 'ungraceful'},
1026+
'search.is-not-defined.dtend': False,
1027+
"principal-search": { "support": "ungraceful" },
1028+
"search.unlimited-time-range": {"support": "broken"},
1029+
1030+
## TODO: play with this and see if it's needed
1031+
'old_flags': [
1032+
'propfind_allprop_failure',
1033+
'duplicates_not_allowed',
1034+
],
1035+
10681036
}
10691037

10701038
synology = {
@@ -1086,6 +1054,7 @@ def dotted_feature_set_list(self, compact=False):
10861054
'search.recurrences.expanded.todo': {'support': 'unsupported'},
10871055
'search.recurrences.expanded.exception': {'support': 'unsupported'},
10881056
'search.recurrences.includes-implicit.todo': {'support': 'unsupported'},
1057+
"search.recurrences.includes-implicit.infinite-scope": False,
10891058
'save-load.journal.mixed-calendar': {'support': 'unsupported'},
10901059
'principal-search': {'support': 'ungraceful'},
10911060
'principal-search.by-name.self': {'support': 'unsupported'},
@@ -1109,6 +1078,7 @@ def dotted_feature_set_list(self, compact=False):
11091078
cyrus = {
11101079
"search.comp-type.optional": {"support": "ungraceful"},
11111080
"search.recurrences.expanded.exception": {"support": "unsupported"},
1081+
"search.recurrences.includes-implicit.infinite-scope": False,
11121082
"search.time-range.alarm": {"support": "ungraceful"},
11131083
'principal-search': {'support': 'ungraceful'},
11141084
# Cyrus enforces unique UIDs across all calendars for a user
@@ -1322,6 +1292,7 @@ def dotted_feature_set_list(self, compact=False):
13221292
"search.recurrences.expanded.todo": {"support": "unsupported"},
13231293
"search.recurrences.expanded.exception": {"support": "unsupported"},
13241294
"search.recurrences.includes-implicit.todo": {"support": "unsupported"},
1295+
"search.recurrences.includes-implicit.infinite-scope": False,
13251296
"principal-search.by-name.self": {"support": "unsupported"},
13261297
"principal-search": {"support": "ungraceful"},
13271298
"save-load.journal.mixed-calendar": {"support": "unsupported"},

tests/test_caldav.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,10 +1272,13 @@ def testCreateEventFromiCal(self, klass):
12721272
## Calendar.new() is supported from icalendar 7, which is yet to be released as of 2025-09
12731273
pytest.skip("Newer icalendar version required")
12741274

1275+
## Use a near-future date so servers with a "sliding window" (e.g. OX) can find the event
1276+
start = datetime.now() + timedelta(days=30)
1277+
end = start + timedelta(hours=1)
12751278
icalevent = icalendar.Event.new(
12761279
uid="ctuid1",
1277-
start=datetime(2015, 10, 10, 8, 7, 6),
1278-
end=datetime(2015, 10, 10, 9, 7, 6),
1280+
start=start,
1281+
end=end,
12791282
summary="This is a test event",
12801283
)
12811284
icalcal.add_component(icalevent)

0 commit comments

Comments
 (0)