Skip to content

Commit 41a668c

Browse files
committed
fix: Fixed maintainer testing and wrong author display
1 parent 03bc411 commit 41a668c

File tree

7 files changed

+346
-45
lines changed

7 files changed

+346
-45
lines changed

lib/api/Confluence.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ export class Confluence {
125125
const documentInfo = new DocumentInfo(
126126
documentId,
127127
author,
128-
lastVersionDate,
128+
(lastVersionDate as Moment).toISOString(),
129129
lastVersionMessage,
130130
title,
131131
path,

lib/api/DocumentInfo.ts

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Moment } from 'moment'
1+
import { Maintainer } from './Maintainer'
22

33
/**
44
* Informations about a Confluence document
@@ -23,7 +23,7 @@ export interface DocumentInfo {
2323
/**
2424
* The date of the last version
2525
*/
26-
lastVersionDate: Moment | string
26+
lastVersionDate: string
2727
/**
2828
* The edit message of the last version
2929
*/
@@ -38,12 +38,19 @@ export interface DocumentInfo {
3838
* @param regexp
3939
*/
4040
matchesPath(regexp: RegExp): boolean
41+
42+
/**
43+
* Get the notification recipients for this document info. Usually contains of the last author and the
44+
* maintainers
45+
* @param maintainers
46+
*/
47+
getRecipients(maintainers: Maintainer[], domain?: string): string[]
4148
}
4249

4350
export class DocumentInfo implements DocumentInfo {
4451
public id: number
4552
public author: string
46-
public lastVersionDate: Moment | string
53+
public lastVersionDate: string
4754
public lastVersionMessage: string
4855
public title: string
4956
public path: Array<string>
@@ -54,7 +61,7 @@ export class DocumentInfo implements DocumentInfo {
5461
constructor(
5562
id: number,
5663
author: string,
57-
lastVersionDate: Moment,
64+
lastVersionDate: string,
5865
lastVersionMessage: string,
5966
title: string,
6067
path: Array<string>,
@@ -76,4 +83,39 @@ export class DocumentInfo implements DocumentInfo {
7683
public matchesPath(regexp: RegExp): boolean {
7784
return regexp.test(this.path.concat([this.title]).join('/'))
7885
}
86+
87+
public static fromDocumentInfo(documentInfo: DocumentInfo): DocumentInfo {
88+
return new DocumentInfo(
89+
documentInfo.id,
90+
documentInfo.author,
91+
documentInfo.lastVersionDate,
92+
documentInfo.lastVersionMessage,
93+
documentInfo.title,
94+
documentInfo.path,
95+
documentInfo.url,
96+
documentInfo.shortUrl,
97+
documentInfo.labels
98+
)
99+
}
100+
101+
public getRecipients(maintainers: Maintainer[], domain?: string): string[] {
102+
const retval = []
103+
let addLastAuthor = maintainers.length > 0 ? false : true
104+
for (const maintainer of maintainers) {
105+
if (this.matchesPath(maintainer.pagePattern)) {
106+
const maintainers = maintainer.maintainer.split(/,/)
107+
if (maintainers.indexOf('_lastauthor') > 0) {
108+
addLastAuthor = true
109+
}
110+
retval.push(...maintainers.filter((entry) => entry != '_lastauthor'))
111+
}
112+
}
113+
if (addLastAuthor) {
114+
retval.push(this.author)
115+
}
116+
if (domain) {
117+
return retval.map((target) => `${target}@${domain}`)
118+
}
119+
return retval
120+
}
79121
}

lib/api/Notification.ts

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import * as Mail from 'nodemailer/lib/mailer'
55
import { DocumentInfo } from './DocumentInfo'
66
import * as Handlebars from 'handlebars'
77
import { Logger } from 'loglevel'
8-
import { Moment } from 'moment'
98
import log = require('loglevel')
109
import moment = require('moment')
1110

@@ -27,13 +26,17 @@ export class Notification {
2726
}
2827

2928
public async notify(documentInfos: Array<DocumentInfo>): Promise<void> {
29+
const workingDocumentInfos = []
30+
documentInfos.forEach((entry) => {
31+
workingDocumentInfos.push(DocumentInfo.fromDocumentInfo(entry))
32+
})
3033
Handlebars.registerHelper('moment', (text, format) => {
3134
return moment(text).format(format)
3235
})
3336
const subjectTemplate = Handlebars.compile(this._configuration.notificationSubjectTemplate)
3437
const bodyTemplate = Handlebars.compile(this._configuration.notificationBodyTemplate)
3538

36-
process: for (const documentInfo of documentInfos) {
39+
process: for (const documentInfo of workingDocumentInfos) {
3740
for (const exception of this._configuration.exceptions) {
3841
if (documentInfo.matchesPath(exception)) {
3942
this._log.info(`Skipping ${documentInfo.title} because it matches the exception ${exception}`)
@@ -48,20 +51,9 @@ export class Notification {
4851
}
4952
}
5053

51-
documentInfo.lastVersionDate = (documentInfo.lastVersionDate as Moment).toISOString() as string
52-
53-
for (const maintainer of this._configuration.maintainer) {
54-
if (documentInfo.matchesPath(maintainer.pagePattern)) {
55-
documentInfo.author = maintainer.maintainer.replace(/_lastauthor/, documentInfo.author)
56-
}
57-
}
58-
59-
let to = documentInfo.author.split(/,/)
60-
if (this._configuration.domain) {
61-
to = to.map((target) => `${target}@${this._configuration.domain}`)
62-
}
54+
const recipients = documentInfo.getRecipients(this._configuration.maintainer, this._configuration.domain)
6355

64-
for (const recipient of to) {
56+
for (const recipient of recipients) {
6557
if (!(recipient in this._notificationBatch)) {
6658
this._notificationBatch[recipient] = []
6759
}

test/ConfigurationTest.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ describe('The Configuration API', (): void => {
1919
chai.expect(configuration.checks[1].labels).to.contain('test2')
2020
chai.expect(configuration.checks[1].maxAge).to.eq(1234)
2121

22-
chai.expect(configuration.maintainer).to.have.lengthOf(1)
23-
2422
chai.expect(configuration.exceptions).to.have.lengthOf(1)
2523
chai.expect(configuration.excludedLabels).to.have.lengthOf(2)
2624

@@ -38,4 +36,12 @@ describe('The Configuration API', (): void => {
3836

3937
chai.expect(configuration.exceptions).to.have.lengthOf(0)
4038
})
39+
it('should support maintainer configuration', async (): Promise<void> => {
40+
const mockServer = new MockServer('https://example.com')
41+
mockServer.addConfigurationDocumentEndpoint()
42+
43+
const configuration = new Configuration('https://example.com', 'nobody', 'nothing', '12347')
44+
await configuration.load()
45+
chai.expect(configuration.maintainer).to.have.lengthOf(1)
46+
})
4147
})

test/ConfluenceTest.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { Confluence } from '../lib/api/Confluence'
33
import { MockServer } from './MockServer'
44
import chai = require('chai')
55
import chaiAsPromised = require('chai-as-promised')
6-
import { Moment } from 'moment'
76

87
chai.use(chaiAsPromised)
98

@@ -19,14 +18,14 @@ describe('The Confluence API', (): void => {
1918
chai.expect(results[0].shortUrl).to.eq('/display/SAMPLE/Test')
2019
chai.expect(results[0].author).to.eq('author')
2120
chai.expect(results[0].id).to.eq(123)
22-
chai.expect((results[0].lastVersionDate as Moment).toISOString()).to.eq('2019-12-31T22:00:00.000Z')
21+
chai.expect(results[0].lastVersionDate).to.eq('2019-12-31T22:00:00.000Z')
2322
chai.expect(results[0].lastVersionMessage).to.eq('Some change')
2423
chai.expect(results[0].title).to.eq('Test')
2524
chai.expect(results[1].url).to.eq('https://example.com/display/SAMPLE/Test2')
2625
chai.expect(results[1].shortUrl).to.eq('/display/SAMPLE/Test2')
2726
chai.expect(results[1].author).to.eq('author2')
2827
chai.expect(results[1].id).to.eq(234)
29-
chai.expect((results[1].lastVersionDate as Moment).toISOString()).to.eq('2020-01-31T22:00:00.000Z')
28+
chai.expect(results[1].lastVersionDate).to.eq('2020-01-31T22:00:00.000Z')
3029
chai.expect(results[1].lastVersionMessage).to.eq('')
3130
chai.expect(results[1].title).to.eq('Test2')
3231
chai.expect(results[0].labels.length).to.eq(1)

test/MockServer.ts

Lines changed: 157 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,6 @@ export class MockServer {
114114
<th>Pagepattern</th>
115115
<th>Maintainer</th>
116116
</tr>
117-
<tr>
118-
<td>main/Test/.*</td>
119-
<td>maintainer,_lastauthor</td>
120-
</tr>
121117
</tbody>
122118
</table>
123119
</ac:rich-text-body>
@@ -261,6 +257,139 @@ export class MockServer {
261257
</table>
262258
</ac:rich-text-body>
263259
</ac:structured-macro>
260+
<ac:structured-macro ac:name='panel' ac:schema-version='1' ac:macro-id='1d192d60-7e69-4af8-8dd6-4006a7bfc952'>
261+
<ac:parameter ac:name='title'>Maintainer</ac:parameter>
262+
<ac:rich-text-body>
263+
<table class='wrapped'>
264+
<colgroup>
265+
<col/>
266+
<col/>
267+
</colgroup>
268+
<tbody>
269+
<tr>
270+
<th>Pagepattern</th>
271+
<th>Maintainer</th>
272+
</tr>
273+
</tbody>
274+
</table>
275+
</ac:rich-text-body>
276+
</ac:structured-macro>
277+
<ac:structured-macro ac:name='panel' ac:schema-version='1' ac:macro-id='1d192d60-7e69-4af8-8dd6-4006a7bfc952'>
278+
<ac:parameter ac:name='title'>Exceptions</ac:parameter>
279+
<ac:rich-text-body>
280+
<table class='wrapped'>
281+
<colgroup>
282+
<col/>
283+
</colgroup>
284+
<tbody>
285+
<tr>
286+
<th>RegularExpression</th>
287+
</tr>
288+
<tr>
289+
<td></td>
290+
</tr>
291+
</tbody>
292+
</table>
293+
</ac:rich-text-body>
294+
</ac:structured-macro>
295+
<ac:structured-macro ac:name='panel' ac:schema-version='1' ac:macro-id='93f1d981-c841-4cb4-b6e2-5940dfe69132'>
296+
<ac:parameter ac:name='title'>Notification Template</ac:parameter>
297+
<ac:rich-text-body>
298+
<ac:structured-macro ac:name='panel' ac:schema-version='1' ac:macro-id='f8503e48-c671-4ed6-897c-def2b2c3fa29'>
299+
<ac:parameter ac:name='title'>Subject</ac:parameter>
300+
<ac:rich-text-body><p>${MockServer.NOTIFICATION_SUBJECT}</p></ac:rich-text-body>
301+
</ac:structured-macro>
302+
<ac:structured-macro ac:name='panel' ac:schema-version='1' ac:macro-id='63c16112-dea3-434e-b1cb-467ff4e36d5f'>
303+
<ac:parameter ac:name='title'>Body</ac:parameter>
304+
<ac:rich-text-body>${MockServer.NOTIFICATION_BODY}</ac:rich-text-body>
305+
</ac:structured-macro>
306+
</ac:rich-text-body>
307+
</ac:structured-macro>
308+
`,
309+
},
310+
},
311+
})
312+
this._scope
313+
.get('/rest/api/content/12347?expand=body.storage')
314+
.basicAuth({
315+
user: 'nobody',
316+
pass: 'nothing',
317+
})
318+
.reply(200, {
319+
body: {
320+
storage: {
321+
value: `
322+
<ac:structured-macro ac:name='panel' ac:schema-version='1' ac:macro-id='4671afbe-d914-470a-bb9e-8b7321f60f79'>
323+
<ac:parameter ac:name='title'>Configuration</ac:parameter>
324+
<ac:rich-text-body>
325+
<table class='wrapped'>
326+
<colgroup>
327+
<col/>
328+
<col/>
329+
</colgroup>
330+
<tbody>
331+
<tr>
332+
<th>Space</th>
333+
<td>SAMPLE</td>
334+
</tr>
335+
<tr>
336+
<th>Domain</th>
337+
<td>example.com</td>
338+
</tr>
339+
<tr>
340+
<th>NotificationFrom</th>
341+
<td>Notification &lt;noreply@example.com&gt;</td>
342+
</tr>
343+
</tbody>
344+
</table>
345+
</ac:rich-text-body>
346+
</ac:structured-macro>
347+
<ac:structured-macro ac:name='panel' ac:schema-version='1' ac:macro-id='ecfe796e-b701-4f30-a74a-b94dbb33daff'>
348+
<ac:parameter ac:name='title'>SMTP</ac:parameter>
349+
<ac:rich-text-body>
350+
<table>
351+
<colgroup>
352+
<col/>
353+
<col/>
354+
</colgroup>
355+
<tbody>
356+
<tr>
357+
<th>Host</th>
358+
<td colspan='1'>localhost</td>
359+
</tr>
360+
<tr>
361+
<th>Port</th>
362+
<td colspan='1'>25</td>
363+
</tr>
364+
</tbody>
365+
</table>
366+
</ac:rich-text-body>
367+
</ac:structured-macro>
368+
<ac:structured-macro ac:name='panel' ac:schema-version='1' ac:macro-id='f19cd8b2-57e0-4c68-a823-8a2daee08c12'>
369+
<ac:parameter ac:name='title'>Checks</ac:parameter>
370+
<ac:rich-text-body>
371+
<table class='wrapped'>
372+
<colgroup>
373+
<col/>
374+
<col/>
375+
</colgroup>
376+
<tbody>
377+
<tr>
378+
<th>Labels</th>
379+
<th>MaxAge</th>
380+
</tr>
381+
<tr>
382+
<td>test1</td>
383+
<td>356</td>
384+
</tr>
385+
<tr>
386+
<td colspan='1'>test2</td>
387+
<td colspan='1'>1234</td>
388+
</tr>
389+
</tbody>
390+
</table>
391+
</ac:rich-text-body>
392+
</ac:structured-macro>
264393
<ac:structured-macro ac:name='panel' ac:schema-version='1' ac:macro-id='1d192d60-7e69-4af8-8dd6-4006a7bfc952'>
265394
<ac:parameter ac:name='title'>Maintainer</ac:parameter>
266395
<ac:rich-text-body>
@@ -294,7 +423,30 @@ export class MockServer {
294423
<th>RegularExpression</th>
295424
</tr>
296425
<tr>
297-
<td></td>
426+
<td>main/Test/NOT</td>
427+
</tr>
428+
</tbody>
429+
</table>
430+
</ac:rich-text-body>
431+
</ac:structured-macro>
432+
<ac:structured-macro ac:name="panel" ac:schema-version="1" ac:macro-id="1d192d60-7e69-4af8-8dd6-4006a7bfc952">
433+
<ac:parameter ac:name="title">Excluded labels</ac:parameter>
434+
<ac:rich-text-body>
435+
<i>This table holds a list of labels. A document which has one of these will be excluded from notifications.</i>
436+
<table class="wrapped">
437+
<colgroup>
438+
<col/>
439+
<col/>
440+
</colgroup>
441+
<tbody>
442+
<tr>
443+
<th>Label</th>
444+
</tr>
445+
<tr>
446+
<td>NOT</td>
447+
</tr>
448+
<tr>
449+
<td>NOT2</td>
298450
</tr>
299451
</tbody>
300452
</table>

0 commit comments

Comments
 (0)