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

moosetechnology / GitProjectHealth / 11666569509

04 Nov 2024 02:45PM UTC coverage: 59.225% (+0.2%) from 59.01%
11666569509

Pull #105

github

web-flow
Merge 280fcb7ca into 3c4574e31
Pull Request #105: fix/add email user to the importer + tests

71 of 90 new or added lines in 4 files covered. (78.89%)

23 existing lines in 1 file now uncovered.

9582 of 16179 relevant lines covered (59.22%)

0.59 hits per line

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

0.0
/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st
1
Class {
2
        #name : 'GitMetricExporter',
3
        #superclass : 'Object',
4
        #instVars : [
5
                'glhImporter',
6
                'jiraImporter',
7
                'label',
8
                'entities',
9
                'projectCache',
10
                'sinceTimeLimit',
11
                'runningPeriods',
12
                'maxCommitWindow',
13
                'over',
14
                'emailDomain',
15
                'metrics',
16
                'analyses'
17
        ],
18
        #category : 'GitLabHealth-Model-Analysis',
19
        #package : 'GitLabHealth-Model-Analysis'
20
}
21

22
{ #category : 'as yet unclassified' }
23
GitMetricExporter class >> demoPeriod [
×
24

×
25
        ^ self new
×
26
                  addAPeriodFrom: '01 march 2023' to: '31 may 2023';
×
27
                  addAPeriodFrom: '01 december 2023' to: '29 february 2024';
×
28
                  addAPeriodFrom: '01 march 2024' to: '31 may 2024'
×
29
]
×
30

31
{ #category : 'adding' }
32
GitMetricExporter >> addAPeriodFrom: since to: until [
×
33

×
34
        runningPeriods add: {
×
35
                        (#since -> since asDate).
×
36
                        (#until -> until asDate) } asDictionary.
×
37
        
×
38
        ^runningPeriods 
×
39
]
×
40

41
{ #category : 'adding' }
42
GitMetricExporter >> addEntitiesFromUserNames: userNames [
×
43
        "import all the project since a certain time"
×
44
        
×
45
        self
×
46
                deprecated: 'Use #setupAnalysesForUsersWithNames instead'
×
47
                on: '03 Sept 2024'
×
48
                in:
×
49
                'Pharo-11.0.0+build.726.sha.aece1b5473acf3830a0e082c1bc3a15d4ff3522b (64 Bit)'.
×
50

×
51
        'Import all projects from the Git repository' recordInfo.
×
52
        projectCache := projectCache ifNil: [
×
53
                                glhImporter importProjectsSince: sinceTimeLimit ].
×
54

×
55
        "then collect the project in which the user has be seen commited"
×
56
        entities addAll: (userNames collect: [ :username |
×
57
                         | projects  i size |
×
58
                         projects := self
×
59
                                             findParticipationOfCommitAuthorNamed: username
×
60
                                             amongProjects: projectCache.
×
61

×
62
                        "metrics := GitMetric4User new.
×
63
                         metrics
×
64
                                 glhImporter: glhImporter;
×
65
                                 jiraImporter: jiraImporter;
×
66
                                 findUserNamed: username."
×
67

×
68

×
69

×
70
                         i := 0.
×
71
                         size := projects size.
×
72
                         metrics itsProjects: (projects collect: [ :p |
×
73
                                          (' ' join: {
×
74
                                                           'complete import of project:'.
×
75
                                                           p name printString.
×
76
                                                           '['.
×
77
                                                           (i := i + 1) printString.
×
78
                                                           '/'.
×
79
                                                           size.
×
80
                                                           ']' }) recordInfo.
×
81

×
82
                                          p id -> (glhImporter completeImportProject: p) ]) asDictionary.
×
83

×
84
                         metrics ]).
×
85

×
86
        ^ self
×
87
]
×
88

89
{ #category : 'adding' }
90
GitMetricExporter >> addEntitiesFromUserNamesAndProjects: usersWithProjects [
×
91

×
92
        self
×
93
                deprecated: 'Use #setupAnalysesForUsersWithNames instead'
×
94
                on: '03 Sept 2024'
×
95
                in:
×
96
                'Pharo-11.0.0+build.726.sha.aece1b5473acf3830a0e082c1bc3a15d4ff3522b (64 Bit)'.
×
97

×
98
        entities addAll: (usersWithProjects associations collect: [ :assoc |
×
99
                         | username projects  |
×
100
                         username := assoc key.
×
101
                         projects := assoc value.
×
102

×
103
                        " metrics := GitMetric4User new.
×
104
                         metrics
×
105
                                 glhImporter: glhImporter;
×
106
                                 jiraImporter: jiraImporter;
×
107
                                 findUserNamed: username.
×
108
                         metrics loadProjectsFromIds: projects."
×
109

×
110
                         username ]).
×
111

×
112
        ^ self 
×
113
]
×
114

115
{ #category : 'utilities' }
116
GitMetricExporter >> constructFilePath: runningOver [
×
117

×
118
        | file |
×
119
        file := (FileLocator home
×
120
                 /
×
121
                         ('GitlabHealth-' , label printString , '-' , runningOver printString
×
122
                          , '-'
×
123
                          , (DateAndTime now printString replaceAll: $: with: $-)
×
124
                          , '.csv')) asFileReference.
×
125
        ^ file
×
126
]
×
127

128
{ #category : 'exporting' }
129
GitMetricExporter >> csvMetricsFor: metricCollection at: date [
×
130

×
131
        | csvMetrics |
×
132
        csvMetrics := metricCollection collect: [ :metric |
×
133
                              metric new description , ' - ' , date asString
×
134
                              -> [ :groupAnalyses |
×
135
                                      | analysis |
×
136
                                      analysis := self
×
137
                                                          getAnalysisWithDate: date
×
138
                                                          from: groupAnalyses.
×
139
                                      analysis
×
140
                                              ifNil: [ nil ]
×
141
                                              ifNotNil: [ analysis metrics at: metric new name ] ] ].
×
142

×
143
        ^ csvMetrics asOrderedDictionary
×
144
]
×
145

146
{ #category : 'accessing' }
147
GitMetricExporter >> entities: aCollection [ 
×
148
        entities := aCollection
×
149
]
×
150

151
{ #category : 'exporting' }
152
GitMetricExporter >> exportFor: usersWithProjects [
×
153

×
154
        self
×
155
                deprecated: 'Use #exportInCSV instead'
×
156
                on: '03 Sept 2024'
×
157
                in:
×
158
                'Pharo-11.0.0+build.726.sha.aece1b5473acf3830a0e082c1bc3a15d4ff3522b (64 Bit)'.
×
159

×
160
        self exportFor: usersWithProjects over: {
×
161
                        Date.
×
162
                        Week.
×
163
                        Month.
×
164
                        Year }
×
165
]
×
166

167
{ #category : 'exporting' }
168
GitMetricExporter >> exportFor: usersWithProjects over: aCollectionOfDateWeekMonthOrYear [
×
169

×
170
        self
×
171
                deprecated: 'Use #exportInCSV instead'
×
172
                on: '03 Sept 2024'
×
173
                in:
×
174
                'Pharo-11.0.0+build.726.sha.aece1b5473acf3830a0e082c1bc3a15d4ff3522b (64 Bit)'.
×
175

×
176
        entities ifNil: [
×
177
                self addEntitiesFromUserNamesAndProjects: usersWithProjects ].
×
178

×
179
        self exportFor: aCollectionOfDateWeekMonthOrYear
×
180
]
×
181

182
{ #category : 'exporting' }
183
GitMetricExporter >> exportInCSV [
×
184

×
185
        self exportUserAnalysesInCSV.
×
186
        self exportProjectAnalysesInCSV.
×
187
]
×
188

189
{ #category : 'exporting' }
190
GitMetricExporter >> exportInDB: repository [
×
191

×
192
        repository enableSingleton.
×
193
        analyses do: [ :analysis | analysis save ]
×
194
]
×
195

196
{ #category : 'exporting' }
197
GitMetricExporter >> exportInS3: bucketName accessKey: accessKey secretKey: secretKey region: region [
×
198

×
199
        | s3 bucket ston date fileName |
×
200
        AWSS3Config default
×
201
                accessKeyId: accessKey;
×
202
                secretKey: secretKey;
×
203
                regionName: region.
×
204

×
205
        s3 := AWSS3 new.
×
206
        bucket := s3 bucketNamed: bucketName.
×
207

×
208
        ston := STON toString: analyses.
×
209

×
210
        date := Date today asString copyReplaceAll: ' ' asString with: '-'.
×
211
        fileName := ('-' join: {
×
212
                                     'analyse'.
×
213
                                     label.
×
214
                                     over asString.
×
215
                                     date }) , '.ston'.
×
216

×
217
        bucket atKey: fileName putObject: ston
×
218
]
×
219

220
{ #category : 'exporting' }
221
GitMetricExporter >> exportProjectAnalysesInCSV [
×
222

×
223
        | exportBrowserModel groupedByOver group groupOver groupByName periods csvMetrics file |
×
224
        exportBrowserModel := MiExportModel new.
×
225

×
226
        groupedByOver := self projectAnalyses groupedBy: #over.
×
227

×
228
        groupedByOver associations do: [ :groupAssociation |
×
229
                group := groupAssociation value.
×
230
                groupOver := groupAssociation key.
×
231

×
232

×
233
                groupByName := group groupedBy: #projectName.
×
234
                exportBrowserModel entitiesList: groupByName.
×
235

×
236
                exportBrowserModel removeColumnForQueryNamed: #Type.
×
237
                exportBrowserModel removeColumnForQueryNamed: #Name.
×
238

×
239
                exportBrowserModel
×
240
                        addColumnForQuery: [ :groupAnalyses |
×
241
                        (groupAnalyses at: 1) projectName ]
×
242
                        withName: #'Project name'.
×
243

×
244
                periods := (group groupedBy: #period) keys.
×
245

×
246
                periods do: [ :period |
×
247
                        csvMetrics := self
×
248
                                              csvMetricsFor: self projectMetrics
×
249
                                              at: (period at: #since).
×
250

×
251

×
252
                        csvMetrics associations do: [ :association |
×
253
                                exportBrowserModel
×
254
                                        addColumnForQuery: association value
×
255
                                        withName: association key ] ].
×
256

×
257
                file := self constructFilePath: groupOver.
×
258
                file writeStreamDo: [ :aStream |
×
259
                        exportBrowserModel writeCSVOn: aStream ] ]
×
260
]
×
261

262
{ #category : 'exporting' }
263
GitMetricExporter >> exportUserAnalysesInCSV [
×
264

×
265
        | exportBrowserModel groupedByOver group groupOver groupByName periods csvMetrics file |
×
266
        exportBrowserModel := MiExportModel new.
×
267
        groupedByOver := self userAnalyses groupedBy: #over.
×
NEW
268
        
×
269
        groupedByOver associations do: [ :groupAssociation |
×
270
                group := groupAssociation value.
×
271
                groupOver := groupAssociation key.
×
NEW
272
                
×
273
                groupByName := group groupedBy: #username.
×
274
                exportBrowserModel entitiesList: groupByName.
×
275
                exportBrowserModel removeColumnForQueryNamed: #Type.
×
276
                exportBrowserModel removeColumnForQueryNamed: #Name.
×
NEW
277
                
×
278
                exportBrowserModel
×
279
                        addColumnForQuery: [ :groupAnalyses |
×
280
                        (groupAnalyses at: 1) username ]
×
281
                        withName: #'User name'.
×
282
                        
×
NEW
283
                periods := (group groupedBy: #period) keys.
×
NEW
284
                periods do: [ :period |
×
NEW
285
                        csvMetrics := self
×
NEW
286
                                              csvMetricsFor: self userMetrics
×
NEW
287
                                              at: (period at: #since).
×
288
                        csvMetrics associations do: [ :association |
×
289
                                exportBrowserModel
×
290
                                        addColumnForQuery: association value
×
291
                                        withName: association key ] ].
×
292
                        
×
293
                        
×
294
                file := self constructFilePath: groupOver.
×
295
                
×
296
                file writeStreamDo: [ :aStream |
×
NEW
297
                        exportBrowserModel writeCSVOn: aStream ] ]
×
NEW
298
]
×
299

300
{ #category : 'projects' }
301
GitMetricExporter >> findParticipationOfCommitAuthorNamed: username amongProjects: aCollectionOfProjects [
×
302

×
303
        | response itsProjects i size |
×
UNCOV
304
        i := 1.
×
UNCOV
305
        size := aCollectionOfProjects size.
×
306
        itsProjects := aCollectionOfProjects select: [ :project |
×
307
                               (' ' join: {
×
308
                                                'search'.
×
309
                                                username printString.
×
310
                                                'in Project:'.
×
311
                                                project name printString.
×
312
                                                '['.
×
313
                                                (i := i + 1) printString.
×
314
                                                '/'.
×
315
                                                size.
×
316
                                                ']' }) recordInfo.
×
317

×
318
                               response := glhImporter repoApi
×
319
                                                   commitsOfUser: username
×
320
                                                   inProject: project id
×
321
                                                   since: '01 january 2023' asDateAndTime
×
322
                                                   until: Date today asDateAndTime.
×
323
                               response := glhImporter parseCommitsResult: response.
×
324
                               response isNotEmpty
×
325
                 ].
×
326

×
327
        ^ itsProjects
×
328
]
×
329

330
{ #category : 'projects' }
331
GitMetricExporter >> findProjectsOfUser: aCollection [ 
×
332
        self shouldBeImplemented.
×
333
]
×
334

335
{ #category : 'analysis' }
336
GitMetricExporter >> generateAnalysesOver: aDateWeekMonthOrYear [
×
337

×
338
        analyses := OrderedCollection new.
×
UNCOV
339
        runningPeriods do: [ :period |
×
UNCOV
340
                analyses addAll: (self
×
341
                                 generateUsersAnalysesDuringPeriod: period
×
342
                                 over: aDateWeekMonthOrYear).
×
343

×
344
                analyses addAll: (self
×
345
                                 generateProjectsAnalysesDuringPeriod: period
×
346
                                 over: aDateWeekMonthOrYear) ].
×
347

×
348
        ^ analyses
×
349
]
×
350

351
{ #category : 'analysis' }
352
GitMetricExporter >> generateProjectsAnalysesDuringPeriod: period over: aDateWeekMonthOrYear [
×
353

×
354
        ^self projectEntities collect: [ :project |
×
UNCOV
355
                ProjectAnalysisReport new
×
UNCOV
356
                        projectName: project name;
×
357
                        period: period;
×
358
                        over: aDateWeekMonthOrYear ]
×
359
]
×
360

361
{ #category : 'analysis' }
362
GitMetricExporter >> generateUsersAnalysesDuringPeriod: period over: aDateWeekMonthOrYear [
×
363

×
364
        | userAnalysisReport newMetric result |
×
UNCOV
365
        ^ self userEntities collect: [ :user |
×
UNCOV
366
                  userAnalysisReport := UserAnalysisReport new
×
367
                                                username: user name;
×
368
                                                period: period;
×
369
                                                over: aDateWeekMonthOrYear.
×
370

×
371
                  metrics do: [ :metric |
×
372
                          newMetric := metric new
×
NEW
373
                                               glhImporter: glhImporter;
×
374
                                               jiraImporter: jiraImporter;
×
375
                                               setPeriodSince: (period at: #since)
×
376
                                               until: (period at: #until);
×
377
                                               over: aDateWeekMonthOrYear;
×
378
                                               user: user;
×
379
                                               emailDomain: emailDomain.
×
380

×
381

×
382
                          result := newMetric calculate.
×
383
                          userAnalysisReport metrics at: newMetric name put: result ].
×
384

×
385
                  userAnalysisReport ]
×
386
]
×
387

388
{ #category : 'utilities' }
389
GitMetricExporter >> getAnalysisWithDate: date from: analysisCollection [
×
390

×
391
        ^analysisCollection
×
392
                detect: [ :groupAnalysis | (groupAnalysis period at: #since) = date ]
×
UNCOV
393
                ifNone: [ nil ]
×
UNCOV
394
]
×
395

396
{ #category : 'accessing' }
397
GitMetricExporter >> glhImporter: anImporter [
×
398

×
399
        glhImporter := anImporter withInitialCommits: false; yourself. 
×
400
]
×
401

402
{ #category : 'adding' }
403
GitMetricExporter >> importAnalysesFromS3: bucketName accessKey: accessKey secretKey: secretKey region: region [
×
404

×
405
        | s3 bucket xmlObjects contentElements filesContent |
×
406
        AWSS3Config default
×
UNCOV
407
                accessKeyId: accessKey;
×
UNCOV
408
                secretKey: secretKey;
×
409
                regionName: region.
×
410

×
411
        s3 := AWSS3 new.
×
412
        bucket := s3 bucketNamed: bucketName.
×
413
        xmlObjects := bucket listObjects.
×
414
        contentElements := xmlObjects root elementsSelect: [ :element |
×
415
                                   element isNamed: 'Contents' ].
×
416

×
417
        filesContent := contentElements collect: [ :contentElement |
×
418
                                | keyValue |
×
419
                                keyValue := contentElement contentStringAt: 'Key'.
×
420
                                bucket getObject: keyValue ].
×
421

×
422
        ^ analyses := (filesContent collect: [ :file | STON fromString: file ])
×
423
                              flattened
×
424
]
×
425

426
{ #category : 'initialization' }
427
GitMetricExporter >> initialize [
×
428

×
429
        entities := OrderedCollection new.
×
430
        "set up the minimal date from which we are looking for the commits a particular user in projects"
×
UNCOV
431
        sinceTimeLimit := '2024-01-01' asDateAndTime.
×
UNCOV
432
        runningPeriods := OrderedCollection new.
×
433
        maxCommitWindow := 3.
×
434
        over := Date.
×
435

×
436
        analyses := OrderedCollection new.
×
437

×
438
        metrics := {
×
439
                           CodeAdditionMetric.
×
440
                           CodeDeletionMetric.
×
441
                           CommentContributionMetric.
×
442
                           CommitFrequencyMetric.
×
443
                           CodeChurnMetric.
×
444
                           DelayUntilFirstChurnMetric.
×
445
                           TimeBetweenCommitMetric.
×
446
                           ContributedProjectMetric.
×
447
                CodeAdditionByMRMetric .
×
448
                CodeDeletionByMRMetric .
×
449
                           MergeRequestDurationMetric.
×
450
                           OpenedMergeRequestMetric.
×
451
                           ClosedMergeRequestMetric.
×
452
                           MergedMergeRequestMetric.
×
453
                           SelfMergedUnderAMinuteMergeRequestMetric.
×
454
                           ClosedTicketsMetric.
×
455
                           JiraTimeMRTimeDifferenceMetric.
×
456
                           CommitsNumberByJiraTicketsMetric }
×
457
]
×
458

459
{ #category : 'accessing' }
460
GitMetricExporter >> jiraImporter: anObject [
×
461

×
462
        jiraImporter := anObject
×
463
]
×
464

465
{ #category : 'accessing' }
466
GitMetricExporter >> label: aString [ 
×
467
        label := aString
×
468
]
×
469

470
{ #category : 'accessing' }
UNCOV
471
GitMetricExporter >> maxCommitWindow: anInteger [
×
472
        maxCommitWindow := anInteger abs
×
473
]
×
474

475
{ #category : 'accessing' }
UNCOV
476
GitMetricExporter >> metrics: anObject [
×
477

×
478
        metrics := anObject
×
479
]
×
480

481
{ #category : 'adding' }
482
GitMetricExporter >> onlyImportProjectsOfGroup: groupId [
×
483

×
484
        | group |
×
485
        group := glhImporter importGroup: groupId.
×
UNCOV
486
        projectCache := group toScope: GLHProject
×
UNCOV
487
]
×
488

489
{ #category : 'accessing' }
490
GitMetricExporter >> projectAnalyses [
×
491

×
492
        ^ analyses select: [ :analysis | analysis class = ProjectAnalysisReport ]
×
493
]
×
494

495
{ #category : 'accessing' }
496
GitMetricExporter >> projectEntities [
×
497

×
498
        ^ entities select: [ :entity | entity class = GLHProject ]
×
499
]
×
500

501
{ #category : 'accessing' }
502
GitMetricExporter >> projectMetrics [
×
503

×
504
        ^ metrics select: [ :metric | metric inheritsFrom: ProjectMetric ]
×
505
]
×
506

507
{ #category : 'setup' }
508
GitMetricExporter >> setupAnalysisForProjectsWithIds: projectIds [
×
509

×
510
        | projects |
×
511
        projects := glhImporter importProjects: projectIds.
×
UNCOV
512

×
UNCOV
513
        entities addAll: projects
×
514
]
×
515

516
{ #category : 'setup' }
517
GitMetricExporter >> setupAnalysisForUsersWithNames: userNames [
×
518
        "import all the project since a certain time"
×
519

×
520
        | users |
×
UNCOV
521
        users := userNames collect: [ :username |
×
UNCOV
522
                         glhImporter importUserByUsername: username ].
×
523

×
524
        glhImporter userCatalogue ifNotNil: [
×
525
                glhImporter userCatalogue scrapeAuthorNamesForUsers: users ].
×
526

×
527
        users do: [ :user |
×
528
                | projects |
×
529
                projects := glhImporter importContributedProjectsOfUser: user.
×
530

×
531
                projects do: [ :project |
×
532
                        glhImporter completeImportProject: project ] ].
×
533

×
534
        entities addAll: users.
×
535

×
536
        ^ self
×
537
]
×
538

539
{ #category : 'accessing' }
540
GitMetricExporter >> userAnalyses [
×
541

×
542
        ^ analyses select: [ :analysis | analysis class = UserAnalysisReport ]
×
543
]
×
544

545
{ #category : 'accessing' }
546
GitMetricExporter >> userEntities [
×
547

×
548
        ^ entities select: [ :entity | entity class = GLHUser ]
×
549
]
×
550

551
{ #category : 'accessing' }
552
GitMetricExporter >> userMetrics [
×
553

×
554
        ^ metrics select: [ :metric | metric inheritsFrom: UserMetric ]
×
555
]
×
556

557
{ #category : 'setup' }
558
GitMetricExporter >> withEmailDomain: anEmailDomain [
×
559

×
560
        "define the email domain of your Git user. Usefull to link them between service (i.e. Jira)"
×
561
        emailDomain := anEmailDomain
×
UNCOV
562
]
×
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