1044 Commits

Author SHA1 Message Date
Jens
36c76f64c9 fix(shipping): use state-based checkbox sync for REPLACE mode (#962)
## ℹ️ Description
*Provide a concise summary of the changes introduced in this pull
request.*

- Link to the related issue(s): Issue #956
- This fixes a regression where `shipping_options` in REPLACE mode could
invert selected carriers (for example `DHL_5` ending up with Hermes
selected) because the code assumed all carrier checkboxes were
pre-checked after clicking "Weiter". Live DOM verification showed this
assumption is not stable across size groups.

## 📋 Changes Summary

- Reworked `__set_shipping_options()` to use state-based checkbox
synchronization for both REPLACE and MODIFY modes:
  - read each carrier checkbox `checked` state
  - compute target state from configured `shipping_options`
  - toggle only when current state differs from desired state
- Added a focused regression test for issue #956:
-
`test_replace_mode_dom_verified_unchecked_defaults_select_wanted_carrier`
- verifies REPLACE mode correctly selects wanted `DHL_002` and does not
toggle unwanted `HERMES_003` when defaults are unchecked
- Updated an existing shipping mapping test fixture to mock carrier
checkbox lookups under the new state-based behavior.
- No dependency, schema, or configuration changes were introduced.

### ⚙️ Type of Change
Select the type(s) of change(s) included in this pull request:
- [x] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ]  New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)


##  Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.

By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Unified shipping carrier selection to a single state-based
synchronization flow, improving consistency and reliability when
toggling carrier options.

* **Tests**
* Expanded shipping-options tests with richer DOM mocks and a new
regression test to verify correct carrier toggling behavior; removed an
outdated unit test related to special-attribute string coercion.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-08 23:34:11 +02:00
kleinanzeigen-bot-tu[bot]
5391f4d37b chore: Update Python dependencies (#960)
✔ Update types-requests 2.33.0.20260402 -> 2.33.0.20260408 successful
  ✔ Update pytest 9.0.2 -> 9.0.3 successful

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-08 22:53:19 +02:00
Jens
728acd48e6 fix(publish): reload form pages to prevent stale image state on retry (#961)
## ℹ️ Description
This pull request fixes retry behavior when image uploads time out
during publish and the next attempt inherits stale form image state.

- Link to the related issue(s): Issue #958
- Describe the motivation and context for this change.
- Retries should start from a clean publish/edit form state to avoid
appending new uploads onto leftover images from a failed attempt.

## 📋 Changes Summary
- Force `publish_ad` to open publish/edit pages with
`reload_if_already_open = True` for both REPLACE and MODIFY flows.
- Keep the existing thumbnail cleanup logic and polish its comment to
reflect defensive pre-populated-form cleanup.
- Extend the pre-submit timeout retryability test to cover both REPLACE
and MODIFY and assert the forced-reload navigation contract.
- Consolidate duplicate post-submit uncertainty tests into one
parametrized test covering both `TimeoutError` and `ProtocolException`.
- Remove one low-value brittle log-wording assertion from image-upload
marker fallback tests while preserving behavior assertions.
- No new dependencies or configuration changes.

### ⚙️ Type of Change
Select the type(s) of change(s) included in this pull request:
- [x] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ]  New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)


##  Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.

By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Improvements**
* Optimized page navigation behavior during ad creation and updates,
improving handling when target pages are already open in the browser.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-08 22:00:15 +02:00
Jens
727366faef fix(publish): rewrite shipping dialog selectors for redesigned DOM (#956) (#957)
## ℹ️ Description

- Link to the related issue(s): Issue #956
- The shipping dialog on kleinanzeigen.de was completely redesigned,
breaking all DOM selectors used by `__set_shipping_options()`. Radio
buttons lost their stable IDs (`#radio-button-SMALL` etc.) and
checkboxes lost their `data-testid` attributes — both now use
React-generated IDs. The fix targets stable `value` attributes instead,
which are API-level identifiers used by the site's JS.

## 📋 Changes Summary

- Add shared shipping constants (`CARRIER_CODE_BY_OPTION`,
`OPTION_NAME_BY_CARRIER_CODE`, `SIZE_INFO_BY_CARRIER_CODE`,
`CARRIER_CODES_BY_SIZE`) to `ad_model.py` as single source of truth for
both publishing and extraction
- Rewrite `__set_shipping_options()` in `__init__.py` with new
selectors:
  - Size radios: `input[@type="radio" and @value="SMALL|MEDIUM|LARGE"]`
- Carrier checkboxes: `input[@type="checkbox" and @value="HERMES_001"]`
etc.
- Use `attrs.get("checked") is not None` consistently (matches existing
pattern at line 2540)
- Re-raise `TimeoutError` with descriptive translatable message instead
of silently swallowing
- Update `extract.py` to use shared `OPTION_NAME_BY_CARRIER_CODE` (DRY)
- Add German translation for new error message
- Update `docs/AD_CONFIGURATION.md` with shipping options reference
table
- Verified against live site: all 3 size groups (Klein/Mittel/Groß) and
individual shipping pass

### ⚙️ Type of Change
Select the type(s) of change(s) included in this pull request:
- [x] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ]  New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)


##  Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test` — 990 passed, 4 skipped).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint` — 0 errors, 0
warnings).
- [x] I have updated documentation where necessary.

By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Documentation**
* Added a Shipping Options Reference table, clarified size-group rules,
tightened sell_directly requirements, and updated the example ad to use
predefined shipping options.

* **Bug Fixes**
* Enforce that selected shipping options belong to a single package
size.
  * Missing shipping options now raise an explicit error.
* Improved dialog interaction, timeout handling, and reliability when
configuring shipping.

* **Tests**
* Updated dialog tests, added coverage for selection modes and error
cases, and removed obsolete async helper tests.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-07 22:39:22 +02:00
Jens
ccfcf435ef fix(publish,download): support condition_s for categories with combobox instead of dialog (#955)
## ℹ️ Description

- Link to the related issue(s): Issue #952
- In certain categories (e.g. 185/249 Modellbau), the condition field is
rendered as a `<button role="combobox">` with id `modellbau.condition`
instead of a dialog with radio buttons. Publishing failed because
`__set_condition` raised `TimeoutError` for these categories, and the
method was short-circuited with `continue` — skipping the generic
XPath-based handler that already supports combobox controls. Downloading
returned `special_attributes: {}` because `ad_attributes` metadata can
be empty/missing for some ads, with no fallback to scrape the DOM.

## 📋 Changes Summary

- Publishing (`__init__.py`): Catch `TimeoutError` from
`__set_condition` and fall through to the generic special-attribute
handler, which correctly handles `button[role=combobox]` controls (e.g.
`modellbau.condition` in category 185/249).
- Downloading (`extract.py`): Add DOM-based fallback in
`_extract_special_attributes_from_ad_page` that scrapes `#viewad-details
.addetailslist--detail` entries when `ad_attributes` is empty/missing,
using `removesuffix` for robust label extraction.
- i18n (`translations.de.yaml`): German translation for the new
INFO-level fallback log message.
- Tests: Added regression tests for both publishing fallback and
DOM-based download extraction. Cleaned up duplicate and superficial
mock-call-assertion tests (4 items per test-scout-cleanup).
- Verified end-to-end against live site via `verify_dom_assumptions.py`:
`set_result.ok: True`, `all_matched: True`, condition correctly set via
`button#modellbau.condition` combobox.

### ⚙️ Type of Change
- [x] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ]  New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)


##  Checklist
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.

By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Condition handling is more resilient: if the condition dialog times
out, the flow logs the event and falls back to the generic handler
instead of aborting.

* **New Features**
* DOM-based fallback extraction of item attributes when primary
attribute data is missing, with mapping of common condition labels to
internal values.

* **Tests**
* Added tests for DOM fallback extraction and condition-setting fallback
behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-07 14:28:10 +02:00
Jens
054dc5ea9d fix(publish): use elem.select() + CDP Backspace to clear React/Vue inputs (#954)
## ℹ️ Description

- Link to the related issue(s): Issue #945
- When retrying a combobox value (e.g. `brand_s: rene_lezard`), the bot
concatenated the old value with the new search text (e.g. "Sonstigesrene
lezard" instead of "rene lezard"). React/Vue-controlled inputs intercept
and revert programmatic `element.value = ""` changes — even when
`input`/`change` DOM events are dispatched. PR #947's JS-based `apply()`
clearing was still unreliable for these framework-managed inputs.

## 📋 Changes Summary

- New `_clear_input()` method in `WebScrapingMixin`: uses the standard
DOM `elem.select()` method via `apply()` to select all text, then sends
a CDP Backspace keyDown+keyUp pair via `_tab.send`. This goes through
the browser's native editing pipeline, triggering the same `InputEvent`
with `inputType: 'deleteContentBackward'` that React observes — so the
framework's internal state is updated correctly. Cross-platform by
design (no OS-specific modifier keys).
- Updated `web_input()`: replaced broken `clear_input()` with
`_clear_input()`.
- Updated `web_select_combobox()`: replaced JS-based `apply()` clearing
with `_clear_input()`.
- Test scout cleanup: removed low-value implementation-detail tests
(`test_clear_input`, `test_dispatch_arrow_down_and_enter`), merged
duplicate underscore/hyphen tests into a single parametrized test,
replaced CDP call-count assertions in
`test_web_input_success_returns_element` with behavioral checks.

### ⚙️ Type of Change
Select the type(s) of change(s) included in this pull request:
- [x] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ]  New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)


##  Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.

By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.
2026-04-07 10:11:26 +02:00
Jens
8bb14370ba fix(ci): replace deprecated tibdex/github-app-token with actions/create-github-app-token (#951)
## ℹ️ Description
*Provide a concise summary of the changes introduced in this pull
request.*

- Link to the related issue(s): Issue #949
- The `tibdex/github-app-token` action is deprecated and runs on Node.js
20, which produces deprecation warnings and will stop working after
September 2026. Its README redirects to the official replacement
`actions/create-github-app-token`. This PR replaces it.

## 📋 Changes Summary

- Replaced `tibdex/github-app-token@v2.1.0` (Node.js 20, deprecated)
with `actions/create-github-app-token@v3.0.0` (Node.js 24, GitHub
official) in:
  - `.github/workflows/publish-release.yml`
  - `.github/workflows/update-python-deps.yml`
- Mapped input names from snake_case (`app_id`, `private_key`) to
kebab-case (`app-id`, `private-key`) as required by the new action.
- No secret changes needed — both actions use the same
`DEPS_UPDATER_APP_ID` and `DEPS_UPDATER_PRIVATE_KEY` secrets.
- No downstream changes needed — the output `token` is named identically
in both actions.

### ⚙️ Type of Change
Select the type(s) of change(s) included in this pull request:
- [x] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ]  New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)


##  Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.

By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Updated CI/CD workflow automation to utilize newer GitHub Actions
components, improving the reliability of the release and deployment
processes.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-06 16:31:16 +02:00
dependabot[bot]
5997248ce9 ci(deps): bump pdm-project/setup-pdm from 4.4 to 4.5 in the all-actions group (#950)
Bumps the all-actions group with 1 update:
[pdm-project/setup-pdm](https://github.com/pdm-project/setup-pdm).

Updates `pdm-project/setup-pdm` from 4.4 to 4.5
<details>
<summary>Commits</summary>
<ul>
<li><a
href="973541a5fe"><code>973541a</code></a>
target node24 and allow the freethreaded version of Python to be chosen
(<a
href="https://redirect.github.com/pdm-project/setup-pdm/issues/75">#75</a>)</li>
<li>See full diff in <a
href="94a823180e...973541a5fe">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=pdm-project/setup-pdm&package-manager=github_actions&previous-version=4.4&new-version=4.5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-06 16:21:24 +02:00
Jens
06cef5f978 fix(publish): normalize underscores in combobox search and clear with DOM events (#947)
## ℹ️ Description
- Link to the related issue(s): #945, #946
- Regressions from #944: after the typeless-combobox routing fix, two
issues appeared when config values contain underscores (e.g.
`rene_lezard` for brand_s).

## 📋 Changes Summary

- underscore conversion: Config values like `rene_lezard` are now
converted to `rene lezard` before being typed into the combobox. The JS
`normalize()` function in dropdown matching also converts `_` to spaces
so that `<li>` labels are matched correctly. Hyphens are preserved since
they can be legitimate characters in brand names.
- robust input clearing: Replaced `nodriver`'s `clear_input()` (which
only sets `element.value=""` without DOM events) with an `apply()` call
that dispatches `input` + `change` events. This ensures React/Vue
framework state is properly reset, preventing stale values from being
concatenated on retries (e.g. `"Sonstigesrene_lezard"`).
- Updated 5 existing tests to use `apply` mocks instead of `clear_input`
mocks (with `side_effect` to model clearing + verification calls).
- Added 2 new tests verifying underscore-to-space conversion and hyphen
preservation in combobox search values.

### ⚙️ Type of Change
- [x] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ]  New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break user setups, scripts,
or configurations)


##  Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.

By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Improved combobox selection reliability with enhanced text
normalization (underscores converted to spaces; consistent whitespace
and case handling).
* Strengthened dropdown option matching to reduce false negatives and
timeouts.
* **Refactor**
* Streamlined input clearing and verification for more consistent and
robust selection behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-06 15:50:58 +02:00
Jens
d02f58c580 fix(publish): use button-combobox dropdown for WANTED ad shipping selection (#948)
## ℹ️ Description

- Link to the related issue(s): Issue #943
- WANTED ads on kleinanzeigen.de render shipping as a special-attribute
combobox dropdown (`<button role="combobox">`) rather than radio
buttons. The previous code tried to click `#ad-shipping-enabled-no` /
`#ad-shipping-enabled-yes` radio buttons that do not exist in WANTED
mode, causing `TimeoutError` crashes when publishing WANTED ads with
`shipping_type: PICKUP` or `SHIPPING`.

## 📋 Changes Summary

- New `web_select_button_combobox()` method in `web_scraping_mixin.py` —
display-text-based selection from `<button role="combobox">` dropdowns
using standard DOM APIs (no React fiber internals). Intended as the
future replacement for the React-fiber-based `__select_button_combobox`
(see issue #930).
- `_WANTED_SHIPPING_LABELS` constant mapping `SHIPPING` → `"Versand
möglich"` and `PICKUP` → `"Nur Abholung"` for the WANTED shipping
dropdown.
- WANTED shipping dispatch rewritten in `__init__.py` — CSS selector
`[role="combobox"][id$=".versand"]` lookup +
`web_select_button_combobox` call replacing broken radio-button code.
- WANTED guard on `sell_directly` — wraps the entire sell_directly
radio-button block in `if ad_cfg.type != "WANTED"` since those controls
are absent in WANTED mode.
- German translations added for 2 new user-facing strings.
- Test scout cleanup (8 items across 2 rounds):
  - Removed 5 log-wording-only tests asserting `caplog.text` strings
- Merged 2 duplicate combobox error-path tests into 1 parametrized test
  - Removed 1 duplicate timeout test superseded by parametrized coverage
- Added `TestWebSelectButtonCombobox` with 2 direct unit tests (happy
path + error path)
  - Rewrote `TestWantedShippingSelection` with 5 dropdown-based tests

### ⚙️ Type of Change
Select the type(s) of change(s) included in this pull request:
- [x] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ]  New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)


##  Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.

By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.
2026-04-06 14:47:28 +02:00
Jens
0893ca1674 fix(publish): handle typeless combobox brand field with ArrowDown+Enter fallback (#944)
## ℹ️ Description
- Link to the related issue(s): #938
- When publishing ads with special attributes like `brand_s`, the brand
combobox `<input role="combobox">` on kleinanzeigen.de has no `type`
attribute (HTML defaults to `text` but the attribute is absent). The
code checked `elem_type == "text"` which failed since `elem_type` was
`""`, causing the field to fall through to `web_input()` — which types
the value but never confirms the autocomplete suggestion, leaving the
field empty.

## 📋 Changes Summary

- `__special_attribute_candidate_priority()`: Match `elem_type in
{"text", ""}` instead of `elem_type == "text"` so typeless combobox
`<input>` elements get priority rank `(1, 0)`.
- `__set_special_attributes()` routing: Route `elem_role == "combobox"
and elem_type in {"text", ""}` to `web_select_combobox()` instead of
falling through to `web_input()`.
- `web_select_combobox()` rewritten with 3-tier fallback:
1. `aria-controls` → find dropdown by ID, click matching `<li>`
(existing path)
  2. No `aria-controls` → search for `[role="listbox"]` by CSS selector
3. No listbox found → dispatch ArrowDown + Enter key events via CDP to
confirm the autocomplete suggestion
- New `_dispatch_arrow_down_and_enter()` method: Uses CDP
`input_.dispatch_key_event` to send ArrowDown (highlight first
suggestion) and Enter (confirm selection).
- New test `test_special_attributes_typeless_combobox_routed_correctly`:
Verifies a typeless combobox `<input>` is routed to
`web_select_combobox` rather than `web_input`.
- Updated tests for the new fallback behavior (previously expected
`TimeoutError`, now expect ArrowDown+Enter fallback).

### ⚙️ Type of Change
- [x] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ]  New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)


##  Checklist
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.

By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Combobox interactions now gracefully fall back to keyboard selection
(ArrowDown+Enter) or alternate listbox lookup when dropdown linkage is
missing, reducing spurious timeouts.
* Combobox detection/handling also accepts inputs without an explicit
type attribute, ensuring the correct input is targeted and verified
before failing.

* **Tests**
* Unit tests expanded to cover the new fallback flows, verification
behavior, and typeless-combobox routing.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-05 23:43:39 +02:00
Jens
747663839b fix(publish): prioritize interactive special-attribute controls (#942)
## ℹ️ Description

- Fixes #938 — special attributes (Marke, Farbe, Größe) silently failed
to persist when publishing ads in the new DOM for categories like
Herrenbekleidung/Jacken & Mäntel and Hemden.
- The bot used `web_find()` which returns the first DOM match. Each
special attribute now has multiple matching elements — a hidden backing
input plus an interactive combobox control. The bot always picked the
hidden input first, so values didn't stick.

## 📋 Changes Summary

- Replaced `web_find()` with `web_find_all()` + candidate-ranking in
`__set_special_attributes`
- Added `__special_attribute_candidate_priority()` — ranks interactive
controls (priority 0–4) above hidden inputs (priority 9)
- Added `__pick_special_attribute_candidate()` and
`__describe_special_attribute_candidate()` helpers
- Fixed unsafe `attrs.type` / `attrs.get("role")` access patterns
- Updated existing tests to mock `web_find_all`; added 2 new tests for
button-combobox and text-combobox priority over hidden inputs

### ⚙️ Type of Change
- [x] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ]  New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)

##  Checklist
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **Bug Fixes**
* Fixed handling of special characters in XPath expressions when values
contain both single and double quotes.

* **Tests**
* Updated unit tests to verify improved robustness in special attribute
element selection, including better preference handling for visible
combobox elements over hidden inputs.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-04 23:19:40 +02:00
kleinanzeigen-bot-tu[bot]
6f9e2b33d6 chore: ✔ Update click 8.3.1 -> 8.3.2 (#941)
✔ Update click 8.3.1 -> 8.3.2 successful

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-04 23:16:59 +02:00
Jens
8cf40dda30 fix(publish): align post-ad selectors with current DOM (#936)
## ℹ️ Description
*Provide a concise summary of the changes introduced in this pull
request.*

- Link to the related issue(s): #920 
- Describe the motivation and context for this change.
Publishing failed on live ads because the Kleinanzeigen post-ad DOM
changed (dotted special-attribute keys, new condition dialog structure,
and shipping radios). This PR updates selector logic to the current DOM
contract, hardens XPath handling, and adds regression coverage.

## 📋 Changes Summary

- Updated publish selector handling in `KleinanzeigenBot`:
- WANTED shipping now uses `ad-shipping-enabled-yes/no` radios with
quick DOM checks.
- `__set_condition()` now opens the new dialog via `.condition` label
context and selects by radio `value`.
- `__set_special_attributes()` now normalizes keys for current dotted
DOM fields, validates selector tokens, safely escapes XPath literals,
supports compound `@name` cases, and handles missing `id` attributes via
XPath fallback.
- `__set_shipping()` removed legacy `.versand_s` assumptions and now
uses explicit step-scoped timeout errors for dialog handling.
- Added/updated unit tests in `tests/unit/test_init.py` for:
  - condition dialog selection behavior,
  - shipping radio behavior (including already-selected paths),
  - special attribute non-string conversion and compound-name lookup.
- Updated docs in `docs/AD_CONFIGURATION.md` to clarify that
`condition_s` uses API values from downloaded ads.
- Updated German translations for newly introduced/adjusted user-facing
error strings.

Mention any dependencies, configuration changes, or additional
requirements introduced.
- No dependency or config schema changes.

### ⚙️ Type of Change
Select the type(s) of change(s) included in this pull request:
- [x] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ]  New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)


##  Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.

By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Documentation**
* Clarified condition rules: require API condition values, listed common
values, added example mappings and YAML guidance.

* **Bug Fixes**
* More reliable condition selection; strengthened special-attribute
validation and lookup; improved shipping toggle and dialog flows with
clearer localized timeout errors and consistent cost input formatting.

* **Tests**
* Expanded unit tests for condition selection, compound
special-attribute resolution, shipping dialog flows, and wanted-ad
shipping behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-03 19:51:32 +02:00
kleinanzeigen-bot-tu[bot]
e3089d8c71 chore: Update Python dependencies (#937)
✔ Update more-itertools 10.8.0 -> 11.0.1 successful
  ✔ Update ruff 0.15.8 -> 0.15.9 successful

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-03 18:54:34 +02:00
Jens
1abe0ec027 fix(upload): avoid stale marker false positives in image upload completion (#933)
## ℹ️ Description
Fix issue #929 by making image upload completion detection ignore stale
hidden `adImages[*].url` markers from previous form state, so publish
waits only for progress from the current upload attempt.

- Link to the related issue(s): Issue #929
- Describe the motivation and context for this change.
- Hidden marker fallback was counting absolute marker totals and could
complete early when pre-existing markers were present.
- This caused false positives after retries/replace flows where stale
DOM marker inputs survived.

## 📋 Changes Summary
- Capture a hidden-marker baseline before uploading images in
`__upload_images`.
- Compute marker completion using count-delta (`max(0,
current_marker_count - baseline_marker_count)`) and keep
`max(thumbnail_count, effective_marker_count)` as the completion signal.
- Add a short settle sleep after thumbnail removals before baseline
capture to reduce async DOM race risk.
- Expand regression tests in `TestImageUploadProcessedMarkerFallback` to
cover stale markers, baseline timeout fallback, max(thumbnail vs
marker-delta) coexistence, and timeout reporting.
- Apply CodeRabbit nitpicks by making the upload dependency helper a
staticmethod and adding an inline explanatory test comment.
- Mention any dependencies, configuration changes, or additional
requirements introduced.
  - No dependency or configuration changes.

### ⚙️ Type of Change
Select the type(s) of change(s) included in this pull request:
- [x] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ]  New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)


##  Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.

By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Improved image upload verification by tracking newly processed images
and ignoring pre-existing/stale markers; added a short pause after image
removal to ensure async updates settle before subsequent uploads.
* **Tests**
* Added async regression tests and helpers covering baseline capture,
timeout fallback, marker-delta clamping, and verification that multiple
image uploads are awaited.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-03 02:13:28 +02:00
Jens
85a856f177 fix(download): handle redesigned overview pagination safely (#934)
## ℹ️ Description
*Provide a concise summary of the changes introduced in this pull
request.*

- Link to the related issue(s): Issue #917
- Describe the motivation and context for this change.
The redesigned overview page no longer exposes the legacy `.Pagination`
container. As a result, `download --ads=all` could stop after page 1 (25
ads) or repeatedly process the same page, missing remaining ads.

## 📋 Changes Summary

- Updated overview pagination navigation to use the current global
`button[aria-label=\"Nächste\"]` controls instead of the removed
`.Pagination` parent container.
- Added stricter enabled-button filtering (`disabled` and
`aria-disabled`) before clicking next in pagination loops.
- Added a duplicate-page guard during URL extraction: if a page yields
only already-seen refs, pagination stops to avoid reprocessing loops.
- Updated pagination and extraction unit tests to match the live DOM
behavior and new pagination flow.
- Added/updated German translations for new/changed log messages.
- Mention any dependencies, configuration changes, or additional
requirements introduced.
  No new dependencies or configuration changes were introduced.

### ⚙️ Type of Change
Select the type(s) of change(s) included in this pull request:
- [x] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ]  New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)


##  Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.

By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* More reliable next-page detection and handling of disabled "Next"
controls, improving pagination stability.
* Order-preserving deduplication of ad links so duplicate refs on the
same page are ignored.
* Pagination now stops automatically when a page reload yields no new
items, avoiding infinite loops.

* **Tests**
* Updated and added unit tests to cover the new pagination detection and
deduplication behaviors.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-03 02:13:04 +02:00
Jens
cf6edc70f3 fix(download): align INFO download logs with final destinations (#935)
## ℹ️ Description
*Provide a concise summary of the changes introduced in this pull
request.*

- Link to the related issue(s): None (no linked issue)
- Describe the motivation and context for this change.
This change fixes confusing download logs that exposed staging
(`.tmp-*`) paths in user-facing INFO output. It keeps staging details at
DEBUG level, logs the final YAML destination at INFO after the atomic
rename succeeds, and adds per-item download progress logging.

## 📋 Changes Summary

- Downgraded `Saving [%s]...` logging in `utils/dicts.py` from INFO to
DEBUG so staging write paths are no longer shown in normal user output.
- Added `Saved ad config to: %s` INFO log in `extract.download_ad()`
after successful staging-to-final directory rename.
- Added `Downloading %d/%d ads...` progress logs in `download_ads()` for
`--ads=all`, `--ads=new`, and numeric ID selectors.
- Updated `--ads=all` summary denominator to report against valid
download candidates (excluding invalid ad IDs), matching the new
progress reporting semantics.
- Added German translations for the two new log messages.
- Mention any dependencies, configuration changes, or additional
requirements introduced.
  No dependencies or configuration changes were introduced.

### ⚙️ Type of Change
Select the type(s) of change(s) included in this pull request:
- [x] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ]  New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)


##  Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.

By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.
2026-04-03 01:52:41 +02:00
kleinanzeigen-bot-tu[bot]
2a87fc4642 chore: Update Python dependencies (#931)
✔ Update types-requests 2.33.0.20260327 -> 2.33.0.20260402 successful
  ✔ Update charset-normalizer 3.4.6 -> 3.4.7 successful
  ✔ Update basedpyright 1.38.4 -> 1.39.0 successful

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-03 01:45:33 +02:00
Alex Strutsysnkyi
54d3d21343 fix: update HTML element IDs after Kleinanzeigen site redesign (#920) (#924)
## Summary

Fixes #920 — Kleinanzeigen.de renamed all form element IDs site-wide.
This PR updates all selectors to match the new `ad-*` prefix pattern.

### Login form changes
| Old | New |
|-----|-----|
| `login-email` | `username` |
| `login-password` | `password` |
| `form#login-form button[type='submit']` | `button[type='submit']` |

### Ad form changes
| Old | New |
|-----|-----|
| `adType2` | `ad-type-WANTED` |
| `postad-title` | `ad-title` |
| `select#price-type-react` (SELECT element) | `button#ad-price-type` +
`li#ad-price-type-menu-option-{N}` (dropdown) |
| `input#pstad-price` | `input#ad-price-amount` |
| `#pstad-descrptn` | `#ad-description` |
| `pstad-zip` | `ad-zip-code` |
| `#pstad-citychsr` (SELECT with options) | `ad-city` (text input) |
| `pstad-street` | `ad-street` |
| `addressVisibility` | `ad-address-visibility` |
| `postad-contactname` | `ad-name` |
| `postad-phonenumber` | `ad-phone` |
| `phoneNumberVisibility` | `ad-phone-visibility` |
| `pstad-submit` / `fieldset#postad-publish` | `//button[contains(.,
'Anzeige aufgeben')]` |

### Category selection changes
| Old | New |
|-----|-----|
| `pstad-descrptn` (trigger click) | `ad-description` |
| `postad-category-path` | `ad-category-path` |
| `pstad-lnk-chngeCtgry` | XPath by text `//a[contains(., 'Kategorie')]
\| //button[contains(., 'Kategorie')]` |
| `//*[@id='postad-step1-sbmt']/button` | `//button[@type='submit']` |

### Notable behavioral changes
- **Price type**: The price type selector changed from a `<select>`
element to a button-triggered dropdown (`<ul>` with `<li>` options). The
mapping is: `FIXED` → option 0, `NEGOTIABLE` → option 1, `GIVE_AWAY` →
option 2.
- **City**: Changed from a `<select>` dropdown populated after ZIP entry
to a plain text `<input>` (`ad-city`).
- **Submit**: `pstad-submit` no longer exists; the form now has a
`<button>` with text "Anzeige aufgeben" (no `id` attribute).

## Test plan
- [ ] Verify login works with new `username`/`password` field IDs
- [ ] Verify ad title field `ad-title` accepts input
- [ ] Verify price type dropdown opens via `ad-price-type` button and
selects correct option
- [ ] Verify description sets via `#ad-description`
- [ ] Verify ZIP/city fields `ad-zip-code` and `ad-city` work
- [ ] Verify ad submits via `//button[contains(., 'Anzeige aufgeben')]`
- [ ] Verify category selection flow with updated XPath selectors

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Restored ad publishing flow to match the site's revised UI: updated
field handling for title/description, pricing, buy‑now,
submit/confirmation, and more resilient category detection and dialog
handling.
* Improved pricing and submission reliability; timeouts now surface
locally.

* **Chores**
* Updated contact, address, shipping and special-attribute handling to
align with the site's changed controls and React-managed inputs.

* **Tests**
* Adjusted unit tests and mocks to reflect the updated page
interactions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Jens <1742418+1cu@users.noreply.github.com>
2026-04-02 20:58:21 +02:00
Jens
9bbac7903c fix(ci): remove obsolete pip-audit ignore for Pygments CVE (#928) 2026-04-02 07:36:45 +02:00
Jens
bcc63b7f1d fix(pagination): continue when paging.last is absent (#922) 2026-04-02 07:36:15 +02:00
kleinanzeigen-bot-tu[bot]
d79a6cf6b6 chore: Update Python dependencies (#918)
✔ Update requests 2.33.0 -> 2.33.1 successful
  ✔ Update pygments 2.19.2 -> 2.20.0 successful
  ✔ Update pyinstaller-hooks-contrib 2026.3 -> 2026.4 successful
  ✔ Update mypy 1.19.1 -> 1.20.0 successful
  ✔ Update nodejs-wheel-binaries 24.14.0 -> 24.14.1 successful

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-01 16:31:54 +02:00
Jens
2ab167952c fix(download): show final directory path in INFO logs instead of staging path (#916)
## ℹ️ Description

- Link to the related issue(s): Issue N/A
- Improves logging clarity for the `download` command by addressing two
user-facing issues:

1. **Path accuracy**: INFO logs now show the final download directory
instead of the temporary staging directory, eliminating confusion about
where files actually end up.

2. **Message clarity**: Log messages now distinguish between the two
fetch operations — JSON API (metadata) vs HTML scan (navigation URLs) —
so the dual-fetch design is explicit rather than appearing redundant.

## 📋 Changes Summary

- Demoted staging directory path to DEBUG level; added INFO log for
final download path
- Updated fetch-related log messages to indicate purpose (metadata vs
navigation URLs)

### ⚙️ Type of Change
- [x] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ]  New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)

##  Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.

By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* Improved logging and progress messages to separately report staging
and final download paths and to clarify scanning progress when
discovering ad URLs.
* Clarified wording to describe the downloaded API payload as "ad
metadata (status, expiry dates)" and to use "ad URL" when reporting
counts.
* **Localization**
* Updated German pluralization to correctly form "Anzeigen‑URLs" where
applicable.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-01 11:07:38 +02:00
dependabot[bot]
498d0934d2 ci(deps): bump the all-actions group with 2 updates (#919) 2026-03-31 09:43:10 +02:00
Jens
a3b0b4bb5b feat(download): resolve inactive state for all/new selectors (#915)
## ℹ️ Description

This PR implements the feature to set downloaded own ads to
`active=False` when their published state is not "active" for "all" and
"new" selectors. Previously, only numeric ID downloads (`--ads=123,456`)
correctly resolved the activity state - this extends that behavior to
the "all" and "new" selectors.

### Motivation and Context

When downloading ads using `--ads=all` or `--ads=new`, ads that were
paused, inactive, or in other non-active states on Kleinanzeigen were
incorrectly saved with `active: true`. This could cause confusion when
users would later publish these ads - they would be published as active
even though they were originally inactive.

This PR ensures that the downloaded ad configuration accurately reflects
the actual state of the ad on Kleinanzeigen:
- Ads with `state="active"` → saved with `active: true`
- Ads with `state="inactive"`, `state="paused"`, or any other state →
saved with `active: false`

## 📋 Changes Summary

### Core Implementation
- Extended `_resolve_download_ad_activity()` usage from numeric IDs to
"all" and "new" selectors
- Created `ResolvedAdState` NamedTuple to replace `tuple[bool, bool]`
for better type safety and self-documenting code
- Created `_download_ad_with_resolved_state()` helper method to
centralize resolution + logging + download logic for "all" and "new"
selectors
- Updated "all" selector to resolve and pass correct active state
- Updated "new" selector to resolve and pass correct active state
- Updated numeric selector to use NamedTuple access (kept inline due to
different warning semantics)

### Code Quality Improvements
- Fixed variable naming: `add_url` → `ad_url` (3 occurrences in "all"
selector)
- Fixed comment typo: "adds" → "ads"

### ⚙️ Type of Change
Select the type(s) of change(s) included in this pull request:
- [ ] 🐞 Bug fix (non-breaking change which fixes an issue)
- [x]  New feature (adds new functionality without breaking existing
usage)
- [x] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)

##  Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.

By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* More accurate handling of ad active/ownership status (treats missing
or unexpected state as inactive)
* Downloads now skip invalid ad links and gracefully skip when
navigation fails
* Improved warning and debug messages for inaccessible, foreign, or
inactive ads

* **Tests**
* Added comprehensive tests for all ad download modes, state handling,
error cases, and edge scenarios
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-27 23:34:47 +01:00
sebthom
8e73072550 fix(web): make browser shutdown tolerant of disappearing psutil process 2026-03-27 20:18:43 +01:00
klangborste
b9c98f4165 fix: handle buy-now dialog opt-out for PICKUP shipping type (#891) 2026-03-27 15:39:44 +01:00
Jens
f836d93ac6 docs(publish_ad): standardize docstring to Google-style Args format (#912) 2026-03-27 15:39:13 +01:00
kleinanzeigen-bot-tu[bot]
14bdd44111 chore: Update Python dependencies (#914)
✔ Update types-requests 2.32.4.20260324 -> 2.33.0.20260327 successful
  ✔ Update ruff 0.15.7 -> 0.15.8 successful

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-27 13:39:04 +01:00
Jens
f2a6cfdb25 fix(cli): align --ads error messages to mention comma-separated keywords (#913)
## ℹ️ Description

- Link to the related issue(s): Issue #903
- The CLI error messages for invalid `--ads` selectors did not mention
that comma-separated keyword combinations (e.g., `changed,due`) are
valid, even though `_is_valid_ads_selector()` accepts them and README
documents them.

## 📋 Changes Summary

- Updated 3 English error messages in `__init__.py` to mention
comma-separated keyword combinations
- Updated 3 corresponding German translations in `translations.de.yaml`
- Fixed a line-length issue (E501) at line 1989 by wrapping a long
statement
- The `extend` command message is unchanged since only `all` is a valid
keyword there

### ⚙️ Type of Change
- [x] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ]  New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)


##  Checklist
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [ ] I have updated documentation where necessary.

By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.
2026-03-27 09:50:16 +01:00
Jens
6100eb09f7 test(extract): migrate description-affix tests to staging path (#911)
## ℹ️ Description
There is no need to remove any legacy code - that has already been done.
But there are three tests that need an update.

- Link to the related issue(s): Issue #866
- Describe the motivation and context for this change.
The description-affix tests were still calling
`_extract_ad_page_info(...)` directly, while runtime uses the staging
directory flow via `_extract_ad_page_info_with_directory_handling(...)`.
This change aligns tests with the active path and keeps timeout behavior
explicit.

## 📋 Changes Summary

- Rewrote three description-affix tests in `tests/unit/test_extract.py`
to call `_extract_ad_page_info_with_directory_handling(...)` instead of
`_extract_ad_page_info(...)`.
- Added `tmp_path`-backed base directory setup in those tests to
exercise path handling through the staging wrapper.
- Updated `web_text` mock sequencing to account for the additional title
read done by the staging wrapper.
- Made timeout expectation deterministic with
`pytest.raises(TimeoutError)`.
- No runtime production code changes; only test updates.

### ⚙️ Type of Change
Select the type(s) of change(s) included in this pull request:
- [x] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ]  New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)


##  Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.

By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **Tests**
* Updated internal testing infrastructure for content-extraction
validation. No user-facing changes.

---

**Note:** This release contains internal development improvements only.
End-users will not experience any functional changes or new features.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-27 09:50:03 +01:00
Jens
b143b26c24 enh(download): enforce single-use placeholders in naming templates (#909)
## ℹ️ Description
This pull request finalizes PR5 by simplifying download naming template
rules and making truncation behavior deterministic and reviewable.

- Link to the related issue(s): Issue #841
- Describe the motivation and context for this change.
Repeated placeholders and implicit truncation priority made naming
outcomes hard to predict. This change enforces single-use placeholders
and aligns validation, rendering, docs, and tests around explicit
priority rules under tight budgets.

## 📋 Changes Summary
- Enforced template validation rule: each placeholder (`{id}`,
`{title}`) may appear at most once in:
  - `download.folder_name_template`
  - `download.ad_file_name_template`
- Added validation error path and i18n entry for repeated placeholders.
- Refined `_render_download_name_with_budget` behavior to deterministic
priority:
  - `{id}` protected as much as possible
  - literals preserved after `{id}`
  - `{title}` truncated first under budget pressure
- Added truncation warnings and bounded log previews for
template/title/rendered values.
- Improved snippet truncation behavior to keep preview length within
configured caps, including small/zero limit handling.
- Expanded tests in `test_config_model.py` and `test_extract.py` to
cover:
  - repeated placeholder rejection
  - id/title truncation warnings
  - helper edge cases for log snippet truncation
- Updated configuration documentation with:
  - valid/invalid template examples
  - tight-budget examples reflecting current priority behavior
  - explicit note about last-resort `{id}` truncation
- Updated generated artifacts where applicable:
  - `docs/config.default.yaml`
  - `schemas/config.schema.json`
- No new runtime dependencies or new config keys introduced.

### ⚙️ Type of Change
Select the type(s) of change(s) included in this pull request:
- [ ] 🐞 Bug fix (non-breaking change which fixes an issue)
- [x]  New feature (adds new functionality without breaking existing
usage)
- [x] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)


##  Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.

By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.
2026-03-26 21:38:27 +01:00
kleinanzeigen-bot-tu[bot]
e0ed4741ea chore: Update Python dependencies (#910) 2026-03-26 17:07:10 +01:00
Jens
ae9a720bbb fix: save foreign numeric-id downloads as inactive (#906) 2026-03-25 14:26:09 +01:00
Jens
5d1e9f1f80 fix: ignore CVE-2026-4539 in pip-audit until upstream fix (#907) 2026-03-25 12:21:11 +01:00
Jens
c0d8788613 ci: remove scope restrictions and add refactor type to PR validation (#908) 2026-03-25 12:20:39 +01:00
Airwave1981
ba47c4c76b fix: clear existing image thumbnails before upload for all modes (#904)
## Problem

When publishing multiple ads in sequence, stale image thumbnails from a
previous ad (or a failed retry) could remain on the page. The thumbnail
count check then failed with errors like:

\\\
Not all images were uploaded within timeout. Expected 2, found 20
thumbnails.
\\\

This happened because existing thumbnails were only removed in \MODIFY\
mode (editing an existing ad), but not in \REPLACE\ mode (publishing a
new ad). On retries, the page was reloaded but could still retain old
thumbnails, causing them to accumulate.

## Fix

Always clear existing thumbnails before uploading new images, regardless
of the publish mode. The cleanup uses a short \quick_dom\ timeout and is
wrapped in \ ry/except TimeoutError\ so it gracefully handles fresh
forms where no thumbnails exist yet.

## Changes

- Removed the \if mode == AdUpdateStrategy.MODIFY\ guard around the
thumbnail cleanup
- Added \ ry/except TimeoutError\ to handle fresh pages where the
thumbnail list is empty
- Added a log message when thumbnails are being removed

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Thumbnail cleanup now runs for both modification and replacement
workflows, improving image update reliability.
* DOM lookup for existing thumbnails gains a timeout and now treats
timeouts as no thumbnails found to avoid publish failures.
* Added a short pause after each thumbnail removal to let the UI settle.
* Info-level logging reports how many thumbnails were removed prior to
upload.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-24 22:37:17 +01:00
kleinanzeigen-bot-tu[bot]
67b641ea86 chore: ✔ Update types-requests 2.32.4.20260107 -> 2.32.4.20260324 (#905)
✔ Update types-requests 2.32.4.20260107 -> 2.32.4.20260324 successful

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-24 20:35:37 +01:00
Jens
e1bb54ef53 enh: replace login UNKNOWN state with boolean + detection reason (#890)
## ℹ️ Description
This PR implements issue #872 by replacing the tri-state login model
(`LOGGED_IN` / `LOGGED_OUT` / `UNKNOWN`) with an explicit login
detection result object that separates control flow from diagnostics.

- Link to the related issue(s): Issue #872
- Describe the motivation and context for this change.
- `UNKNOWN` previously mixed two concerns: decision logic and
observability. In practice, callers mostly needed a binary decision
(logged in or not), while diagnostics needed the *reason* for
inconclusive detection.
- This change makes login decisions explicit (`is_logged_in`) and keeps
diagnostics/context explicit (`reason`), reducing ambiguity and making
behavior easier to reason about and test.

## 📋 Changes Summary
- Replaced `LoginState` with:
- `LoginDetectionReason` enum (`USER_INFO_MATCH`, `CTA_MATCH`,
`SELECTOR_TIMEOUT`)
- `LoginDetectionResult` frozen dataclass (`is_logged_in`, `reason`)
with invariant checks in `__post_init__`
- Updated `get_login_state()` to return `LoginDetectionResult` while
preserving detection order and runtime behavior:
  1. DOM logged-in selector match -> `USER_INFO_MATCH`
  2. Logged-out CTA selector match -> `CTA_MATCH`
3. Inconclusive fallback -> `SELECTOR_TIMEOUT` (+ optional diagnostics
capture)
- Updated login flow call sites to branch on `result.is_logged_in` and
include reason context in post-login failure handling.
- Updated diagnostics text from UNKNOWN-specific wording to inconclusive
wording.
- Renamed diagnostics artifact prefix from `login_detection_unknown` to
`login_detection_inconclusive` and aligned diagnostics utility docs.
- Migrated and expanded unit tests:
  - switched enum-based assertions/mocks to `LoginDetectionResult`
  - added invariant tests for invalid result combinations
- Updated docs to match current behavior and config keys:
  - removed outdated auth-probe fallback wording
- documented `CTA_MATCH` / `SELECTOR_TIMEOUT` meaning and
troubleshooting guidance
- added migration note from `diagnostics.login_detection_capture` to
`diagnostics.capture_on.login_detection`

Mention any dependencies, configuration changes, or additional
requirements introduced.
- No new runtime dependencies introduced.
- No user-facing config schema changes introduced.

### ⚙️ Type of Change
Select the type(s) of change(s) included in this pull request:
- [ ] 🐞 Bug fix (non-breaking change which fixes an issue)
- [x]  New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)


##  Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.

By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* DOM-first login detection with a logged-out CTA check, explicit
inconclusive outcome (SELECTOR_TIMEOUT), and reason-aware detection
surfaced in logs/errors.

* **Documentation**
* Updated troubleshooting and configuration docs and examples to use
diagnostics.capture_on.login_detection and added migration guidance for
the legacy key.

* **Tests**
* Updated and added tests covering new detection outcomes, reason
validation, and diagnostic capture behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-24 20:30:36 +01:00
Jens
a705e4e316 fix: harden downloaded ad staging and rollback (#900)
## ℹ️ Description
This pull request hardens ad download writes so updates are staged and
only swapped into place after successful extraction and YAML
serialization, with explicit rollback safeguards for failure paths.

- Link to the related issue(s): Issue #893
- Describe the motivation and context for this change.
The original PR #851 split identified download directory replacement as
a data-safety risk when failures occur mid-write. This change makes
replacement safer by staging output first, restoring prior data when
swap fails, and tightening cleanup behavior to avoid using dirty staging
directories.

## 📋 Changes Summary
- Refactored `AdExtractor.download_ad()` to use staged output
directories (`.tmp-*`) and backup swap directories (`.bak-*`) before
finalizing writes.
- Changed YAML write flow to write into staging first, then swap staging
to final only after successful serialization.
- Added `backup_created_by_us` guard so rollback restores only backups
created by the current run.
- Added defensive handling for backup/staging cleanup failures with
structured warning/error logging.
- Added stale staging cleanup hardening: stale directories are cleaned
before reuse, and extraction aborts if stale cleanup fails and directory
remains.
- Preserved existing `rename_existing_folders` behavior while routing
extraction output through staging.
- Added/updated German translations for new user-facing operational
messages.
- Expanded unit coverage in `tests/unit/test_extract.py` for:
  - replace-on-success behavior
  - YAML write failures (with and without existing final directory)
  - swap rename rollback
  - stale backup fail-fast
  - backup cleanup warning handling
  - backup-restore failure logging
  - stale staging cleanup success/failure behavior
  - explicit backup removal assertion on successful swap
- Mention any dependencies, configuration changes, or additional
requirements introduced.
  No new dependencies or configuration keys were introduced.

### ⚙️ Type of Change
Select the type(s) of change(s) included in this pull request:
- [x] 🐞 Bug fix (non-breaking change which fixes an issue)
- [ ]  New feature (adds new functionality without breaking existing
usage)
- [ ] 💥 Breaking change (changes that might break existing user setups,
scripts, or configurations)


##  Checklist
Before requesting a review, confirm the following:
- [x] I have reviewed my changes to ensure they meet the project's
standards.
- [x] I have tested my changes and ensured that all tests pass (`pdm run
test`).
- [x] I have formatted the code (`pdm run format`).
- [x] I have verified that linting passes (`pdm run lint`).
- [x] I have updated documentation where necessary.

By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Safer downloads using a staging-then-commit flow to prevent partial
writes.
* Automatic backup creation, atomic replacement, and robust rollback on
errors.
* Improved cleanup and guarded handling for stale staging and failed
rename/cleanup operations.

* **Tests**
* Expanded unit tests covering staging→final swaps, backup/restore,
cleanup, failure paths, and rollback behaviors.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-03-24 20:30:16 +01:00
dependabot[bot]
804f8a7e61 ci(deps): bump the all-actions group with 2 updates (#901)
Bumps the all-actions group with 2 updates:
[codecov/codecov-action](https://github.com/codecov/codecov-action) and
[github/codeql-action](https://github.com/github/codeql-action).

Updates `codecov/codecov-action` from 5.5.2 to 5.5.3
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/codecov/codecov-action/releases">codecov/codecov-action's
releases</a>.</em></p>
<blockquote>
<h2>v5.5.3</h2>
<h2>What's Changed</h2>
<ul>
<li>build(deps): bump actions/github-script from 7.0.1 to 8.0.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1874">codecov/codecov-action#1874</a></li>
<li>chore(release): bump to 5.5.3 by <a
href="https://github.com/thomasrockhu-codecov"><code>@​thomasrockhu-codecov</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1922">codecov/codecov-action#1922</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/codecov/codecov-action/compare/v5.5.2...v5.5.3">https://github.com/codecov/codecov-action/compare/v5.5.2...v5.5.3</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md">codecov/codecov-action's
changelog</a>.</em></p>
<blockquote>
<h2>v5.5.2</h2>
<h3>What's Changed</h3>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/codecov/codecov-action/compare/v5.5.1..v5.5.2">https://github.com/codecov/codecov-action/compare/v5.5.1..v5.5.2</a></p>
<h2>v5.5.1</h2>
<h3>What's Changed</h3>
<ul>
<li>fix: overwrite pr number on fork by <a
href="https://github.com/thomasrockhu-codecov"><code>@​thomasrockhu-codecov</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1871">codecov/codecov-action#1871</a></li>
<li>build(deps): bump actions/checkout from 4.2.2 to 5.0.0 by
<code>@​app/dependabot</code> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1868">codecov/codecov-action#1868</a></li>
<li>build(deps): bump github/codeql-action from 3.29.9 to 3.29.11 by
<code>@​app/dependabot</code> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1867">codecov/codecov-action#1867</a></li>
<li>fix: update to use local app/ dir by <a
href="https://github.com/thomasrockhu-codecov"><code>@​thomasrockhu-codecov</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1872">codecov/codecov-action#1872</a></li>
<li>docs: fix typo in README by <a
href="https://github.com/datalater"><code>@​datalater</code></a> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1866">codecov/codecov-action#1866</a></li>
<li>Document a <code>codecov-cli</code> version reference example by <a
href="https://github.com/webknjaz"><code>@​webknjaz</code></a> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1774">codecov/codecov-action#1774</a></li>
<li>build(deps): bump github/codeql-action from 3.28.18 to 3.29.9 by
<code>@​app/dependabot</code> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1861">codecov/codecov-action#1861</a></li>
<li>build(deps): bump ossf/scorecard-action from 2.4.1 to 2.4.2 by
<code>@​app/dependabot</code> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1833">codecov/codecov-action#1833</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/codecov/codecov-action/compare/v5.5.0..v5.5.1">https://github.com/codecov/codecov-action/compare/v5.5.0..v5.5.1</a></p>
<h2>v5.5.0</h2>
<h3>What's Changed</h3>
<ul>
<li>feat: upgrade wrapper to 0.2.4 by <a
href="https://github.com/jviall"><code>@​jviall</code></a> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1864">codecov/codecov-action#1864</a></li>
<li>Pin actions/github-script by Git SHA by <a
href="https://github.com/martincostello"><code>@​martincostello</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1859">codecov/codecov-action#1859</a></li>
<li>fix: check reqs exist by <a
href="https://github.com/joseph-sentry"><code>@​joseph-sentry</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1835">codecov/codecov-action#1835</a></li>
<li>fix: Typo in README by <a
href="https://github.com/spalmurray"><code>@​spalmurray</code></a> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1838">codecov/codecov-action#1838</a></li>
<li>docs: Refine OIDC docs by <a
href="https://github.com/spalmurray"><code>@​spalmurray</code></a> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1837">codecov/codecov-action#1837</a></li>
<li>build(deps): bump github/codeql-action from 3.28.17 to 3.28.18 by
<code>@​app/dependabot</code> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1829">codecov/codecov-action#1829</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/codecov/codecov-action/compare/v5.4.3..v5.5.0">https://github.com/codecov/codecov-action/compare/v5.4.3..v5.5.0</a></p>
<h2>v5.4.3</h2>
<h3>What's Changed</h3>
<ul>
<li>build(deps): bump github/codeql-action from 3.28.13 to 3.28.17 by
<code>@​app/dependabot</code> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1822">codecov/codecov-action#1822</a></li>
<li>fix: OIDC on forks by <a
href="https://github.com/joseph-sentry"><code>@​joseph-sentry</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1823">codecov/codecov-action#1823</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/codecov/codecov-action/compare/v5.4.2..v5.4.3">https://github.com/codecov/codecov-action/compare/v5.4.2..v5.4.3</a></p>
<h2>v5.4.2</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="1af58845a9"><code>1af5884</code></a>
chore(release): bump to 5.5.3 (<a
href="https://redirect.github.com/codecov/codecov-action/issues/1922">#1922</a>)</li>
<li><a
href="c143300dea"><code>c143300</code></a>
build(deps): bump actions/github-script from 7.0.1 to 8.0.0 (<a
href="https://redirect.github.com/codecov/codecov-action/issues/1874">#1874</a>)</li>
<li>See full diff in <a
href="671740ac38...1af58845a9">compare
view</a></li>
</ul>
</details>
<br />

Updates `github/codeql-action` from 4.33.0 to 4.34.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action's
releases</a>.</em></p>
<blockquote>
<h2>v4.34.1</h2>
<ul>
<li>Downgrade default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.24.3">2.24.3</a>
due to issues with a small percentage of Actions and JavaScript
analyses. <a
href="https://redirect.github.com/github/codeql-action/pull/3762">#3762</a></li>
</ul>
<h2>v4.34.0</h2>
<ul>
<li>Added an experimental change which disables TRAP caching when <a
href="https://redirect.github.com/github/roadmap/issues/1158">improved
incremental analysis</a> is enabled, since improved incremental analysis
supersedes TRAP caching. This will improve performance and reduce
Actions cache usage. We expect to roll this change out to everyone in
March. <a
href="https://redirect.github.com/github/codeql-action/pull/3569">#3569</a></li>
<li>We are rolling out improved incremental analysis to C/C++ analyses
that use build mode <code>none</code>. We expect this rollout to be
complete by the end of April 2026. <a
href="https://redirect.github.com/github/codeql-action/pull/3584">#3584</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.0">2.25.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3585">#3585</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<p>No user facing changes.</p>
<h2>4.34.1 - 20 Mar 2026</h2>
<ul>
<li>Downgrade default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.24.3">2.24.3</a>
due to issues with a small percentage of Actions and JavaScript
analyses. <a
href="https://redirect.github.com/github/codeql-action/pull/3762">#3762</a></li>
</ul>
<h2>4.34.0 - 20 Mar 2026</h2>
<ul>
<li>Added an experimental change which disables TRAP caching when <a
href="https://redirect.github.com/github/roadmap/issues/1158">improved
incremental analysis</a> is enabled, since improved incremental analysis
supersedes TRAP caching. This will improve performance and reduce
Actions cache usage. We expect to roll this change out to everyone in
March. <a
href="https://redirect.github.com/github/codeql-action/pull/3569">#3569</a></li>
<li>We are rolling out improved incremental analysis to C/C++ analyses
that use build mode <code>none</code>. We expect this rollout to be
complete by the end of April 2026. <a
href="https://redirect.github.com/github/codeql-action/pull/3584">#3584</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.0">2.25.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3585">#3585</a></li>
</ul>
<h2>4.33.0 - 16 Mar 2026</h2>
<ul>
<li>
<p>Upcoming change: Starting April 2026, the CodeQL Action will skip
collecting file coverage information on pull requests to improve
analysis performance. File coverage information will still be computed
on non-PR analyses. Pull request analyses will log a warning about this
upcoming change. <a
href="https://redirect.github.com/github/codeql-action/pull/3562">#3562</a></p>
<p>To opt out of this change:</p>
<ul>
<li><strong>Repositories owned by an organization:</strong> Create a
custom repository property with the name
<code>github-codeql-file-coverage-on-prs</code> and the type
&quot;True/false&quot;, then set this property to <code>true</code> in
the repository's settings. For more information, see <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">Managing
custom properties for repositories in your organization</a>.
Alternatively, if you are using an advanced setup workflow, you can set
the <code>CODEQL_ACTION_FILE_COVERAGE_ON_PRS</code> environment variable
to <code>true</code> in your workflow.</li>
<li><strong>User-owned repositories using default setup:</strong> Switch
to an advanced setup workflow and set the
<code>CODEQL_ACTION_FILE_COVERAGE_ON_PRS</code> environment variable to
<code>true</code> in your workflow.</li>
<li><strong>User-owned repositories using advanced setup:</strong> Set
the <code>CODEQL_ACTION_FILE_COVERAGE_ON_PRS</code> environment variable
to <code>true</code> in your workflow.</li>
</ul>
</li>
<li>
<p>Fixed <a
href="https://redirect.github.com/github/codeql-action/issues/3555">a
bug</a> which caused the CodeQL Action to fail loading repository
properties if a &quot;Multi select&quot; repository property was
configured for the repository. <a
href="https://redirect.github.com/github/codeql-action/pull/3557">#3557</a></p>
</li>
<li>
<p>The CodeQL Action now loads <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">custom
repository properties</a> on GitHub Enterprise Server, enabling the
customization of features such as
<code>github-codeql-disable-overlay</code> that was previously only
available on GitHub.com. <a
href="https://redirect.github.com/github/codeql-action/pull/3559">#3559</a></p>
</li>
<li>
<p>Once <a
href="https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries">private
package registries</a> can be configured with OIDC-based authentication
for organizations, the CodeQL Action will now be able to accept such
configurations. <a
href="https://redirect.github.com/github/codeql-action/pull/3563">#3563</a></p>
</li>
<li>
<p>Fixed the retry mechanism for database uploads. Previously this would
fail with the error &quot;Response body object should not be disturbed
or locked&quot;. <a
href="https://redirect.github.com/github/codeql-action/pull/3564">#3564</a></p>
</li>
<li>
<p>A warning is now emitted if the CodeQL Action detects a repository
property whose name suggests that it relates to the CodeQL Action, but
which is not one of the properties recognised by the current version of
the CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3570">#3570</a></p>
</li>
</ul>
<h2>4.32.6 - 05 Mar 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.24.3">2.24.3</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3548">#3548</a></li>
</ul>
<h2>4.32.5 - 02 Mar 2026</h2>
<ul>
<li>Repositories owned by an organization can now set up the
<code>github-codeql-disable-overlay</code> custom repository property to
disable <a
href="https://redirect.github.com/github/roadmap/issues/1158">improved
incremental analysis for CodeQL</a>. First, create a custom repository
property with the name <code>github-codeql-disable-overlay</code> and
the type &quot;True/false&quot; in the organization's settings. Then in
the repository's settings, set this property to <code>true</code> to
disable improved incremental analysis. For more information, see <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">Managing
custom properties for repositories in your organization</a>. This
feature is not yet available on GitHub Enterprise Server. <a
href="https://redirect.github.com/github/codeql-action/pull/3507">#3507</a></li>
<li>Added an experimental change so that when <a
href="https://redirect.github.com/github/roadmap/issues/1158">improved
incremental analysis</a> fails on a runner — potentially due to
insufficient disk space — the failure is recorded in the Actions cache
so that subsequent runs will automatically skip improved incremental
analysis until something changes (e.g. a larger runner is provisioned or
a new CodeQL version is released). We expect to roll this change out to
everyone in March. <a
href="https://redirect.github.com/github/codeql-action/pull/3487">#3487</a></li>
<li>The minimum memory check for improved incremental analysis is now
skipped for CodeQL 2.24.3 and later, which has reduced peak RAM usage.
<a
href="https://redirect.github.com/github/codeql-action/pull/3515">#3515</a></li>
<li>Reduced log levels for best-effort private package registry
connection check failures to reduce noise from workflow annotations. <a
href="https://redirect.github.com/github/codeql-action/pull/3516">#3516</a></li>
<li>Added an experimental change which lowers the minimum disk space
requirement for <a
href="https://redirect.github.com/github/roadmap/issues/1158">improved
incremental analysis</a>, enabling it to run on standard GitHub Actions
runners. We expect to roll this change out to everyone in March. <a
href="https://redirect.github.com/github/codeql-action/pull/3498">#3498</a></li>
<li>Added an experimental change which allows the
<code>start-proxy</code> action to resolve the CodeQL CLI version from
feature flags instead of using the linked CLI bundle version. We expect
to roll this change out to everyone in March. <a
href="https://redirect.github.com/github/codeql-action/pull/3512">#3512</a></li>
<li>The previously experimental changes from versions 4.32.3, 4.32.4,
3.32.3 and 3.32.4 are now enabled by default. <a
href="https://redirect.github.com/github/codeql-action/pull/3503">#3503</a>,
<a
href="https://redirect.github.com/github/codeql-action/pull/3504">#3504</a></li>
</ul>
<h2>4.32.4 - 20 Feb 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.24.2">2.24.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3493">#3493</a></li>
<li>Added an experimental change which improves how certificates are
generated for the authentication proxy that is used by the CodeQL Action
in Default Setup when <a
href="https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries">private
package registries are configured</a>. This is expected to generate more
widely compatible certificates and should have no impact on analyses
which are working correctly already. We expect to roll this change out
to everyone in February. <a
href="https://redirect.github.com/github/codeql-action/pull/3473">#3473</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="3869755554"><code>3869755</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3763">#3763</a>
from github/update-v4.34.1-095e0fe50</li>
<li><a
href="20e68ac12b"><code>20e68ac</code></a>
Update changelog for v4.34.1</li>
<li><a
href="095e0fe505"><code>095e0fe</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3762">#3762</a>
from github/henrymercer/downgrade-default-bundle</li>
<li><a
href="47b94fe61c"><code>47b94fe</code></a>
Add changelog note</li>
<li><a
href="51a1d6917f"><code>51a1d69</code></a>
Downgrade default bundle to codeql-bundle-v2.24.3</li>
<li><a
href="510cf736e3"><code>510cf73</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3589">#3589</a>
from github/mergeback/v4.34.0-to-main-c6f93110</li>
<li><a
href="89f0c86efa"><code>89f0c86</code></a>
Rebuild</li>
<li><a
href="c3f90ba975"><code>c3f90ba</code></a>
Update changelog and version after v4.34.0</li>
<li><a
href="c6f931105c"><code>c6f9311</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3588">#3588</a>
from github/update-v4.34.0-30c555a52</li>
<li><a
href="eeb9b3f424"><code>eeb9b3f</code></a>
Update changelog for v4.34.0</li>
<li>Additional commits viewable in <a
href="b1bff81932...3869755554">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-23 15:51:02 +01:00
Jens
2abe0ccb71 feat: add configurable download naming templates (#896) 2026-03-23 08:02:19 +01:00
Jens
813753dd41 fix: guard browser cleanup pid handling for mocked sessions (#898) 2026-03-23 08:01:29 +01:00
kleinanzeigen-bot-tu[bot]
556af67fa0 chore: ✔ Update pytest-cov 7.0.0 -> 7.1.0 (#899)
✔ Update pytest-cov 7.0.0 -> 7.1.0 successful

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-22 18:08:16 +01:00
kleinanzeigen-bot-tu[bot]
a4d8b7e2cb chore: ✔ Update jaraco-context 6.1.1 -> 6.1.2 (#897)
✔ Update jaraco-context 6.1.1 -> 6.1.2 successful

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-22 10:04:36 +01:00
Jens
2d02d206ec feat: add configurable download directory (#894) 2026-03-20 23:03:32 +01:00
kleinanzeigen-bot-tu[bot]
94c3a1d260 chore: Update Python dependencies (#895)
✔ Update attrs 25.4.0 -> 26.1.0 successful
  ✔ Update ruff 0.15.6 -> 0.15.7 successful

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-20 21:15:31 +01:00
kleinanzeigen-bot-tu[bot]
d25d63f0ce chore: Update Python dependencies (#889)
✔ Update cyclonedx-python-lib 11.6.0 -> 11.7.0 successful
  ✔ Update basedpyright 1.38.2 -> 1.38.3 successful

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-18 21:54:12 +01:00
kleinanzeigen-bot-tu[bot]
e7fed79aa6 chore: ✔ Update coverage 7.13.4 -> 7.13.5 (#888) 2026-03-18 07:00:48 +01:00