feat: granular watch settings with event filtering and author exclusions #21

Merged
pat-s merged 59 commits from feat/granular-watch-settings-clean into v14.0/forgejo-codefloe 2026-03-03 09:22:20 +00:00
Owner

Summary

This PR adds granular control over repository watch notifications, allowing users to:

  • Filter by event type: Choose which events trigger notifications (Issues, Pull Requests, Releases)
  • Exclude specific authors: Prevent notifications from certain users globally or per-repository
  • Exclude bot accounts: Automatically filter out bot activity from notifications
## Summary This PR adds granular control over repository watch notifications, allowing users to: - **Filter by event type**: Choose which events trigger notifications (Issues, Pull Requests, Releases) - **Exclude specific authors**: Prevent notifications from certain users globally or per-repository - **Exclude bot accounts**: Automatically filter out bot activity from notifications
This adds the ability to select which types of events to receive notifications
for when watching a repository:
- Issues
- Pull requests
- Releases

Changes:
- Add WatchEventType bitmask to track event preferences in watch table
- Add migration (v14b) to add watch_events column
- Update watch UI with dropdown to select event types
- Add user settings page for default watch preferences
- Add API support for setting watch events
- Add DefaultWatchEvents instance setting
- Add e2e and integration tests

Users can now customize their watch preferences per-repository instead of
an all-or-nothing approach.
feat: add author exclusions to watch notifications
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m7s
testing / backend-checks (pull_request) Failing after 6m35s
testing / test-unit (pull_request) Has been skipped
testing / test-e2e (pull_request) Has been skipped
testing / test-mysql (pull_request) Has been skipped
testing / test-pgsql (pull_request) Has been skipped
testing / test-sqlite (pull_request) Has been skipped
testing / test-remote-cacher (redis) (pull_request) Has been skipped
testing / test-remote-cacher (valkey) (pull_request) Has been skipped
testing / test-remote-cacher (garnet) (pull_request) Has been skipped
testing / test-remote-cacher (redict) (pull_request) Has been skipped
testing / security-check (pull_request) Has been skipped
a515ffb03f
Allow users to exclude specific authors from generating watch notifications.
Supports global exclusions (configured in user settings), per-repo exclusions
(configured in watch dropdown), and automatic bot user exclusion.

Exclusions are applied when creating issue/PR notifications and sending
release emails.
pat-s requested review from Cyborus 2026-01-30 21:25:45 +00:00
- Remove "Exclude bot accounts" checkbox option
- Add regex pattern field to match usernames to exclude (e.g., .*\[bot\]$)
- Fix user search dropdown to use /user/search_candidates endpoint
- Update all callers to pass author name for pattern matching
fix: add missing locale strings for notification settings
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m6s
testing / backend-checks (pull_request) Failing after 7m1s
testing / test-unit (pull_request) Has been skipped
testing / test-pgsql (pull_request) Has been skipped
testing / test-mysql (pull_request) Has been skipped
testing / test-e2e (pull_request) Has been skipped
testing / test-sqlite (pull_request) Has been skipped
testing / test-remote-cacher (redis) (pull_request) Has been skipped
testing / test-remote-cacher (valkey) (pull_request) Has been skipped
testing / test-remote-cacher (redict) (pull_request) Has been skipped
testing / test-remote-cacher (garnet) (pull_request) Has been skipped
testing / security-check (pull_request) Has been skipped
84bdd90313
Add success messages for auto-watch and default watch events settings.
Remove unused per_repo_help locale string.
chore: regenerate swagger spec for watch API changes
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m54s
testing / backend-checks (pull_request) Has been cancelled
testing / test-sqlite (pull_request) Has been cancelled
testing / security-check (pull_request) Has been cancelled
testing / test-pgsql (pull_request) Has been cancelled
testing / test-remote-cacher (redis) (pull_request) Has been cancelled
testing / test-unit (pull_request) Has been cancelled
testing / test-e2e (pull_request) Has been cancelled
testing / test-remote-cacher (valkey) (pull_request) Has been cancelled
testing / test-remote-cacher (garnet) (pull_request) Has been cancelled
testing / test-remote-cacher (redict) (pull_request) Has been cancelled
testing / test-mysql (pull_request) Has been cancelled
5053b61c57
The SVG had duplicate viewBox attributes (0 0 16 16 and 0 0 24 24).
The first one took precedence but the path data is designed for 24x24,
causing the icon to be cut off at the bottom right.
fix: initialize user search dropdowns after htmx swaps
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m45s
testing / backend-checks (pull_request) Has been cancelled
testing / test-pgsql (pull_request) Has been cancelled
testing / test-sqlite (pull_request) Has been cancelled
testing / security-check (pull_request) Has been cancelled
testing / test-unit (pull_request) Has been cancelled
testing / test-e2e (pull_request) Has been cancelled
testing / test-remote-cacher (redis) (pull_request) Has been cancelled
testing / test-remote-cacher (valkey) (pull_request) Has been cancelled
testing / test-remote-cacher (garnet) (pull_request) Has been cancelled
testing / test-remote-cacher (redict) (pull_request) Has been cancelled
testing / test-mysql (pull_request) Has been cancelled
3139f4f4ce
The inline scripts weren't executing after htmx content swaps.
Move dropdown initialization to htmx.js using data attributes
and htmx:afterSettle event handler.
fix: properly initialize user search dropdowns on page load
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m55s
testing / backend-checks (pull_request) Failing after 9m18s
testing / test-pgsql (pull_request) Has been skipped
testing / test-unit (pull_request) Has been skipped
testing / test-e2e (pull_request) Has been skipped
testing / test-mysql (pull_request) Has been skipped
testing / test-sqlite (pull_request) Has been skipped
testing / test-remote-cacher (redis) (pull_request) Has been skipped
testing / test-remote-cacher (redict) (pull_request) Has been skipped
testing / test-remote-cacher (valkey) (pull_request) Has been skipped
testing / test-remote-cacher (garnet) (pull_request) Has been skipped
testing / security-check (pull_request) Has been skipped
6ec56707ec
- Export initUserSearchDropdowns from htmx.js
- Call it from index.js onDomReady to ensure proper timing
- Move window.config access inside function to avoid timing issues
- Use document.addEventListener for htmx events (bubbles from body)
Add baseline alignment for flex-item-leading to align the repo icon
horizontally with the repo name text, matching the pattern used for
flex-item-icon.
fix(ui): improve repo icon alignment using matched line-height
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m52s
testing / backend-checks (pull_request) Failing after 9m58s
testing / test-unit (pull_request) Has been skipped
testing / test-e2e (pull_request) Has been skipped
testing / test-pgsql (pull_request) Has been skipped
testing / test-remote-cacher (redis) (pull_request) Has been skipped
testing / test-remote-cacher (valkey) (pull_request) Has been skipped
testing / test-remote-cacher (garnet) (pull_request) Has been skipped
testing / test-remote-cacher (redict) (pull_request) Has been skipped
testing / test-sqlite (pull_request) Has been skipped
testing / test-mysql (pull_request) Has been skipped
testing / security-check (pull_request) Has been skipped
4383b86ee2
Replace baseline alignment approach with matched dimensions:
- .flex-item-leading: min-height: 1.5rem with align-items: center
- .flex-item-title: line-height: 1.5rem

Both containers now have the same 24px height, ensuring icons
(both 20px SVGs and 24px avatars) align with text centers.
Uses relative units (rem) for robustness.
First-time contributor

Oh, uh, hi! I guess it makes sense that CODEOWNERS works on cross-instance forks.

Oh, uh, hi! I guess it makes sense that `CODEOWNERS` works on cross-instance forks.
Author
Owner

Ah sorry, will take care this is being removed.

Ah sorry, will take care this is being removed.
pat-s removed review request for Cyborus 2026-01-31 08:58:29 +00:00
lint
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m51s
testing / backend-checks (pull_request) Successful in 15m28s
testing / test-unit (pull_request) Successful in 8m39s
testing / test-e2e (pull_request) Failing after 15m34s
testing / test-remote-cacher (redis) (pull_request) Successful in 2m50s
testing / test-remote-cacher (garnet) (pull_request) Successful in 3m6s
testing / test-remote-cacher (valkey) (pull_request) Successful in 5m7s
testing / test-remote-cacher (redict) (pull_request) Failing after 8m53s
testing / test-sqlite (pull_request) Successful in 47m21s
testing / test-pgsql (pull_request) Successful in 49m23s
testing / test-mysql (pull_request) Successful in 56m35s
testing / security-check (pull_request) Has been skipped
b4abf8d09f
fix(test): use specific selector for issue title Save button
All checks were successful
testing / frontend-checks (pull_request) Successful in 1m46s
testing / backend-checks (pull_request) Successful in 14m42s
testing / test-unit (pull_request) Successful in 14m32s
testing / test-remote-cacher (redict) (pull_request) Successful in 2m51s
testing / test-remote-cacher (garnet) (pull_request) Successful in 2m53s
testing / test-remote-cacher (valkey) (pull_request) Successful in 5m8s
testing / test-remote-cacher (redis) (pull_request) Successful in 5m8s
testing / test-mysql (pull_request) Successful in 40m6s
testing / test-e2e (pull_request) Successful in 42m19s
testing / test-sqlite (pull_request) Successful in 48m9s
testing / test-pgsql (pull_request) Successful in 50m13s
testing / security-check (pull_request) Successful in 1m51s
2c5f966741
The test was failing because getByText('Save') now matches both the
issue title editor Save button and the watch settings Save button.
Use a more specific selector targeting the button with data-update-url
inside #issue-title-editor.
feat: add participating and @mentions watch option
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m46s
testing / backend-checks (pull_request) Successful in 14m50s
testing / test-pgsql (pull_request) Has been cancelled
testing / test-unit (pull_request) Has been cancelled
testing / test-sqlite (pull_request) Has been cancelled
testing / test-mysql (pull_request) Has been cancelled
testing / test-e2e (pull_request) Has been cancelled
testing / test-remote-cacher (valkey) (pull_request) Has been cancelled
testing / test-remote-cacher (garnet) (pull_request) Has been cancelled
testing / test-remote-cacher (redis) (pull_request) Has been cancelled
testing / security-check (pull_request) Has been cancelled
testing / test-remote-cacher (redict) (pull_request) Has been cancelled
37a548499a
Add a fourth watch event type for "Participating and @mentions" which
only triggers notifications when the user is participating in the
issue/PR (author, assignee, mentioned, or has commented).

Changes:
- Add WatchEventParticipating constant (value: 8)
- Add WatchEventDefault constant set to WatchEventParticipating
- Update GetWatchEvents() to return WatchEventDefault instead of All
- Add WatchesParticipating() method to WatchEventType
- Add UI checkbox for participating option in watch settings
- Update user notification settings to include participating default
- Rename "Issues" to "All issues" and "Pull requests" to "All pull
  requests" in locale to distinguish from participating mode

This option is combinable with other watch options (Issues, PRs,
Releases) and is the new implicit default for new watches.
fix(ui): close watch dropdown before htmx swap to prevent flash
Some checks failed
testing / frontend-checks (pull_request) Successful in 57s
testing / backend-checks (pull_request) Has been cancelled
testing / test-unit (pull_request) Has been cancelled
testing / test-e2e (pull_request) Has been cancelled
testing / test-sqlite (pull_request) Has been cancelled
testing / test-pgsql (pull_request) Has been cancelled
testing / test-remote-cacher (redis) (pull_request) Has been cancelled
testing / test-remote-cacher (valkey) (pull_request) Has been cancelled
testing / test-remote-cacher (garnet) (pull_request) Has been cancelled
testing / test-remote-cacher (redict) (pull_request) Has been cancelled
testing / test-mysql (pull_request) Has been cancelled
testing / security-check (pull_request) Has been cancelled
2632fa78de
Close the details dropdown immediately when clicking Save or Unwatch,
before the htmx request is made. This prevents the visible layout
flash that occurred when the dropdown content was being swapped
while still visible.
feat(ui): auto-save watch settings when toggling checkboxes
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m1s
testing / backend-checks (pull_request) Has been cancelled
testing / test-sqlite (pull_request) Has been cancelled
testing / test-e2e (pull_request) Has been cancelled
testing / test-unit (pull_request) Has been cancelled
testing / security-check (pull_request) Has been cancelled
testing / test-pgsql (pull_request) Has been cancelled
testing / test-remote-cacher (valkey) (pull_request) Has been cancelled
testing / test-remote-cacher (garnet) (pull_request) Has been cancelled
testing / test-remote-cacher (redict) (pull_request) Has been cancelled
testing / test-remote-cacher (redis) (pull_request) Has been cancelled
testing / test-mysql (pull_request) Has been cancelled
1e46a22878
- Checkboxes now auto-save on change without requiring Save button
- Dropdown stays open so users can toggle multiple options
- Removed Save button (no longer needed with auto-save)
- Unwatch button remains for completely unwatching
fix(ui): use morph swap to eliminate flash on watch settings toggle
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m48s
testing / backend-checks (pull_request) Successful in 14m34s
testing / test-unit (pull_request) Successful in 14m36s
testing / test-remote-cacher (valkey) (pull_request) Successful in 3m10s
testing / test-remote-cacher (redict) (pull_request) Successful in 3m13s
testing / test-remote-cacher (garnet) (pull_request) Successful in 3m15s
testing / test-remote-cacher (redis) (pull_request) Successful in 4m46s
testing / test-e2e (pull_request) Has been cancelled
testing / test-pgsql (pull_request) Has been cancelled
testing / test-mysql (pull_request) Has been cancelled
testing / test-sqlite (pull_request) Has been cancelled
testing / security-check (pull_request) Has been cancelled
81e34c6725
Use idiomorph's morph:outerHTML swap instead of plain outerHTML.
This performs smart DOM diffing and only updates elements that
actually changed, eliminating the visible flash when toggling
checkboxes.
fix(ui): use hx-swap=none to eliminate flash on checkbox toggle
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m47s
testing / backend-checks (pull_request) Successful in 14m46s
testing / test-unit (pull_request) Successful in 16m25s
testing / test-remote-cacher (valkey) (pull_request) Successful in 5m8s
testing / test-remote-cacher (redis) (pull_request) Successful in 5m9s
testing / test-remote-cacher (garnet) (pull_request) Successful in 5m22s
testing / test-remote-cacher (redict) (pull_request) Successful in 5m24s
testing / test-mysql (pull_request) Failing after 34m20s
testing / test-pgsql (pull_request) Failing after 42m18s
testing / test-e2e (pull_request) Successful in 43m9s
testing / test-sqlite (pull_request) Failing after 44m19s
testing / security-check (pull_request) Has been skipped
a382f14954
Instead of swapping DOM content after auto-save, just return 204
No Content. The checkbox state is already updated by the browser,
so no DOM manipulation is needed. This completely eliminates the
flash issue.
fix: eliminate flash/flicker in watch settings dropdown
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m45s
testing / backend-checks (pull_request) Has been cancelled
testing / test-unit (pull_request) Has been cancelled
testing / test-e2e (pull_request) Has been cancelled
testing / test-pgsql (pull_request) Has been cancelled
testing / test-remote-cacher (valkey) (pull_request) Has been cancelled
testing / test-remote-cacher (garnet) (pull_request) Has been cancelled
testing / test-remote-cacher (redis) (pull_request) Has been cancelled
testing / test-remote-cacher (redict) (pull_request) Has been cancelled
testing / test-mysql (pull_request) Has been cancelled
testing / test-sqlite (pull_request) Has been cancelled
testing / security-check (pull_request) Has been cancelled
410e71e7c2
- Add no-loading-indicator CSS class to disable htmx loading styles
- Use hx-swap="none" with 204 response for seamless auto-save
- Handle unwatch via client-side updates to avoid DOM morphing issues
- Store locale strings in data attributes for client-side text updates
fix: add button text update handler on checkbox change
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m46s
testing / backend-checks (pull_request) Successful in 14m36s
testing / test-unit (pull_request) Successful in 14m36s
testing / test-remote-cacher (redis) (pull_request) Successful in 3m21s
testing / test-remote-cacher (valkey) (pull_request) Successful in 3m26s
testing / test-remote-cacher (garnet) (pull_request) Successful in 3m26s
testing / test-remote-cacher (redict) (pull_request) Successful in 4m46s
testing / test-mysql (pull_request) Failing after 41m56s
testing / test-e2e (pull_request) Successful in 43m41s
testing / test-sqlite (pull_request) Failing after 53m5s
testing / test-pgsql (pull_request) Failing after 55m12s
testing / security-check (pull_request) Has been skipped
a34ea0ab22
The hx-on::after-request handler updates the button text between
"Watch" and "Watching" based on whether any checkbox is selected.
fix: unwatch all unchecks all checkboxes and prevents race condition
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m44s
testing / backend-checks (pull_request) Has been cancelled
testing / test-sqlite (pull_request) Has been cancelled
testing / test-pgsql (pull_request) Has been cancelled
testing / security-check (pull_request) Has been cancelled
testing / test-unit (pull_request) Has been cancelled
testing / test-e2e (pull_request) Has been cancelled
testing / test-remote-cacher (redis) (pull_request) Has been cancelled
testing / test-remote-cacher (valkey) (pull_request) Has been cancelled
testing / test-remote-cacher (garnet) (pull_request) Has been cancelled
testing / test-remote-cacher (redict) (pull_request) Has been cancelled
testing / test-mysql (pull_request) Has been cancelled
1a7cb434c7
- Unwatch now unchecks ALL checkboxes (not just some)
- Add data-skip-trigger flag to prevent form's change handler from
  interfering with unwatch button's UI updates
- Form's after-request handler skips when skip flag is set
fix: use server-side rendering for watch button toggle
All checks were successful
testing / frontend-checks (pull_request) Successful in 1m52s
testing / backend-checks (pull_request) Successful in 15m11s
testing / test-unit (pull_request) Successful in 15m36s
testing / test-remote-cacher (valkey) (pull_request) Successful in 3m13s
testing / test-remote-cacher (redict) (pull_request) Successful in 3m14s
testing / test-remote-cacher (garnet) (pull_request) Successful in 3m14s
testing / test-remote-cacher (redis) (pull_request) Successful in 5m7s
testing / test-mysql (pull_request) Successful in 40m55s
testing / test-e2e (pull_request) Successful in 41m0s
testing / test-sqlite (pull_request) Successful in 48m6s
testing / test-pgsql (pull_request) Successful in 51m9s
testing / security-check (pull_request) Successful in 3m26s
550b2d0607
Replace unreliable htmx from:find trigger with JavaScript-based approach:
- Add initWatchCheckboxes() to handle checkbox change events
- Trigger htmx form submission programmatically on change
- Server returns full HTML with correct Watch/Watching text
- Remove complex client-side text manipulation logic
Add parallelism: 5 and filesystem caching to webpack config to avoid
EMFILE "too many open files" errors on macOS with default ulimit of 1024.
fix(watch): submit form on dropdown close instead of each checkbox change
Some checks failed
testing / frontend-checks (pull_request) Failing after 29s
testing / backend-checks (pull_request) Successful in 8m26s
testing / test-e2e (pull_request) Has been skipped
testing / test-sqlite (pull_request) Has been skipped
testing / test-pgsql (pull_request) Has been skipped
testing / test-unit (pull_request) Has been skipped
testing / test-mysql (pull_request) Has been skipped
testing / test-remote-cacher (redis) (pull_request) Has been skipped
testing / test-remote-cacher (garnet) (pull_request) Has been skipped
testing / test-remote-cacher (redict) (pull_request) Has been skipped
testing / test-remote-cacher (valkey) (pull_request) Has been skipped
testing / security-check (pull_request) Has been skipped
01454935db
Previously, the watch dropdown would submit the form on every checkbox
change, causing the dropdown to flash/reload after each click. This made
it difficult to make multiple changes at once.

Changes:
- Use idiomorph (hx-swap="morph:outerHTML") to preserve dropdown state
- Submit form only when dropdown closes (not on each checkbox change)
- Track changes using form state comparison to avoid unnecessary submits
- Use MutationObserver pattern (like tippy.js/dirauto.js) for initialization
- Show empty checkboxes when not watching instead of user defaults

The dropdown now stays open while making multiple selections, and only
submits when the user closes it (if changes were made).
fix(lint): use import.meta.filename instead of fileURLToPath
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m21s
testing / backend-checks (pull_request) Successful in 24m18s
testing / test-unit (pull_request) Successful in 10m30s
testing / test-remote-cacher (redict) (pull_request) Successful in 3m44s
testing / test-remote-cacher (redis) (pull_request) Successful in 5m9s
testing / test-remote-cacher (garnet) (pull_request) Successful in 5m30s
testing / test-remote-cacher (valkey) (pull_request) Successful in 5m31s
testing / test-mysql (pull_request) Successful in 38m47s
testing / test-sqlite (pull_request) Successful in 47m55s
testing / test-pgsql (pull_request) Successful in 47m58s
testing / test-e2e (pull_request) Failing after 48m21s
testing / security-check (pull_request) Successful in 3m33s
5ebebb50b9
ESLint unicorn/prefer-import-meta-properties rule requires using
import.meta.filename instead of fileURLToPath(import.meta.url).
pat-s force-pushed feat/granular-watch-settings-clean from 84f2e51217
Some checks failed
testing / frontend-checks (pull_request) Failing after 36s
testing / backend-checks (pull_request) Has been cancelled
testing / test-remote-cacher (redis) (pull_request) Has been cancelled
testing / test-remote-cacher (valkey) (pull_request) Has been cancelled
testing / test-remote-cacher (garnet) (pull_request) Has been cancelled
testing / test-unit (pull_request) Has been cancelled
testing / test-e2e (pull_request) Has been cancelled
testing / security-check (pull_request) Has been cancelled
testing / test-remote-cacher (redict) (pull_request) Has been cancelled
testing / test-mysql (pull_request) Has been cancelled
testing / test-pgsql (pull_request) Has been cancelled
testing / test-sqlite (pull_request) Has been cancelled
to 9b242ee807
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m49s
testing / backend-checks (pull_request) Successful in 14m37s
testing / test-unit (pull_request) Successful in 16m8s
testing / test-remote-cacher (valkey) (pull_request) Successful in 3m18s
testing / test-remote-cacher (redict) (pull_request) Successful in 3m18s
testing / test-remote-cacher (garnet) (pull_request) Successful in 3m21s
testing / test-remote-cacher (redis) (pull_request) Successful in 4m58s
testing / test-mysql (pull_request) Successful in 40m18s
testing / test-e2e (pull_request) Successful in 44m14s
testing / test-sqlite (pull_request) Failing after 46m19s
testing / test-pgsql (pull_request) Successful in 51m26s
testing / security-check (pull_request) Has been skipped
2026-02-02 10:03:46 +00:00
Compare
pat-s force-pushed feat/granular-watch-settings-clean from ae9e27a64b
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m54s
testing / backend-checks (pull_request) Successful in 15m20s
testing / test-unit (pull_request) Successful in 15m17s
testing / test-remote-cacher (garnet) (pull_request) Successful in 3m11s
testing / test-remote-cacher (valkey) (pull_request) Successful in 3m16s
testing / test-remote-cacher (redis) (pull_request) Successful in 4m59s
testing / test-remote-cacher (redict) (pull_request) Successful in 4m59s
testing / test-mysql (pull_request) Successful in 39m8s
testing / test-e2e (pull_request) Successful in 42m7s
testing / test-pgsql (pull_request) Successful in 52m12s
testing / test-sqlite (pull_request) Failing after 1h5m2s
testing / security-check (pull_request) Has been skipped
to 67cb67fb0f
All checks were successful
testing / frontend-checks (pull_request) Successful in 1m50s
testing / backend-checks (pull_request) Successful in 14m44s
testing / test-unit (pull_request) Successful in 16m5s
testing / test-remote-cacher (garnet) (pull_request) Successful in 3m1s
testing / test-remote-cacher (redict) (pull_request) Successful in 3m1s
testing / test-remote-cacher (valkey) (pull_request) Successful in 4m58s
testing / test-remote-cacher (redis) (pull_request) Successful in 5m19s
testing / test-mysql (pull_request) Successful in 40m49s
testing / test-e2e (pull_request) Successful in 43m51s
testing / test-sqlite (pull_request) Successful in 46m48s
testing / test-pgsql (pull_request) Successful in 50m59s
testing / security-check (pull_request) Successful in 3m26s
2026-02-03 11:14:47 +00:00
Compare
Email notifications now respect the granular watch event settings
(Issues, PRs, Releases). Add GetRepoWatchersIDsForEvent() to filter
watchers by event type and update mailer paths for issues/PRs/releases.
feat: filter UI notifications by watch event type settings
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m54s
testing / backend-checks (pull_request) Failing after 9m45s
testing / test-unit (pull_request) Has been skipped
testing / test-mysql (pull_request) Has been skipped
testing / test-e2e (pull_request) Has been skipped
testing / test-sqlite (pull_request) Has been skipped
testing / test-pgsql (pull_request) Has been skipped
testing / test-remote-cacher (redis) (pull_request) Has been skipped
testing / test-remote-cacher (valkey) (pull_request) Has been skipped
testing / test-remote-cacher (garnet) (pull_request) Has been skipped
testing / test-remote-cacher (redict) (pull_request) Has been skipped
testing / security-check (pull_request) Has been skipped
bf2051fdbe
UI notifications now respect the granular watch event settings.
Update notification_list.go and uinotification/notify.go to use
GetRepoWatchersIDsForEvent() for filtering by Issues/PRs.
pat-s force-pushed feat/granular-watch-settings-clean from 1d73a12943
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m53s
testing / backend-checks (pull_request) Failing after 9m16s
testing / test-unit (pull_request) Has been skipped
testing / test-remote-cacher (redis) (pull_request) Has been skipped
testing / test-mysql (pull_request) Has been skipped
testing / test-e2e (pull_request) Has been skipped
testing / test-pgsql (pull_request) Has been skipped
testing / test-remote-cacher (garnet) (pull_request) Has been skipped
testing / test-sqlite (pull_request) Has been skipped
testing / test-remote-cacher (valkey) (pull_request) Has been skipped
testing / test-remote-cacher (redict) (pull_request) Has been skipped
testing / security-check (pull_request) Has been skipped
to 67253db25f
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m51s
testing / backend-checks (pull_request) Has been cancelled
testing / security-check (pull_request) Has been cancelled
testing / test-unit (pull_request) Has been cancelled
testing / test-pgsql (pull_request) Has been cancelled
testing / test-e2e (pull_request) Has been cancelled
testing / test-remote-cacher (redis) (pull_request) Has been cancelled
testing / test-sqlite (pull_request) Has been cancelled
testing / test-remote-cacher (valkey) (pull_request) Has been cancelled
testing / test-remote-cacher (garnet) (pull_request) Has been cancelled
testing / test-remote-cacher (redict) (pull_request) Has been cancelled
testing / test-mysql (pull_request) Has been cancelled
2026-02-04 23:13:57 +00:00
Compare
pat-s force-pushed feat/granular-watch-settings-clean from 67253db25f
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m51s
testing / backend-checks (pull_request) Has been cancelled
testing / security-check (pull_request) Has been cancelled
testing / test-unit (pull_request) Has been cancelled
testing / test-pgsql (pull_request) Has been cancelled
testing / test-e2e (pull_request) Has been cancelled
testing / test-remote-cacher (redis) (pull_request) Has been cancelled
testing / test-sqlite (pull_request) Has been cancelled
testing / test-remote-cacher (valkey) (pull_request) Has been cancelled
testing / test-remote-cacher (garnet) (pull_request) Has been cancelled
testing / test-remote-cacher (redict) (pull_request) Has been cancelled
testing / test-mysql (pull_request) Has been cancelled
to 00a2038f40
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m55s
testing / backend-checks (pull_request) Failing after 9m29s
testing / test-unit (pull_request) Has been skipped
testing / test-e2e (pull_request) Has been skipped
testing / test-sqlite (pull_request) Has been skipped
testing / test-pgsql (pull_request) Has been skipped
testing / test-mysql (pull_request) Has been skipped
testing / test-remote-cacher (redis) (pull_request) Has been skipped
testing / test-remote-cacher (valkey) (pull_request) Has been skipped
testing / test-remote-cacher (garnet) (pull_request) Has been skipped
testing / test-remote-cacher (redict) (pull_request) Has been skipped
testing / security-check (pull_request) Has been skipped
2026-02-04 23:21:21 +00:00
Compare
Add a codefloe-specific release notification system that creates
UI notifications for users who have subscribed to release events.

- Create new ReleaseNotification model in models/codefloe/
- Add migration v4 to create release_notification table
- Add NewRelease handler to uinotification service that creates
  notifications for watchers with release events enabled
feat: add UI for release notifications
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m25s
testing / backend-checks (pull_request) Failing after 5m0s
testing / test-unit (pull_request) Has been skipped
testing / test-e2e (pull_request) Has been skipped
testing / test-mysql (pull_request) Has been skipped
testing / test-pgsql (pull_request) Has been skipped
testing / test-sqlite (pull_request) Has been skipped
testing / test-remote-cacher (valkey) (pull_request) Has been skipped
testing / test-remote-cacher (redis) (pull_request) Has been skipped
testing / test-remote-cacher (redict) (pull_request) Has been skipped
testing / test-remote-cacher (garnet) (pull_request) Has been skipped
testing / security-check (pull_request) Has been skipped
050aba7f10
Add a web interface to view and manage release notifications:

- Add routes for release notifications listing, status changes, and purge
- Add ReleaseNotifications, ReleaseNotificationStatusPost, and
  ReleaseNotificationPurgePost handlers
- Create notification_releases.tmpl and notification_releases_div.tmpl
  templates
- Add "Releases" tab to main notification page with unread count badge
- Include release notifications in total notification count
- Add CountReleaseNotifications and MarkReleaseNotificationAsUnread
  functions to the model
- Add "releases" translation key to locale
refactor: integrate release notifications into unified list
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m53s
testing / backend-checks (pull_request) Has been cancelled
testing / test-unit (pull_request) Has been cancelled
testing / test-pgsql (pull_request) Has been cancelled
testing / security-check (pull_request) Has been cancelled
testing / test-e2e (pull_request) Has been cancelled
testing / test-remote-cacher (redis) (pull_request) Has been cancelled
testing / test-remote-cacher (valkey) (pull_request) Has been cancelled
testing / test-sqlite (pull_request) Has been cancelled
testing / test-remote-cacher (redict) (pull_request) Has been cancelled
testing / test-mysql (pull_request) Has been cancelled
testing / test-remote-cacher (garnet) (pull_request) Has been cancelled
81879b7061
Show release notifications alongside issue/PR notifications in the
main "unread" tab instead of a separate tab:

- Create UnifiedNotification wrapper struct to handle both types
- Merge both notification types into a single sorted list
- Update template to render both types inline
- Combine counts for accurate total unread badge
- Update status handler to support both notification types
- Update purge to mark both types as read
- Remove separate release notification routes and templates
fix: compute total notification count in Go instead of template
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m11s
testing / backend-checks (pull_request) Has been cancelled
testing / security-check (pull_request) Has been cancelled
testing / test-e2e (pull_request) Has been cancelled
testing / test-remote-cacher (redis) (pull_request) Has been cancelled
testing / test-sqlite (pull_request) Has been cancelled
testing / test-remote-cacher (valkey) (pull_request) Has been cancelled
testing / test-remote-cacher (garnet) (pull_request) Has been cancelled
testing / test-remote-cacher (redict) (pull_request) Has been cancelled
testing / test-mysql (pull_request) Has been cancelled
testing / test-pgsql (pull_request) Has been cancelled
testing / test-unit (pull_request) Has been cancelled
5072284dee
The template 'add' function doesn't exist in Forgejo. Move the
addition to the Go middleware where we already have access to
both counts.
fix: include release notifications in navbar bell icon count
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m54s
testing / backend-checks (pull_request) Failing after 8m53s
testing / test-unit (pull_request) Has been skipped
testing / test-e2e (pull_request) Has been skipped
testing / test-mysql (pull_request) Has been skipped
testing / test-remote-cacher (garnet) (pull_request) Has been skipped
testing / test-remote-cacher (valkey) (pull_request) Has been skipped
testing / test-remote-cacher (redis) (pull_request) Has been skipped
testing / test-pgsql (pull_request) Has been skipped
testing / test-sqlite (pull_request) Has been skipped
testing / test-remote-cacher (redict) (pull_request) Has been skipped
testing / security-check (pull_request) Has been skipped
268d1cd2f0
Update the navbar template to use TotalNotificationUnreadCount
which includes both issue and release notifications, with a
fallback to NotificationUnreadCount for compatibility.
pat-s force-pushed feat/granular-watch-settings-clean from 9865d928df to 5bd5120155 2026-02-15 21:25:44 +00:00 Compare
pat-s force-pushed feat/granular-watch-settings-clean from 5bd5120155 to 4bc223f9a6 2026-02-15 21:55:20 +00:00 Compare
pat-s force-pushed feat/granular-watch-settings-clean from 4bc223f9a6 to fb8c00f91a 2026-02-15 22:21:28 +00:00 Compare
pat-s force-pushed feat/granular-watch-settings-clean from fb8c00f91a to f773312e9f 2026-02-15 22:40:46 +00:00 Compare
pat-s force-pushed feat/granular-watch-settings-clean from f773312e9f to 0046536529 2026-02-15 23:27:07 +00:00 Compare
Merge branch 'v14.0/forgejo-codefloe' into feat/granular-watch-settings-clean
Some checks failed
testing / frontend-checks (pull_request) Failing after 2m13s
testing / backend-checks (pull_request) Failing after 8m59s
testing / test-e2e (pull_request) Has been skipped
testing / test-mysql (pull_request) Has been skipped
testing / test-unit (pull_request) Has been skipped
testing / test-pgsql (pull_request) Has been skipped
testing / test-sqlite (pull_request) Has been skipped
testing / test-remote-cacher (redis) (pull_request) Has been skipped
testing / test-remote-cacher (garnet) (pull_request) Has been skipped
testing / test-remote-cacher (valkey) (pull_request) Has been skipped
testing / test-remote-cacher (redict) (pull_request) Has been skipped
testing / security-check (pull_request) Has been skipped
a1260298c1
pat-s force-pushed feat/granular-watch-settings-clean from 8b5918e139
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m52s
testing / backend-checks (pull_request) Failing after 9m0s
testing / test-unit (pull_request) Has been skipped
testing / test-e2e (pull_request) Has been skipped
testing / test-pgsql (pull_request) Has been skipped
testing / test-sqlite (pull_request) Has been skipped
testing / test-mysql (pull_request) Has been skipped
testing / test-remote-cacher (redis) (pull_request) Has been skipped
testing / test-remote-cacher (valkey) (pull_request) Has been skipped
testing / test-remote-cacher (redict) (pull_request) Has been skipped
testing / test-remote-cacher (garnet) (pull_request) Has been skipped
testing / security-check (pull_request) Has been skipped
to c3dfe52114
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m48s
testing / backend-checks (pull_request) Failing after 4m25s
testing / test-unit (pull_request) Has been skipped
testing / test-e2e (pull_request) Has been skipped
testing / test-mysql (pull_request) Has been skipped
testing / test-pgsql (pull_request) Has been skipped
testing / test-sqlite (pull_request) Has been skipped
testing / test-remote-cacher (redis) (pull_request) Has been skipped
testing / test-remote-cacher (garnet) (pull_request) Has been skipped
testing / test-remote-cacher (valkey) (pull_request) Has been skipped
testing / test-remote-cacher (redict) (pull_request) Has been skipped
testing / security-check (pull_request) Has been skipped
2026-03-01 12:11:09 +00:00
Compare
pat-s force-pushed feat/granular-watch-settings-clean from c3dfe52114
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m48s
testing / backend-checks (pull_request) Failing after 4m25s
testing / test-unit (pull_request) Has been skipped
testing / test-e2e (pull_request) Has been skipped
testing / test-mysql (pull_request) Has been skipped
testing / test-pgsql (pull_request) Has been skipped
testing / test-sqlite (pull_request) Has been skipped
testing / test-remote-cacher (redis) (pull_request) Has been skipped
testing / test-remote-cacher (garnet) (pull_request) Has been skipped
testing / test-remote-cacher (valkey) (pull_request) Has been skipped
testing / test-remote-cacher (redict) (pull_request) Has been skipped
testing / security-check (pull_request) Has been skipped
to ea6aa13761
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m52s
testing / backend-checks (pull_request) Failing after 9m1s
testing / test-unit (pull_request) Has been skipped
testing / test-pgsql (pull_request) Has been skipped
testing / test-e2e (pull_request) Has been skipped
testing / test-mysql (pull_request) Has been skipped
testing / test-sqlite (pull_request) Has been skipped
testing / test-remote-cacher (redis) (pull_request) Has been skipped
testing / test-remote-cacher (garnet) (pull_request) Has been skipped
testing / test-remote-cacher (redict) (pull_request) Has been skipped
testing / test-remote-cacher (valkey) (pull_request) Has been skipped
testing / security-check (pull_request) Has been skipped
2026-03-02 15:17:49 +00:00
Compare
fix: render WatchesParticipating and excluded users on initial page load
Some checks failed
testing / frontend-checks (pull_request) Successful in 2m7s
testing / backend-checks (pull_request) Failing after 9m38s
testing / test-unit (pull_request) Has been skipped
testing / test-e2e (pull_request) Has been skipped
testing / test-mysql (pull_request) Has been skipped
testing / test-sqlite (pull_request) Has been skipped
testing / test-pgsql (pull_request) Has been skipped
testing / test-remote-cacher (garnet) (pull_request) Has been skipped
testing / test-remote-cacher (redis) (pull_request) Has been skipped
testing / test-remote-cacher (valkey) (pull_request) Has been skipped
testing / test-remote-cacher (redict) (pull_request) Has been skipped
testing / security-check (pull_request) Has been skipped
a67ba15969
The watch settings dropdown was missing WatchesParticipating, ExcludedUserIDs, and ExcludedUsers template data during the initial repo page load (in RepoAssignment). These were only set in loadWatchContext which is called by htmx action handlers, not on full page renders. This caused the "Participating and @mentions" checkbox to always appear unchecked on page load, even when enabled in the database, leading to stale watch_events values when other checkboxes were toggled.

Also fixes the ExcludedUserIDs xorm column name mapping (GonicMapper was mapping it to excluded_user_i_ds instead of excluded_user_ids) by adding an explicit column name tag.

Removes temporary debug logging from notification creation and UI notification handlers.
Add unit tests for FilterUserIDsByWatchParticipating and GetRepoWatchersIDsForEvent to verify event-based filtering with varied watch_events bitmasks. Add unit tests for UpdateWatchSettings covering new watch creation, event updates, and excluded user ID storage. Add integration test for the watch settings form round-trip to prevent regressions on the WatchesParticipating template data bug.
fmt
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m58s
testing / backend-checks (pull_request) Failing after 8m52s
testing / test-unit (pull_request) Has been skipped
testing / test-mysql (pull_request) Has been skipped
testing / test-e2e (pull_request) Has been skipped
testing / test-pgsql (pull_request) Has been skipped
testing / test-sqlite (pull_request) Has been skipped
testing / test-remote-cacher (garnet) (pull_request) Has been skipped
testing / test-remote-cacher (redict) (pull_request) Has been skipped
testing / test-remote-cacher (valkey) (pull_request) Has been skipped
testing / test-remote-cacher (redis) (pull_request) Has been skipped
testing / security-check (pull_request) Has been skipped
fce1a6fea5
lint
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m55s
testing / backend-checks (pull_request) Failing after 9m24s
testing / test-unit (pull_request) Has been skipped
testing / test-e2e (pull_request) Has been skipped
testing / test-mysql (pull_request) Has been skipped
testing / test-sqlite (pull_request) Has been skipped
testing / test-pgsql (pull_request) Has been skipped
testing / test-remote-cacher (redis) (pull_request) Has been skipped
testing / test-remote-cacher (valkey) (pull_request) Has been skipped
testing / test-remote-cacher (garnet) (pull_request) Has been skipped
testing / test-remote-cacher (redict) (pull_request) Has been skipped
testing / security-check (pull_request) Has been skipped
71f778b376
chore: remove dead code flagged by deadcode linter
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m52s
testing / backend-checks (pull_request) Failing after 13m19s
testing / test-e2e (pull_request) Has been skipped
testing / test-unit (pull_request) Has been skipped
testing / test-pgsql (pull_request) Has been skipped
testing / test-sqlite (pull_request) Has been skipped
testing / test-mysql (pull_request) Has been skipped
testing / test-remote-cacher (redis) (pull_request) Has been skipped
testing / test-remote-cacher (valkey) (pull_request) Has been skipped
testing / test-remote-cacher (redict) (pull_request) Has been skipped
testing / test-remote-cacher (garnet) (pull_request) Has been skipped
testing / security-check (pull_request) Has been skipped
19518fd80a
Remove unused CreateReleaseNotification (only the batch variant CreateReleaseNotificationsForUsers is called) and unused GetRepoWatchersIDs (superseded by GetRepoWatchersIDsForEvent).
pat-s force-pushed feat/granular-watch-settings-clean from b795770d83
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m48s
testing / backend-checks (pull_request) Successful in 15m42s
testing / test-unit (pull_request) Failing after 15m22s
testing / test-remote-cacher (valkey) (pull_request) Has been skipped
testing / test-remote-cacher (redis) (pull_request) Has been skipped
testing / test-remote-cacher (garnet) (pull_request) Has been skipped
testing / test-remote-cacher (redict) (pull_request) Has been skipped
testing / test-sqlite (pull_request) Failing after 34m1s
testing / test-mysql (pull_request) Failing after 34m37s
testing / test-e2e (pull_request) Successful in 34m55s
testing / test-pgsql (pull_request) Failing after 36m11s
testing / security-check (pull_request) Has been skipped
to c14ab9d14d
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m52s
testing / backend-checks (pull_request) Successful in 15m29s
testing / test-unit (pull_request) Failing after 8m17s
testing / test-remote-cacher (redis) (pull_request) Has been skipped
testing / test-remote-cacher (garnet) (pull_request) Has been skipped
testing / test-remote-cacher (valkey) (pull_request) Has been skipped
testing / test-remote-cacher (redict) (pull_request) Has been skipped
testing / security-check (pull_request) Has been cancelled
testing / test-pgsql (pull_request) Has been cancelled
testing / test-sqlite (pull_request) Has been cancelled
testing / test-e2e (pull_request) Has been cancelled
testing / test-mysql (pull_request) Has been cancelled
2026-03-02 20:39:43 +00:00
Compare
fix: update TestRepoGetReviewers unit test for new watch fixtures
Some checks failed
testing / frontend-checks (pull_request) Successful in 1m59s
testing / backend-checks (pull_request) Successful in 15m23s
testing / test-unit (pull_request) Successful in 15m23s
testing / test-remote-cacher (redis) (pull_request) Successful in 5m28s
testing / test-remote-cacher (garnet) (pull_request) Successful in 5m33s
testing / test-remote-cacher (redict) (pull_request) Successful in 5m33s
testing / test-remote-cacher (valkey) (pull_request) Successful in 5m55s
testing / test-sqlite (pull_request) Successful in 32m55s
testing / test-mysql (pull_request) Successful in 34m27s
testing / test-e2e (pull_request) Successful in 34m50s
testing / test-pgsql (pull_request) Successful in 36m6s
testing / security-check (pull_request) Failing after 3m27s
501fac93e9
New watchers (user13, user14) on repo1 appear as eligible reviewers in the public repo reviewer query.
**Backport:** https://codeberg.org/forgejo/forgejo/pulls/11179

As noted in https://codeberg.org/forgejo/forgejo/issues/10900#issuecomment-10339634, `TestAPICreateIssueParallel` is failing intermittently in Forgejo CI.  Based upon this intermittent failure, I've made these changes:
- Increase the parallel run of the test from 10 instances to 100, which caused this test to fail consistently and reliably on my dev workstation.  The test execution time at 100 parallel invocations is only ~4 seconds.
- Increase the default `SQLITE_TIMEOUT` from 500ms to 60s, which caused this test to succeed consistently in CI.

Co-authored-by: Mathieu Fenniak <mathieu@fenniak.net>
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11220
Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org>
Reviewed-by: Michael Kriese <michael.kriese@gmx.de>
Co-authored-by: forgejo-backport-action <forgejo-backport-action@noreply.codeberg.org>
Co-committed-by: forgejo-backport-action <forgejo-backport-action@noreply.codeberg.org>
**Backport:** #11164

Manual backport required due to conflicts with recent workflow expansion work.

(cherry picked from commit c7d23fa6e8)

<!--start release-notes-assistant-->

## Release notes
<!--URL:https://codeberg.org/forgejo/forgejo-->
- Bug fixes
  - [PR](https://codeberg.org/forgejo/forgejo/pulls/11166): <!--number 11166 --><!--line 0 --><!--description Zml4OiB3aGVuIGV4cGFuZGluZyBhIGR5bmFtaWMgbWF0cml4LCBvcmlnaW5hbCAnbmVlZHMnIGFjY2VzcyB3YXMgbG9zdA==-->fix: when expanding a dynamic matrix, original 'needs' access was lost<!--description-->
<!--end release-notes-assistant-->

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11166
Reviewed-by: Andreas Ahlenstorf <aahlenst@noreply.codeberg.org>
Co-authored-by: Mathieu Fenniak <mathieu@fenniak.net>
Co-committed-by: Mathieu Fenniak <mathieu@fenniak.net>
**Backport:** https://codeberg.org/forgejo/forgejo/pulls/11287

Fix #11266

Co-authored-by: panc <pan0xc@foxmail.com>
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11327
Reviewed-by: 0ko <0ko@noreply.codeberg.org>
Co-authored-by: forgejo-backport-action <forgejo-backport-action@noreply.codeberg.org>
Co-committed-by: forgejo-backport-action <forgejo-backport-action@noreply.codeberg.org>
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11397
Reviewed-by: Michael Kriese <michael.kriese@gmx.de>
Co-authored-by: Renovate Bot <bot@kriese.eu>
Co-committed-by: Renovate Bot <bot@kriese.eu>
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11398
Reviewed-by: Gusted <gusted@noreply.codeberg.org>
Reviewed-by: Michael Kriese <michael.kriese@gmx.de>
Co-authored-by: Renovate Bot <bot@kriese.eu>
Co-committed-by: Renovate Bot <bot@kriese.eu>
Unable to backport to v14 currently due to govulncheck ([example](https://codeberg.org/forgejo/forgejo/actions/runs/138106/jobs/11/attempt/2)).

#11396 was already opened and merged in v11, but v14 is currently blocked.

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11412
Reviewed-by: 0ko <0ko@noreply.codeberg.org>
Co-authored-by: Mathieu Fenniak <mathieu@fenniak.net>
Co-committed-by: Mathieu Fenniak <mathieu@fenniak.net>
**Backport:** https://codeberg.org/forgejo/forgejo/pulls/11246

This change fixes an issue that makes Forgejo clean up too many versions of a container package even though it should keep them according to the rules set for the package.

The issue affects multi-platform container images.
Forgejo adds a package version for each platform (for example `linux/amd64`, `linux/arm64`) in addition to the actual tag (for example `0.6.0` or `latest`).

This results in rows in the table `package_version` similar to this (unimportant columns omitted for brevity):

| **lower_version** | **created_unix** |
|---|---|
| `latest` | `1768742887`|
| `0.6.0` | `1768742886` |
| `sha256:038e...` | `1768742886` |
| `sha256:fc38...` | `1768742886` |
| `0.5.0` | `1768742864` |
| `sha256:806d...` | `1768742864` |
| `sha256:0a19...` | `1768742864` |
| `0.4.0` | `1768742848` |
| `...` | `...` |

The code assumes that the first `<keep count>` entries can be ignored and considers every entry after `<keep count>` as eligible for cleanup.
That doesn't work for multi-platform container images because, for `<keep count>=5`, it considers version `0.4.0` as eligible.

## Checklist

The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. There also are a few [conditions for merging Pull Requests in Forgejo repositories](https://codeberg.org/forgejo/governance/src/branch/main/PullRequestsAgreement.md). You are also welcome to join the [Forgejo development chatroom](https://matrix.to/#/#forgejo-development:matrix.org).

### Tests

- I added test coverage for Go changes...
  - [x] in their respective `*_test.go` for unit tests.
  - [ ] in the `tests/integration` directory if it involves interactions with a live Forgejo server.
- I added test coverage for JavaScript changes...
  - [ ] in `web_src/js/*.test.js` if it can be unit tested.
  - [ ] in `tests/e2e/*.test.e2e.js` if it requires interactions with a live Forgejo server (see also the [developer guide for JavaScript testing](https://codeberg.org/forgejo/forgejo/src/branch/forgejo/tests/e2e/README.md#end-to-end-tests)).

### Documentation

- [ ] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change.
- [x] I did not document these changes and I do not expect someone else to do it.

### Release notes

- [x] This change will be noticed by a Forgejo user or admin (feature, bug fix, performance, etc.). I suggest to include a release note for this change.
- [ ] This change is not visible to a Forgejo user or admin (refactor, dependency upgrade, etc.). I think there is no need to add a release note for this change.

*The decision if the pull request will be shown in the release notes is up to the mergers / release team.*

The content of the `release-notes/<pull request number>.md` file will serve as the basis for the release notes. If the file does not exist, the title of the pull request will be used instead.

<!--start release-notes-assistant-->

## Release notes
<!--URL:https://codeberg.org/forgejo/forgejo-->
- Bug fixes
  - [PR](https://codeberg.org/forgejo/forgejo/pulls/11246): <!--number 11246 --><!--line 0 --><!--description Y2xlYW51cCBvZiBtdWx0aS1wbGF0Zm9ybSBjb250YWluZXIgaW1hZ2Vz-->cleanup of multi-platform container images<!--description-->
<!--end release-notes-assistant-->

Co-authored-by: wandhydrant <wandhydrant@noreply.codeberg.org>
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11254
Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org>
Co-authored-by: forgejo-backport-action <forgejo-backport-action@noreply.codeberg.org>
Co-committed-by: forgejo-backport-action <forgejo-backport-action@noreply.codeberg.org>
Backport of forgejo/forgejo!11280

- ensure we use the defined node version on ci, so renovate and ci use same version
- fix lockfile to match npm version
- add some debugging to ci

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11467
Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org>
Reviewed-by: 0ko <0ko@noreply.codeberg.org>
Co-authored-by: Gusted <postmaster@gusted.xyz>
Co-committed-by: Gusted <postmaster@gusted.xyz>
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11464
Reviewed-by: Gusted <gusted@noreply.codeberg.org>
Co-authored-by: Renovate Bot <bot@kriese.eu>
Co-committed-by: Renovate Bot <bot@kriese.eu>
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11415
Reviewed-by: Gusted <gusted@noreply.codeberg.org>
Co-authored-by: Renovate Bot <bot@kriese.eu>
Co-committed-by: Renovate Bot <bot@kriese.eu>
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11475
Reviewed-by: Michael Kriese <michael.kriese@gmx.de>
Co-authored-by: Renovate Bot <bot@kriese.eu>
Co-committed-by: Renovate Bot <bot@kriese.eu>
Merge branch 'v14.0/forgejo' of https://codeberg.org/forgejo/forgejo into feat/granular-watch-settings-clean
All checks were successful
Integration tests for the release process / release-simulation (push) Has been skipped
testing / test-unit (pull_request) Successful in 16m22s
testing / frontend-checks (pull_request) Successful in 1m49s
testing / backend-checks (pull_request) Successful in 16m44s
testing / test-remote-cacher (redis) (pull_request) Successful in 2m47s
testing / test-remote-cacher (valkey) (pull_request) Successful in 5m3s
testing / test-mysql (pull_request) Successful in 36m48s
testing / test-remote-cacher (garnet) (pull_request) Successful in 3m7s
testing / test-e2e (pull_request) Successful in 37m36s
testing / test-remote-cacher (redict) (pull_request) Successful in 3m12s
testing / test-sqlite (pull_request) Successful in 37m29s
testing / test-pgsql (pull_request) Successful in 55m1s
testing / security-check (pull_request) Successful in 3m43s
6d6599d432
upd license headers
All checks were successful
testing / frontend-checks (pull_request) Successful in 1m53s
testing / backend-checks (pull_request) Successful in 15m27s
testing / test-unit (pull_request) Successful in 8m31s
testing / test-remote-cacher (garnet) (pull_request) Successful in 5m29s
testing / test-mysql (pull_request) Successful in 29m9s
testing / test-sqlite (pull_request) Successful in 41m56s
testing / test-pgsql (pull_request) Successful in 47m5s
testing / test-remote-cacher (valkey) (pull_request) Successful in 4m57s
testing / test-remote-cacher (redis) (pull_request) Successful in 5m18s
testing / test-remote-cacher (redict) (pull_request) Successful in 5m16s
testing / test-e2e (pull_request) Successful in 28m28s
testing / security-check (pull_request) Successful in 2m20s
issue-labels / backporting (pull_request_target) Has been skipped
milestone / set (pull_request_target) Has been skipped
047d4816bc
pat-s merged commit b54ffb340e into v14.0/forgejo-codefloe 2026-03-03 09:22:20 +00:00
pat-s deleted branch feat/granular-watch-settings-clean 2026-03-03 09:22:21 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
codefloe/forgejo-codefloe!21
No description provided.