1 Commits

Author SHA256 Message Date
Andrii Nikitin
6feb04a14d common: fix timeline cache race condition and update logic
All checks were successful
go-generate-check / go-generate-check (pull_request) Successful in 14s
Integration tests / t (pull_request) Successful in 8m21s
The GetTimeline function previously used a strict timestamp comparison
(Created > LastCachedTime) to fetch new events. This caused the bot to
miss events occurring within the same second as the last update.

This change:
- Switches to ID-based deduplication to safely handle same-second events.
- Correctly updates existing timeline items if they are modified.
- Calculates the next 'Since' parameter using the maximum 'Updated'
  timestamp found in the current cache.

This fixes flakiness in integration tests (specifically test_006) where
maintainer rejections were occasionally ignored by the workflow-pr service.
2026-03-04 12:11:35 +01:00
3 changed files with 16 additions and 12 deletions

View File

@@ -863,9 +863,10 @@ func (gitea *GiteaTransport) GetTimeline(org, repo string, idx int64) ([]*models
TimelineCache, IsCached := giteaTimelineCache[prID]
var LastCachedTime strfmt.DateTime
if IsCached {
l := len(TimelineCache.data)
if l > 0 {
LastCachedTime = TimelineCache.data[0].Updated
for _, d := range TimelineCache.data {
if time.Time(d.Updated).Compare(time.Time(LastCachedTime)) > 0 {
LastCachedTime = d.Updated
}
}
// cache data for 5 seconds
@@ -894,14 +895,20 @@ func (gitea *GiteaTransport) GetTimeline(org, repo string, idx int64) ([]*models
}
for _, d := range res.Payload {
if d != nil {
if time.Time(d.Created).Compare(time.Time(LastCachedTime)) > 0 {
// created after last check, so we append here
TimelineCache.data = append(TimelineCache.data, d)
} else {
// we need something updated in the timeline, maybe
if d == nil {
continue
}
found := false
for i := range TimelineCache.data {
if TimelineCache.data[i].ID == d.ID {
TimelineCache.data[i] = d
found = true
break
}
}
if !found {
TimelineCache.data = append(TimelineCache.data, d)
}
}
if resCount < 10 {

View File

@@ -139,7 +139,6 @@ index 0000000..e69de29
@pytest.mark.t005
# @pytest.mark.xfail(reason="TBD troubleshoot")
def test_005_any_maintainer_approval_sufficient(maintainer_env, ownerA_client, ownerBB_client):
"""
Test scenario:
@@ -201,7 +200,6 @@ index 0000000..e69de29
@pytest.mark.t006
@pytest.mark.xfail(reason="tbd flacky in ci")
def test_006_maintainer_rejection_removes_other_requests(maintainer_env, ownerA_client, ownerBB_client):
"""
Test scenario:

View File

@@ -54,7 +54,6 @@ This is the ProjectGit config file. For runtime config file, see bottom.
| *GitProjectName* | Repository and branch where the ProjectGit lives. | no | string | **Format**: `org/project_repo#branch` | By default assumes `_ObsPrj` with default branch in the *Organization* |
| *ManualMergeOnly* | Merges are permitted only upon receiving a "merge ok" comment from designated maintainers in the PkgGit PR. | no | bool | true, false | false |
| *ManualMergeProject* | Merges are permitted only upon receiving a "merge ok" comment in the ProjectGit PR from project maintainers. | no | bool | true, false | false |
| *MergeMode* | Type of package merge accepted. See below for details. | no | string | ff-only, replace, devel | ff-only |
| *ReviewRequired* | If submitter is a maintainer, require review from another maintainer if available. | no | bool | true, false | false |
| *NoProjectGitPR* | Do not create PrjGit PR, but still perform other tasks. | no | bool | true, false | false |
| *Reviewers* | PrjGit reviewers. Additional review requests are triggered for associated PkgGit PRs. PrjGit PR is merged only when all reviews are complete. | no | array of strings | | `[]` |