Skip to content

Commit 10e5a52

Browse files
committed
tweak authors slightly
1 parent 727f051 commit 10e5a52

3 files changed

Lines changed: 216 additions & 68 deletions

File tree

SCC-OUTPUT-REPORT.html

Lines changed: 65 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@
1313
<tbody><tr>
1414
<th>Go</th>
1515
<th>74</th>
16-
<th>41768</th>
17-
<th>3217</th>
18-
<th>2368</th>
19-
<th>36183</th>
20-
<th>4758</th>
21-
<th>1017905</th>
22-
<th>15466</th>
16+
<th>41916</th>
17+
<th>3225</th>
18+
<th>2402</th>
19+
<th>36289</th>
20+
<th>4789</th>
21+
<th>1023145</th>
22+
<th>15557</th>
2323
</tr><tr>
2424
<td>processor/constants.go</td>
2525
<td></td>
@@ -120,6 +120,16 @@
120120
<td>112</td>
121121
<td>22613</td>
122122
<td>581</td>
123+
</tr><tr>
124+
<td>processor/history_authors.go</td>
125+
<td></td>
126+
<td>682</td>
127+
<td>57</td>
128+
<td>63</td>
129+
<td>562</td>
130+
<td>129</td>
131+
<td>19056</td>
132+
<td>484</td>
123133
</tr><tr>
124134
<td>processor/report_render.go</td>
125135
<td></td>
@@ -160,16 +170,6 @@
160170
<td>133</td>
161171
<td>12733</td>
162172
<td>269</td>
163-
</tr><tr>
164-
<td>processor/history_authors.go</td>
165-
<td></td>
166-
<td>586</td>
167-
<td>54</td>
168-
<td>39</td>
169-
<td>493</td>
170-
<td>111</td>
171-
<td>15890</td>
172-
<td>416</td>
173173
</tr><tr>
174174
<td>config.go</td>
175175
<td></td>
@@ -180,6 +180,16 @@
180180
<td>77</td>
181181
<td>28134</td>
182182
<td>422</td>
183+
</tr><tr>
184+
<td>processor/history_authors_test.go</td>
185+
<td></td>
186+
<td>573</td>
187+
<td>68</td>
188+
<td>46</td>
189+
<td>459</td>
190+
<td>133</td>
191+
<td>18095</td>
192+
<td>302</td>
183193
</tr><tr>
184194
<td>processor/history_author_timeline_test.go</td>
185195
<td></td>
@@ -190,16 +200,6 @@
190200
<td>120</td>
191201
<td>15331</td>
192202
<td>308</td>
193-
</tr><tr>
194-
<td>processor/history_authors_test.go</td>
195-
<td></td>
196-
<td>521</td>
197-
<td>63</td>
198-
<td>36</td>
199-
<td>422</td>
200-
<td>120</td>
201-
<td>16021</td>
202-
<td>277</td>
203203
</tr><tr>
204204
<td>mcp.go</td>
205205
<td></td>
@@ -220,16 +220,6 @@
220220
<td>86</td>
221221
<td>15568</td>
222222
<td>242</td>
223-
</tr><tr>
224-
<td>processor/history_hotspots.go</td>
225-
<td></td>
226-
<td>422</td>
227-
<td>40</td>
228-
<td>47</td>
229-
<td>335</td>
230-
<td>57</td>
231-
<td>12218</td>
232-
<td>305</td>
233223
</tr><tr>
234224
<td>processor/history_languages_test.go</td>
235225
<td></td>
@@ -240,6 +230,16 @@
240230
<td>73</td>
241231
<td>13401</td>
242232
<td>230</td>
233+
</tr><tr>
234+
<td>processor/history_hotspots.go</td>
235+
<td></td>
236+
<td>422</td>
237+
<td>40</td>
238+
<td>47</td>
239+
<td>335</td>
240+
<td>57</td>
241+
<td>12218</td>
242+
<td>305</td>
243243
</tr><tr>
244244
<td>processor/history_author_timeline.go</td>
245245
<td></td>
@@ -250,16 +250,6 @@
250250
<td>64</td>
251251
<td>11760</td>
252252
<td>288</td>
253-
</tr><tr>
254-
<td>processor/history_languages.go</td>
255-
<td></td>
256-
<td>373</td>
257-
<td>40</td>
258-
<td>30</td>
259-
<td>303</td>
260-
<td>52</td>
261-
<td>10482</td>
262-
<td>269</td>
263253
</tr><tr>
264254
<td>processor/file_test.go</td>
265255
<td></td>
@@ -270,6 +260,16 @@
270260
<td>75</td>
271261
<td>8978</td>
272262
<td>178</td>
263+
</tr><tr>
264+
<td>processor/history_languages.go</td>
265+
<td></td>
266+
<td>373</td>
267+
<td>40</td>
268+
<td>30</td>
269+
<td>303</td>
270+
<td>52</td>
271+
<td>10482</td>
272+
<td>269</td>
273273
</tr><tr>
274274
<td>processor/formatters.go</td>
275275
<td></td>
@@ -720,16 +720,6 @@
720720
<td>0</td>
721721
<td>2209</td>
722722
<td>35</td>
723-
</tr><tr>
724-
<td>processor/cocomo_test.go</td>
725-
<td></td>
726-
<td>37</td>
727-
<td>8</td>
728-
<td>4</td>
729-
<td>25</td>
730-
<td>6</td>
731-
<td>686</td>
732-
<td>23</td>
733723
</tr><tr>
734724
<td>processor/bloom.go</td>
735725
<td></td>
@@ -740,6 +730,16 @@
740730
<td>2</td>
741731
<td>1056</td>
742732
<td>29</td>
733+
</tr><tr>
734+
<td>processor/cocomo_test.go</td>
735+
<td></td>
736+
<td>37</td>
737+
<td>8</td>
738+
<td>4</td>
739+
<td>25</td>
740+
<td>6</td>
741+
<td>686</td>
742+
<td>23</td>
743743
</tr><tr>
744744
<td>processor/helpers_test.go</td>
745745
<td></td>
@@ -764,15 +764,15 @@
764764
<tfoot><tr>
765765
<th>Total</th>
766766
<th>74</th>
767-
<th>41768</th>
768-
<th>3217</th>
769-
<th>2368</th>
770-
<th>36183</th>
771-
<th>4758</th>
772-
<th>1017905</th>
773-
<th>15466</th>
767+
<th>41916</th>
768+
<th>3225</th>
769+
<th>2402</th>
770+
<th>36289</th>
771+
<th>4789</th>
772+
<th>1023145</th>
773+
<th>15557</th>
774774
</tr>
775775
<tr>
776-
<th colspan="9">Estimated Cost to Develop (organic) $1,169,567<br>Estimated Schedule Effort (organic) 14.60 months<br>Estimated People Required (organic) 7.12<br></th>
776+
<th colspan="9">Estimated Cost to Develop (organic) $1,173,164<br>Estimated Schedule Effort (organic) 14.61 months<br>Estimated People Required (organic) 7.13<br></th>
777777
</tr></tfoot>
778778
</table></body></html>

processor/history_authors.go

Lines changed: 99 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,13 @@ const (
3232
// authorRow is one materialised row in the report. Sentinel is true for the
3333
// "(before window)" pseudo-author whose lines pre-date the walk window.
3434
type authorRow struct {
35-
Name string
35+
Name string
36+
// Display is the name as rendered in the tabular report and bus-factor
37+
// footer. It equals Name unless two or more in-window identities share
38+
// the same Name, in which case each colliding row is suffixed with a
39+
// distinguishing marker (see disambiguateNames) so the reader can tell
40+
// the identities apart. CSV/JSON emit Name and Email raw and ignore this.
41+
Display string
3642
Email string
3743
Code int64
3844
Comment int64
@@ -247,6 +253,7 @@ func (o *historyAuthorsObserver) Finalise(window HistoryWindow, head HeadSnapsho
247253
}
248254
return strings.Compare(a.Name, b.Name)
249255
})
256+
disambiguateNames(rows)
250257
o.rows = rows
251258

252259
cumPercent := 0.0
@@ -258,7 +265,7 @@ func (o *historyAuthorsObserver) Finalise(window HistoryWindow, head HeadSnapsho
258265
break
259266
}
260267
cumPercent += r.InWindowPercent
261-
o.busAuthors = append(o.busAuthors, r.Name)
268+
o.busAuthors = append(o.busAuthors, r.Display)
262269
if cumPercent > 50 {
263270
break
264271
}
@@ -267,6 +274,95 @@ func (o *historyAuthorsObserver) Finalise(window HistoryWindow, head HeadSnapsho
267274
o.busCovered = cumPercent
268275
}
269276

277+
// disambiguateNames sets Display on every row. When two or more in-window
278+
// identities share the same display Name (e.g. one contributor committing
279+
// under both a work and a noreply email — kept as distinct identities because
280+
// no .mailmap merges them), each colliding row is suffixed with a short
281+
// marker so the reader — and the bus-factor footer, which reuses Display —
282+
// can tell them apart. Non-colliding names, the "others" roll-up and the
283+
// sentinel are left bare.
284+
func disambiguateNames(rows []authorRow) {
285+
groups := map[string][]int{}
286+
for i := range rows {
287+
if rows[i].Sentinel {
288+
continue
289+
}
290+
groups[rows[i].Name] = append(groups[rows[i].Name], i)
291+
}
292+
for _, idx := range groups {
293+
if len(idx) < 2 {
294+
continue
295+
}
296+
markers := disambiguationMarkers(rows, idx)
297+
for k, i := range idx {
298+
rows[i].Display = rows[i].Name + " (" + markers[k] + ")"
299+
}
300+
}
301+
for i := range rows {
302+
if rows[i].Display == "" {
303+
rows[i].Display = rows[i].Name
304+
}
305+
}
306+
}
307+
308+
// disambiguationMarkers returns one marker per row in idx (all sharing a
309+
// display Name), picking the shortest candidate form that is distinct across
310+
// the whole group: registrable domain first (the tidiest, e.g. "github.com"),
311+
// then the full domain, then the full email. Because two identities with the
312+
// same name and same email intern to one authorID, a collision group always
313+
// has distinct emails, so the final form is guaranteed to separate them.
314+
func disambiguationMarkers(rows []authorRow, idx []int) []string {
315+
forms := []func(string) string{
316+
registrableDomain,
317+
emailDomain,
318+
func(email string) string { return email },
319+
}
320+
for _, form := range forms {
321+
out := make([]string, len(idx))
322+
seen := map[string]struct{}{}
323+
distinct := true
324+
for k, i := range idx {
325+
m := form(rows[i].Email)
326+
if m == "" {
327+
distinct = false
328+
break
329+
}
330+
if _, dup := seen[m]; dup {
331+
distinct = false
332+
break
333+
}
334+
seen[m] = struct{}{}
335+
out[k] = m
336+
}
337+
if distinct {
338+
return out
339+
}
340+
}
341+
// Unreachable in practice (see doc comment); fall back to raw email.
342+
out := make([]string, len(idx))
343+
for k, i := range idx {
344+
out[k] = rows[i].Email
345+
}
346+
return out
347+
}
348+
349+
// registrableDomain returns the last two labels of the email's domain
350+
// (e.g. "users.noreply.github.com" -> "github.com"), a short human-readable
351+
// marker for the common single-TLD case. It is a display heuristic, not a
352+
// public-suffix-correct computation — disambiguationMarkers falls back to the
353+
// full domain when this form fails to separate a collision group.
354+
func registrableDomain(email string) string {
355+
d := emailDomain(email)
356+
if d == "" {
357+
return ""
358+
}
359+
parts := strings.Split(d, ".")
360+
if len(parts) <= 2 {
361+
return d
362+
}
363+
return strings.Join(parts[len(parts)-2:], ".")
364+
}
365+
270366
// runAuthorsReport is the dispatch entry point called from Process() when
271367
// --by-author is set (and --timeline is not). Opens the repo at repoPath,
272368
// walks history with baseline seeding, and writes the chosen format to
@@ -344,7 +440,7 @@ func renderAuthorsTabular(o *historyAuthorsObserver) string {
344440

345441
for i := range limit {
346442
r := realRows[i]
347-
writeAuthorRow(&sb, p, wide, r.Name, r.Code, r.Comment, r.Complexity,
443+
writeAuthorRow(&sb, p, wide, r.Display, r.Code, r.Comment, r.Complexity,
348444
fmt.Sprintf("%d", r.Files), r.OwnsPercent, lastSeenString(r))
349445
}
350446

0 commit comments

Comments
 (0)