Skip to content

Commit eb590e6

Browse files
committed
rules: add co-authored-by-is-trailer
Refs: nodejs/node-core-utils#602
1 parent 1eca2be commit eb590e6

File tree

2 files changed

+208
-0
lines changed

2 files changed

+208
-0
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
'use strict'
2+
3+
const id = 'co-authored-by-is-trailer'
4+
5+
module.exports = {
6+
id: id,
7+
meta: {
8+
description: 'enforce that "Co-authored-by:" lines are trailers',
9+
recommended: true
10+
},
11+
defaults: {},
12+
options: {},
13+
validate: (context, rule) => {
14+
const parsed = context.toJSON()
15+
const lines = parsed.body.map((line, i) => [line, i])
16+
const re = /^\s*Co-authored-by:/gi
17+
const coauthors = lines.filter(([line]) => re.test(line))
18+
if (coauthors.length !== 0) {
19+
const firstCoauthor = coauthors[0]
20+
const emptyLines = lines.filter(([text]) => text.trim().length === 0)
21+
// There must be at least one empty line, and the last empty line must be
22+
// above the first Co-authored-by line.
23+
const isTrailer = (emptyLines.length !== 0) &&
24+
emptyLines.pop()[1] < firstCoauthor[1]
25+
if (isTrailer) {
26+
context.report({
27+
id: id,
28+
message: 'Co-authored-by is a trailer',
29+
string: '',
30+
level: 'pass'
31+
})
32+
} else {
33+
context.report({
34+
id: id,
35+
message: 'Co-authored-by must be a trailer',
36+
string: firstCoauthor[0],
37+
line: firstCoauthor[1],
38+
column: 0,
39+
level: 'fail'
40+
})
41+
}
42+
} else {
43+
context.report({
44+
id: id,
45+
message: 'no Co-authored-by metadata',
46+
string: '',
47+
level: 'pass'
48+
})
49+
}
50+
}
51+
}
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
'use strict'
2+
3+
const test = require('tap').test
4+
const Rule = require('../../lib/rules/co-authored-by-is-trailer')
5+
const Commit = require('gitlint-parser-node')
6+
const Validator = require('../../')
7+
8+
test('rule: co-authored-by-is-trailer', (t) => {
9+
t.test('no co-authors', (tt) => {
10+
tt.plan(4)
11+
const v = new Validator()
12+
const context = new Commit({
13+
sha: 'e7c077c610afa371430180fbd447bfef60ebc5ea',
14+
author: {
15+
name: 'Foo',
16+
email: 'foo@example.com',
17+
date: '2016-04-12T19:42:23Z'
18+
},
19+
message: 'test: fix something\n' +
20+
'\n' +
21+
'fhqwhgads'
22+
}, v)
23+
24+
context.report = (opts) => {
25+
tt.pass('called report')
26+
tt.equal(opts.id, 'co-authored-by-is-trailer', 'id')
27+
tt.equal(opts.message, 'no Co-authored-by metadata', 'message')
28+
tt.equal(opts.level, 'pass', 'level')
29+
}
30+
31+
Rule.validate(context)
32+
})
33+
34+
t.test('no empty lines above', (tt) => {
35+
tt.plan(7)
36+
const v = new Validator()
37+
const context = new Commit({
38+
sha: 'e7c077c610afa371430180fbd447bfef60ebc5ea',
39+
author: {
40+
name: 'Foo',
41+
email: 'foo@example.com',
42+
date: '2016-04-12T19:42:23Z'
43+
},
44+
message: 'test: fix something\n' +
45+
'Co-authored-by: Someone <someone@example.com>'
46+
}, v)
47+
48+
context.report = (opts) => {
49+
tt.pass('called report')
50+
tt.equal(opts.id, 'co-authored-by-is-trailer', 'id')
51+
tt.equal(opts.message, 'Co-authored-by must be a trailer', 'message')
52+
tt.equal(opts.string, 'Co-authored-by: Someone <someone@example.com>', 'string')
53+
tt.equal(opts.line, 0, 'line')
54+
tt.equal(opts.column, 0, 'column')
55+
tt.equal(opts.level, 'fail', 'level')
56+
}
57+
58+
Rule.validate(context)
59+
})
60+
61+
t.test('not trailer', (tt) => {
62+
tt.plan(7)
63+
const v = new Validator()
64+
const context = new Commit({
65+
sha: 'e7c077c610afa371430180fbd447bfef60ebc5ea',
66+
author: {
67+
name: 'Foo',
68+
email: 'foo@example.com',
69+
date: '2016-04-12T19:42:23Z'
70+
},
71+
message: 'test: fix something\n' +
72+
'\n' +
73+
'Some description.\n' +
74+
'\n' +
75+
'Co-authored-by: Someone <someone@example.com>\n' +
76+
'\n' +
77+
'Reviewed-By: Bar <bar@example.com>'
78+
}, v)
79+
80+
context.report = (opts) => {
81+
tt.pass('called report')
82+
tt.equal(opts.id, 'co-authored-by-is-trailer', 'id')
83+
tt.equal(opts.message, 'Co-authored-by must be a trailer', 'message')
84+
tt.equal(opts.string, 'Co-authored-by: Someone <someone@example.com>', 'string')
85+
tt.equal(opts.line, 3, 'line')
86+
tt.equal(opts.column, 0, 'column')
87+
tt.equal(opts.level, 'fail', 'level')
88+
}
89+
90+
Rule.validate(context)
91+
})
92+
93+
t.test('not all are trailers', (tt) => {
94+
tt.plan(7)
95+
const v = new Validator()
96+
const context = new Commit({
97+
sha: 'e7c077c610afa371430180fbd447bfef60ebc5ea',
98+
author: {
99+
name: 'Foo',
100+
email: 'foo@example.com',
101+
date: '2016-04-12T19:42:23Z'
102+
},
103+
message: 'test: fix something\n' +
104+
'\n' +
105+
'Some description.\n' +
106+
'\n' +
107+
'Co-authored-by: Someone <someone@example.com>\n' +
108+
'\n' +
109+
'Co-authored-by: Someone Else <someone.else@example.com>\n' +
110+
'Reviewed-By: Bar <bar@example.com>'
111+
}, v)
112+
113+
context.report = (opts) => {
114+
tt.pass('called report')
115+
tt.equal(opts.id, 'co-authored-by-is-trailer', 'id')
116+
tt.equal(opts.message, 'Co-authored-by must be a trailer', 'message')
117+
tt.equal(opts.string, 'Co-authored-by: Someone <someone@example.com>', 'string')
118+
tt.equal(opts.line, 3, 'line')
119+
tt.equal(opts.column, 0, 'column')
120+
tt.equal(opts.level, 'fail', 'level')
121+
}
122+
123+
Rule.validate(context)
124+
})
125+
126+
t.test('is trailer', (tt) => {
127+
tt.plan(4)
128+
const v = new Validator()
129+
const context = new Commit({
130+
sha: 'e7c077c610afa371430180fbd447bfef60ebc5ea',
131+
author: {
132+
name: 'Foo',
133+
email: 'foo@example.com',
134+
date: '2016-04-12T19:42:23Z'
135+
},
136+
message: 'test: fix something\n' +
137+
'\n' +
138+
'Some description.\n' +
139+
'\n' +
140+
'More description.\n' +
141+
'\n' +
142+
'Co-authored-by: Someone <someone@example.com>\n' +
143+
'Reviewed-By: Bar <bar@example.com>'
144+
}, v)
145+
146+
context.report = (opts) => {
147+
tt.pass('called report')
148+
tt.equal(opts.id, 'co-authored-by-is-trailer', 'id')
149+
tt.equal(opts.message, 'Co-authored-by is a trailer', 'message')
150+
tt.equal(opts.level, 'pass', 'level')
151+
}
152+
153+
Rule.validate(context)
154+
})
155+
156+
t.end()
157+
})

0 commit comments

Comments
 (0)