Skip to content

Commit f8600a4

Browse files
committed
PR feedback - coderabbit
1 parent 85d3e37 commit f8600a4

File tree

9 files changed

+118
-14
lines changed

9 files changed

+118
-14
lines changed

backend/__tests__/cache.tickets.spec.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,39 @@ describe('cache', function () {
186186
})
187187
})
188188

189+
describe('#getIssuesForShoot', function () {
190+
it('should return issues matching projectName and name', function () {
191+
const result = cache.getIssuesForShoot({ projectName: 'test', name: 'foo' })
192+
expect(result).toEqual([firstIssue, secondIssue])
193+
expect(emitSpy).not.toHaveBeenCalled()
194+
})
195+
196+
it('should return empty array for unknown shoot', function () {
197+
const result = cache.getIssuesForShoot({ projectName: 'test', name: 'unknown' })
198+
expect(result).toEqual([])
199+
})
200+
201+
it('should update index when issue is removed', function () {
202+
cache.removeIssue({ issue: firstIssue })
203+
const result = cache.getIssuesForShoot({ projectName: 'test', name: 'foo' })
204+
expect(result).toEqual([secondIssue])
205+
})
206+
207+
it('should update index when issue is updated with new shoot', function () {
208+
const updatedIssue = {
209+
metadata: {
210+
number: 1,
211+
updated_at: new Date(Date.now() + 60000).toISOString(),
212+
name: 'bar',
213+
projectName: 'test',
214+
},
215+
}
216+
cache.addOrUpdateIssue({ issue: updatedIssue })
217+
expect(cache.getIssuesForShoot({ projectName: 'test', name: 'foo' })).toEqual([secondIssue])
218+
expect(cache.getIssuesForShoot({ projectName: 'test', name: 'bar' })).toEqual([thirdIssue, updatedIssue])
219+
})
220+
})
221+
189222
describe('#getCommentsForIssue', function () {
190223
it('should return the all comments for the first issue', function () {
191224
const comments = cache.getCommentsForIssue({ issueNumber: 1 })

backend/__tests__/hooks.spec.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ describe('hooks', () => {
112112
hooks.constructor.createInformers = mockCreateInformers = vi.fn(() => informers)
113113
cache.initialize = vi.fn()
114114
cache.indexProjectsByNamespace = vi.fn()
115+
cache.indexShootsBySeedName = vi.fn()
115116
cache.getTicketCache = vi.fn(() => ticketCache)
116117
io.mockReturnValue(ioInstance)
117118
})
@@ -136,6 +137,9 @@ describe('hooks', () => {
136137
expect(cache.indexProjectsByNamespace).toHaveBeenCalledTimes(1)
137138
expect(cache.indexProjectsByNamespace.mock.calls[0]).toEqual([informers.projects])
138139

140+
expect(cache.indexShootsBySeedName).toHaveBeenCalledTimes(1)
141+
expect(cache.indexShootsBySeedName.mock.calls[0]).toEqual([informers.shoots])
142+
139143
expect(io).toHaveBeenCalledTimes(1)
140144
expect(io.mock.calls[0]).toEqual([server, expect.anything()])
141145

backend/__tests__/io.seedstats.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ describe('io/seedstats', () => {
6161
},
6262
}
6363

64-
expect(() => getJoinedRooms(nsp)).toThrow(new TypeError('Invalid seedstats room: invalid-room'))
64+
expect(() => getJoinedRooms(nsp, { seedName: 'seed-1' })).toThrow(new TypeError('Invalid seedstats room: invalid-room'))
6565
})
6666

6767
it('should reject unauthorized seedstats subscriptions', async () => {

backend/__tests__/services.seedstats.spec.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,16 @@ describe('services/seedstats', () => {
113113
]
114114

115115
const ticketCache = {
116-
getIssues: vi.fn(() => issues),
116+
getIssuesForShoot: vi.fn(({ name, projectName }) =>
117+
issues.filter(issue => issue.metadata.projectName === projectName && issue.metadata.name === name),
118+
),
117119
}
118120

119121
beforeEach(() => {
120122
vi.resetAllMocks()
121-
ticketCache.getIssues.mockReturnValue(issues)
123+
ticketCache.getIssuesForShoot.mockImplementation(({ name, projectName }) =>
124+
issues.filter(issue => issue.metadata.projectName === projectName && issue.metadata.name === name),
125+
)
122126
config.frontend.ticket = {
123127
hideClustersWithLabels: ['suppress'],
124128
}

backend/lib/cache/tickets.js

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,13 @@ import EventEmitter from 'events'
88
import _ from 'lodash-es'
99
import logger from '../logger/index.js'
1010

11+
function shootKey (projectName, name) {
12+
return JSON.stringify([projectName, name])
13+
}
14+
1115
function init () {
1216
const issues = new Map()
17+
const issuesByShoot = new Map() // Map<shootKey, Map<issueNumber, issue>>
1318
const commentsForIssues = new Map() // we could also think of getting rid of the comments cache
1419
const emitter = new EventEmitter()
1520

@@ -55,11 +60,19 @@ function init () {
5560
}
5661

5762
function getIssueNumbersForNameAndProjectName ({ name, projectName }) {
58-
return _
59-
.chain(getIssues())
60-
.filter(_.matches({ metadata: { name, projectName } }))
61-
.map('metadata.number')
62-
.value()
63+
const map = issuesByShoot.get(shootKey(projectName, name))
64+
if (!map) {
65+
return []
66+
}
67+
return Array.from(map.keys())
68+
}
69+
70+
function getIssuesForShoot ({ name, projectName }) {
71+
const map = issuesByShoot.get(shootKey(projectName, name))
72+
if (!map) {
73+
return []
74+
}
75+
return Array.from(map.values())
6376
}
6477

6578
function getCommentsForIssueCache ({ issueNumber }) {
@@ -76,7 +89,14 @@ function init () {
7689
}
7790

7891
function addOrUpdateIssue ({ issue }) {
92+
const number = issue.metadata.number
93+
const oldIssue = issues.get(number)
94+
if (oldIssue) {
95+
removeFromShootIndex(oldIssue)
96+
}
7997
updateIfNewer('issue', issues, issue)
98+
// Re-read from issues map — updateIfNewer may have kept the old item if it was newer
99+
addToShootIndex(issues.get(number))
80100
}
81101

82102
function addOrUpdateComment ({ issueNumber, comment }) {
@@ -88,6 +108,11 @@ function init () {
88108
const issueNumber = issue.metadata.number
89109
logger.trace('removing issue', issueNumber, 'and comments')
90110

111+
const cachedIssue = issues.get(issueNumber)
112+
if (cachedIssue) {
113+
removeFromShootIndex(cachedIssue)
114+
}
115+
91116
const comments = getCommentsForIssueCache({ issueNumber })
92117

93118
issues.delete(issueNumber)
@@ -107,6 +132,36 @@ function init () {
107132
emitCommmentDeleted(comment)
108133
}
109134

135+
function addToShootIndex (issue) {
136+
const { projectName, name, number } = issue?.metadata ?? {}
137+
if (!projectName || !name) {
138+
return
139+
}
140+
const key = shootKey(projectName, name)
141+
let map = issuesByShoot.get(key)
142+
if (!map) {
143+
map = new Map()
144+
issuesByShoot.set(key, map)
145+
}
146+
map.set(number, issue)
147+
}
148+
149+
function removeFromShootIndex (issue) {
150+
const { projectName, name, number } = issue?.metadata ?? {}
151+
if (!projectName || !name) {
152+
return
153+
}
154+
const key = shootKey(projectName, name)
155+
const map = issuesByShoot.get(key)
156+
if (!map) {
157+
return
158+
}
159+
map.delete(number)
160+
if (map.size === 0) {
161+
issuesByShoot.delete(key)
162+
}
163+
}
164+
110165
function updateIfNewer (kind, cachedMap, item) {
111166
const identifier = kind === 'issue'
112167
? item.metadata.number
@@ -142,6 +197,7 @@ function init () {
142197
getCommentsForIssue,
143198
getIssueNumbers,
144199
getIssueNumbersForNameAndProjectName,
200+
getIssuesForShoot,
145201
addOrUpdateIssues,
146202
addOrUpdateIssue,
147203
addOrUpdateComment,

backend/lib/io/seedstats.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,12 @@ function parseRoomName (room) {
7676
throw new TypeError(`Invalid seedstats room: ${room}`)
7777
}
7878

79-
function getJoinedRooms (nsp, { seedName } = {}) {
79+
function getJoinedRooms (nsp, { seedName }) {
80+
if (!seedName) {
81+
logger.warn('getJoinedRooms called without seedName')
82+
return []
83+
}
84+
8085
const adapterRooms = nsp?.adapter?.rooms
8186
if (!adapterRooms) {
8287
return []

backend/lib/services/seedstats.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,8 +251,7 @@ function getTicketsForShoot (shoot) {
251251

252252
return cache
253253
.getTicketCache()
254-
.getIssues()
255-
.filter(issue => issue?.metadata?.projectName === projectName && issue?.metadata?.name === shootName)
254+
.getIssuesForShoot({ projectName, name: shootName })
256255
}
257256

258257
function getProjectNameForShoot (shoot) {

frontend/src/composables/useApi/api.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,9 @@ export function getSeedStats ({ unhealthyFilterMask } = {}) {
259259
}
260260

261261
export function getSeedStat ({ name, unhealthyFilterMask } = {}) {
262+
if (!name) {
263+
throw new TypeError('getSeedStat requires a name parameter')
264+
}
262265
name = encodeURIComponent(name)
263266
return getResource(withQuery(`/api/seedstats/${name}`, {
264267
unhealthyFilterMask,

frontend/src/composables/useSeedItem/index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,9 +254,9 @@ export function useSeedStats (seedItem) {
254254
const seedName = computed(() => get(seedItem.value, ['metadata', 'name']))
255255
const seedStat = computed(() => seedStatStore.statByName(seedName.value))
256256

257-
const seedShootCount = computed(() => seedStat.value?.counts?.shootCount ?? 0)
258-
const seedTotalUnhealthyShoots = computed(() => seedStat.value?.counts?.unhealthyShoots?.total ?? 0)
259-
const seedUnhealthyShoots = computed(() => seedStat.value?.counts?.unhealthyShoots?.matching ?? 0)
257+
const seedShootCount = computed(() => seedStat.value?.counts?.shootCount)
258+
const seedTotalUnhealthyShoots = computed(() => seedStat.value?.counts?.unhealthyShoots?.total)
259+
const seedUnhealthyShoots = computed(() => seedStat.value?.counts?.unhealthyShoots?.matching)
260260

261261
return {
262262
seedShootCount,

0 commit comments

Comments
 (0)