• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

moosetechnology / GitProjectHealth / 9549969001

17 Jun 2024 02:58PM UTC coverage: 26.896% (-2.6%) from 29.45%
9549969001

push

github

HLAD Nicolas
Merge 10a1182e1

1830 of 6804 relevant lines covered (26.9%)

0.27 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.35
/src/GitLabHealth-Model-Analysis/GitAnalyzer.class.st
1
Class {
2
        #name : #GitAnalyzer,
3
        #superclass : #Object,
4
        #instVars : [
5
                'glModel',
6
                'fromCommit',
7
                'glhImporter',
8
                'onProject',
9
                'maxChildCommits'
10
        ],
11
        #category : #'GitLabHealth-Model-Analysis'
12
}
13

14
{ #category : #'as yet unclassified' }
15
GitAnalyzer >> analyseAmandment [
1✔
16
        "return the first commit that modify the same lines of code as the fromCommit"
1✔
17

1✔
18
        | churn res |
1✔
19
        
1✔
20
        ('GitAnalyzer, analyse amandment onProject: ', onProject printString )
1✔
21
                recordInfo.
1✔
22
        
1✔
23
        churn := self analyseChurn.
1✔
24

1✔
25
        res := self firstAmandmentFromChrun: churn.
1✔
26

1✔
27
        ^ res
1✔
28
]
1✔
29

30
{ #category : #'as yet unclassified' }
31
GitAnalyzer >> analyseChurn [
1✔
32

1✔
33
        | commitFiles totalContribution childCommits |
1✔
34
        ('GitAnalyzer, analyse chrun onProject: ' , onProject printString)
1✔
35
                recordInfo.
1✔
36
        childCommits := OrderedCollection new.
1✔
37
        totalContribution := self
1✔
38
                                     visitChildCommits: fromCommit childCommits
1✔
39
                                     toStoreThemIn: childCommits
1✔
40
                                     upto: self maxChildCommits.
1✔
41
        totalContribution := totalContribution sum: [ :commit | "nil if merge request commit"
1✔
42
                                     commit additions ifNil: [ 0 ] ].
1✔
43
        commitFiles := self
1✔
44
                               impactedFilesInFollowUpCommitsOf: fromCommit
1✔
45
                               withMaxCommits: self maxChildCommits.
1✔
46
        ^ (self computeChurnOnFiles: commitFiles)
1✔
47
                  at: #totalContribution ifAbsentPut: totalContribution;
1✔
48
                  yourself
1✔
49
]
1✔
50

51
{ #category : #'as yet unclassified' }
52
GitAnalyzer >> analyseCommentContributions [
×
53

×
54
        | additions |
×
55
        
×
56
        ('GitAnalyzer, analyse comment contributions onProject: ', onProject printString )
×
57
                recordInfo.
×
58
        
×
59
        additions := (fromCommit diffs collect: [ :diff |
×
60
                              diff diffRanges collect: [ :range |
×
61
                                      range changes select: [ :change |
×
62
                                              change class = GLPHEAddition ] ] ]) flattened
×
63
                             collect: [ :add | add sourceCode ].
×
64

×
65
        additions := additions collect: [ :codeSource |
×
66
                             (codeSource withoutPrefix: '+') trim ].
×
67
        additions := additions select: [ :codeSource |
×
68
                             codeSource beginsWithAnyOf:
×
69
                                     { '#'. '//'. '/*'. '*'. '*/' } ].
×
70

×
71
        ^ additions size
×
72
]
×
73

74
{ #category : #commit }
75
GitAnalyzer >> analyseCommitContribution [
×
76
        
×
77
        
×
78
        ('GitAnalyzer, analyse commit contribution of: ', fromCommit printString )
×
79
                recordInfo.
×
80
        
×
81
        ^ { (#addition -> fromCommit additions).
×
82
          (#deletion -> fromCommit deletions). } asDictionary 
×
83
]
×
84

85
{ #category : #'as yet unclassified' }
86
GitAnalyzer >> analyseCommitFrequencyFromCommits: initialCommits [
×
87

×
88
        | commits response |
×
89
        
×
90
        ('GitAnalyzer, analyse commit Frequency on: ', onProject printString )
×
91
                recordInfo.
×
92
        
×
93
        response := {  (#numberOfCommit -> nil).
×
94
                            (#frequency -> nil) } asDictionary.
×
95

×
96

×
97
        commits := self arrangeCommitsByDate: initialCommits.
×
98
        commits := (commits associations sortAscending: [ :entry |
×
99
                            entry key asDate ]) asOrderedDictionary.
×
100

×
101
        ^ commits
×
102
]
×
103

104
{ #category : #'as yet unclassified' }
105
GitAnalyzer >> analyseCommitFrequencySince: since until: until [ 
1✔
106

1✔
107
        | commits response |
1✔
108
        
1✔
109
        ('GitAnalyzer, analyse commit Frequency on: ', onProject printString )
1✔
110
                recordInfo.
1✔
111
        
1✔
112
        response := {
1✔
113
                            (#numberOfCommit -> nil).
1✔
114
                            (#frequency -> nil) } asDictionary.
1✔
115

1✔
116
        commits := glhImporter
1✔
117
                           importCommitsOProject: onProject
1✔
118
                           since: since
1✔
119
                           until: until.
1✔
120

1✔
121
        commits := self arrangeCommitsByDate: commits.
1✔
122
        commits := (commits associations sortAscending: [ :entry |
1✔
123
                            entry key asDate ]) asOrderedDictionary.
1✔
124

1✔
125
        ^ commits
1✔
126
]
1✔
127

128
{ #category : #'as yet unclassified' }
129
GitAnalyzer >> analyseMergeResquestValidation: aGLHPMergeRequest [
1✔
130

1✔
131
        |creationDate mergedDate response|
1✔
132
        
1✔
133
        
1✔
134
        ('GitAnalyzer, analyse merge request delay of: ', aGLHPMergeRequest printString )
1✔
135
                recordInfo.
1✔
136
        
1✔
137
        response := { 
1✔
138
                 #id_merge_resquest -> aGLHPMergeRequest iid. 
1✔
139
                 #id_merge_commit -> nil.
1✔
140
                 #created_at ->  aGLHPMergeRequest created_at.
1✔
141
                 #merged_at -> nil .
1✔
142
                 #duration ->  nil.
1✔
143
                 #status -> (aGLHPMergeRequest merge_status)} asDictionary .  
1✔
144
         
1✔
145
        
1✔
146
        creationDate := aGLHPMergeRequest created_at asDateAndTime.
1✔
147

1✔
148
        mergedDate := aGLHPMergeRequest merged_at ifNil: [ 
1✔
149
                
1✔
150
                ^ response 
1✔
151
                
1✔
152
                 ].
1✔
153
        
1✔
154
        ^ response at: #duration put: (mergedDate - creationDate); 
1✔
155
                                        at: #id_merge_commit put: aGLHPMergeRequest merge_commit_sha  ; 
1✔
156
                                        at: #merged_at put: aGLHPMergeRequest merged_at;
1✔
157
                                        yourself. 
1✔
158

1✔
159
]
1✔
160

161
{ #category : #filter }
162
GitAnalyzer >> arrangeCommitsByDate: commits [ 
1✔
163
        |date2commits|
1✔
164
        date2commits := Dictionary new. 
1✔
165
        
1✔
166
        commits do: [ :commit |
1✔
167
                |date|
1✔
168
                date := commit created_at asDate. 
1✔
169
                date2commits at: date printString ifPresent: [ :v | v add: commit ] ifAbsentPut: [ OrderedCollection new add: commit; yourself. ].
1✔
170
                 ].
1✔
171
        ^ date2commits. 
1✔
172
]
1✔
173

174
{ #category : #churn }
175
GitAnalyzer >> computeChurnOnFiles: aCollection [ 
1✔
176
        
1✔
177
        |changesDic perFileChanges  churns |
1✔
178
        
1✔
179
        "1 -> (a GLPHEChange -> NumberOfChurnDetected)"
1✔
180
        changesDic := Dictionary new. 
1✔
181
        
1✔
182
        
1✔
183
        perFileChanges := aCollection associations collect: [ :assoc |
1✔
184
                
1✔
185
                (assoc key -> (self computeSpecificChurnOf: assoc value )). 
1✔
186
                 ] .
1✔
187
        
1✔
188
         churns := perFileChanges collect: [ :assoc |
1✔
189
                |churn file results|
1✔
190
                
1✔
191
                file := assoc key.
1✔
192
                results := assoc value. 
1✔
193
                results values ifEmpty: [ churn := -1. ] ifNotEmpty: [ churn := ((results values select: [ :a | a value > 1 ] )sum: [ :a | a value ]) / (results values sum: [ :a | a value ]) . ].
1✔
194
                
1✔
195
                (file -> churn)
1✔
196
                 ].
1✔
197
        
1✔
198
        ^ {(#churns -> churns).
1✔
199
                        (#details -> perFileChanges)} asDictionary 
1✔
200
]
1✔
201

202
{ #category : #churn }
203
GitAnalyzer >> computeSpecificChurnOf: commit2Changes [ 
1✔
204
        |changesDic|
1✔
205
        "1 -> (a GLPHEChange -> NumberOfChurnDetected)"
1✔
206
        changesDic := OrderedDictionary new. 
1✔
207
        
1✔
208
        
1✔
209
        (commit2Changes sortAscending: [ :assoc | assoc key created_at ]) do: [ :entry |
1✔
210
                |commit diffRanges|
1✔
211
                commit := entry key.
1✔
212
                diffRanges := entry value. 
1✔
213
                
1✔
214
                diffRanges do: [ :diff |
1✔
215
                        |from upTo|
1✔
216
                        
1✔
217
                        from := (diff originalLineRange copyFrom: (diff originalLineRange indexOf: $-)+1 to: (diff originalLineRange indexOf: $, ifAbsent: [ diff originalLineRange size + 1 ] )-1 ) asString asNumber.
1✔
218
                        (from = 0) ifTrue:[from := 1].
1✔
219
                        self insertDiff: diff into: changesDic startingFrom: from. 
1✔
220
                        
1✔
221
                         ].
1✔
222
                
1✔
223
                 ].
1✔
224
        
1✔
225
        
1✔
226
        
1✔
227
        ^ self sortChangeDic: changesDic.
1✔
228
]
1✔
229

230
{ #category : #accessing }
231
GitAnalyzer >> firstAmandmentFromChrun: aChurnAnalysis [ 
1✔
232
        |details whereChangesOccurs firstCommitsPerFile|
1✔
233
        
1✔
234
        whereChangesOccurs := (aChurnAnalysis at: #churns ) select: [ :file | file value > 0 ].
1✔
235
        
1✔
236
        details := whereChangesOccurs collect: [ :file |
1✔
237
                ((aChurnAnalysis at: #details) detect: [ :entry | entry key = file key] )
1✔
238
                 ].
1✔
239
        
1✔
240
        firstCommitsPerFile := details collect: [ :perFile |
1✔
241
                |changes firstCommits first|
1✔
242
                changes := perFile value.
1✔
243
                changes := changes select: [ :line2changes | line2changes value value > 1  ].
1✔
244
                firstCommits := (changes collect: [ :line2changes |  line2changes key second diffRange diff commit ]) values. 
1✔
245
                first := (firstCommits sortAscending: [:c | c created_at ]) first.
1✔
246
                 ].
1✔
247
        
1✔
248

1✔
249
        ^ (firstCommitsPerFile sortAscending: [:c | c created_at ]) ifEmpty: nil ifNotEmpty: [ :v | v first ]  . 
1✔
250

1✔
251
]
1✔
252

253
{ #category : #accessing }
254
GitAnalyzer >> fromCommit: aCommit [
1✔
255
        fromCommit := aCommit. 
1✔
256
]
1✔
257

258
{ #category : #accessing }
259
GitAnalyzer >> glhImporter: anImporter [
1✔
260
        glhImporter := anImporter .
1✔
261
]
1✔
262

263
{ #category : #'as yet unclassified' }
264
GitAnalyzer >> impactedFilesInFollowUpCommitsOf: aGLHCommit [
×
265

×
266
        ^ self
×
267
                  impactedFilesInFollowUpCommitsOf: aGLHCommit
×
268
                  withMaxCommits: self maxChildCommits. 
×
269
]
×
270

271
{ #category : #churn }
272
GitAnalyzer >> impactedFilesInFollowUpCommitsOf: aGLHCommit withMaxCommits: max [
1✔
273

1✔
274
        | commitFiles |
1✔
275
        commitFiles := (fromCommit diffs collect: [ :diff |
1✔
276
                                diff new_path -> (Set new
1✔
277
                                         add: aGLHCommit -> diff diffRanges;
1✔
278
                                         yourself) ]) asDictionary.
1✔
279

1✔
280
        self
1✔
281
                visitChildCommits: fromCommit childCommits
1✔
282
                lookingForFiles: commitFiles upto: max.
1✔
283

1✔
284
        ^ commitFiles
1✔
285
]
1✔
286

287
{ #category : #initialization }
288
GitAnalyzer >> initialize [
1✔
289

1✔
290
        glModel := GLPHEModel new.
1✔
291
        fromCommit := GLHCommit new.
1✔
292
        glhImporter := GLPHModelImporter new.
1✔
293
        onProject := GLHProject new.
1✔
294
        maxChildCommits := -1
1✔
295
]
1✔
296

297
{ #category : #insertion }
298
GitAnalyzer >> insertDiff: aGLPHEDiffRange into: fileChangesDic startingFrom: from [ 
1✔
299
        |index|
1✔
300
        index := from. 
1✔
301
        aGLPHEDiffRange changes do: [ :aChange |
1✔
302
        
1✔
303
                aChange isAddition ifTrue: [ 
1✔
304
                        fileChangesDic at: index ifPresent: [ :current | 
1✔
305
                         
1✔
306
                        current key add: aChange.
1✔
307
                        current value: current value + 1.  ] ifAbsentPut: [((OrderedCollection new add: aChange; yourself) -> 1 ) ].
1✔
308
                         ].
1✔
309
                
1✔
310
                aChange isDeletion ifFalse: [ index := index + 1 ]. 
1✔
311
                
1✔
312
                 ]
1✔
313
]
1✔
314

315
{ #category : #accessing }
316
GitAnalyzer >> maxChildCommit: max [ 
1✔
317
        maxChildCommits := max
1✔
318
]
1✔
319

320
{ #category : #accessing }
321
GitAnalyzer >> maxChildCommits [
1✔
322
        ^ maxChildCommits
1✔
323
]
1✔
324

325
{ #category : #'as yet unclassified' }
326
GitAnalyzer >> onModel: agitHealthModel [
1✔
327
        glModel := agitHealthModel
1✔
328
]
1✔
329

330
{ #category : #accessing }
331
GitAnalyzer >> onProject: aGLHProject [ 
1✔
332
        onProject := aGLHProject
1✔
333
]
1✔
334

335
{ #category : #sorting }
336
GitAnalyzer >> sortChangeDic: aCollection [ 
1✔
337
        ^ (aCollection associations sortAscending: [ :e | e key ] ) asOrderedDictionary 
1✔
338
]
1✔
339

340
{ #category : #visiting }
341
GitAnalyzer >> visitChildCommits: commits lookingForFiles: commitFiles [
×
342

×
343
        ^ self visitChildCommits:  commits lookingForFiles: commitFiles upto: -1 
×
344
]
×
345

346
{ #category : #visiting }
347
GitAnalyzer >> visitChildCommits: commits lookingForFiles: commitFiles upto: nCommits [
1✔
348

1✔
349
        commits ifEmpty: [ ^ commitFiles ].
1✔
350
        (nCommits = 0) ifTrue: [ ^ commitFiles ].
1✔
351

1✔
352
        commits do: [ :commit |
1✔
353
                | files |
1✔
354
                files := commit diffs collect: [ :diff | diff ].
1✔
355

1✔
356
                files do: [ :diff |
1✔
357
                        commitFiles
1✔
358
                                at: diff new_path
1✔
359
                                ifPresent: [ :v | v add: commit -> diff diffRanges ]
1✔
360
                                ifAbsent: [  ] ].
1✔
361

1✔
362
                self
1✔
363
                        visitChildCommits: commit childCommits
1✔
364
                        lookingForFiles: commitFiles
1✔
365
                        upto: nCommits - 1 ].
1✔
366

1✔
367
        ^ commitFiles
1✔
368
]
1✔
369

370
{ #category : #visiting }
371
GitAnalyzer >> visitChildCommits: commits toStoreThemIn: commitsFound upto: nCommits [
1✔
372

1✔
373
        commits ifEmpty: [ ^ commitsFound ].
1✔
374
        nCommits = 0 ifTrue: [ ^ commitsFound ].
1✔
375

1✔
376
        commits do: [ :commit |
1✔
377
                commitsFound add: commit.
1✔
378

1✔
379
                self
1✔
380
                        visitChildCommits: commit childCommits
1✔
381
                        toStoreThemIn: commitsFound
1✔
382
                        upto: nCommits - 1 ].
1✔
383

1✔
384
        ^ commitsFound
1✔
385
]
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc