From ff6cec92dc35504efefd854ccdbc34a7e79c5abf Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Tue, 6 Aug 2024 18:06:15 +0200 Subject: [PATCH 001/154] feat: export metrics in database with Voyage (#18) * chore: install voyage * feat: create AnalysisReport and base of exportInDB * refactor: change metrics for average metrics --------- Co-authored-by: Kilian B --- .../BaselineOfGitLabHealth.class.st | 24 ++-- src/BaselineOfGitLabHealth/package.st | 2 +- .../AnalysisReport.class.st | 129 ++++++++++++++++++ .../GitMetricExporter.class.st | 60 ++++++++ 4 files changed, 204 insertions(+), 11 deletions(-) create mode 100644 src/GitLabHealth-Model-Analysis/AnalysisReport.class.st diff --git a/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st b/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st index 97122f3..5c6d40d 100644 --- a/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st +++ b/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st @@ -1,11 +1,10 @@ Class { - #name : 'BaselineOfGitLabHealth', - #superclass : 'BaselineOf', - #category : 'BaselineOfGitLabHealth', - #package : 'BaselineOfGitLabHealth' + #name : #BaselineOfGitLabHealth, + #superclass : #BaselineOf, + #category : #BaselineOfGitLabHealth } -{ #category : 'baselines' } +{ #category : #baselines } BaselineOfGitLabHealth >> baseline: spec [ @@ -22,14 +21,14 @@ BaselineOfGitLabHealth >> baseline: spec [ spec package: 'GitLabHealth-Model' with: [ spec requires: #( 'Moose' ) ] ] ] ] -{ #category : 'baselines' } +{ #category : #baselines } BaselineOfGitLabHealth >> customProjectAttributes [ self class environment at: #MooseEntity ifAbsent: [ ^ #(#WithoutFamix) ]. ^ #() ] -{ #category : 'baselines' } +{ #category : #baselines } BaselineOfGitLabHealth >> defineDependencies: spec [ spec @@ -37,14 +36,19 @@ BaselineOfGitLabHealth >> defineDependencies: spec [ with: [ spec repository: 'github://svenvc/NeoJSON/repository' ]. spec baseline: 'MoreLogger' - with: [ spec repository: 'github://badetitou/MoreLogger:main/src' ] + with: [ spec repository: 'github://badetitou/MoreLogger:main/src' ]. + spec + baseline: 'Voyage' + with: [ spec + loads: #('mongo'); + repository: 'github://pharo-nosql/voyage/mc' ] ] -{ #category : 'baselines' } +{ #category : #baselines } BaselineOfGitLabHealth >> defineGroups: spec [ ] -{ #category : 'baselines' } +{ #category : #baselines } BaselineOfGitLabHealth >> definePackages: spec [ spec diff --git a/src/BaselineOfGitLabHealth/package.st b/src/BaselineOfGitLabHealth/package.st index 0d5dae3..1aeec40 100644 --- a/src/BaselineOfGitLabHealth/package.st +++ b/src/BaselineOfGitLabHealth/package.st @@ -1 +1 @@ -Package { #name : 'BaselineOfGitLabHealth' } +Package { #name : #BaselineOfGitLabHealth } diff --git a/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st b/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st new file mode 100644 index 0000000..968baa0 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st @@ -0,0 +1,129 @@ +Class { + #name : #AnalysisReport, + #superclass : #Object, + #instVars : [ + 'username', + 'period', + 'codeAddition', + 'codeDeletion', + 'commitFrequency', + 'commentContribution', + 'mergeRequestDuration', + 'codeChurn', + 'delayUntilFirstChurn' + ], + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #testing } +AnalysisReport class >> isVoyageRoot [ + ^true +] + +{ #category : #accessing } +AnalysisReport >> codeAddition [ + + ^ codeAddition +] + +{ #category : #accessing } +AnalysisReport >> codeAddition: anObject [ + + codeAddition := anObject +] + +{ #category : #accessing } +AnalysisReport >> codeChurn [ + + ^ codeChurn +] + +{ #category : #accessing } +AnalysisReport >> codeChurn: anObject [ + + codeChurn := anObject +] + +{ #category : #accessing } +AnalysisReport >> codeDeletion [ + + ^ codeDeletion +] + +{ #category : #accessing } +AnalysisReport >> codeDeletion: anObject [ + + codeDeletion := anObject +] + +{ #category : #accessing } +AnalysisReport >> commentContribution [ + + ^ commentContribution +] + +{ #category : #accessing } +AnalysisReport >> commentContribution: anObject [ + + commentContribution := anObject +] + +{ #category : #accessing } +AnalysisReport >> commitFrequency [ + + ^ commitFrequency +] + +{ #category : #accessing } +AnalysisReport >> commitFrequency: anObject [ + + commitFrequency := anObject +] + +{ #category : #accessing } +AnalysisReport >> delayUntilFirstChurn [ + + ^ delayUntilFirstChurn +] + +{ #category : #accessing } +AnalysisReport >> delayUntilFirstChurn: anObject [ + + delayUntilFirstChurn := anObject +] + +{ #category : #accessing } +AnalysisReport >> mergeRequestDuration [ + + ^ mergeRequestDuration +] + +{ #category : #accessing } +AnalysisReport >> mergeRequestDuration: anObject [ + + mergeRequestDuration := anObject +] + +{ #category : #accessing } +AnalysisReport >> period [ + + ^ period +] + +{ #category : #accessing } +AnalysisReport >> period: anObject [ + + period := anObject +] + +{ #category : #accessing } +AnalysisReport >> username [ + + ^ username +] + +{ #category : #accessing } +AnalysisReport >> username: anObject [ + + username := anObject +] diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 2eade81..475919e 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -377,6 +377,66 @@ GitMetricExporter >> exportFor: usersWithProjects over: aCollectionOfDateWeekMon self exportFor: aCollectionOfDateWeekMonthOrYear. ] +{ #category : #'as yet unclassified' } +GitMetricExporter >> exportInDB: repository [ + + | entity period analysisReport contribution commentContribution mergeRequestDuration codeChurn delayUntilFirstChurn codeAddition codeDeletion commitFrequency | + repository enableSingleton. + + entity := entities at: 1. + period := runningPeriods at: 1. + + contribution := entity + codeContributionsSince: (period at: #since) + until: (period at: #until) + overA: over. + codeAddition := contribution at: #avgAddition. + codeDeletion := contribution at: #avgDeletion. + + commitFrequency := (entity + commitFrequencySince: (period at: #since) + until: (period at: #until) + overA: over) at: #averageFloat. + + commentContribution := (entity + commentsContributionsSince: + (period at: #since) + until: (period at: #until) + overA: over) at: #avgComments. + + mergeRequestDuration := (entity + mergeRequestDurationSince: + (period at: #since) + until: (period at: #until) + overA: over) at: #avgDuration. + + codeChurn := (entity + codeChurnSince: (period at: #since) + until: (period at: #until) + onACommitWindowOf: maxCommitWindow + overA: over) at: #churn. + + delayUntilFirstChurn := (entity + delayUntilFirstChurnSince: + (period at: #since) + until: (period at: #until) + onACommitWindowOf: maxCommitWindow + overA: over) at: #avgDelay. + + analysisReport := AnalysisReport new + username: entity user name; + period: period; + codeAddition: codeAddition; + codeDeletion: codeDeletion; + commitFrequency: commitFrequency; + commentContribution: commentContribution; + mergeRequestDuration: mergeRequestDuration; + codeChurn: codeChurn; + delayUntilFirstChurn: delayUntilFirstChurn. + + analysisReport save +] + { #category : #projects } GitMetricExporter >> findParticipationOfCommitAuthorNamed: username amongProjects: aCollectionOfProjects [ From 782d8953a10525048e79c230811df954fa7795ff Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Wed, 7 Aug 2024 13:38:39 +0200 Subject: [PATCH 002/154] feat: in exportInDB save all entities for all periods --- .../GitMetricExporter.class.st | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 475919e..79ac967 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -380,13 +380,13 @@ GitMetricExporter >> exportFor: usersWithProjects over: aCollectionOfDateWeekMon { #category : #'as yet unclassified' } GitMetricExporter >> exportInDB: repository [ - | entity period analysisReport contribution commentContribution mergeRequestDuration codeChurn delayUntilFirstChurn codeAddition codeDeletion commitFrequency | + | analysisReport contribution commentContribution mergeRequestDuration codeChurn delayUntilFirstChurn codeAddition codeDeletion commitFrequency | repository enableSingleton. - - entity := entities at: 1. - period := runningPeriods at: 1. - - contribution := entity + + runningPeriods do: [ :period | + entities do: [ + :entity | + contribution := entity codeContributionsSince: (period at: #since) until: (period at: #until) overA: over. @@ -435,6 +435,13 @@ GitMetricExporter >> exportInDB: repository [ delayUntilFirstChurn: delayUntilFirstChurn. analysisReport save + + ] + + ] + + + ] { #category : #projects } From 62bc9629a9cba7040cf9c2da71f8a33bc4b70aff Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Wed, 7 Aug 2024 14:47:07 +0200 Subject: [PATCH 003/154] refactor: generateAnalyses and use them in export --- .../GitMetric4User.class.st | 54 ++++++ .../GitMetricExporter.class.st | 165 +++++++++++------- 2 files changed, 158 insertions(+), 61 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st index e103f4d..7fa59db 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st @@ -507,6 +507,60 @@ GitMetric4User >> foundSuccessorOf: userCommits andCompleteImportForMax: commitL ^ analyzingCommits ] +{ #category : #'as yet unclassified' } +GitMetric4User >> generateAnalysisForPeriod: period over: over withMaxCommitWindows: maxCommitWindow [ + + | contribution codeAddition codeDeletion commitFrequency commentContribution mergeRequestDuration codeChurn delayUntilFirstChurn | + + contribution := self + codeContributionsSince: (period at: #since) + until: (period at: #until) + overA: over. + codeAddition := contribution at: #avgAddition. + codeDeletion := contribution at: #avgDeletion. + + commitFrequency := (self + commitFrequencySince: (period at: #since) + until: (period at: #until) + overA: over) at: #averageFloat. + + commentContribution := (self + commentsContributionsSince: + (period at: #since) + until: (period at: #until) + overA: over) at: #avgComments. + + mergeRequestDuration := (self + mergeRequestDurationSince: + (period at: #since) + until: (period at: #until) + overA: over) at: #avgDuration. + + codeChurn := (self + codeChurnSince: (period at: #since) + until: (period at: #until) + onACommitWindowOf: maxCommitWindow + overA: over) at: #churn. + + delayUntilFirstChurn := (self + delayUntilFirstChurnSince: + (period at: #since) + until: (period at: #until) + onACommitWindowOf: maxCommitWindow + overA: over) at: #avgDelay. + + ^ AnalysisReport new + username: self user name; + period: period; + codeAddition: codeAddition; + codeDeletion: codeDeletion; + commitFrequency: commitFrequency; + commentContribution: commentContribution; + mergeRequestDuration: mergeRequestDuration; + codeChurn: codeChurn; + delayUntilFirstChurn: delayUntilFirstChurn +] + { #category : #initialization } GitMetric4User >> initialize [ diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 79ac967..a3a9a2b 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -9,7 +9,8 @@ Class { 'sinceTimeLimit', 'runningPeriods', 'maxCommitWindow', - 'over' + 'over', + 'analyses' ], #category : #'GitLabHealth-Model-Analysis' } @@ -181,6 +182,18 @@ GitMetricExporter >> addMergeRequestDurationExporter: exportBrowserModel [ withName: columnName ] ] +{ #category : #accessing } +GitMetricExporter >> analyses [ + + ^ analyses +] + +{ #category : #accessing } +GitMetricExporter >> analyses: anObject [ + + analyses := anObject +] + { #category : #'as yet unclassified' } GitMetricExporter >> blockCodeAdditionSince: period [ @@ -378,70 +391,82 @@ GitMetricExporter >> exportFor: usersWithProjects over: aCollectionOfDateWeekMon ] { #category : #'as yet unclassified' } +GitMetricExporter >> exportInCSVOver: aCollectionOfDateWeekMonthOrYear [ + + | exportBrowserModel file | + exportBrowserModel := MiExportModel new. + + self analyses ifNil: [ self generateAnalyses ]. + exportBrowserModel entitiesList: self analyses. + + exportBrowserModel removeColumnForQueryNamed: #Type. + exportBrowserModel removeColumnForQueryNamed: #Name. + + exportBrowserModel + addColumnForQuery: [ :analysis | analysis username ] + withName: #'User name'. + + exportBrowserModel + addColumnForQuery: [ :analysis | analysis period ] + withName: #Period. + + "Code Contribution " + exportBrowserModel + addColumnForQuery: [ :analysis | analysis codeAddition ] + withName: 'code addition (avg)' asSymbol. + + exportBrowserModel + addColumnForQuery: [ :analysis | analysis codeDeletion ] + withName: 'code deletion (avg)' asSymbol. + + "Commit frequencies " + exportBrowserModel + addColumnForQuery: [ :analysis | analysis commitFrequency ] + withName: 'commits frequency (avg) ' asSymbol. + + "comment contribution " + exportBrowserModel + addColumnForQuery: [ :analysis | analysis commentContribution ] + withName: 'comment contribution (avg)' asSymbol. + + "merge Request Duration " + exportBrowserModel + addColumnForQuery: [ :analysis | analysis mergeRequestDuration ] + withName: 'merge Request Duration ' asSymbol. + + "code churn" + exportBrowserModel + addColumnForQuery: [ :analysis | analysis codeChurn ] + withName: + 'churn % (W=' , maxCommitWindow printString , ') ' asSymbol. + + "delay Until First Churn" + exportBrowserModel + addColumnForQuery: [ :analysis | analysis delayUntilFirstChurn ] + withName: + 'delay Until First Churn (W=' , maxCommitWindow printString + , ') ' asSymbol. + + aCollectionOfDateWeekMonthOrYear do: [ :aDateWeekMonthOrYear | + over := aDateWeekMonthOrYear. + file := self constructFilePath: over. + + file writeStreamDo: [ :aStream | + aStream + << 'sep=,'; + << OSPlatform current lineEnding. + exportBrowserModel writeCSVOn: aStream ] ]. + + 'Done computing' recordInfo +] + +{ #category : #export } GitMetricExporter >> exportInDB: repository [ - | analysisReport contribution commentContribution mergeRequestDuration codeChurn delayUntilFirstChurn codeAddition codeDeletion commitFrequency | repository enableSingleton. - - runningPeriods do: [ :period | - entities do: [ - :entity | - contribution := entity - codeContributionsSince: (period at: #since) - until: (period at: #until) - overA: over. - codeAddition := contribution at: #avgAddition. - codeDeletion := contribution at: #avgDeletion. - - commitFrequency := (entity - commitFrequencySince: (period at: #since) - until: (period at: #until) - overA: over) at: #averageFloat. - - commentContribution := (entity - commentsContributionsSince: - (period at: #since) - until: (period at: #until) - overA: over) at: #avgComments. - - mergeRequestDuration := (entity - mergeRequestDurationSince: - (period at: #since) - until: (period at: #until) - overA: over) at: #avgDuration. - - codeChurn := (entity - codeChurnSince: (period at: #since) - until: (period at: #until) - onACommitWindowOf: maxCommitWindow - overA: over) at: #churn. - - delayUntilFirstChurn := (entity - delayUntilFirstChurnSince: - (period at: #since) - until: (period at: #until) - onACommitWindowOf: maxCommitWindow - overA: over) at: #avgDelay. - - analysisReport := AnalysisReport new - username: entity user name; - period: period; - codeAddition: codeAddition; - codeDeletion: codeDeletion; - commitFrequency: commitFrequency; - commentContribution: commentContribution; - mergeRequestDuration: mergeRequestDuration; - codeChurn: codeChurn; - delayUntilFirstChurn: delayUntilFirstChurn. - - analysisReport save - - ] - - ] - - + self analyses ifNil: [ self generateAnalyses ]. + self analyses do: [ :analysis | analysis save ] ] { #category : #projects } @@ -479,6 +504,24 @@ GitMetricExporter >> findProjectsOfUser: aCollection [ self shouldBeImplemented. ] +{ #category : #analysis } +GitMetricExporter >> generateAnalyses [ + + | newAnalyses | + newAnalyses := OrderedCollection new. + + runningPeriods do: [ :period | + newAnalyses addAll: (entities collect: [ :entity | + entity + generateAnalysisForPeriod: period + over: over + withMaxCommitWindows: maxCommitWindow ]) ]. + + self analyses: newAnalyses. + + ^ newAnalyses +] + { #category : #accessing } GitMetricExporter >> glhImporter: anImporter [ From 12697d3c58c0e37ddf253a3d9bcec2a7ec67d0dc Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Wed, 7 Aug 2024 15:36:22 +0200 Subject: [PATCH 004/154] refactor: remove unused methods and classify all methods --- .../GitMetricExporter.class.st | 235 +----------------- 1 file changed, 10 insertions(+), 225 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index a3a9a2b..5375b72 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -34,71 +34,7 @@ GitMetricExporter >> addAPeriodFrom: since to: until [ ^runningPeriods ] -{ #category : #'as yet unclassified' } -GitMetricExporter >> addCodeChurnExporter: exportBrowserModel [ - - | columnName | - maxCommitWindow := 3. - runningPeriods do: [ :period | - columnName := ('churn % (W=' , maxCommitWindow printString , ') ' - , period printString) asSymbol. - - exportBrowserModel - addColumnForQuery: (self blockCodeChurnSince: period) - withName: columnName. - - ]. -] - -{ #category : #'as yet unclassified' } -GitMetricExporter >> addCommentContributionExporter: exportBrowserModel [ - - | columnName | - Smalltalk snapshot: true andQuit: false. - - runningPeriods do: [ :period | - columnName := ('comment contribution (avg) ' , period printString) - asSymbol. - - exportBrowserModel - addColumnForQuery: (self blockCommentsContributionSince: period) - withName: columnName ] -] - -{ #category : #'as yet unclassified' } -GitMetricExporter >> addContributionExporter: exportBrowserModel [ - - | columnName | - "Code Contribution " - runningPeriods do: [ :period | - columnName := ('code addition (avg) ' , period printString) asSymbol. - - exportBrowserModel - addColumnForQuery: (self blockCodeAdditionSince: period) - withName: columnName. - - columnName := ('code deletion (avg) ' , period printString) asSymbol. - exportBrowserModel - addColumnForQuery: (self blockCodeDeletionSince: period) - withName: columnName. - - ] -] - -{ #category : #'as yet unclassified' } -GitMetricExporter >> addDelayUntilFirstChurnExporter: exportBrowserModel [ - - | columnName | - runningPeriods do: [ :period | - columnName := ('delay Until First Churn (W=' , maxCommitWindow printString , ') ' - , period printString) asSymbol. - - exportBrowserModel - addColumnForQuery: (self blockDelayUntilFirstChurnSince: period) - withName: columnName ] -] - -{ #category : #'as yet unclassified' } +{ #category : #adding } GitMetricExporter >> addEntitiesFromUserNames: userNames [ "import all the project since a certain time" @@ -137,7 +73,7 @@ GitMetricExporter >> addEntitiesFromUserNames: userNames [ ^ self ] -{ #category : #'as yet unclassified' } +{ #category : #adding } GitMetricExporter >> addEntitiesFromUserNamesAndProjects: usersWithProjects [ entities addAll: (usersWithProjects associations collect: [ :assoc | @@ -156,32 +92,6 @@ GitMetricExporter >> addEntitiesFromUserNamesAndProjects: usersWithProjects [ ^ self ] -{ #category : #'as yet unclassified' } -GitMetricExporter >> addFrequencyCommitExporter: exportBrowserModel [ - - | columnName | - runningPeriods do: [ :period | - columnName := ('commits frequency (avg) ' , period printString) - asSymbol. - - exportBrowserModel - addColumnForQuery: (self blockCommitFrequencySince: period) - withName: columnName ] -] - -{ #category : #'as yet unclassified' } -GitMetricExporter >> addMergeRequestDurationExporter: exportBrowserModel [ - - | columnName | - runningPeriods do: [ :period | - columnName := ('merge Request Duration ' , period printString) - asSymbol. - - exportBrowserModel - addColumnForQuery: (self blockMergeRequestDurationSince: period) - withName: columnName ] -] - { #category : #accessing } GitMetricExporter >> analyses [ @@ -194,86 +104,7 @@ GitMetricExporter >> analyses: anObject [ analyses := anObject ] -{ #category : #'as yet unclassified' } -GitMetricExporter >> blockCodeAdditionSince: period [ - - ^ [ :metrics | - ((metrics - codeContributionsSince: (period at: #since) - until: (period at: #until) - overA: over) at: #avgAddition) printString ] -] - -{ #category : #'as yet unclassified' } -GitMetricExporter >> blockCodeChurnSince: period [ - "comment stating purpose of instance-side method" - - "scope: class-variables & instance-variables" - - ^ [ :metrics | - ((metrics - codeChurnSince: (period at: #since) - until: (period at: #until) - onACommitWindowOf: maxCommitWindow - overA: over) at: #churn) printString ] -] - -{ #category : #'as yet unclassified' } -GitMetricExporter >> blockCodeDeletionSince: period [ - - ^ [ :metrics | - ((metrics - codeContributionsSince: (period at: #since) - until: (period at: #until) - overA: over) at: #avgDeletion) printString ] -] - -{ #category : #'as yet unclassified' } -GitMetricExporter >> blockCommentsContributionSince: period [ - - ^ [ :metrics | - ((metrics - commentsContributionsSince: (period at: #since) - until: (period at: #until) - overA: over) at: #avgComments) printString ] -] - -{ #category : #'as yet unclassified' } -GitMetricExporter >> blockCommitFrequencySince: period [ - - ^ [ :metrics | - ((metrics - commitFrequencySince: (period at: #since) - until: (period at: #until) - overA: over) at: #averageFloat) printString ] -] - -{ #category : #'as yet unclassified' } -GitMetricExporter >> blockDelayUntilFirstChurnSince: period [ - "comment stating purpose of instance-side method" - - "scope: class-variables & instance-variables" - - ^ [ :metrics | - ((metrics - delayUntilFirstChurnSince: (period at: #since) - until: (period at: #until) - onACommitWindowOf: maxCommitWindow - overA: over) at: #avgDelay) printString ] -] - -{ #category : #'as yet unclassified' } -GitMetricExporter >> blockMergeRequestDurationSince: period [ - - ^ [ :metrics | - - ((metrics - mergeRequestDurationSince: (period at: #since) - until: (period at: #until) - overA: over) at: #avgDuration) printString ] -] - -{ #category : #'as yet unclassified' } +{ #category : #utilities } GitMetricExporter >> constructFilePath: runningOver [ | file | @@ -286,7 +117,7 @@ GitMetricExporter >> constructFilePath: runningOver [ ^ file ] -{ #category : #'as yet unclassified' } +{ #category : #exporting } GitMetricExporter >> debugExportOver: aCollectionOfDateWeekMonthOrYear [ | period | @@ -329,59 +160,13 @@ GitMetricExporter >> entities: aCollection [ entities := aCollection ] -{ #category : #'as yet unclassified' } -GitMetricExporter >> exportAverageOver: aCollectionOfDateWeekMonthOrYear [ - - | file exportBrowserModel | - exportBrowserModel := MiExportModel new. - exportBrowserModel entitiesList: entities. - exportBrowserModel removeColumnForQueryNamed: #Type. - exportBrowserModel removeColumnForQueryNamed: #Name. - - exportBrowserModel - addColumnForQuery: [ :metrics | metrics user name printString ] - withName: #'User name'. - - "Code Contribution " - self addContributionExporter: exportBrowserModel. - - "Commit frequencies " - self addFrequencyCommitExporter: exportBrowserModel. - - "comment contribution " - self addCommentContributionExporter: exportBrowserModel. - - "merge Request Duration " - self addMergeRequestDurationExporter: exportBrowserModel. - - "code churn" - self addCodeChurnExporter: exportBrowserModel. - - "delay Until First Churn" - self addDelayUntilFirstChurnExporter: exportBrowserModel. - - self addMergeRequestDurationExporter: exportBrowserModel. - - aCollectionOfDateWeekMonthOrYear do: [ :aDateWeekMonthOrYear | - over := aDateWeekMonthOrYear. - file := self constructFilePath: over. - - file writeStreamDo: [ :aStream | - aStream - << 'sep=,'; - << OSPlatform current lineEnding. - exportBrowserModel writeCSVOn: aStream ] ]. - - 'Done computing' recordInfo -] - -{ #category : #'as yet unclassified' } +{ #category : #exporting } GitMetricExporter >> exportFor: usersWithProjects [ self exportFor: usersWithProjects over: { Date. Week . Month . Year }. ] -{ #category : #'as yet unclassified' } +{ #category : #exporting } GitMetricExporter >> exportFor: usersWithProjects over: aCollectionOfDateWeekMonthOrYear [ entities ifNil: [ @@ -390,7 +175,7 @@ GitMetricExporter >> exportFor: usersWithProjects over: aCollectionOfDateWeekMon self exportFor: aCollectionOfDateWeekMonthOrYear. ] -{ #category : #'as yet unclassified' } +{ #category : #exporting } GitMetricExporter >> exportInCSVOver: aCollectionOfDateWeekMonthOrYear [ | exportBrowserModel file | @@ -460,7 +245,7 @@ GitMetricExporter >> exportInCSVOver: aCollectionOfDateWeekMonthOrYear [ 'Done computing' recordInfo ] -{ #category : #export } +{ #category : #exporting } GitMetricExporter >> exportInDB: repository [ repository enableSingleton. @@ -499,7 +284,7 @@ GitMetricExporter >> findParticipationOfCommitAuthorNamed: username amongProject ^ itsProjects ] -{ #category : #'as yet unclassified' } +{ #category : #projects } GitMetricExporter >> findProjectsOfUser: aCollection [ self shouldBeImplemented. ] @@ -549,7 +334,7 @@ GitMetricExporter >> maxCommitWindow: anInteger [ maxCommitWindow := anInteger abs ] -{ #category : #'as yet unclassified' } +{ #category : #adding } GitMetricExporter >> onlyImportProjectsOfGroup: groupId [ | group | From 26ab6b4e6c8028030db28b6020b99ade9c7f48e9 Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Thu, 8 Aug 2024 18:01:19 +0200 Subject: [PATCH 005/154] add import for user and their project contributions --- .../GLHUserCatalogue.class.st | 28 ++++ .../User2CommitAuthor.class.st | 40 ++++++ .../GLHMetamodelGenerator.class.st | 7 +- .../GLHModelImporterLocalTest.class.st | 11 +- .../GLHModelImporterTest.class.st | 25 ++-- .../GLHModelImporterTestResource.class.st | 11 +- .../package.st | 2 +- .../GLHApi.class.st | 41 +++++- .../GLHModelImporter.class.st | 136 ++++++++++++++---- 9 files changed, 240 insertions(+), 61 deletions(-) create mode 100644 src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st create mode 100644 src/GitLabHealth-Model-Analysis/User2CommitAuthor.class.st diff --git a/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st b/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st new file mode 100644 index 0000000..39ccf76 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st @@ -0,0 +1,28 @@ +Class { + #name : #GLHUserCatalogue, + #superclass : #Dictionary, + #instVars : [ + 'users' + ], + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #adding } +GLHUserCatalogue >> addUser: aGLHUser [ + + self add: (User2CommitAuthor new user: aGLHUser) +] + +{ #category : #completion } +GLHUserCatalogue >> completeCommitAuthorForUser: aGLHUser [ + |assoc| + assoc := self associationAt: aGLHUser. + assoc value addAll: (aGLHUser commits collect: [:c | c author_name]). + +] + +{ #category : #initialization } +GLHUserCatalogue >> initialize [ + + +] diff --git a/src/GitLabHealth-Model-Analysis/User2CommitAuthor.class.st b/src/GitLabHealth-Model-Analysis/User2CommitAuthor.class.st new file mode 100644 index 0000000..83d63ab --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/User2CommitAuthor.class.st @@ -0,0 +1,40 @@ +Class { + #name : #User2CommitAuthor, + #superclass : #Association, + #instVars : [ + 'user', + 'commitAuthors' + ], + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #adding } +User2CommitAuthor >> addAllCommitAuthors: commitAuthorsList [ + ^ self value addAll: commitAuthorsList +] + +{ #category : #adding } +User2CommitAuthor >> addCommitAuhtor: aCommitAuthor [ + ^ self value add: aCommitAuthor. +] + +{ #category : #accessing } +User2CommitAuthor >> commitAuthors [ + ^ value +] + +{ #category : #initialization } +User2CommitAuthor >> initialize [ + self value: Set new. + +] + +{ #category : #accessing } +User2CommitAuthor >> user [ + ^ key +] + +{ #category : #accessing } +User2CommitAuthor >> user: aGLHUser [ + self key: aGLHUser +] diff --git a/src/GitLabHealth-Model-Generator/GLHMetamodelGenerator.class.st b/src/GitLabHealth-Model-Generator/GLHMetamodelGenerator.class.st index 0876ea7..30b611d 100644 --- a/src/GitLabHealth-Model-Generator/GLHMetamodelGenerator.class.st +++ b/src/GitLabHealth-Model-Generator/GLHMetamodelGenerator.class.st @@ -160,6 +160,7 @@ GLHMetamodelGenerator >> defineRelations [ (group property: #subGroups) <>-* (group property: #group). (project property: #pipelines) <>-* (pipeline property: #project). (project property: #creator) *- (user property: #createdProjects). + (project property: #contributors) *-* (user property: #contributedProjects). (project property: #repository) <>- (repository property: #project). (repository property: #branches) <>-* (branch property: #repository). (branch property: #files) <>-* (file property: #branch). @@ -167,14 +168,14 @@ GLHMetamodelGenerator >> defineRelations [ <>-* (file property: #directoryOwner). (repository property: #commits) <>-* (commit property: #repository). (branch property: #commits) <>-* (commit property: #branch). - + (commit property: #diffs) <>-* (diff property: #commit). (user property: #commits) <>-* (commit property: #commitCreator). - (commit property: #parentCommits) *-* (commit property: #childCommits). + (commit property: #parentCommits) + *-* (commit property: #childCommits). (commit property: #jobs) <>-* (job property: #commit). (pipeline property: #jobs) <>-* (job property: #pipeline). (user property: #jobs) <>-* (job property: #user) - ] { #category : #definition } diff --git a/src/GitLabHealth-Model-Importer-Tests/GLHModelImporterLocalTest.class.st b/src/GitLabHealth-Model-Importer-Tests/GLHModelImporterLocalTest.class.st index 6ecd15e..8e61c1c 100644 --- a/src/GitLabHealth-Model-Importer-Tests/GLHModelImporterLocalTest.class.st +++ b/src/GitLabHealth-Model-Importer-Tests/GLHModelImporterLocalTest.class.st @@ -2,17 +2,16 @@ The test suite for `GLHModelImporter` but not using remote API " Class { - #name : 'GLHModelImporterLocalTest', - #superclass : 'TestCase', + #name : #GLHModelImporterLocalTest, + #superclass : #TestCase, #instVars : [ 'importer', 'model' ], - #category : 'GitLabHealth-Model-Importer-Tests', - #package : 'GitLabHealth-Model-Importer-Tests' + #category : 'GitLabHealth-Model-Importer-Tests' } -{ #category : 'running' } +{ #category : #running } GLHModelImporterLocalTest >> setUp [ super setUp. @@ -22,7 +21,7 @@ GLHModelImporterLocalTest >> setUp [ importer glhModel: model ] -{ #category : 'tests' } +{ #category : #tests } GLHModelImporterLocalTest >> testImportUserAlreadyInModel [ | user | diff --git a/src/GitLabHealth-Model-Importer-Tests/GLHModelImporterTest.class.st b/src/GitLabHealth-Model-Importer-Tests/GLHModelImporterTest.class.st index 978380a..06c1036 100644 --- a/src/GitLabHealth-Model-Importer-Tests/GLHModelImporterTest.class.st +++ b/src/GitLabHealth-Model-Importer-Tests/GLHModelImporterTest.class.st @@ -2,37 +2,36 @@ A GLHModelImporterTest is a test class for testing the behavior of GLHModelImporter " Class { - #name : 'GLHModelImporterTest', - #superclass : 'TestCase', + #name : #GLHModelImporterTest, + #superclass : #TestCase, #instVars : [ 'glphModel', 'glphApi', 'since', 'glhImporter' ], - #category : 'GitLabHealth-Model-Importer-Tests', - #package : 'GitLabHealth-Model-Importer-Tests' + #category : #'GitLabHealth-Model-Importer-Tests' } -{ #category : 'accessing' } +{ #category : #accessing } GLHModelImporterTest class >> resources [ ^ Array with: GLHModelImporterTestResource ] -{ #category : 'running' } +{ #category : #running } GLHModelImporterTest >> glhImporter [ ^ self class resources first current glhImporter ] -{ #category : 'running' } +{ #category : #running } GLHModelImporterTest >> model [ ^ self class resources first current model ] -{ #category : 'test' } +{ #category : #test } GLHModelImporterTest >> testFilterCommitChanges [ | importer collection resultCollection | @@ -53,7 +52,7 @@ GLHModelImporterTest >> testFilterCommitChanges [ self assert: resultCollection size equals: 7 ] -{ #category : 'tests' } +{ #category : #tests } GLHModelImporterTest >> testImportBranch [ | testCodeChurnRepository | @@ -62,20 +61,20 @@ GLHModelImporterTest >> testImportBranch [ self assert: testCodeChurnRepository branches isNotEmpty ] -{ #category : 'tests' } +{ #category : #tests } GLHModelImporterTest >> testImportCommits [ | projectTestCodeChurn | projectTestCodeChurn := (self model allWithType: GLHProject) detect: [ :project | project id = 57841283 ]. - self glhImporter importCommits: projectTestCodeChurn. + self glhImporter importLastestCommitsOfProject: projectTestCodeChurn. self assert: projectTestCodeChurn repository commits last author_name equals: 'Nicolas Hlad' ] -{ #category : 'tests' } +{ #category : #tests } GLHModelImporterTest >> testImportGroup [ | evrefGroup | @@ -87,7 +86,7 @@ GLHModelImporterTest >> testImportGroup [ (evrefGroup projects anySatisfy: [ :project | project id = 57841283 ]) ] -{ #category : 'tests' } +{ #category : #tests } GLHModelImporterTest >> testImportProject [ self assert: (self model allWithType: GLHProject) size equals: 1. diff --git a/src/GitLabHealth-Model-Importer-Tests/GLHModelImporterTestResource.class.st b/src/GitLabHealth-Model-Importer-Tests/GLHModelImporterTestResource.class.st index 09becdc..b4a4b6d 100644 --- a/src/GitLabHealth-Model-Importer-Tests/GLHModelImporterTestResource.class.st +++ b/src/GitLabHealth-Model-Importer-Tests/GLHModelImporterTestResource.class.st @@ -1,21 +1,20 @@ Class { - #name : 'GLHModelImporterTestResource', - #superclass : 'MooseModelTestResource', + #name : #GLHModelImporterTestResource, + #superclass : #MooseModelTestResource, #instVars : [ 'glphApi', 'glhImporter' ], - #category : 'GitLabHealth-Model-Importer-Tests', - #package : 'GitLabHealth-Model-Importer-Tests' + #category : 'GitLabHealth-Model-Importer-Tests' } -{ #category : 'setup' } +{ #category : #setup } GLHModelImporterTestResource >> glhImporter [ ^ glhImporter ] -{ #category : 'setup' } +{ #category : #setup } GLHModelImporterTestResource >> importModel [ model := GLPHEModel new. diff --git a/src/GitLabHealth-Model-Importer-Tests/package.st b/src/GitLabHealth-Model-Importer-Tests/package.st index c8e2168..41aade7 100644 --- a/src/GitLabHealth-Model-Importer-Tests/package.st +++ b/src/GitLabHealth-Model-Importer-Tests/package.st @@ -1 +1 @@ -Package { #name : 'GitLabHealth-Model-Importer-Tests' } +Package { #name : #'GitLabHealth-Model-Importer-Tests' } diff --git a/src/GitLabHealth-Model-Importer/GLHApi.class.st b/src/GitLabHealth-Model-Importer/GLHApi.class.st index d12f853..c25e9d3 100644 --- a/src/GitLabHealth-Model-Importer/GLHApi.class.st +++ b/src/GitLabHealth-Model-Importer/GLHApi.class.st @@ -11,7 +11,7 @@ Class { #classVars : [ 'currentAPI' ], - #category : 'GitLabHealth-Model-Importer' + #category : #'GitLabHealth-Model-Importer' } { #category : #accessing } @@ -266,6 +266,22 @@ GLHApi >> compareProject: aProjectID from: fromSha to: toSha fromProject: fromPr ^ self client get ] +{ #category : #'as yet unclassified' } +GLHApi >> contributedProjectsOfUserId: anUserID orderBy: orderByAttribute simple: simpleBoolean sort: AscOrDesc perPage: perPageNumber page: pageIndex [ + + self client path: self baseAPIUrl , '/users/', anUserID printString, '/contributed_projects'. + + orderByAttribute ifNotNil: [ + self client queryAt: #order_by put: orderByAttribute ]. + simpleBoolean ifNotNil: [ self client queryAt: #simple put: simpleBoolean ]. + AscOrDesc ifNotNil: [ self client queryAt: #sort put: AscOrDesc ]. + perPageNumber ifNotNil: [ self client queryAt: #per_page put: perPageNumber ]. + pageIndex ifNotNil: [ self client queryAt: #page put: pageIndex ]. + + + ^ self client get. +] + { #category : #'api - branches' } GLHApi >> createBranch: newBranchName forProject: aProjectID fromBranch: refBranchName [ @@ -515,3 +531,26 @@ GLHApi >> userWithUsername: anUsername [ ^ self client get: self baseAPIUrl , '/users?username=' , anUsername ] + +{ #category : #'as yet unclassified' } +GLHApi >> usersHuman: humans active: active withoutProjectBots: withoutBot perPage: perPage page: page [ + + self client path: self baseAPIUrl , '/users/'. + + withoutBot ifNotNil: [ + self client queryAt: #without_project_bots put: withoutBot ]. + active ifNotNil: [ self client queryAt: #active put: active ]. + humans ifNotNil: [ self client queryAt: #humans put: humans ]. + perPage ifNotNil: [ self client queryAt: #per_page put: perPage ]. + page ifNotNil: [ self client queryAt: #page put: page ]. + ^ self client get +] + +{ #category : #user } +GLHApi >> usersPerPage: perPage page: page [ + + self client path: self baseAPIUrl , '/users/'. + perPage ifNotNil: [ self client queryAt: #per_page put: perPage ]. + page ifNotNil: [ self client queryAt: #page put: page ]. + ^ self client get +] diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index 1aa3c96..449bb10 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -241,6 +241,32 @@ GLHModelImporter >> glhModel: anObject [ glhModel := anObject ] +{ #category : #'as yet unclassified' } +GLHModelImporter >> importActiveHumanUsers [ + + | newlyFoundUser page foundUsers | + page := 0. + foundUsers := OrderedCollection new. + newlyFoundUser := { true }. + [ newlyFoundUser isNotEmpty ] whileTrue: [ + | results | + page := page + 1. + ('import users page ' , page printString) recordInfo. + results := GLHApi current + usersHuman: true active: true withoutProjectBots: true perPage: 100 page: page. + + newlyFoundUser := self parseUsersResult: results. + "newlyFoundCommit do: [ :c | c repository: aProject repository ]." + + foundUsers addAll: (self glhModel addAll: newlyFoundUser + unless: self blockOnIdEquality) ]. + + + ^ foundUsers + + +] + { #category : #api } GLHModelImporter >> importAllGroups [ @@ -305,37 +331,6 @@ GLHModelImporter >> importCommitOfProject: anProject withId: anID [ ^ commit ] -{ #category : #'private - api' } -GLHModelImporter >> importCommits: aGLHProject [ - "limited to the last 20 commits" - - | results parsedResults | - results := self glhApi - commitsOfProject: aGLHProject id - forRefName: nil - since: nil - until: nil - path: nil - author: nil - all: nil - with_stats: true - firstParent: nil - order: nil - trailers: nil - perPage: nil - page: nil. - parsedResults := self parseCommitsResult: results. - self glhModel addAll: parsedResults unless: self blockOnIdEquality. - - parsedResults do: [ :commit | - commit repository: aGLHProject repository ]. - - self withCommitDiffs ifTrue: [ - parsedResults do: [ :commit | self importDiffOfCommit: commit ] ]. - - ^ parsedResults. -] - { #category : #'as yet unclassified' } GLHModelImporter >> importCommitsFollowing: aCommit upToDays: aNumberOfDay [ "import the 'n' commits of a project starting from an initial 'aCommit' commit. @@ -500,6 +495,38 @@ GLHModelImporter >> importCommitsOfBranch: aGLHBranch forRefName: refName until: until: toDate ] +{ #category : #'as yet unclassified' } +GLHModelImporter >> importContributedProjectsOfUser: aGLHUser [ + | newlyFoundElmts page foundElmts | + page := 0. + foundElmts := OrderedCollection new. + newlyFoundElmts := { true }. + [ newlyFoundElmts isNotEmpty ] whileTrue: [ + | results | + page := page + 1. + ('import contributed project of user ', aGLHUser name ,' page ' , page printString) recordInfo. + results := GLHApi current + contributedProjectsOfUserId: aGLHUser id + orderBy: 'created_at' + simple: true + sort: 'desc' + perPage: 100 + page: page. + + newlyFoundElmts := self parseArrayOfProject: results. + "newlyFoundCommit do: [ :c | c repository: aProject repository ]." + + foundElmts addAll: + (self glhModel + addAll: newlyFoundElmts + unless: self blockOnIdEquality) ]. + + self flag: 'TODO: uncomment that contributed project are added to user'. + "aGLHUser contributedProjects addAll: foundElmts unless: self blockOnIdEquality. " + + ^ foundElmts +] + { #category : #'as yet unclassified' } GLHModelImporter >> importCreatorOfCommit: aCommit [ @@ -601,6 +628,37 @@ GLHModelImporter >> importJobsOf: aPipeline [ ] +{ #category : #'private - api' } +GLHModelImporter >> importLastestCommitsOfProject: aGLHProject [ + "limited to the last 20 commits" + + | results parsedResults | + results := self glhApi + commitsOfProject: aGLHProject id + forRefName: nil + since: nil + until: nil + path: nil + author: nil + all: nil + with_stats: true + firstParent: nil + order: nil + trailers: nil + perPage: nil + page: nil. + parsedResults := self parseCommitsResult: results. + self glhModel addAll: parsedResults unless: self blockOnIdEquality. + + parsedResults do: [ :commit | + commit repository: aGLHProject repository ]. + + self withCommitDiffs ifTrue: [ + parsedResults do: [ :commit | self importDiffOfCommit: commit ] ]. + + ^ parsedResults. +] + { #category : #commit } GLHModelImporter >> importParentCommitsOfCommit: aGLHCommit forOnly: number [ @@ -1044,6 +1102,22 @@ GLHModelImporter >> parseUserResult: result [ ^ reader nextAs: GLHUser ] +{ #category : #private } +GLHModelImporter >> parseUsersResult: result [ + + | reader | + reader := NeoJSONReader on: result readStream. + + reader mapInstVarsFor: GLHUser. + + reader + for: #ArrayOfUser + customDo: [ :customMappting | + customMappting listOfElementSchema: GLHUser ]. + + ^ reader nextAs: #ArrayOfUser +] + { #category : #'private - api' } GLHModelImporter >> pipelinesOf: aProjectID [ From 06836e5bcfe1908541d1ea7bf6a36a2204292169 Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Fri, 9 Aug 2024 11:05:47 +0200 Subject: [PATCH 006/154] remove method that are only use by themselves --- .../GLHModelImporter.class.st | 33 ------------------- 1 file changed, 33 deletions(-) diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index 1aa3c96..4aa4ce2 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -601,32 +601,6 @@ GLHModelImporter >> importJobsOf: aPipeline [ ] -{ #category : #commit } -GLHModelImporter >> importParentCommitsOfCommit: aGLHCommit forOnly: number [ - - | parentsIds commits | - commits := OrderedCollection new. - number = 0 ifTrue: [ - ^ commits - add: aGLHCommit; - yourself ]. - - parentsIds := aGLHCommit parent_ids. - - commits addAll: (parentsIds collect: [ :id | - self - importCommitOfProject: aGLHCommit repository project - withId: id. - (self selectEntityType: GLHCommit overAttribut: #id equalTo: id) - first ]). - - - ^ commits , (commits collect: [ :parentCommit | - self - importParentCommitsOfCommit: parentCommit - forOnly: number - 1 ]) flatten -] - { #category : #commit } GLHModelImporter >> importParentCommitsOfCommit: aGLHCommit since: aDate [ @@ -1053,13 +1027,6 @@ GLHModelImporter >> pipelinesOf: aProjectID [ ^ self parsePipelinesResult: result ] -{ #category : #'as yet unclassified' } -GLHModelImporter >> selectEntityType: aType overAttribut: aSelector equalTo: value [ - - ^ (self glhModel allWithType: aType) - select: [ :entity | (entity perform: aSelector) = value ] -] - { #category : #'private - api' } GLHModelImporter >> subGroupsOf: aGroupID [ From 626e5a2ccb7dde8890d663e54cb7fb7ddf05e210 Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Fri, 9 Aug 2024 11:08:45 +0200 Subject: [PATCH 007/154] remove deprecated method --- .../GLHModelImporter.class.st | 22 ------------------- .../GLPHModelImporter.class.st | 2 +- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index 4aa4ce2..7acaa1d 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -894,28 +894,6 @@ GLHModelImporter >> parseCommitsResult: result [ ^ reader nextAs: #ArrayOfCommit ] -{ #category : #private } -GLHModelImporter >> parseDiffResult: result [ - - | reader | - self - deprecated: 'Use #newParseDiffResult: instead' - on: '28 June 2024' - in: - 'Pharo-11.0.0+build.726.sha.aece1b5473acf3830a0e082c1bc3a15d4ff3522b (64 Bit)'. - reader := NeoJSONReader on: result readStream. - reader for: GLHDiff do: [ :mapping | - mapping mapInstVars: - #( deleted_file new_file new_path old_path renamed_file ). - mapping mapInstVar: #diffString to: #diff ]. - - reader - for: #ArrayOfDiffs - customDo: [ :customMappting | - customMappting listOfElementSchema: GLHDiff ]. - ^ reader nextAs: #ArrayOfDiffs -] - { #category : #private } GLHModelImporter >> parseFileTreeResult: aResult [ diff --git a/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st b/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st index 4b9f134..34daab1 100644 --- a/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st +++ b/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st @@ -216,7 +216,7 @@ GLPHModelImporter >> importDiffOfMergeRequest: aMergeRequest [ diffsMergeRequestOfProject: aMergeRequest project_id withId: aMergeRequest iid. - diffsResult := self parseDiffResult: result. + diffsResult := self newParseDiffResult: result. aMergeRequest diffs From 3bf4cef0fd23cb84aad205a94e0c418f2f75b414 Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Fri, 9 Aug 2024 11:28:09 +0200 Subject: [PATCH 008/154] organize all readers the same ways --- src/GitLabHealth-Model-Importer/GLHModelImporter.class.st | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index 1aa3c96..0e2dda4 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -123,7 +123,7 @@ GLHModelImporter >> completeImportedCommit: aCommit [ ^ aCommit ] -{ #category : #private } +{ #category : #'private - configure reader' } GLHModelImporter >> configureReaderForCommit: reader [ reader for: GLHCommit do: [ :mapping | @@ -155,7 +155,7 @@ GLHModelImporter >> configureReaderForCommit: reader [ ] -{ #category : #'as yet unclassified' } +{ #category : #'private - configure reader' } GLHModelImporter >> configureReaderForDiffs: reader [ reader for: GLHDiff do: [ :mapping | @@ -170,7 +170,7 @@ GLHModelImporter >> configureReaderForDiffs: reader [ ^ reader ] -{ #category : #private } +{ #category : #'private - configure reader' } GLHModelImporter >> configureReaderForGroup: reader [ reader for: GLHGroup do: [ :mapping | From 90adcab17bda42c64f64a3f8f5c41bcb842ab4b0 Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Fri, 9 Aug 2024 11:47:52 +0200 Subject: [PATCH 009/154] fix import project location --- .../GLHModelImporter.class.st | 30 +++++++++++++++---- .../GLPHModelImporter.class.st | 23 -------------- 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index 1aa3c96..9a34e20 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -659,6 +659,18 @@ GLHModelImporter >> importPipelinesOfProject: aGLHProject [ aGLHProject pipelines add: pipeline unless: self blockOnIdEquality] ] +{ #category : #projects } +GLHModelImporter >> importProject: aProjectID [ + + | result projectResult | + ('Import project with id: ' , aProjectID printString) recordInfo. + + result := self glhApi project: aProjectID. + projectResult := self parseProjectResult: result. + + ^ self completeImportProject: projectResult +] + { #category : #imports } GLHModelImporter >> importProjects [ @@ -667,11 +679,8 @@ GLHModelImporter >> importProjects [ { #category : #projects } GLHModelImporter >> importProjects: aCollectionOfProjectID [ - - ^ aCollectionOfProjectID collect: [ :id | - self importProject: id. - ] - + + ^ aCollectionOfProjectID collect: [ :id | self importProject: id ] ] { #category : #imports } @@ -1026,6 +1035,17 @@ GLHModelImporter >> parsePipelinesResult: result [ ^ reader nextAs: #ArrayOfPipelines ] +{ #category : #parsing } +GLHModelImporter >> parseProjectResult: aResult [ + | reader | + reader := NeoJSONReader on: aResult readStream. + reader for: GLHProject do: [ :mapping | + mapping mapInstVars. ]. +" reader mapInstVarsFor: GLHProject." + + ^ reader nextAs: GLHProject +] + { #category : #private } GLHModelImporter >> parseSubGroupResult: aResult [ diff --git a/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st b/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st index 4b9f134..bcb346e 100644 --- a/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st +++ b/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st @@ -380,18 +380,6 @@ GLPHModelImporter >> importMergeResquestMerger: aGLPHEMergeRequest [ aGLPHEMergeRequest merge_user: (self importUser: authorID) ] -{ #category : #'as yet unclassified' } -GLPHModelImporter >> importProject: aProjectID [ - - | result projectResult | - ('Import project with id: ' , aProjectID printString) recordInfo. - - result := self glhApi project: aProjectID. - projectResult := self parseProjectResult: result. - - ^ self completeImportProject: projectResult -] - { #category : #'private - api' } GLPHModelImporter >> importRepository: aGLHRepository [ @@ -465,17 +453,6 @@ GLPHModelImporter >> parseMergeRequestResult: result [ ^ generalReader nextAs: #ArrayOfMergeRequest ] -{ #category : #parsing } -GLPHModelImporter >> parseProjectResult: aResult [ - | reader | - reader := NeoJSONReader on: aResult readStream. - reader for: GLHProject do: [ :mapping | - mapping mapInstVars. ]. -" reader mapInstVarsFor: GLHProject." - - ^ reader nextAs: GLHProject -] - { #category : #accessing } GLPHModelImporter >> withCommitsSince: someDays [ "substract the current date with a given number of days. Use to retrieve the commits submit in the last giving days" From 6863623d1b9f9159ef050eda4be93c148b8e2805 Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Fri, 9 Aug 2024 11:55:07 +0200 Subject: [PATCH 010/154] remove an additional deprecated and without sender method --- .../GLHModelImporter.class.st | 45 ------------------- 1 file changed, 45 deletions(-) diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index 7acaa1d..25b08ed 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -390,51 +390,6 @@ GLHModelImporter >> importCommitsOProject: aProject since: fromDate until: toDat ^ self glhModel addAll: foundCommit unless: self blockOnIdEquality ] -{ #category : #api } -GLHModelImporter >> importCommitsOf: aGLHProject withStats: aBoolean until: toDate [ - - | newlyFoundCommit page | - - self deprecated: [ ] . - - page := 0. - newlyFoundCommit := { true }. - [ newlyFoundCommit isNotEmpty ] whileTrue: [ - | results parsedResults existingCommits | - page := page + 1. - ('import commit page ' , page printString) recordInfo. - results := self glhApi - commitsOfProject: aGLHProject id - forRefName: nil - since: nil - until: nil - path: nil - author: nil - all: nil - with_stats: aBoolean - firstParent: nil - order: nil - trailers: nil - perPage: 100 - page: page. - parsedResults := self parseCommitsResult: results. - existingCommits := aGLHProject mooseModel allWithType: GLHCommit. - - newlyFoundCommit := parsedResults reject: [ :commitParsed | - (toDate isNil or: [ - commitParsed committed_date - < toDate asDateAndTime ]) or: [ - existingCommits anySatisfy: [ :existingCommit | - existingCommit id = commitParsed id ] ] ]. - aGLHProject mooseModel addAll: newlyFoundCommit. - aGLHProject repository commits addAll: newlyFoundCommit ]. - - - self withCommitDiffs ifTrue: [ - aGLHProject repository commits do: [ :commit | - self importDiffOfCommit: commit ] ] -] - { #category : #commit } GLHModelImporter >> importCommitsOfBranch: aGLHBranch forRefName: refName since: fromDate [ From f1de289b8729c36105d202ebeeeb520e385715a7 Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Fri, 9 Aug 2024 12:20:25 +0200 Subject: [PATCH 011/154] add method to scrap commit author name associated to a user with closely matching names --- .../GLHUserCatalogue.class.st | 56 ++++++++++++- .../MooseAbstractGroup.extension.st | 2 +- .../GLHModelImporter.class.st | 79 ++++++++++++++----- src/GitLabHealth-Model/GLHProject.class.st | 38 +++++++-- src/GitLabHealth-Model/GLHUser.class.st | 27 ++++++- .../GLPHModelImporter.class.st | 22 ------ .../GLHDiff.extension.st | 19 ----- 7 files changed, 170 insertions(+), 73 deletions(-) delete mode 100644 src/GitProject-FamixConnector-Model/GLHDiff.extension.st diff --git a/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st b/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st index 39ccf76..26a3a76 100644 --- a/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st +++ b/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st @@ -7,6 +7,26 @@ Class { #category : #'GitLabHealth-Model-Analysis' } +{ #category : #'as yet unclassified' } +GLHUserCatalogue class >> scrapeContributedProjectsForCommitAuthorsRelatedToUser: aGLHUser [ + "get all " + + |maxProjects itsProjects| + maxProjects := 5. + + GLHModelImporter current withCommitDiffs: false. + itsProjects := aGLHUser contributedProjects ifEmpty: [(GLHModelImporter current importContributedProjectsOfUser: aGLHUser)]. + + itsProjects collect: [ :project | + GLHModelImporter current importAndLoadLatestsCommitsOfProject: project. + ] from: 1 to: (itsProjects size > maxProjects ifTrue: [ maxProjects ] ifFalse: [ itsProjects size ] ) . + + ^ (aGLHUser commits collect: [ :commit | commit author_name ]) asSet. + + + +] + { #category : #adding } GLHUserCatalogue >> addUser: aGLHUser [ @@ -14,11 +34,12 @@ GLHUserCatalogue >> addUser: aGLHUser [ ] { #category : #completion } -GLHUserCatalogue >> completeCommitAuthorForUser: aGLHUser [ - |assoc| +GLHUserCatalogue >> completeAuthorNameOfUser: aGLHUser with: authorNames [ + + | assoc | assoc := self associationAt: aGLHUser. - assoc value addAll: (aGLHUser commits collect: [:c | c author_name]). - + assoc value addAll: + authorNames ] { #category : #initialization } @@ -26,3 +47,30 @@ GLHUserCatalogue >> initialize [ ] + +{ #category : #'as yet unclassified' } +GLHUserCatalogue >> scrapeAuthorNameForAllUsers [ + + self associations do: [ :assoc | + | aGLHUser| + aGLHUser := assoc key. + assoc value addAll: (GLHUserCatalogue + scrapeContributedProjectsForCommitAuthorsRelatedToUser: aGLHUser) + ] + +] + +{ #category : #'as yet unclassified' } +GLHUserCatalogue >> scrapeAuthorNameForUser: aGLHUser [ + | assoc | + assoc := self associationAt: aGLHUser. + assoc value addAll: (GLHUserCatalogue scrapeContributedProjectsForCommitAuthorsRelatedToUser: aGLHUser). +] + +{ #category : #completion } +GLHUserCatalogue >> searchModelForAuthorNamesOfUser: aGLHUser [ + |assoc| + assoc := self associationAt: aGLHUser. + assoc value addAll: (aGLHUser commits collect: [:c | c author_name]). + +] diff --git a/src/GitLabHealth-Model-Extension/MooseAbstractGroup.extension.st b/src/GitLabHealth-Model-Extension/MooseAbstractGroup.extension.st index 808b195..201be1d 100644 --- a/src/GitLabHealth-Model-Extension/MooseAbstractGroup.extension.st +++ b/src/GitLabHealth-Model-Extension/MooseAbstractGroup.extension.st @@ -13,7 +13,7 @@ MooseAbstractGroup >> addAll: anElmtCollection ofType: aType unless: aConditionA | originalCollection returnCollection | originalCollection := (self allWithType: aType). "Create same kind of collection" - returnCollection := self species new. + returnCollection := OrderedCollection new. anElmtCollection do: [ :anElmt | originalCollection diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index 449bb10..e8e6c50 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -86,12 +86,39 @@ GLHModelImporter >> blockOnNameEquality [ ^ self blockEqualityOn: #name ] +{ #category : #commit } +GLHModelImporter >> chainsCommitsFrom: commitsCollection [ + + | dic | + + ('Chains ', commitsCollection size printString , ' commits') recordInfo. + + dic := ((self glhModel allWithType: GLHCommit) collect: [ :commit | + commit id -> commit ]) asSet asDictionary. + + commitsCollection do: [ :commit | + commit parent_ids do: [ :parentId | + dic + at: parentId + ifPresent: [ :parentCommit | + parentCommit childCommits + add: commit + unless: self blockOnIdEquality ] + ifAbsent: [ ] ] ]. + ^ commitsCollection +] + { #category : #'private - api' } GLHModelImporter >> completeImportProject: aGLHProject [ - |importedProject| + + | importedProject | ('Complete import of project: ' , aGLHProject id printString) recordInfo. - importedProject := self glhModel add: aGLHProject unless: (self blockOnIdEquality ). + aGLHProject repository ifNotNil: [ ^ aGLHProject ]. + + importedProject := self glhModel + add: aGLHProject + unless: self blockOnIdEquality. self importPipelinesOfProject: importedProject. @@ -286,6 +313,17 @@ GLHModelImporter >> importAllGroups [ ^ foundGroups ] +{ #category : #'as yet unclassified' } +GLHModelImporter >> importAndLoadLatestsCommitsOfProject: aGLHProject [ + + | commits | + self completeImportProject: aGLHProject. + commits := self importLastestCommitsOfProject: aGLHProject. + commits do: [ :commit | self completeImportedCommit: commit ]. + self chainsCommitsFrom: commits. + ^ commits +] + { #category : #'private - api' } GLHModelImporter >> importCommit: aCommitID ofProject: aGLHProject [ @@ -496,7 +534,8 @@ GLHModelImporter >> importCommitsOfBranch: aGLHBranch forRefName: refName until: ] { #category : #'as yet unclassified' } -GLHModelImporter >> importContributedProjectsOfUser: aGLHUser [ +GLHModelImporter >> importContributedProjectsOfUser: aGLHUser [ + | newlyFoundElmts page foundElmts | page := 0. foundElmts := OrderedCollection new. @@ -504,25 +543,27 @@ GLHModelImporter >> importContributedProjectsOfUser: aGLHUser [ [ newlyFoundElmts isNotEmpty ] whileTrue: [ | results | page := page + 1. - ('import contributed project of user ', aGLHUser name ,' page ' , page printString) recordInfo. + ('import contributed project of user ' , aGLHUser name , ' page ' + , page printString) recordInfo. results := GLHApi current contributedProjectsOfUserId: aGLHUser id - orderBy: 'created_at' - simple: true - sort: 'desc' + orderBy: 'created_at' + simple: true + sort: 'desc' perPage: 100 page: page. newlyFoundElmts := self parseArrayOfProject: results. - "newlyFoundCommit do: [ :c | c repository: aProject repository ]." foundElmts addAll: (self glhModel addAll: newlyFoundElmts unless: self blockOnIdEquality) ]. - self flag: 'TODO: uncomment that contributed project are added to user'. - "aGLHUser contributedProjects addAll: foundElmts unless: self blockOnIdEquality. " + + aGLHUser contributedProjects + addAll: foundElmts + unless: self blockOnIdEquality. ^ foundElmts ] @@ -769,16 +810,18 @@ GLHModelImporter >> importRepository: aGLHRepository [ ('import the repository of project ' , aGLHRepository project name) recordInfo. - resultBranches := self glhApi branchesOfRepository: + resultBranches := GLHApi current branchesOfRepository: aGLHRepository project id. branches := self parseBranchesResult: resultBranches. - ('import the branches of project ') recordInfo. + 'import the branches of project ' recordInfo. branches := aGLHRepository branches - addAll: branches - unless: self blockOnNameEquality. - branches := self glhModel addAll: branches unless: self blockOnNameEquality. + addAll: branches + unless: self blockOnNameEquality. + branches := self glhModel + addAll: branches + unless: self blockOnNameEquality. self withFiles ifTrue: [ @@ -792,13 +835,13 @@ GLHModelImporter >> importRepository: aGLHRepository [ GLHModelImporter >> importUser: aUserID [ | result userResult | - (glhModel allWithType: GLHUser) + (self glhModel allWithType: GLHUser) detect: [ :user | user id = aUserID ] ifFound: [ :user | ^ user ]. ('Import user: ' , aUserID printString) recordInfo. - result := self glhApi user: aUserID. + result := GLHApi current user: aUserID. userResult := self parseUserResult: result. - ^ glhModel add: userResult unless: self blockOnIdEquality + ^ self glhModel add: userResult unless: self blockOnIdEquality ] { #category : #user } diff --git a/src/GitLabHealth-Model/GLHProject.class.st b/src/GitLabHealth-Model/GLHProject.class.st index f74e08f..2e28733 100644 --- a/src/GitLabHealth-Model/GLHProject.class.st +++ b/src/GitLabHealth-Model/GLHProject.class.st @@ -18,6 +18,7 @@ A GitLab Project ### Other | Relation | Origin | Opposite | Type | Comment | |---| +| `contributors` | `GLHProject` | `contributedProjects` | `GLHUser` | | | `creator` | `GLHProject` | `createdProjects` | `GLHUser` | | @@ -44,18 +45,19 @@ Class { #traits : 'FamixTNamedEntity', #classTraits : 'FamixTNamedEntity classTrait', #instVars : [ - '#id => FMProperty', - '#topics => FMProperty', '#archived => FMProperty', - '#description => FMProperty', - '#readme_url => FMProperty', '#avatar_url => FMProperty', - '#web_url => FMProperty', + '#contributors => FMMany type: #GLHUser opposite: #contributedProjects', + '#creator => FMOne type: #GLHUser opposite: #createdProjects', '#creator_id => FMProperty', + '#description => FMProperty', '#group => FMOne type: #GLHGroup opposite: #projects', + '#id => FMProperty', '#pipelines => FMMany type: #GLHPipeline opposite: #project', - '#creator => FMOne type: #GLHUser opposite: #createdProjects', - '#repository => FMOne type: #GLHRepository opposite: #project' + '#readme_url => FMProperty', + '#repository => FMOne type: #GLHRepository opposite: #project', + '#topics => FMProperty', + '#web_url => FMProperty' ], #category : #'GitLabHealth-Model-Entities' } @@ -69,6 +71,12 @@ GLHProject class >> annotation [ ^ self ] +{ #category : #adding } +GLHProject >> addContributor: anObject [ + + ^ self contributors add: anObject +] + { #category : #adding } GLHProject >> addPipeline: anObject [ @@ -103,6 +111,22 @@ GLHProject >> avatar_url: anObject [ avatar_url := anObject ] +{ #category : #accessing } +GLHProject >> contributors [ + "Relation named: #contributors type: #GLHUser opposite: #contributedProjects" + + + + ^ contributors +] + +{ #category : #accessing } +GLHProject >> contributors: anObject [ + + + contributors value: anObject +] + { #category : #accessing } GLHProject >> creator [ "Relation named: #creator type: #GLHUser opposite: #createdProjects" diff --git a/src/GitLabHealth-Model/GLHUser.class.st b/src/GitLabHealth-Model/GLHUser.class.st index 8807f97..c4996ed 100644 --- a/src/GitLabHealth-Model/GLHUser.class.st +++ b/src/GitLabHealth-Model/GLHUser.class.st @@ -13,6 +13,7 @@ A GitLab User ### Other | Relation | Origin | Opposite | Type | Comment | |---| +| `contributedProjects` | `GLHUser` | `contributors` | `GLHProject` | | | `createdProjects` | `GLHUser` | `creator` | `GLHProject` | | @@ -55,12 +56,14 @@ Class { '#bio => FMProperty', '#bot => FMProperty', '#commits => FMMany type: #GLHCommit opposite: #commitCreator', + '#contributedProjects => FMMany type: #GLHProject opposite: #contributors', '#createdProjects => FMMany type: #GLHProject opposite: #creator', '#created_at => FMProperty', '#followers => FMProperty', '#following => FMProperty', '#id => FMProperty', '#job_title => FMProperty', + '#jobs => FMMany type: #GLHJob opposite: #user', '#linkedin => FMProperty', '#location => FMProperty', '#name => FMProperty', @@ -73,8 +76,7 @@ Class { '#username => FMProperty', '#web_url => FMProperty', '#website_url => FMProperty', - '#work_information => FMProperty', - '#jobs => FMMany type: #GLHJob opposite: #user' + '#work_information => FMProperty' ], #category : #'GitLabHealth-Model-Entities' } @@ -94,6 +96,12 @@ GLHUser >> addCommit: anObject [ ^ self commits add: anObject ] +{ #category : #adding } +GLHUser >> addContributedProject: anObject [ + + ^ self contributedProjects add: anObject +] + { #category : #adding } GLHUser >> addCreatedProject: anObject [ @@ -171,6 +179,21 @@ GLHUser >> commitsGroup [ ^ MooseSpecializedGroup withAll: self commits asSet ] +{ #category : #accessing } +GLHUser >> contributedProjects [ + "Relation named: #contributedProjects type: #GLHProject opposite: #contributors" + + + ^ contributedProjects +] + +{ #category : #accessing } +GLHUser >> contributedProjects: anObject [ + + + contributedProjects value: anObject +] + { #category : #accessing } GLHUser >> createdProjects [ "Relation named: #createdProjects type: #GLHProject opposite: #creator" diff --git a/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st b/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st index 4b9f134..76ce551 100644 --- a/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st +++ b/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st @@ -13,28 +13,6 @@ GLPHModelImporter >> blockForDiffRangeEquality [ existing newLineRange = new newLineRange ] ] ] ] -{ #category : #commit } -GLPHModelImporter >> chainsCommitsFrom: commitsCollection [ - - | dic | - - ('Chains ', commitsCollection size printString , ' commits') recordInfo. - - dic := ((self glhModel allWithType: GLHCommit) collect: [ :commit | - commit id -> commit ]) asSet asDictionary. - - commitsCollection do: [ :commit | - commit parent_ids do: [ :parentId | - dic - at: parentId - ifPresent: [ :parentCommit | - parentCommit childCommits - add: commit - unless: self blockOnIdEquality ] - ifAbsent: [ ] ] ]. - ^ commitsCollection -] - { #category : #commit } GLPHModelImporter >> commitsOfProject: aGLHProject forRefName: refName until: toDate [ diff --git a/src/GitProject-FamixConnector-Model/GLHDiff.extension.st b/src/GitProject-FamixConnector-Model/GLHDiff.extension.st deleted file mode 100644 index 3e04344..0000000 --- a/src/GitProject-FamixConnector-Model/GLHDiff.extension.st +++ /dev/null @@ -1,19 +0,0 @@ -Extension { #name : #GLHDiff } - -{ #category : #'*GitProject-FamixConnector-Model-accessing' } -GLHDiff >> onSourceEntity [ - "Relation named: #onSourceEntity type: #FamixTSourceEntity opposite: #appliedDiffs" - - - - - - ^ self attributeAt: #onSourceEntity ifAbsent: [ nil ] -] - -{ #category : #'*GitProject-FamixConnector-Model-accessing' } -GLHDiff >> onSourceEntity: anObject [ - - - self attributeAt: #onSourceEntity put: (FMMultivalueLink on: self update: #appliedDiffs from: self onSourceEntity to: anObject). -] From 686635c418f4e51b82be973d0dbb2594807a1072 Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Fri, 9 Aug 2024 13:56:37 +0200 Subject: [PATCH 012/154] add a jira connector to the jira project --- .../BaselineOfGitLabHealth.class.st | 56 +++++++-- src/BaselineOfGitLabHealth/package.st | 2 +- .../GLHCommit.extension.st | 8 +- .../GitProjectJiraConnectorGenerator.class.st | 56 +++++++++ .../package.st | 1 + .../GLHCommit.extension.st | 20 ++++ .../GLPHEMergeRequest.extension.st | 27 +++++ .../GPJCModel.class.st | 20 ++++ .../JPIssue.extension.st | 46 ++++++++ src/GitProject-JiraConnector-Model/package.st | 1 + .../GPJCConnectorTest.class.st | 109 ++++++++++++++++++ src/GitProject-JiraConnector-Tests/package.st | 1 + .../GPJCConnector.class.st | 72 ++++++++++++ src/GitProject-JiraConnector/package.st | 1 + 14 files changed, 408 insertions(+), 12 deletions(-) create mode 100644 src/GitProject-JiraConnector-Generator/GitProjectJiraConnectorGenerator.class.st create mode 100644 src/GitProject-JiraConnector-Generator/package.st create mode 100644 src/GitProject-JiraConnector-Model/GLHCommit.extension.st create mode 100644 src/GitProject-JiraConnector-Model/GLPHEMergeRequest.extension.st create mode 100644 src/GitProject-JiraConnector-Model/GPJCModel.class.st create mode 100644 src/GitProject-JiraConnector-Model/JPIssue.extension.st create mode 100644 src/GitProject-JiraConnector-Model/package.st create mode 100644 src/GitProject-JiraConnector-Tests/GPJCConnectorTest.class.st create mode 100644 src/GitProject-JiraConnector-Tests/package.st create mode 100644 src/GitProject-JiraConnector/GPJCConnector.class.st create mode 100644 src/GitProject-JiraConnector/package.st diff --git a/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st b/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st index 97122f3..d30921e 100644 --- a/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st +++ b/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st @@ -1,11 +1,10 @@ Class { - #name : 'BaselineOfGitLabHealth', - #superclass : 'BaselineOf', - #category : 'BaselineOfGitLabHealth', - #package : 'BaselineOfGitLabHealth' + #name : #BaselineOfGitLabHealth, + #superclass : #BaselineOf, + #category : #BaselineOfGitLabHealth } -{ #category : 'baselines' } +{ #category : #baselines } BaselineOfGitLabHealth >> baseline: spec [ @@ -13,6 +12,7 @@ BaselineOfGitLabHealth >> baseline: spec [ self defineDependencies: spec. self definePackages: spec. self defineGroups: spec. + self defineJiraConnector: spec. spec for: #( #WithoutFamix ) do: [ spec @@ -22,14 +22,14 @@ BaselineOfGitLabHealth >> baseline: spec [ spec package: 'GitLabHealth-Model' with: [ spec requires: #( 'Moose' ) ] ] ] ] -{ #category : 'baselines' } +{ #category : #baselines } BaselineOfGitLabHealth >> customProjectAttributes [ self class environment at: #MooseEntity ifAbsent: [ ^ #(#WithoutFamix) ]. ^ #() ] -{ #category : 'baselines' } +{ #category : #baselines } BaselineOfGitLabHealth >> defineDependencies: spec [ spec @@ -40,11 +40,49 @@ BaselineOfGitLabHealth >> defineDependencies: spec [ with: [ spec repository: 'github://badetitou/MoreLogger:main/src' ] ] -{ #category : 'baselines' } +{ #category : #baselines } BaselineOfGitLabHealth >> defineGroups: spec [ + + spec + group: 'Jira' + with: + #( 'GitProject-JiraConnector' 'GitProject-JiraConnector-Generator' ). + spec + group: 'Core' + with: #( 'GitLabHealth-Model' 'GitLabHealth-Model-Extension' + 'GitLabHealth-Model-Extension-Tests' + 'GitLabHealth-Model-Generator' 'GitLabHealth-Model-Inspector' + 'GitLabHealth-Model-Visualization' + 'GitLabHealth-Model-Importer' 'GitLabHealth-Model-Importer-Tests' + 'GitHubHealth-Model-Importer-Tests' + 'GLPHExtended-Model' 'GLPHExtended-Model-Tests' + 'GLPHExtended-Model-Extension' 'GitLabHealth-Model-Analysis' + 'GitLabHealth-Visualization' 'GitLabProjectHealth-ExtendModel-Generator' + 'GitLabProjectHealth-Model-Importer' + 'GitLabProjectHealth-Model-Importer-Tests' ). + spec group: 'default' with: #( 'Core' ) +] + +{ #category : #baselines } +BaselineOfGitLabHealth >> defineJiraConnector: spec [ + + spec + package: 'GitProject-JiraConnector-Model'; + package: 'GitProject-JiraConnector' with: [ + spec requires: #( 'GitProject-JiraConnector-Model' + 'JiraPharoAPI' ) ]; + package: 'GitProject-JiraConnector-Generator'; + package: 'GitProject-JiraConnector-Tests' + with: [ spec requires: #( 'GitProject-JiraConnector' ) ]. + + "dependency" + spec + baseline: 'JiraPharoAPI' + with: [ + spec repository: 'github://Evref-BL/Jira-Pharo-API:main/src' ] ] -{ #category : 'baselines' } +{ #category : #baselines } BaselineOfGitLabHealth >> definePackages: spec [ spec diff --git a/src/BaselineOfGitLabHealth/package.st b/src/BaselineOfGitLabHealth/package.st index 0d5dae3..1aeec40 100644 --- a/src/BaselineOfGitLabHealth/package.st +++ b/src/BaselineOfGitLabHealth/package.st @@ -1 +1 @@ -Package { #name : 'BaselineOfGitLabHealth' } +Package { #name : #BaselineOfGitLabHealth } diff --git a/src/GitLabHealth-Model-Extension/GLHCommit.extension.st b/src/GitLabHealth-Model-Extension/GLHCommit.extension.st index 54b169c..d1a1ba3 100644 --- a/src/GitLabHealth-Model-Extension/GLHCommit.extension.st +++ b/src/GitLabHealth-Model-Extension/GLHCommit.extension.st @@ -39,8 +39,12 @@ GLHCommit >> inspectionGLHCommitFileImpacts [ ] { #category : #'*GitLabHealth-Model-Extension' } -GLHCommit >> name [ - ^ message ifNil: [ 'Commit#' , short_id ] +GLHCommit >> mooseNameOn: stream [ + + message ifNotNil: [ :mess | stream nextPutAll: mess ] ifNil: [ + stream + nextPutAll: 'Commit#'; + nextPutAll: (short_id ifNil: [ 'unknow id' ]) ] ] { #category : #'*GitLabHealth-Model-Extension' } diff --git a/src/GitProject-JiraConnector-Generator/GitProjectJiraConnectorGenerator.class.st b/src/GitProject-JiraConnector-Generator/GitProjectJiraConnectorGenerator.class.st new file mode 100644 index 0000000..d176dd8 --- /dev/null +++ b/src/GitProject-JiraConnector-Generator/GitProjectJiraConnectorGenerator.class.st @@ -0,0 +1,56 @@ +Class { + #name : #GitProjectJiraConnectorGenerator, + #superclass : #FamixMetamodelGenerator, + #instVars : [ + 'glhMergeRequest', + 'glhCommit', + 'jiraIssue' + ], + #category : #'GitProject-JiraConnector-Generator' +} + +{ #category : #accessing } +GitProjectJiraConnectorGenerator class >> packageName [ + + ^ #'GitProject-JiraConnector-Model' +] + +{ #category : #accessing } +GitProjectJiraConnectorGenerator class >> prefix [ + + ^ #GPJC +] + +{ #category : #accessing } +GitProjectJiraConnectorGenerator class >> submetamodels [ + + ^ { + GLHMetamodelGenerator. + GLPHMetamodelGenerator. + JPMetamodelGenerator } +] + +{ #category : #definition } +GitProjectJiraConnectorGenerator >> defineClasses [ + + super defineClasses. + glhMergeRequest := self + remoteEntity: #MergeRequest + withPrefix: #GLPHE. + glhCommit := self remoteEntity: #Commit withPrefix: #GLH. + jiraIssue := self remoteEntity: #Issue withPrefix: #JP +] + +{ #category : #definition } +GitProjectJiraConnectorGenerator >> defineRelations [ + + super defineRelations. + ((glhMergeRequest property: #jiraIssue) comment: + 'the jira issue associated to this merge request') + -<> ((jiraIssue property: #mergeRequest) comment: + 'A merge request in Git associated to this issue'). + ((glhCommit property: #jiraIssue) comment: + 'The jira issue associated with this commit') + *-<> ((jiraIssue property: #commits) comment: + 'The commits associated with this jira issue') +] diff --git a/src/GitProject-JiraConnector-Generator/package.st b/src/GitProject-JiraConnector-Generator/package.st new file mode 100644 index 0000000..cf4479e --- /dev/null +++ b/src/GitProject-JiraConnector-Generator/package.st @@ -0,0 +1 @@ +Package { #name : #'GitProject-JiraConnector-Generator' } diff --git a/src/GitProject-JiraConnector-Model/GLHCommit.extension.st b/src/GitProject-JiraConnector-Model/GLHCommit.extension.st new file mode 100644 index 0000000..b06d346 --- /dev/null +++ b/src/GitProject-JiraConnector-Model/GLHCommit.extension.st @@ -0,0 +1,20 @@ +Extension { #name : #GLHCommit } + +{ #category : #'*GitProject-JiraConnector-Model-accessing' } +GLHCommit >> jiraIssue [ + "Relation named: #jiraIssue type: #JPIssue opposite: #commits" + + + + + + + ^ self attributeAt: #jiraIssue ifAbsent: [ nil ] +] + +{ #category : #'*GitProject-JiraConnector-Model-accessing' } +GLHCommit >> jiraIssue: anObject [ + + + self attributeAt: #jiraIssue put: (FMMultivalueLink on: self update: #commits from: self jiraIssue to: anObject). +] diff --git a/src/GitProject-JiraConnector-Model/GLPHEMergeRequest.extension.st b/src/GitProject-JiraConnector-Model/GLPHEMergeRequest.extension.st new file mode 100644 index 0000000..f0c0e26 --- /dev/null +++ b/src/GitProject-JiraConnector-Model/GLPHEMergeRequest.extension.st @@ -0,0 +1,27 @@ +Extension { #name : #GLPHEMergeRequest } + +{ #category : #'*GitProject-JiraConnector-Model-accessing' } +GLPHEMergeRequest >> jiraIssue [ + "Relation named: #jiraIssue type: #JPIssue opposite: #mergeRequest" + + + + + + + ^ self attributeAt: #jiraIssue ifAbsent: [ nil ] +] + +{ #category : #'*GitProject-JiraConnector-Model-accessing' } +GLPHEMergeRequest >> jiraIssue: anObject [ + + + (self attributeAt: #jiraIssue ifAbsentPut: [nil]) == anObject ifTrue: [ ^ anObject ]. + anObject ifNil: [ | otherSide | + otherSide := self jiraIssue. + self attributeAt: #jiraIssue put: anObject. + otherSide mergeRequest: nil ] + ifNotNil: [ + self attributeAt: #jiraIssue put: anObject. + anObject mergeRequest: self ] +] diff --git a/src/GitProject-JiraConnector-Model/GPJCModel.class.st b/src/GitProject-JiraConnector-Model/GPJCModel.class.st new file mode 100644 index 0000000..888abcd --- /dev/null +++ b/src/GitProject-JiraConnector-Model/GPJCModel.class.st @@ -0,0 +1,20 @@ +Class { + #name : #GPJCModel, + #superclass : #MooseModel, + #traits : 'GLHTEntityCreator + GLPHETEntityCreator + JPTEntityCreator', + #classTraits : 'GLHTEntityCreator classTrait + GLPHETEntityCreator classTrait + JPTEntityCreator classTrait', + #category : #'GitProject-JiraConnector-Model-Model' +} + +{ #category : #accessing } +GPJCModel class >> allSubmetamodelsPackagesNames [ + + ^ #(#'Moose-Query' #'JiraPharoAPI-Model' #'GitLabHealth-Model' #'GLPHExtended-Model' #'Famix-Traits') +] + +{ #category : #meta } +GPJCModel class >> annotation [ + + + +] diff --git a/src/GitProject-JiraConnector-Model/JPIssue.extension.st b/src/GitProject-JiraConnector-Model/JPIssue.extension.st new file mode 100644 index 0000000..f519fae --- /dev/null +++ b/src/GitProject-JiraConnector-Model/JPIssue.extension.st @@ -0,0 +1,46 @@ +Extension { #name : #JPIssue } + +{ #category : #'*GitProject-JiraConnector-Model-accessing' } +JPIssue >> commits [ + "Relation named: #commits type: #GLHCommit opposite: #jiraIssue" + + + + + + + ^ self attributeAt: #commits ifAbsentPut: [ FMMultivalueLink on: self opposite: #jiraIssue: ] +] + +{ #category : #'*GitProject-JiraConnector-Model-accessing' } +JPIssue >> commits: anObject [ + + + self commits value: anObject +] + +{ #category : #'*GitProject-JiraConnector-Model-accessing' } +JPIssue >> mergeRequest [ + "Relation named: #mergeRequest type: #GLPHEMergeRequest opposite: #jiraIssue" + + + + + + + ^ self attributeAt: #mergeRequest ifAbsent: [ nil ] +] + +{ #category : #'*GitProject-JiraConnector-Model-accessing' } +JPIssue >> mergeRequest: anObject [ + + + (self attributeAt: #mergeRequest ifAbsentPut: [nil]) == anObject ifTrue: [ ^ anObject ]. + anObject ifNil: [ | otherSide | + otherSide := self mergeRequest. + self attributeAt: #mergeRequest put: anObject. + otherSide jiraIssue: nil ] + ifNotNil: [ + self attributeAt: #mergeRequest put: anObject. + anObject jiraIssue: self ] +] diff --git a/src/GitProject-JiraConnector-Model/package.st b/src/GitProject-JiraConnector-Model/package.st new file mode 100644 index 0000000..1ab2344 --- /dev/null +++ b/src/GitProject-JiraConnector-Model/package.st @@ -0,0 +1 @@ +Package { #name : #'GitProject-JiraConnector-Model' } diff --git a/src/GitProject-JiraConnector-Tests/GPJCConnectorTest.class.st b/src/GitProject-JiraConnector-Tests/GPJCConnectorTest.class.st new file mode 100644 index 0000000..8ad7bbc --- /dev/null +++ b/src/GitProject-JiraConnector-Tests/GPJCConnectorTest.class.st @@ -0,0 +1,109 @@ +" +A GPJCConnectorTest is a test class for testing the behavior of GPJCConnector +" +Class { + #name : #GPJCConnectorTest, + #superclass : #TestCase, + #instVars : [ + 'connector', + 'gitProject', + 'jiraModel' + ], + #category : #'GitProject-JiraConnector-Tests' +} + +{ #category : #running } +GPJCConnectorTest >> setUp [ + + super setUp. + connector := GPJCConnector new. + gitProject := GLPHEModel new. + jiraModel := JPModel new. + connector jiraModel: jiraModel. + connector gpModel: gitProject +] + +{ #category : #test } +GPJCConnectorTest >> testConnectCommit [ + + | issue commit | + issue := jiraModel newIssue. + issue key: 'HELLO-WORLD'. + + commit := gitProject newCommit. + commit message: 'I am a commit for [HELLO-WORLD]'. + + connector connect. + self assert: issue commits anyOne equals: commit. + self assert: commit jiraIssue equals: issue +] + +{ #category : #test } +GPJCConnectorTest >> testConnectCommitDoesNotExist [ + + | issue commit | + issue := jiraModel newIssue. + issue key: 'HELLO-WORLD-'. + + commit := gitProject newCommit. + commit message: 'I am a commit for [HELLO-WORLD]'. + + connector connect. + self assert: issue commits isEmpty. + self assert: commit jiraIssue equals: nil +] + +{ #category : #test } +GPJCConnectorTest >> testConnectMergeRequest [ + + | issue mergeRequest | + issue := jiraModel newIssue. + issue key: 'HELLO-WORLD'. + + mergeRequest := gitProject newMergeRequest. + mergeRequest title: 'I am a merge request for [HELLO-WORLD]'. + + connector connect. + self assert: issue mergeRequest equals: mergeRequest. + self assert: mergeRequest jiraIssue equals: issue +] + +{ #category : #test } +GPJCConnectorTest >> testConnectMergeRequestDoesNotExist [ + + | issue mergeRequest | + issue := jiraModel newIssue. + issue key: 'HELLO-WORLD-'. + + mergeRequest := gitProject newMergeRequest. + mergeRequest title: 'I am a merge request for [HELLO-WORLD]'. + + connector connect. + self assert: issue mergeRequest equals: nil. + self assert: mergeRequest jiraIssue equals: nil +] + +{ #category : #test } +GPJCConnectorTest >> testConnectSeveralCommit [ + + | issue commit commit2 commit3 | + issue := jiraModel newIssue. + issue key: 'HELLO-WORLD'. + + commit := gitProject newCommit. + commit message: 'I am a commit for [HELLO-WORLD]'. + commit2 := gitProject newCommit. + commit2 message: 'I am a HELLO-WORLD commit for'. + commit3 := gitProject newCommit. + commit3 message: '[HELLO-WORLD] I am a commit for'. + + connector connect. + self assert: issue commits size equals: 3. + self assert: (issue commits includesAll: { + commit. + commit2. + commit3 }). + self assert: commit jiraIssue equals: issue. + self assert: commit2 jiraIssue equals: issue. + self assert: commit3 jiraIssue equals: issue +] diff --git a/src/GitProject-JiraConnector-Tests/package.st b/src/GitProject-JiraConnector-Tests/package.st new file mode 100644 index 0000000..8ec3cd4 --- /dev/null +++ b/src/GitProject-JiraConnector-Tests/package.st @@ -0,0 +1 @@ +Package { #name : #'GitProject-JiraConnector-Tests' } diff --git a/src/GitProject-JiraConnector/GPJCConnector.class.st b/src/GitProject-JiraConnector/GPJCConnector.class.st new file mode 100644 index 0000000..6237db5 --- /dev/null +++ b/src/GitProject-JiraConnector/GPJCConnector.class.st @@ -0,0 +1,72 @@ +" +I connect a `JPModel` with a `GLHModel` using the relation define in the `GPJCModel` metamodel. + +You can use me with + +```st +GPJCConnector new + gpModel: aGpModel; ""or glh model"" + jiraModel: aJiraModel; + connect +``` + +I also ensure to not repeat relations (you can execute me multiple times safely) +" +Class { + #name : #GPJCConnector, + #superclass : #Object, + #instVars : [ + 'jiraModel', + 'gpModel' + ], + #category : #'GitProject-JiraConnector' +} + +{ #category : #accessing } +GPJCConnector >> connect [ + + (self gpModel allWithType: GLHCommit) do: [ :commit | + self connectCommit: commit ]. + (self gpModel allWithType: GLPHEMergeRequest) do: [ :mergeRequest | + self connectMergeRequest: mergeRequest ] +] + +{ #category : #accessing } +GPJCConnector >> connectCommit: commit [ + + (jiraModel allWithType: JPIssue) + detect: [ :issue | commit message includesSubstring: issue key ] + ifFound: [ :issue | commit jiraIssue: issue ] +] + +{ #category : #accessing } +GPJCConnector >> connectMergeRequest: mergeRequest [ + + (jiraModel allWithType: JPIssue) + detect: [ :issue | mergeRequest title includesSubstring: issue key ] + ifFound: [ :issue | mergeRequest jiraIssue: issue ] +] + +{ #category : #accessing } +GPJCConnector >> gpModel [ + + ^ gpModel +] + +{ #category : #accessing } +GPJCConnector >> gpModel: anObject [ + + gpModel := anObject +] + +{ #category : #accessing } +GPJCConnector >> jiraModel [ + + ^ jiraModel +] + +{ #category : #accessing } +GPJCConnector >> jiraModel: anObject [ + + jiraModel := anObject +] diff --git a/src/GitProject-JiraConnector/package.st b/src/GitProject-JiraConnector/package.st new file mode 100644 index 0000000..29a7c8e --- /dev/null +++ b/src/GitProject-JiraConnector/package.st @@ -0,0 +1 @@ +Package { #name : #'GitProject-JiraConnector' } From c4cccc4635da1e4e02c365902db3c5bc6d363616 Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Fri, 9 Aug 2024 13:59:07 +0200 Subject: [PATCH 013/154] add JiraConnector to smalltalkci --- .smalltalk.ston | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.smalltalk.ston b/.smalltalk.ston index ae3730a..45bd543 100644 --- a/.smalltalk.ston +++ b/.smalltalk.ston @@ -4,15 +4,16 @@ SmalltalkCISpec { SCIMetacelloLoadSpec { #baseline : 'GitLabHealth', #directory : 'src', + #load : [ 'default', 'Jira' ], #platforms : [ #pharo ], #onConflict : #useIncoming, #onUpgrade : #useIncoming } ], #testing: { - #packages : [ 'GitLab*', 'GLPH.*', 'GitHub.*' ], + #packages : [ 'GitLab*', 'GLPH.*', 'GitHub.*', 'GitProject.*' ], #coverage : { - #packages : [ 'GitLab.*', 'GLPH.*', 'GitHub.*' ], + #packages : [ 'GitLab.*', 'GLPH.*', 'GitHub.*', 'GitProject.*' ], #format : #lcov } } From a2eba262ed7c82226144ea61743e3641a113001e Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Fri, 9 Aug 2024 14:03:33 +0200 Subject: [PATCH 014/154] improve readme with explanation on how to use this sub project --- README.md | 49 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 5ff68dc..0c8c57c 100644 --- a/README.md +++ b/README.md @@ -103,16 +103,51 @@ Here is the metamodel used in this project ![GitProject meta-model png](https://raw.githubusercontent.com/moosetechnology/GitProjectHealth/v1/doc/gitproject.png) +## Connectors +This project comes with connectors to others metamodel to increase its powerfullness. + +### Jira Connector + +The Jira connector connect this project to the [Pharo Jira API project](https://github.com/Evref-BL/Jira-Pharo-API). +It basically looks for commit and merge request links to Jira Issue. + +To install the connector, please perform: + +```st +Metacello new + repository: 'github://moosetechnology/GitProjectHealth:main/src'; + baseline: 'GitLabHealth'; + onConflict: [ :ex | ex useIncoming ]; + onUpgrade: [ :ex | ex useIncoming ]; + onDowngrade: [ :ex | ex useLoaded ]; + load: #( 'default' 'Jira' ) +``` + +> loading default is optional if you already loaded it. + +Then, it is possible to connect two models using + +```st +GPJCConnector new + gpModel: aGpModel; "or glh model" + jiraModel: aJiraModel; + connect +``` + +### Famix Connector + +> The project exists and some code already exists, but it is not released yet. +> Raise an issue if you want us to investigate more on this ## Contributor This work has been first developed by the [research department of Berger-Levrault](https://www.research-bl.com/) +## Running metrics with docker -## Running metrics with docker +### Running locally -### running locally ```smalltalk |glphModel glphApi glhImporter beforeExp duringExp usersWithProjects gme| @@ -180,7 +215,6 @@ Smalltalk snapshot: true andQuit: true. ``` ### deploying with docker - ```bash git clone https://github.com/moosetechnology/GitProjectHealth.git @@ -190,13 +224,10 @@ git checkout GLPH-importer-new-changes sudo docker build -t code-churn-pharo . sudo docker run code-churn-pharo & ``` -locate and retrieve csv output files: + +Locate and retrieve csv output files: + ```bash sudo docker ps sudo docker exec -it find / -type f -name 'IA4Code*.csv' 2>/dev/null ``` - - - - - From 6e1a5a9f041fe030689a5e2f6000dc856ae6ed34 Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Fri, 9 Aug 2024 14:08:32 +0200 Subject: [PATCH 015/154] fix baseline to correctly load jira stuff before loading the jira connector --- .../BaselineOfGitLabHealth.class.st | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st b/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st index 340b0c8..3dbbb49 100644 --- a/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st +++ b/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st @@ -72,13 +72,15 @@ BaselineOfGitLabHealth >> defineGroups: spec [ BaselineOfGitLabHealth >> defineJiraConnector: spec [ spec - package: 'GitProject-JiraConnector-Model'; + package: 'GitProject-JiraConnector-Model' + with: [ spec requires: #( 'JiraPharoAPI' ) ]; package: 'GitProject-JiraConnector' with: [ spec requires: #( 'GitProject-JiraConnector-Model' 'JiraPharoAPI' ) ]; package: 'GitProject-JiraConnector-Generator'; - package: 'GitProject-JiraConnector-Tests' - with: [ spec requires: #( 'GitProject-JiraConnector' ) ]. + package: 'GitProject-JiraConnector-Tests' with: [ + spec requires: #( 'GitProject-JiraConnector' + 'JiraPharoAPI' ) ]. "dependency" spec From 9483dc5f2b2befb8818d6e723064296756b53122 Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Fri, 9 Aug 2024 15:06:04 +0200 Subject: [PATCH 016/154] Update BaselineOfGitLabHealth.class.st --- src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st b/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st index 3dbbb49..b6e83fa 100644 --- a/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st +++ b/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st @@ -51,7 +51,7 @@ BaselineOfGitLabHealth >> defineGroups: spec [ spec group: 'Jira' with: - #( 'GitProject-JiraConnector' 'GitProject-JiraConnector-Generator' ). + #( 'GitProject-JiraConnector' 'GitProject-JiraConnector-Generator' 'GitProject-JiraConnector-Tests' ). spec group: 'Core' with: #( 'GitLabHealth-Model' 'GitLabHealth-Model-Extension' From 8a997a870f56723b4b98210a89aa58adeb66097b Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Fri, 9 Aug 2024 16:17:40 +0200 Subject: [PATCH 017/154] progress on dictionnary inclusion for author and user matching --- .../GLHUserCatalogue.class.st | 84 +++++++++++++------ .../User2CommitAuthor.class.st | 6 ++ .../GLHApi.class.st | 7 +- .../GLHModelImporter.class.st | 80 +++++++++++++----- 4 files changed, 131 insertions(+), 46 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st b/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st index 26a3a76..ab5e2a8 100644 --- a/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st +++ b/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st @@ -8,23 +8,25 @@ Class { } { #category : #'as yet unclassified' } -GLHUserCatalogue class >> scrapeContributedProjectsForCommitAuthorsRelatedToUser: aGLHUser [ +GLHUserCatalogue class >> scrapeContributedProjectsForCommitAuthorsRelatedToUser: aGLHUser [ "get all " - - |maxProjects itsProjects| - maxProjects := 5. - GLHModelImporter current withCommitDiffs: false. - itsProjects := aGLHUser contributedProjects ifEmpty: [(GLHModelImporter current importContributedProjectsOfUser: aGLHUser)]. - - itsProjects collect: [ :project | - GLHModelImporter current importAndLoadLatestsCommitsOfProject: project. - ] from: 1 to: (itsProjects size > maxProjects ifTrue: [ maxProjects ] ifFalse: [ itsProjects size ] ) . - - ^ (aGLHUser commits collect: [ :commit | commit author_name ]) asSet. - - + | maxProjects itsProjects | + maxProjects := 10. + + GLHModelImporter current withCommitDiffs: false. + itsProjects := aGLHUser contributedProjects ifEmpty: [ + GLHModelImporter current + importContributedProjectsOfUser: aGLHUser ]. + + itsProjects + collect: [ :project | + GLHModelImporter current importAndLoadLatestsCommitsOfProject: + project ] + from: 1 + to: (itsProjects size min: maxProjects). + ^ (aGLHUser commits collect: [ :commit | commit author_name ]) asSet ] { #category : #adding } @@ -33,13 +35,48 @@ GLHUserCatalogue >> addUser: aGLHUser [ self add: (User2CommitAuthor new user: aGLHUser) ] +{ #category : #adding } +GLHUserCatalogue >> addUser: aGLHUser withName: name [ + + self at: aGLHUser ifPresent: [ :names | names add: name ] ifAbsentPut: [ + Set new + add: name; + yourself ] +] + +{ #category : #'as yet unclassified' } +GLHUserCatalogue >> collectUsernames [ + |username2User| + self ifEmpty: [ ^ { } ]. + + username2User := OrderedCollection new. + + self associationsDo: [ :assoc | + |user| + user := assoc key. + assoc value do: [ :username | + username2User add: (username -> user). + ]. + ]. + + ^ username2User. + +] + { #category : #completion } -GLHUserCatalogue >> completeAuthorNameOfUser: aGLHUser with: authorNames [ +GLHUserCatalogue >> completeAuthorNameOfUser: aGLHUser with: authorName [ | assoc | assoc := self associationAt: aGLHUser. - assoc value addAll: - authorNames + assoc value add: authorName +] + +{ #category : #completion } +GLHUserCatalogue >> completeAuthorNameOfUser: aGLHUser withAll: authorNames [ + + | assoc | + assoc := self associationAt: aGLHUser. + assoc value addAll: authorNames ] { #category : #initialization } @@ -50,14 +87,11 @@ GLHUserCatalogue >> initialize [ { #category : #'as yet unclassified' } GLHUserCatalogue >> scrapeAuthorNameForAllUsers [ - - self associations do: [ :assoc | - | aGLHUser| - aGLHUser := assoc key. - assoc value addAll: (GLHUserCatalogue - scrapeContributedProjectsForCommitAuthorsRelatedToUser: aGLHUser) - ] - + |currentUsers| + currentUsers := self keys. + currentUsers do: [ :key | + (self at: key) addAll: (GLHUserCatalogue + scrapeContributedProjectsForCommitAuthorsRelatedToUser: key) ] ] { #category : #'as yet unclassified' } diff --git a/src/GitLabHealth-Model-Analysis/User2CommitAuthor.class.st b/src/GitLabHealth-Model-Analysis/User2CommitAuthor.class.st index 83d63ab..42d61e9 100644 --- a/src/GitLabHealth-Model-Analysis/User2CommitAuthor.class.st +++ b/src/GitLabHealth-Model-Analysis/User2CommitAuthor.class.st @@ -23,6 +23,12 @@ User2CommitAuthor >> commitAuthors [ ^ value ] +{ #category : #accessing } +User2CommitAuthor >> commitAuthors: values [ + + self value: values. +] + { #category : #initialization } User2CommitAuthor >> initialize [ self value: Set new. diff --git a/src/GitLabHealth-Model-Importer/GLHApi.class.st b/src/GitLabHealth-Model-Importer/GLHApi.class.st index c25e9d3..ba2eb22 100644 --- a/src/GitLabHealth-Model-Importer/GLHApi.class.st +++ b/src/GitLabHealth-Model-Importer/GLHApi.class.st @@ -393,7 +393,7 @@ GLHApi >> initialize [ self client: (ZnClient new accept: ZnMimeType applicationJson; yourself). - currentAPI:= self + ] { #category : #'api - jobs' } @@ -416,6 +416,11 @@ GLHApi >> listGroupsWithTopLevelOnly: topLevelOnly page: aPageNumber [ ^ self client get ] +{ #category : #'as yet unclassified' } +GLHApi >> makeGlobal [ + currentAPI := self +] + { #category : #api } GLHApi >> pipelinesOfProject: aProjectID [ ^ self client get: self baseAPIUrl , '/projects/' , aProjectID printString, '/pipelines' diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index e8e6c50..d303904 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -9,7 +9,8 @@ Class { 'withCommitsSince', 'withInitialCommits', 'withInitialMergeRequest', - 'generalReader' + 'generalReader', + 'userCatalogue' ], #classVars : [ 'currentImporter' @@ -328,7 +329,7 @@ GLHModelImporter >> importAndLoadLatestsCommitsOfProject: aGLHProject [ GLHModelImporter >> importCommit: aCommitID ofProject: aGLHProject [ | result parsedResult | - (glhModel allWithType: GLHCommit) asOrderedCollection + (self glhModel allWithType: GLHCommit) asOrderedCollection detect: [ :commit | commit id = aCommitID ] ifFound: [ :commit | ^ commit ]. result := self glhApi @@ -547,7 +548,7 @@ GLHModelImporter >> importContributedProjectsOfUser: aGLHUser [ , page printString) recordInfo. results := GLHApi current contributedProjectsOfUserId: aGLHUser id - orderBy: 'created_at' + orderBy: 'last_activity_at' simple: true sort: 'desc' perPage: 100 @@ -570,9 +571,11 @@ GLHModelImporter >> importContributedProjectsOfUser: aGLHUser [ { #category : #'as yet unclassified' } GLHModelImporter >> importCreatorOfCommit: aCommit [ - + aCommit commitCreator ifNil: [ + aCommit commitCreator: + (self importUserByUsername: aCommit author_name) ] ] @@ -671,7 +674,7 @@ GLHModelImporter >> importJobsOf: aPipeline [ { #category : #'private - api' } GLHModelImporter >> importLastestCommitsOfProject: aGLHProject [ - "limited to the last 20 commits" + "limited to the last 50 commits" | results parsedResults | results := self glhApi @@ -686,7 +689,7 @@ GLHModelImporter >> importLastestCommitsOfProject: aGLHProject [ firstParent: nil order: nil trailers: nil - perPage: nil + perPage: 50 page: nil. parsedResults := self parseCommitsResult: results. self glhModel addAll: parsedResults unless: self blockOnIdEquality. @@ -696,8 +699,8 @@ GLHModelImporter >> importLastestCommitsOfProject: aGLHProject [ self withCommitDiffs ifTrue: [ parsedResults do: [ :commit | self importDiffOfCommit: commit ] ]. - - ^ parsedResults. + + ^ parsedResults ] { #category : #commit } @@ -780,7 +783,7 @@ GLHModelImporter >> importProjectsSince: since [ "copy import from commits" | newlyFoundProjects page foundProject amount | - ('import all Projects since: ', since printString) recordInfo. + ('import all Projects since: ' , since printString) recordInfo. "number of projects per page" amount := 100. @@ -791,10 +794,10 @@ GLHModelImporter >> importProjectsSince: since [ | results | page := page + 1. ('import projects page #' , page printString) recordInfo. - + results := self glhApi projects: amount since: since page: page. - newlyFoundProjects := glhModel + newlyFoundProjects := self glhModel addAll: (self parseArrayOfProject: results) unless: self blockOnIdEquality. foundProject addAll: newlyFoundProjects ]. @@ -847,34 +850,55 @@ GLHModelImporter >> importUser: aUserID [ { #category : #user } GLHModelImporter >> importUserByUsername: anUsername [ - | dicUsername | + | dicUsername resultUser| + dicUsername := ((self glhModel allWithType: GLHUser) collect: [ :user | user username -> user ]) asSet asDictionary. + + dicUsername addAll: (self userCatalogue collectUsernames) asDictionary . - ^ dicUsername at: anUsername ifPresent: [ :user | user ] ifAbsent: [ + resultUser := dicUsername at: anUsername + ifAbsent: [ + "thus we have to import this new user" | result userId searchResult | - ('Import user with username: ' , anUsername printString) - recordInfo. + ('Import user with username: ' , anUsername printString) recordInfo. result := self glhApi usersSearchByUsername: anUsername. searchResult := NeoJSONReader fromString: result. (searchResult class = Dictionary and: [ (searchResult at: #message) includesSubstring: '403 Forbidden' ]) ifTrue: [ - glhModel - add: (GLHUser new username: anUsername; name: anUsername; yourself ) + "if the result is an 403 error we fake a new user" + self glhModel + add: (GLHUser new + username: anUsername; + name: anUsername; + yourself) unless: [ :nu :ou | nu username = ou username ] ] ifFalse: [ searchResult ifEmpty: [ + "results can be empty thus we force a new user with the info we have " GLHUser new + name: anUsername; username: anUsername; yourself ] ifNotEmpty: [ userId := searchResult first at: #id. (self glhModel allWithType: GLHUser) detect: [ :user | user id = userId ] - ifNone: [ self importUser: userId ] ] ] ] + ifNone: [ self importUser: userId ] + ] + ] + ]. + + self userCatalogue addUser: resultUser withName: anUsername. + + ^ resultUser + + + + ] { #category : #initialization } @@ -894,8 +918,8 @@ GLHModelImporter >> initialize [ withInitialCommits := false. withInitialMergeRequest := false. withCommitsSince := (Date today - 1 week) asDateAndTime. - self initReader. - currentImporter := self. + userCatalogue := GLHUserCatalogue new. + self initReader ] { #category : #importer } @@ -906,6 +930,11 @@ GLHModelImporter >> loadAllProjectsFromRepositorySoftware [ projects := self glhApi projects. ] +{ #category : #'as yet unclassified' } +GLHModelImporter >> makeGlobal [ + currentImporter := self +] + { #category : #private } GLHModelImporter >> newParseCommitResult: result [ @@ -1195,6 +1224,17 @@ GLHModelImporter >> subGroupsOf: aGroupID [ ^ results ] +{ #category : #accessing } +GLHModelImporter >> userCatalogue [ + ^ userCatalogue +] + +{ #category : #accessing } +GLHModelImporter >> userCatalogue: aGLHUserCatalogue [ + + userCatalogue := aGLHUserCatalogue +] + { #category : #accessing } GLHModelImporter >> withCommitDiffs [ From 519f27907f943479582ddac36c7b5eb3570bc154 Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Fri, 9 Aug 2024 16:34:49 +0200 Subject: [PATCH 018/154] handeling fake user with no id case --- src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st b/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st index ab5e2a8..0147da5 100644 --- a/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st +++ b/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st @@ -12,6 +12,9 @@ GLHUserCatalogue class >> scrapeContributedProjectsForCommitAuthorsRelatedToUser "get all " | maxProjects itsProjects | + + aGLHUser id ifNil: [ ^ { } asSet ]. + maxProjects := 10. GLHModelImporter current withCommitDiffs: false. From 66fb1f8e2f4a5a5c2e3e45d6250a347a3e4336f7 Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Mon, 12 Aug 2024 12:05:05 +0200 Subject: [PATCH 019/154] add tests and export to json --- .../GLHUserCatalogueTest.class.st | 182 ++++++++++++++++++ .../GLHUserCatalogue.class.st | 88 ++++++--- .../User2CommitAuthor.class.st | 46 ----- 3 files changed, 246 insertions(+), 70 deletions(-) create mode 100644 src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueTest.class.st delete mode 100644 src/GitLabHealth-Model-Analysis/User2CommitAuthor.class.st diff --git a/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueTest.class.st new file mode 100644 index 0000000..93cb8b3 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueTest.class.st @@ -0,0 +1,182 @@ +" +A GLHUserCatalogueTest is a test class for testing the behavior of GLHUserCatalogue +" +Class { + #name : #GLHUserCatalogueTest, + #superclass : #TestCase, + #category : #'GitLabHealth-Model-Analysis-Tests' +} + +{ #category : #test } +GLHUserCatalogueTest >> testAddSameUser [ + + | user catalogue | + catalogue := GLHUserCatalogue new. + + user := GLHUser new + username: 'testUser'; + name: 'test user'; + yourself. + + catalogue addUser: user. + catalogue addUser: user. + + self assert: catalogue size equals: 1 +] + +{ #category : #test } +GLHUserCatalogueTest >> testAddUser [ + + | user catalogue | + catalogue := GLHUserCatalogue new. + + user := GLHUser new + username: 'testUser'; + name: 'test user'; + yourself. + + catalogue addUser: user. + + self assert: catalogue size equals: 1. +] + +{ #category : #test } +GLHUserCatalogueTest >> testAddUserWithName [ + + | user catalogue | + catalogue := GLHUserCatalogue new. + + user := GLHUser new + username: 'testUser'; + name: 'test user'; + yourself. + + catalogue addUser: user withName: 'toto'. + + self assert: (catalogue at: user) size equals: 3. + self assert: ((catalogue at: user) includes: 'toto') equals: true. + self assert: ((catalogue at: user) includes: 'testUser') equals: true. + self + assert: ((catalogue at: user) includes: 'test user') + equals: true +] + +{ #category : #test } +GLHUserCatalogueTest >> testAddUserWithNames [ + + + | user catalogue | + catalogue := GLHUserCatalogue new. + + user := GLHUser new + username: 'testUser'; + name: 'test user'; + yourself. + + catalogue addUser: user withNames: {'toto' . 'tata' . 'titi'}. + + self assert: (catalogue at: user) size equals: 5. + self assert: ((catalogue at: user) includes: 'toto') equals: true. + self assert: ((catalogue at: user) includes: 'tata') equals: true. + self + assert: ((catalogue at: user) includes: 'titi') + equals: true +] + +{ #category : #test } +GLHUserCatalogueTest >> testAddUsers [ + + | user1 user2 catalogue | + catalogue := GLHUserCatalogue new. + + user1 := GLHUser new + username: 'testUser1'; + name: 'test user1'; + yourself. + + user2 := GLHUser new + username: 'testUser2'; + name: 'test user2'; + yourself. + + catalogue addUser: user1. + catalogue addUser: user2. + + self assert: catalogue size equals: 2 +] + +{ #category : #test } +GLHUserCatalogueTest >> testCollectUsernames [ + + | user1 user2 catalogue res | + catalogue := GLHUserCatalogue new. + + user1 := GLHUser new + username: 'testUser1'; + name: 'test user1'; + yourself. + + user2 := GLHUser new + username: 'testUser2'; + name: 'test user2'; + yourself. + + catalogue addUser: user1. + catalogue addUser: user2. + + + res := catalogue collectUsernames. + + self assert: res size equals: 4. + self assert: (res at: 'testUser1') equals: user1. + self assert: (res at: 'testUser2') equals: user2. + self assert: (res at: 'test user1') equals: user1. + self assert: (res at: 'test user2') equals: user2. + + +] + +{ #category : #test } +GLHUserCatalogueTest >> testExportToJson [ + + | user json catalogue res | + user := GLHUser new + username: 'testUser'; + name: 'test user'; + yourself. + catalogue := GLHUserCatalogue new. + + catalogue addUser: user. + json := catalogue exportToJson. + + res := (STONJSON fromString: json) asDictionary. + self assert: res size equals: catalogue size. + self + assert: (res at: user name) size + equals: (catalogue at: user) size. + + self + assert: ((res at: user name) includes: ((catalogue at: user) anyOne)) + equals: true +] + +{ #category : #tests } +GLHUserCatalogueTest >> testLoadFromJson [ + + | user json catalogue res| + user := GLHUser new + username: 'testUser'; + name: 'test user'; + yourself. + catalogue := GLHUserCatalogue new. + + catalogue addUser: user. + json := catalogue exportToJson. + + res:= (GLHUserCatalogue loadFromJson: json). + self + assert: res size + equals: catalogue size. + + +] diff --git a/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st b/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st index 0147da5..df1f71f 100644 --- a/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st +++ b/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st @@ -7,6 +7,11 @@ Class { #category : #'GitLabHealth-Model-Analysis' } +{ #category : #import } +GLHUserCatalogue class >> loadFromJson: aString [ + ^ STON fromString: aString. +] + { #category : #'as yet unclassified' } GLHUserCatalogue class >> scrapeContributedProjectsForCommitAuthorsRelatedToUser: aGLHUser [ "get all " @@ -35,51 +40,78 @@ GLHUserCatalogue class >> scrapeContributedProjectsForCommitAuthorsRelatedToUser { #category : #adding } GLHUserCatalogue >> addUser: aGLHUser [ - self add: (User2CommitAuthor new user: aGLHUser) + self at: aGLHUser ifAbsentPut: [ Set new add: (aGLHUser username); add: (aGLHUser name) ; yourself ]. ] { #category : #adding } GLHUserCatalogue >> addUser: aGLHUser withName: name [ self at: aGLHUser ifPresent: [ :names | names add: name ] ifAbsentPut: [ - Set new - add: name; - yourself ] + Set new add: (aGLHUser username); add: (aGLHUser name) ; add: name; yourself ] +] + +{ #category : #adding } +GLHUserCatalogue >> addUser: aGLHUser withNames: aCollectionOfNames [ + + self + at: aGLHUser + ifPresent: [ :names | names addAll: aCollectionOfNames ] + ifAbsentPut: [ + Set new + add: aGLHUser username; + add: aGLHUser name; + addAll: aCollectionOfNames; + yourself ] ] { #category : #'as yet unclassified' } GLHUserCatalogue >> collectUsernames [ - |username2User| - self ifEmpty: [ ^ { } ]. - + + | username2User | + self ifEmpty: [ ^ { } ]. + username2User := OrderedCollection new. - + self associationsDo: [ :assoc | - |user| - user := assoc key. - assoc value do: [ :username | - username2User add: (username -> user). - ]. - ]. - - ^ username2User. + | user | + user := assoc key. + assoc value do: [ :username | username2User add: username -> user ] ]. + ^ username2User asDictionary. ] { #category : #completion } GLHUserCatalogue >> completeAuthorNameOfUser: aGLHUser with: authorName [ - | assoc | - assoc := self associationAt: aGLHUser. - assoc value add: authorName + self + deprecated: 'Use #addUser:withName: instead' + on: '12 August 2024' + in: + 'Pharo-11.0.0+build.726.sha.aece1b5473acf3830a0e082c1bc3a15d4ff3522b (64 Bit)'. + + self addUser: aGLHUser withName: authorName ] { #category : #completion } GLHUserCatalogue >> completeAuthorNameOfUser: aGLHUser withAll: authorNames [ - | assoc | - assoc := self associationAt: aGLHUser. - assoc value addAll: authorNames + self + deprecated: 'Use #addUser:withNames: instead' + on: '12 August 2024' + in: + 'Pharo-11.0.0+build.726.sha.aece1b5473acf3830a0e082c1bc3a15d4ff3522b (64 Bit)'. + + + self addUser: aGLHUser withNames: authorNames +] + +{ #category : #export } +GLHUserCatalogue >> exportToJson [ + + | tempDic | + tempDic := self associations collect: [ :assoc | (assoc key name) -> (assoc value asArray) ]. + + ^ STON toString: tempDic ] { #category : #initialization } @@ -88,6 +120,12 @@ GLHUserCatalogue >> initialize [ ] +{ #category : #import } +GLHUserCatalogue >> loadFromJson: aString [ + + ^ STON fromString: aString +] + { #category : #'as yet unclassified' } GLHUserCatalogue >> scrapeAuthorNameForAllUsers [ |currentUsers| @@ -98,10 +136,12 @@ GLHUserCatalogue >> scrapeAuthorNameForAllUsers [ ] { #category : #'as yet unclassified' } -GLHUserCatalogue >> scrapeAuthorNameForUser: aGLHUser [ +GLHUserCatalogue >> scrapeAuthorNameForUser: aGLHUser [ + | assoc | assoc := self associationAt: aGLHUser. - assoc value addAll: (GLHUserCatalogue scrapeContributedProjectsForCommitAuthorsRelatedToUser: aGLHUser). + assoc value addAll: (GLHUserCatalogue + scrapeContributedProjectsForCommitAuthorsRelatedToUser: aGLHUser) ] { #category : #completion } diff --git a/src/GitLabHealth-Model-Analysis/User2CommitAuthor.class.st b/src/GitLabHealth-Model-Analysis/User2CommitAuthor.class.st deleted file mode 100644 index 42d61e9..0000000 --- a/src/GitLabHealth-Model-Analysis/User2CommitAuthor.class.st +++ /dev/null @@ -1,46 +0,0 @@ -Class { - #name : #User2CommitAuthor, - #superclass : #Association, - #instVars : [ - 'user', - 'commitAuthors' - ], - #category : #'GitLabHealth-Model-Analysis' -} - -{ #category : #adding } -User2CommitAuthor >> addAllCommitAuthors: commitAuthorsList [ - ^ self value addAll: commitAuthorsList -] - -{ #category : #adding } -User2CommitAuthor >> addCommitAuhtor: aCommitAuthor [ - ^ self value add: aCommitAuthor. -] - -{ #category : #accessing } -User2CommitAuthor >> commitAuthors [ - ^ value -] - -{ #category : #accessing } -User2CommitAuthor >> commitAuthors: values [ - - self value: values. -] - -{ #category : #initialization } -User2CommitAuthor >> initialize [ - self value: Set new. - -] - -{ #category : #accessing } -User2CommitAuthor >> user [ - ^ key -] - -{ #category : #accessing } -User2CommitAuthor >> user: aGLHUser [ - self key: aGLHUser -] From 66ef8080694d6425f69c328f1530a3cf9a4aa64d Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Mon, 12 Aug 2024 18:21:14 +0200 Subject: [PATCH 020/154] add import and export; add test; includes catalogue in Importer --- .../GLHUserCatalogueTest.class.st | 50 ++++--- .../GLHUserCatalogue.class.st | 135 +++++++++++++++--- .../GLHModelImporter.class.st | 97 ++++++------- 3 files changed, 192 insertions(+), 90 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueTest.class.st index 93cb8b3..f828a73 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueTest.class.st @@ -136,8 +136,8 @@ GLHUserCatalogueTest >> testCollectUsernames [ ] -{ #category : #test } -GLHUserCatalogueTest >> testExportToJson [ +{ #category : #tests } +GLHUserCatalogueTest >> testExportAndLoad [ | user json catalogue res | user := GLHUser new @@ -149,34 +149,44 @@ GLHUserCatalogueTest >> testExportToJson [ catalogue addUser: user. json := catalogue exportToJson. - res := (STONJSON fromString: json) asDictionary. - self assert: res size equals: catalogue size. - self - assert: (res at: user name) size - equals: (catalogue at: user) size. - - self - assert: ((res at: user name) includes: ((catalogue at: user) anyOne)) - equals: true + res := GLHUserCatalogue loadFromJson: json. + self assert: res size equals: catalogue size ] -{ #category : #tests } -GLHUserCatalogueTest >> testLoadFromJson [ +{ #category : #test } +GLHUserCatalogueTest >> testExportToJson [ - | user json catalogue res| + | user user2 json catalogue res | user := GLHUser new username: 'testUser'; name: 'test user'; + id: 1; + yourself. + user2 := GLHUser new + username: 'testUser2'; + name: 'test user2'; + id: 2; yourself. catalogue := GLHUserCatalogue new. - catalogue addUser: user. + catalogue addUser: user; addUser: user2. json := catalogue exportToJson. - res:= (GLHUserCatalogue loadFromJson: json). - self - assert: res size - equals: catalogue size. - + res := (STONJSON fromString: json). + self assert: res size equals: catalogue size. + self assert: ((res at: 'test user2') at: #foundNames) size equals: 2 . + self assert: ((res at: 'test user') at: #foundNames) size equals: 2 . ] + +{ #category : #tests } +GLHUserCatalogueTest >> testLoadFromJson [ + + | json res | + json := '{"Benoit VERHAEGHE":{"id":1,"username":"Benoit.VERHAEGHE","foundNames":["Benoit VERHAEGHE","Benoit.VERHAEGHE","Benoît VERHAEGHE","Benoît Verhaeghe"],"name":"Benoit VERHAEGHE"},"HLAD Nicolas":{"id":2,"username":"Nicolas.HLAD","foundNames":["Nicolas Hlad","Nicolas.HLAD","HLAD Nicolas"],"name":"HLAD Nicolas"}}'. + + res := GLHUserCatalogue loadFromJson: json. + self assert: res size equals: 2. + self assert: (res searchUserWithName: 'Nicolas') isNotEmpty equals: true. + self assert: (res searchUserWithName: 'VERHAEGHE') isNotEmpty equals: true. +] diff --git a/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st b/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st index df1f71f..06d12f0 100644 --- a/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st +++ b/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st @@ -2,14 +2,28 @@ Class { #name : #GLHUserCatalogue, #superclass : #Dictionary, #instVars : [ - 'users' + 'users', + 'anImporter' ], #category : #'GitLabHealth-Model-Analysis' } { #category : #import } -GLHUserCatalogue class >> loadFromJson: aString [ - ^ STON fromString: aString. +GLHUserCatalogue class >> loadFromJson: aString [ + + | catalogue dic | + catalogue := GLHUserCatalogue new. + dic := (STONJSON fromString: aString) asDictionary. + dic associationsDo: [ :assoc | + | itsName itsUsername itsCommitNames itsId| + itsName := assoc key. + itsCommitNames := assoc value at: #foundNames. + itsUsername := assoc value at: #username. + itsId := assoc value at: #id. + + catalogue addUser: (GLHUser new id: itsId; username: itsUsername; name: itsName; yourself ) withNames: itsCommitNames ]. + + ^ catalogue . ] { #category : #'as yet unclassified' } @@ -17,9 +31,15 @@ GLHUserCatalogue class >> scrapeContributedProjectsForCommitAuthorsRelatedToUser "get all " | maxProjects itsProjects | - + self + deprecated: + 'Use #scrapeWithImporter:ContributedProjectsForCommitAuthorsRelatedToUser: instead' + on: '12 August 2024' + in: + 'Pharo-11.0.0+build.726.sha.aece1b5473acf3830a0e082c1bc3a15d4ff3522b (64 Bit)'. + aGLHUser id ifNil: [ ^ { } asSet ]. - + maxProjects := 10. GLHModelImporter current withCommitDiffs: false. @@ -37,6 +57,30 @@ GLHUserCatalogue class >> scrapeContributedProjectsForCommitAuthorsRelatedToUser ^ (aGLHUser commits collect: [ :commit | commit author_name ]) asSet ] +{ #category : #'as yet unclassified' } +GLHUserCatalogue class >> scrapeWithImporter: anImporter contributedProjectsForCommitAuthorsRelatedToUser: aGLHUser [ + "get all " + + | maxProjects itsProjects | + aGLHUser id ifNil: [ ^ { } asSet ]. + + maxProjects := 10. + + anImporter withCommitDiffs: false. + itsProjects := aGLHUser contributedProjects ifEmpty: [ + anImporter + importContributedProjectsOfUser: aGLHUser ]. + + itsProjects + collect: [ :project | + anImporter importAndLoadLatestsCommitsOfProject: + project ] + from: 1 + to: (itsProjects size min: maxProjects). + + ^ (aGLHUser commits collect: [ :commit | commit author_name ]) asSet +] + { #category : #adding } GLHUserCatalogue >> addUser: aGLHUser [ @@ -46,8 +90,15 @@ GLHUserCatalogue >> addUser: aGLHUser [ { #category : #adding } GLHUserCatalogue >> addUser: aGLHUser withName: name [ - self at: aGLHUser ifPresent: [ :names | names add: name ] ifAbsentPut: [ - Set new add: (aGLHUser username); add: (aGLHUser name) ; add: name; yourself ] + self + at: aGLHUser + ifPresent: [ :names | names add: name ] + ifAbsentPut: [ + Set new + add: aGLHUser username; + add: aGLHUser name; + add: name; + yourself ] ] { #category : #adding } @@ -64,20 +115,26 @@ GLHUserCatalogue >> addUser: aGLHUser withNames: aCollectionOfNames [ yourself ] ] +{ #category : #accessing } +GLHUserCatalogue >> anImporter: aGLHModelImporter [ + anImporter := aGLHModelImporter + +] + { #category : #'as yet unclassified' } GLHUserCatalogue >> collectUsernames [ | username2User | self ifEmpty: [ ^ { } ]. - username2User := OrderedCollection new. + username2User := Dictionary new. self associationsDo: [ :assoc | | user | user := assoc key. - assoc value do: [ :username | username2User add: username -> user ] ]. + assoc value do: [ :username | username2User at: username put: user ] ]. - ^ username2User asDictionary. + ^ username2User ] { #category : #completion } @@ -109,30 +166,50 @@ GLHUserCatalogue >> completeAuthorNameOfUser: aGLHUser withAll: authorNames [ GLHUserCatalogue >> exportToJson [ | tempDic | - tempDic := self associations collect: [ :assoc | (assoc key name) -> (assoc value asArray) ]. - - ^ STON toString: tempDic + " tempDic := self associations collect: [ :assoc | + Dictionary new at: (assoc key name) put: ({ + (#names -> assoc value asArray). + (#id -> assoc key id) } asDictionary); yourself ]." + tempDic := Dictionary new. + self associationsDo: [ :assoc | + tempDic + at: assoc key name put: { + (#name -> assoc key name). + (#username -> assoc key username). + (#foundNames -> assoc value asArray). + (#id -> assoc key id) } asDictionary; + yourself ]. + + ^ STONJSON toString: tempDic ] { #category : #initialization } GLHUserCatalogue >> initialize [ - + anImporter := GLHModelImporter current. ] -{ #category : #import } -GLHUserCatalogue >> loadFromJson: aString [ +{ #category : #'as yet unclassified' } +GLHUserCatalogue >> loadAllUsers [ + "use it after a catalogue import from JSON" - ^ STON fromString: aString + self associationsDo: [ :assoc | + | user | + user := assoc key. + user := anImporter ifNotNil: [ + user id ifNotNil: [ anImporter importUser: user id ] ifNil: [ anImporter importUserByUsername: user username ] + ] ifNil: user. + assoc key: user ] ] { #category : #'as yet unclassified' } GLHUserCatalogue >> scrapeAuthorNameForAllUsers [ - |currentUsers| + + | currentUsers | currentUsers := self keys. currentUsers do: [ :key | (self at: key) addAll: (GLHUserCatalogue - scrapeContributedProjectsForCommitAuthorsRelatedToUser: key) ] + scrapeWithImporter: anImporter contributedProjectsForCommitAuthorsRelatedToUser: key) ] ] { #category : #'as yet unclassified' } @@ -141,7 +218,8 @@ GLHUserCatalogue >> scrapeAuthorNameForUser: aGLHUser [ | assoc | assoc := self associationAt: aGLHUser. assoc value addAll: (GLHUserCatalogue - scrapeContributedProjectsForCommitAuthorsRelatedToUser: aGLHUser) + scrapeWithImporter: anImporter + contributedProjectsForCommitAuthorsRelatedToUser: aGLHUser) ] { #category : #completion } @@ -151,3 +229,20 @@ GLHUserCatalogue >> searchModelForAuthorNamesOfUser: aGLHUser [ assoc value addAll: (aGLHUser commits collect: [:c | c author_name]). ] + +{ #category : #search } +GLHUserCatalogue >> searchName: aName [ + + ^ self select: [ :collectionOfName | + (' ' join: collectionOfName) asLowercase includesSubstring: aName asLowercase ] +] + +{ #category : #search } +GLHUserCatalogue >> searchUserWithName: aName [ + ^ (self searchName: aName) keys. +] + +{ #category : #accessing } +GLHUserCatalogue >> users [ + ^ self keys +] diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index d303904..3499e69 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -692,10 +692,11 @@ GLHModelImporter >> importLastestCommitsOfProject: aGLHProject [ perPage: 50 page: nil. parsedResults := self parseCommitsResult: results. - self glhModel addAll: parsedResults unless: self blockOnIdEquality. + parsedResults := self glhModel addAll: parsedResults unless: self blockOnIdEquality. - parsedResults do: [ :commit | - commit repository: aGLHProject repository ]. + aGLHProject repository commits addAll: parsedResults unless: self blockOnIdEquality. + "parsedResults do: [ :commit | + commit repository: aGLHProject repository ]." self withCommitDiffs ifTrue: [ parsedResults do: [ :commit | self importDiffOfCommit: commit ] ]. @@ -850,55 +851,51 @@ GLHModelImporter >> importUser: aUserID [ { #category : #user } GLHModelImporter >> importUserByUsername: anUsername [ - | dicUsername resultUser| - + | dicUsername resultUser | dicUsername := ((self glhModel allWithType: GLHUser) collect: [ :user | user username -> user ]) asSet asDictionary. - - dicUsername addAll: (self userCatalogue collectUsernames) asDictionary . - - resultUser := dicUsername at: anUsername - ifAbsent: [ - "thus we have to import this new user" - | result userId searchResult | - ('Import user with username: ' , anUsername printString) recordInfo. - result := self glhApi usersSearchByUsername: anUsername. - searchResult := NeoJSONReader fromString: result. - - (searchResult class = Dictionary and: [ - (searchResult at: #message) includesSubstring: '403 Forbidden' ]) - ifTrue: [ - "if the result is an 403 error we fake a new user" - self glhModel - add: (GLHUser new - username: anUsername; - name: anUsername; - yourself) - unless: [ :nu :ou | nu username = ou username ] ] - ifFalse: [ - searchResult - ifEmpty: [ - "results can be empty thus we force a new user with the info we have " - GLHUser new - name: anUsername; - username: anUsername; - yourself ] - ifNotEmpty: [ - userId := searchResult first at: #id. - (self glhModel allWithType: GLHUser) - detect: [ :user | user id = userId ] - ifNone: [ self importUser: userId ] - ] - ] - ]. - - self userCatalogue addUser: resultUser withName: anUsername. - - ^ resultUser - - - + dicUsername addAll: self userCatalogue collectUsernames. + + + resultUser := dicUsername + at: anUsername + ifAbsent: [ "thus we have to import this new user" + | result userId searchResult | + ('Import user with username: ' + , anUsername printString) recordInfo. + result := self glhApi usersSearchByUsername: + anUsername. + searchResult := NeoJSONReader fromString: result. + + (searchResult class = Dictionary and: [ + (searchResult at: #message) includesSubstring: + '403 Forbidden' ]) + ifTrue: [ "if the result is an 403 error we fake a new user" + self glhModel + add: (GLHUser new + username: anUsername; + name: anUsername; + yourself) + unless: [ :nu :ou | nu username = ou username ] ] + ifFalse: [ + searchResult + ifEmpty: [ "results can be empty thus we force a new user with the info we have " + self glhModel + add: (GLHUser new + username: anUsername; + name: anUsername; + yourself) + unless: [ :nu :ou | nu username = ou username ] ] + ifNotEmpty: [ "because we may already have the researched user, we look by ID in the model" + userId := searchResult first at: #id. + (self glhModel allWithType: GLHUser) + detect: [ :user | user id = userId ] + ifNone: [ self importUser: userId ] ] ] ]. + + self userCatalogue addUser: resultUser withName: anUsername. + + ^ resultUser ] { #category : #initialization } @@ -918,7 +915,7 @@ GLHModelImporter >> initialize [ withInitialCommits := false. withInitialMergeRequest := false. withCommitsSince := (Date today - 1 week) asDateAndTime. - userCatalogue := GLHUserCatalogue new. + userCatalogue := GLHUserCatalogue new anImporter: self; yourself. self initReader ] From e90fdb5a832ec23234874fd6141b119ebdfd6844 Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Mon, 12 Aug 2024 18:39:43 +0200 Subject: [PATCH 021/154] remove glhApi current in some implementation --- .../GLHModelImporter.class.st | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index 3499e69..8989229 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -271,7 +271,7 @@ GLHModelImporter >> glhModel: anObject [ { #category : #'as yet unclassified' } GLHModelImporter >> importActiveHumanUsers [ - + | newlyFoundUser page foundUsers | page := 0. foundUsers := OrderedCollection new. @@ -280,19 +280,23 @@ GLHModelImporter >> importActiveHumanUsers [ | results | page := page + 1. ('import users page ' , page printString) recordInfo. - results := GLHApi current - usersHuman: true active: true withoutProjectBots: true perPage: 100 page: page. + results := self glhApi + usersHuman: true + active: true + withoutProjectBots: true + perPage: 100 + page: page. newlyFoundUser := self parseUsersResult: results. "newlyFoundCommit do: [ :c | c repository: aProject repository ]." - - foundUsers addAll: (self glhModel addAll: newlyFoundUser + + foundUsers addAll: + (self glhModel + addAll: newlyFoundUser unless: self blockOnIdEquality) ]. ^ foundUsers - - ] { #category : #api } @@ -396,7 +400,7 @@ GLHModelImporter >> importCommitsOProject: aProject since: fromDate until: toDat | results | page := page + 1. ('import commit page ' , page printString) recordInfo. - results := GLHApi current + results := self glhApi commitsOfProject: aProject id forRefName: nil since: @@ -546,7 +550,7 @@ GLHModelImporter >> importContributedProjectsOfUser: aGLHUser [ page := page + 1. ('import contributed project of user ' , aGLHUser name , ' page ' , page printString) recordInfo. - results := GLHApi current + results := self glhApi contributedProjectsOfUserId: aGLHUser id orderBy: 'last_activity_at' simple: true @@ -814,7 +818,7 @@ GLHModelImporter >> importRepository: aGLHRepository [ ('import the repository of project ' , aGLHRepository project name) recordInfo. - resultBranches := GLHApi current branchesOfRepository: + resultBranches := self glhApi branchesOfRepository: aGLHRepository project id. branches := self parseBranchesResult: resultBranches. @@ -843,7 +847,7 @@ GLHModelImporter >> importUser: aUserID [ detect: [ :user | user id = aUserID ] ifFound: [ :user | ^ user ]. ('Import user: ' , aUserID printString) recordInfo. - result := GLHApi current user: aUserID. + result := self glhApi user: aUserID. userResult := self parseUserResult: result. ^ self glhModel add: userResult unless: self blockOnIdEquality ] From 19ba9f66a7e65dbb417db85b8b23f42ee3e87527 Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Tue, 13 Aug 2024 10:58:11 +0200 Subject: [PATCH 022/154] patch import --- src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 2eade81..5631e39 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -443,6 +443,6 @@ GitMetricExporter >> maxCommitWindow: anInteger [ GitMetricExporter >> onlyImportProjectsOfGroup: groupId [ | group | - group := GLHModelImporter current importGroup: groupId. - projectCache := (group toScope: GLHProject) + group := glhImporter importGroup: groupId. + projectCache := group toScope: GLHProject ] From 844a9b6cefa96ef050e20884cf9d7100d532621d Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Tue, 13 Aug 2024 17:08:44 +0200 Subject: [PATCH 023/154] new method to retrieve the projects a User work on for the metricexporter --- .../GitMetricExporter.class.st | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 301fdfd..8508487 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -341,3 +341,42 @@ GitMetricExporter >> onlyImportProjectsOfGroup: groupId [ group := glhImporter importGroup: groupId. projectCache := group toScope: GLHProject ] + +{ #category : #adding } +GitMetricExporter >> setupAnalysisForUsersWithNames: userNames [ + "import all the project since a certain time" + + | users | + + users := userNames collect: [ :username | + glhImporter importUserByUsername: username ]. + + glhImporter userCatalogue scrapeAuthorNameForAllUsers. + + entities addAll: (users collect: [:user | + | itsProjects metrics i size | + itsProjects := glhImporter importContributedProjectsOfUser: user. + + metrics := GitMetric4User new. + metrics + glhImporter: glhImporter; + user: user. + + i := 0. + size := itsProjects size. + metrics itsProjects: (itsProjects collect: [ :p | + (' ' join: { + 'complete import of project:'. + p name printString. + '['. + (i := i + 1) printString. + '/'. + size. + ']' }) recordInfo. + + p id -> (glhImporter completeImportProject: p) ]) asDictionary. + ] + ). + + ^ self +] From c2427b6bef039f59dcd7020221e79967a0725213 Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Wed, 14 Aug 2024 19:00:28 +0200 Subject: [PATCH 024/154] new catalogue version (in progress) --- .../GLHUserCatalogueTest.class.st | 146 ++++++--- .../GLHUserCatalogueV2Test.class.st | 259 ++++++++++++++++ .../GLHUserCatalogue.class.st | 47 ++- .../GLHUserCatalogueItem.class.st | 15 + .../GLHUserCatalogueV2.class.st | 289 ++++++++++++++++++ .../GitMetricExporter.class.st | 21 +- .../GLHModelImporter.class.st | 4 +- 7 files changed, 716 insertions(+), 65 deletions(-) create mode 100644 src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueV2Test.class.st create mode 100644 src/GitLabHealth-Model-Analysis/GLHUserCatalogueItem.class.st create mode 100644 src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st diff --git a/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueTest.class.st index f828a73..ac24887 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueTest.class.st @@ -4,14 +4,22 @@ A GLHUserCatalogueTest is a test class for testing the behavior of GLHUserCatalo Class { #name : #GLHUserCatalogueTest, #superclass : #TestCase, + #instVars : [ + 'catalogue' + ], #category : #'GitLabHealth-Model-Analysis-Tests' } +{ #category : #running } +GLHUserCatalogueTest >> setUp [ + + catalogue := GLHUserCatalogue new. +] + { #category : #test } GLHUserCatalogueTest >> testAddSameUser [ - | user catalogue | - catalogue := GLHUserCatalogue new. + | user | user := GLHUser new username: 'testUser'; @@ -27,24 +35,24 @@ GLHUserCatalogueTest >> testAddSameUser [ { #category : #test } GLHUserCatalogueTest >> testAddUser [ - | user catalogue | - catalogue := GLHUserCatalogue new. + | user | + user := GLHUser new username: 'testUser'; name: 'test user'; yourself. - catalogue addUser: user. - - self assert: catalogue size equals: 1. + catalogue addUser: user. + + self assert: catalogue size equals: 1 ] { #category : #test } GLHUserCatalogueTest >> testAddUserWithName [ - | user catalogue | - catalogue := GLHUserCatalogue new. + | user | + user := GLHUser new username: 'testUser'; @@ -64,30 +72,27 @@ GLHUserCatalogueTest >> testAddUserWithName [ { #category : #test } GLHUserCatalogueTest >> testAddUserWithNames [ - - | user catalogue | - catalogue := GLHUserCatalogue new. + | user | + user := GLHUser new username: 'testUser'; name: 'test user'; yourself. - catalogue addUser: user withNames: {'toto' . 'tata' . 'titi'}. - + catalogue addUser: user withNames: { 'toto'. 'tata'. 'titi' }. + self assert: (catalogue at: user) size equals: 5. self assert: ((catalogue at: user) includes: 'toto') equals: true. self assert: ((catalogue at: user) includes: 'tata') equals: true. - self - assert: ((catalogue at: user) includes: 'titi') - equals: true + self assert: ((catalogue at: user) includes: 'titi') equals: true ] { #category : #test } GLHUserCatalogueTest >> testAddUsers [ - | user1 user2 catalogue | - catalogue := GLHUserCatalogue new. + | user1 user2 | + user1 := GLHUser new username: 'testUser1'; @@ -108,8 +113,8 @@ GLHUserCatalogueTest >> testAddUsers [ { #category : #test } GLHUserCatalogueTest >> testCollectUsernames [ - | user1 user2 catalogue res | - catalogue := GLHUserCatalogue new. + | user1 user2 res | + user1 := GLHUser new username: 'testUser1'; @@ -126,25 +131,23 @@ GLHUserCatalogueTest >> testCollectUsernames [ res := catalogue collectUsernames. - - self assert: res size equals: 4. - self assert: (res at: 'testUser1') equals: user1. - self assert: (res at: 'testUser2') equals: user2. - self assert: (res at: 'test user1') equals: user1. - self assert: (res at: 'test user2') equals: user2. - + self assert: res size equals: 4. + self assert: (res at: 'testUser1') equals: user1. + self assert: (res at: 'testUser2') equals: user2. + self assert: (res at: 'test user1') equals: user1. + self assert: (res at: 'test user2') equals: user2 ] { #category : #tests } GLHUserCatalogueTest >> testExportAndLoad [ - | user json catalogue res | + | user json res | user := GLHUser new username: 'testUser'; name: 'test user'; yourself. - catalogue := GLHUserCatalogue new. + catalogue addUser: user. json := catalogue exportToJson. @@ -156,27 +159,28 @@ GLHUserCatalogueTest >> testExportAndLoad [ { #category : #test } GLHUserCatalogueTest >> testExportToJson [ - | user user2 json catalogue res | + | user user2 json res | user := GLHUser new username: 'testUser'; name: 'test user'; - id: 1; - yourself. - user2 := GLHUser new - username: 'testUser2'; - name: 'test user2'; - id: 2; + id: 1; yourself. - catalogue := GLHUserCatalogue new. + user2 := GLHUser new + username: 'testUser2'; + name: 'test user2'; + id: 2; + yourself. - catalogue addUser: user; addUser: user2. + + catalogue + addUser: user; + addUser: user2. json := catalogue exportToJson. - res := (STONJSON fromString: json). + res := STONJSON fromString: json. self assert: res size equals: catalogue size. - self assert: ((res at: 'test user2') at: #foundNames) size equals: 2 . - self assert: ((res at: 'test user') at: #foundNames) size equals: 2 . - + self assert: ((res at: 'test user2') at: #foundNames) size equals: 2. + self assert: ((res at: 'test user') at: #foundNames) size equals: 2 ] { #category : #tests } @@ -190,3 +194,59 @@ GLHUserCatalogueTest >> testLoadFromJson [ self assert: (res searchUserWithName: 'Nicolas') isNotEmpty equals: true. self assert: (res searchUserWithName: 'VERHAEGHE') isNotEmpty equals: true. ] + +{ #category : #test } +GLHUserCatalogueTest >> testNamesAt [ + + | user | + + + user := GLHUser new + username: 'testUser'; + name: 'test user'; + yourself. + + catalogue addUser: user withName: 'toto'. + + + self assert: (catalogue namesAt: user) size equals: 3. + self + assert: ((catalogue namesAt: user) includes: 'toto') + equals: true. + self + assert: ((catalogue namesAt: user) includes: 'testUser') + equals: true. + self + assert: ((catalogue namesAt: user) includes: 'test user') + equals: true +] + +{ #category : #test } +GLHUserCatalogueTest >> testNamesAtChangingUser [ + + | user | + + + user := GLHUser new + username: 'testUser'; + yourself. + + user hash. " 114462615" + + catalogue addUser: user withName: 'toto'. + + user name: 'test User'. + + user hash. + + self assert: (catalogue namesAt: user) size equals: 3. + self + assert: ((catalogue namesAt: user) includes: 'toto') + equals: true. + self + assert: ((catalogue namesAt: user) includes: 'testUser') + equals: true. + self + assert: ((catalogue namesAt: user) includes: 'test user') + equals: true +] diff --git a/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueV2Test.class.st b/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueV2Test.class.st new file mode 100644 index 0000000..b1e9b90 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueV2Test.class.st @@ -0,0 +1,259 @@ +Class { + #name : #GLHUserCatalogueV2Test, + #superclass : #TestCase, + #instVars : [ + 'catalogue' + ], + #category : #'GitLabHealth-Model-Analysis-Tests' +} + +{ #category : #running } +GLHUserCatalogueV2Test >> setUp [ + + catalogue := GLHUserCatalogueV2 new +] + +{ #category : #test } +GLHUserCatalogueV2Test >> testAddSameUser [ + + | user | + + user := GLHUser new + username: 'testUser'; + name: 'test user'; + yourself. + + catalogue addUser: user. + catalogue addUser: user. + + self assert: catalogue size equals: 1 +] + +{ #category : #test } +GLHUserCatalogueV2Test >> testAddUser [ + + | user | + + + user := GLHUser new + username: 'testUser'; + name: 'test user'; + yourself. + + catalogue addUser: user. + + self assert: catalogue size equals: 1 +] + +{ #category : #test } +GLHUserCatalogueV2Test >> testAddUserWithName [ + + | user | + + + user := GLHUser new + username: 'testUser'; + name: 'test user'; + yourself. + + catalogue addUser: user withName: 'toto'. + + self assert: (catalogue namesAt: user) size equals: 3. + self assert: ((catalogue namesAt: user) includes: 'toto') equals: true. + self assert: ((catalogue namesAt: user) includes: 'testUser') equals: true. + self + assert: ((catalogue namesAt: user) includes: 'test user') + equals: true +] + +{ #category : #test } +GLHUserCatalogueV2Test >> testAddUserWithNames [ + + | user | + user := GLHUser new + username: 'testUser'; + name: 'test user'; + yourself. + + catalogue addUser: user withNames: { 'toto'. 'tata'. 'titi' }. + + self assert: (catalogue namesAt: user) size equals: 5. + self + assert: ((catalogue namesAt: user) includes: 'toto') + equals: true. + self + assert: ((catalogue namesAt: user) includes: 'tata') + equals: true. + self + assert: ((catalogue namesAt: user) includes: 'titi') + equals: true +] + +{ #category : #test } +GLHUserCatalogueV2Test >> testAddUsers [ + + | user1 user2 | + + + user1 := GLHUser new + username: 'testUser1'; + name: 'test user1'; + yourself. + + user2 := GLHUser new + username: 'testUser2'; + name: 'test user2'; + yourself. + + catalogue addUser: user1. + catalogue addUser: user2. + + self assert: catalogue size equals: 2 +] + +{ #category : #test } +GLHUserCatalogueV2Test >> testCollectUsernames [ + + | user1 user2 res | + + + user1 := GLHUser new + username: 'testUser1'; + name: 'test user1'; + yourself. + + user2 := GLHUser new + username: 'testUser2'; + name: 'test user2'; + yourself. + + catalogue addUser: user1. + catalogue addUser: user2. + + + res := catalogue collectUsernames. + + self assert: res size equals: 4. + self assert: (res at: 'testUser1') equals: user1. + self assert: (res at: 'testUser2') equals: user2. + self assert: (res at: 'test user1') equals: user1. + self assert: (res at: 'test user2') equals: user2 +] + +{ #category : #tests } +GLHUserCatalogueV2Test >> testExportAndLoad [ + + | user json res | + user := GLHUser new + username: 'testUser'; + name: 'test user'; + yourself. + + + catalogue addUser: user. + json := catalogue exportToJson. + + res := GLHUserCatalogue loadFromJson: json. + self assert: res size equals: catalogue size +] + +{ #category : #test } +GLHUserCatalogueV2Test >> testExportToJson [ + + | user user2 json res | + user := GLHUser new + username: 'testUser'; + name: 'test user'; + id: 1; + yourself. + user2 := GLHUser new + username: 'testUser2'; + name: 'test user2'; + id: 2; + yourself. + + + catalogue + addUser: user; + addUser: user2. + json := catalogue exportToJson. + + res := STONJSON fromString: json. + self assert: res size equals: catalogue size. + self assert: ((res at: 'test user2') at: #foundNames) size equals: 2. + self assert: ((res at: 'test user') at: #foundNames) size equals: 2 +] + +{ #category : #tests } +GLHUserCatalogueV2Test >> testLoadFromJson [ + + | json res | + json := '{"Benoit VERHAEGHE":{"id":1,"username":"Benoit.VERHAEGHE","foundNames":["Benoit VERHAEGHE","Benoit.VERHAEGHE","Benoît VERHAEGHE","Benoît Verhaeghe"],"name":"Benoit VERHAEGHE"},"HLAD Nicolas":{"id":2,"username":"Nicolas.HLAD","foundNames":["Nicolas Hlad","Nicolas.HLAD","HLAD Nicolas"],"name":"HLAD Nicolas"}}'. + + res := GLHUserCatalogue loadFromJson: json. + self assert: res size equals: 2. + + self + assert: (res searchUserWithName: 'Hlad') anyOne name + equals: 'HLAD Nicolas'. + self + assert: (res searchUserWithName: 'VERHAEGHE') anyOne name + equals: 'Benoit VERHAEGHE'. +] + +{ #category : #test } +GLHUserCatalogueV2Test >> testNamesAt [ + + | user | + + + user := GLHUser new + username: 'testUser'; + name: 'test user'; + yourself. + + catalogue addUser: user withName: 'toto'. + + + self assert: (catalogue namesAt: user) size equals: 3. + self + assert: ((catalogue namesAt: user) includes: 'toto') + equals: true. + self + assert: ((catalogue namesAt: user) includes: 'testUser') + equals: true. + self + assert: ((catalogue namesAt: user) includes: 'test user') + equals: true +] + +{ #category : #test } +GLHUserCatalogueV2Test >> testNamesAtChangingUser [ + + | user | + + + user := GLHUser new + name: 'test User'; + yourself. + + user hash. " 114462615" + + catalogue addUser: user withName: 'toto'. + + user username: 'testUser'. + + user hash. + + self assert: (catalogue namesAt: user) size equals: 3. + self + assert: ((catalogue namesAt: user) includes: 'toto') + equals: true. + "his username has been added after so its not in the catalogue" + self + assert: ((catalogue namesAt: user) includes: 'testUser') + equals: false. + self + assert: ((catalogue namesAt: user) includes: 'test User') + equals: true +] diff --git a/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st b/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st index 06d12f0..4881058 100644 --- a/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st +++ b/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st @@ -12,18 +12,24 @@ Class { GLHUserCatalogue class >> loadFromJson: aString [ | catalogue dic | - catalogue := GLHUserCatalogue new. + catalogue := self new. dic := (STONJSON fromString: aString) asDictionary. dic associationsDo: [ :assoc | - | itsName itsUsername itsCommitNames itsId| + | itsName itsUsername itsCommitNames itsId | itsName := assoc key. itsCommitNames := assoc value at: #foundNames. - itsUsername := assoc value at: #username. + itsUsername := assoc value at: #username. itsId := assoc value at: #id. - - catalogue addUser: (GLHUser new id: itsId; username: itsUsername; name: itsName; yourself ) withNames: itsCommitNames ]. - - ^ catalogue . + + catalogue + addUser: (GLHUser new + id: itsId; + username: itsUsername; + name: itsName; + yourself) + withNames: itsCommitNames ]. + + ^ catalogue ] { #category : #'as yet unclassified' } @@ -121,13 +127,20 @@ GLHUserCatalogue >> anImporter: aGLHModelImporter [ ] +{ #category : #accessing } +GLHUserCatalogue >> atWithId: anId [ + |res | + res := self associations detect: [ :assoc | assoc key id = anId ] ifNone: [ nil ]. + ^ res ifNotNil: [ res value ]. +] + { #category : #'as yet unclassified' } GLHUserCatalogue >> collectUsernames [ | username2User | self ifEmpty: [ ^ { } ]. - username2User := Dictionary new. + username2User := OrderedDictionary new. self associationsDo: [ :assoc | | user | @@ -190,7 +203,15 @@ GLHUserCatalogue >> initialize [ ] { #category : #'as yet unclassified' } -GLHUserCatalogue >> loadAllUsers [ +GLHUserCatalogue >> namesAt: aGLHUser [ + + | assoc | + assoc := self associationAt: aGLHUser. + ^ assoc value +] + +{ #category : #'as yet unclassified' } +GLHUserCatalogue >> reImportAllUsers [ "use it after a catalogue import from JSON" self associationsDo: [ :assoc | @@ -222,6 +243,14 @@ GLHUserCatalogue >> scrapeAuthorNameForUser: aGLHUser [ contributedProjectsForCommitAuthorsRelatedToUser: aGLHUser) ] +{ #category : #scrape } +GLHUserCatalogue >> scrapeAuthorNamesForUsers: aUserCollection [ + + aUserCollection do: [ :aGLHUser | + self scrapeAuthorNameForUser: aGLHUser + ]. +] + { #category : #completion } GLHUserCatalogue >> searchModelForAuthorNamesOfUser: aGLHUser [ |assoc| diff --git a/src/GitLabHealth-Model-Analysis/GLHUserCatalogueItem.class.st b/src/GitLabHealth-Model-Analysis/GLHUserCatalogueItem.class.st new file mode 100644 index 0000000..108c1d6 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/GLHUserCatalogueItem.class.st @@ -0,0 +1,15 @@ +Class { + #name : #GLHUserCatalogueItem, + #superclass : #Dictionary, + #instVars : [ + 'user', + 'names' + ], + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #initialization } +GLHUserCatalogueItem >> initialize [ + + names := Set new. +] diff --git a/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st b/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st new file mode 100644 index 0000000..d289db3 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st @@ -0,0 +1,289 @@ +Class { + #name : #GLHUserCatalogueV2, + #superclass : #GLHUserCatalogue, + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #import } +GLHUserCatalogueV2 class >> loadFromJson: aString [ + + | catalogue dic | + catalogue := self new. + dic := (STONJSON fromString: aString) asDictionary. + dic associationsDo: [ :assoc | + | itsName itsUsername itsCommitNames itsId| + itsName := assoc key. + itsCommitNames := assoc value at: #foundNames. + itsUsername := assoc value at: #username. + itsId := assoc value at: #id. + + catalogue addUser: (GLHUser new id: itsId; username: itsUsername; name: itsName; yourself ) withNames: itsCommitNames ]. + + ^ catalogue . +] + +{ #category : #'as yet unclassified' } +GLHUserCatalogueV2 class >> scrapeContributedProjectsForCommitAuthorsRelatedToUser: aGLHUser [ + "get all " + + | maxProjects itsProjects | + self + deprecated: + 'Use #scrapeWithImporter:ContributedProjectsForCommitAuthorsRelatedToUser: instead' + on: '12 August 2024' + in: + 'Pharo-11.0.0+build.726.sha.aece1b5473acf3830a0e082c1bc3a15d4ff3522b (64 Bit)'. + + aGLHUser id ifNil: [ ^ { } asSet ]. + + maxProjects := 10. + + GLHModelImporter current withCommitDiffs: false. + itsProjects := aGLHUser contributedProjects ifEmpty: [ + GLHModelImporter current + importContributedProjectsOfUser: aGLHUser ]. + + itsProjects + collect: [ :project | + GLHModelImporter current importAndLoadLatestsCommitsOfProject: + project ] + from: 1 + to: (itsProjects size min: maxProjects). + + ^ (aGLHUser commits collect: [ :commit | commit author_name ]) asSet +] + +{ #category : #'as yet unclassified' } +GLHUserCatalogueV2 class >> scrapeWithImporter: anImporter contributedProjectsForCommitAuthorsRelatedToUser: aGLHUser [ + "get all " + + | maxProjects itsProjects | + aGLHUser id ifNil: [ ^ { } asSet ]. + + maxProjects := 10. + + anImporter withCommitDiffs: false. + itsProjects := aGLHUser contributedProjects ifEmpty: [ + anImporter + importContributedProjectsOfUser: aGLHUser ]. + + itsProjects + collect: [ :project | + anImporter importAndLoadLatestsCommitsOfProject: + project ] + from: 1 + to: (itsProjects size min: maxProjects). + + ^ (aGLHUser commits collect: [ :commit | commit author_name ]) asSet +] + +{ #category : #adding } +GLHUserCatalogueV2 >> addUser: aGLHUser [ + + self at: aGLHUser name ifAbsentPut: [ + self newEntryForUser: aGLHUser ] +] + +{ #category : #adding } +GLHUserCatalogueV2 >> addUser: aGLHUser withName: name [ + + self + at: aGLHUser name + ifPresent: [ :entry | (entry at: #names) add: name ] + ifAbsentPut: [ + |entry| + entry := (self newEntryForUser: aGLHUser). + (entry at: #names) add: name. + entry + ] +] + +{ #category : #adding } +GLHUserCatalogueV2 >> addUser: aGLHUser withNames: aCollectionOfNames [ + + self + at: aGLHUser name + ifPresent: [ :entry | (entry at: #names) addAll: aCollectionOfNames ] + ifAbsentPut: [ + |entry| + entry := (self newEntryForUser: aGLHUser ). + (entry at: #names ) addAll: aCollectionOfNames. + entry ] +] + +{ #category : #accessing } +GLHUserCatalogueV2 >> anImporter: aGLHModelImporter [ + anImporter := aGLHModelImporter + +] + +{ #category : #'as yet unclassified' } +GLHUserCatalogueV2 >> collectUsernames [ + + | username2User | + self ifEmpty: [ ^ { } ]. + + username2User := OrderedDictionary new. + + self associationsDo: [ :assoc | + | user | + user := assoc value at: #user . + (assoc value at: #names) do: [ :username | username2User at: username put: user ] ]. + + ^ username2User +] + +{ #category : #completion } +GLHUserCatalogueV2 >> completeAuthorNameOfUser: aGLHUser with: authorName [ + + self + deprecated: 'Use #addUser:withName: instead' + on: '12 August 2024' + in: + 'Pharo-11.0.0+build.726.sha.aece1b5473acf3830a0e082c1bc3a15d4ff3522b (64 Bit)'. + + self addUser: aGLHUser withName: authorName +] + +{ #category : #completion } +GLHUserCatalogueV2 >> completeAuthorNameOfUser: aGLHUser withAll: authorNames [ + + self + deprecated: 'Use #addUser:withNames: instead' + on: '12 August 2024' + in: + 'Pharo-11.0.0+build.726.sha.aece1b5473acf3830a0e082c1bc3a15d4ff3522b (64 Bit)'. + + + self addUser: aGLHUser withNames: authorNames +] + +{ #category : #export } +GLHUserCatalogueV2 >> exportToJson [ + + | tempDic | + " tempDic := self associations collect: [ :assoc | + Dictionary new at: (assoc key name) put: ({ + (#names -> assoc value asArray). + (#id -> assoc key id) } asDictionary); yourself ]." + tempDic := Dictionary new. + self associationsDo: [ :assoc | + |entry user names| + entry := assoc value. + user := entry at: #user. + names := entry at: #names. + tempDic + at: assoc key put: { + (#name -> user name). + (#username -> user username). + (#foundNames -> names asArray). + (#id -> user id) } asDictionary; + yourself ]. + + ^ STONJSON toString: tempDic +] + +{ #category : #initialization } +GLHUserCatalogueV2 >> initialize [ + + anImporter := GLHModelImporter current. +] + +{ #category : #'accessing - name' } +GLHUserCatalogueV2 >> names [ + ^ self collect: [ :entry | entry at: #names ] +] + +{ #category : #'as yet unclassified' } +GLHUserCatalogueV2 >> namesAt: aGLHUser [ + ^ (self at: aGLHUser name) at: #names. +] + +{ #category : #'instance creation' } +GLHUserCatalogueV2 >> newEntryForUser: aGLHUser [. + +^ Dictionary new + at: #user put: aGLHUser; + at: #names put: (Set new + add: aGLHUser username; + add: aGLHUser name; + yourself); + yourself +] + +{ #category : #'as yet unclassified' } +GLHUserCatalogueV2 >> reImportAllUsers [ + "use it after a catalogue import from JSON" + + self associationsDo: [ :assoc | + | user | + user := assoc value at: #user. + user := anImporter + ifNotNil: [ + user id + ifNotNil: [ anImporter importUser: user id ] + ifNil: [ anImporter importUserByUsername: user username ] ] + ifNil: [user]. + assoc value at: #user put: user ] +] + +{ #category : #'as yet unclassified' } +GLHUserCatalogueV2 >> scrapeAuthorNameForAllUsers [ + + self users do: [ :user | self scrapeAuthorNameForUser: user ] +] + +{ #category : #'as yet unclassified' } +GLHUserCatalogueV2 >> scrapeAuthorNameForUser: aGLHUser [ + + self addUser: aGLHUser withNames: (GLHUserCatalogue + scrapeWithImporter: anImporter + contributedProjectsForCommitAuthorsRelatedToUser: aGLHUser). +] + +{ #category : #scrape } +GLHUserCatalogueV2 >> scrapeAuthorNamesForUsers: aUserCollection [ + + aUserCollection do: [ :aGLHUser | + self scrapeAuthorNameForUser: aGLHUser + ]. +] + +{ #category : #search } +GLHUserCatalogueV2 >> searchId: anId [ + ^ self select: [ :entry | (entry at: #user) id = anId ]. +] + +{ #category : #completion } +GLHUserCatalogueV2 >> searchModelForAuthorNamesOfUser: aGLHUser [ + + self addUser: aGLHUser withNames: + (aGLHUser commits collect: [ :c | c author_name ]) +] + +{ #category : #search } +GLHUserCatalogueV2 >> searchName: aName [ + + ^ self select: [ :entry | + |collectionOfName| + collectionOfName := entry at: #names. + (' ' join: collectionOfName) asLowercase includesSubstring: + aName asLowercase ] +] + +{ #category : #search } +GLHUserCatalogueV2 >> searchUserWithName: aName [ + + ^ (self searchName: aName) users +] + +{ #category : #accessing } +GLHUserCatalogueV2 >> userAt: aGLHUser [ + ^ (self at: aGLHUser name) at: #user. +] + +{ #category : #accessing } +GLHUserCatalogueV2 >> users [ + + ^ self collect: [ :entry | entry at: #user ]. +] diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 8508487..ea2bffa 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -347,23 +347,22 @@ GitMetricExporter >> setupAnalysisForUsersWithNames: userNames [ "import all the project since a certain time" | users | - users := userNames collect: [ :username | glhImporter importUserByUsername: username ]. - - glhImporter userCatalogue scrapeAuthorNameForAllUsers. - entities addAll: (users collect: [:user | - | itsProjects metrics i size | - itsProjects := glhImporter importContributedProjectsOfUser: user. - + glhImporter userCatalogue scrapeAuthorNamesForUsers: users. + + entities addAll: (users collect: [ :user | + | itsProjects metrics i size | + itsProjects := glhImporter importContributedProjectsOfUser: user. + metrics := GitMetric4User new. metrics glhImporter: glhImporter; user: user. - + i := 0. - size := itsProjects size. + size := itsProjects size. metrics itsProjects: (itsProjects collect: [ :p | (' ' join: { 'complete import of project:'. @@ -374,9 +373,7 @@ GitMetricExporter >> setupAnalysisForUsersWithNames: userNames [ size. ']' }) recordInfo. - p id -> (glhImporter completeImportProject: p) ]) asDictionary. - ] - ). + p id -> (glhImporter completeImportProject: p) ]) asDictionary ]). ^ self ] diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index 9a1abf7..69008a4 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -857,7 +857,9 @@ GLHModelImporter >> initialize [ withInitialCommits := false. withInitialMergeRequest := false. withCommitsSince := (Date today - 1 week) asDateAndTime. - userCatalogue := GLHUserCatalogue new anImporter: self; yourself. + userCatalogue := GLHUserCatalogueV2 new + anImporter: self; + yourself. self initReader ] From e7355e2ba343d9fecfba056a7c6cd897eaedebf8 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Mon, 19 Aug 2024 10:09:28 +0200 Subject: [PATCH 025/154] feat: export analyses in s3 (#26) * feat: add exportInS3 method * chore: install aws dependency --- .../BaselineOfGitLabHealth.class.st | 9 +++++++-- .../GitMetricExporter.class.st | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st b/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st index b6e83fa..cdaad70 100644 --- a/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st +++ b/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st @@ -38,11 +38,16 @@ BaselineOfGitLabHealth >> defineDependencies: spec [ spec baseline: 'MoreLogger' with: [ spec repository: 'github://badetitou/MoreLogger:main/src' ]. - spec + spec baseline: 'Voyage' with: [ spec loads: #('mongo'); - repository: 'github://pharo-nosql/voyage/mc' ] + repository: 'github://pharo-nosql/voyage/mc' ]. + spec + baseline: 'AWS' + with: [ + spec repository: 'github://newapplesho/aws-sdk-smalltalk/pharo-repository' + ] ] { #category : #baselines } diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 301fdfd..ce2587b 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -254,6 +254,24 @@ GitMetricExporter >> exportInDB: repository [ self analyses do: [ :analysis | analysis save ] ] +{ #category : #exporting } +GitMetricExporter >> exportInS3: bucketName accessKey: accessKey secretKey: secretKey region: region [ + | s3 bucket ston date | +AWSS3Config default + accessKeyId: accessKey; + secretKey: secretKey; + regionName: region. + + s3 := AWSS3 new. + bucket:= s3 bucketNamed: bucketName. + + ston := STON toString: analyses. + + date := (Date today asString) copyReplaceAll: ' 'asString with: '-'. + + bucket atKey:'analyses-', date, '.ston' putObject: ston. +] + { #category : #projects } GitMetricExporter >> findParticipationOfCommitAuthorNamed: username amongProjects: aCollectionOfProjects [ From 157ef93199c1a84b66a2220faa6ba818bcdf56a7 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Mon, 19 Aug 2024 10:16:33 +0200 Subject: [PATCH 026/154] feat(metrics): average time between commits (#27) * feat: add method averageTimeBetweenCommitsSince:until * feat: add averageTimeBetweenCommits in analysis report * fix: change averageTimeBetweenCommit in seconds for duration * feat: add over in averageTimeBetweenCommits * refactor: change the way the average is calculated in averageTimeBetweenCommit metric * refactor: remove unused code --- .../AnalysisReport.class.st | 15 ++++- .../GitMetric4User.class.st | 64 ++++++++++++++++++- .../GitMetricExporter.class.st | 6 ++ 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st b/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st index 968baa0..e0e9e32 100644 --- a/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st +++ b/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st @@ -10,7 +10,8 @@ Class { 'commentContribution', 'mergeRequestDuration', 'codeChurn', - 'delayUntilFirstChurn' + 'delayUntilFirstChurn', + 'averageTimeBetweenCommits' ], #category : #'GitLabHealth-Model-Analysis' } @@ -20,6 +21,18 @@ AnalysisReport class >> isVoyageRoot [ ^true ] +{ #category : #accessing } +AnalysisReport >> averageTimeBetweenCommits [ + + ^ averageTimeBetweenCommits +] + +{ #category : #accessing } +AnalysisReport >> averageTimeBetweenCommits: anObject [ + + averageTimeBetweenCommits := anObject +] + { #category : #accessing } AnalysisReport >> codeAddition [ diff --git a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st index 7fa59db..7430e10 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st @@ -8,6 +8,63 @@ Class { #category : #'GitLabHealth-Model-Analysis' } +{ #category : #metrics } +GitMetric4User >> averageTimeBetweenCommitSince: since until: until over: aDateWeekMonthOrYear [ + + | commits commitSortedByDate commits1 commits2 differences groupedByDate dateOver | + + groupedByDate := self + setupGroupedDateFrom: since + to: until + over: aDateWeekMonthOrYear. + + gitAnalyzer := GitAnalyzer new + onModel: glhModel; + glhImporter: glhImporter. + + glhImporter withCommitDiffs: false. + commits := self + loadCommitsFromProjectsIds: itsProjects keys + since: since + until: until. + glhImporter withCommitDiffs: true. + commits := commits reject: [ :commit | commit commitCreator ~= user ]. + + commitSortedByDate := commits sorted: [ :commit1 :commit2 | + commit1 committed_date + < commit2 committed_date ]. + + commitSortedByDate do: [ :commit | + dateOver := self + transformDate: commit committed_date + to: aDateWeekMonthOrYear. + + groupedByDate at: dateOver printString ifPresent: [ :value | value add: commit ]. + ]. + + groupedByDate := groupedByDate select: [ :group | group size >= 2 ]. + + + groupedByDate := groupedByDate collect: [ :group | + differences := (1 to: group size - 1) collect: [ :i | + commits1 := group at: i. + commits2 := group at: i + 1. + + (commits2 committed_date - commits1 committed_date) asSeconds ]. + + differences average asDuration. + ]. + + + ^{ + (#overEach -> aDateWeekMonthOrYear name). + (#forOver -> (groupedByDate keys size printString + , aDateWeekMonthOrYear printString)). + (#average -> groupedByDate average). + (#details -> groupedByDate). + (#userCommits -> commits size) } asDictionary. +] + { #category : #churn } GitMetric4User >> codeChurnSince: since until: until onACommitWindowOf: commitLimit overA: aDateWeekMonthOrYear [ @@ -510,7 +567,7 @@ GitMetric4User >> foundSuccessorOf: userCommits andCompleteImportForMax: commitL { #category : #'as yet unclassified' } GitMetric4User >> generateAnalysisForPeriod: period over: over withMaxCommitWindows: maxCommitWindow [ - | contribution codeAddition codeDeletion commitFrequency commentContribution mergeRequestDuration codeChurn delayUntilFirstChurn | + | contribution codeAddition codeDeletion commitFrequency commentContribution mergeRequestDuration codeChurn delayUntilFirstChurn averageTimeBetweenCommits | contribution := self codeContributionsSince: (period at: #since) @@ -548,6 +605,8 @@ GitMetric4User >> generateAnalysisForPeriod: period over: over withMaxCommitWind until: (period at: #until) onACommitWindowOf: maxCommitWindow overA: over) at: #avgDelay. + + averageTimeBetweenCommits := (self averageTimeBetweenCommitSince: (period at: #since) until: (period at: #until) over: over) at: #average. ^ AnalysisReport new username: self user name; @@ -558,7 +617,8 @@ GitMetric4User >> generateAnalysisForPeriod: period over: over withMaxCommitWind commentContribution: commentContribution; mergeRequestDuration: mergeRequestDuration; codeChurn: codeChurn; - delayUntilFirstChurn: delayUntilFirstChurn + delayUntilFirstChurn: delayUntilFirstChurn; + averageTimeBetweenCommits: averageTimeBetweenCommits. ] { #category : #initialization } diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index ce2587b..8aaea38 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -231,6 +231,12 @@ GitMetricExporter >> exportInCSVOver: aCollectionOfDateWeekMonthOrYear [ withName: 'delay Until First Churn (W=' , maxCommitWindow printString , ') ' asSymbol. + + "average time between commits" + exportBrowserModel + addColumnForQuery: [ :analysis | analysis averageTimeBetweenCommits ] + withName: + 'average time between commits' asSymbol. aCollectionOfDateWeekMonthOrYear do: [ :aDateWeekMonthOrYear | over := aDateWeekMonthOrYear. From 7a6969e8ab05e03cc5718ab2cbac5612630a0034 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Mon, 19 Aug 2024 10:40:15 +0200 Subject: [PATCH 027/154] feat(metrics): number of project with a commit of the user (#30) * feat: create numberOfProjetWithCommit method * feat: add numberOfProjectWithCommit metric in analysis report and csv export * fix: missing semicolon * fix: missing comma --- .../AnalysisReport.class.st | 13 +++++ .../GitMetric4User.class.st | 50 ++++++++++++++++++- .../GitMetricExporter.class.st | 6 +++ 3 files changed, 68 insertions(+), 1 deletion(-) diff --git a/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st b/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st index e0e9e32..ed85ea3 100644 --- a/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st +++ b/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st @@ -11,6 +11,7 @@ Class { 'mergeRequestDuration', 'codeChurn', 'delayUntilFirstChurn', + 'numberOfProjectWithCommit', 'averageTimeBetweenCommits' ], #category : #'GitLabHealth-Model-Analysis' @@ -117,6 +118,18 @@ AnalysisReport >> mergeRequestDuration: anObject [ mergeRequestDuration := anObject ] +{ #category : #accessing } +AnalysisReport >> numberOfProjectWithCommit [ + + ^ numberOfProjectWithCommit +] + +{ #category : #accessing } +AnalysisReport >> numberOfProjectWithCommit: anObject [ + + numberOfProjectWithCommit := anObject +] + { #category : #accessing } AnalysisReport >> period [ diff --git a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st index 7430e10..c464772 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st @@ -567,7 +567,7 @@ GitMetric4User >> foundSuccessorOf: userCommits andCompleteImportForMax: commitL { #category : #'as yet unclassified' } GitMetric4User >> generateAnalysisForPeriod: period over: over withMaxCommitWindows: maxCommitWindow [ - | contribution codeAddition codeDeletion commitFrequency commentContribution mergeRequestDuration codeChurn delayUntilFirstChurn averageTimeBetweenCommits | + | contribution codeAddition codeDeletion commitFrequency commentContribution mergeRequestDuration codeChurn delayUntilFirstChurn averageTimeBetweenCommits averageTimeBetweenCommits | contribution := self codeContributionsSince: (period at: #since) @@ -606,6 +606,7 @@ GitMetric4User >> generateAnalysisForPeriod: period over: over withMaxCommitWind onACommitWindowOf: maxCommitWindow overA: over) at: #avgDelay. + numberOfProjectWithCommit := self numberOfProjectWithCommitSince: (period at: #since) until: (period at: #until) overA: over. averageTimeBetweenCommits := (self averageTimeBetweenCommitSince: (period at: #since) until: (period at: #until) over: over) at: #average. ^ AnalysisReport new @@ -618,6 +619,7 @@ GitMetric4User >> generateAnalysisForPeriod: period over: over withMaxCommitWind mergeRequestDuration: mergeRequestDuration; codeChurn: codeChurn; delayUntilFirstChurn: delayUntilFirstChurn; + numberOfProjectWithCommit: (numberOfProjectWithCommit at: #average); averageTimeBetweenCommits: averageTimeBetweenCommits. ] @@ -730,6 +732,52 @@ GitMetric4User >> mergeRequestDurationSince: since until: until overA: aDateWeek (#details -> groupedByDate) } asDictionary ] +{ #category : #metrics } +GitMetric4User >> numberOfProjectWithCommitSince: since until: until overA: aDateWeekMonthOrYear [ + | groupedByDate commits userCommits dateOver projects | + groupedByDate := self + setupGroupedDateFrom: since + to: until + over: aDateWeekMonthOrYear. + + gitAnalyzer := GitAnalyzer new + onModel: glhModel; + glhImporter: glhImporter. + + glhImporter withCommitDiffs: false. + commits := self + loadCommitsFromProjectsIds: itsProjects keys + since: since + until: until. + glhImporter withCommitDiffs: true. + userCommits := commits reject: [ :commit | commit commitCreator ~= user ]. + + + userCommits do: [ :userCommit | + dateOver := self + transformDate: userCommit committed_date + to: aDateWeekMonthOrYear. + + groupedByDate at: dateOver printString ifPresent: [ :value | value add: (userCommit repository project) ]. + ]. + + groupedByDate := groupedByDate collect: [ :group | + projects := Set newFrom: group. + projects size. + ]. + + ^ { + (#overEach -> aDateWeekMonthOrYear name). + (#forOver -> (groupedByDate keys size printString + , aDateWeekMonthOrYear printString)). + (#average + -> + groupedByDate average asFloat). + (#details -> groupedByDate). + (#userCommits -> commits size) } asDictionary + +] + { #category : #accessing } GitMetric4User >> user [ ^ user diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 8aaea38..b3827db 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -232,6 +232,12 @@ GitMetricExporter >> exportInCSVOver: aCollectionOfDateWeekMonthOrYear [ 'delay Until First Churn (W=' , maxCommitWindow printString , ') ' asSymbol. + "number of project with minimum one commit of user" + exportBrowserModel + addColumnForQuery: [ :analysis | analysis numberOfProjectWithCommit ] + withName: + 'number of project with min 1 commit of user' asSymbol. + "average time between commits" exportBrowserModel addColumnForQuery: [ :analysis | analysis averageTimeBetweenCommits ] From f8a271406769af7627cb2b5ed7e18ef4862b9deb Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Mon, 19 Aug 2024 11:24:27 +0200 Subject: [PATCH 028/154] refactor: define over in the generateAnalysis method (#29) * refactor: create generateAnalysisOver: to define over in generation method * feat: add over in analysisReport * refactor: change period for since and util in csv export * fix: cant parse body in AnalysisReport * refactor: rename over to overA averageTimeBetweenCommits method --- .../AnalysisReport.class.st | 14 ++ .../GitMetric4User.class.st | 145 ++++++++++-------- .../GitMetricExporter.class.st | 86 +++++------ 3 files changed, 127 insertions(+), 118 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st b/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st index ed85ea3..987a2bb 100644 --- a/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st +++ b/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st @@ -4,6 +4,7 @@ Class { #instVars : [ 'username', 'period', + 'over', 'codeAddition', 'codeDeletion', 'commitFrequency', @@ -130,6 +131,19 @@ AnalysisReport >> numberOfProjectWithCommit: anObject [ numberOfProjectWithCommit := anObject ] +{ #category : #accessing } +AnalysisReport >> over [ + + ^ over +] + +{ #category : #accessing } +AnalysisReport >> over: anObject [ + + over := anObject + +] + { #category : #accessing } AnalysisReport >> period [ diff --git a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st index c464772..36f7c70 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st @@ -9,15 +9,14 @@ Class { } { #category : #metrics } -GitMetric4User >> averageTimeBetweenCommitSince: since until: until over: aDateWeekMonthOrYear [ +GitMetric4User >> averageTimeBetweenCommitSince: since until: until overA: aDateWeekMonthOrYear [ | commits commitSortedByDate commits1 commits2 differences groupedByDate dateOver | - groupedByDate := self setupGroupedDateFrom: since to: until over: aDateWeekMonthOrYear. - + gitAnalyzer := GitAnalyzer new onModel: glhModel; glhImporter: glhImporter. @@ -33,36 +32,38 @@ GitMetric4User >> averageTimeBetweenCommitSince: since until: until over: aDateW commitSortedByDate := commits sorted: [ :commit1 :commit2 | commit1 committed_date < commit2 committed_date ]. - - commitSortedByDate do: [ :commit | - dateOver := self - transformDate: commit committed_date + + commitSortedByDate do: [ :commit | + dateOver := self + transformDate: commit committed_date to: aDateWeekMonthOrYear. - - groupedByDate at: dateOver printString ifPresent: [ :value | value add: commit ]. - ]. - groupedByDate := groupedByDate select: [ :group | group size >= 2 ]. - + groupedByDate + at: dateOver printString + ifPresent: [ :value | value add: commit ] ]. - groupedByDate := groupedByDate collect: [ :group | - differences := (1 to: group size - 1) collect: [ :i | - commits1 := group at: i. - commits2 := group at: i + 1. + groupedByDate := groupedByDate select: [ :group | group size >= 2 ]. - (commits2 committed_date - commits1 committed_date) asSeconds ]. - differences average asDuration. - ]. - + groupedByDate := groupedByDate collect: [ :group | + differences := (1 to: group size - 1) collect: [ :i | + commits1 := group at: i. + commits2 := group at: i + 1. - ^{ + (commits2 committed_date + - commits1 committed_date) + asSeconds ]. + + differences average asDuration ]. + + + ^ { (#overEach -> aDateWeekMonthOrYear name). (#forOver -> (groupedByDate keys size printString , aDateWeekMonthOrYear printString)). (#average -> groupedByDate average). (#details -> groupedByDate). - (#userCommits -> commits size) } asDictionary. + (#userCommits -> commits size) } asDictionary ] { #category : #churn } @@ -314,7 +315,7 @@ GitMetric4User >> commitFrequencySince: since until: until overA: aDateWeekMonth (#details -> groupedByDate) } asOrderedDictionary ] -{ #category : #'as yet unclassified' } +{ #category : #metrics } GitMetric4User >> commitsProducedOnProject: projectId since: sinceDate until: untilDate [ | frequencies | @@ -564,63 +565,71 @@ GitMetric4User >> foundSuccessorOf: userCommits andCompleteImportForMax: commitL ^ analyzingCommits ] -{ #category : #'as yet unclassified' } -GitMetric4User >> generateAnalysisForPeriod: period over: over withMaxCommitWindows: maxCommitWindow [ +{ #category : #analysis } +GitMetric4User >> generateAnalysisForPeriod: period over: aDateWeekMonthOrYear withMaxCommitWindows: maxCommitWindow [ - | contribution codeAddition codeDeletion commitFrequency commentContribution mergeRequestDuration codeChurn delayUntilFirstChurn averageTimeBetweenCommits averageTimeBetweenCommits | - + | contribution commitFrequency commentContribution mergeRequestDuration codeChurn delayUntilFirstChurn averageTimeBetweenCommits numberOfProjectWithCommit | contribution := self codeContributionsSince: (period at: #since) until: (period at: #until) - overA: over. - codeAddition := contribution at: #avgAddition. - codeDeletion := contribution at: #avgDeletion. + overA: aDateWeekMonthOrYear. - commitFrequency := (self - commitFrequencySince: (period at: #since) - until: (period at: #until) - overA: over) at: #averageFloat. + commitFrequency := self + commitFrequencySince: (period at: #since) + until: (period at: #until) + overA: aDateWeekMonthOrYear. - commentContribution := (self - commentsContributionsSince: + commentContribution := self + commentsContributionsSince: + (period at: #since) + until: (period at: #until) + overA: aDateWeekMonthOrYear. + + mergeRequestDuration := self + mergeRequestDurationSince: (period at: #since) until: (period at: #until) - overA: over) at: #avgComments. - - mergeRequestDuration := (self - mergeRequestDurationSince: - (period at: #since) - until: (period at: #until) - overA: over) at: #avgDuration. - - codeChurn := (self - codeChurnSince: (period at: #since) - until: (period at: #until) - onACommitWindowOf: maxCommitWindow - overA: over) at: #churn. - - delayUntilFirstChurn := (self - delayUntilFirstChurnSince: - (period at: #since) - until: (period at: #until) - onACommitWindowOf: maxCommitWindow - overA: over) at: #avgDelay. - - numberOfProjectWithCommit := self numberOfProjectWithCommitSince: (period at: #since) until: (period at: #until) overA: over. - averageTimeBetweenCommits := (self averageTimeBetweenCommitSince: (period at: #since) until: (period at: #until) over: over) at: #average. + overA: aDateWeekMonthOrYear. + + codeChurn := self + codeChurnSince: (period at: #since) + until: (period at: #until) + onACommitWindowOf: maxCommitWindow + overA: aDateWeekMonthOrYear. + + delayUntilFirstChurn := self + delayUntilFirstChurnSince: + (period at: #since) + until: (period at: #until) + onACommitWindowOf: maxCommitWindow + overA: aDateWeekMonthOrYear. + + numberOfProjectWithCommit := self + numberOfProjectWithCommitSince: + (period at: #since) + until: (period at: #until) + overA: aDateWeekMonthOrYear. + averageTimeBetweenCommits := self + averageTimeBetweenCommitSince: + (period at: #since) + until: (period at: #until) + overA: aDateWeekMonthOrYear. ^ AnalysisReport new username: self user name; period: period; - codeAddition: codeAddition; - codeDeletion: codeDeletion; - commitFrequency: commitFrequency; - commentContribution: commentContribution; - mergeRequestDuration: mergeRequestDuration; - codeChurn: codeChurn; - delayUntilFirstChurn: delayUntilFirstChurn; - numberOfProjectWithCommit: (numberOfProjectWithCommit at: #average); - averageTimeBetweenCommits: averageTimeBetweenCommits. + over: aDateWeekMonthOrYear asString; + codeAddition: (contribution at: #avgAddition); + codeDeletion: (contribution at: #avgDeletion); + commitFrequency: (commitFrequency at: #averageFloat); + commentContribution: (commentContribution at: #avgComments); + mergeRequestDuration: (mergeRequestDuration at: #avgDuration); + codeChurn: (codeChurn at: #churn); + delayUntilFirstChurn: (delayUntilFirstChurn at: #avgDelay); + numberOfProjectWithCommit: + (numberOfProjectWithCommit at: #average); + averageTimeBetweenCommits: + (averageTimeBetweenCommits at: #average) ] { #category : #initialization } diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index b3827db..b9a9f25 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -117,44 +117,6 @@ GitMetricExporter >> constructFilePath: runningOver [ ^ file ] -{ #category : #exporting } -GitMetricExporter >> debugExportOver: aCollectionOfDateWeekMonthOrYear [ - - | period | - over := Date. - - period := runningPeriods first. - - - 1 halt. - "Code Contribution " - - (entities collect: (self blockCodeAdditionSince: period)) recordInfo. - (entities collect: (self blockCodeDeletionSince: period)) recordInfo. - - "Commit frequencies " - (entities collect: (self blockCommitFrequencySince: period)) - recordInfo. - - "comment contribution " - (entities collect: (self blockCommentsContributionSince: period)) - recordInfo. - - "merge Request Duration " - (entities collect: (self blockMergeRequestDurationSince: period)) - recordInfo. - - "code churn" - (entities collect: (self blockCodeChurnSince: period)) recordInfo. - - "delay Until First Churn" - (entities collect: (self blockDelayUntilFirstChurnSince: period)) - recordInfo. - - - 'Done computing debug' recordInfo -] - { #category : #accessing } GitMetricExporter >> entities: aCollection [ entities := aCollection @@ -176,7 +138,7 @@ GitMetricExporter >> exportFor: usersWithProjects over: aCollectionOfDateWeekMon ] { #category : #exporting } -GitMetricExporter >> exportInCSVOver: aCollectionOfDateWeekMonthOrYear [ +GitMetricExporter >> exportInCSV [ | exportBrowserModel file | exportBrowserModel := MiExportModel new. @@ -192,8 +154,16 @@ GitMetricExporter >> exportInCSVOver: aCollectionOfDateWeekMonthOrYear [ withName: #'User name'. exportBrowserModel - addColumnForQuery: [ :analysis | analysis period ] - withName: #Period. + addColumnForQuery: [ :analysis | analysis period at: #since ] + withName: #Since. + + exportBrowserModel + addColumnForQuery: [ :analysis | analysis period at: #until ] + withName: #Until. + + exportBrowserModel + addColumnForQuery: [ :analysis | analysis over ] + withName: #Over. "Code Contribution " exportBrowserModel @@ -244,15 +214,12 @@ GitMetricExporter >> exportInCSVOver: aCollectionOfDateWeekMonthOrYear [ withName: 'average time between commits' asSymbol. - aCollectionOfDateWeekMonthOrYear do: [ :aDateWeekMonthOrYear | - over := aDateWeekMonthOrYear. - file := self constructFilePath: over. - - file writeStreamDo: [ :aStream | - aStream - << 'sep=,'; - << OSPlatform current lineEnding. - exportBrowserModel writeCSVOn: aStream ] ]. + file := self constructFilePath: over. + file writeStreamDo: [ :aStream | + aStream + << 'sep=,'; + << OSPlatform current lineEnding. + exportBrowserModel writeCSVOn: aStream ]. 'Done computing' recordInfo ] @@ -337,6 +304,25 @@ GitMetricExporter >> generateAnalyses [ ^ newAnalyses ] +{ #category : #analysis } +GitMetricExporter >> generateAnalysesOver: aDateWeekMonthOrYear [ + + | newAnalyses | + over := aDateWeekMonthOrYear. + newAnalyses := OrderedCollection new. + + runningPeriods do: [ :period | + newAnalyses addAll: (entities collect: [ :entity | + entity + generateAnalysisForPeriod: period + over: over + withMaxCommitWindows: maxCommitWindow ]) ]. + + self analyses: newAnalyses. + + ^ newAnalyses +] + { #category : #accessing } GitMetricExporter >> glhImporter: anImporter [ From b820902b4c6af21a70bf3aa8d90665a275ffa65e Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Mon, 19 Aug 2024 13:17:59 +0200 Subject: [PATCH 029/154] fix: error if there are no commits in averageTimeBetweenCommits method (#33) --- src/GitLabHealth-Model-Analysis/GitMetric4User.class.st | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st index 36f7c70..0688590 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st @@ -11,7 +11,7 @@ Class { { #category : #metrics } GitMetric4User >> averageTimeBetweenCommitSince: since until: until overA: aDateWeekMonthOrYear [ - | commits commitSortedByDate commits1 commits2 differences groupedByDate dateOver | + | commits commitSortedByDate commits1 commits2 differences groupedByDate dateOver average | groupedByDate := self setupGroupedDateFrom: since to: until @@ -56,12 +56,15 @@ GitMetric4User >> averageTimeBetweenCommitSince: since until: until overA: aDate differences average asDuration ]. + average := groupedByDate + ifEmpty: [ nil ] + ifNotEmpty: [ groupedByDate average ]. ^ { (#overEach -> aDateWeekMonthOrYear name). (#forOver -> (groupedByDate keys size printString , aDateWeekMonthOrYear printString)). - (#average -> groupedByDate average). + (#average -> average). (#details -> groupedByDate). (#userCommits -> commits size) } asDictionary ] From 7ecd14a6c91a65d309a741152f1e298c32a69bcc Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Mon, 19 Aug 2024 15:37:00 +0200 Subject: [PATCH 030/154] fix: put s3 pharo library in baseline (#34) * chore: add aws and voyage in baseline requirement * chore: useLoaded for conflict in .smalltalk.ston --- .smalltalk.ston | 2 +- src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.smalltalk.ston b/.smalltalk.ston index 45bd543..0b19fe0 100644 --- a/.smalltalk.ston +++ b/.smalltalk.ston @@ -6,7 +6,7 @@ SmalltalkCISpec { #directory : 'src', #load : [ 'default', 'Jira' ], #platforms : [ #pharo ], - #onConflict : #useIncoming, + #onConflict : #useLoaded, #onUpgrade : #useIncoming } ], diff --git a/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st b/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st index cdaad70..be2c453 100644 --- a/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st +++ b/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st @@ -128,7 +128,7 @@ BaselineOfGitLabHealth >> definePackages: spec [ package: 'GLPHExtended-Model-Extension' with: [ spec requires: #( 'GLPHExtended-Model' 'GitLabHealth-Model' 'GitLabHealth-Model-Extension' ) ]; - package: 'GitLabHealth-Model-Analysis'; + package: 'GitLabHealth-Model-Analysis' with: [ spec requires: #( 'Voyage' 'AWS' ) ]; package: 'GitLabHealth-Model-Analysis-Tests' with: [ spec requires: #( 'GitLabHealth-Model-Analysis' ) ]; package: 'GitLabHealth-Visualization'; From 26656624b75f800ac8e60066b6d2305cdcc47e33 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Mon, 19 Aug 2024 16:48:04 +0200 Subject: [PATCH 031/154] feat: use label and over in s3 export filename (#36) --- .../GitMetricExporter.class.st | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index b9a9f25..02faa13 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -235,20 +235,26 @@ GitMetricExporter >> exportInDB: repository [ { #category : #exporting } GitMetricExporter >> exportInS3: bucketName accessKey: accessKey secretKey: secretKey region: region [ - | s3 bucket ston date | -AWSS3Config default - accessKeyId: accessKey; - secretKey: secretKey; - regionName: region. + + | s3 bucket ston date fileName | + AWSS3Config default + accessKeyId: accessKey; + secretKey: secretKey; + regionName: region. s3 := AWSS3 new. - bucket:= s3 bucketNamed: bucketName. - + bucket := s3 bucketNamed: bucketName. + ston := STON toString: analyses. - - date := (Date today asString) copyReplaceAll: ' 'asString with: '-'. - - bucket atKey:'analyses-', date, '.ston' putObject: ston. + + date := Date today asString copyReplaceAll: ' ' asString with: '-'. + fileName := ('-' join: { + 'analyse'. + label. + over asString. + date }) , '.ston'. + + bucket atKey: fileName putObject: ston ] { #category : #projects } From 23bad1ee287f6ceeb3bd1e7b5113b74b8fb7c6d5 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Tue, 20 Aug 2024 11:13:46 +0200 Subject: [PATCH 032/154] feat(metrics): number of open merge requests (#37) * refactor: change classification of metrics * refactor: create method loadItsMergeRequest * feat: add method averageNumberOfOpenMergeRequest * feat: add averageNumberOfOpenMergeRequest in AnalysisReport * feat: add averageNumberOfOpenMergeRequest in csv export * refactor: rename averageNumberOfOpenMergeRequest method --- .../AnalysisReport.class.st | 15 +- .../GitMetric.class.st | 5 +- .../GitMetric4User.class.st | 153 ++++++++++++------ .../GitMetricExporter.class.st | 17 +- 4 files changed, 135 insertions(+), 55 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st b/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st index 987a2bb..3dc89dd 100644 --- a/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st +++ b/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st @@ -13,7 +13,8 @@ Class { 'codeChurn', 'delayUntilFirstChurn', 'numberOfProjectWithCommit', - 'averageTimeBetweenCommits' + 'averageTimeBetweenCommits', + 'averageNumberOfOpenMergeRequest' ], #category : #'GitLabHealth-Model-Analysis' } @@ -23,6 +24,18 @@ AnalysisReport class >> isVoyageRoot [ ^true ] +{ #category : #accessing } +AnalysisReport >> averageNumberOfOpenMergeRequest [ + + ^ averageNumberOfOpenMergeRequest +] + +{ #category : #accessing } +AnalysisReport >> averageNumberOfOpenMergeRequest: anObject [ + + averageNumberOfOpenMergeRequest := anObject +] + { #category : #accessing } AnalysisReport >> averageTimeBetweenCommits [ diff --git a/src/GitLabHealth-Model-Analysis/GitMetric.class.st b/src/GitLabHealth-Model-Analysis/GitMetric.class.st index 4b48b45..ac30ac5 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetric.class.st @@ -122,7 +122,10 @@ GitMetric >> loadMergeRequestsFromProjectsIds: aCollection since: since until: u | allMr period | "itsMergeRequests ifNil: [ itsMergeRequests := Dictionary new ]." - period := self cacheSymbolFor: GLPHEMergeRequest since: since until: until. + period := self + cacheSymbolFor: GLPHEMergeRequest + since: since + until: until. allMr := aCollection collect: [ :idProject | | project mr | diff --git a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st index 0688590..550d307 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st @@ -8,7 +8,7 @@ Class { #category : #'GitLabHealth-Model-Analysis' } -{ #category : #metrics } +{ #category : #'metrics - commits' } GitMetric4User >> averageTimeBetweenCommitSince: since until: until overA: aDateWeekMonthOrYear [ | commits commitSortedByDate commits1 commits2 differences groupedByDate dateOver average | @@ -155,7 +155,7 @@ GitMetric4User >> codeChurnSince: since until: until onACommitWindowOf: commitLi (#churnWindow -> commitLimit) } asDictionary ] -{ #category : #metrics } +{ #category : #'metrics - commits' } GitMetric4User >> codeContributionsSince: since until: until overA: aDateWeekMonthOrYear [ | commits contributions groupedByDate | @@ -218,7 +218,7 @@ GitMetric4User >> codeContributionsSince: since until: until overA: aDateWeekMon (#userCommits -> commits size) } asDictionary ] -{ #category : #metrics } +{ #category : #'metrics - commits' } GitMetric4User >> commentsContributionsSince: since until: until overA: aDateWeekMonthOrYear [ | commits contributions groupedByDate | @@ -278,7 +278,7 @@ GitMetric4User >> commentsContributionsSince: since until: until overA: aDateWee (#userCommits -> commits size) } asDictionary ] -{ #category : #metrics } +{ #category : #'metrics - commits' } GitMetric4User >> commitFrequencySince: since until: until overA: aDateWeekMonthOrYear [ | periods total groupedByDate userCommits | @@ -318,7 +318,7 @@ GitMetric4User >> commitFrequencySince: since until: until overA: aDateWeekMonth (#details -> groupedByDate) } asOrderedDictionary ] -{ #category : #metrics } +{ #category : #'metrics - commits' } GitMetric4User >> commitsProducedOnProject: projectId since: sinceDate until: untilDate [ | frequencies | @@ -348,7 +348,7 @@ GitMetric4User >> commitsProducedOnProject: projectId since: sinceDate until: un ^ frequencies ] -{ #category : #metrics } +{ #category : #'metrics - commits' } GitMetric4User >> commitsProducedOnProject: aProjectId since: since until: until overA: aWeekOrMonthOrYear [ "'aWeekOrMonthOrYear' should be the class of Data, Week, Month or Year" @@ -571,53 +571,60 @@ GitMetric4User >> foundSuccessorOf: userCommits andCompleteImportForMax: commitL { #category : #analysis } GitMetric4User >> generateAnalysisForPeriod: period over: aDateWeekMonthOrYear withMaxCommitWindows: maxCommitWindow [ - | contribution commitFrequency commentContribution mergeRequestDuration codeChurn delayUntilFirstChurn averageTimeBetweenCommits numberOfProjectWithCommit | + | contribution commitFrequency commentContribution mergeRequestDuration codeChurn delayUntilFirstChurn averageTimeBetweenCommits numberOfProjectWithCommit until since numberOfOpenMergeRequest | + since := period at: #since. + until := period at: #until. + + "COMMITS" contribution := self - codeContributionsSince: (period at: #since) - until: (period at: #until) + codeContributionsSince: since + until: until overA: aDateWeekMonthOrYear. commitFrequency := self - commitFrequencySince: (period at: #since) - until: (period at: #until) + commitFrequencySince: since + until: until overA: aDateWeekMonthOrYear. commentContribution := self - commentsContributionsSince: - (period at: #since) - until: (period at: #until) + commentsContributionsSince: since + until: until overA: aDateWeekMonthOrYear. - mergeRequestDuration := self - mergeRequestDurationSince: - (period at: #since) - until: (period at: #until) - overA: aDateWeekMonthOrYear. - codeChurn := self - codeChurnSince: (period at: #since) - until: (period at: #until) + codeChurnSince: since + until: until onACommitWindowOf: maxCommitWindow overA: aDateWeekMonthOrYear. delayUntilFirstChurn := self - delayUntilFirstChurnSince: - (period at: #since) - until: (period at: #until) + delayUntilFirstChurnSince: since + until: until onACommitWindowOf: maxCommitWindow overA: aDateWeekMonthOrYear. numberOfProjectWithCommit := self - numberOfProjectWithCommitSince: - (period at: #since) - until: (period at: #until) + numberOfProjectWithCommitSince: since + until: until overA: aDateWeekMonthOrYear. averageTimeBetweenCommits := self - averageTimeBetweenCommitSince: - (period at: #since) - until: (period at: #until) + averageTimeBetweenCommitSince: since + until: until overA: aDateWeekMonthOrYear. + "MERGE REQUESTS" + + mergeRequestDuration := self + mergeRequestDurationSince: since + until: until + overA: aDateWeekMonthOrYear. + + numberOfOpenMergeRequest := self + numberOfOpenMergeRequestSince: + since + until: until + overA: aDateWeekMonthOrYear. + ^ AnalysisReport new username: self user name; period: period; @@ -632,7 +639,9 @@ GitMetric4User >> generateAnalysisForPeriod: period over: aDateWeekMonthOrYear w numberOfProjectWithCommit: (numberOfProjectWithCommit at: #average); averageTimeBetweenCommits: - (averageTimeBetweenCommits at: #average) + (averageTimeBetweenCommits at: #average); + averageNumberOfOpenMergeRequest: + (numberOfOpenMergeRequest at: #average) ] { #category : #initialization } @@ -666,7 +675,30 @@ GitMetric4User >> loadCommitOfProjects: aCollection since: aTimespan [ ^ self userCommits. ] -{ #category : #metrics } +{ #category : #loading } +GitMetric4User >> loadItsMergeRequestsSince: since until: until [ + + | mergeRequests | + gitAnalyzer := GitAnalyzer new + glhImporter: glhImporter; + onModel: glhModel. + + glhImporter withCommitDiffs: false. + mergeRequests := self + loadMergeRequestsFromProjectsIds: itsProjects keys + since: since + until: until. + glhImporter withCommitDiffs: true. + + mergeRequests do: [ :mr | glhImporter importMergeResquestAuthor: mr ]. + + itsMergeRequests := mergeRequests select: [ :mergeRequest | + mergeRequest author = self user ]. + + ^ itsMergeRequests +] + +{ #category : #'metrics - merge request' } GitMetric4User >> mergeRequestDurationSince: since until: until overA: aDateWeekMonthOrYear [ | mergeRequest res groupedByDate filterGroups avg | @@ -675,16 +707,7 @@ GitMetric4User >> mergeRequestDurationSince: since until: until overA: aDateWeek to: until over: aDateWeekMonthOrYear. - gitAnalyzer := GitAnalyzer new - glhImporter: glhImporter; - onModel: glhModel. - - glhImporter withCommitDiffs: false. - mergeRequest := self - loadMergeRequestsFromProjectsIds: itsProjects keys - since: since - until: until. - glhImporter withCommitDiffs: true. + mergeRequest := self loadItsMergeRequestsSince: since until: until. mergeRequest ifEmpty: [ ^ { @@ -728,9 +751,8 @@ GitMetric4User >> mergeRequestDurationSince: since until: until overA: aDateWeek filterGroups at: assoc key put: sum / denominator ]. - + avg := 0. filterGroups keys - ifEmpty: [ avg := 0 ] ifNotEmpty: [ avg := filterGroups values sum / filterGroups keys size ]. @@ -744,7 +766,46 @@ GitMetric4User >> mergeRequestDurationSince: since until: until overA: aDateWeek (#details -> groupedByDate) } asDictionary ] -{ #category : #metrics } +{ #category : #'metrics - merge request' } +GitMetric4User >> numberOfOpenMergeRequestSince: since until: until overA: aDateWeekMonthOrYear [ + + | groupedByDate userMergeRequests dateOver average | + groupedByDate := self + setupGroupedDateFrom: since + to: until + over: aDateWeekMonthOrYear. + + userMergeRequests := self + loadItsMergeRequestsSince: since + until: until. + + userMergeRequests do: [ :userMergeRequest | + dateOver := self + transformDate: userMergeRequest created_at + to: aDateWeekMonthOrYear. + + groupedByDate + at: dateOver printString + ifPresent: [ :value | value add: userMergeRequest ] ]. + + + groupedByDate := groupedByDate collect: [ :group | group size ]. + + + average := groupedByDate + ifEmpty: [ 0 ] + ifNotEmpty: [ groupedByDate average ]. + + ^ { + (#overEach -> aDateWeekMonthOrYear name). + (#forOver -> (groupedByDate keys size printString + , aDateWeekMonthOrYear printString)). + (#average -> average asFloat). + (#details -> groupedByDate). + (#userMergeRequests -> userMergeRequests size) } asDictionary +] + +{ #category : #'metrics - commits' } GitMetric4User >> numberOfProjectWithCommitSince: since until: until overA: aDateWeekMonthOrYear [ | groupedByDate commits userCommits dateOver projects | groupedByDate := self diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 02faa13..178255b 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -201,18 +201,21 @@ GitMetricExporter >> exportInCSV [ withName: 'delay Until First Churn (W=' , maxCommitWindow printString , ') ' asSymbol. - + "number of project with minimum one commit of user" exportBrowserModel addColumnForQuery: [ :analysis | analysis numberOfProjectWithCommit ] - withName: - 'number of project with min 1 commit of user' asSymbol. - + withName: 'number of project with min 1 commit of user' asSymbol. + "average time between commits" exportBrowserModel - addColumnForQuery: [ :analysis | analysis averageTimeBetweenCommits ] - withName: - 'average time between commits' asSymbol. + addColumnForQuery: [ :analysis | analysis averageTimeBetweenCommits ] + withName: 'average time between commits' asSymbol. + + "average number of open merge request" + exportBrowserModel + addColumnForQuery: [ :analysis | analysis averageNumberOfOpenMergeRequest ] + withName: 'average number of open merge request' asSymbol. file := self constructFilePath: over. file writeStreamDo: [ :aStream | From f97a00db1993b9dcfa8ba23ca0dc91da5ac035d7 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Tue, 20 Aug 2024 13:55:30 +0200 Subject: [PATCH 033/154] feat(metrics): number of merged merge requests (#38) * feat: add numberOfMergedMergeRequestSince:until:overA method * feat: add numberOfMergedMergeRequest in analysis report and in csv export --- .../AnalysisReport.class.st | 15 +++++- .../GitMetric4User.class.st | 52 ++++++++++++++++--- .../GitMetricExporter.class.st | 12 ++++- 3 files changed, 70 insertions(+), 9 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st b/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st index 3dc89dd..6125723 100644 --- a/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st +++ b/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st @@ -14,7 +14,8 @@ Class { 'delayUntilFirstChurn', 'numberOfProjectWithCommit', 'averageTimeBetweenCommits', - 'averageNumberOfOpenMergeRequest' + 'averageNumberOfOpenMergeRequest', + 'averageNumberOfMergedMergeRequest' ], #category : #'GitLabHealth-Model-Analysis' } @@ -24,6 +25,18 @@ AnalysisReport class >> isVoyageRoot [ ^true ] +{ #category : #accessing } +AnalysisReport >> averageNumberOfMergedMergeRequest [ + + ^ averageNumberOfMergedMergeRequest +] + +{ #category : #accessing } +AnalysisReport >> averageNumberOfMergedMergeRequest: anObject [ + + averageNumberOfMergedMergeRequest := anObject +] + { #category : #accessing } AnalysisReport >> averageNumberOfOpenMergeRequest [ diff --git a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st index 550d307..e4d2413 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st @@ -571,7 +571,7 @@ GitMetric4User >> foundSuccessorOf: userCommits andCompleteImportForMax: commitL { #category : #analysis } GitMetric4User >> generateAnalysisForPeriod: period over: aDateWeekMonthOrYear withMaxCommitWindows: maxCommitWindow [ - | contribution commitFrequency commentContribution mergeRequestDuration codeChurn delayUntilFirstChurn averageTimeBetweenCommits numberOfProjectWithCommit until since numberOfOpenMergeRequest | + | contribution commitFrequency commentContribution mergeRequestDuration codeChurn delayUntilFirstChurn averageTimeBetweenCommits numberOfProjectWithCommit until since numberOfOpenMergeRequest numberOfMergedMergeRequest | since := period at: #since. until := period at: #until. @@ -620,10 +620,14 @@ GitMetric4User >> generateAnalysisForPeriod: period over: aDateWeekMonthOrYear w overA: aDateWeekMonthOrYear. numberOfOpenMergeRequest := self - numberOfOpenMergeRequestSince: - since - until: until - overA: aDateWeekMonthOrYear. + numberOfOpenMergeRequestSince: since + until: until + overA: aDateWeekMonthOrYear. + + numberOfMergedMergeRequest := self + numberOfMergedMergeRequestSince: since + until: until + overA: aDateWeekMonthOrYear. ^ AnalysisReport new username: self user name; @@ -641,7 +645,9 @@ GitMetric4User >> generateAnalysisForPeriod: period over: aDateWeekMonthOrYear w averageTimeBetweenCommits: (averageTimeBetweenCommits at: #average); averageNumberOfOpenMergeRequest: - (numberOfOpenMergeRequest at: #average) + (numberOfOpenMergeRequest at: #average); + averageNumberOfMergedMergeRequest: + (numberOfMergedMergeRequest at: #average) ] { #category : #initialization } @@ -766,6 +772,40 @@ GitMetric4User >> mergeRequestDurationSince: since until: until overA: aDateWeek (#details -> groupedByDate) } asDictionary ] +{ #category : #'metrics - merge request' } +GitMetric4User >> numberOfMergedMergeRequestSince: since until: until overA: aDateWeekMonthOrYear [ + + | groupedByDate userMergeRequests dateOver average userMergedMergeRequests | + groupedByDate := self + setupGroupedDateFrom: since + to: until + over: aDateWeekMonthOrYear. + userMergeRequests := self + loadItsMergeRequestsSince: since + until: until. + userMergedMergeRequests := userMergeRequests select: [ + :userMergeRequest | + userMergeRequest merged_at isNotNil ]. + userMergedMergeRequests do: [ :userMergeRequest | + dateOver := self + transformDate: userMergeRequest created_at + to: aDateWeekMonthOrYear. + groupedByDate + at: dateOver printString + ifPresent: [ :value | value add: userMergeRequest ] ]. + groupedByDate := groupedByDate collect: [ :group | group size ]. + average := groupedByDate + ifEmpty: [ 0 ] + ifNotEmpty: [ groupedByDate average ]. + ^ { + (#overEach -> aDateWeekMonthOrYear name). + (#forOver -> (groupedByDate keys size printString + , aDateWeekMonthOrYear printString)). + (#average -> average asFloat). + (#details -> groupedByDate). + (#userMergeRequests -> userMergeRequests size) } asDictionary +] + { #category : #'metrics - merge request' } GitMetric4User >> numberOfOpenMergeRequestSince: since until: until overA: aDateWeekMonthOrYear [ diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 178255b..8274d62 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -211,11 +211,19 @@ GitMetricExporter >> exportInCSV [ exportBrowserModel addColumnForQuery: [ :analysis | analysis averageTimeBetweenCommits ] withName: 'average time between commits' asSymbol. - + "average number of open merge request" exportBrowserModel - addColumnForQuery: [ :analysis | analysis averageNumberOfOpenMergeRequest ] + addColumnForQuery: [ :analysis | + analysis averageNumberOfOpenMergeRequest ] withName: 'average number of open merge request' asSymbol. + + + "average number of merged merge request" + exportBrowserModel + addColumnForQuery: [ :analysis | + analysis averageNumberOfMergedMergeRequest ] + withName: 'average number of merged merge request' asSymbol. file := self constructFilePath: over. file writeStreamDo: [ :aStream | From 8794542c7afb088bc082a751ba26664931176b04 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Tue, 20 Aug 2024 15:14:58 +0200 Subject: [PATCH 034/154] feat(metrics): number of closed merge requests (#39) * feat: add closedMergeRequestsSince:until:overA method * feat: add averageClosedMergeRequests in analysisReport and csv export * refactor: rename merge request metrics method * refactor: rename merge request metrics variables * refactor: put back numberOf prefix in merge request metrics method name --- .../AnalysisReport.class.st | 65 +++++++++------ .../GitMetric4User.class.st | 83 +++++++++++++++---- .../GitMetricExporter.class.st | 34 ++++---- 3 files changed, 126 insertions(+), 56 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st b/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st index 6125723..8f6a2f6 100644 --- a/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st +++ b/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st @@ -14,8 +14,9 @@ Class { 'delayUntilFirstChurn', 'numberOfProjectWithCommit', 'averageTimeBetweenCommits', - 'averageNumberOfOpenMergeRequest', - 'averageNumberOfMergedMergeRequest' + 'numberOfOpenMergeRequests', + 'numberOfMergedMergeRequest', + 'numberOfClosedMergeRequests' ], #category : #'GitLabHealth-Model-Analysis' } @@ -25,30 +26,6 @@ AnalysisReport class >> isVoyageRoot [ ^true ] -{ #category : #accessing } -AnalysisReport >> averageNumberOfMergedMergeRequest [ - - ^ averageNumberOfMergedMergeRequest -] - -{ #category : #accessing } -AnalysisReport >> averageNumberOfMergedMergeRequest: anObject [ - - averageNumberOfMergedMergeRequest := anObject -] - -{ #category : #accessing } -AnalysisReport >> averageNumberOfOpenMergeRequest [ - - ^ averageNumberOfOpenMergeRequest -] - -{ #category : #accessing } -AnalysisReport >> averageNumberOfOpenMergeRequest: anObject [ - - averageNumberOfOpenMergeRequest := anObject -] - { #category : #accessing } AnalysisReport >> averageTimeBetweenCommits [ @@ -145,6 +122,42 @@ AnalysisReport >> mergeRequestDuration: anObject [ mergeRequestDuration := anObject ] +{ #category : #accessing } +AnalysisReport >> numberOfClosedMergeRequests [ + + ^ numberOfClosedMergeRequests +] + +{ #category : #accessing } +AnalysisReport >> numberOfClosedMergeRequests: anObject [ + + numberOfClosedMergeRequests := anObject +] + +{ #category : #accessing } +AnalysisReport >> numberOfMergedMergeRequest [ + + ^ numberOfMergedMergeRequest +] + +{ #category : #accessing } +AnalysisReport >> numberOfMergedMergeRequest: anObject [ + + numberOfMergedMergeRequest := anObject +] + +{ #category : #accessing } +AnalysisReport >> numberOfOpenMergeRequests [ + + ^ numberOfOpenMergeRequests +] + +{ #category : #accessing } +AnalysisReport >> numberOfOpenMergeRequests: anObject [ + + numberOfOpenMergeRequests := anObject +] + { #category : #accessing } AnalysisReport >> numberOfProjectWithCommit [ diff --git a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st index e4d2413..cb20def 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st @@ -571,7 +571,7 @@ GitMetric4User >> foundSuccessorOf: userCommits andCompleteImportForMax: commitL { #category : #analysis } GitMetric4User >> generateAnalysisForPeriod: period over: aDateWeekMonthOrYear withMaxCommitWindows: maxCommitWindow [ - | contribution commitFrequency commentContribution mergeRequestDuration codeChurn delayUntilFirstChurn averageTimeBetweenCommits numberOfProjectWithCommit until since numberOfOpenMergeRequest numberOfMergedMergeRequest | + | contribution commitFrequency commentContribution mergeRequestDuration codeChurn delayUntilFirstChurn averageTimeBetweenCommits numberOfProjectWithCommit until since numberOfOpenMergeRequests numberOfMergedMergeRequests numberOfClosedMergeRequests | since := period at: #since. until := period at: #until. @@ -619,15 +619,22 @@ GitMetric4User >> generateAnalysisForPeriod: period over: aDateWeekMonthOrYear w until: until overA: aDateWeekMonthOrYear. - numberOfOpenMergeRequest := self - numberOfOpenMergeRequestSince: since - until: until - overA: aDateWeekMonthOrYear. + numberOfOpenMergeRequests := self + numberOfOpenMergeRequestsSince: since + until: until + overA: aDateWeekMonthOrYear. + + numberOfMergedMergeRequests := self + numberOfMergedMergeRequestsSince: + since + until: until + overA: aDateWeekMonthOrYear. - numberOfMergedMergeRequest := self - numberOfMergedMergeRequestSince: since - until: until - overA: aDateWeekMonthOrYear. + numberOfClosedMergeRequests := self + numberOfClosedMergeRequestSince: + since + until: until + overA: aDateWeekMonthOrYear. ^ AnalysisReport new username: self user name; @@ -644,10 +651,9 @@ GitMetric4User >> generateAnalysisForPeriod: period over: aDateWeekMonthOrYear w (numberOfProjectWithCommit at: #average); averageTimeBetweenCommits: (averageTimeBetweenCommits at: #average); - averageNumberOfOpenMergeRequest: - (numberOfOpenMergeRequest at: #average); - averageNumberOfMergedMergeRequest: - (numberOfMergedMergeRequest at: #average) + numberOfOpenMergeRequests: (numberOfOpenMergeRequests at: #average); + numberOfMergedMergeRequest: (numberOfMergedMergeRequests at: #average); + numberOfClosedMergeRequests: (numberOfClosedMergeRequests at: #average) ] { #category : #initialization } @@ -773,7 +779,51 @@ GitMetric4User >> mergeRequestDurationSince: since until: until overA: aDateWeek ] { #category : #'metrics - merge request' } -GitMetric4User >> numberOfMergedMergeRequestSince: since until: until overA: aDateWeekMonthOrYear [ +GitMetric4User >> numberOfClosedMergeRequestSince: since until: until overA: aDateWeekMonthOrYear [ + + | groupedByDate userMergeRequests dateOver average userClosedMergeRequests | + groupedByDate := self + setupGroupedDateFrom: since + to: until + over: aDateWeekMonthOrYear. + + userMergeRequests := self + loadItsMergeRequestsSince: since + until: until. + + userClosedMergeRequests := userMergeRequests select: [ + :userMergeRequest | + userMergeRequest merged_at isNil and: + userMergeRequest state = 'closed' ]. + + userClosedMergeRequests do: [ :userMergeRequest | + dateOver := self + transformDate: userMergeRequest created_at + to: aDateWeekMonthOrYear. + + groupedByDate + at: dateOver printString + ifPresent: [ :value | value add: userMergeRequest ] ]. + + + groupedByDate := groupedByDate collect: [ :group | group size ]. + + + average := groupedByDate + ifEmpty: [ 0 ] + ifNotEmpty: [ groupedByDate average ]. + + ^ { + (#overEach -> aDateWeekMonthOrYear name). + (#forOver -> (groupedByDate keys size printString + , aDateWeekMonthOrYear printString)). + (#average -> average asFloat). + (#details -> groupedByDate). + (#userMergeRequests -> userMergeRequests size) } asDictionary +] + +{ #category : #'metrics - merge request' } +GitMetric4User >> numberOfMergedMergeRequestsSince: since until: until overA: aDateWeekMonthOrYear [ | groupedByDate userMergeRequests dateOver average userMergedMergeRequests | groupedByDate := self @@ -783,9 +833,11 @@ GitMetric4User >> numberOfMergedMergeRequestSince: since until: until overA: aDa userMergeRequests := self loadItsMergeRequestsSince: since until: until. + userMergedMergeRequests := userMergeRequests select: [ :userMergeRequest | userMergeRequest merged_at isNotNil ]. + userMergedMergeRequests do: [ :userMergeRequest | dateOver := self transformDate: userMergeRequest created_at @@ -794,6 +846,7 @@ GitMetric4User >> numberOfMergedMergeRequestSince: since until: until overA: aDa at: dateOver printString ifPresent: [ :value | value add: userMergeRequest ] ]. groupedByDate := groupedByDate collect: [ :group | group size ]. + average := groupedByDate ifEmpty: [ 0 ] ifNotEmpty: [ groupedByDate average ]. @@ -807,7 +860,7 @@ GitMetric4User >> numberOfMergedMergeRequestSince: since until: until overA: aDa ] { #category : #'metrics - merge request' } -GitMetric4User >> numberOfOpenMergeRequestSince: since until: until overA: aDateWeekMonthOrYear [ +GitMetric4User >> numberOfOpenMergeRequestsSince: since until: until overA: aDateWeekMonthOrYear [ | groupedByDate userMergeRequests dateOver average | groupedByDate := self diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 8274d62..af7b0ec 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -184,11 +184,6 @@ GitMetricExporter >> exportInCSV [ addColumnForQuery: [ :analysis | analysis commentContribution ] withName: 'comment contribution (avg)' asSymbol. - "merge Request Duration " - exportBrowserModel - addColumnForQuery: [ :analysis | analysis mergeRequestDuration ] - withName: 'merge Request Duration ' asSymbol. - "code churn" exportBrowserModel addColumnForQuery: [ :analysis | analysis codeChurn ] @@ -207,23 +202,32 @@ GitMetricExporter >> exportInCSV [ addColumnForQuery: [ :analysis | analysis numberOfProjectWithCommit ] withName: 'number of project with min 1 commit of user' asSymbol. + "merge Request Duration " + exportBrowserModel + addColumnForQuery: [ :analysis | analysis mergeRequestDuration ] + withName: 'merge Request Duration ' asSymbol. + "average time between commits" exportBrowserModel addColumnForQuery: [ :analysis | analysis averageTimeBetweenCommits ] withName: 'average time between commits' asSymbol. - "average number of open merge request" + "number of open merge request" exportBrowserModel - addColumnForQuery: [ :analysis | - analysis averageNumberOfOpenMergeRequest ] - withName: 'average number of open merge request' asSymbol. - - - "average number of merged merge request" + addColumnForQuery: [ :analysis | analysis numberOfOpenMergeRequests ] + withName: 'number of open merge request' asSymbol. + + + "number of merged merge request" + exportBrowserModel + addColumnForQuery: [ :analysis | analysis numberOfMergedMergeRequest ] + withName: 'number of merged merge request' asSymbol. + + "number of merge requests closed and not merged" exportBrowserModel - addColumnForQuery: [ :analysis | - analysis averageNumberOfMergedMergeRequest ] - withName: 'average number of merged merge request' asSymbol. + addColumnForQuery: [ :analysis | analysis numberOfClosedMergeRequests ] + withName: 'number of merge requests closed and not merged' asSymbol. + file := self constructFilePath: over. file writeStreamDo: [ :aStream | From efff1d503d5c9bdf2cc9cee7ae6cd8ba9af525b8 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Tue, 20 Aug 2024 16:20:35 +0200 Subject: [PATCH 035/154] feat: add number of merge request without review in analysisReport and csv export --- .../AnalysisReport.class.st | 15 +++- .../GitMetric4User.class.st | 78 ++++++++++++++++++- .../GitMetricExporter.class.st | 15 +++- 3 files changed, 100 insertions(+), 8 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st b/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st index 8f6a2f6..cf7b3fc 100644 --- a/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st +++ b/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st @@ -16,7 +16,8 @@ Class { 'averageTimeBetweenCommits', 'numberOfOpenMergeRequests', 'numberOfMergedMergeRequest', - 'numberOfClosedMergeRequests' + 'numberOfClosedMergeRequests', + 'numberOfMergeRequestsWithoutReview' ], #category : #'GitLabHealth-Model-Analysis' } @@ -134,6 +135,18 @@ AnalysisReport >> numberOfClosedMergeRequests: anObject [ numberOfClosedMergeRequests := anObject ] +{ #category : #accessing } +AnalysisReport >> numberOfMergeRequestsWithoutReview [ + + ^ numberOfMergeRequestsWithoutReview +] + +{ #category : #accessing } +AnalysisReport >> numberOfMergeRequestsWithoutReview: anObject [ + + numberOfMergeRequestsWithoutReview := anObject +] + { #category : #accessing } AnalysisReport >> numberOfMergedMergeRequest [ diff --git a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st index cb20def..de01d63 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st @@ -571,7 +571,7 @@ GitMetric4User >> foundSuccessorOf: userCommits andCompleteImportForMax: commitL { #category : #analysis } GitMetric4User >> generateAnalysisForPeriod: period over: aDateWeekMonthOrYear withMaxCommitWindows: maxCommitWindow [ - | contribution commitFrequency commentContribution mergeRequestDuration codeChurn delayUntilFirstChurn averageTimeBetweenCommits numberOfProjectWithCommit until since numberOfOpenMergeRequests numberOfMergedMergeRequests numberOfClosedMergeRequests | + | contribution commitFrequency commentContribution mergeRequestDuration codeChurn delayUntilFirstChurn averageTimeBetweenCommits numberOfProjectWithCommit until since numberOfOpenMergeRequests numberOfMergedMergeRequests numberOfClosedMergeRequests numberOfMergeRequestWithoutReview | since := period at: #since. until := period at: #until. @@ -636,6 +636,12 @@ GitMetric4User >> generateAnalysisForPeriod: period over: aDateWeekMonthOrYear w until: until overA: aDateWeekMonthOrYear. + numberOfMergeRequestWithoutReview := self + numberOfMergeRequestsMergedWithoutReviewSince: + since + until: until + overA: aDateWeekMonthOrYear. + ^ AnalysisReport new username: self user name; period: period; @@ -651,9 +657,13 @@ GitMetric4User >> generateAnalysisForPeriod: period over: aDateWeekMonthOrYear w (numberOfProjectWithCommit at: #average); averageTimeBetweenCommits: (averageTimeBetweenCommits at: #average); - numberOfOpenMergeRequests: (numberOfOpenMergeRequests at: #average); - numberOfMergedMergeRequest: (numberOfMergedMergeRequests at: #average); - numberOfClosedMergeRequests: (numberOfClosedMergeRequests at: #average) + numberOfOpenMergeRequests: + (numberOfOpenMergeRequests at: #average); + numberOfMergedMergeRequest: + (numberOfMergedMergeRequests at: #average); + numberOfClosedMergeRequests: + (numberOfClosedMergeRequests at: #average); + numberOfMergeRequestsWithoutReview: (numberOfMergeRequestWithoutReview at: #average). ] { #category : #initialization } @@ -822,6 +832,66 @@ GitMetric4User >> numberOfClosedMergeRequestSince: since until: until overA: aDa (#userMergeRequests -> userMergeRequests size) } asDictionary ] +{ #category : #'metrics - merge request' } +GitMetric4User >> numberOfMergeRequestsMergedWithoutReviewSince: since until: until overA: aDateWeekMonthOrYear [ + + | groupedByDate userMergeRequests dateOver average noVerificationMergeRequests mergedMergeRequest | + groupedByDate := self + setupGroupedDateFrom: since + to: until + over: aDateWeekMonthOrYear. + + userMergeRequests := self + loadItsMergeRequestsSince: since + until: until. + + mergedMergeRequest := userMergeRequests select: [ :mr | + mr merged_at isNotNil ]. + + + noVerificationMergeRequests := mergedMergeRequest select: [ + :userMergeRequest | + | validation | + glhImporter + importMergeResquestMerger: + userMergeRequest. + + validation := gitAnalyzer + analyseMergeResquestValidation: + userMergeRequest. + + userMergeRequest merge_user + = userMergeRequest author and: + (validation at: #duration) + < 1 minutes ]. + + + noVerificationMergeRequests do: [ :userMergeRequest | + dateOver := self + transformDate: userMergeRequest created_at + to: aDateWeekMonthOrYear. + + groupedByDate + at: dateOver printString + ifPresent: [ :value | value add: userMergeRequest ] ]. + + + groupedByDate := groupedByDate collect: [ :group | group size ]. + + + average := groupedByDate + ifEmpty: [ 0 ] + ifNotEmpty: [ groupedByDate average ]. + + ^ { + (#overEach -> aDateWeekMonthOrYear name). + (#forOver -> (groupedByDate keys size printString + , aDateWeekMonthOrYear printString)). + (#average -> average asFloat). + (#details -> groupedByDate). + (#userMergeRequests -> userMergeRequests size) } asDictionary +] + { #category : #'metrics - merge request' } GitMetric4User >> numberOfMergedMergeRequestsSince: since until: until overA: aDateWeekMonthOrYear [ diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index af7b0ec..8fd5ca0 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -214,21 +214,30 @@ GitMetricExporter >> exportInCSV [ "number of open merge request" exportBrowserModel - addColumnForQuery: [ :analysis | analysis numberOfOpenMergeRequests ] + addColumnForQuery: [ :analysis | analysis numberOfOpenMergeRequests ] withName: 'number of open merge request' asSymbol. "number of merged merge request" exportBrowserModel - addColumnForQuery: [ :analysis | analysis numberOfMergedMergeRequest ] + addColumnForQuery: [ :analysis | + analysis numberOfMergedMergeRequest ] withName: 'number of merged merge request' asSymbol. "number of merge requests closed and not merged" exportBrowserModel - addColumnForQuery: [ :analysis | analysis numberOfClosedMergeRequests ] + addColumnForQuery: [ :analysis | + analysis numberOfClosedMergeRequests ] withName: 'number of merge requests closed and not merged' asSymbol. + "number of merge requests withour review" + exportBrowserModel + addColumnForQuery: [ :analysis | + analysis numberOfMergeRequestsWithoutReview ] + withName: 'number of merge requests without review' asSymbol. + + file := self constructFilePath: over. file writeStreamDo: [ :aStream | aStream From 89fea77ad874ef825b023295746b4ff493dc374c Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Wed, 21 Aug 2024 12:25:13 +0200 Subject: [PATCH 036/154] feat: add importAnalyses from s3 method --- .../GitMetricExporter.class.st | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 24d9c13..7d2aa81 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -359,6 +359,30 @@ GitMetricExporter >> glhImporter: anImporter [ glhImporter := anImporter withInitialCommits: false; yourself. ] +{ #category : #adding } +GitMetricExporter >> importAnalysesFromS3: bucketName accessKey: accessKey secretKey: secretKey region: region [ + + | s3 bucket xmlObjects contentElements filesContent | + AWSS3Config default + accessKeyId: accessKey; + secretKey: secretKey; + regionName: region. + + s3 := AWSS3 new. + bucket := s3 bucketNamed: bucketName. + xmlObjects := bucket listObjects. + contentElements := xmlObjects root elementsSelect: [ :element | + element isNamed: 'Contents' ]. + + filesContent := contentElements collect: [ :contentElement | + | keyValue | + keyValue := contentElement contentStringAt: 'Key'. + bucket getObject: keyValue ]. + + ^ analyses := (filesContent collect: [ :file | STON fromString: file ]) + flattened +] + { #category : #initialization } GitMetricExporter >> initialize [ From 0091990ab9db1a05299ae6d9d7f293aad7475adc Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Wed, 21 Aug 2024 13:14:27 +0200 Subject: [PATCH 037/154] doc: change install script in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0c8c57c..388c7af 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ In the Moose image, in a playground (`Ctrl+O`, `Ctrl+W`), perform: Metacello new repository: 'github://moosetechnology/GitProjectHealth:main/src'; baseline: 'GitLabHealth'; - onConflict: [ :ex | ex useIncoming ]; + onConflict: [ :ex | ex useLoaded ]; onUpgrade: [ :ex | ex useIncoming ]; onDowngrade: [ :ex | ex useLoaded ]; load From 48010cb6d8344e07901c5149967637695c9552c0 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Thu, 22 Aug 2024 10:43:14 +0200 Subject: [PATCH 038/154] refactor: change format of csv to put date in column name --- .../GitMetricExporter.class.st | 47 ++++++++----------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 7d2aa81..a18b918 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -140,10 +140,14 @@ GitMetricExporter >> exportFor: usersWithProjects over: aCollectionOfDateWeekMon { #category : #exporting } GitMetricExporter >> exportInCSV [ - | exportBrowserModel file | + | exportBrowserModel file period analysesDate | exportBrowserModel := MiExportModel new. self analyses ifNil: [ self generateAnalyses ]. + + period := runningPeriods at: 1. + analysesDate := (period at: #since) asString. + exportBrowserModel entitiesList: self analyses. exportBrowserModel removeColumnForQueryNamed: #Type. @@ -153,89 +157,78 @@ GitMetricExporter >> exportInCSV [ addColumnForQuery: [ :analysis | analysis username ] withName: #'User name'. - exportBrowserModel - addColumnForQuery: [ :analysis | analysis period at: #since ] - withName: #Since. - - exportBrowserModel - addColumnForQuery: [ :analysis | analysis period at: #until ] - withName: #Until. - - exportBrowserModel - addColumnForQuery: [ :analysis | analysis over ] - withName: #Over. - "Code Contribution " exportBrowserModel addColumnForQuery: [ :analysis | analysis codeAddition ] - withName: 'code addition (avg)' asSymbol. + withName: 'code addition (avg)' , ' - ', analysesDate. exportBrowserModel addColumnForQuery: [ :analysis | analysis codeDeletion ] - withName: 'code deletion (avg)' asSymbol. + withName: 'code deletion (avg)' , ' - ', analysesDate. "Commit frequencies " exportBrowserModel addColumnForQuery: [ :analysis | analysis commitFrequency ] - withName: 'commits frequency (avg) ' asSymbol. + withName: 'commits frequency (avg)',' - ', analysesDate. "comment contribution " exportBrowserModel addColumnForQuery: [ :analysis | analysis commentContribution ] - withName: 'comment contribution (avg)' asSymbol. + withName: 'comment contribution (avg)', ' - ', analysesDate. "code churn" exportBrowserModel addColumnForQuery: [ :analysis | analysis codeChurn ] withName: - 'churn % (W=' , maxCommitWindow printString , ') ' asSymbol. + 'churn % (W=' , maxCommitWindow printString , ') ' , ' - ', analysesDate. "delay Until First Churn" exportBrowserModel addColumnForQuery: [ :analysis | analysis delayUntilFirstChurn ] withName: - 'delay Until First Churn (W=' , maxCommitWindow printString - , ') ' asSymbol. + 'delay Until First Churn (W=' , maxCommitWindow printString , ') ' , ' - ', analysesDate. "number of project with minimum one commit of user" exportBrowserModel addColumnForQuery: [ :analysis | analysis numberOfProjectWithCommit ] - withName: 'number of project with min 1 commit of user' asSymbol. + withName: + 'number of project with min 1 commit of user' , ' - ', analysesDate. "merge Request Duration " exportBrowserModel addColumnForQuery: [ :analysis | analysis mergeRequestDuration ] - withName: 'merge Request Duration ' asSymbol. + withName: 'merge Request Duration ' , ' - ', analysesDate. "average time between commits" exportBrowserModel addColumnForQuery: [ :analysis | analysis averageTimeBetweenCommits ] - withName: 'average time between commits' asSymbol. + withName: 'average time between commits' , ' - ', analysesDate. "number of open merge request" exportBrowserModel addColumnForQuery: [ :analysis | analysis numberOfOpenMergeRequests ] - withName: 'number of open merge request' asSymbol. + withName: 'number of open merge request' , ' - ', analysesDate. "number of merged merge request" exportBrowserModel addColumnForQuery: [ :analysis | analysis numberOfMergedMergeRequest ] - withName: 'number of merged merge request' asSymbol. + withName: 'number of merged merge request' , ' - ', analysesDate. "number of merge requests closed and not merged" exportBrowserModel addColumnForQuery: [ :analysis | analysis numberOfClosedMergeRequests ] - withName: 'number of merge requests closed and not merged' asSymbol. + withName: + 'number of merge requests closed and not merged' , ' - ', analysesDate. "number of merge requests withour review" exportBrowserModel addColumnForQuery: [ :analysis | analysis numberOfMergeRequestsWithoutReview ] - withName: 'number of merge requests without review' asSymbol. + withName: 'number of merge requests without review' , ' - ', analysesDate. file := self constructFilePath: over. From 7552c8c23847b4858fe89e679792c2e3593f1ddb Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Thu, 22 Aug 2024 11:32:17 +0200 Subject: [PATCH 039/154] refactor: add csvMetrics and change exportInCSV to use it --- .../GitMetricExporter.class.st | 132 +++++++----------- 1 file changed, 50 insertions(+), 82 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index a18b918..6486343 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -117,6 +117,48 @@ GitMetricExporter >> constructFilePath: runningOver [ ^ file ] +{ #category : #exporting } +GitMetricExporter >> csvMetrics [ + + ^ OrderedDictionary newFrom: { + ('code addition (avg)' -> [ :analysis | analysis codeAddition ]). + + ('code deletion (avg)' -> [ :analysis | analysis codeDeletion ]). + + ('commits frequency (avg)' + -> [ :analysis | analysis commitFrequency ]). + + ('comment contribution (avg)' + -> [ :analysis | analysis commentContribution ]). + + ('churn % (W=' , maxCommitWindow printString , ') ' + -> [ :analysis | analysis codeChurn ]). + + ('delay Until First Churn (W=' , maxCommitWindow printString + , ') ' -> [ :analysis | analysis delayUntilFirstChurn ]). + + ('number of project with min 1 commit of user' + -> [ :analysis | analysis numberOfProjectWithCommit ]). + + ('merge Request Duration' + -> [ :analysis | analysis mergeRequestDuration ]). + + ('average time between commits' + -> [ :analysis | analysis averageTimeBetweenCommits ]). + + ('number of open merge request' + -> [ :analysis | analysis numberOfOpenMergeRequests ]). + + ('number of merged merge request' + -> [ :analysis | analysis numberOfMergedMergeRequest ]). + + ('number of merge requests closed and not merged' + -> [ :analysis | analysis numberOfClosedMergeRequests ]). + + ('number of merge requests without review' + -> [ :analysis | analysis numberOfMergeRequestsWithoutReview ]) } +] + { #category : #accessing } GitMetricExporter >> entities: aCollection [ entities := aCollection @@ -140,104 +182,30 @@ GitMetricExporter >> exportFor: usersWithProjects over: aCollectionOfDateWeekMon { #category : #exporting } GitMetricExporter >> exportInCSV [ - | exportBrowserModel file period analysesDate | + | exportBrowserModel file period analysesDate metrics | exportBrowserModel := MiExportModel new. - self analyses ifNil: [ self generateAnalyses ]. - + metrics := self csvMetrics. period := runningPeriods at: 1. analysesDate := (period at: #since) asString. - exportBrowserModel entitiesList: self analyses. - exportBrowserModel removeColumnForQueryNamed: #Type. exportBrowserModel removeColumnForQueryNamed: #Name. - exportBrowserModel addColumnForQuery: [ :analysis | analysis username ] withName: #'User name'. - - "Code Contribution " - exportBrowserModel - addColumnForQuery: [ :analysis | analysis codeAddition ] - withName: 'code addition (avg)' , ' - ', analysesDate. - - exportBrowserModel - addColumnForQuery: [ :analysis | analysis codeDeletion ] - withName: 'code deletion (avg)' , ' - ', analysesDate. - - "Commit frequencies " - exportBrowserModel - addColumnForQuery: [ :analysis | analysis commitFrequency ] - withName: 'commits frequency (avg)',' - ', analysesDate. - - "comment contribution " - exportBrowserModel - addColumnForQuery: [ :analysis | analysis commentContribution ] - withName: 'comment contribution (avg)', ' - ', analysesDate. - - "code churn" - exportBrowserModel - addColumnForQuery: [ :analysis | analysis codeChurn ] - withName: - 'churn % (W=' , maxCommitWindow printString , ') ' , ' - ', analysesDate. - - "delay Until First Churn" - exportBrowserModel - addColumnForQuery: [ :analysis | analysis delayUntilFirstChurn ] - withName: - 'delay Until First Churn (W=' , maxCommitWindow printString , ') ' , ' - ', analysesDate. - - "number of project with minimum one commit of user" - exportBrowserModel - addColumnForQuery: [ :analysis | analysis numberOfProjectWithCommit ] - withName: - 'number of project with min 1 commit of user' , ' - ', analysesDate. - - "merge Request Duration " - exportBrowserModel - addColumnForQuery: [ :analysis | analysis mergeRequestDuration ] - withName: 'merge Request Duration ' , ' - ', analysesDate. - - "average time between commits" - exportBrowserModel - addColumnForQuery: [ :analysis | analysis averageTimeBetweenCommits ] - withName: 'average time between commits' , ' - ', analysesDate. - - "number of open merge request" - exportBrowserModel - addColumnForQuery: [ :analysis | analysis numberOfOpenMergeRequests ] - withName: 'number of open merge request' , ' - ', analysesDate. - - - "number of merged merge request" - exportBrowserModel - addColumnForQuery: [ :analysis | - analysis numberOfMergedMergeRequest ] - withName: 'number of merged merge request' , ' - ', analysesDate. - - "number of merge requests closed and not merged" - exportBrowserModel - addColumnForQuery: [ :analysis | - analysis numberOfClosedMergeRequests ] - withName: - 'number of merge requests closed and not merged' , ' - ', analysesDate. - - - "number of merge requests withour review" - exportBrowserModel - addColumnForQuery: [ :analysis | - analysis numberOfMergeRequestsWithoutReview ] - withName: 'number of merge requests without review' , ' - ', analysesDate. - - + metrics associations do: [ :association | + exportBrowserModel + addColumnForQuery: association value + withName: (' - ' join: { + association key. + analysesDate }) ]. file := self constructFilePath: over. file writeStreamDo: [ :aStream | aStream << 'sep=,'; << OSPlatform current lineEnding. exportBrowserModel writeCSVOn: aStream ]. - 'Done computing' recordInfo ] From b6f91a2957b9d6954110da1bf130e57f408f9ea5 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Thu, 22 Aug 2024 11:37:34 +0200 Subject: [PATCH 040/154] feat: make new exportInCSV work for multiple periods --- .../GitMetricExporter.class.st | 57 ++++++++++++------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 6486343..1af5a30 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -182,30 +182,47 @@ GitMetricExporter >> exportFor: usersWithProjects over: aCollectionOfDateWeekMon { #category : #exporting } GitMetricExporter >> exportInCSV [ - | exportBrowserModel file period analysesDate metrics | + | exportBrowserModel file metrics | exportBrowserModel := MiExportModel new. + self analyses ifNil: [ self generateAnalyses ]. metrics := self csvMetrics. - period := runningPeriods at: 1. - analysesDate := (period at: #since) asString. - exportBrowserModel entitiesList: self analyses. - exportBrowserModel removeColumnForQueryNamed: #Type. - exportBrowserModel removeColumnForQueryNamed: #Name. - exportBrowserModel - addColumnForQuery: [ :analysis | analysis username ] - withName: #'User name'. - metrics associations do: [ :association | + + runningPeriods do: [ :period | + | periodAnalyses analysesDate | + periodAnalyses := self analyses select: [ :analysis | + (analysis period at: #since) = period + at: #since + and: + (analysis period at: #until) + = (period at: #until) ]. + analysesDate := (period at: #since) asString. + + exportBrowserModel entitiesList: periodAnalyses. + + exportBrowserModel removeColumnForQueryNamed: #Type. + exportBrowserModel removeColumnForQueryNamed: #Name. + exportBrowserModel - addColumnForQuery: association value - withName: (' - ' join: { - association key. - analysesDate }) ]. - file := self constructFilePath: over. - file writeStreamDo: [ :aStream | - aStream - << 'sep=,'; - << OSPlatform current lineEnding. - exportBrowserModel writeCSVOn: aStream ]. + addColumnForQuery: [ :analysis | analysis username ] + withName: #'User name'. + + + metrics associations do: [ :association | + exportBrowserModel + addColumnForQuery: association value + withName: (' - ' join: { + association key. + analysesDate }) ]. + + + file := self constructFilePath: over. + file writeStreamDo: [ :aStream | + aStream + << 'sep=,'; + << OSPlatform current lineEnding. + exportBrowserModel writeCSVOn: aStream ] ]. + 'Done computing' recordInfo ] From 690c6a5528096d13ce5e1c9c6a9810ff25ba7725 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Thu, 22 Aug 2024 11:42:33 +0200 Subject: [PATCH 041/154] fix: error in exportInCSV --- src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 1af5a30..fc4cd98 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -191,11 +191,10 @@ GitMetricExporter >> exportInCSV [ runningPeriods do: [ :period | | periodAnalyses analysesDate | periodAnalyses := self analyses select: [ :analysis | - (analysis period at: #since) = period - at: #since + ((analysis period at: #since) = (period at: #since)) and: - (analysis period at: #until) - = (period at: #until) ]. + ((analysis period at: #until) + = (period at: #until)) ]. analysesDate := (period at: #since) asString. exportBrowserModel entitiesList: periodAnalyses. From 472726f9430cdcc2718e0c2c6723870b6142bad2 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Thu, 22 Aug 2024 16:31:20 +0200 Subject: [PATCH 042/154] feat: change csv export to get multiple period in one csv file --- .../GitMetricExporter.class.st | 126 +++++++++++++++--- 1 file changed, 108 insertions(+), 18 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index fc4cd98..71f6f91 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -159,6 +159,87 @@ GitMetricExporter >> csvMetrics [ -> [ :analysis | analysis numberOfMergeRequestsWithoutReview ]) } ] +{ #category : #exporting } +GitMetricExporter >> csvMetricsFor: date [ + + ^ OrderedDictionary newFrom: { + ('code addition (avg) - ' , date asString -> [ :groupAnalyses | + | analysis | + analysis := self getAnalysisWithDate: date from: groupAnalyses. + analysis ifNil: [ nil ] ifNotNil: [ analysis codeAddition ] ]). + + ('code deletion (avg) - ' , date asString -> [ :groupAnalyses | + | analysis | + analysis := self getAnalysisWithDate: date from: groupAnalyses. + analysis ifNil: [ nil ] ifNotNil: [ analysis codeDeletion ] ]). + + ('commits frequency (avg) - ' , date asString + -> [ :groupAnalyses | + | analysis | + analysis := self getAnalysisWithDate: date from: groupAnalyses. + analysis ifNil: [ nil ] ifNotNil: [ analysis commitFrequency ] ]). + + ('comment contribution (avg) - ' , date asString + -> [ :groupAnalyses | + | analysis | + analysis := self getAnalysisWithDate: date from: groupAnalyses. + analysis ifNil: [ nil ] ifNotNil: [ analysis commentContribution ] ]). + + ('churn % (W=' , maxCommitWindow printString , ') - ' + , date asString -> [ :groupAnalyses | + | analysis | + analysis := self getAnalysisWithDate: date from: groupAnalyses. + analysis ifNil: [ nil ] ifNotNil: [ analysis codeChurn ] ]). + + ('delay Until First Churn (W=' , maxCommitWindow printString + , ') - ' , date asString -> [ :groupAnalyses | + | analysis | + analysis := self getAnalysisWithDate: date from: groupAnalyses. + analysis ifNil: [ nil ] ifNotNil: [ analysis delayUntilFirstChurn ] ]). + + ('number of project with min 1 commit of user - ' , date asString + -> [ :groupAnalyses | + (groupAnalyses + detect: [ :analysis | (analysis period at: #since) = date ] + ifNone: [ '' ]) numberOfProjectWithCommit ]). + + ('merge Request Duration - ' , date asString + -> [ :groupAnalyses | + | analysis | + analysis := self getAnalysisWithDate: date from: groupAnalyses. + analysis ifNil: [ nil ] ifNotNil: [ analysis mergeRequestDuration ] ]). + + ('average time between commits - ' , date asString + -> [ :groupAnalyses | + (groupAnalyses + detect: [ :analysis | (analysis period at: #since) = date ] + ifNone: [ '' ]) averageTimeBetweenCommits ]). + + ('number of open merge request - ' , date asString + -> [ :groupAnalyses | + | analysis | + analysis := self getAnalysisWithDate: date from: groupAnalyses. + analysis ifNil: [ nil ] ifNotNil: [ analysis numberOfOpenMergeRequests ] ]). + + ('number of merged merge request - ' , date asString + -> [ :groupAnalyses | + | analysis | + analysis := self getAnalysisWithDate: date from: groupAnalyses. + analysis ifNil: [ nil ] ifNotNil: [ analysis numberOfMergedMergeRequest ] ]). + + ('number of merge requests closed and not merged - ' + , date asString -> [ :groupAnalyses | + | analysis | + analysis := self getAnalysisWithDate: date from: groupAnalyses. + analysis ifNil: [ nil ] ifNotNil: [ analysis numberOfClosedMergeRequests ] ]). + + ('number of merge requests without review - ' , date asString + -> [ :groupAnalyses | + | analysis | + analysis := self getAnalysisWithDate: date from: groupAnalyses. + analysis ifNil: [ nil ] ifNotNil: [ analysis numberOfMergeRequestsWithoutReview ] ]) } +] + { #category : #accessing } GitMetricExporter >> entities: aCollection [ entities := aCollection @@ -182,40 +263,41 @@ GitMetricExporter >> exportFor: usersWithProjects over: aCollectionOfDateWeekMon { #category : #exporting } GitMetricExporter >> exportInCSV [ - | exportBrowserModel file metrics | + | exportBrowserModel file metrics groupedByOver groupByName periods group groupOver | exportBrowserModel := MiExportModel new. self analyses ifNil: [ self generateAnalyses ]. metrics := self csvMetrics. - runningPeriods do: [ :period | - | periodAnalyses analysesDate | - periodAnalyses := self analyses select: [ :analysis | - ((analysis period at: #since) = (period at: #since)) - and: - ((analysis period at: #until) - = (period at: #until)) ]. - analysesDate := (period at: #since) asString. + groupedByOver := self analyses groupedBy: #over. + + groupedByOver associations do: [ :groupAssociation | + group := groupAssociation value. + groupOver := groupAssociation key. + groupByName := group groupedBy: #username. - exportBrowserModel entitiesList: periodAnalyses. + exportBrowserModel entitiesList: groupByName. exportBrowserModel removeColumnForQueryNamed: #Type. exportBrowserModel removeColumnForQueryNamed: #Name. exportBrowserModel - addColumnForQuery: [ :analysis | analysis username ] + addColumnForQuery: [ :groupAnalyses | + (groupAnalyses at: 1) username ] withName: #'User name'. + periods := (group groupedBy: #period) keys. - metrics associations do: [ :association | - exportBrowserModel - addColumnForQuery: association value - withName: (' - ' join: { - association key. - analysesDate }) ]. + periods do: [ :period | + metrics := self csvMetricsFor: (period at: #since). - file := self constructFilePath: over. + metrics associations do: [ :association | + exportBrowserModel + addColumnForQuery: association value + withName: association key ] ]. + + file := self constructFilePath: groupOver. file writeStreamDo: [ :aStream | aStream << 'sep=,'; @@ -330,6 +412,14 @@ GitMetricExporter >> generateAnalysesOver: aDateWeekMonthOrYear [ ^ newAnalyses ] +{ #category : #utilities } +GitMetricExporter >> getAnalysisWithDate: date from: analysisCollection [ + + ^analysisCollection + detect: [ :groupAnalysis | (groupAnalysis period at: #since) = date ] + ifNone: [ nil ] +] + { #category : #accessing } GitMetricExporter >> glhImporter: anImporter [ From f773a2339560a0eb926237aadad204615510b343 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Thu, 22 Aug 2024 16:33:51 +0200 Subject: [PATCH 043/154] refactor: remove unused code --- .../GitMetricExporter.class.st | 47 +------------------ 1 file changed, 2 insertions(+), 45 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 71f6f91..f5acb21 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -117,48 +117,6 @@ GitMetricExporter >> constructFilePath: runningOver [ ^ file ] -{ #category : #exporting } -GitMetricExporter >> csvMetrics [ - - ^ OrderedDictionary newFrom: { - ('code addition (avg)' -> [ :analysis | analysis codeAddition ]). - - ('code deletion (avg)' -> [ :analysis | analysis codeDeletion ]). - - ('commits frequency (avg)' - -> [ :analysis | analysis commitFrequency ]). - - ('comment contribution (avg)' - -> [ :analysis | analysis commentContribution ]). - - ('churn % (W=' , maxCommitWindow printString , ') ' - -> [ :analysis | analysis codeChurn ]). - - ('delay Until First Churn (W=' , maxCommitWindow printString - , ') ' -> [ :analysis | analysis delayUntilFirstChurn ]). - - ('number of project with min 1 commit of user' - -> [ :analysis | analysis numberOfProjectWithCommit ]). - - ('merge Request Duration' - -> [ :analysis | analysis mergeRequestDuration ]). - - ('average time between commits' - -> [ :analysis | analysis averageTimeBetweenCommits ]). - - ('number of open merge request' - -> [ :analysis | analysis numberOfOpenMergeRequests ]). - - ('number of merged merge request' - -> [ :analysis | analysis numberOfMergedMergeRequest ]). - - ('number of merge requests closed and not merged' - -> [ :analysis | analysis numberOfClosedMergeRequests ]). - - ('number of merge requests without review' - -> [ :analysis | analysis numberOfMergeRequestsWithoutReview ]) } -] - { #category : #exporting } GitMetricExporter >> csvMetricsFor: date [ @@ -267,15 +225,14 @@ GitMetricExporter >> exportInCSV [ exportBrowserModel := MiExportModel new. self analyses ifNil: [ self generateAnalyses ]. - metrics := self csvMetrics. - groupedByOver := self analyses groupedBy: #over. groupedByOver associations do: [ :groupAssociation | group := groupAssociation value. groupOver := groupAssociation key. + + groupByName := group groupedBy: #username. - exportBrowserModel entitiesList: groupByName. exportBrowserModel removeColumnForQueryNamed: #Type. From 67e04fe6c8c95f714b63c973315ac65bb19fb0b3 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Fri, 23 Aug 2024 15:56:07 +0200 Subject: [PATCH 044/154] feat: add load its merge request with jira issue method --- .../GitMetric.class.st | 7 +++++ .../GitMetric4User.class.st | 19 ++++++++++++ .../GitMetricExporter.class.st | 31 +++++++++++++------ 3 files changed, 47 insertions(+), 10 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetric.class.st b/src/GitLabHealth-Model-Analysis/GitMetric.class.st index ac30ac5..5127304 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetric.class.st @@ -4,6 +4,7 @@ Class { #instVars : [ 'user', 'glhImporter', + 'jiraImporter', 'itsProjects', 'gitAnalyzer', 'glhModel' @@ -85,6 +86,12 @@ GitMetric >> glhImporter: aGLPHModelImporter [ glhImporter := aGLPHModelImporter ] +{ #category : #accessing } +GitMetric >> jiraImporter: anObject [ + + jiraImporter := anObject +] + { #category : #churn } GitMetric >> loadCommitsFromProjectsIds: aCollection since: since until: until [ diff --git a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st index de01d63..3aed82b 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st @@ -697,6 +697,25 @@ GitMetric4User >> loadCommitOfProjects: aCollection since: aTimespan [ ^ self userCommits. ] +{ #category : #loading } +GitMetric4User >> loadItsMergeRequesWithJiraIssueSince: since until: until [ + + itsMergeRequests := self + loadItsMergeRequestsSince: since + until: until. + + jiraImporter importAllCurrentAndPastIssuesOf: + user commits anyOne author_email. + + GPJCConnector new + gpModel: glhImporter glhModel; + jiraModel: jiraImporter model; + connect. + + ^ itsMergeRequests select: [ :mergeRequest | + mergeRequest jiraIssue isNotNil ] +] + { #category : #loading } GitMetric4User >> loadItsMergeRequestsSince: since until: until [ diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index f5acb21..4e2f50a 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -3,6 +3,7 @@ Class { #superclass : #Object, #instVars : [ 'glhImporter', + 'jiraImporter', 'label', 'entities', 'projectCache', @@ -45,11 +46,14 @@ GitMetricExporter >> addEntitiesFromUserNames: userNames [ "then collect the project in which the user has be seen commited" entities addAll: (userNames collect: [ :username | | projects metrics i size | - projects := self findParticipationOfCommitAuthorNamed: username amongProjects: projectCache. + projects := self + findParticipationOfCommitAuthorNamed: username + amongProjects: projectCache. metrics := GitMetric4User new. metrics glhImporter: glhImporter; + jiraImporter: jiraImporter; findUserNamed: username. @@ -77,17 +81,18 @@ GitMetricExporter >> addEntitiesFromUserNames: userNames [ GitMetricExporter >> addEntitiesFromUserNamesAndProjects: usersWithProjects [ entities addAll: (usersWithProjects associations collect: [ :assoc | - | username projects metrics | - username := assoc key. - projects := assoc value. + | username projects metrics | + username := assoc key. + projects := assoc value. - metrics := GitMetric4User new. - metrics - glhImporter: glhImporter; - findUserNamed: username. - metrics loadProjectsFromIds: projects. + metrics := GitMetric4User new. + metrics + glhImporter: glhImporter; + jiraImporter: jiraImporter; + findUserNamed: username. + metrics loadProjectsFromIds: projects. - metrics ]). + metrics ]). ^ self ] @@ -418,6 +423,12 @@ GitMetricExporter >> initialize [ over := Date ] +{ #category : #accessing } +GitMetricExporter >> jiraImporter: anObject [ + + jiraImporter := anObject +] + { #category : #accessing } GitMetricExporter >> label: aString [ label := aString From 2e8a04ef8a7687aaf923936df9f71e4f8605ddd9 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Fri, 23 Aug 2024 16:39:36 +0200 Subject: [PATCH 045/154] feat: number of jira tickets closed metric --- .../GitMetric4User.class.st | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st index 3aed82b..3f7068a 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st @@ -1033,6 +1033,47 @@ GitMetric4User >> numberOfProjectWithCommitSince: since until: until overA: aDat ] +{ #category : #'metrics -jira' } +GitMetric4User >> numberOfTicketsClosedSince: since until: until overA: aDateWeekMonthOrYear [ + + | groupedByDate itsMergeRequestsWithJiraIssue dateOver average mergedMergeRequestWithJiraIssue | + groupedByDate := self + setupGroupedDateFrom: since + to: until + over: aDateWeekMonthOrYear. + + itsMergeRequestsWithJiraIssue := self + loadItsMergeRequesWithJiraIssueSince: + since + until: until. + + mergedMergeRequestWithJiraIssue := itsMergeRequestsWithJiraIssue + select: [ :mr | + mr merged_at isNotNil ]. + + mergedMergeRequestWithJiraIssue do: [ :userMergeRequest | + dateOver := self + transformDate: userMergeRequest created_at + to: aDateWeekMonthOrYear. + groupedByDate + at: dateOver printString + ifPresent: [ :value | value add: userMergeRequest ] ]. + + groupedByDate := groupedByDate collect: [ :group | group size ]. + + average := groupedByDate + ifEmpty: [ 0 ] + ifNotEmpty: [ groupedByDate average ]. + ^ { + (#overEach -> aDateWeekMonthOrYear name). + (#forOver -> (groupedByDate keys size printString + , aDateWeekMonthOrYear printString)). + (#average -> average asFloat). + (#details -> groupedByDate). + (#userMergeRequestsWithJiraIssue -> itsMergeRequestsWithJiraIssue size) } + asDictionary +] + { #category : #accessing } GitMetric4User >> user [ ^ user From e497baaaa898b4440659ecd3914f6e8830fb5602 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Fri, 23 Aug 2024 16:46:29 +0200 Subject: [PATCH 046/154] feat: add numberOfTicketClosed in analysisReport and csv export --- .../AnalysisReport.class.st | 15 ++++- .../GitMetricExporter.class.st | 62 +++++++++++++------ 2 files changed, 56 insertions(+), 21 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st b/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st index cf7b3fc..2da1f3d 100644 --- a/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st +++ b/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st @@ -17,7 +17,8 @@ Class { 'numberOfOpenMergeRequests', 'numberOfMergedMergeRequest', 'numberOfClosedMergeRequests', - 'numberOfMergeRequestsWithoutReview' + 'numberOfMergeRequestsWithoutReview', + 'numberOfTicketsClosed' ], #category : #'GitLabHealth-Model-Analysis' } @@ -183,6 +184,18 @@ AnalysisReport >> numberOfProjectWithCommit: anObject [ numberOfProjectWithCommit := anObject ] +{ #category : #accessing } +AnalysisReport >> numberOfTicketsClosed [ + + ^ numberOfTicketsClosed +] + +{ #category : #accessing } +AnalysisReport >> numberOfTicketsClosed: anObject [ + + numberOfTicketsClosed := anObject +] + { #category : #accessing } AnalysisReport >> over [ diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 4e2f50a..6d55fcd 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -138,15 +138,17 @@ GitMetricExporter >> csvMetricsFor: date [ ('commits frequency (avg) - ' , date asString -> [ :groupAnalyses | - | analysis | - analysis := self getAnalysisWithDate: date from: groupAnalyses. - analysis ifNil: [ nil ] ifNotNil: [ analysis commitFrequency ] ]). + | analysis | + analysis := self getAnalysisWithDate: date from: groupAnalyses. + analysis ifNil: [ nil ] ifNotNil: [ analysis commitFrequency ] ]). ('comment contribution (avg) - ' , date asString -> [ :groupAnalyses | - | analysis | - analysis := self getAnalysisWithDate: date from: groupAnalyses. - analysis ifNil: [ nil ] ifNotNil: [ analysis commentContribution ] ]). + | analysis | + analysis := self getAnalysisWithDate: date from: groupAnalyses. + analysis + ifNil: [ nil ] + ifNotNil: [ analysis commentContribution ] ]). ('churn % (W=' , maxCommitWindow printString , ') - ' , date asString -> [ :groupAnalyses | @@ -158,7 +160,9 @@ GitMetricExporter >> csvMetricsFor: date [ , ') - ' , date asString -> [ :groupAnalyses | | analysis | analysis := self getAnalysisWithDate: date from: groupAnalyses. - analysis ifNil: [ nil ] ifNotNil: [ analysis delayUntilFirstChurn ] ]). + analysis + ifNil: [ nil ] + ifNotNil: [ analysis delayUntilFirstChurn ] ]). ('number of project with min 1 commit of user - ' , date asString -> [ :groupAnalyses | @@ -168,9 +172,11 @@ GitMetricExporter >> csvMetricsFor: date [ ('merge Request Duration - ' , date asString -> [ :groupAnalyses | - | analysis | - analysis := self getAnalysisWithDate: date from: groupAnalyses. - analysis ifNil: [ nil ] ifNotNil: [ analysis mergeRequestDuration ] ]). + | analysis | + analysis := self getAnalysisWithDate: date from: groupAnalyses. + analysis + ifNil: [ nil ] + ifNotNil: [ analysis mergeRequestDuration ] ]). ('average time between commits - ' , date asString -> [ :groupAnalyses | @@ -180,27 +186,43 @@ GitMetricExporter >> csvMetricsFor: date [ ('number of open merge request - ' , date asString -> [ :groupAnalyses | - | analysis | - analysis := self getAnalysisWithDate: date from: groupAnalyses. - analysis ifNil: [ nil ] ifNotNil: [ analysis numberOfOpenMergeRequests ] ]). + | analysis | + analysis := self getAnalysisWithDate: date from: groupAnalyses. + analysis + ifNil: [ nil ] + ifNotNil: [ analysis numberOfOpenMergeRequests ] ]). ('number of merged merge request - ' , date asString -> [ :groupAnalyses | - | analysis | - analysis := self getAnalysisWithDate: date from: groupAnalyses. - analysis ifNil: [ nil ] ifNotNil: [ analysis numberOfMergedMergeRequest ] ]). + | analysis | + analysis := self getAnalysisWithDate: date from: groupAnalyses. + analysis + ifNil: [ nil ] + ifNotNil: [ analysis numberOfMergedMergeRequest ] ]). ('number of merge requests closed and not merged - ' , date asString -> [ :groupAnalyses | | analysis | analysis := self getAnalysisWithDate: date from: groupAnalyses. - analysis ifNil: [ nil ] ifNotNil: [ analysis numberOfClosedMergeRequests ] ]). + analysis + ifNil: [ nil ] + ifNotNil: [ analysis numberOfClosedMergeRequests ] ]). ('number of merge requests without review - ' , date asString -> [ :groupAnalyses | - | analysis | - analysis := self getAnalysisWithDate: date from: groupAnalyses. - analysis ifNil: [ nil ] ifNotNil: [ analysis numberOfMergeRequestsWithoutReview ] ]) } + | analysis | + analysis := self getAnalysisWithDate: date from: groupAnalyses. + analysis + ifNil: [ nil ] + ifNotNil: [ analysis numberOfMergeRequestsWithoutReview ] ]). + + ('number of merge request with jira ticket closed - ' , date asString + -> [ :groupAnalyses | + | analysis | + analysis := self getAnalysisWithDate: date from: groupAnalyses. + analysis + ifNil: [ nil ] + ifNotNil: [ analysis numberOfTicketsClosed ] ]) } ] { #category : #accessing } From 77f7293efec7993a83defa7554584934ff6b06ff Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Fri, 23 Aug 2024 16:47:11 +0200 Subject: [PATCH 047/154] feat: add number of tickets closed in generateAnalysis --- .../GitMetric4User.class.st | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st index 3f7068a..f2e21d7 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st @@ -571,38 +571,31 @@ GitMetric4User >> foundSuccessorOf: userCommits andCompleteImportForMax: commitL { #category : #analysis } GitMetric4User >> generateAnalysisForPeriod: period over: aDateWeekMonthOrYear withMaxCommitWindows: maxCommitWindow [ - | contribution commitFrequency commentContribution mergeRequestDuration codeChurn delayUntilFirstChurn averageTimeBetweenCommits numberOfProjectWithCommit until since numberOfOpenMergeRequests numberOfMergedMergeRequests numberOfClosedMergeRequests numberOfMergeRequestWithoutReview | + | contribution commitFrequency commentContribution mergeRequestDuration codeChurn delayUntilFirstChurn averageTimeBetweenCommits numberOfProjectWithCommit until since numberOfOpenMergeRequests numberOfMergedMergeRequests numberOfClosedMergeRequests numberOfMergeRequestWithoutReview numberOfTicketsClosed | since := period at: #since. until := period at: #until. - - "COMMITS" contribution := self codeContributionsSince: since until: until overA: aDateWeekMonthOrYear. - commitFrequency := self commitFrequencySince: since until: until overA: aDateWeekMonthOrYear. - commentContribution := self commentsContributionsSince: since until: until overA: aDateWeekMonthOrYear. - codeChurn := self codeChurnSince: since until: until onACommitWindowOf: maxCommitWindow overA: aDateWeekMonthOrYear. - delayUntilFirstChurn := self delayUntilFirstChurnSince: since until: until onACommitWindowOf: maxCommitWindow overA: aDateWeekMonthOrYear. - numberOfProjectWithCommit := self numberOfProjectWithCommitSince: since until: until @@ -611,37 +604,33 @@ GitMetric4User >> generateAnalysisForPeriod: period over: aDateWeekMonthOrYear w averageTimeBetweenCommitSince: since until: until overA: aDateWeekMonthOrYear. - - "MERGE REQUESTS" - mergeRequestDuration := self mergeRequestDurationSince: since until: until overA: aDateWeekMonthOrYear. - numberOfOpenMergeRequests := self numberOfOpenMergeRequestsSince: since until: until overA: aDateWeekMonthOrYear. - numberOfMergedMergeRequests := self numberOfMergedMergeRequestsSince: since until: until overA: aDateWeekMonthOrYear. - numberOfClosedMergeRequests := self numberOfClosedMergeRequestSince: since until: until overA: aDateWeekMonthOrYear. - numberOfMergeRequestWithoutReview := self numberOfMergeRequestsMergedWithoutReviewSince: since until: until overA: aDateWeekMonthOrYear. - + numberOfTicketsClosed := self + numberOfTicketsClosedSince: since + until: until + overA: aDateWeekMonthOrYear. ^ AnalysisReport new username: self user name; period: period; @@ -663,7 +652,9 @@ GitMetric4User >> generateAnalysisForPeriod: period over: aDateWeekMonthOrYear w (numberOfMergedMergeRequests at: #average); numberOfClosedMergeRequests: (numberOfClosedMergeRequests at: #average); - numberOfMergeRequestsWithoutReview: (numberOfMergeRequestWithoutReview at: #average). + numberOfMergeRequestsWithoutReview: + (numberOfMergeRequestWithoutReview at: #average); + numberOfTicketsClosed: (numberOfTicketsClosed at: #average) ] { #category : #initialization } From f00cf1b1e0b1951388670983095ecf0ccc0a421e Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Mon, 26 Aug 2024 12:00:41 +0200 Subject: [PATCH 048/154] add possibility to add a user email domain to search user on jira --- .../GLHUserCatalogueV2.class.st | 18 ++++++++++++------ .../GitMetric4User.class.st | 8 ++++++-- .../GitMetricExporter.class.st | 3 ++- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st b/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st index d289db3..b9b6c58 100644 --- a/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st +++ b/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st @@ -11,15 +11,21 @@ GLHUserCatalogueV2 class >> loadFromJson: aString [ catalogue := self new. dic := (STONJSON fromString: aString) asDictionary. dic associationsDo: [ :assoc | - | itsName itsUsername itsCommitNames itsId| + | itsName itsUsername itsCommitNames itsId | itsName := assoc key. itsCommitNames := assoc value at: #foundNames. - itsUsername := assoc value at: #username. + itsUsername := assoc value at: #username. itsId := assoc value at: #id. - - catalogue addUser: (GLHUser new id: itsId; username: itsUsername; name: itsName; yourself ) withNames: itsCommitNames ]. - - ^ catalogue . + + catalogue + addUser: (GLHUser new + id: itsId; + username: itsUsername; + name: itsName; + yourself) + withNames: itsCommitNames ]. + + ^ catalogue ] { #category : #'as yet unclassified' } diff --git a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st index f2e21d7..e9c56ea 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st @@ -3,7 +3,8 @@ Class { #superclass : #GitMetric, #instVars : [ 'itsCommits', - 'itsMergeRequests' + 'itsMergeRequests', + 'emailDomain' ], #category : #'GitLabHealth-Model-Analysis' } @@ -691,12 +692,15 @@ GitMetric4User >> loadCommitOfProjects: aCollection since: aTimespan [ { #category : #loading } GitMetric4User >> loadItsMergeRequesWithJiraIssueSince: since until: until [ + |email| itsMergeRequests := self loadItsMergeRequestsSince: since until: until. + email := ('' join: {user username . '@berger-levrault.com'}) asLowercase . + jiraImporter importAllCurrentAndPastIssuesOf: - user commits anyOne author_email. + email. GPJCConnector new gpModel: glhImporter glhModel; diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 6d55fcd..af3f68a 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -11,7 +11,8 @@ Class { 'runningPeriods', 'maxCommitWindow', 'over', - 'analyses' + 'analyses', + 'emailDomain' ], #category : #'GitLabHealth-Model-Analysis' } From 73a69b084247b5f961fa3034eda1123c266902f9 Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Tue, 27 Aug 2024 10:39:47 +0200 Subject: [PATCH 049/154] add email setup for jira interfacing --- .../GitMetric4User.class.st | 20 +++++++++++++++++-- .../GitMetricExporter.class.st | 13 +++++++++++- .../GLHModelImporter.class.st | 3 ++- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st index e9c56ea..f1c2d1f 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st @@ -9,6 +9,20 @@ Class { #category : #'GitLabHealth-Model-Analysis' } +{ #category : #'email' } +GitMetric4User >> withUserEmailDomain: aEmailDomain [ + emailDomain := aEmailDomain. +] + +{ #category : #'email' } +GitMetric4User >> userEmail [ + "overide this method to adapt on your situation" + + ^ ('' join: { + user username. + emailDomain }) asLowercase. +] + { #category : #'metrics - commits' } GitMetric4User >> averageTimeBetweenCommitSince: since until: until overA: aDateWeekMonthOrYear [ @@ -664,7 +678,9 @@ GitMetric4User >> initialize [ user := GLHUser new. itsProjects := Dictionary new. itsCommits := Dictionary new. - itsMergeRequests := Dictionary new + itsMergeRequests := Dictionary new. + + emailDomain := '@generic-domain.com' ] { #category : #accessing } @@ -697,7 +713,7 @@ GitMetric4User >> loadItsMergeRequesWithJiraIssueSince: since until: until [ loadItsMergeRequestsSince: since until: until. - email := ('' join: {user username . '@berger-levrault.com'}) asLowercase . + email := self userEmail. jiraImporter importAllCurrentAndPastIssuesOf: email. diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index af3f68a..a7fc98d 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -17,6 +17,8 @@ Class { #category : #'GitLabHealth-Model-Analysis' } + + { #category : #'as yet unclassified' } GitMetricExporter class >> demoPeriod [ @@ -26,6 +28,13 @@ GitMetricExporter class >> demoPeriod [ addAPeriodFrom: '01 march 2024' to: '31 may 2024' ] +{ #category : #setup } +GitMetricExporter >> withEmailDomain: anEmailDomain [ + + "define the email domain of your Git user. Usefull to link them between service (i.e. Jira)" + emailDomain := anEmailDomain +] + { #category : #adding } GitMetricExporter >> addAPeriodFrom: since to: until [ @@ -470,7 +479,7 @@ GitMetricExporter >> onlyImportProjectsOfGroup: groupId [ projectCache := group toScope: GLHProject ] -{ #category : #adding } +{ #category : #setup } GitMetricExporter >> setupAnalysisForUsersWithNames: userNames [ "import all the project since a certain time" @@ -487,6 +496,8 @@ GitMetricExporter >> setupAnalysisForUsersWithNames: userNames [ metrics := GitMetric4User new. metrics glhImporter: glhImporter; + jiraImporter: jiraImporter; + withUserEmailDomain: emailDomain; user: user. i := 0. diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index 69008a4..108b819 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -1155,7 +1155,8 @@ GLHModelImporter >> userCatalogue [ { #category : #accessing } GLHModelImporter >> userCatalogue: aGLHUserCatalogue [ - userCatalogue := aGLHUserCatalogue + userCatalogue := aGLHUserCatalogue. + aGLHUserCatalogue anImporter: self. ] { #category : #accessing } From 3e90499c44cf65dc099e0cefed2e046b6d8249ab Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Tue, 27 Aug 2024 14:43:13 +0200 Subject: [PATCH 050/154] refactor : base structure and codeContributionMetric --- .../CodeContributionMetric.class.st | 50 ++++++++++ .../Metric.class.st | 99 +++++++++++++++++++ .../UserMetric.class.st | 73 ++++++++++++++ 3 files changed, 222 insertions(+) create mode 100644 src/GitLabHealth-Model-Analysis/CodeContributionMetric.class.st create mode 100644 src/GitLabHealth-Model-Analysis/Metric.class.st create mode 100644 src/GitLabHealth-Model-Analysis/UserMetric.class.st diff --git a/src/GitLabHealth-Model-Analysis/CodeContributionMetric.class.st b/src/GitLabHealth-Model-Analysis/CodeContributionMetric.class.st new file mode 100644 index 0000000..e109ad4 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/CodeContributionMetric.class.st @@ -0,0 +1,50 @@ +Class { + #name : #CodeContributionMetric, + #superclass : #UserMetric, + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #'as yet unclassified' } +CodeContributionMetric >> calculate [ + + | gitAnalyzer contributions groupedByDate | + groupedByDate := self setupGroupedDate. + + gitAnalyzer := GitAnalyzer new + onModel: glhModel; + glhImporter: glhImporter. + + contributions := userCommits collect: [ :commit | + commit -> (gitAnalyzer + fromCommit: commit; + analyseCommitContribution) ]. + + + contributions do: [ :assoc | + | dateOver | + dateOver := self transformDate: assoc key created_at to: over. + groupedByDate + at: dateOver printString + ifPresent: [ :v | v add: assoc value ] + ifAbsentPut: [ + OrderedCollection new + add: assoc value; + yourself ] ]. + + groupedByDate := groupedByDate collect: [ :contribs | + | totalAdd totalDele | + totalAdd := contribs sum: [ :v | v at: #addition ]. + totalDele := contribs sum: [ :v | v at: #deletion ]. + { + (#addition -> totalAdd). + (#deletion -> totalDele) } asDictionary ]. + + ^ groupedByDate +] + +{ #category : #loading } +CodeContributionMetric >> load [ + + self loadUserProjects. + self loadUserCommits. +] diff --git a/src/GitLabHealth-Model-Analysis/Metric.class.st b/src/GitLabHealth-Model-Analysis/Metric.class.st new file mode 100644 index 0000000..8d8e854 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/Metric.class.st @@ -0,0 +1,99 @@ +Class { + #name : #Metric, + #superclass : #Object, + #instVars : [ + 'name', + 'description', + 'period', + 'over', + 'glhImporter', + 'glhModel' + ], + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #'as yet unclassified' } +Metric >> calculate [ + + ^self subclassResponsibility +] + +{ #category : #accessing } +Metric >> glhImporter: anObject [ + + glhImporter := anObject +] + +{ #category : #loading } +Metric >> load [ + ^self subclassResponsibility +] + +{ #category : #accessing } +Metric >> over: anObject [ + + over := anObject +] + +{ #category : #initialization } +Metric >> setPeriodSince: since until: until [ + + period := { + (#since -> since asDate). + (#until -> until asDate) } asDictionary +] + +{ #category : #'as yet unclassified' } +Metric >> setupGroupedDate [ + + | groupedByDate start end increment overSymbol | + groupedByDate := OrderedDictionary new. + + increment := 1. + start := self transformDate: (period at: #since) to: over. + end := self transformDate: (period at: #until) to: over. + + groupedByDate + at: start printString + ifAbsentPut: [ OrderedCollection new ]. + + overSymbol := over name asLowercase asSymbol. + overSymbol = #date ifTrue: [ over := #day ]. + overSymbol = #month ifTrue: [ + increment := 32. + over := #day ]. + + + [ groupedByDate keys last asDateAndTime < end ] whileTrue: [ + | index | + index := groupedByDate keys last asDateAndTime + + (increment perform: overSymbol). + index := self transformDate: index to: over. + groupedByDate + at: index printString + ifAbsentPut: [ OrderedCollection new ] ]. + + + over = #day ifTrue: [ + groupedByDate := (groupedByDate associations select: [ :date | + | aWeekday | + aWeekday := date key asDate weekday. + (aWeekday = #Sunday or: [ aWeekday = #Saturday ]) + not ]) asOrderedDictionary ]. + + + groupedByDate + at: end printString + ifAbsentPut: [ OrderedCollection new ]. + + ^ groupedByDate +] + +{ #category : #'as yet unclassified' } +Metric >> transformDate: date to: aWeekOrMonthOrYear [ + + aWeekOrMonthOrYear = Month ifTrue: [ ^ date asDate month asDate ]. + + ^ (date asDate perform: ('as' , aWeekOrMonthOrYear name) asSymbol) + asDate +] diff --git a/src/GitLabHealth-Model-Analysis/UserMetric.class.st b/src/GitLabHealth-Model-Analysis/UserMetric.class.st new file mode 100644 index 0000000..fd9f421 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/UserMetric.class.st @@ -0,0 +1,73 @@ +Class { + #name : #UserMetric, + #superclass : #Metric, + #instVars : [ + 'user', + 'userProjects', + 'userCommits' + ], + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #'as yet unclassified' } +UserMetric >> cacheSymbolFor: anEntityType since: since until: until [ + + ^ (anEntityType printString , ' since ' , since printString , ' to ' + , until printString) asSymbol +] + +{ #category : #'as yet unclassified' } +UserMetric >> calculate [ + + ^ self subclassResponsibility +] + +{ #category : #loading } +UserMetric >> load [ + + ^ self subclassResponsibility +] + +{ #category : #'as yet unclassified' } +UserMetric >> loadUserCommits [ + + | allCommits cacheSymbol | + userProjects ifNil: [ self loadUserProjects ]. + glhImporter withCommitDiffs: false. + + cacheSymbol := self + cacheSymbolFor: GLHCommit + since: (period at: #since) + until: (period at: #until). + + "download commits unless project cache is not empty" + allCommits := userProjects collect: [ :project | + + glhImporter + importCommitsOProject: project + since: (period at: #since) + until: (period at: #until). + ]. + + allCommits := allCommits flatten. + allCommits do: [ :commit | glhImporter importCreatorOfCommit: commit ]. + glhImporter chainsCommitsFrom: allCommits. + glhImporter withCommitDiffs: true. + + ^ userCommits := allCommits reject: [ :commit | + commit commitCreator ~= user ] +] + +{ #category : #'as yet unclassified' } +UserMetric >> loadUserProjects [ + + userProjects := glhImporter importContributedProjectsOfUser: user. + + userProjects do: [ :project | glhImporter completeImportProject: project] +] + +{ #category : #accessing } +UserMetric >> user: anObject [ + + user := anObject +] From 612fe0b46514fcb138ed44beed1e13f331c9b572 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Tue, 27 Aug 2024 15:26:28 +0200 Subject: [PATCH 051/154] refactor: remove unused variable --- .../CodeContributionMetric.class.st | 1 - src/GitLabHealth-Model-Analysis/Metric.class.st | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/CodeContributionMetric.class.st b/src/GitLabHealth-Model-Analysis/CodeContributionMetric.class.st index e109ad4..7c8fb77 100644 --- a/src/GitLabHealth-Model-Analysis/CodeContributionMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CodeContributionMetric.class.st @@ -11,7 +11,6 @@ CodeContributionMetric >> calculate [ groupedByDate := self setupGroupedDate. gitAnalyzer := GitAnalyzer new - onModel: glhModel; glhImporter: glhImporter. contributions := userCommits collect: [ :commit | diff --git a/src/GitLabHealth-Model-Analysis/Metric.class.st b/src/GitLabHealth-Model-Analysis/Metric.class.st index 8d8e854..a7fab4b 100644 --- a/src/GitLabHealth-Model-Analysis/Metric.class.st +++ b/src/GitLabHealth-Model-Analysis/Metric.class.st @@ -6,8 +6,7 @@ Class { 'description', 'period', 'over', - 'glhImporter', - 'glhModel' + 'glhImporter' ], #category : #'GitLabHealth-Model-Analysis' } From 67ff15178ab81c02c90a485e734d30a7ecfab9ac Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Tue, 27 Aug 2024 16:24:52 +0200 Subject: [PATCH 052/154] refactor: create new calculate method and change export in csv for new metrics --- .../CodeContributionMetric.class.st | 12 ++ .../GitMetricExporter.class.st | 159 ++++++------------ .../Metric.class.st | 12 ++ .../UserAnalysisReport.class.st | 58 +++++++ .../UserMetric.class.st | 12 ++ 5 files changed, 147 insertions(+), 106 deletions(-) create mode 100644 src/GitLabHealth-Model-Analysis/UserAnalysisReport.class.st diff --git a/src/GitLabHealth-Model-Analysis/CodeContributionMetric.class.st b/src/GitLabHealth-Model-Analysis/CodeContributionMetric.class.st index 7c8fb77..a8c02d8 100644 --- a/src/GitLabHealth-Model-Analysis/CodeContributionMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CodeContributionMetric.class.st @@ -41,9 +41,21 @@ CodeContributionMetric >> calculate [ ^ groupedByDate ] +{ #category : #accessing } +CodeContributionMetric >> description [ + + ^ 'code addition (avg)' +] + { #category : #loading } CodeContributionMetric >> load [ self loadUserProjects. self loadUserCommits. ] + +{ #category : #accessing } +CodeContributionMetric >> name [ + + ^ 'codeContribution' +] diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 6d55fcd..f9eade4 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -11,7 +11,8 @@ Class { 'runningPeriods', 'maxCommitWindow', 'over', - 'analyses' + 'analyses', + 'metrics' ], #category : #'GitLabHealth-Model-Analysis' } @@ -109,6 +110,35 @@ GitMetricExporter >> analyses: anObject [ analyses := anObject ] +{ #category : #'as yet unclassified' } +GitMetricExporter >> calculateAllMetricsOver: aDateWeekMonthOrYear [ + + | entity period userAnalysisReport result | + entity := entities at: 1. + period := runningPeriods at: 1. + + + userAnalysisReport := UserAnalysisReport new + username: entity user name; + period: period; + over: aDateWeekMonthOrYear. + + metrics do: [ :metric | + metric + glhImporter: glhImporter; + setPeriodSince: (period at: #since) until: (period at: #until); + over: aDateWeekMonthOrYear; + user: entity user. + + + metric load. + result := metric calculate. + userAnalysisReport metrics at: metric name put: result ]. + + self analyses: { userAnalysisReport }. + ^ userAnalysisReport +] + { #category : #utilities } GitMetricExporter >> constructFilePath: runningOver [ @@ -125,104 +155,19 @@ GitMetricExporter >> constructFilePath: runningOver [ { #category : #exporting } GitMetricExporter >> csvMetricsFor: date [ - ^ OrderedDictionary newFrom: { - ('code addition (avg) - ' , date asString -> [ :groupAnalyses | - | analysis | - analysis := self getAnalysisWithDate: date from: groupAnalyses. - analysis ifNil: [ nil ] ifNotNil: [ analysis codeAddition ] ]). - - ('code deletion (avg) - ' , date asString -> [ :groupAnalyses | - | analysis | - analysis := self getAnalysisWithDate: date from: groupAnalyses. - analysis ifNil: [ nil ] ifNotNil: [ analysis codeDeletion ] ]). - - ('commits frequency (avg) - ' , date asString - -> [ :groupAnalyses | - | analysis | - analysis := self getAnalysisWithDate: date from: groupAnalyses. - analysis ifNil: [ nil ] ifNotNil: [ analysis commitFrequency ] ]). - - ('comment contribution (avg) - ' , date asString - -> [ :groupAnalyses | - | analysis | - analysis := self getAnalysisWithDate: date from: groupAnalyses. - analysis - ifNil: [ nil ] - ifNotNil: [ analysis commentContribution ] ]). - - ('churn % (W=' , maxCommitWindow printString , ') - ' - , date asString -> [ :groupAnalyses | - | analysis | - analysis := self getAnalysisWithDate: date from: groupAnalyses. - analysis ifNil: [ nil ] ifNotNil: [ analysis codeChurn ] ]). - - ('delay Until First Churn (W=' , maxCommitWindow printString - , ') - ' , date asString -> [ :groupAnalyses | - | analysis | - analysis := self getAnalysisWithDate: date from: groupAnalyses. - analysis - ifNil: [ nil ] - ifNotNil: [ analysis delayUntilFirstChurn ] ]). - - ('number of project with min 1 commit of user - ' , date asString - -> [ :groupAnalyses | - (groupAnalyses - detect: [ :analysis | (analysis period at: #since) = date ] - ifNone: [ '' ]) numberOfProjectWithCommit ]). - - ('merge Request Duration - ' , date asString - -> [ :groupAnalyses | - | analysis | - analysis := self getAnalysisWithDate: date from: groupAnalyses. - analysis - ifNil: [ nil ] - ifNotNil: [ analysis mergeRequestDuration ] ]). - - ('average time between commits - ' , date asString - -> [ :groupAnalyses | - (groupAnalyses - detect: [ :analysis | (analysis period at: #since) = date ] - ifNone: [ '' ]) averageTimeBetweenCommits ]). - - ('number of open merge request - ' , date asString - -> [ :groupAnalyses | - | analysis | - analysis := self getAnalysisWithDate: date from: groupAnalyses. - analysis - ifNil: [ nil ] - ifNotNil: [ analysis numberOfOpenMergeRequests ] ]). - - ('number of merged merge request - ' , date asString - -> [ :groupAnalyses | - | analysis | - analysis := self getAnalysisWithDate: date from: groupAnalyses. - analysis - ifNil: [ nil ] - ifNotNil: [ analysis numberOfMergedMergeRequest ] ]). - - ('number of merge requests closed and not merged - ' - , date asString -> [ :groupAnalyses | - | analysis | - analysis := self getAnalysisWithDate: date from: groupAnalyses. - analysis - ifNil: [ nil ] - ifNotNil: [ analysis numberOfClosedMergeRequests ] ]). - - ('number of merge requests without review - ' , date asString - -> [ :groupAnalyses | - | analysis | - analysis := self getAnalysisWithDate: date from: groupAnalyses. - analysis - ifNil: [ nil ] - ifNotNil: [ analysis numberOfMergeRequestsWithoutReview ] ]). - - ('number of merge request with jira ticket closed - ' , date asString - -> [ :groupAnalyses | - | analysis | - analysis := self getAnalysisWithDate: date from: groupAnalyses. - analysis - ifNil: [ nil ] - ifNotNil: [ analysis numberOfTicketsClosed ] ]) } + | csvMetrics | + csvMetrics := metrics collect: [ :metric | + metric description , date asString + -> [ :groupAnalyses | + | analysis | + analysis := self + getAnalysisWithDate: date + from: groupAnalyses. + analysis + ifNil: [ nil ] + ifNotNil: [ analysis metrics at: metric name ] ] ]. + + ^ csvMetrics asDictionary ] { #category : #accessing } @@ -248,7 +193,7 @@ GitMetricExporter >> exportFor: usersWithProjects over: aCollectionOfDateWeekMon { #category : #exporting } GitMetricExporter >> exportInCSV [ - | exportBrowserModel file metrics groupedByOver groupByName periods group groupOver | + | exportBrowserModel file groupedByOver groupByName periods group groupOver csvMetrics | exportBrowserModel := MiExportModel new. self analyses ifNil: [ self generateAnalyses ]. @@ -257,8 +202,8 @@ GitMetricExporter >> exportInCSV [ groupedByOver associations do: [ :groupAssociation | group := groupAssociation value. groupOver := groupAssociation key. - - + + groupByName := group groupedBy: #username. exportBrowserModel entitiesList: groupByName. @@ -273,10 +218,10 @@ GitMetricExporter >> exportInCSV [ periods := (group groupedBy: #period) keys. periods do: [ :period | - metrics := self csvMetricsFor: (period at: #since). + csvMetrics := self csvMetricsFor: (period at: #since). - metrics associations do: [ :association | + csvMetrics associations do: [ :association | exportBrowserModel addColumnForQuery: association value withName: association key ] ]. @@ -439,10 +384,12 @@ GitMetricExporter >> initialize [ entities := OrderedCollection new. "set up the minimal date from which we are looking for the commits a particular user in projects" - sinceTimeLimit := '2024-01-01' asDateAndTime.. + sinceTimeLimit := '2024-01-01' asDateAndTime. runningPeriods := OrderedCollection new. maxCommitWindow := 3. - over := Date + over := Date. + + metrics := { CodeContributionMetric new } ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/Metric.class.st b/src/GitLabHealth-Model-Analysis/Metric.class.st index a7fab4b..404cbbf 100644 --- a/src/GitLabHealth-Model-Analysis/Metric.class.st +++ b/src/GitLabHealth-Model-Analysis/Metric.class.st @@ -17,6 +17,12 @@ Metric >> calculate [ ^self subclassResponsibility ] +{ #category : #accessing } +Metric >> description [ + + ^ self subclassResponsibility +] + { #category : #accessing } Metric >> glhImporter: anObject [ @@ -28,6 +34,12 @@ Metric >> load [ ^self subclassResponsibility ] +{ #category : #accessing } +Metric >> name [ + + ^ self subclassResponsibility +] + { #category : #accessing } Metric >> over: anObject [ diff --git a/src/GitLabHealth-Model-Analysis/UserAnalysisReport.class.st b/src/GitLabHealth-Model-Analysis/UserAnalysisReport.class.st new file mode 100644 index 0000000..67e6a6a --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/UserAnalysisReport.class.st @@ -0,0 +1,58 @@ +Class { + #name : #UserAnalysisReport, + #superclass : #Object, + #instVars : [ + 'username', + 'period', + 'over', + 'metrics' + ], + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #initialization } +UserAnalysisReport >> initialize [ + metrics := Dictionary new. +] + +{ #category : #accessing } +UserAnalysisReport >> metrics [ + + ^ metrics +] + +{ #category : #accessing } +UserAnalysisReport >> over [ + + ^ over +] + +{ #category : #accessing } +UserAnalysisReport >> over: anObject [ + + over := anObject +] + +{ #category : #accessing } +UserAnalysisReport >> period [ + + ^ period +] + +{ #category : #accessing } +UserAnalysisReport >> period: anObject [ + + period := anObject +] + +{ #category : #accessing } +UserAnalysisReport >> username [ + + ^ username +] + +{ #category : #accessing } +UserAnalysisReport >> username: anObject [ + + username := anObject +] diff --git a/src/GitLabHealth-Model-Analysis/UserMetric.class.st b/src/GitLabHealth-Model-Analysis/UserMetric.class.st index fd9f421..e8a5e12 100644 --- a/src/GitLabHealth-Model-Analysis/UserMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserMetric.class.st @@ -22,6 +22,12 @@ UserMetric >> calculate [ ^ self subclassResponsibility ] +{ #category : #accessing } +UserMetric >> description [ + + ^ self subclassResponsibility +] + { #category : #loading } UserMetric >> load [ @@ -66,6 +72,12 @@ UserMetric >> loadUserProjects [ userProjects do: [ :project | glhImporter completeImportProject: project] ] +{ #category : #accessing } +UserMetric >> name [ + + ^ self subclassResponsibility +] + { #category : #accessing } UserMetric >> user: anObject [ From 5364eaf7ec3aef1a0753f464565bf5696132c67a Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Tue, 27 Aug 2024 16:36:01 +0200 Subject: [PATCH 053/154] refactor: split codeContribution in codeAddiction and codeDeletion --- ...c.class.st => CodeAdditionMetric.class.st} | 25 ++++----- .../CodeDeletionMetric.class.st | 55 +++++++++++++++++++ .../GitMetricExporter.class.st | 4 +- .../Metric.class.st | 2 - 4 files changed, 68 insertions(+), 18 deletions(-) rename src/GitLabHealth-Model-Analysis/{CodeContributionMetric.class.st => CodeAdditionMetric.class.st} (60%) create mode 100644 src/GitLabHealth-Model-Analysis/CodeDeletionMetric.class.st diff --git a/src/GitLabHealth-Model-Analysis/CodeContributionMetric.class.st b/src/GitLabHealth-Model-Analysis/CodeAdditionMetric.class.st similarity index 60% rename from src/GitLabHealth-Model-Analysis/CodeContributionMetric.class.st rename to src/GitLabHealth-Model-Analysis/CodeAdditionMetric.class.st index a8c02d8..579f6b7 100644 --- a/src/GitLabHealth-Model-Analysis/CodeContributionMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CodeAdditionMetric.class.st @@ -1,17 +1,16 @@ Class { - #name : #CodeContributionMetric, + #name : #CodeAdditionMetric, #superclass : #UserMetric, #category : #'GitLabHealth-Model-Analysis' } { #category : #'as yet unclassified' } -CodeContributionMetric >> calculate [ +CodeAdditionMetric >> calculate [ | gitAnalyzer contributions groupedByDate | groupedByDate := self setupGroupedDate. - gitAnalyzer := GitAnalyzer new - glhImporter: glhImporter. + gitAnalyzer := GitAnalyzer new glhImporter: glhImporter. contributions := userCommits collect: [ :commit | commit -> (gitAnalyzer @@ -31,31 +30,29 @@ CodeContributionMetric >> calculate [ yourself ] ]. groupedByDate := groupedByDate collect: [ :contribs | - | totalAdd totalDele | - totalAdd := contribs sum: [ :v | v at: #addition ]. - totalDele := contribs sum: [ :v | v at: #deletion ]. - { - (#addition -> totalAdd). - (#deletion -> totalDele) } asDictionary ]. + + contribs sum: [ :v | v at: #addition ]. + + ]. ^ groupedByDate ] { #category : #accessing } -CodeContributionMetric >> description [ +CodeAdditionMetric >> description [ ^ 'code addition (avg)' ] { #category : #loading } -CodeContributionMetric >> load [ +CodeAdditionMetric >> load [ self loadUserProjects. - self loadUserCommits. + self loadUserCommits ] { #category : #accessing } -CodeContributionMetric >> name [ +CodeAdditionMetric >> name [ ^ 'codeContribution' ] diff --git a/src/GitLabHealth-Model-Analysis/CodeDeletionMetric.class.st b/src/GitLabHealth-Model-Analysis/CodeDeletionMetric.class.st new file mode 100644 index 0000000..e612315 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/CodeDeletionMetric.class.st @@ -0,0 +1,55 @@ +Class { + #name : #CodeDeletionMetric, + #superclass : #UserMetric, + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #'as yet unclassified' } +CodeDeletionMetric >> calculate [ + + | gitAnalyzer contributions groupedByDate | + groupedByDate := self setupGroupedDate. + + gitAnalyzer := GitAnalyzer new glhImporter: glhImporter. + + contributions := userCommits collect: [ :commit | + commit -> (gitAnalyzer + fromCommit: commit; + analyseCommitContribution) ]. + + + contributions do: [ :assoc | + | dateOver | + dateOver := self transformDate: assoc key created_at to: over. + groupedByDate + at: dateOver printString + ifPresent: [ :v | v add: assoc value ] + ifAbsentPut: [ + OrderedCollection new + add: assoc value; + yourself ] ]. + + groupedByDate := groupedByDate collect: [ :contribs | + contribs sum: [ :v | v at: #deletion ] ]. + + ^ groupedByDate +] + +{ #category : #accessing } +CodeDeletionMetric >> description [ + + ^'code deletion (avg)' +] + +{ #category : #loading } +CodeDeletionMetric >> load [ + + self loadUserProjects. + self loadUserCommits +] + +{ #category : #accessing } +CodeDeletionMetric >> name [ + + ^'codeDeletion' +] diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index f9eade4..747685f 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -388,8 +388,8 @@ GitMetricExporter >> initialize [ runningPeriods := OrderedCollection new. maxCommitWindow := 3. over := Date. - - metrics := { CodeContributionMetric new } + + metrics := { CodeAdditionMetric new . CodeDeletionMetric new. } ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/Metric.class.st b/src/GitLabHealth-Model-Analysis/Metric.class.st index 404cbbf..09dfef1 100644 --- a/src/GitLabHealth-Model-Analysis/Metric.class.st +++ b/src/GitLabHealth-Model-Analysis/Metric.class.st @@ -2,8 +2,6 @@ Class { #name : #Metric, #superclass : #Object, #instVars : [ - 'name', - 'description', 'period', 'over', 'glhImporter' From e941396bbbec14c0aea14cd8f7caa0abd75de9ae Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Tue, 27 Aug 2024 16:37:20 +0200 Subject: [PATCH 054/154] fix: fix name of cell in csv export --- src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 747685f..11eac38 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -157,7 +157,7 @@ GitMetricExporter >> csvMetricsFor: date [ | csvMetrics | csvMetrics := metrics collect: [ :metric | - metric description , date asString + metric description ,' - ', date asString -> [ :groupAnalyses | | analysis | analysis := self From 9693bad5f51ee30fc2075620de82a6fb157a48d0 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Tue, 27 Aug 2024 16:40:05 +0200 Subject: [PATCH 055/154] refactor: change methods protocol --- .../CodeAdditionMetric.class.st | 2 +- .../CodeDeletionMetric.class.st | 2 +- .../GitMetricExporter.class.st | 2 +- src/GitLabHealth-Model-Analysis/Metric.class.st | 6 +++--- src/GitLabHealth-Model-Analysis/UserMetric.class.st | 8 ++++---- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/CodeAdditionMetric.class.st b/src/GitLabHealth-Model-Analysis/CodeAdditionMetric.class.st index 579f6b7..9b1dfa5 100644 --- a/src/GitLabHealth-Model-Analysis/CodeAdditionMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CodeAdditionMetric.class.st @@ -4,7 +4,7 @@ Class { #category : #'GitLabHealth-Model-Analysis' } -{ #category : #'as yet unclassified' } +{ #category : #calculating } CodeAdditionMetric >> calculate [ | gitAnalyzer contributions groupedByDate | diff --git a/src/GitLabHealth-Model-Analysis/CodeDeletionMetric.class.st b/src/GitLabHealth-Model-Analysis/CodeDeletionMetric.class.st index e612315..6010269 100644 --- a/src/GitLabHealth-Model-Analysis/CodeDeletionMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CodeDeletionMetric.class.st @@ -4,7 +4,7 @@ Class { #category : #'GitLabHealth-Model-Analysis' } -{ #category : #'as yet unclassified' } +{ #category : #calculating } CodeDeletionMetric >> calculate [ | gitAnalyzer contributions groupedByDate | diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 11eac38..3ac3dc7 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -110,7 +110,7 @@ GitMetricExporter >> analyses: anObject [ analyses := anObject ] -{ #category : #'as yet unclassified' } +{ #category : #calculating } GitMetricExporter >> calculateAllMetricsOver: aDateWeekMonthOrYear [ | entity period userAnalysisReport result | diff --git a/src/GitLabHealth-Model-Analysis/Metric.class.st b/src/GitLabHealth-Model-Analysis/Metric.class.st index 09dfef1..a4b0949 100644 --- a/src/GitLabHealth-Model-Analysis/Metric.class.st +++ b/src/GitLabHealth-Model-Analysis/Metric.class.st @@ -9,7 +9,7 @@ Class { #category : #'GitLabHealth-Model-Analysis' } -{ #category : #'as yet unclassified' } +{ #category : #calculating } Metric >> calculate [ ^self subclassResponsibility @@ -52,7 +52,7 @@ Metric >> setPeriodSince: since until: until [ (#until -> until asDate) } asDictionary ] -{ #category : #'as yet unclassified' } +{ #category : #'utils - date' } Metric >> setupGroupedDate [ | groupedByDate start end increment overSymbol | @@ -98,7 +98,7 @@ Metric >> setupGroupedDate [ ^ groupedByDate ] -{ #category : #'as yet unclassified' } +{ #category : #'utils - date' } Metric >> transformDate: date to: aWeekOrMonthOrYear [ aWeekOrMonthOrYear = Month ifTrue: [ ^ date asDate month asDate ]. diff --git a/src/GitLabHealth-Model-Analysis/UserMetric.class.st b/src/GitLabHealth-Model-Analysis/UserMetric.class.st index e8a5e12..cddd4c4 100644 --- a/src/GitLabHealth-Model-Analysis/UserMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserMetric.class.st @@ -9,14 +9,14 @@ Class { #category : #'GitLabHealth-Model-Analysis' } -{ #category : #'as yet unclassified' } +{ #category : #utils } UserMetric >> cacheSymbolFor: anEntityType since: since until: until [ ^ (anEntityType printString , ' since ' , since printString , ' to ' , until printString) asSymbol ] -{ #category : #'as yet unclassified' } +{ #category : #calculating } UserMetric >> calculate [ ^ self subclassResponsibility @@ -34,7 +34,7 @@ UserMetric >> load [ ^ self subclassResponsibility ] -{ #category : #'as yet unclassified' } +{ #category : #loading } UserMetric >> loadUserCommits [ | allCommits cacheSymbol | @@ -64,7 +64,7 @@ UserMetric >> loadUserCommits [ commit commitCreator ~= user ] ] -{ #category : #'as yet unclassified' } +{ #category : #loading } UserMetric >> loadUserProjects [ userProjects := glhImporter importContributedProjectsOfUser: user. From eec026a2bf30faa9ea4a96e7652ff223e5050bcb Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Tue, 27 Aug 2024 16:41:49 +0200 Subject: [PATCH 056/154] refactor: put average in csv export --- src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 3ac3dc7..772e1e1 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -157,7 +157,7 @@ GitMetricExporter >> csvMetricsFor: date [ | csvMetrics | csvMetrics := metrics collect: [ :metric | - metric description ,' - ', date asString + metric description , ' - ' , date asString -> [ :groupAnalyses | | analysis | analysis := self @@ -165,7 +165,7 @@ GitMetricExporter >> csvMetricsFor: date [ from: groupAnalyses. analysis ifNil: [ nil ] - ifNotNil: [ analysis metrics at: metric name ] ] ]. + ifNotNil: [ (analysis metrics at: metric name) average ] ] ]. ^ csvMetrics asDictionary ] From 2ede0b1656407843a2c84da8f277826dfdfb8430 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:01:06 +0200 Subject: [PATCH 057/154] feat: add commentContribution metric --- .../CommentContributionMetric.class.st | 61 +++++++++++++++++++ .../GitMetricExporter.class.st | 6 +- 2 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st diff --git a/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st b/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st new file mode 100644 index 0000000..1391e82 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st @@ -0,0 +1,61 @@ +Class { + #name : #CommentContributionMetric, + #superclass : #UserMetric, + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #calculating } +CommentContributionMetric >> calculate [ + + | groupedByDate gitAnalyzer contributions | + groupedByDate := self + setupGroupedDate. + + gitAnalyzer := GitAnalyzer new glhImporter: glhImporter. + + contributions := userCommits collect: [ :commit | + commit -> (gitAnalyzer + fromCommit: commit; + analyseCommentContribution) ]. + + + contributions do: [ :assoc | + | dateOver | + dateOver := self transformDate: assoc key created_at to: over. + groupedByDate + at: dateOver printString + ifPresent: [ :v | v add: assoc value ] + ifAbsentPut: [ + OrderedCollection new + add: assoc value; + yourself ] ]. + + groupedByDate := groupedByDate collect: [ :contribs | + contribs + ifNotEmpty: [ contribs sum ] + ifEmpty: [ 0 ] ]. + + + ^ groupedByDate +] + +{ #category : #accessing } +CommentContributionMetric >> description [ + + ^ 'comment contribution (avg)' +] + +{ #category : #loading } +CommentContributionMetric >> load [ + + self loadUserProjects. + self loadUserCommits. + + userCommits do: [ :commit | glhImporter completeImportedCommit: commit ]. +] + +{ #category : #accessing } +CommentContributionMetric >> name [ + + ^ 'commentContribution' +] diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 772e1e1..d12d854 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -156,6 +156,7 @@ GitMetricExporter >> constructFilePath: runningOver [ GitMetricExporter >> csvMetricsFor: date [ | csvMetrics | + csvMetrics := metrics collect: [ :metric | metric description , ' - ' , date asString -> [ :groupAnalyses | @@ -165,9 +166,10 @@ GitMetricExporter >> csvMetricsFor: date [ from: groupAnalyses. analysis ifNil: [ nil ] - ifNotNil: [ (analysis metrics at: metric name) average ] ] ]. + ifNotNil: [ + (analysis metrics at: metric name) average asFloat ] ] ]. - ^ csvMetrics asDictionary + ^ csvMetrics asOrderedDictionary ] { #category : #accessing } From e94c73c72123d93da9c96540ddc5b501f0b71200 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:08:07 +0200 Subject: [PATCH 058/154] fix: add commentContributionMetric in exporter initialisation --- src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index d12d854..827aef2 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -391,7 +391,10 @@ GitMetricExporter >> initialize [ maxCommitWindow := 3. over := Date. - metrics := { CodeAdditionMetric new . CodeDeletionMetric new. } + metrics := { + CodeAdditionMetric new. + CodeDeletionMetric new. + CommentContributionMetric new. } ] { #category : #accessing } From b0451ea50eb1776d75889c9657df35fa1e1b23e7 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:29:44 +0200 Subject: [PATCH 059/154] refactor: change calculateMetrics to run on all period and all entities --- .../GitMetricExporter.class.st | 52 ++++++++++--------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 827aef2..934da4f 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -113,30 +113,32 @@ GitMetricExporter >> analyses: anObject [ { #category : #calculating } GitMetricExporter >> calculateAllMetricsOver: aDateWeekMonthOrYear [ - | entity period userAnalysisReport result | - entity := entities at: 1. - period := runningPeriods at: 1. - - - userAnalysisReport := UserAnalysisReport new - username: entity user name; - period: period; - over: aDateWeekMonthOrYear. - - metrics do: [ :metric | - metric - glhImporter: glhImporter; - setPeriodSince: (period at: #since) until: (period at: #until); - over: aDateWeekMonthOrYear; - user: entity user. - - - metric load. - result := metric calculate. - userAnalysisReport metrics at: metric name put: result ]. + | userAnalysisReport result analysesReport | + runningPeriods do: [ :period | + analysesReport := entities collect: [ :entity | + userAnalysisReport := UserAnalysisReport new + username: entity user name; + period: period; + over: aDateWeekMonthOrYear. + + metrics do: [ :metric | + metric + glhImporter: glhImporter; + setPeriodSince: (period at: #since) until: (period at: #until); + over: aDateWeekMonthOrYear; + user: entity user. + + + metric load. + result := metric calculate. + userAnalysisReport metrics at: metric name put: result ]. + + userAnalysisReport + ]. +self analyses addAll: analysesReport. +]. - self analyses: { userAnalysisReport }. - ^ userAnalysisReport + ^ analyses ] { #category : #utilities } @@ -390,11 +392,13 @@ GitMetricExporter >> initialize [ runningPeriods := OrderedCollection new. maxCommitWindow := 3. over := Date. + + analyses := OrderedCollection new. metrics := { CodeAdditionMetric new. CodeDeletionMetric new. - CommentContributionMetric new. } + CommentContributionMetric new } ] { #category : #accessing } From 64845ae5af40fc5cf2abd56aa354e9992fb3bb16 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Wed, 28 Aug 2024 11:25:31 +0200 Subject: [PATCH 060/154] feat: add CommitFrequencyMetric --- .../CommitFrequencyMetric.class.st | 40 +++++++++++++++++++ .../GitMetricExporter.class.st | 6 ++- .../UserMetric.class.st | 5 +++ 3 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 src/GitLabHealth-Model-Analysis/CommitFrequencyMetric.class.st diff --git a/src/GitLabHealth-Model-Analysis/CommitFrequencyMetric.class.st b/src/GitLabHealth-Model-Analysis/CommitFrequencyMetric.class.st new file mode 100644 index 0000000..6b580cd --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/CommitFrequencyMetric.class.st @@ -0,0 +1,40 @@ +Class { + #name : #CommitFrequencyMetric, + #superclass : #UserMetric, + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #calculating } +CommitFrequencyMetric >> calculate [ + + | groupedByDate | + groupedByDate := self setupGroupedDate. + + userCommits do: [ :c | + | dateOver | + dateOver := self transformDate: c created_at to: over. + groupedByDate at: dateOver printString ifPresent: [ :v | v add: c ] ]. + + groupedByDate := groupedByDate collect: [ :group | group size ]. + + ^ groupedByDate +] + +{ #category : #accessing } +CommitFrequencyMetric >> description [ + + ^'commits frequency (avg)' +] + +{ #category : #loading } +CommitFrequencyMetric >> load [ + + self loadUserProjects. + self loadUserCommits. +] + +{ #category : #accessing } +CommitFrequencyMetric >> name [ + + ^ 'commitFrequency' +] diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 934da4f..9847908 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -392,13 +392,15 @@ GitMetricExporter >> initialize [ runningPeriods := OrderedCollection new. maxCommitWindow := 3. over := Date. - + analyses := OrderedCollection new. metrics := { CodeAdditionMetric new. CodeDeletionMetric new. - CommentContributionMetric new } + CommentContributionMetric new. + CommitFrequencyMetric new. + } ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/UserMetric.class.st b/src/GitLabHealth-Model-Analysis/UserMetric.class.st index cddd4c4..73e0c9d 100644 --- a/src/GitLabHealth-Model-Analysis/UserMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserMetric.class.st @@ -28,6 +28,11 @@ UserMetric >> description [ ^ self subclassResponsibility ] +{ #category : #initialization } +UserMetric >> initialize [ + over := Date +] + { #category : #loading } UserMetric >> load [ From 77726c78f7748db8c9756f0b53313dae7812fc3f Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Wed, 28 Aug 2024 11:35:47 +0200 Subject: [PATCH 061/154] feat: add ContributedProjectMetric --- .../ContributedProjectMetric.class.st | 44 +++++++++++++++++++ .../GitMetricExporter.class.st | 5 ++- 2 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 src/GitLabHealth-Model-Analysis/ContributedProjectMetric.class.st diff --git a/src/GitLabHealth-Model-Analysis/ContributedProjectMetric.class.st b/src/GitLabHealth-Model-Analysis/ContributedProjectMetric.class.st new file mode 100644 index 0000000..e91e007 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/ContributedProjectMetric.class.st @@ -0,0 +1,44 @@ +Class { + #name : #ContributedProjectMetric, + #superclass : #UserMetric, + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #calculating } +ContributedProjectMetric >> calculate [ + + | groupedByDate dateOver projects | + groupedByDate := self setupGroupedDate. + + userCommits do: [ :userCommit | + dateOver := self transformDate: userCommit committed_date to: over. + + groupedByDate + at: dateOver printString + ifPresent: [ :value | value add: userCommit repository project ] ]. + + groupedByDate := groupedByDate collect: [ :group | + projects := Set newFrom: group. + projects size ]. + + ^ groupedByDate +] + +{ #category : #accessing } +ContributedProjectMetric >> description [ + + ^ 'number of project with min 1 commit of user' +] + +{ #category : #loading } +ContributedProjectMetric >> load [ + + self loadUserProjects. + self loadUserCommits. +] + +{ #category : #accessing } +ContributedProjectMetric >> name [ + + ^ 'contributedProject' +] diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 9847908..cf62488 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -399,8 +399,9 @@ GitMetricExporter >> initialize [ CodeAdditionMetric new. CodeDeletionMetric new. CommentContributionMetric new. - CommitFrequencyMetric new. - } + CommitFrequencyMetric new. + ContributedProjectMetric new. + } ] { #category : #accessing } From 85c82131ee04077a6f06fa8cca65955665730dcd Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Wed, 28 Aug 2024 13:00:50 +0200 Subject: [PATCH 062/154] feat: add TimeBetweenCommitMetric --- .../GitMetricExporter.class.st | 8 +-- .../TimeBetweenCommitMetric.class.st | 58 +++++++++++++++++++ 2 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index cf62488..e76d8ae 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -158,7 +158,6 @@ GitMetricExporter >> constructFilePath: runningOver [ GitMetricExporter >> csvMetricsFor: date [ | csvMetrics | - csvMetrics := metrics collect: [ :metric | metric description , ' - ' , date asString -> [ :groupAnalyses | @@ -169,7 +168,7 @@ GitMetricExporter >> csvMetricsFor: date [ analysis ifNil: [ nil ] ifNotNil: [ - (analysis metrics at: metric name) average asFloat ] ] ]. + (analysis metrics at: metric name) average ] ] ]. ^ csvMetrics asOrderedDictionary ] @@ -400,8 +399,9 @@ GitMetricExporter >> initialize [ CodeDeletionMetric new. CommentContributionMetric new. CommitFrequencyMetric new. - ContributedProjectMetric new. - } + ContributedProjectMetric new. + TimeBetweenCommitMetric new. + } ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st b/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st new file mode 100644 index 0000000..17c368c --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st @@ -0,0 +1,58 @@ +Class { + #name : #TimeBetweenCommitMetric, + #superclass : #UserMetric, + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #calculating } +TimeBetweenCommitMetric >> calculate [ + + | commitSortedByDate commits1 commits2 differences groupedByDate dateOver | + groupedByDate := self setupGroupedDate. + + commitSortedByDate := userCommits sorted: [ :commit1 :commit2 | + commit1 committed_date + < commit2 committed_date ]. + + commitSortedByDate do: [ :commit | + dateOver := self transformDate: commit committed_date to: over. + + groupedByDate + at: dateOver printString + ifPresent: [ :value | value add: commit ] ]. + + groupedByDate := groupedByDate select: [ :group | group size >= 2 ]. + + + groupedByDate := groupedByDate collect: [ :group | + differences := (1 to: group size - 1) collect: [ :i | + commits1 := group at: i. + commits2 := group at: i + 1. + + (commits2 committed_date + - commits1 committed_date) + asSeconds ]. + + differences average asDuration ]. + + ^ groupedByDate +] + +{ #category : #accessing } +TimeBetweenCommitMetric >> description [ + + ^ 'average time between commits' +] + +{ #category : #loading } +TimeBetweenCommitMetric >> load [ + + self loadUserProjects. + self loadUserCommits. +] + +{ #category : #accessing } +TimeBetweenCommitMetric >> name [ + + ^ 'timeBetweenCommit' +] From c3bc7348b16858d62a3f3b68ac36e97a9edc6867 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Wed, 28 Aug 2024 15:37:40 +0200 Subject: [PATCH 063/154] feat: add mergeRequestDurationMetric --- .../GitMetricExporter.class.st | 4 +- .../MergeRequestDurationMetric.class.st | 69 +++++++++++++++++++ .../UserMetric.class.st | 32 ++++++++- 3 files changed, 102 insertions(+), 3 deletions(-) create mode 100644 src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index e76d8ae..0b638ab 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -400,8 +400,8 @@ GitMetricExporter >> initialize [ CommentContributionMetric new. CommitFrequencyMetric new. ContributedProjectMetric new. - TimeBetweenCommitMetric new. - } + TimeBetweenCommitMetric new. + MergeRequestDurationMetric new. } ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st b/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st new file mode 100644 index 0000000..87aa167 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st @@ -0,0 +1,69 @@ +Class { + #name : #MergeRequestDurationMetric, + #superclass : #UserMetric, + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #calculating } +MergeRequestDurationMetric >> calculate [ + + | groupedByDate gitAnalyzer mergeRequestsValidation filterGroups | + groupedByDate := self setupGroupedDate. + + userMergeRequests ifEmpty: [ ^ nil ]. + + gitAnalyzer := GitAnalyzer new glhImporter: glhImporter. + + mergeRequestsValidation := userMergeRequests collect: [ :mr | + gitAnalyzer + analyseMergeResquestValidation: mr ]. + + + mergeRequestsValidation do: [ :dic | + | overDate | + overDate := self transformDate: (dic at: #created_at) to: over. + + groupedByDate + at: overDate printString + ifPresent: [ :durations | durations add: (dic at: #duration) ] + ifAbsentPut: [ + OrderedCollection new + add: (dic at: #duration); + yourself ] ]. + + + filterGroups := groupedByDate reject: [ :array | array isEmpty ]. + + filterGroups associations do: [ :assoc | + | sum denominator | + denominator := assoc value size. + + sum := assoc value sum: [ :v | + v ifNil: [ + denominator := denominator - 1. + 0 asDuration ] ]. + denominator = 0 ifTrue: [ denominator := 1 ]. + + filterGroups at: assoc key put: sum / denominator ]. + + ^ filterGroups +] + +{ #category : #accessing } +MergeRequestDurationMetric >> description [ + + ^ 'merge request duration' +] + +{ #category : #loading } +MergeRequestDurationMetric >> load [ + + self loadUserProjects. + self loadUserMergeRequests. +] + +{ #category : #accessing } +MergeRequestDurationMetric >> name [ + + ^ 'mergeRequestDuration' +] diff --git a/src/GitLabHealth-Model-Analysis/UserMetric.class.st b/src/GitLabHealth-Model-Analysis/UserMetric.class.st index 73e0c9d..19fdc91 100644 --- a/src/GitLabHealth-Model-Analysis/UserMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserMetric.class.st @@ -4,7 +4,8 @@ Class { #instVars : [ 'user', 'userProjects', - 'userCommits' + 'userCommits', + 'userMergeRequests' ], #category : #'GitLabHealth-Model-Analysis' } @@ -69,6 +70,35 @@ UserMetric >> loadUserCommits [ commit commitCreator ~= user ] ] +{ #category : #loading } +UserMetric >> loadUserMergeRequests [ + + | mergeRequests cacheSymbol | + glhImporter withCommitDiffs: false. + cacheSymbol := self + cacheSymbolFor: GLPHEMergeRequest + since: (period at: #since) + until: (period at: #until). + + mergeRequests := userProjects collect: [ :project | + | mr | + project cacheAt: cacheSymbol ifAbsentPut: [ + mr := glhImporter + importMergeRequests: project + since: (period at: #since) + until: (period at: #until). + mr ] ]. + + mergeRequests := mergeRequests flattened. + glhImporter withCommitDiffs: true. + + mergeRequests do: [ :mr | glhImporter importMergeResquestAuthor: mr ]. + + userMergeRequests := mergeRequests select: [ :mergeRequest | + mergeRequest author = user ]. + ^ userMergeRequests +] + { #category : #loading } UserMetric >> loadUserProjects [ From c58a57a5e1ff832ab5520a6f7cabcd5eccd9c8fa Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Wed, 28 Aug 2024 15:47:21 +0200 Subject: [PATCH 064/154] feat: add ClosedMergeRequest and mergedMergerequest metric --- .../ClosedMergeRequestMetric.class.st | 52 +++++++++++++++ .../GitMetricExporter.class.st | 5 +- .../MergedMergeRequest.class.st | 66 +++++++++++++++++++ 3 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st create mode 100644 src/GitLabHealth-Model-Analysis/MergedMergeRequest.class.st diff --git a/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st new file mode 100644 index 0000000..f61ebe2 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st @@ -0,0 +1,52 @@ +Class { + #name : #ClosedMergeRequestMetric, + #superclass : #UserMetric, + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #calculating } +ClosedMergeRequestMetric >> calculate [ + + | groupedByDate userClosedMergeRequests dateOver | + groupedByDate := self + setupGroupedDate. + + userClosedMergeRequests := userMergeRequests select: [ + :userMergeRequest | + userMergeRequest merged_at isNil and: + userMergeRequest state = 'closed' ]. + + userClosedMergeRequests do: [ :userMergeRequest | + dateOver := self + transformDate: userMergeRequest created_at + to: over. + + groupedByDate + at: dateOver printString + ifPresent: [ :value | value add: userMergeRequest ] ]. + + + groupedByDate := groupedByDate collect: [ :group | group size ]. + + + ^ groupedByDate +] + +{ #category : #accessing } +ClosedMergeRequestMetric >> description [ + + ^ 'number of merge requests closed and not merged' +] + +{ #category : #loading } +ClosedMergeRequestMetric >> load [ + + self loadUserProjects. + self loadUserMergeRequests +] + +{ #category : #accessing } +ClosedMergeRequestMetric >> name [ + + ^ 'closedMergeRequest' +] diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 0b638ab..ee0256b 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -401,7 +401,10 @@ GitMetricExporter >> initialize [ CommitFrequencyMetric new. ContributedProjectMetric new. TimeBetweenCommitMetric new. - MergeRequestDurationMetric new. } + MergeRequestDurationMetric new. + ClosedMergeRequestMetric new. + MergedMergeRequest new. + } ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/MergedMergeRequest.class.st b/src/GitLabHealth-Model-Analysis/MergedMergeRequest.class.st new file mode 100644 index 0000000..3eae83a --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/MergedMergeRequest.class.st @@ -0,0 +1,66 @@ +Class { + #name : #MergedMergeRequest, + #superclass : #UserMetric, + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #calculating } +MergedMergeRequest >> calculate [ + + | groupedByDate mergedMergeRequest noVerificationMergeRequests dateOver gitAnalyzer | + groupedByDate := self setupGroupedDate. + + gitAnalyzer := GitAnalyzer new glhImporter: glhImporter. + + mergedMergeRequest := userMergeRequests select: [ :mr | + mr merged_at isNotNil ]. + + + noVerificationMergeRequests := mergedMergeRequest select: [ + :userMergeRequest | + | validation | + glhImporter + importMergeResquestMerger: + userMergeRequest. + + validation := gitAnalyzer + analyseMergeResquestValidation: + userMergeRequest. + + userMergeRequest merge_user + = userMergeRequest author and: + (validation at: #duration) + < 1 minutes ]. + + + noVerificationMergeRequests do: [ :userMergeRequest | + dateOver := self transformDate: userMergeRequest created_at to: over. + + groupedByDate + at: dateOver printString + ifPresent: [ :value | value add: userMergeRequest ] ]. + + + groupedByDate := groupedByDate collect: [ :group | group size ]. + + ^ groupedByDate +] + +{ #category : #accessing } +MergedMergeRequest >> description [ + + ^ 'number of merged merge request' +] + +{ #category : #loading } +MergedMergeRequest >> load [ + + self loadUserProjects. + self loadUserMergeRequests +] + +{ #category : #accessing } +MergedMergeRequest >> name [ + + ^ 'mergedMergeRequest' +] From c16d4cbc9ee230a8e3fced19751b0689b3213b76 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Wed, 28 Aug 2024 15:56:55 +0200 Subject: [PATCH 065/154] feat : add last merge request metrics --- .../GitMetricExporter.class.st | 5 +- .../MergedMergeRequestMetric.class.st | 47 +++++++++++++++++++ ...dMergeRequestWithoutReviewMetric.class.st} | 14 +++--- .../OpenedMergeRequestMetric.class.st | 42 +++++++++++++++++ 4 files changed, 99 insertions(+), 9 deletions(-) create mode 100644 src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st rename src/GitLabHealth-Model-Analysis/{MergedMergeRequest.class.st => MergedMergeRequestWithoutReviewMetric.class.st} (82%) create mode 100644 src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index ee0256b..96a870b 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -402,9 +402,10 @@ GitMetricExporter >> initialize [ ContributedProjectMetric new. TimeBetweenCommitMetric new. MergeRequestDurationMetric new. + OpenedMergeRequestMetric new. ClosedMergeRequestMetric new. - MergedMergeRequest new. - } + MergedMergeRequestMetric new. + MergedMergeRequestWithoutReviewMetric new } ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st new file mode 100644 index 0000000..e5402d8 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st @@ -0,0 +1,47 @@ +Class { + #name : #MergedMergeRequestMetric, + #superclass : #UserMetric, + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #calculating } +MergedMergeRequestMetric >> calculate [ + + | groupedByDate userMergedMergeRequests dateOver | + groupedByDate := self + setupGroupedDate. + + userMergedMergeRequests := userMergeRequests select: [ + :userMergeRequest | + userMergeRequest merged_at isNotNil ]. + + userMergedMergeRequests do: [ :userMergeRequest | + dateOver := self + transformDate: userMergeRequest created_at + to: over. + groupedByDate + at: dateOver printString + ifPresent: [ :value | value add: userMergeRequest ] ]. + groupedByDate := groupedByDate collect: [ :group | group size ]. + + ^ groupedByDate +] + +{ #category : #accessing } +MergedMergeRequestMetric >> description [ + + ^ 'number of merged merge request' +] + +{ #category : #loading } +MergedMergeRequestMetric >> load [ + + self loadUserProjects. + self loadUserMergeRequests. +] + +{ #category : #accessing } +MergedMergeRequestMetric >> name [ + + ^ 'mergedMergeRequest' +] diff --git a/src/GitLabHealth-Model-Analysis/MergedMergeRequest.class.st b/src/GitLabHealth-Model-Analysis/MergedMergeRequestWithoutReviewMetric.class.st similarity index 82% rename from src/GitLabHealth-Model-Analysis/MergedMergeRequest.class.st rename to src/GitLabHealth-Model-Analysis/MergedMergeRequestWithoutReviewMetric.class.st index 3eae83a..f53e798 100644 --- a/src/GitLabHealth-Model-Analysis/MergedMergeRequest.class.st +++ b/src/GitLabHealth-Model-Analysis/MergedMergeRequestWithoutReviewMetric.class.st @@ -1,11 +1,11 @@ Class { - #name : #MergedMergeRequest, + #name : #MergedMergeRequestWithoutReviewMetric, #superclass : #UserMetric, #category : #'GitLabHealth-Model-Analysis' } { #category : #calculating } -MergedMergeRequest >> calculate [ +MergedMergeRequestWithoutReviewMetric >> calculate [ | groupedByDate mergedMergeRequest noVerificationMergeRequests dateOver gitAnalyzer | groupedByDate := self setupGroupedDate. @@ -47,20 +47,20 @@ MergedMergeRequest >> calculate [ ] { #category : #accessing } -MergedMergeRequest >> description [ +MergedMergeRequestWithoutReviewMetric >> description [ - ^ 'number of merged merge request' + ^ 'number of merge requests merged without review' ] { #category : #loading } -MergedMergeRequest >> load [ +MergedMergeRequestWithoutReviewMetric >> load [ self loadUserProjects. self loadUserMergeRequests ] { #category : #accessing } -MergedMergeRequest >> name [ +MergedMergeRequestWithoutReviewMetric >> name [ - ^ 'mergedMergeRequest' + ^ 'mergeRequestMergedWithoutReview' ] diff --git a/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st new file mode 100644 index 0000000..3d0ff80 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st @@ -0,0 +1,42 @@ +Class { + #name : #OpenedMergeRequestMetric, + #superclass : #UserMetric, + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #calculating } +OpenedMergeRequestMetric >> calculate [ + + | groupedByDate dateOver | + groupedByDate := self setupGroupedDate. + + userMergeRequests do: [ :userMergeRequest | + dateOver := self transformDate: userMergeRequest created_at to: over. + + groupedByDate + at: dateOver printString + ifPresent: [ :value | value add: userMergeRequest ] ]. + + groupedByDate := groupedByDate collect: [ :group | group size ]. + + ^ groupedByDate +] + +{ #category : #accessing } +OpenedMergeRequestMetric >> description [ + + ^'number of opened merge request' +] + +{ #category : #loading } +OpenedMergeRequestMetric >> load [ + + self loadUserProjects. + self loadUserMergeRequests +] + +{ #category : #accessing } +OpenedMergeRequestMetric >> name [ + + ^'openedMergeRequest' +] From 6d97a4c84bfcd941fc79cc0acc98d706af269d54 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Wed, 28 Aug 2024 17:47:21 +0200 Subject: [PATCH 066/154] feat: CodeChurnMetric --- .../CodeChurnMetric.class.st | 91 +++++++++++++++++++ .../GitMetric4User.class.st | 15 +-- .../GitMetricExporter.class.st | 8 +- .../UserMetric.class.st | 23 +++++ 4 files changed, 120 insertions(+), 17 deletions(-) create mode 100644 src/GitLabHealth-Model-Analysis/CodeChurnMetric.class.st diff --git a/src/GitLabHealth-Model-Analysis/CodeChurnMetric.class.st b/src/GitLabHealth-Model-Analysis/CodeChurnMetric.class.st new file mode 100644 index 0000000..80a07b2 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/CodeChurnMetric.class.st @@ -0,0 +1,91 @@ +Class { + #name : #CodeChurnMetric, + #superclass : #UserMetric, + #instVars : [ + 'maxCommitWindow' + ], + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #calculating } +CodeChurnMetric >> calculate [ + + | commits res groupedByDate totalContributions gitAnalyzer | + totalContributions := OrderedCollection new. + groupedByDate := self setupGroupedDate. + gitAnalyzer := GitAnalyzer new + glhImporter: glhImporter; + maxChildCommit: maxCommitWindow. + glhImporter withCommitDiffs: false. + commits := self + foundSuccessorOf: userCommits + andCompleteImportForMax: maxCommitWindow. + + + res := commits collect: [ :commit | + commit -> (gitAnalyzer + fromCommit: commit; + analyseChurn) ]. + res do: [ :commits4Churns | + | commit allChurnsInCommit sumChurnInCommit overDate contribution churnOnCommit | + commit := commits4Churns key. + allChurnsInCommit := commits4Churns value. + sumChurnInCommit := (allChurnsInCommit at: #churns) sum: [ :churn | + | numerator | + numerator := churn value at: #churnLoC. + numerator ]. + contribution := allChurnsInCommit at: #totalContribution. + totalContributions add: contribution. + churnOnCommit := { + (#churnOnCommit -> sumChurnInCommit). + (#LoCOnCommit -> contribution) } asDictionary. + overDate := self transformDate: commit created_at to: over. + groupedByDate + at: overDate printString + ifPresent: [ :array | array add: churnOnCommit ] + ifAbsentPut: [ + OrderedCollection new + add: churnOnCommit; + yourself ] ]. + groupedByDate := groupedByDate collect: [ :churnsAtDate | + | totalChurn totalContribution percentage | + totalChurn := churnsAtDate sum: [ :churn | + churn at: #churnOnCommit ]. + totalContribution := churnsAtDate sum: [ :churn | + churn at: #LoCOnCommit ]. + totalContribution = 0 + ifTrue: [ percentage := 0 asFloat ] + ifFalse: [ + percentage := (totalChurn * 100 + / totalContribution) asFloat ]. + { + (#churn -> totalChurn). + (#contribution -> totalContribution). + (#percentage -> percentage) } asDictionary ]. + + ^ groupedByDate collect: [ :date | date at: #percentage ] +] + +{ #category : #accessing } +CodeChurnMetric >> description [ + + ^ 'churn % (W=' , maxCommitWindow printString , ')' +] + +{ #category : #initialization } +CodeChurnMetric >> initialize [ + maxCommitWindow := 3 +] + +{ #category : #loading } +CodeChurnMetric >> load [ + + self loadUserProjects. + self loadUserCommits. +] + +{ #category : #accessing } +CodeChurnMetric >> name [ + + ^ 'codeChurn' +] diff --git a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st index f2e21d7..d2c2774 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st @@ -139,20 +139,7 @@ GitMetric4User >> codeChurnSince: since until: until onACommitWindowOf: commitLi (#churn -> totalChurn). (#contribution -> totalContribution). (#percentage -> percentage) } asDictionary ]. - ^ { - (#details -> groupedByDate). - (#totalContribution -> (totalContributions - ifEmpty: [ 0 ] - ifNotEmpty: [ totalContributions sum ])). - (#totalChurn -> (groupedByDate sum: [ :date | date at: #churn ])). - (#churn - -> - (groupedByDate collect: [ :date | date at: #percentage ]) average). - (#overEach -> aDateWeekMonthOrYear name). - (#forOver -> (groupedByDate keys size printString - , aDateWeekMonthOrYear printString)). - (#userCommits -> commits size). - (#churnWindow -> commitLimit) } asDictionary + ^ groupedByDate collect: [ :date | date at: #percentage ] ] { #category : #'metrics - commits' } diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 96a870b..e5bec86 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -402,10 +402,12 @@ GitMetricExporter >> initialize [ ContributedProjectMetric new. TimeBetweenCommitMetric new. MergeRequestDurationMetric new. - OpenedMergeRequestMetric new. + OpenedMergeRequestMetric new. ClosedMergeRequestMetric new. - MergedMergeRequestMetric new. - MergedMergeRequestWithoutReviewMetric new } + MergedMergeRequestMetric new. + MergedMergeRequestWithoutReviewMetric new. + CodeChurnMetric new. + } ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/UserMetric.class.st b/src/GitLabHealth-Model-Analysis/UserMetric.class.st index 19fdc91..eef44a1 100644 --- a/src/GitLabHealth-Model-Analysis/UserMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserMetric.class.st @@ -29,6 +29,29 @@ UserMetric >> description [ ^ self subclassResponsibility ] +{ #category : #churn } +UserMetric >> foundSuccessorOf: commits andCompleteImportForMax: commitLimit [ + + | analyzingCommits gitAnalyzer | + analyzingCommits := Set new. + + gitAnalyzer := GitAnalyzer new + glhImporter: glhImporter; + maxChildCommit: commitLimit. + + glhImporter withCommitDiffs: true. + + userCommits do: [ :c | + gitAnalyzer + visitChildCommits: c childCommits + toStoreThemIn: analyzingCommits + upto: commitLimit ]. + + analyzingCommits do: [ :c | glhImporter completeImportedCommit: c ]. + + ^ analyzingCommits +] + { #category : #initialization } UserMetric >> initialize [ over := Date From 43f2e30e6f19a13777a6b5aaf7600ae060655f41 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Thu, 29 Aug 2024 09:25:14 +0200 Subject: [PATCH 067/154] feat: add ClosedTicketsMetric and DelayUntilFirstChurnMetric --- .../ClosedTicketsMetric.class.st | 58 ++++++++++++ .../DelayUntilFirstChurnMetric.class.st | 92 +++++++++++++++++++ .../GitMetricExporter.class.st | 49 +++++----- .../Metric.class.st | 9 +- 4 files changed, 184 insertions(+), 24 deletions(-) create mode 100644 src/GitLabHealth-Model-Analysis/ClosedTicketsMetric.class.st create mode 100644 src/GitLabHealth-Model-Analysis/DelayUntilFirstChurnMetric.class.st diff --git a/src/GitLabHealth-Model-Analysis/ClosedTicketsMetric.class.st b/src/GitLabHealth-Model-Analysis/ClosedTicketsMetric.class.st new file mode 100644 index 0000000..dc44456 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/ClosedTicketsMetric.class.st @@ -0,0 +1,58 @@ +Class { + #name : #ClosedTicketsMetric, + #superclass : #UserMetric, + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #calculating } +ClosedTicketsMetric >> calculate [ + + | groupedByDate dateOver average | + groupedByDate := self setupGroupedDate. + + + userMergeRequests do: [ :userMergeRequest | + dateOver := self transformDate: userMergeRequest created_at to: over. + groupedByDate + at: dateOver printString + ifPresent: [ :value | value add: userMergeRequest ] ]. + + groupedByDate := groupedByDate collect: [ :group | group size ]. + + average := groupedByDate + ifEmpty: [ 0 ] + ifNotEmpty: [ groupedByDate average ]. + + ^ groupedByDate +] + +{ #category : #accessing } +ClosedTicketsMetric >> description [ + + ^ 'number of merge request with jira ticket closed' +] + +{ #category : #loading } +ClosedTicketsMetric >> load [ + + self loadUserProjects. + self loadUserMergeRequests. + + jiraImporter importAllCurrentAndPastIssuesOf: + user commits anyOne author_email. + + GPJCConnector new + gpModel: glhImporter glhModel; + jiraModel: jiraImporter model; + connect. + + userMergeRequests := userMergeRequests select: [ :mergeRequest | + mergeRequest jiraIssue isNotNil ]. + +] + +{ #category : #accessing } +ClosedTicketsMetric >> name [ + + ^ 'closedTickets' +] diff --git a/src/GitLabHealth-Model-Analysis/DelayUntilFirstChurnMetric.class.st b/src/GitLabHealth-Model-Analysis/DelayUntilFirstChurnMetric.class.st new file mode 100644 index 0000000..976c89f --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/DelayUntilFirstChurnMetric.class.st @@ -0,0 +1,92 @@ +Class { + #name : #DelayUntilFirstChurnMetric, + #superclass : #UserMetric, + #instVars : [ + 'maxCommitWindow' + ], + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #calculating } +DelayUntilFirstChurnMetric >> calculate [ + + | commits groupedByDate res | + groupedByDate := self setupGroupedDate. + commits := self + foundSuccessorOf: userCommits + andCompleteImportForMax: maxCommitWindow. + + + "class commit by dates, filter none user commits" + commits do: [ :commit | + commit commitCreator = user ifTrue: [ + | overDate | + overDate := self transformDate: commit created_at to: over. + + groupedByDate + at: overDate printString + ifPresent: [ :arrayOfCommits | arrayOfCommits add: commit ] + ifAbsentPut: [ + OrderedCollection new + add: commit; + yourself ] ] ]. + + + + res := groupedByDate collect: [ :commits4Date | + | durationFromA2B | + commits4Date collect: [ :commitA | + | commitB | + commitB := GitAnalyzer new + glhImporter: glhImporter; + fromCommit: commitA; + maxChildCommit: maxCommitWindow; + analyseDelayUntilFirstChurn. + + durationFromA2B := commitB + ifNil: [ 0 ] + ifNotNil: [ + commitB created_at - commitA created_at ]. + durationFromA2B ] ]. + + + + res := res collect: [ :durationsByDate | + | filtered | + filtered := durationsByDate reject: [ :value | value = 0 ]. + filtered isEmpty + ifTrue: [ nil ] + ifFalse: [ + (filtered sum: [ :v | v asDuration asSeconds ]) + / filtered size ] ]. + + res := res reject: #isNil. + + ^ res +] + +{ #category : #accessing } +DelayUntilFirstChurnMetric >> description [ + + ^ 'delay Until First Churn (W=' , maxCommitWindow printString + , ')' +] + +{ #category : #initialization } +DelayUntilFirstChurnMetric >> initialize [ + super initialize. + maxCommitWindow := 3 +] + +{ #category : #loading } +DelayUntilFirstChurnMetric >> load [ + + self loadUserProjects. + self loadUserCommits. +] + +{ #category : #accessing } +DelayUntilFirstChurnMetric >> name [ + + ^'delayUntilFirstChurn' +] diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index e5bec86..218450a 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -116,27 +116,29 @@ GitMetricExporter >> calculateAllMetricsOver: aDateWeekMonthOrYear [ | userAnalysisReport result analysesReport | runningPeriods do: [ :period | analysesReport := entities collect: [ :entity | - userAnalysisReport := UserAnalysisReport new - username: entity user name; - period: period; - over: aDateWeekMonthOrYear. - - metrics do: [ :metric | - metric - glhImporter: glhImporter; - setPeriodSince: (period at: #since) until: (period at: #until); - over: aDateWeekMonthOrYear; - user: entity user. - - - metric load. - result := metric calculate. - userAnalysisReport metrics at: metric name put: result ]. - - userAnalysisReport - ]. -self analyses addAll: analysesReport. -]. + userAnalysisReport := UserAnalysisReport new + username: entity user name; + period: period; + over: aDateWeekMonthOrYear. + + metrics do: [ :metric | + metric + glhImporter: glhImporter; + jiraImporter: jiraImporter; + setPeriodSince: (period at: #since) + until: (period at: #until); + over: aDateWeekMonthOrYear; + user: entity user. + + + metric load. + result := metric calculate. + userAnalysisReport metrics + at: metric name + put: result ]. + + userAnalysisReport ]. + self analyses addAll: analysesReport ]. ^ analyses ] @@ -399,6 +401,8 @@ GitMetricExporter >> initialize [ CodeDeletionMetric new. CommentContributionMetric new. CommitFrequencyMetric new. + CodeChurnMetric new. + DelayUntilFirstChurnMetric new. ContributedProjectMetric new. TimeBetweenCommitMetric new. MergeRequestDurationMetric new. @@ -406,8 +410,7 @@ GitMetricExporter >> initialize [ ClosedMergeRequestMetric new. MergedMergeRequestMetric new. MergedMergeRequestWithoutReviewMetric new. - CodeChurnMetric new. - } + ClosedTicketsMetric new } ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/Metric.class.st b/src/GitLabHealth-Model-Analysis/Metric.class.st index a4b0949..912cf06 100644 --- a/src/GitLabHealth-Model-Analysis/Metric.class.st +++ b/src/GitLabHealth-Model-Analysis/Metric.class.st @@ -4,7 +4,8 @@ Class { #instVars : [ 'period', 'over', - 'glhImporter' + 'glhImporter', + 'jiraImporter' ], #category : #'GitLabHealth-Model-Analysis' } @@ -27,6 +28,12 @@ Metric >> glhImporter: anObject [ glhImporter := anObject ] +{ #category : #accessing } +Metric >> jiraImporter: anObject [ + + jiraImporter := anObject +] + { #category : #loading } Metric >> load [ ^self subclassResponsibility From decf6ed7b6db6ffc52285ef368b52eb0217a48bd Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Thu, 29 Aug 2024 09:33:00 +0200 Subject: [PATCH 068/154] fix: remove metrics variable --- src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 218450a..3875ef4 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -11,8 +11,7 @@ Class { 'runningPeriods', 'maxCommitWindow', 'over', - 'analyses', - 'metrics' + 'analyses' ], #category : #'GitLabHealth-Model-Analysis' } From 71d0d878d8efcb5c80578674ad9b0bd671748161 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Thu, 29 Aug 2024 10:52:53 +0200 Subject: [PATCH 069/154] refactor: change caculate to return average --- .../ClosedMergeRequestMetric.class.st | 11 ++---- .../ClosedTicketsMetric.class.st | 13 ++----- .../CodeAdditionMetric.class.st | 7 +--- .../CodeChurnMetric.class.st | 2 +- .../CodeDeletionMetric.class.st | 2 +- .../CommentContributionMetric.class.st | 5 +-- .../CommitFrequencyMetric.class.st | 2 +- .../ContributedProjectMetric.class.st | 2 +- .../DelayUntilFirstChurnMetric.class.st | 8 +++- .../GitMetricExporter.class.st | 37 ++++--------------- .../MergeRequestDurationMetric.class.st | 2 +- .../MergedMergeRequestMetric.class.st | 9 ++--- ...edMergeRequestWithoutReviewMetric.class.st | 2 +- .../OpenedMergeRequestMetric.class.st | 2 +- .../TimeBetweenCommitMetric.class.st | 8 +++- .../UserMetric.class.st | 16 +++++++- 16 files changed, 57 insertions(+), 71 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st index f61ebe2..4627f09 100644 --- a/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st @@ -8,8 +8,7 @@ Class { ClosedMergeRequestMetric >> calculate [ | groupedByDate userClosedMergeRequests dateOver | - groupedByDate := self - setupGroupedDate. + groupedByDate := self setupGroupedDate. userClosedMergeRequests := userMergeRequests select: [ :userMergeRequest | @@ -17,9 +16,7 @@ ClosedMergeRequestMetric >> calculate [ userMergeRequest state = 'closed' ]. userClosedMergeRequests do: [ :userMergeRequest | - dateOver := self - transformDate: userMergeRequest created_at - to: over. + dateOver := self transformDate: userMergeRequest created_at to: over. groupedByDate at: dateOver printString @@ -27,9 +24,9 @@ ClosedMergeRequestMetric >> calculate [ groupedByDate := groupedByDate collect: [ :group | group size ]. + - - ^ groupedByDate + ^ groupedByDate average asFloat ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/ClosedTicketsMetric.class.st b/src/GitLabHealth-Model-Analysis/ClosedTicketsMetric.class.st index dc44456..8f1f850 100644 --- a/src/GitLabHealth-Model-Analysis/ClosedTicketsMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/ClosedTicketsMetric.class.st @@ -7,7 +7,7 @@ Class { { #category : #calculating } ClosedTicketsMetric >> calculate [ - | groupedByDate dateOver average | + | groupedByDate dateOver | groupedByDate := self setupGroupedDate. @@ -19,11 +19,7 @@ ClosedTicketsMetric >> calculate [ groupedByDate := groupedByDate collect: [ :group | group size ]. - average := groupedByDate - ifEmpty: [ 0 ] - ifNotEmpty: [ groupedByDate average ]. - - ^ groupedByDate + ^ groupedByDate average asFloat ] { #category : #accessing } @@ -39,7 +35,7 @@ ClosedTicketsMetric >> load [ self loadUserMergeRequests. jiraImporter importAllCurrentAndPastIssuesOf: - user commits anyOne author_email. + self userEmail. GPJCConnector new gpModel: glhImporter glhModel; @@ -47,8 +43,7 @@ ClosedTicketsMetric >> load [ connect. userMergeRequests := userMergeRequests select: [ :mergeRequest | - mergeRequest jiraIssue isNotNil ]. - + mergeRequest jiraIssue isNotNil ] ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/CodeAdditionMetric.class.st b/src/GitLabHealth-Model-Analysis/CodeAdditionMetric.class.st index 9b1dfa5..c79d017 100644 --- a/src/GitLabHealth-Model-Analysis/CodeAdditionMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CodeAdditionMetric.class.st @@ -30,12 +30,9 @@ CodeAdditionMetric >> calculate [ yourself ] ]. groupedByDate := groupedByDate collect: [ :contribs | - - contribs sum: [ :v | v at: #addition ]. - - ]. + contribs sum: [ :v | v at: #addition ] ]. - ^ groupedByDate + ^ groupedByDate average asFloat ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/CodeChurnMetric.class.st b/src/GitLabHealth-Model-Analysis/CodeChurnMetric.class.st index 80a07b2..d58d07a 100644 --- a/src/GitLabHealth-Model-Analysis/CodeChurnMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CodeChurnMetric.class.st @@ -63,7 +63,7 @@ CodeChurnMetric >> calculate [ (#contribution -> totalContribution). (#percentage -> percentage) } asDictionary ]. - ^ groupedByDate collect: [ :date | date at: #percentage ] + ^ (groupedByDate collect: [ :date | date at: #percentage ]) average ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/CodeDeletionMetric.class.st b/src/GitLabHealth-Model-Analysis/CodeDeletionMetric.class.st index 6010269..223eef3 100644 --- a/src/GitLabHealth-Model-Analysis/CodeDeletionMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CodeDeletionMetric.class.st @@ -32,7 +32,7 @@ CodeDeletionMetric >> calculate [ groupedByDate := groupedByDate collect: [ :contribs | contribs sum: [ :v | v at: #deletion ] ]. - ^ groupedByDate + ^ groupedByDate average asFloat ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st b/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st index 1391e82..5e6642c 100644 --- a/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st @@ -8,8 +8,7 @@ Class { CommentContributionMetric >> calculate [ | groupedByDate gitAnalyzer contributions | - groupedByDate := self - setupGroupedDate. + groupedByDate := self setupGroupedDate. gitAnalyzer := GitAnalyzer new glhImporter: glhImporter. @@ -36,7 +35,7 @@ CommentContributionMetric >> calculate [ ifEmpty: [ 0 ] ]. - ^ groupedByDate + ^ groupedByDate average asFloat ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/CommitFrequencyMetric.class.st b/src/GitLabHealth-Model-Analysis/CommitFrequencyMetric.class.st index 6b580cd..17d2d48 100644 --- a/src/GitLabHealth-Model-Analysis/CommitFrequencyMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CommitFrequencyMetric.class.st @@ -17,7 +17,7 @@ CommitFrequencyMetric >> calculate [ groupedByDate := groupedByDate collect: [ :group | group size ]. - ^ groupedByDate + ^ groupedByDate average asFloat ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/ContributedProjectMetric.class.st b/src/GitLabHealth-Model-Analysis/ContributedProjectMetric.class.st index e91e007..7402ea3 100644 --- a/src/GitLabHealth-Model-Analysis/ContributedProjectMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/ContributedProjectMetric.class.st @@ -21,7 +21,7 @@ ContributedProjectMetric >> calculate [ projects := Set newFrom: group. projects size ]. - ^ groupedByDate + ^ groupedByDate average asFloat ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/DelayUntilFirstChurnMetric.class.st b/src/GitLabHealth-Model-Analysis/DelayUntilFirstChurnMetric.class.st index 976c89f..d5e1778 100644 --- a/src/GitLabHealth-Model-Analysis/DelayUntilFirstChurnMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/DelayUntilFirstChurnMetric.class.st @@ -10,7 +10,7 @@ Class { { #category : #calculating } DelayUntilFirstChurnMetric >> calculate [ - | commits groupedByDate res | + | commits groupedByDate res average | groupedByDate := self setupGroupedDate. commits := self foundSuccessorOf: userCommits @@ -62,7 +62,11 @@ DelayUntilFirstChurnMetric >> calculate [ res := res reject: #isNil. - ^ res + average := res + ifEmpty: [ nil ] + ifNotEmpty: [ res values average asFloat ]. + + ^ average ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 543275d..09ccc89 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -12,7 +12,8 @@ Class { 'maxCommitWindow', 'over', 'analyses', - 'emailDomain' + 'emailDomain', + 'metrics' ], #category : #'GitLabHealth-Model-Analysis' } @@ -117,18 +118,19 @@ GitMetricExporter >> calculateAllMetricsOver: aDateWeekMonthOrYear [ runningPeriods do: [ :period | analysesReport := entities collect: [ :entity | userAnalysisReport := UserAnalysisReport new - username: entity user name; + username: entity name; period: period; over: aDateWeekMonthOrYear. metrics do: [ :metric | metric glhImporter: glhImporter; - jiraImporter: jiraImporter; + jiraImporter: jiraImporter; setPeriodSince: (period at: #since) until: (period at: #until); over: aDateWeekMonthOrYear; - user: entity user. + user: entity; + emailDomain: emailDomain. metric load. @@ -170,7 +172,7 @@ GitMetricExporter >> csvMetricsFor: date [ analysis ifNil: [ nil ] ifNotNil: [ - (analysis metrics at: metric name) average ] ] ]. + analysis metrics at: metric name ] ] ]. ^ csvMetrics asOrderedDictionary ] @@ -447,30 +449,7 @@ GitMetricExporter >> setupAnalysisForUsersWithNames: userNames [ glhImporter userCatalogue scrapeAuthorNamesForUsers: users. - entities addAll: (users collect: [ :user | - | itsProjects metrics i size | - itsProjects := glhImporter importContributedProjectsOfUser: user. - - metrics := GitMetric4User new. - metrics - glhImporter: glhImporter; - jiraImporter: jiraImporter; - withUserEmailDomain: emailDomain; - user: user. - - i := 0. - size := itsProjects size. - metrics itsProjects: (itsProjects collect: [ :p | - (' ' join: { - 'complete import of project:'. - p name printString. - '['. - (i := i + 1) printString. - '/'. - size. - ']' }) recordInfo. - - p id -> (glhImporter completeImportProject: p) ]) asDictionary ]). + entities addAll: users. ^ self ] diff --git a/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st b/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st index 87aa167..5083885 100644 --- a/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st @@ -46,7 +46,7 @@ MergeRequestDurationMetric >> calculate [ filterGroups at: assoc key put: sum / denominator ]. - ^ filterGroups + ^ filterGroups average asDuration ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st index e5402d8..235e526 100644 --- a/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st @@ -8,23 +8,20 @@ Class { MergedMergeRequestMetric >> calculate [ | groupedByDate userMergedMergeRequests dateOver | - groupedByDate := self - setupGroupedDate. + groupedByDate := self setupGroupedDate. userMergedMergeRequests := userMergeRequests select: [ :userMergeRequest | userMergeRequest merged_at isNotNil ]. userMergedMergeRequests do: [ :userMergeRequest | - dateOver := self - transformDate: userMergeRequest created_at - to: over. + dateOver := self transformDate: userMergeRequest created_at to: over. groupedByDate at: dateOver printString ifPresent: [ :value | value add: userMergeRequest ] ]. groupedByDate := groupedByDate collect: [ :group | group size ]. - ^ groupedByDate + ^ groupedByDate average asFloat ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/MergedMergeRequestWithoutReviewMetric.class.st b/src/GitLabHealth-Model-Analysis/MergedMergeRequestWithoutReviewMetric.class.st index f53e798..48c339e 100644 --- a/src/GitLabHealth-Model-Analysis/MergedMergeRequestWithoutReviewMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/MergedMergeRequestWithoutReviewMetric.class.st @@ -43,7 +43,7 @@ MergedMergeRequestWithoutReviewMetric >> calculate [ groupedByDate := groupedByDate collect: [ :group | group size ]. - ^ groupedByDate + ^ groupedByDate average asFloat ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st index 3d0ff80..e20ec33 100644 --- a/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st @@ -19,7 +19,7 @@ OpenedMergeRequestMetric >> calculate [ groupedByDate := groupedByDate collect: [ :group | group size ]. - ^ groupedByDate + ^ groupedByDate average asFloat ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st b/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st index 17c368c..febf3eb 100644 --- a/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st @@ -7,7 +7,7 @@ Class { { #category : #calculating } TimeBetweenCommitMetric >> calculate [ - | commitSortedByDate commits1 commits2 differences groupedByDate dateOver | + | commitSortedByDate commits1 commits2 differences groupedByDate dateOver average | groupedByDate := self setupGroupedDate. commitSortedByDate := userCommits sorted: [ :commit1 :commit2 | @@ -34,8 +34,12 @@ TimeBetweenCommitMetric >> calculate [ asSeconds ]. differences average asDuration ]. + + average := groupedByDate + ifEmpty: [ nil ] + ifNotEmpty: [ groupedByDate average ]. - ^ groupedByDate + ^ average ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/UserMetric.class.st b/src/GitLabHealth-Model-Analysis/UserMetric.class.st index eef44a1..a88e4f6 100644 --- a/src/GitLabHealth-Model-Analysis/UserMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserMetric.class.st @@ -5,7 +5,8 @@ Class { 'user', 'userProjects', 'userCommits', - 'userMergeRequests' + 'userMergeRequests', + 'emailDomain' ], #category : #'GitLabHealth-Model-Analysis' } @@ -29,6 +30,12 @@ UserMetric >> description [ ^ self subclassResponsibility ] +{ #category : #accessing } +UserMetric >> emailDomain: anObject [ + + emailDomain := anObject +] + { #category : #churn } UserMetric >> foundSuccessorOf: commits andCompleteImportForMax: commitLimit [ @@ -141,3 +148,10 @@ UserMetric >> user: anObject [ user := anObject ] + +{ #category : #email } +UserMetric >> userEmail [ + ^ ('' join: { + user username. + emailDomain }) asLowercase +] From d3b0b3dacfa451aecbb25fdb2706b538bff2e0ca Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Thu, 29 Aug 2024 14:34:13 +0200 Subject: [PATCH 070/154] fix: improve performance --- .../ClosedMergeRequestMetric.class.st | 6 +- .../ClosedTicketsMetric.class.st | 15 +-- .../CodeAdditionMetric.class.st | 6 +- .../CodeChurnMetric.class.st | 14 +- .../CodeDeletionMetric.class.st | 6 +- .../CommentContributionMetric.class.st | 8 +- .../CommitFrequencyMetric.class.st | 4 +- .../ContributedProjectMetric.class.st | 4 +- .../DelayUntilFirstChurnMetric.class.st | 14 +- .../GitMetric4User.class.st | 124 ++++++++++++++---- .../GitMetricExporter.class.st | 71 +++++----- .../MergeRequestDurationMetric.class.st | 9 +- .../MergedMergeRequestMetric.class.st | 7 +- ...edMergeRequestWithoutReviewMetric.class.st | 13 +- .../Metric.class.st | 16 +-- .../OpenedMergeRequestMetric.class.st | 7 +- .../TimeBetweenCommitMetric.class.st | 10 +- .../UserMetric.class.st | 67 +--------- 18 files changed, 202 insertions(+), 199 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st index 4627f09..a2d06e8 100644 --- a/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st @@ -8,6 +8,7 @@ Class { ClosedMergeRequestMetric >> calculate [ | groupedByDate userClosedMergeRequests dateOver | + userMergeRequests ifNil: [ self load ]. groupedByDate := self setupGroupedDate. userClosedMergeRequests := userMergeRequests select: [ @@ -24,7 +25,7 @@ ClosedMergeRequestMetric >> calculate [ groupedByDate := groupedByDate collect: [ :group | group size ]. - + ^ groupedByDate average asFloat ] @@ -38,8 +39,7 @@ ClosedMergeRequestMetric >> description [ { #category : #loading } ClosedMergeRequestMetric >> load [ - self loadUserProjects. - self loadUserMergeRequests + userMergeRequests := user loadMergeRequestsSince: (period at: #since) until: (period at: #until). ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/ClosedTicketsMetric.class.st b/src/GitLabHealth-Model-Analysis/ClosedTicketsMetric.class.st index 8f1f850..3ac67e5 100644 --- a/src/GitLabHealth-Model-Analysis/ClosedTicketsMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/ClosedTicketsMetric.class.st @@ -8,6 +8,7 @@ Class { ClosedTicketsMetric >> calculate [ | groupedByDate dateOver | + userMergeRequests ifNil: [ self load ]. groupedByDate := self setupGroupedDate. @@ -31,19 +32,7 @@ ClosedTicketsMetric >> description [ { #category : #loading } ClosedTicketsMetric >> load [ - self loadUserProjects. - self loadUserMergeRequests. - - jiraImporter importAllCurrentAndPastIssuesOf: - self userEmail. - - GPJCConnector new - gpModel: glhImporter glhModel; - jiraModel: jiraImporter model; - connect. - - userMergeRequests := userMergeRequests select: [ :mergeRequest | - mergeRequest jiraIssue isNotNil ] + userMergeRequests := user loadMergeRequesWithJiraIssueSince: (period at: #since) until: (period at: #until). ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/CodeAdditionMetric.class.st b/src/GitLabHealth-Model-Analysis/CodeAdditionMetric.class.st index c79d017..37c4e28 100644 --- a/src/GitLabHealth-Model-Analysis/CodeAdditionMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CodeAdditionMetric.class.st @@ -8,9 +8,10 @@ Class { CodeAdditionMetric >> calculate [ | gitAnalyzer contributions groupedByDate | + userCommits ifNil: [ self load ]. groupedByDate := self setupGroupedDate. - gitAnalyzer := GitAnalyzer new glhImporter: glhImporter. + gitAnalyzer := GitAnalyzer new. contributions := userCommits collect: [ :commit | commit -> (gitAnalyzer @@ -44,8 +45,7 @@ CodeAdditionMetric >> description [ { #category : #loading } CodeAdditionMetric >> load [ - self loadUserProjects. - self loadUserCommits + userCommits := user loadCommitsSince: (period at: #since) until: (period at: #until). ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/CodeChurnMetric.class.st b/src/GitLabHealth-Model-Analysis/CodeChurnMetric.class.st index d58d07a..8244f30 100644 --- a/src/GitLabHealth-Model-Analysis/CodeChurnMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CodeChurnMetric.class.st @@ -11,17 +11,16 @@ Class { CodeChurnMetric >> calculate [ | commits res groupedByDate totalContributions gitAnalyzer | + userCommits ifNil: [ self load ]. + totalContributions := OrderedCollection new. groupedByDate := self setupGroupedDate. - gitAnalyzer := GitAnalyzer new - glhImporter: glhImporter; - maxChildCommit: maxCommitWindow. - glhImporter withCommitDiffs: false. - commits := self + gitAnalyzer := GitAnalyzer new maxChildCommit: maxCommitWindow. + + commits := user foundSuccessorOf: userCommits andCompleteImportForMax: maxCommitWindow. - res := commits collect: [ :commit | commit -> (gitAnalyzer fromCommit: commit; @@ -80,8 +79,7 @@ CodeChurnMetric >> initialize [ { #category : #loading } CodeChurnMetric >> load [ - self loadUserProjects. - self loadUserCommits. + userCommits := user loadCommitsSince: (period at: #since) until: (period at: #until) ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/CodeDeletionMetric.class.st b/src/GitLabHealth-Model-Analysis/CodeDeletionMetric.class.st index 223eef3..68dcc06 100644 --- a/src/GitLabHealth-Model-Analysis/CodeDeletionMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CodeDeletionMetric.class.st @@ -8,9 +8,10 @@ Class { CodeDeletionMetric >> calculate [ | gitAnalyzer contributions groupedByDate | + userCommits ifNil: [ self load ]. groupedByDate := self setupGroupedDate. - gitAnalyzer := GitAnalyzer new glhImporter: glhImporter. + gitAnalyzer := GitAnalyzer new. contributions := userCommits collect: [ :commit | commit -> (gitAnalyzer @@ -44,8 +45,7 @@ CodeDeletionMetric >> description [ { #category : #loading } CodeDeletionMetric >> load [ - self loadUserProjects. - self loadUserCommits + userCommits := user loadCommitsSince: (period at: #since) until: (period at: #until) ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st b/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st index 5e6642c..d451f9f 100644 --- a/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st @@ -8,9 +8,10 @@ Class { CommentContributionMetric >> calculate [ | groupedByDate gitAnalyzer contributions | + userCommits ifNil: [ self load ]. groupedByDate := self setupGroupedDate. - gitAnalyzer := GitAnalyzer new glhImporter: glhImporter. + gitAnalyzer := GitAnalyzer new. contributions := userCommits collect: [ :commit | commit -> (gitAnalyzer @@ -47,10 +48,7 @@ CommentContributionMetric >> description [ { #category : #loading } CommentContributionMetric >> load [ - self loadUserProjects. - self loadUserCommits. - - userCommits do: [ :commit | glhImporter completeImportedCommit: commit ]. + userCommits := user loadCompleteCommitsSince: (period at: #since) until: (period at: #until). ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/CommitFrequencyMetric.class.st b/src/GitLabHealth-Model-Analysis/CommitFrequencyMetric.class.st index 17d2d48..11501d9 100644 --- a/src/GitLabHealth-Model-Analysis/CommitFrequencyMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CommitFrequencyMetric.class.st @@ -8,6 +8,7 @@ Class { CommitFrequencyMetric >> calculate [ | groupedByDate | + userCommits ifNil: [ self load ]. groupedByDate := self setupGroupedDate. userCommits do: [ :c | @@ -29,8 +30,7 @@ CommitFrequencyMetric >> description [ { #category : #loading } CommitFrequencyMetric >> load [ - self loadUserProjects. - self loadUserCommits. + userCommits := user loadCommitsSince: (period at: #since) until: (period at: #until). ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/ContributedProjectMetric.class.st b/src/GitLabHealth-Model-Analysis/ContributedProjectMetric.class.st index 7402ea3..16a9e0e 100644 --- a/src/GitLabHealth-Model-Analysis/ContributedProjectMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/ContributedProjectMetric.class.st @@ -8,6 +8,7 @@ Class { ContributedProjectMetric >> calculate [ | groupedByDate dateOver projects | + userCommits ifNil: [ self load ]. groupedByDate := self setupGroupedDate. userCommits do: [ :userCommit | @@ -33,8 +34,7 @@ ContributedProjectMetric >> description [ { #category : #loading } ContributedProjectMetric >> load [ - self loadUserProjects. - self loadUserCommits. + userCommits := user loadCommitsSince: (period at: #since) until: (period at: #until). ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/DelayUntilFirstChurnMetric.class.st b/src/GitLabHealth-Model-Analysis/DelayUntilFirstChurnMetric.class.st index d5e1778..f1ca836 100644 --- a/src/GitLabHealth-Model-Analysis/DelayUntilFirstChurnMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/DelayUntilFirstChurnMetric.class.st @@ -11,15 +11,16 @@ Class { DelayUntilFirstChurnMetric >> calculate [ | commits groupedByDate res average | + userCommits ifNil: [ self load ]. groupedByDate := self setupGroupedDate. - commits := self + commits := user foundSuccessorOf: userCommits andCompleteImportForMax: maxCommitWindow. "class commit by dates, filter none user commits" commits do: [ :commit | - commit commitCreator = user ifTrue: [ + commit commitCreator = user user ifTrue: [ | overDate | overDate := self transformDate: commit created_at to: over. @@ -38,7 +39,6 @@ DelayUntilFirstChurnMetric >> calculate [ commits4Date collect: [ :commitA | | commitB | commitB := GitAnalyzer new - glhImporter: glhImporter; fromCommit: commitA; maxChildCommit: maxCommitWindow; analyseDelayUntilFirstChurn. @@ -59,7 +59,7 @@ DelayUntilFirstChurnMetric >> calculate [ ifFalse: [ (filtered sum: [ :v | v asDuration asSeconds ]) / filtered size ] ]. - + res := res reject: #isNil. average := res @@ -85,8 +85,10 @@ DelayUntilFirstChurnMetric >> initialize [ { #category : #loading } DelayUntilFirstChurnMetric >> load [ - self loadUserProjects. - self loadUserCommits. + + userCommits := user + loadCommitsSince: (period at: #since) + until: (period at: #until) ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st index b952730..3677a48 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st @@ -537,20 +537,21 @@ GitMetric4User >> delayUntilFirstChurnSince: since until: until overA: aDateWeek { #category : #churn } GitMetric4User >> foundSuccessorOf: userCommits andCompleteImportForMax: commitLimit [ - | analyzingCommits i size| + | analyzingCommits i size | analyzingCommits := Set new. glhImporter withCommitDiffs: true. userCommits do: [ :c | - gitAnalyzer + GitAnalyzer new visitChildCommits: c childCommits toStoreThemIn: analyzingCommits upto: commitLimit ]. i := 0. - size := analyzingCommits size. + size := analyzingCommits size. analyzingCommits do: [ :c | - ('import complete commits [' , (i:=i+1) printString, '/', size printString , ']' ) recordInfo. + ('import complete commits [' , (i := i + 1) printString , '/' + , size printString , ']') recordInfo. glhImporter completeImportedCommit: c ]. ^ analyzingCommits @@ -649,10 +650,9 @@ GitMetric4User >> generateAnalysisForPeriod: period over: aDateWeekMonthOrYear w GitMetric4User >> initialize [ user := GLHUser new. - itsProjects := Dictionary new. itsCommits := Dictionary new. itsMergeRequests := Dictionary new. - + emailDomain := '@generic-domain.com' ] @@ -679,17 +679,71 @@ GitMetric4User >> loadCommitOfProjects: aCollection since: aTimespan [ ] { #category : #loading } -GitMetric4User >> loadItsMergeRequesWithJiraIssueSince: since until: until [ +GitMetric4User >> loadCommitsSince: since until: until [ + + | cacheSymbol allCommits userCommits | + itsProjects ifNil: [ self loadProjects ]. + + glhImporter withCommitDiffs: false. + + cacheSymbol := self + cacheSymbolFor: GLHCommit + since: since + until: until. + + "download commits unless project cache is not empty" + allCommits := itsProjects collect: [ :project | + project repository cacheAt: cacheSymbol ifAbsentPut: [ + | foundCommits | + foundCommits := glhImporter + importCommitsOProject: project + since: since + until: until. + foundCommits ] ]. + + allCommits := allCommits flatten. + allCommits do: [ :commit | glhImporter importCreatorOfCommit: commit ]. + glhImporter chainsCommitsFrom: allCommits. + glhImporter withCommitDiffs: true. + + ^ userCommits := allCommits reject: [ :commit | + commit commitCreator ~= user ] +] + +{ #category : #loading } +GitMetric4User >> loadCompleteCommitsSince: since until: until [ + + | commits | + commits := self loadCommitsSince: since until: until. + commits do: [ :commit | glhImporter completeImportedCommit: commit ]. + ^commits + + +] + +{ #category : #loading } +GitMetric4User >> loadCompleteMergeRequestsSince: since until: until [ - |email| + | mergeRequests | + mergeRequests := self loadMergeRequestsSince: since until: until. + + mergeRequests do: [ :mergeRequest | + glhImporter importMergeResquestMerger: mergeRequest ]. + + ^mergeRequests +] + +{ #category : #loading } +GitMetric4User >> loadMergeRequesWithJiraIssueSince: since until: until [ + + | email | itsMergeRequests := self - loadItsMergeRequestsSince: since + loadMergeRequestsSince: since until: until. - email := self userEmail. + email := self userEmail. - jiraImporter importAllCurrentAndPastIssuesOf: - email. + jiraImporter importAllCurrentAndPastIssuesOf: email. GPJCConnector new gpModel: glhImporter glhModel; @@ -701,26 +755,46 @@ GitMetric4User >> loadItsMergeRequesWithJiraIssueSince: since until: until [ ] { #category : #loading } -GitMetric4User >> loadItsMergeRequestsSince: since until: until [ +GitMetric4User >> loadMergeRequestsSince: since until: until [ + + | cacheSymbol mergeRequests userMergeRequests | + itsProjects ifNil: [ self loadProjects ]. + glhImporter withCommitDiffs: false. + cacheSymbol := self + cacheSymbolFor: GLPHEMergeRequest + since: since + until: until. - | mergeRequests | - gitAnalyzer := GitAnalyzer new - glhImporter: glhImporter; - onModel: glhModel. + mergeRequests := itsProjects collect: [ :project | + | mr | + project cacheAt: cacheSymbol ifAbsentPut: [ + mr := glhImporter + importMergeRequests: project + since: since + until: until. + mr ] ]. - glhImporter withCommitDiffs: false. - mergeRequests := self - loadMergeRequestsFromProjectsIds: itsProjects keys - since: since - until: until. + mergeRequests := mergeRequests flattened. glhImporter withCommitDiffs: true. mergeRequests do: [ :mr | glhImporter importMergeResquestAuthor: mr ]. - itsMergeRequests := mergeRequests select: [ :mergeRequest | - mergeRequest author = self user ]. + userMergeRequests := mergeRequests select: [ :mergeRequest | + mergeRequest author = user ]. + ^ userMergeRequests +] + +{ #category : #loading } +GitMetric4User >> loadProjects [ + + itsProjects ifNotNil: [ ^ itsProjects ]. + + itsProjects := glhImporter importContributedProjectsOfUser: user. + + itsProjects do: [ :project | + glhImporter completeImportProject: project ]. - ^ itsMergeRequests + ^ itsProjects ] { #category : #'metrics - merge request' } diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 09ccc89..82c34db 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -114,29 +114,26 @@ GitMetricExporter >> analyses: anObject [ { #category : #calculating } GitMetricExporter >> calculateAllMetricsOver: aDateWeekMonthOrYear [ - | userAnalysisReport result analysesReport | + | userAnalysisReport result analysesReport newMetric | runningPeriods do: [ :period | analysesReport := entities collect: [ :entity | userAnalysisReport := UserAnalysisReport new - username: entity name; + username: entity user name; period: period; over: aDateWeekMonthOrYear. metrics do: [ :metric | - metric - glhImporter: glhImporter; - jiraImporter: jiraImporter; - setPeriodSince: (period at: #since) - until: (period at: #until); - over: aDateWeekMonthOrYear; - user: entity; - emailDomain: emailDomain. - - - metric load. - result := metric calculate. + newMetric := metric new + setPeriodSince: + (period at: #since) + until: (period at: #until); + over: aDateWeekMonthOrYear; + user: entity. + + + result := newMetric calculate. userAnalysisReport metrics - at: metric name + at: newMetric name put: result ]. userAnalysisReport ]. @@ -163,7 +160,7 @@ GitMetricExporter >> csvMetricsFor: date [ | csvMetrics | csvMetrics := metrics collect: [ :metric | - metric description , ' - ' , date asString + metric new description , ' - ' , date asString -> [ :groupAnalyses | | analysis | analysis := self @@ -172,7 +169,7 @@ GitMetricExporter >> csvMetricsFor: date [ analysis ifNil: [ nil ] ifNotNil: [ - analysis metrics at: metric name ] ] ]. + analysis metrics at: metric new name ] ] ]. ^ csvMetrics asOrderedDictionary ] @@ -399,20 +396,20 @@ GitMetricExporter >> initialize [ analyses := OrderedCollection new. metrics := { - CodeAdditionMetric new. - CodeDeletionMetric new. - CommentContributionMetric new. - CommitFrequencyMetric new. - CodeChurnMetric new. - DelayUntilFirstChurnMetric new. - ContributedProjectMetric new. - TimeBetweenCommitMetric new. - MergeRequestDurationMetric new. - OpenedMergeRequestMetric new. - ClosedMergeRequestMetric new. - MergedMergeRequestMetric new. - MergedMergeRequestWithoutReviewMetric new. - ClosedTicketsMetric new } + CodeAdditionMetric. + CodeDeletionMetric. + CommentContributionMetric. + CommitFrequencyMetric. + CodeChurnMetric + "DelayUntilFirstChurnMetric. + TimeBetweenCommitMetric. + ContributedProjectMetric. + MergeRequestDurationMetric. + OpenedMergeRequestMetric. + ClosedMergeRequestMetric. + MergedMergeRequestMetric. + MergedMergeRequestWithoutReviewMetric. + ClosedTicketsMetric " } ] { #category : #accessing } @@ -449,7 +446,17 @@ GitMetricExporter >> setupAnalysisForUsersWithNames: userNames [ glhImporter userCatalogue scrapeAuthorNamesForUsers: users. - entities addAll: users. + entities addAll: (users collect: [ :user | + | metricUser | + metricUser := GitMetric4User new. + metricUser + glhImporter: glhImporter; + jiraImporter: jiraImporter; + withUserEmailDomain: emailDomain; + user: user. + + metricUser loadProjects. + metricUser ]). ^ self ] diff --git a/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st b/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st index 5083885..25717a5 100644 --- a/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st @@ -8,11 +8,12 @@ Class { MergeRequestDurationMetric >> calculate [ | groupedByDate gitAnalyzer mergeRequestsValidation filterGroups | + userMergeRequests ifNil: [ self load ]. groupedByDate := self setupGroupedDate. userMergeRequests ifEmpty: [ ^ nil ]. - gitAnalyzer := GitAnalyzer new glhImporter: glhImporter. + gitAnalyzer := GitAnalyzer new. mergeRequestsValidation := userMergeRequests collect: [ :mr | gitAnalyzer @@ -58,8 +59,10 @@ MergeRequestDurationMetric >> description [ { #category : #loading } MergeRequestDurationMetric >> load [ - self loadUserProjects. - self loadUserMergeRequests. + + userMergeRequests := user + loadMergeRequestsSince: (period at: #since) + until: (period at: #until) ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st index 235e526..4ceda5f 100644 --- a/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st @@ -8,6 +8,7 @@ Class { MergedMergeRequestMetric >> calculate [ | groupedByDate userMergedMergeRequests dateOver | + userMergeRequests ifNil: [ self load ]. groupedByDate := self setupGroupedDate. userMergedMergeRequests := userMergeRequests select: [ @@ -33,8 +34,10 @@ MergedMergeRequestMetric >> description [ { #category : #loading } MergedMergeRequestMetric >> load [ - self loadUserProjects. - self loadUserMergeRequests. + + userMergeRequests := user + loadMergeRequestsSince: (period at: #since) + until: (period at: #until) ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/MergedMergeRequestWithoutReviewMetric.class.st b/src/GitLabHealth-Model-Analysis/MergedMergeRequestWithoutReviewMetric.class.st index 48c339e..cb2d409 100644 --- a/src/GitLabHealth-Model-Analysis/MergedMergeRequestWithoutReviewMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/MergedMergeRequestWithoutReviewMetric.class.st @@ -8,9 +8,10 @@ Class { MergedMergeRequestWithoutReviewMetric >> calculate [ | groupedByDate mergedMergeRequest noVerificationMergeRequests dateOver gitAnalyzer | + userMergeRequests ifNil: [ self load ]. groupedByDate := self setupGroupedDate. - gitAnalyzer := GitAnalyzer new glhImporter: glhImporter. + gitAnalyzer := GitAnalyzer new. mergedMergeRequest := userMergeRequests select: [ :mr | mr merged_at isNotNil ]. @@ -19,10 +20,6 @@ MergedMergeRequestWithoutReviewMetric >> calculate [ noVerificationMergeRequests := mergedMergeRequest select: [ :userMergeRequest | | validation | - glhImporter - importMergeResquestMerger: - userMergeRequest. - validation := gitAnalyzer analyseMergeResquestValidation: userMergeRequest. @@ -55,8 +52,10 @@ MergedMergeRequestWithoutReviewMetric >> description [ { #category : #loading } MergedMergeRequestWithoutReviewMetric >> load [ - self loadUserProjects. - self loadUserMergeRequests + userMergeRequests := user + loadCompleteMergeRequestsSince: + (period at: #since) + until: (period at: #until) ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/Metric.class.st b/src/GitLabHealth-Model-Analysis/Metric.class.st index 912cf06..ad447f9 100644 --- a/src/GitLabHealth-Model-Analysis/Metric.class.st +++ b/src/GitLabHealth-Model-Analysis/Metric.class.st @@ -3,9 +3,7 @@ Class { #superclass : #Object, #instVars : [ 'period', - 'over', - 'glhImporter', - 'jiraImporter' + 'over' ], #category : #'GitLabHealth-Model-Analysis' } @@ -22,18 +20,6 @@ Metric >> description [ ^ self subclassResponsibility ] -{ #category : #accessing } -Metric >> glhImporter: anObject [ - - glhImporter := anObject -] - -{ #category : #accessing } -Metric >> jiraImporter: anObject [ - - jiraImporter := anObject -] - { #category : #loading } Metric >> load [ ^self subclassResponsibility diff --git a/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st index e20ec33..cae71f2 100644 --- a/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st @@ -8,6 +8,7 @@ Class { OpenedMergeRequestMetric >> calculate [ | groupedByDate dateOver | + userMergeRequests ifNil: [ self load ]. groupedByDate := self setupGroupedDate. userMergeRequests do: [ :userMergeRequest | @@ -31,8 +32,10 @@ OpenedMergeRequestMetric >> description [ { #category : #loading } OpenedMergeRequestMetric >> load [ - self loadUserProjects. - self loadUserMergeRequests + + userMergeRequests := user + loadMergeRequestsSince: (period at: #since) + until: (period at: #until) ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st b/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st index febf3eb..cc59532 100644 --- a/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st @@ -8,6 +8,7 @@ Class { TimeBetweenCommitMetric >> calculate [ | commitSortedByDate commits1 commits2 differences groupedByDate dateOver average | + userCommits ifNil: [ self load ]. groupedByDate := self setupGroupedDate. commitSortedByDate := userCommits sorted: [ :commit1 :commit2 | @@ -34,8 +35,8 @@ TimeBetweenCommitMetric >> calculate [ asSeconds ]. differences average asDuration ]. - - average := groupedByDate + + average := groupedByDate ifEmpty: [ nil ] ifNotEmpty: [ groupedByDate average ]. @@ -51,8 +52,9 @@ TimeBetweenCommitMetric >> description [ { #category : #loading } TimeBetweenCommitMetric >> load [ - self loadUserProjects. - self loadUserCommits. + userCommits := user + loadCommitsSince: (period at: #since) + until: (period at: #until) ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/UserMetric.class.st b/src/GitLabHealth-Model-Analysis/UserMetric.class.st index a88e4f6..0ec791e 100644 --- a/src/GitLabHealth-Model-Analysis/UserMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserMetric.class.st @@ -5,8 +5,7 @@ Class { 'user', 'userProjects', 'userCommits', - 'userMergeRequests', - 'emailDomain' + 'userMergeRequests' ], #category : #'GitLabHealth-Model-Analysis' } @@ -30,35 +29,6 @@ UserMetric >> description [ ^ self subclassResponsibility ] -{ #category : #accessing } -UserMetric >> emailDomain: anObject [ - - emailDomain := anObject -] - -{ #category : #churn } -UserMetric >> foundSuccessorOf: commits andCompleteImportForMax: commitLimit [ - - | analyzingCommits gitAnalyzer | - analyzingCommits := Set new. - - gitAnalyzer := GitAnalyzer new - glhImporter: glhImporter; - maxChildCommit: commitLimit. - - glhImporter withCommitDiffs: true. - - userCommits do: [ :c | - gitAnalyzer - visitChildCommits: c childCommits - toStoreThemIn: analyzingCommits - upto: commitLimit ]. - - analyzingCommits do: [ :c | glhImporter completeImportedCommit: c ]. - - ^ analyzingCommits -] - { #category : #initialization } UserMetric >> initialize [ over := Date @@ -72,32 +42,8 @@ UserMetric >> load [ { #category : #loading } UserMetric >> loadUserCommits [ - - | allCommits cacheSymbol | - userProjects ifNil: [ self loadUserProjects ]. - glhImporter withCommitDiffs: false. - - cacheSymbol := self - cacheSymbolFor: GLHCommit - since: (period at: #since) - until: (period at: #until). - - "download commits unless project cache is not empty" - allCommits := userProjects collect: [ :project | - - glhImporter - importCommitsOProject: project - since: (period at: #since) - until: (period at: #until). - ]. - - allCommits := allCommits flatten. - allCommits do: [ :commit | glhImporter importCreatorOfCommit: commit ]. - glhImporter chainsCommitsFrom: allCommits. - glhImporter withCommitDiffs: true. - - ^ userCommits := allCommits reject: [ :commit | - commit commitCreator ~= user ] + + userCommits := user loadCommitsSince: (period at: #since) until: (period at: #until) ] { #category : #loading } @@ -148,10 +94,3 @@ UserMetric >> user: anObject [ user := anObject ] - -{ #category : #email } -UserMetric >> userEmail [ - ^ ('' join: { - user username. - emailDomain }) asLowercase -] From e3b364ef30689a84d6078619781d933f60fac99e Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Thu, 29 Aug 2024 14:54:48 +0200 Subject: [PATCH 071/154] refactor: create subclass in Metric --- .../ClosedMergeRequestMetric.class.st | 8 +---- .../ClosedTicketsMetric.class.st | 8 +---- .../CodeAdditionMetric.class.st | 8 +---- .../CodeChurnMetric.class.st | 8 +---- .../CodeDeletionMetric.class.st | 8 +---- .../CommentContributionMetric.class.st | 5 ++- .../CommitFrequencyMetric.class.st | 8 +---- .../ContributedProjectMetric.class.st | 8 +---- .../DelayUntilFirstChurnMetric.class.st | 11 +------ .../GitMetricExporter.class.st | 6 ++-- .../MergeRequestDurationMetric.class.st | 11 +------ .../MergedMergeRequestMetric.class.st | 11 +------ ...edMergeRequestWithoutReviewMetric.class.st | 2 +- .../OpenedMergeRequestMetric.class.st | 11 +------ .../TimeBetweenCommitMetric.class.st | 10 +----- .../UserCommitsMetric.class.st | 31 +++++++++++++++++++ .../UserJiraMetric.class.st | 31 +++++++++++++++++++ .../UserMergeRequestMetric.class.st | 31 +++++++++++++++++++ 18 files changed, 111 insertions(+), 105 deletions(-) create mode 100644 src/GitLabHealth-Model-Analysis/UserCommitsMetric.class.st create mode 100644 src/GitLabHealth-Model-Analysis/UserJiraMetric.class.st create mode 100644 src/GitLabHealth-Model-Analysis/UserMergeRequestMetric.class.st diff --git a/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st index a2d06e8..d98dd6b 100644 --- a/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st @@ -1,6 +1,6 @@ Class { #name : #ClosedMergeRequestMetric, - #superclass : #UserMetric, + #superclass : #UserMergeRequestMetric, #category : #'GitLabHealth-Model-Analysis' } @@ -36,12 +36,6 @@ ClosedMergeRequestMetric >> description [ ^ 'number of merge requests closed and not merged' ] -{ #category : #loading } -ClosedMergeRequestMetric >> load [ - - userMergeRequests := user loadMergeRequestsSince: (period at: #since) until: (period at: #until). -] - { #category : #accessing } ClosedMergeRequestMetric >> name [ diff --git a/src/GitLabHealth-Model-Analysis/ClosedTicketsMetric.class.st b/src/GitLabHealth-Model-Analysis/ClosedTicketsMetric.class.st index 3ac67e5..4da2be6 100644 --- a/src/GitLabHealth-Model-Analysis/ClosedTicketsMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/ClosedTicketsMetric.class.st @@ -1,6 +1,6 @@ Class { #name : #ClosedTicketsMetric, - #superclass : #UserMetric, + #superclass : #UserJiraMetric, #category : #'GitLabHealth-Model-Analysis' } @@ -29,12 +29,6 @@ ClosedTicketsMetric >> description [ ^ 'number of merge request with jira ticket closed' ] -{ #category : #loading } -ClosedTicketsMetric >> load [ - - userMergeRequests := user loadMergeRequesWithJiraIssueSince: (period at: #since) until: (period at: #until). -] - { #category : #accessing } ClosedTicketsMetric >> name [ diff --git a/src/GitLabHealth-Model-Analysis/CodeAdditionMetric.class.st b/src/GitLabHealth-Model-Analysis/CodeAdditionMetric.class.st index 37c4e28..8f4ddd8 100644 --- a/src/GitLabHealth-Model-Analysis/CodeAdditionMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CodeAdditionMetric.class.st @@ -1,6 +1,6 @@ Class { #name : #CodeAdditionMetric, - #superclass : #UserMetric, + #superclass : #UserCommitsMetric, #category : #'GitLabHealth-Model-Analysis' } @@ -42,12 +42,6 @@ CodeAdditionMetric >> description [ ^ 'code addition (avg)' ] -{ #category : #loading } -CodeAdditionMetric >> load [ - - userCommits := user loadCommitsSince: (period at: #since) until: (period at: #until). -] - { #category : #accessing } CodeAdditionMetric >> name [ diff --git a/src/GitLabHealth-Model-Analysis/CodeChurnMetric.class.st b/src/GitLabHealth-Model-Analysis/CodeChurnMetric.class.st index 8244f30..5e41133 100644 --- a/src/GitLabHealth-Model-Analysis/CodeChurnMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CodeChurnMetric.class.st @@ -1,6 +1,6 @@ Class { #name : #CodeChurnMetric, - #superclass : #UserMetric, + #superclass : #UserCommitsMetric, #instVars : [ 'maxCommitWindow' ], @@ -76,12 +76,6 @@ CodeChurnMetric >> initialize [ maxCommitWindow := 3 ] -{ #category : #loading } -CodeChurnMetric >> load [ - - userCommits := user loadCommitsSince: (period at: #since) until: (period at: #until) -] - { #category : #accessing } CodeChurnMetric >> name [ diff --git a/src/GitLabHealth-Model-Analysis/CodeDeletionMetric.class.st b/src/GitLabHealth-Model-Analysis/CodeDeletionMetric.class.st index 68dcc06..4469457 100644 --- a/src/GitLabHealth-Model-Analysis/CodeDeletionMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CodeDeletionMetric.class.st @@ -1,6 +1,6 @@ Class { #name : #CodeDeletionMetric, - #superclass : #UserMetric, + #superclass : #UserCommitsMetric, #category : #'GitLabHealth-Model-Analysis' } @@ -42,12 +42,6 @@ CodeDeletionMetric >> description [ ^'code deletion (avg)' ] -{ #category : #loading } -CodeDeletionMetric >> load [ - - userCommits := user loadCommitsSince: (period at: #since) until: (period at: #until) -] - { #category : #accessing } CodeDeletionMetric >> name [ diff --git a/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st b/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st index d451f9f..b37793a 100644 --- a/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st @@ -1,6 +1,6 @@ Class { #name : #CommentContributionMetric, - #superclass : #UserMetric, + #superclass : #UserCommitsMetric, #category : #'GitLabHealth-Model-Analysis' } @@ -47,8 +47,7 @@ CommentContributionMetric >> description [ { #category : #loading } CommentContributionMetric >> load [ - - userCommits := user loadCompleteCommitsSince: (period at: #since) until: (period at: #until). + userCommits := user loadCompleteCommitsSince: (period at: #since) until: (period at: #until). ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/CommitFrequencyMetric.class.st b/src/GitLabHealth-Model-Analysis/CommitFrequencyMetric.class.st index 11501d9..d907f36 100644 --- a/src/GitLabHealth-Model-Analysis/CommitFrequencyMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CommitFrequencyMetric.class.st @@ -1,6 +1,6 @@ Class { #name : #CommitFrequencyMetric, - #superclass : #UserMetric, + #superclass : #UserCommitsMetric, #category : #'GitLabHealth-Model-Analysis' } @@ -27,12 +27,6 @@ CommitFrequencyMetric >> description [ ^'commits frequency (avg)' ] -{ #category : #loading } -CommitFrequencyMetric >> load [ - - userCommits := user loadCommitsSince: (period at: #since) until: (period at: #until). -] - { #category : #accessing } CommitFrequencyMetric >> name [ diff --git a/src/GitLabHealth-Model-Analysis/ContributedProjectMetric.class.st b/src/GitLabHealth-Model-Analysis/ContributedProjectMetric.class.st index 16a9e0e..32a3414 100644 --- a/src/GitLabHealth-Model-Analysis/ContributedProjectMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/ContributedProjectMetric.class.st @@ -1,6 +1,6 @@ Class { #name : #ContributedProjectMetric, - #superclass : #UserMetric, + #superclass : #UserCommitsMetric, #category : #'GitLabHealth-Model-Analysis' } @@ -31,12 +31,6 @@ ContributedProjectMetric >> description [ ^ 'number of project with min 1 commit of user' ] -{ #category : #loading } -ContributedProjectMetric >> load [ - - userCommits := user loadCommitsSince: (period at: #since) until: (period at: #until). -] - { #category : #accessing } ContributedProjectMetric >> name [ diff --git a/src/GitLabHealth-Model-Analysis/DelayUntilFirstChurnMetric.class.st b/src/GitLabHealth-Model-Analysis/DelayUntilFirstChurnMetric.class.st index f1ca836..4bc759c 100644 --- a/src/GitLabHealth-Model-Analysis/DelayUntilFirstChurnMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/DelayUntilFirstChurnMetric.class.st @@ -1,6 +1,6 @@ Class { #name : #DelayUntilFirstChurnMetric, - #superclass : #UserMetric, + #superclass : #UserCommitsMetric, #instVars : [ 'maxCommitWindow' ], @@ -82,15 +82,6 @@ DelayUntilFirstChurnMetric >> initialize [ maxCommitWindow := 3 ] -{ #category : #loading } -DelayUntilFirstChurnMetric >> load [ - - - userCommits := user - loadCommitsSince: (period at: #since) - until: (period at: #until) -] - { #category : #accessing } DelayUntilFirstChurnMetric >> name [ diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 82c34db..c09cac2 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -400,8 +400,8 @@ GitMetricExporter >> initialize [ CodeDeletionMetric. CommentContributionMetric. CommitFrequencyMetric. - CodeChurnMetric - "DelayUntilFirstChurnMetric. + CodeChurnMetric. + DelayUntilFirstChurnMetric. TimeBetweenCommitMetric. ContributedProjectMetric. MergeRequestDurationMetric. @@ -409,7 +409,7 @@ GitMetricExporter >> initialize [ ClosedMergeRequestMetric. MergedMergeRequestMetric. MergedMergeRequestWithoutReviewMetric. - ClosedTicketsMetric " } + ClosedTicketsMetric} ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st b/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st index 25717a5..2902a9b 100644 --- a/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st @@ -1,6 +1,6 @@ Class { #name : #MergeRequestDurationMetric, - #superclass : #UserMetric, + #superclass : #UserMergeRequestMetric, #category : #'GitLabHealth-Model-Analysis' } @@ -56,15 +56,6 @@ MergeRequestDurationMetric >> description [ ^ 'merge request duration' ] -{ #category : #loading } -MergeRequestDurationMetric >> load [ - - - userMergeRequests := user - loadMergeRequestsSince: (period at: #since) - until: (period at: #until) -] - { #category : #accessing } MergeRequestDurationMetric >> name [ diff --git a/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st index 4ceda5f..33190cc 100644 --- a/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st @@ -1,6 +1,6 @@ Class { #name : #MergedMergeRequestMetric, - #superclass : #UserMetric, + #superclass : #UserMergeRequestMetric, #category : #'GitLabHealth-Model-Analysis' } @@ -31,15 +31,6 @@ MergedMergeRequestMetric >> description [ ^ 'number of merged merge request' ] -{ #category : #loading } -MergedMergeRequestMetric >> load [ - - - userMergeRequests := user - loadMergeRequestsSince: (period at: #since) - until: (period at: #until) -] - { #category : #accessing } MergedMergeRequestMetric >> name [ diff --git a/src/GitLabHealth-Model-Analysis/MergedMergeRequestWithoutReviewMetric.class.st b/src/GitLabHealth-Model-Analysis/MergedMergeRequestWithoutReviewMetric.class.st index cb2d409..0c19679 100644 --- a/src/GitLabHealth-Model-Analysis/MergedMergeRequestWithoutReviewMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/MergedMergeRequestWithoutReviewMetric.class.st @@ -1,6 +1,6 @@ Class { #name : #MergedMergeRequestWithoutReviewMetric, - #superclass : #UserMetric, + #superclass : #UserMergeRequestMetric, #category : #'GitLabHealth-Model-Analysis' } diff --git a/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st index cae71f2..158f18e 100644 --- a/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st @@ -1,6 +1,6 @@ Class { #name : #OpenedMergeRequestMetric, - #superclass : #UserMetric, + #superclass : #UserMergeRequestMetric, #category : #'GitLabHealth-Model-Analysis' } @@ -29,15 +29,6 @@ OpenedMergeRequestMetric >> description [ ^'number of opened merge request' ] -{ #category : #loading } -OpenedMergeRequestMetric >> load [ - - - userMergeRequests := user - loadMergeRequestsSince: (period at: #since) - until: (period at: #until) -] - { #category : #accessing } OpenedMergeRequestMetric >> name [ diff --git a/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st b/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st index cc59532..6beb335 100644 --- a/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st @@ -1,6 +1,6 @@ Class { #name : #TimeBetweenCommitMetric, - #superclass : #UserMetric, + #superclass : #UserCommitsMetric, #category : #'GitLabHealth-Model-Analysis' } @@ -49,14 +49,6 @@ TimeBetweenCommitMetric >> description [ ^ 'average time between commits' ] -{ #category : #loading } -TimeBetweenCommitMetric >> load [ - - userCommits := user - loadCommitsSince: (period at: #since) - until: (period at: #until) -] - { #category : #accessing } TimeBetweenCommitMetric >> name [ diff --git a/src/GitLabHealth-Model-Analysis/UserCommitsMetric.class.st b/src/GitLabHealth-Model-Analysis/UserCommitsMetric.class.st new file mode 100644 index 0000000..843d94a --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/UserCommitsMetric.class.st @@ -0,0 +1,31 @@ +Class { + #name : #UserCommitsMetric, + #superclass : #UserMetric, + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #calculating } +UserCommitsMetric >> calculate [ + + ^ self subclassResponsibility +] + +{ #category : #accessing } +UserCommitsMetric >> description [ + + ^ self subclassResponsibility +] + +{ #category : #loading } +UserCommitsMetric >> load [ + + userCommits := user + loadCommitsSince: (period at: #since) + until: (period at: #until) +] + +{ #category : #accessing } +UserCommitsMetric >> name [ + + ^ self subclassResponsibility +] diff --git a/src/GitLabHealth-Model-Analysis/UserJiraMetric.class.st b/src/GitLabHealth-Model-Analysis/UserJiraMetric.class.st new file mode 100644 index 0000000..a3c6095 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/UserJiraMetric.class.st @@ -0,0 +1,31 @@ +Class { + #name : #UserJiraMetric, + #superclass : #UserMetric, + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #calculating } +UserJiraMetric >> calculate [ + + ^ self subclassResponsibility +] + +{ #category : #accessing } +UserJiraMetric >> description [ + + ^ self subclassResponsibility +] + +{ #category : #loading } +UserJiraMetric >> load [ + userMergeRequests := user + loadMergeRequesWithJiraIssueSince: + (period at: #since) + until: (period at: #until) +] + +{ #category : #accessing } +UserJiraMetric >> name [ + + ^ self subclassResponsibility +] diff --git a/src/GitLabHealth-Model-Analysis/UserMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/UserMergeRequestMetric.class.st new file mode 100644 index 0000000..056fad9 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/UserMergeRequestMetric.class.st @@ -0,0 +1,31 @@ +Class { + #name : #UserMergeRequestMetric, + #superclass : #UserMetric, + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #calculating } +UserMergeRequestMetric >> calculate [ + + ^ self subclassResponsibility +] + +{ #category : #accessing } +UserMergeRequestMetric >> description [ + + ^ self subclassResponsibility +] + +{ #category : #loading } +UserMergeRequestMetric >> load [ + + userMergeRequests := user + loadMergeRequestsSince: (period at: #since) + until: (period at: #until) +] + +{ #category : #accessing } +UserMergeRequestMetric >> name [ + + ^ self subclassResponsibility +] From c9f271bc27731ca092740277270486c52108e255 Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Thu, 29 Aug 2024 16:09:52 +0200 Subject: [PATCH 072/154] add new algo for user name distances and correct 403 error on pipeline --- .../GLHUserCatalogueV2Test.class.st | 24 ++++++++++++++ .../GitMetric4User.class.st | 28 ++++++++-------- .../GitMetricExporter.class.st | 16 ++++------ .../String.extension.st | 32 +++++++++++++++++++ .../GLHModelImporter.class.st | 5 ++- 5 files changed, 81 insertions(+), 24 deletions(-) create mode 100644 src/GitLabHealth-Model-Analysis/String.extension.st diff --git a/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueV2Test.class.st b/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueV2Test.class.st index b1e9b90..a8c7e05 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueV2Test.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueV2Test.class.st @@ -184,6 +184,30 @@ GLHUserCatalogueV2Test >> testExportToJson [ self assert: ((res at: 'test user') at: #foundNames) size equals: 2 ] +{ #category : #'as yet unclassified' } +GLHUserCatalogueV2Test >> testLevenshteinDistanceBetweenBenoitAndNicolas [ + self assert: ('benoit' levenshteinDistanceWith: 'nicolas') equals: 6 + +] + +{ #category : #'as yet unclassified' } +GLHUserCatalogueV2Test >> testLevenshteinDistanceBetweenExamenAndExaman [ + self assert: ('examen' levenshteinDistanceWith: 'examan') equals: 1 + +] + +{ #category : #'as yet unclassified' } +GLHUserCatalogueV2Test >> testLevenshteinDistanceBetweenExamenAndExamen [ + self assert: ('examen' levenshteinDistanceWith: 'examen') equals: 0 + +] + +{ #category : #'as yet unclassified' } +GLHUserCatalogueV2Test >> testLevenshteinDistanceBetweenNicolasAndNico [ + self assert: ('nicolas' levenshteinDistanceWith: 'nico') equals: 3 + +] + { #category : #tests } GLHUserCatalogueV2Test >> testLoadFromJson [ diff --git a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st index f1c2d1f..b34741d 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st @@ -9,20 +9,6 @@ Class { #category : #'GitLabHealth-Model-Analysis' } -{ #category : #'email' } -GitMetric4User >> withUserEmailDomain: aEmailDomain [ - emailDomain := aEmailDomain. -] - -{ #category : #'email' } -GitMetric4User >> userEmail [ - "overide this method to adapt on your situation" - - ^ ('' join: { - user username. - emailDomain }) asLowercase. -] - { #category : #'metrics - commits' } GitMetric4User >> averageTimeBetweenCommitSince: since until: until overA: aDateWeekMonthOrYear [ @@ -1099,3 +1085,17 @@ GitMetric4User >> user: anUser [ GitMetric4User >> userCommits [ ^ user commits ] + +{ #category : #email } +GitMetric4User >> userEmail [ + "overide this method to adapt on your situation" + + ^ ('' join: { + user username. + emailDomain }) asLowercase. +] + +{ #category : #email } +GitMetric4User >> withUserEmailDomain: aEmailDomain [ + emailDomain := aEmailDomain. +] diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index a7fc98d..66769c0 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -17,8 +17,6 @@ Class { #category : #'GitLabHealth-Model-Analysis' } - - { #category : #'as yet unclassified' } GitMetricExporter class >> demoPeriod [ @@ -28,13 +26,6 @@ GitMetricExporter class >> demoPeriod [ addAPeriodFrom: '01 march 2024' to: '31 may 2024' ] -{ #category : #setup } -GitMetricExporter >> withEmailDomain: anEmailDomain [ - - "define the email domain of your Git user. Usefull to link them between service (i.e. Jira)" - emailDomain := anEmailDomain -] - { #category : #adding } GitMetricExporter >> addAPeriodFrom: since to: until [ @@ -516,3 +507,10 @@ GitMetricExporter >> setupAnalysisForUsersWithNames: userNames [ ^ self ] + +{ #category : #setup } +GitMetricExporter >> withEmailDomain: anEmailDomain [ + + "define the email domain of your Git user. Usefull to link them between service (i.e. Jira)" + emailDomain := anEmailDomain +] diff --git a/src/GitLabHealth-Model-Analysis/String.extension.st b/src/GitLabHealth-Model-Analysis/String.extension.st new file mode 100644 index 0000000..249814e --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/String.extension.st @@ -0,0 +1,32 @@ +Extension { #name : #String } + +{ #category : #'*GitLabHealth-Model-Analysis' } +String >> levenshteinDistanceWith: aString [ + | m n distances cost | + + m := self size. + n := aString size. + + "Initialize a 2D array (m+1 x n+1) to store distances" + distances := Array2D rows: m+1 columns: n+1 element: 0. + + "Fill base cases for first row and first column" + 1 to: m do: [ :i | distances at: i+1 at: 1 put: i ]. + 1 to: n do: [ :j | distances at: 1 at: j+1 put: j ]. + + + "Compute distances using dynamic programming" + 2 to: m do: [ :i | + 2 to: n do: [ :j | + cost := (self at: i) = (aString at: j) ifTrue: [ 0 ] ifFalse: [ 1 ]. + distances at: (i) at: (j) put: { + ((distances at: i-1 at: j) + 1) . + ((distances at: 1 at: j-1) + 1) . + ((distances at: i-1 at: j-1) + cost) . + } min . + ]. + ]. + + "Return the Levenshtein distance between the two strings" + ^ distances at: m at: n +] diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index 108b819..c18f270 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -1060,6 +1060,9 @@ GLHModelImporter >> parseJobsResult: result ofProject: aProject [ GLHModelImporter >> parsePipelinesResult: result [ | reader | + + result = '{"message":"403 Forbidden"}' ifTrue: [ ^ { } ]. + reader := NeoJSONReader on: result readStream. reader mapInstVarsFor: GLHPipeline. reader for: GLHPipeline do: [ :mapping | @@ -1126,7 +1129,7 @@ GLHModelImporter >> pipelinesOf: aProjectID [ | result | ('Search pipelines of: ' , aProjectID printString) recordInfo. result := self glhApi pipelinesOfProject: aProjectID. - ^ self parsePipelinesResult: result + ^ self parsePipelinesResult: result . ] { #category : #'private - api' } From 50f4c7cbe864e332df6e21e490a1b6b658fde4a6 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Thu, 29 Aug 2024 16:26:33 +0200 Subject: [PATCH 073/154] refactor: remove unused method --- .../AnalysisReport.class.st | 234 ----- .../GitMetric4User.class.st | 949 ------------------ .../GitMetricExporter.class.st | 79 +- 3 files changed, 21 insertions(+), 1241 deletions(-) delete mode 100644 src/GitLabHealth-Model-Analysis/AnalysisReport.class.st diff --git a/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st b/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st deleted file mode 100644 index 2da1f3d..0000000 --- a/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st +++ /dev/null @@ -1,234 +0,0 @@ -Class { - #name : #AnalysisReport, - #superclass : #Object, - #instVars : [ - 'username', - 'period', - 'over', - 'codeAddition', - 'codeDeletion', - 'commitFrequency', - 'commentContribution', - 'mergeRequestDuration', - 'codeChurn', - 'delayUntilFirstChurn', - 'numberOfProjectWithCommit', - 'averageTimeBetweenCommits', - 'numberOfOpenMergeRequests', - 'numberOfMergedMergeRequest', - 'numberOfClosedMergeRequests', - 'numberOfMergeRequestsWithoutReview', - 'numberOfTicketsClosed' - ], - #category : #'GitLabHealth-Model-Analysis' -} - -{ #category : #testing } -AnalysisReport class >> isVoyageRoot [ - ^true -] - -{ #category : #accessing } -AnalysisReport >> averageTimeBetweenCommits [ - - ^ averageTimeBetweenCommits -] - -{ #category : #accessing } -AnalysisReport >> averageTimeBetweenCommits: anObject [ - - averageTimeBetweenCommits := anObject -] - -{ #category : #accessing } -AnalysisReport >> codeAddition [ - - ^ codeAddition -] - -{ #category : #accessing } -AnalysisReport >> codeAddition: anObject [ - - codeAddition := anObject -] - -{ #category : #accessing } -AnalysisReport >> codeChurn [ - - ^ codeChurn -] - -{ #category : #accessing } -AnalysisReport >> codeChurn: anObject [ - - codeChurn := anObject -] - -{ #category : #accessing } -AnalysisReport >> codeDeletion [ - - ^ codeDeletion -] - -{ #category : #accessing } -AnalysisReport >> codeDeletion: anObject [ - - codeDeletion := anObject -] - -{ #category : #accessing } -AnalysisReport >> commentContribution [ - - ^ commentContribution -] - -{ #category : #accessing } -AnalysisReport >> commentContribution: anObject [ - - commentContribution := anObject -] - -{ #category : #accessing } -AnalysisReport >> commitFrequency [ - - ^ commitFrequency -] - -{ #category : #accessing } -AnalysisReport >> commitFrequency: anObject [ - - commitFrequency := anObject -] - -{ #category : #accessing } -AnalysisReport >> delayUntilFirstChurn [ - - ^ delayUntilFirstChurn -] - -{ #category : #accessing } -AnalysisReport >> delayUntilFirstChurn: anObject [ - - delayUntilFirstChurn := anObject -] - -{ #category : #accessing } -AnalysisReport >> mergeRequestDuration [ - - ^ mergeRequestDuration -] - -{ #category : #accessing } -AnalysisReport >> mergeRequestDuration: anObject [ - - mergeRequestDuration := anObject -] - -{ #category : #accessing } -AnalysisReport >> numberOfClosedMergeRequests [ - - ^ numberOfClosedMergeRequests -] - -{ #category : #accessing } -AnalysisReport >> numberOfClosedMergeRequests: anObject [ - - numberOfClosedMergeRequests := anObject -] - -{ #category : #accessing } -AnalysisReport >> numberOfMergeRequestsWithoutReview [ - - ^ numberOfMergeRequestsWithoutReview -] - -{ #category : #accessing } -AnalysisReport >> numberOfMergeRequestsWithoutReview: anObject [ - - numberOfMergeRequestsWithoutReview := anObject -] - -{ #category : #accessing } -AnalysisReport >> numberOfMergedMergeRequest [ - - ^ numberOfMergedMergeRequest -] - -{ #category : #accessing } -AnalysisReport >> numberOfMergedMergeRequest: anObject [ - - numberOfMergedMergeRequest := anObject -] - -{ #category : #accessing } -AnalysisReport >> numberOfOpenMergeRequests [ - - ^ numberOfOpenMergeRequests -] - -{ #category : #accessing } -AnalysisReport >> numberOfOpenMergeRequests: anObject [ - - numberOfOpenMergeRequests := anObject -] - -{ #category : #accessing } -AnalysisReport >> numberOfProjectWithCommit [ - - ^ numberOfProjectWithCommit -] - -{ #category : #accessing } -AnalysisReport >> numberOfProjectWithCommit: anObject [ - - numberOfProjectWithCommit := anObject -] - -{ #category : #accessing } -AnalysisReport >> numberOfTicketsClosed [ - - ^ numberOfTicketsClosed -] - -{ #category : #accessing } -AnalysisReport >> numberOfTicketsClosed: anObject [ - - numberOfTicketsClosed := anObject -] - -{ #category : #accessing } -AnalysisReport >> over [ - - ^ over -] - -{ #category : #accessing } -AnalysisReport >> over: anObject [ - - over := anObject - -] - -{ #category : #accessing } -AnalysisReport >> period [ - - ^ period -] - -{ #category : #accessing } -AnalysisReport >> period: anObject [ - - period := anObject -] - -{ #category : #accessing } -AnalysisReport >> username [ - - ^ username -] - -{ #category : #accessing } -AnalysisReport >> username: anObject [ - - username := anObject -] diff --git a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st index 3677a48..88c48fe 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st @@ -9,531 +9,6 @@ Class { #category : #'GitLabHealth-Model-Analysis' } -{ #category : #'metrics - commits' } -GitMetric4User >> averageTimeBetweenCommitSince: since until: until overA: aDateWeekMonthOrYear [ - - | commits commitSortedByDate commits1 commits2 differences groupedByDate dateOver average | - groupedByDate := self - setupGroupedDateFrom: since - to: until - over: aDateWeekMonthOrYear. - - gitAnalyzer := GitAnalyzer new - onModel: glhModel; - glhImporter: glhImporter. - - glhImporter withCommitDiffs: false. - commits := self - loadCommitsFromProjectsIds: itsProjects keys - since: since - until: until. - glhImporter withCommitDiffs: true. - commits := commits reject: [ :commit | commit commitCreator ~= user ]. - - commitSortedByDate := commits sorted: [ :commit1 :commit2 | - commit1 committed_date - < commit2 committed_date ]. - - commitSortedByDate do: [ :commit | - dateOver := self - transformDate: commit committed_date - to: aDateWeekMonthOrYear. - - groupedByDate - at: dateOver printString - ifPresent: [ :value | value add: commit ] ]. - - groupedByDate := groupedByDate select: [ :group | group size >= 2 ]. - - - groupedByDate := groupedByDate collect: [ :group | - differences := (1 to: group size - 1) collect: [ :i | - commits1 := group at: i. - commits2 := group at: i + 1. - - (commits2 committed_date - - commits1 committed_date) - asSeconds ]. - - differences average asDuration ]. - - average := groupedByDate - ifEmpty: [ nil ] - ifNotEmpty: [ groupedByDate average ]. - - ^ { - (#overEach -> aDateWeekMonthOrYear name). - (#forOver -> (groupedByDate keys size printString - , aDateWeekMonthOrYear printString)). - (#average -> average). - (#details -> groupedByDate). - (#userCommits -> commits size) } asDictionary -] - -{ #category : #churn } -GitMetric4User >> codeChurnSince: since until: until onACommitWindowOf: commitLimit overA: aDateWeekMonthOrYear [ - - | commits res groupedByDate totalContributions userCommits | - "for each commit, we get its churn result (a dictionnary)" - 'GitMetric4User: code churn' recordInfo. - totalContributions := OrderedCollection new. - groupedByDate := self - setupGroupedDateFrom: since - to: until - over: aDateWeekMonthOrYear. - gitAnalyzer := GitAnalyzer new - glhImporter: glhImporter; - onModel: glhModel; - maxChildCommit: commitLimit. - glhImporter withCommitDiffs: false. - commits := self - loadCommitsFromProjectsIds: itsProjects keys - since: since - until: until. - glhImporter withCommitDiffs: true. - userCommits := commits reject: [ :commit | - commit commitCreator ~= user ]. - commits := self - foundSuccessorOf: userCommits - andCompleteImportForMax: commitLimit. - - - res := commits collect: [ :commit | - commit -> (gitAnalyzer - fromCommit: commit; - analyseChurn) ]. - res do: [ :commits4Churns | - | commit allChurnsInCommit sumChurnInCommit overDate contribution churnOnCommit | - commit := commits4Churns key. - allChurnsInCommit := commits4Churns value. - sumChurnInCommit := (allChurnsInCommit at: #churns) sum: [ :churn | - | numerator | - numerator := churn value at: #churnLoC. - numerator ]. - contribution := allChurnsInCommit at: #totalContribution. - totalContributions add: contribution. - churnOnCommit := { - (#churnOnCommit -> sumChurnInCommit). - (#LoCOnCommit -> contribution) } asDictionary. - overDate := self - transformDate: commit created_at - to: aDateWeekMonthOrYear. - groupedByDate - at: overDate printString - ifPresent: [ :array | array add: churnOnCommit ] - ifAbsentPut: [ - OrderedCollection new - add: churnOnCommit; - yourself ] ]. - groupedByDate := groupedByDate collect: [ :churnsAtDate | - | totalChurn totalContribution percentage | - totalChurn := churnsAtDate sum: [ :churn | - churn at: #churnOnCommit ]. - totalContribution := churnsAtDate sum: [ :churn | - churn at: #LoCOnCommit ]. - totalContribution = 0 - ifTrue: [ percentage := 0 asFloat ] - ifFalse: [ - percentage := (totalChurn * 100 - / totalContribution) asFloat ]. - { - (#churn -> totalChurn). - (#contribution -> totalContribution). - (#percentage -> percentage) } asDictionary ]. - ^ groupedByDate collect: [ :date | date at: #percentage ] -] - -{ #category : #'metrics - commits' } -GitMetric4User >> codeContributionsSince: since until: until overA: aDateWeekMonthOrYear [ - - | commits contributions groupedByDate | - 'GitMetric4User: code contribution' recordInfo. - - groupedByDate := self - setupGroupedDateFrom: since - to: until - over: aDateWeekMonthOrYear. - - gitAnalyzer := GitAnalyzer new - onModel: glhModel; - glhImporter: glhImporter. - - glhImporter withCommitDiffs: false. - commits := self - loadCommitsFromProjectsIds: itsProjects keys - since: since - until: until. - glhImporter withCommitDiffs: true. - commits := commits reject: [ :commit | commit commitCreator ~= user ]. - - contributions := commits collect: [ :commit | - commit -> (gitAnalyzer - fromCommit: commit; - analyseCommitContribution) ]. - - contributions do: [ :assoc | - | dateOver | - dateOver := self - transformDate: assoc key created_at - to: aDateWeekMonthOrYear. - groupedByDate - at: dateOver printString - ifPresent: [ :v | v add: assoc value ] - ifAbsentPut: [ - OrderedCollection new - add: assoc value; - yourself ] ]. - - groupedByDate := groupedByDate collect: [ :contribs | - | totalAdd totalDele | - totalAdd := contribs sum: [ :v | v at: #addition ]. - totalDele := contribs sum: [ :v | v at: #deletion ]. - { - (#addition -> totalAdd). - (#deletion -> totalDele) } asDictionary ]. - - ^ { - (#overEach -> aDateWeekMonthOrYear name). - (#forOver -> (groupedByDate keys size printString - , aDateWeekMonthOrYear printString)). - (#avgAddition - -> - (groupedByDate collect: [ :d | d at: #addition ]) average asFloat). - (#avgDeletion - -> - (groupedByDate collect: [ :d | d at: #deletion ]) average asFloat). - (#details -> groupedByDate). - (#userCommits -> commits size) } asDictionary -] - -{ #category : #'metrics - commits' } -GitMetric4User >> commentsContributionsSince: since until: until overA: aDateWeekMonthOrYear [ - - | commits contributions groupedByDate | - 'GitMetric4User: comment contribution' recordInfo. - - groupedByDate := self - setupGroupedDateFrom: since - to: until - over: aDateWeekMonthOrYear. - - gitAnalyzer := GitAnalyzer new - onModel: glhModel; - glhImporter: glhImporter. - - glhImporter withCommitDiffs: false. - commits := self - loadCommitsFromProjectsIds: itsProjects keys - since: since - until: until. - glhImporter withCommitDiffs: true. - commits := commits reject: [ :commit | commit commitCreator ~= user ]. - commits do: [ :commit | glhImporter completeImportedCommit: commit ]. - - - contributions := commits collect: [ :commit | - commit -> (gitAnalyzer - fromCommit: commit; - analyseCommentContribution) ]. - - - contributions do: [ :assoc | - | dateOver | - dateOver := self - transformDate: assoc key created_at - to: aDateWeekMonthOrYear. - groupedByDate - at: dateOver printString - ifPresent: [ :v | v add: assoc value ] - ifAbsentPut: [ - OrderedCollection new - add: assoc value; - yourself ] ]. - - groupedByDate := groupedByDate collect: [ :contribs | - contribs - ifNotEmpty: [ contribs sum ] - ifEmpty: [ 0 ] ]. - - - ^ { - (#details -> groupedByDate). - (#totalComments -> groupedByDate values sum). - (#avgComments -> groupedByDate values average asFloat). - (#overEach -> aDateWeekMonthOrYear name). - (#forOver -> (groupedByDate keys size printString - , aDateWeekMonthOrYear printString)). - (#userCommits -> commits size) } asDictionary -] - -{ #category : #'metrics - commits' } -GitMetric4User >> commitFrequencySince: since until: until overA: aDateWeekMonthOrYear [ - - | periods total groupedByDate userCommits | - 'GitMetric4User: commit frequency' recordInfo. - - groupedByDate := self - setupGroupedDateFrom: since - to: until - over: aDateWeekMonthOrYear. - - glhImporter withCommitDiffs: false. - userCommits := self - loadCommitsFromProjectsIds: itsProjects keys - since: since - until: until. - glhImporter withCommitDiffs: true. - userCommits := userCommits reject: [ :c | c commitCreator ~= user ]. - - userCommits do: [ :c | - | dateOver | - dateOver := self - transformDate: c created_at - to: aDateWeekMonthOrYear. - groupedByDate at: dateOver printString ifPresent: [ :v | v add: c ] ]. - - periods := groupedByDate keys size. - total := groupedByDate values sum: [ :commits | commits size ]. - - - ^ { - (#averageFrac -> (total / periods)). - (#averageFloat -> (total / periods) asFloat). - (#userCommit -> total). - (#forOver -> (groupedByDate keys size printString - , aDateWeekMonthOrYear printString)). - (#periode -> aDateWeekMonthOrYear name). - (#details -> groupedByDate) } asOrderedDictionary -] - -{ #category : #'metrics - commits' } -GitMetric4User >> commitsProducedOnProject: projectId since: sinceDate until: untilDate [ - - | frequencies | - - - gitAnalyzer := GitAnalyzer new - glhImporter: glhImporter; - onModel: glhModel. - - frequencies := gitAnalyzer - onProject: (itsProjects at: projectId); - analyseCommitFrequencySince: sinceDate - until: untilDate. - - "complete each commit " - frequencies values flattened do: [ :commit | - glhImporter completeImportedCommit: commit. - ]. - - "Filter the associations in the 'frequencies' collection, removing any commits not created by the specified 'user'. " - frequencies associations do: [ :assoc | - |commits| - commits := assoc value. - assoc value: (commits reject: [ :commit | commit commitCreator ~= user ]). - ]. - - ^ frequencies -] - -{ #category : #'metrics - commits' } -GitMetric4User >> commitsProducedOnProject: aProjectId since: since until: until overA: aWeekOrMonthOrYear [ - "'aWeekOrMonthOrYear' should be the class of Data, Week, Month or Year" - - | frequency aggregatedFrequencies | - aggregatedFrequencies := self - setupGroupedDateFrom: since - to: until - over: aWeekOrMonthOrYear. - - frequency := self - commitsProducedOnProject: aProjectId - since: since - until: until. - - frequency associations do: [ :assoc | - | date commits overDate | - date := assoc key. - commits := assoc value. - - commits ifNotEmpty: [ " convert the date as its week date. For some english reason, the week start in sunday so we should add a + 1 day " - overDate := self transformDate: date to: aWeekOrMonthOrYear. - aggregatedFrequencies - at: overDate printString - ifPresent: [ :collection | collection addAll: commits ] - ifAbsentPut: [ commits ] ] ]. - - ^ aggregatedFrequencies -] - -{ #category : #churn } -GitMetric4User >> delayUntilFirstChurnSince: since until: until onACommitWindowOf: maxCommitWindow overA: aDateWeekMonthOrYear [ - - | commits groupedByDate res avg userCommits | - 'GitMetric4User: delay until first churn' recordInfo. - - groupedByDate := self - setupGroupedDateFrom: since - to: until - over: aDateWeekMonthOrYear. - - glhImporter withCommitDiffs: false. - commits := self - loadCommitsFromProjectsIds: itsProjects keys - since: since - until: until. - glhImporter withCommitDiffs: true. - - userCommits := commits reject: [ :commit | - commit commitCreator ~= user ]. - commits := self - foundSuccessorOf: userCommits - andCompleteImportForMax: maxCommitWindow. - - - "class commit by dates, filter none user commits" - commits do: [ :commit | - commit commitCreator = user ifTrue: [ - | overDate | - overDate := self - transformDate: commit created_at - to: aDateWeekMonthOrYear. - - groupedByDate - at: overDate printString - ifPresent: [ :arrayOfCommits | arrayOfCommits add: commit ] - ifAbsentPut: [ - OrderedCollection new - add: commit; - yourself ] ] ]. - - - - res := groupedByDate collect: [ :commits4Date | - | durationFromA2B | - commits4Date collect: [ :commitA | - | commitB | - commitB := GitAnalyzer new - glhImporter: glhImporter; - onModel: glhModel; - fromCommit: commitA; - maxChildCommit: maxCommitWindow; - analyseDelayUntilFirstChurn. - - durationFromA2B := commitB - ifNil: [ 0 ] - ifNotNil: [ - commitB created_at - commitA created_at ]. - durationFromA2B ] ]. - - - - res := res collect: [ :durationsByDate | - | filtered | - filtered := durationsByDate reject: [ :value | value = 0 ]. - filtered isEmpty - ifTrue: [ nil ] - ifFalse: [ - (filtered sum: [ :v | v asDuration asSeconds]) / filtered size ] ]. - - res := res reject: #isNil. - - res - ifEmpty: [ avg := nil ] - ifNotEmpty: [ avg := res values average asFloat ]. - - - ^ { - (#avgDelay -> avg). - (#overEach -> aDateWeekMonthOrYear name). - (#forOver -> (groupedByDate keys size printString - , aDateWeekMonthOrYear printString)). - (#details -> groupedByDate) } asDictionary -] - -{ #category : #churn } -GitMetric4User >> delayUntilFirstChurnSince: since until: until overA: aDateWeekMonthOrYear [ - - | commits groupedByDate res avg | - self - deprecated: - 'Use #delayUntilFirstChurnSince:until:onACommitWindowOf:overA: instead' - on: '1 July 2024' - in: - 'Pharo-11.0.0+build.726.sha.aece1b5473acf3830a0e082c1bc3a15d4ff3522b (64 Bit)'. - - 'GitMetric4User: delay until first churn' recordInfo. - - groupedByDate := self - setupGroupedDateFrom: since - to: until - over: aDateWeekMonthOrYear. - - commits := self - loadCommitsFromProjectsIds: itsProjects keys - since: since - until: until. - - "class commit by dates, filter none user commits" - commits do: [ :commit | - commit commitCreator = user ifTrue: [ - | overDate | - overDate := self - transformDate: commit created_at - to: aDateWeekMonthOrYear. - - groupedByDate - at: overDate printString - ifPresent: [ :arrayOfCommits | arrayOfCommits add: commit ] - ifAbsentPut: [ - OrderedCollection new - add: commit; - yourself ] ] ]. - - - - res := groupedByDate collect: [ :commits4Date | - | durationFromA2B | - commits4Date collect: [ :commitA | - | commitB | - commitB := GitAnalyzer new - glhImporter: glhImporter; - onModel: glhModel; - fromCommit: commitA; - maxChildCommit: 5; - analyseDelayUntilFirstChurn. - - durationFromA2B := commitB - ifNil: [ 0 ] - ifNotNil: [ - commitB created_at - commitA created_at ]. - durationFromA2B ] ]. - - - - res := res collect: [ :durationsByDate | - | filtered | - filtered := durationsByDate reject: [ :value | value = 0 ]. - filtered isEmpty - ifTrue: [ nil ] - ifFalse: [ - (filtered sum: [ :v | v asDuration ]) / filtered size ] ]. - - res := res reject: #isNil. - - res - ifEmpty: [ avg := nil ] - ifNotEmpty: [ avg := res values sum / res keys size ]. - - - ^ { - (#avgDelay -> avg). - (#overEach -> aDateWeekMonthOrYear name). - (#forOver -> (groupedByDate keys size printString - , aDateWeekMonthOrYear printString)). - (#details -> groupedByDate) } asDictionary -] - { #category : #churn } GitMetric4User >> foundSuccessorOf: userCommits andCompleteImportForMax: commitLimit [ @@ -557,95 +32,6 @@ GitMetric4User >> foundSuccessorOf: userCommits andCompleteImportForMax: commitL ^ analyzingCommits ] -{ #category : #analysis } -GitMetric4User >> generateAnalysisForPeriod: period over: aDateWeekMonthOrYear withMaxCommitWindows: maxCommitWindow [ - - | contribution commitFrequency commentContribution mergeRequestDuration codeChurn delayUntilFirstChurn averageTimeBetweenCommits numberOfProjectWithCommit until since numberOfOpenMergeRequests numberOfMergedMergeRequests numberOfClosedMergeRequests numberOfMergeRequestWithoutReview numberOfTicketsClosed | - since := period at: #since. - until := period at: #until. - contribution := self - codeContributionsSince: since - until: until - overA: aDateWeekMonthOrYear. - commitFrequency := self - commitFrequencySince: since - until: until - overA: aDateWeekMonthOrYear. - commentContribution := self - commentsContributionsSince: since - until: until - overA: aDateWeekMonthOrYear. - codeChurn := self - codeChurnSince: since - until: until - onACommitWindowOf: maxCommitWindow - overA: aDateWeekMonthOrYear. - delayUntilFirstChurn := self - delayUntilFirstChurnSince: since - until: until - onACommitWindowOf: maxCommitWindow - overA: aDateWeekMonthOrYear. - numberOfProjectWithCommit := self - numberOfProjectWithCommitSince: since - until: until - overA: aDateWeekMonthOrYear. - averageTimeBetweenCommits := self - averageTimeBetweenCommitSince: since - until: until - overA: aDateWeekMonthOrYear. - mergeRequestDuration := self - mergeRequestDurationSince: since - until: until - overA: aDateWeekMonthOrYear. - numberOfOpenMergeRequests := self - numberOfOpenMergeRequestsSince: since - until: until - overA: aDateWeekMonthOrYear. - numberOfMergedMergeRequests := self - numberOfMergedMergeRequestsSince: - since - until: until - overA: aDateWeekMonthOrYear. - numberOfClosedMergeRequests := self - numberOfClosedMergeRequestSince: - since - until: until - overA: aDateWeekMonthOrYear. - numberOfMergeRequestWithoutReview := self - numberOfMergeRequestsMergedWithoutReviewSince: - since - until: until - overA: aDateWeekMonthOrYear. - numberOfTicketsClosed := self - numberOfTicketsClosedSince: since - until: until - overA: aDateWeekMonthOrYear. - ^ AnalysisReport new - username: self user name; - period: period; - over: aDateWeekMonthOrYear asString; - codeAddition: (contribution at: #avgAddition); - codeDeletion: (contribution at: #avgDeletion); - commitFrequency: (commitFrequency at: #averageFloat); - commentContribution: (commentContribution at: #avgComments); - mergeRequestDuration: (mergeRequestDuration at: #avgDuration); - codeChurn: (codeChurn at: #churn); - delayUntilFirstChurn: (delayUntilFirstChurn at: #avgDelay); - numberOfProjectWithCommit: - (numberOfProjectWithCommit at: #average); - averageTimeBetweenCommits: - (averageTimeBetweenCommits at: #average); - numberOfOpenMergeRequests: - (numberOfOpenMergeRequests at: #average); - numberOfMergedMergeRequest: - (numberOfMergedMergeRequests at: #average); - numberOfClosedMergeRequests: - (numberOfClosedMergeRequests at: #average); - numberOfMergeRequestsWithoutReview: - (numberOfMergeRequestWithoutReview at: #average); - numberOfTicketsClosed: (numberOfTicketsClosed at: #average) -] - { #category : #initialization } GitMetric4User >> initialize [ @@ -797,341 +183,6 @@ GitMetric4User >> loadProjects [ ^ itsProjects ] -{ #category : #'metrics - merge request' } -GitMetric4User >> mergeRequestDurationSince: since until: until overA: aDateWeekMonthOrYear [ - - | mergeRequest res groupedByDate filterGroups avg | - groupedByDate := self - setupGroupedDateFrom: since - to: until - over: aDateWeekMonthOrYear. - - mergeRequest := self loadItsMergeRequestsSince: since until: until. - - mergeRequest ifEmpty: [ - ^ { - (#avgDuration -> nil). - (#overEach -> aDateWeekMonthOrYear name). - (#forOver -> (groupedByDate keys size printString - , aDateWeekMonthOrYear printString)). - (#totalMergeRequest -> 0). - (#details -> nil) } asDictionary ]. - - res := mergeRequest collect: [ :mr | - gitAnalyzer analyseMergeResquestValidation: mr ]. - - - res do: [ :dic | - | overDate | - overDate := self - transformDate: (dic at: #created_at) - to: aDateWeekMonthOrYear. - - groupedByDate - at: overDate printString - ifPresent: [ :durations | durations add: (dic at: #duration) ] - ifAbsentPut: [ - OrderedCollection new - add: (dic at: #duration); - yourself ] ]. - - - filterGroups := groupedByDate reject: [ :array | array isEmpty ]. - - filterGroups associations do: [ :assoc | - | sum denominator | - denominator := assoc value size. - - sum := assoc value sum: [ :v | - v ifNil: [ - denominator := denominator - 1. - 0 asDuration ] ]. - denominator = 0 ifTrue: [ denominator := 1 ]. - - filterGroups at: assoc key put: sum / denominator ]. - - avg := 0. - filterGroups keys - ifNotEmpty: [ - avg := filterGroups values sum / filterGroups keys size ]. - - - ^ { - (#avgDuration -> avg). - (#overEach -> aDateWeekMonthOrYear name). - (#forOver -> (groupedByDate keys size printString - , aDateWeekMonthOrYear printString)). - (#totalMergeRequest -> mergeRequest size). - (#details -> groupedByDate) } asDictionary -] - -{ #category : #'metrics - merge request' } -GitMetric4User >> numberOfClosedMergeRequestSince: since until: until overA: aDateWeekMonthOrYear [ - - | groupedByDate userMergeRequests dateOver average userClosedMergeRequests | - groupedByDate := self - setupGroupedDateFrom: since - to: until - over: aDateWeekMonthOrYear. - - userMergeRequests := self - loadItsMergeRequestsSince: since - until: until. - - userClosedMergeRequests := userMergeRequests select: [ - :userMergeRequest | - userMergeRequest merged_at isNil and: - userMergeRequest state = 'closed' ]. - - userClosedMergeRequests do: [ :userMergeRequest | - dateOver := self - transformDate: userMergeRequest created_at - to: aDateWeekMonthOrYear. - - groupedByDate - at: dateOver printString - ifPresent: [ :value | value add: userMergeRequest ] ]. - - - groupedByDate := groupedByDate collect: [ :group | group size ]. - - - average := groupedByDate - ifEmpty: [ 0 ] - ifNotEmpty: [ groupedByDate average ]. - - ^ { - (#overEach -> aDateWeekMonthOrYear name). - (#forOver -> (groupedByDate keys size printString - , aDateWeekMonthOrYear printString)). - (#average -> average asFloat). - (#details -> groupedByDate). - (#userMergeRequests -> userMergeRequests size) } asDictionary -] - -{ #category : #'metrics - merge request' } -GitMetric4User >> numberOfMergeRequestsMergedWithoutReviewSince: since until: until overA: aDateWeekMonthOrYear [ - - | groupedByDate userMergeRequests dateOver average noVerificationMergeRequests mergedMergeRequest | - groupedByDate := self - setupGroupedDateFrom: since - to: until - over: aDateWeekMonthOrYear. - - userMergeRequests := self - loadItsMergeRequestsSince: since - until: until. - - mergedMergeRequest := userMergeRequests select: [ :mr | - mr merged_at isNotNil ]. - - - noVerificationMergeRequests := mergedMergeRequest select: [ - :userMergeRequest | - | validation | - glhImporter - importMergeResquestMerger: - userMergeRequest. - - validation := gitAnalyzer - analyseMergeResquestValidation: - userMergeRequest. - - userMergeRequest merge_user - = userMergeRequest author and: - (validation at: #duration) - < 1 minutes ]. - - - noVerificationMergeRequests do: [ :userMergeRequest | - dateOver := self - transformDate: userMergeRequest created_at - to: aDateWeekMonthOrYear. - - groupedByDate - at: dateOver printString - ifPresent: [ :value | value add: userMergeRequest ] ]. - - - groupedByDate := groupedByDate collect: [ :group | group size ]. - - - average := groupedByDate - ifEmpty: [ 0 ] - ifNotEmpty: [ groupedByDate average ]. - - ^ { - (#overEach -> aDateWeekMonthOrYear name). - (#forOver -> (groupedByDate keys size printString - , aDateWeekMonthOrYear printString)). - (#average -> average asFloat). - (#details -> groupedByDate). - (#userMergeRequests -> userMergeRequests size) } asDictionary -] - -{ #category : #'metrics - merge request' } -GitMetric4User >> numberOfMergedMergeRequestsSince: since until: until overA: aDateWeekMonthOrYear [ - - | groupedByDate userMergeRequests dateOver average userMergedMergeRequests | - groupedByDate := self - setupGroupedDateFrom: since - to: until - over: aDateWeekMonthOrYear. - userMergeRequests := self - loadItsMergeRequestsSince: since - until: until. - - userMergedMergeRequests := userMergeRequests select: [ - :userMergeRequest | - userMergeRequest merged_at isNotNil ]. - - userMergedMergeRequests do: [ :userMergeRequest | - dateOver := self - transformDate: userMergeRequest created_at - to: aDateWeekMonthOrYear. - groupedByDate - at: dateOver printString - ifPresent: [ :value | value add: userMergeRequest ] ]. - groupedByDate := groupedByDate collect: [ :group | group size ]. - - average := groupedByDate - ifEmpty: [ 0 ] - ifNotEmpty: [ groupedByDate average ]. - ^ { - (#overEach -> aDateWeekMonthOrYear name). - (#forOver -> (groupedByDate keys size printString - , aDateWeekMonthOrYear printString)). - (#average -> average asFloat). - (#details -> groupedByDate). - (#userMergeRequests -> userMergeRequests size) } asDictionary -] - -{ #category : #'metrics - merge request' } -GitMetric4User >> numberOfOpenMergeRequestsSince: since until: until overA: aDateWeekMonthOrYear [ - - | groupedByDate userMergeRequests dateOver average | - groupedByDate := self - setupGroupedDateFrom: since - to: until - over: aDateWeekMonthOrYear. - - userMergeRequests := self - loadItsMergeRequestsSince: since - until: until. - - userMergeRequests do: [ :userMergeRequest | - dateOver := self - transformDate: userMergeRequest created_at - to: aDateWeekMonthOrYear. - - groupedByDate - at: dateOver printString - ifPresent: [ :value | value add: userMergeRequest ] ]. - - - groupedByDate := groupedByDate collect: [ :group | group size ]. - - - average := groupedByDate - ifEmpty: [ 0 ] - ifNotEmpty: [ groupedByDate average ]. - - ^ { - (#overEach -> aDateWeekMonthOrYear name). - (#forOver -> (groupedByDate keys size printString - , aDateWeekMonthOrYear printString)). - (#average -> average asFloat). - (#details -> groupedByDate). - (#userMergeRequests -> userMergeRequests size) } asDictionary -] - -{ #category : #'metrics - commits' } -GitMetric4User >> numberOfProjectWithCommitSince: since until: until overA: aDateWeekMonthOrYear [ - | groupedByDate commits userCommits dateOver projects | - groupedByDate := self - setupGroupedDateFrom: since - to: until - over: aDateWeekMonthOrYear. - - gitAnalyzer := GitAnalyzer new - onModel: glhModel; - glhImporter: glhImporter. - - glhImporter withCommitDiffs: false. - commits := self - loadCommitsFromProjectsIds: itsProjects keys - since: since - until: until. - glhImporter withCommitDiffs: true. - userCommits := commits reject: [ :commit | commit commitCreator ~= user ]. - - - userCommits do: [ :userCommit | - dateOver := self - transformDate: userCommit committed_date - to: aDateWeekMonthOrYear. - - groupedByDate at: dateOver printString ifPresent: [ :value | value add: (userCommit repository project) ]. - ]. - - groupedByDate := groupedByDate collect: [ :group | - projects := Set newFrom: group. - projects size. - ]. - - ^ { - (#overEach -> aDateWeekMonthOrYear name). - (#forOver -> (groupedByDate keys size printString - , aDateWeekMonthOrYear printString)). - (#average - -> - groupedByDate average asFloat). - (#details -> groupedByDate). - (#userCommits -> commits size) } asDictionary - -] - -{ #category : #'metrics -jira' } -GitMetric4User >> numberOfTicketsClosedSince: since until: until overA: aDateWeekMonthOrYear [ - - | groupedByDate itsMergeRequestsWithJiraIssue dateOver average mergedMergeRequestWithJiraIssue | - groupedByDate := self - setupGroupedDateFrom: since - to: until - over: aDateWeekMonthOrYear. - - itsMergeRequestsWithJiraIssue := self - loadItsMergeRequesWithJiraIssueSince: - since - until: until. - - mergedMergeRequestWithJiraIssue := itsMergeRequestsWithJiraIssue - select: [ :mr | - mr merged_at isNotNil ]. - - mergedMergeRequestWithJiraIssue do: [ :userMergeRequest | - dateOver := self - transformDate: userMergeRequest created_at - to: aDateWeekMonthOrYear. - groupedByDate - at: dateOver printString - ifPresent: [ :value | value add: userMergeRequest ] ]. - - groupedByDate := groupedByDate collect: [ :group | group size ]. - - average := groupedByDate - ifEmpty: [ 0 ] - ifNotEmpty: [ groupedByDate average ]. - ^ { - (#overEach -> aDateWeekMonthOrYear name). - (#forOver -> (groupedByDate keys size printString - , aDateWeekMonthOrYear printString)). - (#average -> average asFloat). - (#details -> groupedByDate). - (#userMergeRequestsWithJiraIssue -> itsMergeRequestsWithJiraIssue size) } - asDictionary -] - { #category : #accessing } GitMetric4User >> user [ ^ user diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index c09cac2..4204edc 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -111,37 +111,6 @@ GitMetricExporter >> analyses: anObject [ analyses := anObject ] -{ #category : #calculating } -GitMetricExporter >> calculateAllMetricsOver: aDateWeekMonthOrYear [ - - | userAnalysisReport result analysesReport newMetric | - runningPeriods do: [ :period | - analysesReport := entities collect: [ :entity | - userAnalysisReport := UserAnalysisReport new - username: entity user name; - period: period; - over: aDateWeekMonthOrYear. - - metrics do: [ :metric | - newMetric := metric new - setPeriodSince: - (period at: #since) - until: (period at: #until); - over: aDateWeekMonthOrYear; - user: entity. - - - result := newMetric calculate. - userAnalysisReport metrics - at: newMetric name - put: result ]. - - userAnalysisReport ]. - self analyses addAll: analysesReport ]. - - ^ analyses -] - { #category : #utilities } GitMetricExporter >> constructFilePath: runningOver [ @@ -309,40 +278,34 @@ GitMetricExporter >> findProjectsOfUser: aCollection [ ] { #category : #analysis } -GitMetricExporter >> generateAnalyses [ - - | newAnalyses | - newAnalyses := OrderedCollection new. +GitMetricExporter >> generateAnalysesOver: aDateWeekMonthOrYear [ + | userAnalysisReport result analysesReport newMetric | runningPeriods do: [ :period | - newAnalyses addAll: (entities collect: [ :entity | - entity - generateAnalysisForPeriod: period - over: over - withMaxCommitWindows: maxCommitWindow ]) ]. - - self analyses: newAnalyses. - - ^ newAnalyses -] + analysesReport := entities collect: [ :entity | + userAnalysisReport := UserAnalysisReport new + username: entity user name; + period: period; + over: aDateWeekMonthOrYear. -{ #category : #analysis } -GitMetricExporter >> generateAnalysesOver: aDateWeekMonthOrYear [ + metrics do: [ :metric | + newMetric := metric new + setPeriodSince: + (period at: #since) + until: (period at: #until); + over: aDateWeekMonthOrYear; + user: entity. - | newAnalyses | - over := aDateWeekMonthOrYear. - newAnalyses := OrderedCollection new. - runningPeriods do: [ :period | - newAnalyses addAll: (entities collect: [ :entity | - entity - generateAnalysisForPeriod: period - over: over - withMaxCommitWindows: maxCommitWindow ]) ]. + result := newMetric calculate. + userAnalysisReport metrics + at: newMetric name + put: result ]. - self analyses: newAnalyses. + userAnalysisReport ]. + self analyses addAll: analysesReport ]. - ^ newAnalyses + ^ analyses ] { #category : #utilities } From 817af1cf484f3c7fe06fdfca3f6992c4de088ca4 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Thu, 29 Aug 2024 16:31:36 +0200 Subject: [PATCH 074/154] refactor: remove unused method in UserMetric --- .../UserMetric.class.st | 43 ------------------- 1 file changed, 43 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/UserMetric.class.st b/src/GitLabHealth-Model-Analysis/UserMetric.class.st index 0ec791e..d2ae287 100644 --- a/src/GitLabHealth-Model-Analysis/UserMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserMetric.class.st @@ -40,49 +40,6 @@ UserMetric >> load [ ^ self subclassResponsibility ] -{ #category : #loading } -UserMetric >> loadUserCommits [ - - userCommits := user loadCommitsSince: (period at: #since) until: (period at: #until) -] - -{ #category : #loading } -UserMetric >> loadUserMergeRequests [ - - | mergeRequests cacheSymbol | - glhImporter withCommitDiffs: false. - cacheSymbol := self - cacheSymbolFor: GLPHEMergeRequest - since: (period at: #since) - until: (period at: #until). - - mergeRequests := userProjects collect: [ :project | - | mr | - project cacheAt: cacheSymbol ifAbsentPut: [ - mr := glhImporter - importMergeRequests: project - since: (period at: #since) - until: (period at: #until). - mr ] ]. - - mergeRequests := mergeRequests flattened. - glhImporter withCommitDiffs: true. - - mergeRequests do: [ :mr | glhImporter importMergeResquestAuthor: mr ]. - - userMergeRequests := mergeRequests select: [ :mergeRequest | - mergeRequest author = user ]. - ^ userMergeRequests -] - -{ #category : #loading } -UserMetric >> loadUserProjects [ - - userProjects := glhImporter importContributedProjectsOfUser: user. - - userProjects do: [ :project | glhImporter completeImportProject: project] -] - { #category : #accessing } UserMetric >> name [ From ab00fd805bfa05b867a4c8058428260b1d680a7d Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Thu, 29 Aug 2024 16:53:23 +0200 Subject: [PATCH 075/154] fix: fix loadMergeRequestsWith jira issue name --- .../GitMetric4User.class.st | 40 +++++++++---------- .../UserJiraMetric.class.st | 3 +- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st index 88c48fe..c9bc3cf 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st @@ -119,27 +119,6 @@ GitMetric4User >> loadCompleteMergeRequestsSince: since until: until [ ^mergeRequests ] -{ #category : #loading } -GitMetric4User >> loadMergeRequesWithJiraIssueSince: since until: until [ - - | email | - itsMergeRequests := self - loadMergeRequestsSince: since - until: until. - - email := self userEmail. - - jiraImporter importAllCurrentAndPastIssuesOf: email. - - GPJCConnector new - gpModel: glhImporter glhModel; - jiraModel: jiraImporter model; - connect. - - ^ itsMergeRequests select: [ :mergeRequest | - mergeRequest jiraIssue isNotNil ] -] - { #category : #loading } GitMetric4User >> loadMergeRequestsSince: since until: until [ @@ -170,6 +149,25 @@ GitMetric4User >> loadMergeRequestsSince: since until: until [ ^ userMergeRequests ] +{ #category : #loading } +GitMetric4User >> loadMergeRequestsWithJiraIssueSince: since until: until [ + + | email | + itsMergeRequests := self loadMergeRequestsSince: since until: until. + + email := self userEmail. + + jiraImporter importAllCurrentAndPastIssuesOf: email. + + GPJCConnector new + gpModel: glhImporter glhModel; + jiraModel: jiraImporter model; + connect. + + ^ itsMergeRequests select: [ :mergeRequest | + mergeRequest jiraIssue isNotNil ] +] + { #category : #loading } GitMetric4User >> loadProjects [ diff --git a/src/GitLabHealth-Model-Analysis/UserJiraMetric.class.st b/src/GitLabHealth-Model-Analysis/UserJiraMetric.class.st index a3c6095..1f0ccac 100644 --- a/src/GitLabHealth-Model-Analysis/UserJiraMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserJiraMetric.class.st @@ -18,8 +18,9 @@ UserJiraMetric >> description [ { #category : #loading } UserJiraMetric >> load [ + userMergeRequests := user - loadMergeRequesWithJiraIssueSince: + loadMergeRequestsWithJiraIssueSince: (period at: #since) until: (period at: #until) ] From a3e239fa8a03a19364257afb6eeb14965b8024e6 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Fri, 30 Aug 2024 13:19:32 +0200 Subject: [PATCH 076/154] fix: remove unused code --- src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st | 3 +-- .../GLPHModelImporter.class.st | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 4204edc..aac90d5 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -169,7 +169,6 @@ GitMetricExporter >> exportInCSV [ | exportBrowserModel file groupedByOver groupByName periods group groupOver csvMetrics | exportBrowserModel := MiExportModel new. - self analyses ifNil: [ self generateAnalyses ]. groupedByOver := self analyses groupedBy: #over. groupedByOver associations do: [ :groupAssociation | @@ -280,7 +279,7 @@ GitMetricExporter >> findProjectsOfUser: aCollection [ { #category : #analysis } GitMetricExporter >> generateAnalysesOver: aDateWeekMonthOrYear [ - | userAnalysisReport result analysesReport newMetric | + | userAnalysisReport result analysesReport newMetric | runningPeriods do: [ :period | analysesReport := entities collect: [ :entity | userAnalysisReport := UserAnalysisReport new diff --git a/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st b/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st index 6d29a5f..971ba06 100644 --- a/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st +++ b/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st @@ -296,7 +296,7 @@ GLPHModelImporter >> importMergeRequests: aGLHProject since: fromDate until: toD self withCommitDiffs ifTrue: [ aGLHProject mergeRequests do: [ :mr | self importDiffOfMergeRequest: mr ] ]. - + self glhModel addAll: foundMR unless: (self blockEqualityOn: #iid). ^ foundMR From 3be43eb6193eb5fef73a78abfdcec5acea175b65 Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Fri, 30 Aug 2024 14:38:01 +0200 Subject: [PATCH 077/154] add levenshtein distance and RSHeatMap --- .../GLHUserCatalogueV2.class.st | 66 +++++++++++++++++++ .../String.extension.st | 6 ++ src/GitLabHealth-Model/GLHUser.class.st | 2 +- 3 files changed, 73 insertions(+), 1 deletion(-) diff --git a/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st b/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st index b9b6c58..8739277 100644 --- a/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st +++ b/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st @@ -83,6 +83,46 @@ GLHUserCatalogueV2 class >> scrapeWithImporter: anImporter contributedProjectsFo ^ (aGLHUser commits collect: [ :commit | commit author_name ]) asSet ] +{ #category : #'as yet unclassified' } +GLHUserCatalogueV2 >> RSHeatMapLevenshtein [ + + | builder| + builder := RSHeatmap new. + builder objectsX: self keys. + builder objectsY: self keys. + + builder dataMatrix: self levenshteinMatrix. + + builder build. + builder gradientLegend remove. + builder canvas open +] + +{ #category : #'as yet unclassified' } +GLHUserCatalogueV2 >> RSHeatMapLevenshteinTrimedAt: aBlockCondition [ + + | builder matrice| + builder := RSHeatmap new. + builder objectsX: self keys. + builder objectsY: self keys. + + + matrice := self levenshteinMatrix. + 1 to: matrice size do: [ :i | + 1 to: (matrice at: i) size do: [ :j | + |val| + val := ((matrice at: i) at: j). + (matrice at: i) at: j put: ( aBlockCondition value: val ). + ] ]. + + + builder dataMatrix: matrice. + + builder build. + builder gradientLegend remove. + builder canvas open +] + { #category : #adding } GLHUserCatalogueV2 >> addUser: aGLHUser [ @@ -189,12 +229,38 @@ GLHUserCatalogueV2 >> exportToJson [ ^ STONJSON toString: tempDic ] +{ #category : #fuse } +GLHUserCatalogueV2 >> fuse: mainUser with: subUser [ + self at: mainUser ifPresent: [ :entry | + self at: subUser ifAbsent: [ ^ self ]. + (entry at: #names) addAll: (self at: subUser at: #names ). + self removeKey: subUser. + ]. +] + { #category : #initialization } GLHUserCatalogueV2 >> initialize [ anImporter := GLHModelImporter current. ] +{ #category : #'as yet unclassified' } +GLHUserCatalogueV2 >> levenshteinMatrix [ + | matrix| + + matrix := Array new: self keys size . + 1 to: matrix size do: [ :i | matrix at: i put: (Array new: self keys size) ]. + + 1 to: self keys size do: [ :i | + 1 to: self keys size do: [ :j | + + (matrix at: i) at: j put: ( (self keys at: i) absLevenshteinDistanceWith: (self keys at: j) ). + ]. + ]. + + ^ matrix. +] + { #category : #'accessing - name' } GLHUserCatalogueV2 >> names [ ^ self collect: [ :entry | entry at: #names ] diff --git a/src/GitLabHealth-Model-Analysis/String.extension.st b/src/GitLabHealth-Model-Analysis/String.extension.st index 249814e..d6be4df 100644 --- a/src/GitLabHealth-Model-Analysis/String.extension.st +++ b/src/GitLabHealth-Model-Analysis/String.extension.st @@ -1,5 +1,11 @@ Extension { #name : #String } +{ #category : #'*GitLabHealth-Model-Analysis' } +String >> absLevenshteinDistanceWith: aString [ + ^ { self levenshteinDistanceWith: aString . + aString levenshteinDistanceWith: self } max. +] + { #category : #'*GitLabHealth-Model-Analysis' } String >> levenshteinDistanceWith: aString [ | m n distances cost | diff --git a/src/GitLabHealth-Model/GLHUser.class.st b/src/GitLabHealth-Model/GLHUser.class.st index c4996ed..a5ca67c 100644 --- a/src/GitLabHealth-Model/GLHUser.class.st +++ b/src/GitLabHealth-Model/GLHUser.class.st @@ -336,7 +336,7 @@ GLHUser >> name [ - ^ name + ^ name ] { #category : #accessing } From 81832ecb3bc8a238081671028102a74b776632ac Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Mon, 2 Sep 2024 17:31:30 +0200 Subject: [PATCH 078/154] refactor: remove GitMetric and GitMetric4User classes --- .../CodeChurnMetric.class.st | 4 +- .../CommentContributionMetric.class.st | 5 +- .../DelayUntilFirstChurnMetric.class.st | 6 +- .../GitMetric.class.st | 213 ------------------ .../GitMetric4Group.class.st | 8 - .../GitMetric4Project.class.st | 8 - .../GitMetric4User.class.st | 211 ----------------- .../GitMetricExporter.class.st | 29 +-- ...edMergeRequestWithoutReviewMetric.class.st | 2 +- .../Metric.class.st | 16 +- .../UserCommitsMetric.class.st | 2 +- .../UserJiraMetric.class.st | 2 +- .../UserMergeRequestMetric.class.st | 2 +- .../UserMetric.class.st | 139 +++++++++++- 14 files changed, 180 insertions(+), 467 deletions(-) delete mode 100644 src/GitLabHealth-Model-Analysis/GitMetric.class.st delete mode 100644 src/GitLabHealth-Model-Analysis/GitMetric4Group.class.st delete mode 100644 src/GitLabHealth-Model-Analysis/GitMetric4Project.class.st delete mode 100644 src/GitLabHealth-Model-Analysis/GitMetric4User.class.st diff --git a/src/GitLabHealth-Model-Analysis/CodeChurnMetric.class.st b/src/GitLabHealth-Model-Analysis/CodeChurnMetric.class.st index 5e41133..18917e8 100644 --- a/src/GitLabHealth-Model-Analysis/CodeChurnMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CodeChurnMetric.class.st @@ -12,12 +12,12 @@ CodeChurnMetric >> calculate [ | commits res groupedByDate totalContributions gitAnalyzer | userCommits ifNil: [ self load ]. - + totalContributions := OrderedCollection new. groupedByDate := self setupGroupedDate. gitAnalyzer := GitAnalyzer new maxChildCommit: maxCommitWindow. - commits := user + commits := self foundSuccessorOf: userCommits andCompleteImportForMax: maxCommitWindow. diff --git a/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st b/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st index b37793a..33d3fe4 100644 --- a/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st @@ -47,7 +47,10 @@ CommentContributionMetric >> description [ { #category : #loading } CommentContributionMetric >> load [ - userCommits := user loadCompleteCommitsSince: (period at: #since) until: (period at: #until). + + userCommits := self + loadCompleteCommitsSince: (period at: #since) + until: (period at: #until) ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/DelayUntilFirstChurnMetric.class.st b/src/GitLabHealth-Model-Analysis/DelayUntilFirstChurnMetric.class.st index 4bc759c..61b51fa 100644 --- a/src/GitLabHealth-Model-Analysis/DelayUntilFirstChurnMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/DelayUntilFirstChurnMetric.class.st @@ -13,14 +13,14 @@ DelayUntilFirstChurnMetric >> calculate [ | commits groupedByDate res average | userCommits ifNil: [ self load ]. groupedByDate := self setupGroupedDate. - commits := user + commits := self foundSuccessorOf: userCommits andCompleteImportForMax: maxCommitWindow. "class commit by dates, filter none user commits" commits do: [ :commit | - commit commitCreator = user user ifTrue: [ + commit commitCreator = user ifTrue: [ | overDate | overDate := self transformDate: commit created_at to: over. @@ -59,7 +59,7 @@ DelayUntilFirstChurnMetric >> calculate [ ifFalse: [ (filtered sum: [ :v | v asDuration asSeconds ]) / filtered size ] ]. - + res := res reject: #isNil. average := res diff --git a/src/GitLabHealth-Model-Analysis/GitMetric.class.st b/src/GitLabHealth-Model-Analysis/GitMetric.class.st deleted file mode 100644 index 5127304..0000000 --- a/src/GitLabHealth-Model-Analysis/GitMetric.class.st +++ /dev/null @@ -1,213 +0,0 @@ -Class { - #name : #GitMetric, - #superclass : #Object, - #instVars : [ - 'user', - 'glhImporter', - 'jiraImporter', - 'itsProjects', - 'gitAnalyzer', - 'glhModel' - ], - #category : #'GitLabHealth-Model-Analysis' -} - -{ #category : #setup } -GitMetric class >> setupGroupedDateFrom: since to: until over: aDateWeekMonthOrYear [ - - | groupedByDate start end over increment | - groupedByDate := OrderedDictionary new. - - increment := 1. - start := self transformDate: since to: aDateWeekMonthOrYear. - end := self transformDate: until to: aDateWeekMonthOrYear. - - groupedByDate - at: start printString - ifAbsentPut: [ OrderedCollection new ]. - - over := aDateWeekMonthOrYear name asLowercase asSymbol. - over = #date ifTrue: [ over := #day ]. - over = #month ifTrue: [ - increment := 32. - over := #day ]. - - - [ groupedByDate keys last asDateAndTime < end ] whileTrue: [ - | index | - index := groupedByDate keys last asDateAndTime - + (increment perform: over). - index := self transformDate: index to: aDateWeekMonthOrYear. - groupedByDate - at: index printString - ifAbsentPut: [ OrderedCollection new ] ]. - - - over = #day ifTrue: [ - groupedByDate keysDo: [ :date | - | aWeekday | - aWeekday := date asDate weekday. - (aWeekday = #Sunday or: [ aWeekday = #Saturday ]) ifTrue: [ - groupedByDate removeKey: date ] ] ]. - - - groupedByDate - at: end printString - ifAbsentPut: [ OrderedCollection new ]. - - ^ groupedByDate -] - -{ #category : #'as yet unclassified' } -GitMetric class >> transformDate: date to: aWeekOrMonthOrYear [ - - aWeekOrMonthOrYear = Month ifTrue: [ ^ date asDate month asDate ]. - - ^ (date asDate perform: ('as' , aWeekOrMonthOrYear name) asSymbol) - asDate -] - -{ #category : #'as yet unclassified' } -GitMetric >> cacheSymbolFor: anEntityType since: since until: until [ - - ^ (anEntityType printString , ' since ' , since printString , ' to ' - , until printString) asSymbol -] - -{ #category : #'as yet unclassified' } -GitMetric >> findUserNamed: aUsername [ - - user := glhImporter importUserByUsername: aUsername. - ^ user -] - -{ #category : #accessing } -GitMetric >> glhImporter: aGLPHModelImporter [ - glhImporter := aGLPHModelImporter -] - -{ #category : #accessing } -GitMetric >> jiraImporter: anObject [ - - jiraImporter := anObject -] - -{ #category : #churn } -GitMetric >> loadCommitsFromProjectsIds: aCollection since: since until: until [ - - | allCommits period size i| - period := self cacheSymbolFor: GLHCommit since: since until: until. - - "download commits unless project cache is not empty" - allCommits := aCollection collect: [ :idProject | - | project | - project := itsProjects at: idProject. - project repository cacheAt: period ifAbsentPut: [ - | foundCommits | - foundCommits := glhImporter - importCommitsOProject: project - since: since - until: until. - foundCommits ] ]. - - allCommits := allCommits flatten. - - i := 0. - size := allCommits size. - allCommits do: [ :commit | - ('import commit creators [', (i:=i+1) printString, '/', size printString) recordInfo. - - glhImporter importCreatorOfCommit: commit ]. - - glhImporter chainsCommitsFrom: allCommits. - - ^ allCommits -] - -{ #category : #churn } -GitMetric >> loadMergeRequestsFromProjectsIds: aCollection since: since until: until [ - - | allMr period | - "itsMergeRequests ifNil: [ itsMergeRequests := Dictionary new ]." - period := self - cacheSymbolFor: GLPHEMergeRequest - since: since - until: until. - - allMr := aCollection collect: [ :idProject | - | project mr | - project := itsProjects at: idProject. - project cacheAt: period ifAbsentPut: [ - mr := glhImporter - importMergeRequests: project - since: since - until: until. - mr ] ]. - - ^ allMr flattened -] - -{ #category : #loading } -GitMetric >> loadProjectsFromIds: projectIds [ - - projectIds do: [ :id | - - itsProjects at: id ifAbsentPut: [ glhImporter importProject: id ] ]. - - ^ itsProjects -] - -{ #category : #setup } -GitMetric >> setupGroupedDateFrom: since to: until over: aDateWeekMonthOrYear [ - - | groupedByDate start end over increment | - groupedByDate := OrderedDictionary new. - - increment := 1. - start := self transformDate: since to: aDateWeekMonthOrYear. - end := self transformDate: until to: aDateWeekMonthOrYear. - - groupedByDate - at: start printString - ifAbsentPut: [ OrderedCollection new ]. - - over := aDateWeekMonthOrYear name asLowercase asSymbol. - over = #date ifTrue: [ over := #day ]. - over = #month ifTrue: [ - increment := 32. - over := #day ]. - - - [ groupedByDate keys last asDateAndTime < end ] whileTrue: [ - | index | - index := groupedByDate keys last asDateAndTime - + (increment perform: over). - index := self transformDate: index to: aDateWeekMonthOrYear. - groupedByDate - at: index printString - ifAbsentPut: [ OrderedCollection new ] ]. - - - over = #day ifTrue: [ - - groupedByDate := (groupedByDate associations select: [ :date | - | aWeekday | - aWeekday := date key asDate weekday. - (aWeekday = #Sunday or: [ aWeekday = #Saturday ]) not ]) asOrderedDictionary ]. - - - groupedByDate - at: end printString - ifAbsentPut: [ OrderedCollection new ]. - - ^ groupedByDate -] - -{ #category : #'as yet unclassified' } -GitMetric >> transformDate: date to: aWeekOrMonthOrYear [ - - aWeekOrMonthOrYear = Month ifTrue: [ ^ date asDate month asDate ]. - - ^ (date asDate perform: ('as' , aWeekOrMonthOrYear name) asSymbol) - asDate -] diff --git a/src/GitLabHealth-Model-Analysis/GitMetric4Group.class.st b/src/GitLabHealth-Model-Analysis/GitMetric4Group.class.st deleted file mode 100644 index dc8a9ec..0000000 --- a/src/GitLabHealth-Model-Analysis/GitMetric4Group.class.st +++ /dev/null @@ -1,8 +0,0 @@ -Class { - #name : #GitMetric4Group, - #superclass : #GitMetric, - #instVars : [ - 'project' - ], - #category : 'GitLabHealth-Model-Analysis' -} diff --git a/src/GitLabHealth-Model-Analysis/GitMetric4Project.class.st b/src/GitLabHealth-Model-Analysis/GitMetric4Project.class.st deleted file mode 100644 index 4e7136c..0000000 --- a/src/GitLabHealth-Model-Analysis/GitMetric4Project.class.st +++ /dev/null @@ -1,8 +0,0 @@ -Class { - #name : #GitMetric4Project, - #superclass : #GitMetric, - #instVars : [ - 'project' - ], - #category : 'GitLabHealth-Model-Analysis' -} diff --git a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st b/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st deleted file mode 100644 index c9bc3cf..0000000 --- a/src/GitLabHealth-Model-Analysis/GitMetric4User.class.st +++ /dev/null @@ -1,211 +0,0 @@ -Class { - #name : #GitMetric4User, - #superclass : #GitMetric, - #instVars : [ - 'itsCommits', - 'itsMergeRequests', - 'emailDomain' - ], - #category : #'GitLabHealth-Model-Analysis' -} - -{ #category : #churn } -GitMetric4User >> foundSuccessorOf: userCommits andCompleteImportForMax: commitLimit [ - - | analyzingCommits i size | - analyzingCommits := Set new. - glhImporter withCommitDiffs: true. - - userCommits do: [ :c | - GitAnalyzer new - visitChildCommits: c childCommits - toStoreThemIn: analyzingCommits - upto: commitLimit ]. - - i := 0. - size := analyzingCommits size. - analyzingCommits do: [ :c | - ('import complete commits [' , (i := i + 1) printString , '/' - , size printString , ']') recordInfo. - glhImporter completeImportedCommit: c ]. - - ^ analyzingCommits -] - -{ #category : #initialization } -GitMetric4User >> initialize [ - - user := GLHUser new. - itsCommits := Dictionary new. - itsMergeRequests := Dictionary new. - - emailDomain := '@generic-domain.com' -] - -{ #category : #accessing } -GitMetric4User >> itsProjects: projects [ - itsProjects := projects . -] - -{ #category : #churn } -GitMetric4User >> loadCommitOfProjects: aCollection since: aTimespan [ - |commits| - - commits := (aCollection collect: [ :id | - glhImporter - importCommitsOProject: (itsProjects at: id) - since: aTimespan - until: nil ]) flattened. - - commits do: [ :commit | - glhImporter completeImportedCommit: commit. - ]. - - ^ self userCommits. -] - -{ #category : #loading } -GitMetric4User >> loadCommitsSince: since until: until [ - - | cacheSymbol allCommits userCommits | - itsProjects ifNil: [ self loadProjects ]. - - glhImporter withCommitDiffs: false. - - cacheSymbol := self - cacheSymbolFor: GLHCommit - since: since - until: until. - - "download commits unless project cache is not empty" - allCommits := itsProjects collect: [ :project | - project repository cacheAt: cacheSymbol ifAbsentPut: [ - | foundCommits | - foundCommits := glhImporter - importCommitsOProject: project - since: since - until: until. - foundCommits ] ]. - - allCommits := allCommits flatten. - allCommits do: [ :commit | glhImporter importCreatorOfCommit: commit ]. - glhImporter chainsCommitsFrom: allCommits. - glhImporter withCommitDiffs: true. - - ^ userCommits := allCommits reject: [ :commit | - commit commitCreator ~= user ] -] - -{ #category : #loading } -GitMetric4User >> loadCompleteCommitsSince: since until: until [ - - | commits | - commits := self loadCommitsSince: since until: until. - commits do: [ :commit | glhImporter completeImportedCommit: commit ]. - ^commits - - -] - -{ #category : #loading } -GitMetric4User >> loadCompleteMergeRequestsSince: since until: until [ - - | mergeRequests | - mergeRequests := self loadMergeRequestsSince: since until: until. - - mergeRequests do: [ :mergeRequest | - glhImporter importMergeResquestMerger: mergeRequest ]. - - ^mergeRequests -] - -{ #category : #loading } -GitMetric4User >> loadMergeRequestsSince: since until: until [ - - | cacheSymbol mergeRequests userMergeRequests | - itsProjects ifNil: [ self loadProjects ]. - glhImporter withCommitDiffs: false. - cacheSymbol := self - cacheSymbolFor: GLPHEMergeRequest - since: since - until: until. - - mergeRequests := itsProjects collect: [ :project | - | mr | - project cacheAt: cacheSymbol ifAbsentPut: [ - mr := glhImporter - importMergeRequests: project - since: since - until: until. - mr ] ]. - - mergeRequests := mergeRequests flattened. - glhImporter withCommitDiffs: true. - - mergeRequests do: [ :mr | glhImporter importMergeResquestAuthor: mr ]. - - userMergeRequests := mergeRequests select: [ :mergeRequest | - mergeRequest author = user ]. - ^ userMergeRequests -] - -{ #category : #loading } -GitMetric4User >> loadMergeRequestsWithJiraIssueSince: since until: until [ - - | email | - itsMergeRequests := self loadMergeRequestsSince: since until: until. - - email := self userEmail. - - jiraImporter importAllCurrentAndPastIssuesOf: email. - - GPJCConnector new - gpModel: glhImporter glhModel; - jiraModel: jiraImporter model; - connect. - - ^ itsMergeRequests select: [ :mergeRequest | - mergeRequest jiraIssue isNotNil ] -] - -{ #category : #loading } -GitMetric4User >> loadProjects [ - - itsProjects ifNotNil: [ ^ itsProjects ]. - - itsProjects := glhImporter importContributedProjectsOfUser: user. - - itsProjects do: [ :project | - glhImporter completeImportProject: project ]. - - ^ itsProjects -] - -{ #category : #accessing } -GitMetric4User >> user [ - ^ user -] - -{ #category : #accessing } -GitMetric4User >> user: anUser [ - user := anUser. -] - -{ #category : #accessing } -GitMetric4User >> userCommits [ - ^ user commits -] - -{ #category : #email } -GitMetric4User >> userEmail [ - "overide this method to adapt on your situation" - - ^ ('' join: { - user username. - emailDomain }) asLowercase. -] - -{ #category : #email } -GitMetric4User >> withUserEmailDomain: aEmailDomain [ - emailDomain := aEmailDomain. -] diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index aac90d5..487f73f 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -283,7 +283,7 @@ GitMetricExporter >> generateAnalysesOver: aDateWeekMonthOrYear [ runningPeriods do: [ :period | analysesReport := entities collect: [ :entity | userAnalysisReport := UserAnalysisReport new - username: entity user name; + username: entity name; period: period; over: aDateWeekMonthOrYear. @@ -293,7 +293,10 @@ GitMetricExporter >> generateAnalysesOver: aDateWeekMonthOrYear [ (period at: #since) until: (period at: #until); over: aDateWeekMonthOrYear; - user: entity. + user: entity; + glhImporter: glhImporter; + jiraImporter: jiraImporter; + emailDomain: emailDomain. result := newMetric calculate. @@ -407,18 +410,16 @@ GitMetricExporter >> setupAnalysisForUsersWithNames: userNames [ glhImporter importUserByUsername: username ]. glhImporter userCatalogue scrapeAuthorNamesForUsers: users. - - entities addAll: (users collect: [ :user | - | metricUser | - metricUser := GitMetric4User new. - metricUser - glhImporter: glhImporter; - jiraImporter: jiraImporter; - withUserEmailDomain: emailDomain; - user: user. - - metricUser loadProjects. - metricUser ]). + + users do: [ :user | + |projects | + projects := glhImporter importContributedProjectsOfUser: user. + projects do: [ :project | + glhImporter completeImportProject: project ]. + + ]. + + entities addAll: users. ^ self ] diff --git a/src/GitLabHealth-Model-Analysis/MergedMergeRequestWithoutReviewMetric.class.st b/src/GitLabHealth-Model-Analysis/MergedMergeRequestWithoutReviewMetric.class.st index 0c19679..4371515 100644 --- a/src/GitLabHealth-Model-Analysis/MergedMergeRequestWithoutReviewMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/MergedMergeRequestWithoutReviewMetric.class.st @@ -52,7 +52,7 @@ MergedMergeRequestWithoutReviewMetric >> description [ { #category : #loading } MergedMergeRequestWithoutReviewMetric >> load [ - userMergeRequests := user + userMergeRequests := self loadCompleteMergeRequestsSince: (period at: #since) until: (period at: #until) diff --git a/src/GitLabHealth-Model-Analysis/Metric.class.st b/src/GitLabHealth-Model-Analysis/Metric.class.st index ad447f9..912cf06 100644 --- a/src/GitLabHealth-Model-Analysis/Metric.class.st +++ b/src/GitLabHealth-Model-Analysis/Metric.class.st @@ -3,7 +3,9 @@ Class { #superclass : #Object, #instVars : [ 'period', - 'over' + 'over', + 'glhImporter', + 'jiraImporter' ], #category : #'GitLabHealth-Model-Analysis' } @@ -20,6 +22,18 @@ Metric >> description [ ^ self subclassResponsibility ] +{ #category : #accessing } +Metric >> glhImporter: anObject [ + + glhImporter := anObject +] + +{ #category : #accessing } +Metric >> jiraImporter: anObject [ + + jiraImporter := anObject +] + { #category : #loading } Metric >> load [ ^self subclassResponsibility diff --git a/src/GitLabHealth-Model-Analysis/UserCommitsMetric.class.st b/src/GitLabHealth-Model-Analysis/UserCommitsMetric.class.st index 843d94a..c4fe087 100644 --- a/src/GitLabHealth-Model-Analysis/UserCommitsMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserCommitsMetric.class.st @@ -19,7 +19,7 @@ UserCommitsMetric >> description [ { #category : #loading } UserCommitsMetric >> load [ - userCommits := user + userCommits := self loadCommitsSince: (period at: #since) until: (period at: #until) ] diff --git a/src/GitLabHealth-Model-Analysis/UserJiraMetric.class.st b/src/GitLabHealth-Model-Analysis/UserJiraMetric.class.st index 1f0ccac..b09b6f2 100644 --- a/src/GitLabHealth-Model-Analysis/UserJiraMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserJiraMetric.class.st @@ -19,7 +19,7 @@ UserJiraMetric >> description [ { #category : #loading } UserJiraMetric >> load [ - userMergeRequests := user + userMergeRequests := self loadMergeRequestsWithJiraIssueSince: (period at: #since) until: (period at: #until) diff --git a/src/GitLabHealth-Model-Analysis/UserMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/UserMergeRequestMetric.class.st index 056fad9..c9f94e9 100644 --- a/src/GitLabHealth-Model-Analysis/UserMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserMergeRequestMetric.class.st @@ -19,7 +19,7 @@ UserMergeRequestMetric >> description [ { #category : #loading } UserMergeRequestMetric >> load [ - userMergeRequests := user + userMergeRequests := self loadMergeRequestsSince: (period at: #since) until: (period at: #until) ] diff --git a/src/GitLabHealth-Model-Analysis/UserMetric.class.st b/src/GitLabHealth-Model-Analysis/UserMetric.class.st index d2ae287..4cbabfc 100644 --- a/src/GitLabHealth-Model-Analysis/UserMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserMetric.class.st @@ -3,9 +3,9 @@ Class { #superclass : #Metric, #instVars : [ 'user', - 'userProjects', 'userCommits', - 'userMergeRequests' + 'userMergeRequests', + 'emailDomain' ], #category : #'GitLabHealth-Model-Analysis' } @@ -29,6 +29,34 @@ UserMetric >> description [ ^ self subclassResponsibility ] +{ #category : #accessing } +UserMetric >> emailDomain: anObject [ + + emailDomain := anObject +] + +{ #category : #churn } +UserMetric >> foundSuccessorOf: commits andCompleteImportForMax: commitLimit [ + + | analyzingCommits i size | + analyzingCommits := Set new. + glhImporter withCommitDiffs: true. + + commits do: [ :c | + GitAnalyzer new + visitChildCommits: c childCommits + toStoreThemIn: analyzingCommits + upto: commitLimit ]. + + i := 0. + size := analyzingCommits size. + analyzingCommits do: [ :c | + + glhImporter completeImportedCommit: c ]. + + ^ analyzingCommits +] + { #category : #initialization } UserMetric >> initialize [ over := Date @@ -40,6 +68,106 @@ UserMetric >> load [ ^ self subclassResponsibility ] +{ #category : #loading } +UserMetric >> loadCommitsSince: since until: until [ + + | cacheSymbol allCommits | + glhImporter withCommitDiffs: false. + + cacheSymbol := self + cacheSymbolFor: GLHCommit + since: since + until: until. + + "download commits unless project cache is not empty" + allCommits := user contributedProjects collect: [ :project | + project repository + cacheAt: cacheSymbol + ifAbsentPut: [ + | foundCommits | + foundCommits := glhImporter + importCommitsOProject: project + since: since + until: until. + foundCommits ] ]. + + allCommits := allCommits flatten. + allCommits do: [ :commit | glhImporter importCreatorOfCommit: commit ]. + glhImporter chainsCommitsFrom: allCommits. + glhImporter withCommitDiffs: true. + + ^allCommits reject: [ :commit | + commit commitCreator ~= user ] +] + +{ #category : #loading } +UserMetric >> loadCompleteCommitsSince: since until: until [ + + | commits | + commits := self loadCommitsSince: since until: until. + commits do: [ :commit | glhImporter completeImportedCommit: commit ]. + ^ commits +] + +{ #category : #loading } +UserMetric >> loadCompleteMergeRequestsSince: since until: until [ + + | mergeRequests | + mergeRequests := self loadMergeRequestsSince: since until: until. + + mergeRequests do: [ :mergeRequest | + glhImporter importMergeResquestMerger: mergeRequest ]. + + ^ mergeRequests +] + +{ #category : #loading } +UserMetric >> loadMergeRequestsSince: since until: until [ + + | cacheSymbol mergeRequests | + glhImporter withCommitDiffs: false. + cacheSymbol := self + cacheSymbolFor: GLPHEMergeRequest + since: since + until: until. + + mergeRequests := user contributedProjects collect: [ :project | + | mr | + project cacheAt: cacheSymbol ifAbsentPut: [ + mr := glhImporter + importMergeRequests: project + since: since + until: until. + mr ] ]. + + mergeRequests := mergeRequests flattened. + glhImporter withCommitDiffs: true. + + mergeRequests do: [ :mr | glhImporter importMergeResquestAuthor: mr ]. + + ^mergeRequests select: [ :mergeRequest | + mergeRequest author = user ]. +] + +{ #category : #loading } +UserMetric >> loadMergeRequestsWithJiraIssueSince: since until: until [ + + | email mergeRequests | + mergeRequests := self loadMergeRequestsSince: since until: until. + + email := self userEmail. + + jiraImporter importAllCurrentAndPastIssuesOf: email. + + GPJCConnector new + gpModel: glhImporter glhModel; + jiraModel: jiraImporter model; + connect. + + ^ mergeRequests select: [ :mergeRequest | + mergeRequest jiraIssue isNotNil ] +] + { #category : #accessing } UserMetric >> name [ @@ -51,3 +179,10 @@ UserMetric >> user: anObject [ user := anObject ] + +{ #category : #email } +UserMetric >> userEmail [ + ^ ('' join: { + user username. + emailDomain }) asLowercase +] From bae5d110753ba38a37f9116246e181aec56a0327 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Tue, 3 Sep 2024 13:28:53 +0200 Subject: [PATCH 079/154] refactor: deprecate addEntities methods --- .../GitMetricExporter.class.st | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 487f73f..7d31e12 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -40,6 +40,12 @@ GitMetricExporter >> addAPeriodFrom: since to: until [ { #category : #adding } GitMetricExporter >> addEntitiesFromUserNames: userNames [ "import all the project since a certain time" + + self + deprecated: 'Use #setupAnalysesForUsersWithNames instead' + on: '03 Sept 2024' + in: + 'Pharo-11.0.0+build.726.sha.aece1b5473acf3830a0e082c1bc3a15d4ff3522b (64 Bit)'. 'Import all projects from the Git repository' recordInfo. projectCache := projectCache ifNil: [ @@ -47,16 +53,16 @@ GitMetricExporter >> addEntitiesFromUserNames: userNames [ "then collect the project in which the user has be seen commited" entities addAll: (userNames collect: [ :username | - | projects metrics i size | + | projects i size | projects := self findParticipationOfCommitAuthorNamed: username amongProjects: projectCache. - metrics := GitMetric4User new. + "metrics := GitMetric4User new. metrics glhImporter: glhImporter; - jiraImporter: jiraImporter; - findUserNamed: username. + jiraImporter: jiraImporter; + findUserNamed: username." @@ -82,21 +88,27 @@ GitMetricExporter >> addEntitiesFromUserNames: userNames [ { #category : #adding } GitMetricExporter >> addEntitiesFromUserNamesAndProjects: usersWithProjects [ + self + deprecated: 'Use #setupAnalysesForUsersWithNames instead' + on: '03 Sept 2024' + in: + 'Pharo-11.0.0+build.726.sha.aece1b5473acf3830a0e082c1bc3a15d4ff3522b (64 Bit)'. + entities addAll: (usersWithProjects associations collect: [ :assoc | - | username projects metrics | + | username projects | username := assoc key. projects := assoc value. - metrics := GitMetric4User new. + " metrics := GitMetric4User new. metrics glhImporter: glhImporter; jiraImporter: jiraImporter; findUserNamed: username. - metrics loadProjectsFromIds: projects. + metrics loadProjectsFromIds: projects." - metrics ]). + username ]). - ^ self + ^ self ] { #category : #accessing } From 65c43f4be90cba6aa45dc1a1543ec0df755f3f63 Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Wed, 4 Sep 2024 12:14:34 +0200 Subject: [PATCH 080/154] add project into catalogue --- .../GLHUserCatalogueV2.class.st | 86 ++++++++++++------- .../GLHModelImporter.class.st | 7 +- .../GLPHModelImporter.class.st | 8 +- 3 files changed, 64 insertions(+), 37 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st b/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st index 8739277..6bb93ef 100644 --- a/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st +++ b/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st @@ -126,35 +126,58 @@ GLHUserCatalogueV2 >> RSHeatMapLevenshteinTrimedAt: aBlockCondition [ { #category : #adding } GLHUserCatalogueV2 >> addUser: aGLHUser [ - self at: aGLHUser name ifAbsentPut: [ - self newEntryForUser: aGLHUser ] + ^ self at: aGLHUser name ifAbsentPut: [ + self initACatalogueEntryForUser: aGLHUser ] ] { #category : #adding } GLHUserCatalogueV2 >> addUser: aGLHUser withName: name [ - self - at: aGLHUser name - ifPresent: [ :entry | (entry at: #names) add: name ] - ifAbsentPut: [ - |entry| - entry := (self newEntryForUser: aGLHUser). - (entry at: #names) add: name. - entry - ] + ^ self addUser: aGLHUser withNames: { name } + ] { #category : #adding } GLHUserCatalogueV2 >> addUser: aGLHUser withNames: aCollectionOfNames [ - - self + | entry | + entry := (self at: aGLHUser name - ifPresent: [ :entry | (entry at: #names) addAll: aCollectionOfNames ] - ifAbsentPut: [ - |entry| - entry := (self newEntryForUser: aGLHUser ). - (entry at: #names ) addAll: aCollectionOfNames. - entry ] + ifAbsentPut: [ (self initACatalogueEntryForUser: aGLHUser ). ]). + (entry at: #names) addAll: aCollectionOfNames. + ^ entry +] + +{ #category : #adding } +GLHUserCatalogueV2 >> addUser: aGLHUser withNames: aCollectionOfNames withProject: aProjectID [ + + ^ self addUser: aGLHUser withNames: aCollectionOfNames withProjects: { aProjectID } +] + +{ #category : #adding } +GLHUserCatalogueV2 >> addUser: aGLHUser withNames: aCollectionOfNames withProjects: aCollectionOfProjectIDs [ + |entry| + + entry := self addUser: aGLHUser withNames: aCollectionOfNames. + (entry at: #contributedProjects) addAll: aCollectionOfProjectIDs. + ^ entry. + +] + +{ #category : #adding } +GLHUserCatalogueV2 >> addUser: aGLHUser withProject: aProjectID [ + + ^ self addUser: aGLHUser withProjects: {aProjectID}. + +] + +{ #category : #adding } +GLHUserCatalogueV2 >> addUser: aGLHUser withProjects: aCollectionOfProjectIDs [ + |entry| + + entry := self addUser: aGLHUser. + (entry at: #contributedProjects) addAll: aCollectionOfProjectIDs. + ^ entry. + ] { #category : #accessing } @@ -238,6 +261,19 @@ GLHUserCatalogueV2 >> fuse: mainUser with: subUser [ ]. ] +{ #category : #'instance creation' } +GLHUserCatalogueV2 >> initACatalogueEntryForUser: aGLHUser [. + +^ Dictionary new + at: #user put: aGLHUser; + at: #names put: (Set new + add: aGLHUser username; + add: aGLHUser name; + yourself); + at: #contributedProjects put: (Set new); + yourself +] + { #category : #initialization } GLHUserCatalogueV2 >> initialize [ @@ -271,18 +307,6 @@ GLHUserCatalogueV2 >> namesAt: aGLHUser [ ^ (self at: aGLHUser name) at: #names. ] -{ #category : #'instance creation' } -GLHUserCatalogueV2 >> newEntryForUser: aGLHUser [. - -^ Dictionary new - at: #user put: aGLHUser; - at: #names put: (Set new - add: aGLHUser username; - add: aGLHUser name; - yourself); - yourself -] - { #category : #'as yet unclassified' } GLHUserCatalogueV2 >> reImportAllUsers [ "use it after a catalogue import from JSON" diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index c18f270..645486a 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -496,7 +496,7 @@ GLHModelImporter >> importCommitsOfBranch: aGLHBranch forRefName: refName until: { #category : #'as yet unclassified' } GLHModelImporter >> importContributedProjectsOfUser: aGLHUser [ - | newlyFoundElmts page foundElmts | + | newlyFoundElmts page foundElmts knownProjects| page := 0. foundElmts := OrderedCollection new. newlyFoundElmts := { true }. @@ -519,10 +519,11 @@ GLHModelImporter >> importContributedProjectsOfUser: aGLHUser [ (self glhModel addAll: newlyFoundElmts unless: self blockOnIdEquality) ]. - + + knownProjects := self importProject: ((self userCatalogue at: aGLHUser name) at: #contributedProjects). aGLHUser contributedProjects - addAll: foundElmts + addAll: (foundElmts, knownProjects) unless: self blockOnIdEquality. ^ foundElmts diff --git a/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st b/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st index 971ba06..2f5f2d4 100644 --- a/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st +++ b/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st @@ -231,7 +231,7 @@ GLPHModelImporter >> importDiffRangesForDiff: aGLHDiff [ { #category : #'import - merge request' } GLPHModelImporter >> importMergeRequests: aGLHProject [ - | results parsedResults | + | results parsedResults mrs| ('Import merge request of Project: ' , aGLHProject id printString) recordInfo. @@ -242,7 +242,7 @@ GLPHModelImporter >> importMergeRequests: aGLHProject [ addAll: parsedResults unless: self blockOnIdEquality. - self glhModel + mrs := self glhModel addAll: aGLHProject mergeRequests unless: self blockOnIdEquality. @@ -254,7 +254,9 @@ GLPHModelImporter >> importMergeRequests: aGLHProject [ self withCommitDiffs ifTrue: [ aGLHProject mergeRequests do: [ :mr | - self importDiffOfMergeRequest: mr ] ] + self importDiffOfMergeRequest: mr ] ]. + + ^ mrs ] { #category : #'import - merge request' } From 5b5dd694230ab0f6d0f573e36f444dcf4c37d440 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Wed, 4 Sep 2024 14:44:54 +0200 Subject: [PATCH 081/154] feat: add project metrics structure (#48) * refactor: rename analyses for userAnalyses * feat: add projectAnalyses in generateAnalyses method * feat: add projectAnalyses in csv export * fix: issue cause by the merge with develop --- .../AnalysisReport.class.st | 46 ++++ .../GitMetricExporter.class.st | 249 ++++++++++++------ .../ProjectAnalysisReport.class.st | 20 ++ .../ProjectMetric.class.st | 8 + .../UserAnalysisReport.class.st | 42 +-- 5 files changed, 251 insertions(+), 114 deletions(-) create mode 100644 src/GitLabHealth-Model-Analysis/AnalysisReport.class.st create mode 100644 src/GitLabHealth-Model-Analysis/ProjectAnalysisReport.class.st create mode 100644 src/GitLabHealth-Model-Analysis/ProjectMetric.class.st diff --git a/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st b/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st new file mode 100644 index 0000000..210996f --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/AnalysisReport.class.st @@ -0,0 +1,46 @@ +Class { + #name : #AnalysisReport, + #superclass : #Object, + #instVars : [ + 'period', + 'over', + 'metrics' + ], + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #initialization } +AnalysisReport >> initialize [ + + metrics := Dictionary new +] + +{ #category : #accessing } +AnalysisReport >> metrics [ + + ^ metrics +] + +{ #category : #accessing } +AnalysisReport >> over [ + + ^ over +] + +{ #category : #accessing } +AnalysisReport >> over: anObject [ + + over := anObject +] + +{ #category : #accessing } +AnalysisReport >> period [ + + ^ period +] + +{ #category : #accessing } +AnalysisReport >> period: anObject [ + + period := anObject +] diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 7d31e12..5bdc721 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -11,9 +11,9 @@ Class { 'runningPeriods', 'maxCommitWindow', 'over', - 'analyses', 'emailDomain', - 'metrics' + 'metrics', + 'analyses' ], #category : #'GitLabHealth-Model-Analysis' } @@ -111,18 +111,6 @@ GitMetricExporter >> addEntitiesFromUserNamesAndProjects: usersWithProjects [ ^ self ] -{ #category : #accessing } -GitMetricExporter >> analyses [ - - ^ analyses -] - -{ #category : #accessing } -GitMetricExporter >> analyses: anObject [ - - analyses := anObject -] - { #category : #utilities } GitMetricExporter >> constructFilePath: runningOver [ @@ -137,10 +125,10 @@ GitMetricExporter >> constructFilePath: runningOver [ ] { #category : #exporting } -GitMetricExporter >> csvMetricsFor: date [ +GitMetricExporter >> csvMetricsFor: metricCollection at: date [ | csvMetrics | - csvMetrics := metrics collect: [ :metric | + csvMetrics := metricCollection collect: [ :metric | metric new description , ' - ' , date asString -> [ :groupAnalyses | | analysis | @@ -149,8 +137,7 @@ GitMetricExporter >> csvMetricsFor: date [ from: groupAnalyses. analysis ifNil: [ nil ] - ifNotNil: [ - analysis metrics at: metric new name ] ] ]. + ifNotNil: [ analysis metrics at: metric new name ] ] ]. ^ csvMetrics asOrderedDictionary ] @@ -178,17 +165,55 @@ GitMetricExporter >> exportFor: usersWithProjects over: aCollectionOfDateWeekMon { #category : #exporting } GitMetricExporter >> exportInCSV [ - | exportBrowserModel file groupedByOver groupByName periods group groupOver csvMetrics | + self exportUserAnalysesInCSV. + self exportProjectAnalysesInCSV. +] + +{ #category : #exporting } +GitMetricExporter >> exportInDB: repository [ + + repository enableSingleton. + analyses do: [ :analysis | analysis save ] +] + +{ #category : #exporting } +GitMetricExporter >> exportInS3: bucketName accessKey: accessKey secretKey: secretKey region: region [ + + | s3 bucket ston date fileName | + AWSS3Config default + accessKeyId: accessKey; + secretKey: secretKey; + regionName: region. + + s3 := AWSS3 new. + bucket := s3 bucketNamed: bucketName. + + ston := STON toString: analyses. + + date := Date today asString copyReplaceAll: ' ' asString with: '-'. + fileName := ('-' join: { + 'analyse'. + label. + over asString. + date }) , '.ston'. + + bucket atKey: fileName putObject: ston +] + +{ #category : #exporting } +GitMetricExporter >> exportProjectAnalysesInCSV [ + + | exportBrowserModel groupedByOver group groupOver groupByName periods csvMetrics file | exportBrowserModel := MiExportModel new. - groupedByOver := self analyses groupedBy: #over. + groupedByOver := self projectAnalyses groupedBy: #over. groupedByOver associations do: [ :groupAssociation | group := groupAssociation value. groupOver := groupAssociation key. - groupByName := group groupedBy: #username. + groupByName := group groupedBy: #projectName. exportBrowserModel entitiesList: groupByName. exportBrowserModel removeColumnForQueryNamed: #Type. @@ -196,13 +221,15 @@ GitMetricExporter >> exportInCSV [ exportBrowserModel addColumnForQuery: [ :groupAnalyses | - (groupAnalyses at: 1) username ] - withName: #'User name'. + (groupAnalyses at: 1) projectName ] + withName: #'Project name'. periods := (group groupedBy: #period) keys. periods do: [ :period | - csvMetrics := self csvMetricsFor: (period at: #since). + csvMetrics := self + csvMetricsFor: self projectMetrics + at: (period at: #since). csvMetrics associations do: [ :association | @@ -215,42 +242,53 @@ GitMetricExporter >> exportInCSV [ aStream << 'sep=,'; << OSPlatform current lineEnding. - exportBrowserModel writeCSVOn: aStream ] ]. - - 'Done computing' recordInfo + exportBrowserModel writeCSVOn: aStream ] ] ] { #category : #exporting } -GitMetricExporter >> exportInDB: repository [ +GitMetricExporter >> exportUserAnalysesInCSV [ - repository enableSingleton. + | exportBrowserModel groupedByOver group groupOver groupByName periods csvMetrics file | + exportBrowserModel := MiExportModel new. - self analyses ifNil: [ self generateAnalyses ]. - self analyses do: [ :analysis | analysis save ] -] + groupedByOver := self userAnalyses groupedBy: #over. + -{ #category : #exporting } -GitMetricExporter >> exportInS3: bucketName accessKey: accessKey secretKey: secretKey region: region [ + groupedByOver associations do: [ :groupAssociation | + group := groupAssociation value. + groupOver := groupAssociation key. - | s3 bucket ston date fileName | - AWSS3Config default - accessKeyId: accessKey; - secretKey: secretKey; - regionName: region. - s3 := AWSS3 new. - bucket := s3 bucketNamed: bucketName. + groupByName := group groupedBy: #username. + exportBrowserModel entitiesList: groupByName. - ston := STON toString: analyses. + exportBrowserModel removeColumnForQueryNamed: #Type. + exportBrowserModel removeColumnForQueryNamed: #Name. - date := Date today asString copyReplaceAll: ' ' asString with: '-'. - fileName := ('-' join: { - 'analyse'. - label. - over asString. - date }) , '.ston'. + exportBrowserModel + addColumnForQuery: [ :groupAnalyses | + (groupAnalyses at: 1) username ] + withName: #'User name'. - bucket atKey: fileName putObject: ston + periods := (group groupedBy: #period) keys. + + periods do: [ :period | + csvMetrics := self + csvMetricsFor: self userMetrics + at: (period at: #since). + + + csvMetrics associations do: [ :association | + exportBrowserModel + addColumnForQuery: association value + withName: association key ] ]. + + file := self constructFilePath: groupOver. + file writeStreamDo: [ :aStream | + aStream + << 'sep=,'; + << OSPlatform current lineEnding. + exportBrowserModel writeCSVOn: aStream ] ] ] { #category : #projects } @@ -291,35 +329,53 @@ GitMetricExporter >> findProjectsOfUser: aCollection [ { #category : #analysis } GitMetricExporter >> generateAnalysesOver: aDateWeekMonthOrYear [ - | userAnalysisReport result analysesReport newMetric | + | userAnalyses projectAnalyses | runningPeriods do: [ :period | - analysesReport := entities collect: [ :entity | - userAnalysisReport := UserAnalysisReport new - username: entity name; - period: period; - over: aDateWeekMonthOrYear. - - metrics do: [ :metric | - newMetric := metric new - setPeriodSince: - (period at: #since) - until: (period at: #until); - over: aDateWeekMonthOrYear; - user: entity; - glhImporter: glhImporter; - jiraImporter: jiraImporter; - emailDomain: emailDomain. - + userAnalyses := self + generateUsersAnalysesDuringPeriod: period + over: aDateWeekMonthOrYear. + projectAnalyses := self + generateProjectsAnalysesDuringPeriod: period + over: aDateWeekMonthOrYear ]. + + ^ analyses := userAnalyses, projectAnalyses. +] - result := newMetric calculate. - userAnalysisReport metrics - at: newMetric name - put: result ]. +{ #category : #analysis } +GitMetricExporter >> generateProjectsAnalysesDuringPeriod: period over: aDateWeekMonthOrYear [ - userAnalysisReport ]. - self analyses addAll: analysesReport ]. + ^self projectEntities collect: [ :project | + ProjectAnalysisReport new + projectName: project name; + period: period; + over: aDateWeekMonthOrYear ] +] - ^ analyses +{ #category : #analysis } +GitMetricExporter >> generateUsersAnalysesDuringPeriod: period over: aDateWeekMonthOrYear [ + + | userAnalysisReport newMetric result | + ^ self userEntities collect: [ :user | + userAnalysisReport := UserAnalysisReport new + username: user name; + period: period; + over: aDateWeekMonthOrYear. + + metrics do: [ :metric | + newMetric := metric new + glhImporter: glhImporter; + jiraImporter: jiraImporter; + setPeriodSince: (period at: #since) + until: (period at: #until); + over: aDateWeekMonthOrYear; + user: user; + emailDomain: emailDomain. + + + result := newMetric calculate. + userAnalysisReport metrics at: newMetric name put: result ]. + + userAnalysisReport ] ] { #category : #utilities } @@ -413,6 +469,33 @@ GitMetricExporter >> onlyImportProjectsOfGroup: groupId [ projectCache := group toScope: GLHProject ] +{ #category : #accessing } +GitMetricExporter >> projectAnalyses [ + + ^ analyses select: [ :analysis | analysis class = ProjectAnalysisReport ] +] + +{ #category : #accessing } +GitMetricExporter >> projectEntities [ + + ^ entities select: [ :entity | entity class = GLHProject ] +] + +{ #category : #accessing } +GitMetricExporter >> projectMetrics [ + + ^ metrics select: [ :metric | metric inheritsFrom: ProjectMetric ] +] + +{ #category : #setup } +GitMetricExporter >> setupAnalysisForProjectsWithIds: projectIds [ + + | projects | + projects := glhImporter importProjects: projectIds. + + entities addAll: projects +] + { #category : #setup } GitMetricExporter >> setupAnalysisForUsersWithNames: userNames [ "import all the project since a certain time" @@ -436,6 +519,24 @@ GitMetricExporter >> setupAnalysisForUsersWithNames: userNames [ ^ self ] +{ #category : #accessing } +GitMetricExporter >> userAnalyses [ + + ^ analyses select: [ :analysis | analysis class = UserAnalysisReport ] +] + +{ #category : #accessing } +GitMetricExporter >> userEntities [ + + ^ entities select: [ :entity | entity class = GLHUser ] +] + +{ #category : #accessing } +GitMetricExporter >> userMetrics [ + + ^ metrics select: [ :metric | metric inheritsFrom: UserMetric ] +] + { #category : #setup } GitMetricExporter >> withEmailDomain: anEmailDomain [ diff --git a/src/GitLabHealth-Model-Analysis/ProjectAnalysisReport.class.st b/src/GitLabHealth-Model-Analysis/ProjectAnalysisReport.class.st new file mode 100644 index 0000000..f9990bd --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/ProjectAnalysisReport.class.st @@ -0,0 +1,20 @@ +Class { + #name : #ProjectAnalysisReport, + #superclass : #AnalysisReport, + #instVars : [ + 'projectName' + ], + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #accessing } +ProjectAnalysisReport >> projectName [ + + ^ projectName +] + +{ #category : #accessing } +ProjectAnalysisReport >> projectName: anObject [ + + projectName := anObject +] diff --git a/src/GitLabHealth-Model-Analysis/ProjectMetric.class.st b/src/GitLabHealth-Model-Analysis/ProjectMetric.class.st new file mode 100644 index 0000000..fbb90de --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/ProjectMetric.class.st @@ -0,0 +1,8 @@ +Class { + #name : #ProjectMetric, + #superclass : #Metric, + #instVars : [ + 'project' + ], + #category : #'GitLabHealth-Model-Analysis' +} diff --git a/src/GitLabHealth-Model-Analysis/UserAnalysisReport.class.st b/src/GitLabHealth-Model-Analysis/UserAnalysisReport.class.st index 67e6a6a..8e5fe53 100644 --- a/src/GitLabHealth-Model-Analysis/UserAnalysisReport.class.st +++ b/src/GitLabHealth-Model-Analysis/UserAnalysisReport.class.st @@ -1,50 +1,12 @@ Class { #name : #UserAnalysisReport, - #superclass : #Object, + #superclass : #AnalysisReport, #instVars : [ - 'username', - 'period', - 'over', - 'metrics' + 'username' ], #category : #'GitLabHealth-Model-Analysis' } -{ #category : #initialization } -UserAnalysisReport >> initialize [ - metrics := Dictionary new. -] - -{ #category : #accessing } -UserAnalysisReport >> metrics [ - - ^ metrics -] - -{ #category : #accessing } -UserAnalysisReport >> over [ - - ^ over -] - -{ #category : #accessing } -UserAnalysisReport >> over: anObject [ - - over := anObject -] - -{ #category : #accessing } -UserAnalysisReport >> period [ - - ^ period -] - -{ #category : #accessing } -UserAnalysisReport >> period: anObject [ - - period := anObject -] - { #category : #accessing } UserAnalysisReport >> username [ From 7aeba7371c1de9d29e28e0d5c770862a305156ab Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Wed, 4 Sep 2024 15:12:48 +0200 Subject: [PATCH 082/154] fix catalogue to add project ids --- .../GLHUserCatalogueTest.class.st | 7 +-- .../GLHUserCatalogueV2Test.class.st | 15 ++++-- .../GLHUserCatalogueV2.class.st | 49 +++++++++++++++++-- .../GLHModelImporter.class.st | 13 +++-- 4 files changed, 65 insertions(+), 19 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueTest.class.st index ac24887..84ccd0c 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueTest.class.st @@ -231,13 +231,10 @@ GLHUserCatalogueTest >> testNamesAtChangingUser [ username: 'testUser'; yourself. - user hash. " 114462615" catalogue addUser: user withName: 'toto'. - user name: 'test User'. - user hash. self assert: (catalogue namesAt: user) size equals: 3. self @@ -247,6 +244,6 @@ GLHUserCatalogueTest >> testNamesAtChangingUser [ assert: ((catalogue namesAt: user) includes: 'testUser') equals: true. self - assert: ((catalogue namesAt: user) includes: 'test user') - equals: true + assert: ((catalogue namesAt: user) includes: 'test User') + equals: false ] diff --git a/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueV2Test.class.st b/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueV2Test.class.st index a8c7e05..0cb4535 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueV2Test.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueV2Test.class.st @@ -147,14 +147,17 @@ GLHUserCatalogueV2Test >> testExportAndLoad [ user := GLHUser new username: 'testUser'; name: 'test user'; + contributedProjects: { GLHProject new id: 11 }; yourself. - catalogue addUser: user. json := catalogue exportToJson. - res := GLHUserCatalogue loadFromJson: json. - self assert: res size equals: catalogue size + res := GLHUserCatalogueV2 loadFromJson: json. + self assert: res size equals: catalogue size. + self assert: ((res at: 'test user' at: #contributedProjects) includes: 11) equals: true. + self assert: ((res at: 'test user' at: #names) includes: 'test user') equals: true. + self assert: ((res at: 'test user' at: #names) includes: 'testUser') equals: true. ] { #category : #test } @@ -164,12 +167,14 @@ GLHUserCatalogueV2Test >> testExportToJson [ user := GLHUser new username: 'testUser'; name: 'test user'; + contributedProjects: { GLHProject new id: 11 } ; id: 1; yourself. user2 := GLHUser new username: 'testUser2'; name: 'test user2'; id: 2; + contributedProjects: { GLHProject new id: 21 . GLHProject new id: 22 } ; yourself. @@ -181,7 +186,9 @@ GLHUserCatalogueV2Test >> testExportToJson [ res := STONJSON fromString: json. self assert: res size equals: catalogue size. self assert: ((res at: 'test user2') at: #foundNames) size equals: 2. - self assert: ((res at: 'test user') at: #foundNames) size equals: 2 + self assert: ((res at: 'test user') at: #foundNames) size equals: 2. + self assert: ((res at: 'test user') at: #contributedProjects) size equals: 1. + self assert: ((res at: 'test user2') at: #contributedProjects) size equals: 2. ] { #category : #'as yet unclassified' } diff --git a/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st b/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st index 6bb93ef..39a8edf 100644 --- a/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st +++ b/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st @@ -11,11 +11,12 @@ GLHUserCatalogueV2 class >> loadFromJson: aString [ catalogue := self new. dic := (STONJSON fromString: aString) asDictionary. dic associationsDo: [ :assoc | - | itsName itsUsername itsCommitNames itsId | + | itsName itsUsername itsCommitNames itsId itsProjectIDs| itsName := assoc key. itsCommitNames := assoc value at: #foundNames. itsUsername := assoc value at: #username. itsId := assoc value at: #id. + itsProjectIDs := assoc value at: #contributedProjects ifAbsent: [{}]. catalogue addUser: (GLHUser new @@ -23,7 +24,8 @@ GLHUserCatalogueV2 class >> loadFromJson: aString [ username: itsUsername; name: itsName; yourself) - withNames: itsCommitNames ]. + withNames: itsCommitNames + withProjects: itsProjectIDs ]. ^ catalogue ] @@ -186,6 +188,12 @@ GLHUserCatalogueV2 >> anImporter: aGLHModelImporter [ ] +{ #category : #accessing } +GLHUserCatalogueV2 >> atId: anId [ + ^ self detect: [ :entry | + (entry at: #user) id = anId ] +] + { #category : #'as yet unclassified' } GLHUserCatalogueV2 >> collectUsernames [ @@ -237,15 +245,17 @@ GLHUserCatalogueV2 >> exportToJson [ (#id -> assoc key id) } asDictionary); yourself ]." tempDic := Dictionary new. self associationsDo: [ :assoc | - |entry user names| + |entry user names projectIDs| entry := assoc value. user := entry at: #user. names := entry at: #names. + projectIDs := entry at: #contributedProjects. tempDic at: assoc key put: { (#name -> user name). (#username -> user username). (#foundNames -> names asArray). + (#contributedProjects -> projectIDs asArray). (#id -> user id) } asDictionary; yourself ]. @@ -270,7 +280,9 @@ GLHUserCatalogueV2 >> initACatalogueEntryForUser: aGLHUser [. add: aGLHUser username; add: aGLHUser name; yourself); - at: #contributedProjects put: (Set new); + at: #contributedProjects put: (Set new + addAll: (aGLHUser contributedProjects collect: #id); + yourself ); yourself ] @@ -323,10 +335,37 @@ GLHUserCatalogueV2 >> reImportAllUsers [ assoc value at: #user put: user ] ] +{ #category : #'as yet unclassified' } +GLHUserCatalogueV2 >> reImportUser: aGLHUser [ + "use it after a catalogue import from JSON" + |user| + user := anImporter + ifNotNil: [ + aGLHUser id + ifNotNil: [ anImporter importUser: aGLHUser id ] + ifNil: [ anImporter importUserByUsername: aGLHUser username ] ] + ifNil: [aGLHUser]. + + + self at: aGLHUser name at: #user put: (user). + +] + +{ #category : #scrape } +GLHUserCatalogueV2 >> scrapeAuthorNameForAllRealUsers [ + + |listOfUsers| + listOfUsers := self users select: [ :user | user id isNotNil ]. + listOfUsers do: [ :user | self scrapeAuthorNameForUser: user ]. +] + { #category : #'as yet unclassified' } GLHUserCatalogueV2 >> scrapeAuthorNameForAllUsers [ - self users do: [ :user | self scrapeAuthorNameForUser: user ] + |listOfUsers| + + listOfUsers := self users. + listOfUsers do: [ :user | self scrapeAuthorNameForUser: user ] ] { #category : #'as yet unclassified' } diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index 645486a..0cfb639 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -496,7 +496,7 @@ GLHModelImporter >> importCommitsOfBranch: aGLHBranch forRefName: refName until: { #category : #'as yet unclassified' } GLHModelImporter >> importContributedProjectsOfUser: aGLHUser [ - | newlyFoundElmts page foundElmts knownProjects| + | newlyFoundElmts page foundElmts remaningProjects| page := 0. foundElmts := OrderedCollection new. newlyFoundElmts := { true }. @@ -519,12 +519,15 @@ GLHModelImporter >> importContributedProjectsOfUser: aGLHUser [ (self glhModel addAll: newlyFoundElmts unless: self blockOnIdEquality) ]. - - knownProjects := self importProject: ((self userCatalogue at: aGLHUser name) at: #contributedProjects). + + + remaningProjects := self importProjects: ((foundElmts collect: #id) difference: ((self userCatalogue atId: aGLHUser id) at: #contributedProjects)). aGLHUser contributedProjects - addAll: (foundElmts, knownProjects) + addAll: (foundElmts, remaningProjects) unless: self blockOnIdEquality. + + self userCatalogue addUser: aGLHUser withProjects: (aGLHUser contributedProjects collect: #id). ^ foundElmts ] @@ -1062,7 +1065,7 @@ GLHModelImporter >> parsePipelinesResult: result [ | reader | - result = '{"message":"403 Forbidden"}' ifTrue: [ ^ { } ]. + (result includesSubstring: '{"message":"40' )ifTrue: [ ^ { } ]. reader := NeoJSONReader on: result readStream. reader mapInstVarsFor: GLHPipeline. From c8eac7aeca8c21f967d95f2c0dc4f4711fdfc666 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Wed, 4 Sep 2024 17:30:10 +0200 Subject: [PATCH 083/154] test: add test for CodeAdditionMetric --- .../CodeAdditionMetricTest.class.st | 45 +++++++++++++++++++ .../GLPHImporterMock.class.st | 44 ++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 src/GitLabHealth-Model-Analysis-Tests/CodeAdditionMetricTest.class.st create mode 100644 src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st diff --git a/src/GitLabHealth-Model-Analysis-Tests/CodeAdditionMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/CodeAdditionMetricTest.class.st new file mode 100644 index 0000000..5560630 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis-Tests/CodeAdditionMetricTest.class.st @@ -0,0 +1,45 @@ +" +A CodeAdditionMetricTest is a test class for testing the behavior of CodeAdditionMetric +" +Class { + #name : #CodeAdditionMetricTest, + #superclass : #TestCase, + #category : #'GitLabHealth-Model-Analysis-Tests' +} + +{ #category : #tests } +CodeAdditionMetricTest >> testCalculate [ + "Given" + + | user glhImporter codeAddition result | + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter commits: { + (GLHCommit new + id: 1; + created_at: '04-09-2024'; + commitCreator: user; + additions: 5). + (GLHCommit new + id: 2; + created_at: '04-09-2024'; + commitCreator: user; + additions: 5) }. + + + codeAddition := CodeAdditionMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '04-09-2024' until: '04-09-2024'; + over: Week. + + "Given" + result := codeAddition calculate. + + "Then" + self assert: result equals: 10 +] diff --git a/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st b/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st new file mode 100644 index 0000000..cabc359 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st @@ -0,0 +1,44 @@ +Class { + #name : #GLPHImporterMock, + #superclass : #Object, + #instVars : [ + 'commits', + 'commitDiffs' + ], + #category : #'GitLabHealth-Model-Analysis-Tests' +} + +{ #category : #commit } +GLPHImporterMock >> chainsCommitsFrom: fromCommits [ + ^self + +] + +{ #category : #accessing } +GLPHImporterMock >> commits [ + + ^ commits +] + +{ #category : #accessing } +GLPHImporterMock >> commits: anObject [ + + commits := anObject +] + +{ #category : #commit } +GLPHImporterMock >> importCommitsOProject: project since: since until: until [ + + ^commits +] + +{ #category : #'as yet unclassified' } +GLPHImporterMock >> importCreatorOfCommit: commit [ + + ^self +] + +{ #category : #accessing } +GLPHImporterMock >> withCommitDiffs: aCommitDiffs [ + commitDiffs := aCommitDiffs +] From efc7c3742a15f585c70ac2f38984632cbcbedf56 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Wed, 4 Sep 2024 17:33:41 +0200 Subject: [PATCH 084/154] test: CodeDeletionMetric --- .../CodeDeletionMetricTest.class.st | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/GitLabHealth-Model-Analysis-Tests/CodeDeletionMetricTest.class.st diff --git a/src/GitLabHealth-Model-Analysis-Tests/CodeDeletionMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/CodeDeletionMetricTest.class.st new file mode 100644 index 0000000..9f2fbbc --- /dev/null +++ b/src/GitLabHealth-Model-Analysis-Tests/CodeDeletionMetricTest.class.st @@ -0,0 +1,44 @@ +" +A CodeDeletionMetricTest is a test class for testing the behavior of CodeDeletionMetric +" +Class { + #name : #CodeDeletionMetricTest, + #superclass : #TestCase, + #category : #'GitLabHealth-Model-Analysis-Tests' +} + +{ #category : #tests } +CodeDeletionMetricTest >> testCalculate [ + + | user glhImporter result codeDeletion | + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter commits: { + (GLHCommit new + id: 1; + created_at: '04-09-2024'; + commitCreator: user; + deletions: 5). + (GLHCommit new + id: 2; + created_at: '04-09-2024'; + commitCreator: user; + deletions: 5) }. + + + codeDeletion := CodeDeletionMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '04-09-2024' until: '04-09-2024'; + over: Week. + + "Given" + result := codeDeletion calculate. + + "Then" + self assert: result equals: 10 +] From 2bb7d679b7a3a23b83e6a76954548079b2f5b927 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Thu, 5 Sep 2024 09:11:36 +0200 Subject: [PATCH 085/154] test: calculate CommitFrequencyMetric --- .../CommitFrequencyMetricTest.class.st | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/GitLabHealth-Model-Analysis-Tests/CommitFrequencyMetricTest.class.st diff --git a/src/GitLabHealth-Model-Analysis-Tests/CommitFrequencyMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/CommitFrequencyMetricTest.class.st new file mode 100644 index 0000000..1376fe4 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis-Tests/CommitFrequencyMetricTest.class.st @@ -0,0 +1,44 @@ +" +A CommitFrequencyMetricTest is a test class for testing the behavior of CommitFrequencyMetric +" +Class { + #name : #CommitFrequencyMetricTest, + #superclass : #TestCase, + #category : #'GitLabHealth-Model-Analysis-Tests' +} + +{ #category : #tests } +CommitFrequencyMetricTest >> testCalculate [ + + | user glhImporter result commitFrequency | + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter commits: { + (GLHCommit new + id: 1; + created_at: '04-09-2024'; + commitCreator: user; + additions: 5). + (GLHCommit new + id: 2; + created_at: '04-09-2024'; + commitCreator: user; + additions: 5) }. + + + commitFrequency := CommitFrequencyMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '04-09-2024' until: '04-09-2024'; + over: Week. + + "Given" + result := commitFrequency calculate. + + "Then" + self assert: result equals: 2 +] From a2d6952fa9d4a18eafff98a8d6ec274ed2c75161 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Thu, 5 Sep 2024 09:12:08 +0200 Subject: [PATCH 086/154] test: calculate ContributedProjectMetric --- .../ContributedProjectMetricTest.class.st | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 src/GitLabHealth-Model-Analysis-Tests/ContributedProjectMetricTest.class.st diff --git a/src/GitLabHealth-Model-Analysis-Tests/ContributedProjectMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/ContributedProjectMetricTest.class.st new file mode 100644 index 0000000..4f3c9d3 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis-Tests/ContributedProjectMetricTest.class.st @@ -0,0 +1,48 @@ +" +A ContributedProjectMetricTest is a test class for testing the behavior of ContributedProjectMetric +" +Class { + #name : #ContributedProjectMetricTest, + #superclass : #TestCase, + #category : #'GitLabHealth-Model-Analysis-Tests' +} + +{ #category : #tests } +ContributedProjectMetricTest >> testCalculate [ + + | user glhImporter result contributedProject project1 repository1 | + project1 := GLHProject new repository: GLHRepository new. + repository1 := GLHRepository new project: project1. + user := GLHUser new + username: 'test'; + contributedProjects: { project1 }. + + glhImporter := GLPHImporterMock new. + glhImporter commits: { + (GLHCommit new + id: 1; + created_at: '04-09-2024'; + committed_date: '04-09-2024'; + commitCreator: user; + repository: repository1). + (GLHCommit new + id: 2; + created_at: '04-09-2024'; + committed_date: '04-09-2024'; + commitCreator: user; + repository: repository1) }. + + + contributedProject := ContributedProjectMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '04-09-2024' + until: '04-09-2024'; + over: Week. + + "Given" + result := contributedProject calculate. + + "Then" + self assert: result equals: 1 +] From 012b41378e4eceb8b852ac3c63268d2d9c02bb26 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Thu, 5 Sep 2024 10:39:28 +0200 Subject: [PATCH 087/154] tests: add tests when no commits + CommentContributionMetric caculate test --- .../CodeAdditionMetricTest.class.st | 26 +++++++ .../CodeDeletionMetricTest.class.st | 25 +++++++ .../CommentContributionMetricTest.class.st | 68 +++++++++++++++++ .../CommitFrequencyMetricTest.class.st | 38 +++++++--- .../ContributedProjectMetricTest.class.st | 27 +++++++ .../GLPHImporterMock.class.st | 10 +++ .../TimeBetweenCommitMetricTest.class.st | 73 +++++++++++++++++++ .../GitAnalyzer.class.st | 3 +- .../Metric.class.st | 2 +- 9 files changed, 258 insertions(+), 14 deletions(-) create mode 100644 src/GitLabHealth-Model-Analysis-Tests/CommentContributionMetricTest.class.st create mode 100644 src/GitLabHealth-Model-Analysis-Tests/TimeBetweenCommitMetricTest.class.st diff --git a/src/GitLabHealth-Model-Analysis-Tests/CodeAdditionMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/CodeAdditionMetricTest.class.st index 5560630..4ca7cb7 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/CodeAdditionMetricTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/CodeAdditionMetricTest.class.st @@ -43,3 +43,29 @@ CodeAdditionMetricTest >> testCalculate [ "Then" self assert: result equals: 10 ] + +{ #category : #tests } +CodeAdditionMetricTest >> testCalculateNoCommits [ + "Given" + + | user glhImporter codeAddition result | + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + + + codeAddition := CodeAdditionMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '04-09-2024' until: '04-09-2024'; + over: Week. + + "Given" + result := codeAddition calculate. + + "Then" + self assert: result equals: 0 +] diff --git a/src/GitLabHealth-Model-Analysis-Tests/CodeDeletionMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/CodeDeletionMetricTest.class.st index 9f2fbbc..c25cefa 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/CodeDeletionMetricTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/CodeDeletionMetricTest.class.st @@ -42,3 +42,28 @@ CodeDeletionMetricTest >> testCalculate [ "Then" self assert: result equals: 10 ] + +{ #category : #tests } +CodeDeletionMetricTest >> testCalculateNoCommits [ + + | user glhImporter result codeDeletion | + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + + + codeDeletion := CodeDeletionMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '04-09-2024' until: '04-09-2024'; + over: Week. + + "Given" + result := codeDeletion calculate. + + "Then" + self assert: result equals: 0 +] diff --git a/src/GitLabHealth-Model-Analysis-Tests/CommentContributionMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/CommentContributionMetricTest.class.st new file mode 100644 index 0000000..ba88554 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis-Tests/CommentContributionMetricTest.class.st @@ -0,0 +1,68 @@ +" +A CommentContributionMetricTest is a test class for testing the behavior of CommentContributionMetric +" +Class { + #name : #CommentContributionMetricTest, + #superclass : #TestCase, + #category : #'GitLabHealth-Model-Analysis-Tests' +} + +{ #category : #tests } +CommentContributionMetricTest >> testCalculate [ + + | user glhImporter result commitDiff commentContribution | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + commitDiff := GLHDiff new diffRanges: { (GLPHEDiffRange new changes: + { (GLPHEAddition new sourceCode: '// test') }) }. + + glhImporter := GLPHImporterMock new. + glhImporter commits: { (GLHCommit new + id: 1; + created_at: '04-09-2024'; + commitCreator: user; + diffs: { commitDiff }) }. + + + commentContribution := CommentContributionMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '04-09-2024' + until: '04-09-2024'; + over: Week. + "When" + result := commentContribution calculate. + + "Then" + self assert: result equals: 1 +] + +{ #category : #tests } +CommentContributionMetricTest >> testCalculateNoCommits [ + + | user glhImporter result commentContribution | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + + + commentContribution := CommentContributionMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '04-09-2024' + until: '04-09-2024'; + over: Week. + "When" + result := commentContribution calculate. + + "Then" + self assert: result equals: 0 +] diff --git a/src/GitLabHealth-Model-Analysis-Tests/CommitFrequencyMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/CommitFrequencyMetricTest.class.st index 1376fe4..a988f49 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/CommitFrequencyMetricTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/CommitFrequencyMetricTest.class.st @@ -17,17 +17,6 @@ CommitFrequencyMetricTest >> testCalculate [ { (GLHProject new repository: GLHRepository new) }. glhImporter := GLPHImporterMock new. - glhImporter commits: { - (GLHCommit new - id: 1; - created_at: '04-09-2024'; - commitCreator: user; - additions: 5). - (GLHCommit new - id: 2; - created_at: '04-09-2024'; - commitCreator: user; - additions: 5) }. commitFrequency := CommitFrequencyMetric new @@ -40,5 +29,30 @@ CommitFrequencyMetricTest >> testCalculate [ result := commitFrequency calculate. "Then" - self assert: result equals: 2 + self assert: result equals: 0 +] + +{ #category : #tests } +CommitFrequencyMetricTest >> testCalculateNoCommits [ + + | user glhImporter result commitFrequency | + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + + + commitFrequency := CommitFrequencyMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '04-09-2024' until: '04-09-2024'; + over: Week. + + "Given" + result := commitFrequency calculate. + + "Then" + self assert: result equals: 0 ] diff --git a/src/GitLabHealth-Model-Analysis-Tests/ContributedProjectMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/ContributedProjectMetricTest.class.st index 4f3c9d3..b77ddb8 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/ContributedProjectMetricTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/ContributedProjectMetricTest.class.st @@ -46,3 +46,30 @@ ContributedProjectMetricTest >> testCalculate [ "Then" self assert: result equals: 1 ] + +{ #category : #tests } +ContributedProjectMetricTest >> testCalculateNoCommits [ + + | user glhImporter result contributedProject project1 repository1 | + project1 := GLHProject new repository: GLHRepository new. + repository1 := GLHRepository new project: project1. + user := GLHUser new + username: 'test'; + contributedProjects: { project1 }. + + glhImporter := GLPHImporterMock new. + + + contributedProject := ContributedProjectMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '04-09-2024' + until: '04-09-2024'; + over: Week. + + "Given" + result := contributedProject calculate. + + "Then" + self assert: result equals: 0 +] diff --git a/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st b/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st index cabc359..027efee 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st @@ -26,6 +26,11 @@ GLPHImporterMock >> commits: anObject [ commits := anObject ] +{ #category : #'as yet unclassified' } +GLPHImporterMock >> completeImportedCommit: commit [ + ^self +] + { #category : #commit } GLPHImporterMock >> importCommitsOProject: project since: since until: until [ @@ -38,6 +43,11 @@ GLPHImporterMock >> importCreatorOfCommit: commit [ ^self ] +{ #category : #initialization } +GLPHImporterMock >> initialize [ + commits := OrderedCollection new +] + { #category : #accessing } GLPHImporterMock >> withCommitDiffs: aCommitDiffs [ commitDiffs := aCommitDiffs diff --git a/src/GitLabHealth-Model-Analysis-Tests/TimeBetweenCommitMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/TimeBetweenCommitMetricTest.class.st new file mode 100644 index 0000000..d2a2a47 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis-Tests/TimeBetweenCommitMetricTest.class.st @@ -0,0 +1,73 @@ +" +A TimeBetweenCommitMetricTest is a test class for testing the behavior of TimeBetweenCommitMetric +" +Class { + #name : #TimeBetweenCommitMetricTest, + #superclass : #TestCase, + #category : #'GitLabHealth-Model-Analysis-Tests' +} + +{ #category : #tests } +TimeBetweenCommitMetricTest >> testCalculate [ + + | user glhImporter result timeBetweenCommit | + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter commits: { + (GLHCommit new + id: 1; + created_at: '09-04-2024:01:00:00'; + committed_date: '09-04-2024:01:00:00' asDateAndTime; + commitCreator: user; + additions: 5). + (GLHCommit new + id: 2; + created_at: '09-04-2024'; + committed_date: '09-05-2024' asDate; + commitCreator: user; + additions: 5) }. + + + timeBetweenCommit := TimeBetweenCommitMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-04-2024' + until: '09-04-2024'; + over: Week. + + "Given" + result := timeBetweenCommit calculate. + + "Then" + self assert: result equals: 23 hours +] + +{ #category : #tests } +TimeBetweenCommitMetricTest >> testCalculateNoCommits [ + + | user glhImporter result timeBetweenCommit | + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + + + timeBetweenCommit := TimeBetweenCommitMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-04-2024' + until: '09-04-2024'; + over: Week. + + "Given" + result := timeBetweenCommit calculate. + + "Then" + self assert: result equals: nil +] diff --git a/src/GitLabHealth-Model-Analysis/GitAnalyzer.class.st b/src/GitLabHealth-Model-Analysis/GitAnalyzer.class.st index d27d592..fc0ded4 100644 --- a/src/GitLabHealth-Model-Analysis/GitAnalyzer.class.st +++ b/src/GitLabHealth-Model-Analysis/GitAnalyzer.class.st @@ -8,7 +8,7 @@ Class { 'onProject', 'maxChildCommits' ], - #category : 'GitLabHealth-Model-Analysis' + #category : #'GitLabHealth-Model-Analysis' } { #category : #analyze } @@ -46,6 +46,7 @@ GitAnalyzer >> analyseCommentContribution [ ('GitAnalyzer, analyse comment contributions onProject: ' , onProject printString) recordInfo. numberOfComments := 0. + fromCommit diffs do: [ :diff | diff diffRanges do: [ :range | range changes do: [ :change | diff --git a/src/GitLabHealth-Model-Analysis/Metric.class.st b/src/GitLabHealth-Model-Analysis/Metric.class.st index 912cf06..3871199 100644 --- a/src/GitLabHealth-Model-Analysis/Metric.class.st +++ b/src/GitLabHealth-Model-Analysis/Metric.class.st @@ -68,7 +68,7 @@ Metric >> setupGroupedDate [ increment := 1. start := self transformDate: (period at: #since) to: over. end := self transformDate: (period at: #until) to: over. - + groupedByDate at: start printString ifAbsentPut: [ OrderedCollection new ]. From 045d21b11182d60ffb4d5ead5db92d4eacd2a233 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Thu, 5 Sep 2024 11:06:05 +0200 Subject: [PATCH 088/154] tests: MergedMergeRequestMetric calculate + OpenedMergeRequestMetric calculate --- .../GLPHImporterMock.class.st | 32 ++++++++- .../MergedMergeRequestMetricTest.class.st | 70 +++++++++++++++++++ .../OpenedMergeRequestMetricTest.class.st | 65 +++++++++++++++++ .../OpenedMergeRequestMetric.class.st | 1 + .../UserMetric.class.st | 3 +- 5 files changed, 166 insertions(+), 5 deletions(-) create mode 100644 src/GitLabHealth-Model-Analysis-Tests/MergedMergeRequestMetricTest.class.st create mode 100644 src/GitLabHealth-Model-Analysis-Tests/OpenedMergeRequestMetricTest.class.st diff --git a/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st b/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st index 027efee..6484f3b 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st @@ -3,7 +3,8 @@ Class { #superclass : #Object, #instVars : [ 'commits', - 'commitDiffs' + 'commitDiffs', + 'mergeRequests' ], #category : #'GitLabHealth-Model-Analysis-Tests' } @@ -43,9 +44,34 @@ GLPHImporterMock >> importCreatorOfCommit: commit [ ^self ] +{ #category : #'import - merge request' } +GLPHImporterMock >> importMergeRequests: project since: since until: until [ + ^mergeRequests + +] + +{ #category : #'import - merge request' } +GLPHImporterMock >> importMergeResquestAuthor: mr [ + ^self +] + { #category : #initialization } -GLPHImporterMock >> initialize [ - commits := OrderedCollection new +GLPHImporterMock >> initialize [ + + commits := OrderedCollection new. + mergeRequests := OrderedCollection new. +] + +{ #category : #accessing } +GLPHImporterMock >> mergeRequests [ + + ^ mergeRequests +] + +{ #category : #accessing } +GLPHImporterMock >> mergeRequests: anObject [ + + mergeRequests := anObject ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis-Tests/MergedMergeRequestMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/MergedMergeRequestMetricTest.class.st new file mode 100644 index 0000000..7a549a8 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis-Tests/MergedMergeRequestMetricTest.class.st @@ -0,0 +1,70 @@ +" +A MergedMergeRequestMetricTest is a test class for testing the behavior of MergedMergeRequestMetric +" +Class { + #name : #MergedMergeRequestMetricTest, + #superclass : #TestCase, + #category : #'GitLabHealth-Model-Analysis-Tests' +} + +{ #category : #tests } +MergedMergeRequestMetricTest >> testCalculate [ + + | result glhImporter user mergedMergeRequest | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: '09-05-2024') + .(GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: nil)}. + + + mergedMergeRequest := MergedMergeRequestMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-04-2024' + until: '09-04-2024'; + over: Week. + + "When" + result := mergedMergeRequest calculate. + + "Then" + self assert: result equals: 1 +] + +{ #category : #tests } +MergedMergeRequestMetricTest >> testCalculateNoMergeRequests [ + + | result glhImporter user mergedMergeRequest | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + + + mergedMergeRequest := MergedMergeRequestMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-04-2024' + until: '09-04-2024'; + over: Week. + + "When" + result := mergedMergeRequest calculate. + + "Then" + self assert: result equals: 0 +] diff --git a/src/GitLabHealth-Model-Analysis-Tests/OpenedMergeRequestMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/OpenedMergeRequestMetricTest.class.st new file mode 100644 index 0000000..5ced5ed --- /dev/null +++ b/src/GitLabHealth-Model-Analysis-Tests/OpenedMergeRequestMetricTest.class.st @@ -0,0 +1,65 @@ +" +An OpenedMergeRequestMetricTest is a test class for testing the behavior of OpenedMergeRequestMetric +" +Class { + #name : #OpenedMergeRequestMetricTest, + #superclass : #TestCase, + #category : #'GitLabHealth-Model-Analysis-Tests' +} + +{ #category : #tests } +OpenedMergeRequestMetricTest >> testCalculate [ + + | openedMergeRequest result glhImporter user | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024') }. + + + openedMergeRequest := OpenedMergeRequestMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-04-2024' + until: '09-04-2024'; + over: Week. + + "When" + result := openedMergeRequest calculate. + + "Then" + self assert: result equals: 1 +] + +{ #category : #tests } +OpenedMergeRequestMetricTest >> testCalculateNoMergeRequests [ + + | openedMergeRequest result glhImporter user | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + + + openedMergeRequest := OpenedMergeRequestMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-04-2024' + until: '09-04-2024'; + over: Week. + + "When" + result := openedMergeRequest calculate. + + "Then" + self assert: result equals: 0 +] diff --git a/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st index 158f18e..2e1c4b2 100644 --- a/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st @@ -9,6 +9,7 @@ OpenedMergeRequestMetric >> calculate [ | groupedByDate dateOver | userMergeRequests ifNil: [ self load ]. + groupedByDate := self setupGroupedDate. userMergeRequests do: [ :userMergeRequest | diff --git a/src/GitLabHealth-Model-Analysis/UserMetric.class.st b/src/GitLabHealth-Model-Analysis/UserMetric.class.st index 4cbabfc..d7f517b 100644 --- a/src/GitLabHealth-Model-Analysis/UserMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserMetric.class.st @@ -145,8 +145,7 @@ UserMetric >> loadMergeRequestsSince: since until: until [ mergeRequests do: [ :mr | glhImporter importMergeResquestAuthor: mr ]. - ^mergeRequests select: [ :mergeRequest | - mergeRequest author = user ]. + ^ mergeRequests select: [ :mergeRequest | mergeRequest author = user ] ] { #category : #loading } From 1122aff1564b89a8a150539cda227556c945a50f Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Thu, 5 Sep 2024 11:16:01 +0200 Subject: [PATCH 089/154] test: ClosedMergeRequestMetric calculate --- .../ClosedMergeRequestMetricTest.class.st | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 src/GitLabHealth-Model-Analysis-Tests/ClosedMergeRequestMetricTest.class.st diff --git a/src/GitLabHealth-Model-Analysis-Tests/ClosedMergeRequestMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/ClosedMergeRequestMetricTest.class.st new file mode 100644 index 0000000..e4219c2 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis-Tests/ClosedMergeRequestMetricTest.class.st @@ -0,0 +1,72 @@ +" +A ClosedMergeRequestMetricTest is a test class for testing the behavior of ClosedMergeRequestMetric +" +Class { + #name : #ClosedMergeRequestMetricTest, + #superclass : #TestCase, + #category : #'GitLabHealth-Model-Analysis-Tests' +} + +{ #category : #tests } +ClosedMergeRequestMetricTest >> testCalculate [ + + | result glhImporter user closedMergeRequestMetric | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { + (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: '09-05-2024'; + state: 'closed'). + (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: nil; + state: 'closed') }. + + + closedMergeRequestMetric := ClosedMergeRequestMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-04-2024' + until: '09-04-2024'; + over: Week. + + "When" + result := closedMergeRequestMetric calculate. + + "Then" + self assert: result equals: 1 +] + +{ #category : #tests } +ClosedMergeRequestMetricTest >> testCalculateNoMergeRequests [ + + | result glhImporter user closedMergeRequestMetric | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + + closedMergeRequestMetric := ClosedMergeRequestMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-04-2024' + until: '09-04-2024'; + over: Week. + + "When" + result := closedMergeRequestMetric calculate. + + "Then" + self assert: result equals: 0 +] From 98db746efa51962ad87725bbb32d9f7709aa22b7 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Thu, 5 Sep 2024 11:26:45 +0200 Subject: [PATCH 090/154] tests: MergeRequestDurationMetric calculate --- .../MergeRequestDurationMetricTest.class.st | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 src/GitLabHealth-Model-Analysis-Tests/MergeRequestDurationMetricTest.class.st diff --git a/src/GitLabHealth-Model-Analysis-Tests/MergeRequestDurationMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/MergeRequestDurationMetricTest.class.st new file mode 100644 index 0000000..1c3531f --- /dev/null +++ b/src/GitLabHealth-Model-Analysis-Tests/MergeRequestDurationMetricTest.class.st @@ -0,0 +1,70 @@ +" +A MergeRequestDurationMetricTest is a test class for testing the behavior of MergeRequestDurationMetric +" +Class { + #name : #MergeRequestDurationMetricTest, + #superclass : #TestCase, + #category : #'GitLabHealth-Model-Analysis-Tests' +} + +{ #category : #tests } +MergeRequestDurationMetricTest >> testCalculate [ + + | result glhImporter user mergeRequestDuration | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { + (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024:00:00:00' asDateAndTime; + merged_at: '09-05-2024:10:00:00' asDateAndTime). + (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024' asDate; + merged_at: nil) }. + + + mergeRequestDuration := MergeRequestDurationMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-04-2024' + until: '09-04-2024'; + over: Week. + + "When" + result := mergeRequestDuration calculate. + + "Then" + self assert: result equals: 10 hours +] + +{ #category : #tests } +MergeRequestDurationMetricTest >> testCalculateNoMergeRequests [ + + | result glhImporter user mergeRequestDuration | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + + mergeRequestDuration := MergeRequestDurationMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-04-2024' + until: '09-04-2024'; + over: Week. + + "When" + result := mergeRequestDuration calculate. + + "Then" + self assert: result equals: nil +] From 5c36a5bd09362b063d28025b3905c5be138d91ab Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Thu, 5 Sep 2024 11:45:34 +0200 Subject: [PATCH 091/154] test: MergedMergeRequestWithoutReviewMetric calculate test --- .../GLPHImporterMock.class.st | 5 ++ ...rgeRequestWithoutReviewMetricTest.class.st | 74 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 src/GitLabHealth-Model-Analysis-Tests/MergedMergeRequestWithoutReviewMetricTest.class.st diff --git a/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st b/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st index 6484f3b..3e30da6 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st @@ -55,6 +55,11 @@ GLPHImporterMock >> importMergeResquestAuthor: mr [ ^self ] +{ #category : #'import - merge request' } +GLPHImporterMock >> importMergeResquestMerger: mergeRequest [ + ^self +] + { #category : #initialization } GLPHImporterMock >> initialize [ diff --git a/src/GitLabHealth-Model-Analysis-Tests/MergedMergeRequestWithoutReviewMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/MergedMergeRequestWithoutReviewMetricTest.class.st new file mode 100644 index 0000000..92301d4 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis-Tests/MergedMergeRequestWithoutReviewMetricTest.class.st @@ -0,0 +1,74 @@ +" +A MergedMergeRequestWithoutReviewMetricTest is a test class for testing the behavior of MergedMergeRequestWithoutReviewMetric +" +Class { + #name : #MergedMergeRequestWithoutReviewMetricTest, + #superclass : #TestCase, + #category : #'GitLabHealth-Model-Analysis-Tests' +} + +{ #category : #tests } +MergedMergeRequestWithoutReviewMetricTest >> testCalculate [ + + | result glhImporter user mergedMergeRequestWithoutReview | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { + (GLPHEMergeRequest new + author: user; + merge_user: user; + created_at: '09-05-2024:00-00-00' asDateAndTime; + merged_at: '09-05-2024:00-00-01' asDateAndTime). + (GLPHEMergeRequest new + author: user; + merge_user: nil; + created_at: '09-05-2024:00-00-00' asDateAndTime; + merged_at: '09-05-2024:00-00-01' asDateAndTime) }. + + + mergedMergeRequestWithoutReview := MergedMergeRequestWithoutReviewMetric + new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-04-2024' + until: '09-04-2024'; + over: Week. + + "When" + result := mergedMergeRequestWithoutReview calculate. + + "Then" + self assert: result equals: 1 +] + +{ #category : #tests } +MergedMergeRequestWithoutReviewMetricTest >> testCalculateNoMergeRequests [ + + | result glhImporter user mergedMergeRequestWithoutReview | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + + mergedMergeRequestWithoutReview := MergedMergeRequestWithoutReviewMetric + new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-04-2024' + until: '09-04-2024'; + over: Week. + + "When" + result := mergedMergeRequestWithoutReview calculate. + + "Then" + self assert: result equals: 0 +] From 3dddb4e00d14877efe118a5852eb5ad032a7eb25 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Thu, 5 Sep 2024 11:48:54 +0200 Subject: [PATCH 092/154] refactor: improve tests comments --- .../CodeAdditionMetricTest.class.st | 8 ++++---- .../CodeDeletionMetricTest.class.st | 6 ++++-- .../CommitFrequencyMetricTest.class.st | 6 ++++-- .../ContributedProjectMetricTest.class.st | 6 ++++-- .../TimeBetweenCommitMetricTest.class.st | 6 ++++-- 5 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis-Tests/CodeAdditionMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/CodeAdditionMetricTest.class.st index 4ca7cb7..bcc81e7 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/CodeAdditionMetricTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/CodeAdditionMetricTest.class.st @@ -9,9 +9,9 @@ Class { { #category : #tests } CodeAdditionMetricTest >> testCalculate [ - "Given" | user glhImporter codeAddition result | + "Given" user := GLHUser new username: 'test'; contributedProjects: @@ -37,7 +37,7 @@ CodeAdditionMetricTest >> testCalculate [ setPeriodSince: '04-09-2024' until: '04-09-2024'; over: Week. - "Given" + "When" result := codeAddition calculate. "Then" @@ -46,9 +46,9 @@ CodeAdditionMetricTest >> testCalculate [ { #category : #tests } CodeAdditionMetricTest >> testCalculateNoCommits [ - "Given" | user glhImporter codeAddition result | + "Given" user := GLHUser new username: 'test'; contributedProjects: @@ -63,7 +63,7 @@ CodeAdditionMetricTest >> testCalculateNoCommits [ setPeriodSince: '04-09-2024' until: '04-09-2024'; over: Week. - "Given" + "When" result := codeAddition calculate. "Then" diff --git a/src/GitLabHealth-Model-Analysis-Tests/CodeDeletionMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/CodeDeletionMetricTest.class.st index c25cefa..5ce44b8 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/CodeDeletionMetricTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/CodeDeletionMetricTest.class.st @@ -11,6 +11,7 @@ Class { CodeDeletionMetricTest >> testCalculate [ | user glhImporter result codeDeletion | + "Given" user := GLHUser new username: 'test'; contributedProjects: @@ -36,7 +37,7 @@ CodeDeletionMetricTest >> testCalculate [ setPeriodSince: '04-09-2024' until: '04-09-2024'; over: Week. - "Given" + "When" result := codeDeletion calculate. "Then" @@ -47,6 +48,7 @@ CodeDeletionMetricTest >> testCalculate [ CodeDeletionMetricTest >> testCalculateNoCommits [ | user glhImporter result codeDeletion | + "Given" user := GLHUser new username: 'test'; contributedProjects: @@ -61,7 +63,7 @@ CodeDeletionMetricTest >> testCalculateNoCommits [ setPeriodSince: '04-09-2024' until: '04-09-2024'; over: Week. - "Given" + "When" result := codeDeletion calculate. "Then" diff --git a/src/GitLabHealth-Model-Analysis-Tests/CommitFrequencyMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/CommitFrequencyMetricTest.class.st index a988f49..7fa1f1c 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/CommitFrequencyMetricTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/CommitFrequencyMetricTest.class.st @@ -11,6 +11,7 @@ Class { CommitFrequencyMetricTest >> testCalculate [ | user glhImporter result commitFrequency | + "Given" user := GLHUser new username: 'test'; contributedProjects: @@ -25,7 +26,7 @@ CommitFrequencyMetricTest >> testCalculate [ setPeriodSince: '04-09-2024' until: '04-09-2024'; over: Week. - "Given" + "When" result := commitFrequency calculate. "Then" @@ -36,6 +37,7 @@ CommitFrequencyMetricTest >> testCalculate [ CommitFrequencyMetricTest >> testCalculateNoCommits [ | user glhImporter result commitFrequency | + "Given" user := GLHUser new username: 'test'; contributedProjects: @@ -50,7 +52,7 @@ CommitFrequencyMetricTest >> testCalculateNoCommits [ setPeriodSince: '04-09-2024' until: '04-09-2024'; over: Week. - "Given" + "When" result := commitFrequency calculate. "Then" diff --git a/src/GitLabHealth-Model-Analysis-Tests/ContributedProjectMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/ContributedProjectMetricTest.class.st index b77ddb8..59a2e0c 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/ContributedProjectMetricTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/ContributedProjectMetricTest.class.st @@ -11,6 +11,7 @@ Class { ContributedProjectMetricTest >> testCalculate [ | user glhImporter result contributedProject project1 repository1 | + "Given" project1 := GLHProject new repository: GLHRepository new. repository1 := GLHRepository new project: project1. user := GLHUser new @@ -40,7 +41,7 @@ ContributedProjectMetricTest >> testCalculate [ until: '04-09-2024'; over: Week. - "Given" + "When" result := contributedProject calculate. "Then" @@ -51,6 +52,7 @@ ContributedProjectMetricTest >> testCalculate [ ContributedProjectMetricTest >> testCalculateNoCommits [ | user glhImporter result contributedProject project1 repository1 | + "Given" project1 := GLHProject new repository: GLHRepository new. repository1 := GLHRepository new project: project1. user := GLHUser new @@ -67,7 +69,7 @@ ContributedProjectMetricTest >> testCalculateNoCommits [ until: '04-09-2024'; over: Week. - "Given" + "When" result := contributedProject calculate. "Then" diff --git a/src/GitLabHealth-Model-Analysis-Tests/TimeBetweenCommitMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/TimeBetweenCommitMetricTest.class.st index d2a2a47..ca9b885 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/TimeBetweenCommitMetricTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/TimeBetweenCommitMetricTest.class.st @@ -11,6 +11,7 @@ Class { TimeBetweenCommitMetricTest >> testCalculate [ | user glhImporter result timeBetweenCommit | + "Given" user := GLHUser new username: 'test'; contributedProjects: @@ -39,7 +40,7 @@ TimeBetweenCommitMetricTest >> testCalculate [ until: '09-04-2024'; over: Week. - "Given" + "When" result := timeBetweenCommit calculate. "Then" @@ -50,6 +51,7 @@ TimeBetweenCommitMetricTest >> testCalculate [ TimeBetweenCommitMetricTest >> testCalculateNoCommits [ | user glhImporter result timeBetweenCommit | + "Given" user := GLHUser new username: 'test'; contributedProjects: @@ -65,7 +67,7 @@ TimeBetweenCommitMetricTest >> testCalculateNoCommits [ until: '09-04-2024'; over: Week. - "Given" + "When" result := timeBetweenCommit calculate. "Then" From 59fb6818981486f8716620ab10e77be325fe7cda Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Thu, 5 Sep 2024 14:55:50 +0200 Subject: [PATCH 093/154] fix fuse:with: to include projectIds --- .../GLHUserCatalogueV2Test.class.st | 2 +- src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueV2Test.class.st b/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueV2Test.class.st index 0cb4535..54460e7 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueV2Test.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueV2Test.class.st @@ -152,8 +152,8 @@ GLHUserCatalogueV2Test >> testExportAndLoad [ catalogue addUser: user. json := catalogue exportToJson. - res := GLHUserCatalogueV2 loadFromJson: json. + self assert: res size equals: catalogue size. self assert: ((res at: 'test user' at: #contributedProjects) includes: 11) equals: true. self assert: ((res at: 'test user' at: #names) includes: 'test user') equals: true. diff --git a/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st b/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st index 39a8edf..e6d1a5f 100644 --- a/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st +++ b/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st @@ -259,7 +259,7 @@ GLHUserCatalogueV2 >> exportToJson [ (#id -> user id) } asDictionary; yourself ]. - ^ STONJSON toString: tempDic + ^ STONJSON toStringPretty: tempDic ] { #category : #fuse } @@ -267,6 +267,7 @@ GLHUserCatalogueV2 >> fuse: mainUser with: subUser [ self at: mainUser ifPresent: [ :entry | self at: subUser ifAbsent: [ ^ self ]. (entry at: #names) addAll: (self at: subUser at: #names ). + (entry at: #contributedProjects) addAll: (self at: subUser at: #contributedProjects ). self removeKey: subUser. ]. ] From 59523b985e6253cc0cffd62afb6c6c2d4d5619be Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Thu, 5 Sep 2024 15:43:09 +0200 Subject: [PATCH 094/154] add project ids to the catalogue when importing a user by name --- src/GitLabHealth-Model-Importer/GLHModelImporter.class.st | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index 0cfb639..d5f5ae1 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -535,11 +535,11 @@ GLHModelImporter >> importContributedProjectsOfUser: aGLHUser [ { #category : #'as yet unclassified' } GLHModelImporter >> importCreatorOfCommit: aCommit [ - aCommit commitCreator ifNil: [ - + aCommit commitCreator ifNil: [ aCommit commitCreator: - - (self importUserByUsername: aCommit author_name) ] + (self importUserByUsername: aCommit author_name) ]. + self userCatalogue addUser: aCommit commitCreator withProject: aCommit repository project id. + ^ aCommit commitCreator ] { #category : #api } From 8f78d524896dae5cda446d59055351b71710a37a Mon Sep 17 00:00:00 2001 From: BAUVENT Kilian Date: Thu, 5 Sep 2024 15:54:46 +0200 Subject: [PATCH 095/154] test: ClosedTicketsMetricTest --- .../ClosedTicketsMetricTest.class.st | 42 +++++++++++++++++ .../GLPHImporterMock.class.st | 25 +++++++++-- .../JiraImporterMock.class.st | 45 +++++++++++++++++++ .../GLHUserCatalogueV2.class.st | 2 +- .../GPJCConnector.class.st | 1 - 5 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 src/GitLabHealth-Model-Analysis-Tests/ClosedTicketsMetricTest.class.st create mode 100644 src/GitLabHealth-Model-Analysis-Tests/JiraImporterMock.class.st diff --git a/src/GitLabHealth-Model-Analysis-Tests/ClosedTicketsMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/ClosedTicketsMetricTest.class.st new file mode 100644 index 0000000..9d81b52 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis-Tests/ClosedTicketsMetricTest.class.st @@ -0,0 +1,42 @@ +" +A ClosedTicketsMetricTest is a test class for testing the behavior of ClosedTicketsMetric +" +Class { + #name : #ClosedTicketsMetricTest, + #superclass : #TestCase, + #category : #'GitLabHealth-Model-Analysis-Tests' +} + +{ #category : #tests } +ClosedTicketsMetricTest >> testCalculate [ + + | result glhImporter user closedTicket jiraImporter | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + title: '205 feat do something') }. + + jiraImporter := JiraImporterMock new. + jiraImporter issues: { (JPIssue new key: '205') }. + + + closedTicket := ClosedTicketsMetric new + user: user; + glhImporter: glhImporter; + jiraImporter: jiraImporter; + setPeriodSince: '09-04-2024' until: '09-04-2024'; + over: Week. + + "When" + result := closedTicket calculate. + + "Then" + self assert: result equals: 1 +] diff --git a/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st b/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st index 3e30da6..d5e860e 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st @@ -4,7 +4,8 @@ Class { #instVars : [ 'commits', 'commitDiffs', - 'mergeRequests' + 'mergeRequests', + 'glhModel' ], #category : #'GitLabHealth-Model-Analysis-Tests' } @@ -32,10 +33,23 @@ GLPHImporterMock >> completeImportedCommit: commit [ ^self ] +{ #category : #accessing } +GLPHImporterMock >> glhModel [ + + ^ glhModel +] + +{ #category : #accessing } +GLPHImporterMock >> glhModel: anObject [ + + glhModel := anObject +] + { #category : #commit } GLPHImporterMock >> importCommitsOProject: project since: since until: until [ - ^commits + glhModel addAll: commits. + ^ commits ] { #category : #'as yet unclassified' } @@ -46,8 +60,9 @@ GLPHImporterMock >> importCreatorOfCommit: commit [ { #category : #'import - merge request' } GLPHImporterMock >> importMergeRequests: project since: since until: until [ - ^mergeRequests - + + glhModel addAll: mergeRequests. + ^ mergeRequests ] { #category : #'import - merge request' } @@ -65,6 +80,8 @@ GLPHImporterMock >> initialize [ commits := OrderedCollection new. mergeRequests := OrderedCollection new. + +glhModel := GLPHEModel new name: 'model' ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis-Tests/JiraImporterMock.class.st b/src/GitLabHealth-Model-Analysis-Tests/JiraImporterMock.class.st new file mode 100644 index 0000000..3ba29d2 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis-Tests/JiraImporterMock.class.st @@ -0,0 +1,45 @@ +Class { + #name : #JiraImporterMock, + #superclass : #Object, + #instVars : [ + 'issues', + 'model' + ], + #category : #'GitLabHealth-Model-Analysis-Tests' +} + +{ #category : #'api - import' } +JiraImporterMock >> importAllCurrentAndPastIssuesOf: email [ + + model addAll: issues. + ^ issues +] + +{ #category : #initialization } +JiraImporterMock >> initialize [ + model := GLPHEModel new name: 'model' +] + +{ #category : #accessing } +JiraImporterMock >> issues [ + + ^ issues +] + +{ #category : #accessing } +JiraImporterMock >> issues: anObject [ + + issues := anObject +] + +{ #category : #accessing } +JiraImporterMock >> model [ + + ^ model +] + +{ #category : #accessing } +JiraImporterMock >> model: anObject [ + + model := anObject +] diff --git a/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st b/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st index 8739277..5cc8bbd 100644 --- a/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st +++ b/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st @@ -214,7 +214,7 @@ GLHUserCatalogueV2 >> exportToJson [ (#id -> assoc key id) } asDictionary); yourself ]." tempDic := Dictionary new. self associationsDo: [ :assoc | - |entry user names| + | entry user names | entry := assoc value. user := entry at: #user. names := entry at: #names. diff --git a/src/GitProject-JiraConnector/GPJCConnector.class.st b/src/GitProject-JiraConnector/GPJCConnector.class.st index 6237db5..c8c2222 100644 --- a/src/GitProject-JiraConnector/GPJCConnector.class.st +++ b/src/GitProject-JiraConnector/GPJCConnector.class.st @@ -24,7 +24,6 @@ Class { { #category : #accessing } GPJCConnector >> connect [ - (self gpModel allWithType: GLHCommit) do: [ :commit | self connectCommit: commit ]. (self gpModel allWithType: GLPHEMergeRequest) do: [ :mergeRequest | From 4f01fb9bb477b6dac54bbf19ae99e02076112bab Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Fri, 6 Sep 2024 10:22:39 +0200 Subject: [PATCH 096/154] refactor: change duration for seconds in metrics (#51) * refactor: change duration in seconds * refactor: deprecate exportFor and exportForOver --- .../GitMetricExporter.class.st | 20 +++++++++++++++++-- .../MergeRequestDurationMetric.class.st | 6 +++--- .../TimeBetweenCommitMetric.class.st | 5 +++-- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 5bdc721..cd9122c 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -150,16 +150,32 @@ GitMetricExporter >> entities: aCollection [ { #category : #exporting } GitMetricExporter >> exportFor: usersWithProjects [ - self exportFor: usersWithProjects over: { Date. Week . Month . Year }. + self + deprecated: 'Use #exportInCSV instead' + on: '03 Sept 2024' + in: + 'Pharo-11.0.0+build.726.sha.aece1b5473acf3830a0e082c1bc3a15d4ff3522b (64 Bit)'. + + self exportFor: usersWithProjects over: { + Date. + Week. + Month. + Year } ] { #category : #exporting } GitMetricExporter >> exportFor: usersWithProjects over: aCollectionOfDateWeekMonthOrYear [ + self + deprecated: 'Use #exportInCSV instead' + on: '03 Sept 2024' + in: + 'Pharo-11.0.0+build.726.sha.aece1b5473acf3830a0e082c1bc3a15d4ff3522b (64 Bit)'. + entities ifNil: [ self addEntitiesFromUserNamesAndProjects: usersWithProjects ]. - self exportFor: aCollectionOfDateWeekMonthOrYear. + self exportFor: aCollectionOfDateWeekMonthOrYear ] { #category : #exporting } diff --git a/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st b/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st index 2902a9b..196569b 100644 --- a/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st @@ -8,7 +8,7 @@ Class { MergeRequestDurationMetric >> calculate [ | groupedByDate gitAnalyzer mergeRequestsValidation filterGroups | - userMergeRequests ifNil: [ self load ]. + userMergeRequests ifNil: [ self load ]. groupedByDate := self setupGroupedDate. userMergeRequests ifEmpty: [ ^ nil ]. @@ -47,13 +47,13 @@ MergeRequestDurationMetric >> calculate [ filterGroups at: assoc key put: sum / denominator ]. - ^ filterGroups average asDuration + ^ filterGroups average asSeconds ] { #category : #accessing } MergeRequestDurationMetric >> description [ - ^ 'merge request duration' + ^ 'merge request duration (in seconds)' ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st b/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st index 6beb335..1b2dcf6 100644 --- a/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st @@ -33,8 +33,9 @@ TimeBetweenCommitMetric >> calculate [ (commits2 committed_date - commits1 committed_date) asSeconds ]. + - differences average asDuration ]. + differences average asFloat ]. average := groupedByDate ifEmpty: [ nil ] @@ -46,7 +47,7 @@ TimeBetweenCommitMetric >> calculate [ { #category : #accessing } TimeBetweenCommitMetric >> description [ - ^ 'average time between commits' + ^ 'average time between commits (in seconds)' ] { #category : #accessing } From 372f4e28c4e73f6c2ffb6ee22385eab2a435db96 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Fri, 6 Sep 2024 10:53:51 +0200 Subject: [PATCH 097/154] fix: update tests that are not working anymore --- .../MergeRequestDurationMetricTest.class.st | 2 +- .../TimeBetweenCommitMetricTest.class.st | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis-Tests/MergeRequestDurationMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/MergeRequestDurationMetricTest.class.st index 1c3531f..e3b9d4b 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/MergeRequestDurationMetricTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/MergeRequestDurationMetricTest.class.st @@ -40,7 +40,7 @@ MergeRequestDurationMetricTest >> testCalculate [ result := mergeRequestDuration calculate. "Then" - self assert: result equals: 10 hours + self assert: result equals: (10 * 60 * 60) ] { #category : #tests } diff --git a/src/GitLabHealth-Model-Analysis-Tests/TimeBetweenCommitMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/TimeBetweenCommitMetricTest.class.st index ca9b885..9aacf50 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/TimeBetweenCommitMetricTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/TimeBetweenCommitMetricTest.class.st @@ -44,7 +44,7 @@ TimeBetweenCommitMetricTest >> testCalculate [ result := timeBetweenCommit calculate. "Then" - self assert: result equals: 23 hours + self assert: result equals: (23 hours asSeconds) ] { #category : #tests } From 8c6968c9b7e06859111ee11b982582404202dd5a Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Fri, 6 Sep 2024 11:24:39 +0200 Subject: [PATCH 098/154] add visu for contributor to detect fake user (no id) --- .../GLHUserCatalogueV2Test.class.st | 25 +++ .../GLHGroup.extension.st | 7 + .../GLHProject.extension.st | 10 ++ ...LHProjectContributorVisualization.class.st | 149 ++++++++++++++++++ 4 files changed, 191 insertions(+) create mode 100644 src/GitLabHealth-Model-Extension/GLHGroup.extension.st create mode 100644 src/GitLabHealth-Model-Extension/GLHProject.extension.st create mode 100644 src/GitLabHealth-Model-Visualization/GLHProjectContributorVisualization.class.st diff --git a/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueV2Test.class.st b/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueV2Test.class.st index 54460e7..39de711 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueV2Test.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/GLHUserCatalogueV2Test.class.st @@ -191,6 +191,31 @@ GLHUserCatalogueV2Test >> testExportToJson [ self assert: ((res at: 'test user2') at: #contributedProjects) size equals: 2. ] +{ #category : #test } +GLHUserCatalogueV2Test >> testExportToJsonApostrophe [ + + | user json res | + user := GLHUser new + username: 'test User'; + name: 'tes''t user'; + contributedProjects: { GLHProject new id: 11 } ; + id: 1; + yourself. + + + + catalogue + addUser: user. + json := catalogue exportToJson. + + res := STONJSON fromString: json. + self assert: res size equals: catalogue size. + + self assert: ((res at: 'tes''t user') at: #foundNames) size equals: 2. + self assert: ((res at: 'tes''t user') at: #contributedProjects) size equals: 1. + +] + { #category : #'as yet unclassified' } GLHUserCatalogueV2Test >> testLevenshteinDistanceBetweenBenoitAndNicolas [ self assert: ('benoit' levenshteinDistanceWith: 'nicolas') equals: 6 diff --git a/src/GitLabHealth-Model-Extension/GLHGroup.extension.st b/src/GitLabHealth-Model-Extension/GLHGroup.extension.st new file mode 100644 index 0000000..500de68 --- /dev/null +++ b/src/GitLabHealth-Model-Extension/GLHGroup.extension.st @@ -0,0 +1,7 @@ +Extension { #name : #GLHGroup } + +{ #category : #'*GitLabHealth-Model-Extension' } +GLHGroup >> allProjectstoScope [ + "return the all the projects and subprojects of this group" + ^ self toScope: GLHProject +] diff --git a/src/GitLabHealth-Model-Extension/GLHProject.extension.st b/src/GitLabHealth-Model-Extension/GLHProject.extension.st new file mode 100644 index 0000000..1e03919 --- /dev/null +++ b/src/GitLabHealth-Model-Extension/GLHProject.extension.st @@ -0,0 +1,10 @@ +Extension { #name : #GLHProject } + +{ #category : #'*GitLabHealth-Model-Extension' } +GLHProject >> projectContributorsInspector: aBuilder [ + + + ^ SpRoassalInspectorPresenter new + canvas: (GLHProjectContributorVisualization new forProject: self ); + yourself +] diff --git a/src/GitLabHealth-Model-Visualization/GLHProjectContributorVisualization.class.st b/src/GitLabHealth-Model-Visualization/GLHProjectContributorVisualization.class.st new file mode 100644 index 0000000..0f8e933 --- /dev/null +++ b/src/GitLabHealth-Model-Visualization/GLHProjectContributorVisualization.class.st @@ -0,0 +1,149 @@ +Class { + #name : #GLHProjectContributorVisualization, + #superclass : #MiAbstractVisualization, + #instVars : [ + 'fakeUserColor', + 'userColor' + ], + #category : #'GitLabHealth-Model-Visualization' +} + +{ #category : #private } +GLHProjectContributorVisualization >> createLegend [ + + | legend | + legend := RSLegend new. + legend + text: 'fake user' + withBoxColor: self fakeUserColor . + legend + text: 'real user' + withBoxColor: self userColor . + + + legend legendDo: [ :l | + l + draggable; + withBorder; + padding: 20 ]. + legend location right middle. + + ^ legend +] + +{ #category : #'as yet unclassified' } +GLHProjectContributorVisualization >> createShapeForProject: aProject [ + + | box inspect | + + box := RSBox new + size: 5; + model: aProject; + yourself. + box color: Color lightBlue . + + inspect := RSInspectableInteraction new. + inspect inspectShapeBlock: [ :user | + user inspect. + "block must return a Window :-(" + SystemWindow new + ]. + box @ inspect. + + box @ (RSPopup text: [ :user | + String streamContents: [ :st | + ] ]). + + ^ box +] + +{ #category : #'as yet unclassified' } +GLHProjectContributorVisualization >> createShapeForUser: aUser [ + + | box inspect rsGroup| + + box := RSBox new + size: 10; + model: aUser; + yourself. + box color: (aUser id + ifNil: [ self fakeUserColor ] + ifNotNil: [ self userColor.]). + + + inspect := RSInspectableInteraction new. + inspect inspectShapeBlock: [ :user | + user inspect. + "block must return a Window :-(" + SystemWindow new + ]. + box @ inspect. + + box @ (RSPopup text: [ :user | + String streamContents: [ :st | + st << user name"; << 'id: ' ; << (user id ifNil: ['-'])". + ] ]). + + rsGroup := RSGroup new add: box; yourself. + rsGroup add: (RSLabel new text: aUser name; yourself ). + + RSHorizontalLineLayout new alignMiddle on: rsGroup. + + ^ RSComposite new + shapes: rsGroup; + model: aUser; + + yourself +] + +{ #category : #accessing } +GLHProjectContributorVisualization >> fakeUserColor [ + ^ Color lightGray +] + +{ #category : #'as yet unclassified' } +GLHProjectContributorVisualization >> forProject: aGLHProject [ + + | c shapes legend | + c := RSCanvas new. + + shapes := ((aGLHProject toScope: GLHCommit) collect: #commitCreator) asSet collect: [:author | self createShapeForUser: author ]. +" shapes add: (self createShapeForProject: aGLHProject )." + + c addAll: shapes. + + c @ RSCanvasController. + RSLineBuilder orthoHorizontal + markerEnd: (RSMarker new + offset: 2; + shape: (RSShapeFactory triangle + color: Color black; + size: 5; + yourself)); + attachPoint: RSHorizontalAttachPoint new; + canvas: c; + shapes: c nodes; + connectFrom: [ ]. + RSHorizontalVanDerPloegTreeLayout new on: c nodes. + + legend := self createLegend. + legend container: c. + legend build. + + ^ c +] + +{ #category : #initialization } +GLHProjectContributorVisualization >> initialize [ + + super initialize. + + fakeUserColor := Color purple lighter. + userColor := Color green. + +] + +{ #category : #accessing } +GLHProjectContributorVisualization >> userColor [ + ^ Color lightGreen +] From 5e78e52d207f5ca11614a505faff90098366b517 Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Thu, 12 Sep 2024 16:10:08 +0200 Subject: [PATCH 099/154] add global for importer --- .../GLHUserCatalogue.class.st | 2 +- .../GLHUserCatalogueV2.class.st | 2 +- .../GLHModelImporter.class.st | 20 +++++++++++++++---- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st b/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st index 4881058..808bbd6 100644 --- a/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st +++ b/src/GitLabHealth-Model-Analysis/GLHUserCatalogue.class.st @@ -199,7 +199,7 @@ GLHUserCatalogue >> exportToJson [ { #category : #initialization } GLHUserCatalogue >> initialize [ - anImporter := GLHModelImporter current. + anImporter := GLHModelImporter importers anyOne. ] { #category : #'as yet unclassified' } diff --git a/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st b/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st index e6d1a5f..04d177e 100644 --- a/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st +++ b/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st @@ -290,7 +290,7 @@ GLHUserCatalogueV2 >> initACatalogueEntryForUser: aGLHUser [. { #category : #initialization } GLHUserCatalogueV2 >> initialize [ - anImporter := GLHModelImporter current. + anImporter := GLHModelImporter new. ] { #category : #'as yet unclassified' } diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index d5f5ae1..4a11c0f 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -18,10 +18,14 @@ Class { #category : #'GitLabHealth-Model-Importer' } -{ #category : #accessing } -GLHModelImporter class >> current [ +{ #category : #'as yet unclassified' } +GLHModelImporter class >> importers [ + ^ currentImporter +] - ^ currentImporter +{ #category : #initialization } +GLHModelImporter class >> reset [ + currentImporter := nil. ] { #category : #'private - api' } @@ -877,7 +881,15 @@ GLHModelImporter >> loadAllProjectsFromRepositorySoftware [ { #category : #'as yet unclassified' } GLHModelImporter >> makeGlobal [ - currentImporter := self + ^ self makeGlobal: DateAndTime now printString. +] + +{ #category : #'as yet unclassified' } +GLHModelImporter >> makeGlobal: aLabel [ + + currentImporter := currentImporter ifNil: [ OrderedDictionary new ]. + currentImporter at: aLabel put: self. + ^ self ] { #category : #private } From c47bc335fb75aebdcca99cd2e558027ed0451840 Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Thu, 12 Sep 2024 17:49:02 +0200 Subject: [PATCH 100/154] fix metric names and add new ones for Merge request --- .../ClosedMergeRequestMetricTest.class.st | 230 ++++++++++++++++++ .../MergedMergeRequestMetricTest.class.st | 74 +++++- .../OpenedMergeRequestMetricTest.class.st | 106 +++++++- .../PendingMergeRequestMetricTest.class.st | 176 ++++++++++++++ ...iewedByUserMergeRequestMetricTest.class.st | 126 ++++++++++ ...derAMinuteMergeRequestMetricTest.class.st} | 11 +- .../ClosedMergeRequestMetric.class.st | 5 +- .../GLHUserCatalogueV2.class.st | 9 + .../GitMetricExporter.class.st | 2 +- .../MergedMergeRequestMetric.class.st | 3 +- .../PendingMergeRequestMetric.class.st | 38 +++ .../ReviewedByUserMergeRequestMetric.class.st | 57 +++++ ...edUnderAMinuteMergeRequestMetric.class.st} | 10 +- 13 files changed, 824 insertions(+), 23 deletions(-) create mode 100644 src/GitLabHealth-Model-Analysis-Tests/PendingMergeRequestMetricTest.class.st create mode 100644 src/GitLabHealth-Model-Analysis-Tests/ReviewedByUserMergeRequestMetricTest.class.st rename src/GitLabHealth-Model-Analysis-Tests/{MergedMergeRequestWithoutReviewMetricTest.class.st => SelfMergedUnderAMinuteMergeRequestMetricTest.class.st} (84%) create mode 100644 src/GitLabHealth-Model-Analysis/PendingMergeRequestMetric.class.st create mode 100644 src/GitLabHealth-Model-Analysis/ReviewedByUserMergeRequestMetric.class.st rename src/GitLabHealth-Model-Analysis/{MergedMergeRequestWithoutReviewMetric.class.st => SelfMergedUnderAMinuteMergeRequestMetric.class.st} (86%) diff --git a/src/GitLabHealth-Model-Analysis-Tests/ClosedMergeRequestMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/ClosedMergeRequestMetricTest.class.st index e4219c2..1bf9f7e 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/ClosedMergeRequestMetricTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/ClosedMergeRequestMetricTest.class.st @@ -41,10 +41,202 @@ ClosedMergeRequestMetricTest >> testCalculate [ "When" result := closedMergeRequestMetric calculate. + "Then" + self assert: result equals: 2 +] + +{ #category : #tests } +ClosedMergeRequestMetricTest >> testCalculate1MRinPeriod2Outside [ + + | result glhImporter user closedMergeRequestMetric | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { + (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: '09-05-2024'; + state: 'closed'). + (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: nil; + state: 'closed'). + (GLPHEMergeRequest new + author: user; + created_at: '08-01-2024'; + merged_at: nil; + state: 'closed')}. + + + closedMergeRequestMetric := ClosedMergeRequestMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '08-01-2024' + until: '08-05-2024'; + over: Week. + + "When" + result := closedMergeRequestMetric calculate. + "Then" self assert: result equals: 1 ] +{ #category : #tests } +ClosedMergeRequestMetricTest >> testCalculate3MR [ + + | result glhImporter user closedMergeRequestMetric | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { + (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: '09-05-2024'; + state: 'closed'). + (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: nil; + state: 'closed'). + (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: nil; + state: 'closed') }. + + + closedMergeRequestMetric := ClosedMergeRequestMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-04-2024' + until: '09-04-2024'; + over: Week. + + "When" + result := closedMergeRequestMetric calculate. + + "Then" + self assert: result equals: 3 +] + +{ #category : #tests } +ClosedMergeRequestMetricTest >> testCalculate3MRClosed2Opened [ + + | result glhImporter user closedMergeRequestMetric | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { + (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: '09-05-2024'; + state: 'closed'). + (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: nil; + state: 'closed'). + (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: nil; + state: 'closed'). + (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: nil; + state: 'opened'). + (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: nil; + state: 'opened') }. + + + closedMergeRequestMetric := ClosedMergeRequestMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-04-2024' + until: '09-04-2024'; + over: Week. + + "When" + result := closedMergeRequestMetric calculate. + + "Then" + self assert: result equals: 3 +] + +{ #category : #tests } +ClosedMergeRequestMetricTest >> testCalculateNoClosedMR [ + + | result glhImporter user closedMergeRequestMetric | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { + (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: '09-05-2024'; + state: 'opened'). + (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: nil; + state: 'opened'). + (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: nil; + state: 'opened'). + (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: nil; + state: 'opened'). + (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: nil; + state: 'opened') }. + + + closedMergeRequestMetric := ClosedMergeRequestMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-04-2024' + until: '09-04-2024'; + over: Week. + + "When" + result := closedMergeRequestMetric calculate. + + "Then" + self assert: result equals: 0 +] + { #category : #tests } ClosedMergeRequestMetricTest >> testCalculateNoMergeRequests [ @@ -70,3 +262,41 @@ ClosedMergeRequestMetricTest >> testCalculateNoMergeRequests [ "Then" self assert: result equals: 0 ] + +{ #category : #tests } +ClosedMergeRequestMetricTest >> testCalculateOutSidePeriod [ + + | result glhImporter user closedMergeRequestMetric | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { + (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: '09-05-2024'; + state: 'closed'). + (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: nil; + state: 'closed') }. + + + closedMergeRequestMetric := ClosedMergeRequestMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '08-01-2024' + until: '08-05-2024'; + over: Week. + + "When" + result := closedMergeRequestMetric calculate. + + "Then" + self assert: result equals: 0 +] diff --git a/src/GitLabHealth-Model-Analysis-Tests/MergedMergeRequestMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/MergedMergeRequestMetricTest.class.st index 7a549a8..10b5169 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/MergedMergeRequestMetricTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/MergedMergeRequestMetricTest.class.st @@ -10,6 +10,76 @@ Class { { #category : #tests } MergedMergeRequestMetricTest >> testCalculate [ + | result glhImporter user mergedMergeRequest | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: '09-05-2024') + }. + + + mergedMergeRequest := MergedMergeRequestMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-01-2024' + until: '09-07-2024'; + over: Week. + + "When" + result := mergedMergeRequest calculate. + + "Then" + self assert: result equals: 1 +] + +{ #category : #tests } +MergedMergeRequestMetricTest >> testCalculate1MRInPeriod1Outside [ + + | result glhImporter user mergedMergeRequest | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { + "open and merge during the same week" + (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: '09-05-2024') + "open but merged anotherWeek" + .(GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: '09-10-2024')}. + + + mergedMergeRequest := MergedMergeRequestMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-01-2024' + until: '09-07-2024'; + over: Week. + + "When" + result := mergedMergeRequest calculate. + + "Then" + self assert: result equals: 1 +] + +{ #category : #tests } +MergedMergeRequestMetricTest >> testCalculate1MROpenedButNotMerged [ + | result glhImporter user mergedMergeRequest | "Given" user := GLHUser new @@ -31,8 +101,8 @@ MergedMergeRequestMetricTest >> testCalculate [ mergedMergeRequest := MergedMergeRequestMetric new user: user; glhImporter: glhImporter; - setPeriodSince: '09-04-2024' - until: '09-04-2024'; + setPeriodSince: '09-01-2024' + until: '09-07-2024'; over: Week. "When" diff --git a/src/GitLabHealth-Model-Analysis-Tests/OpenedMergeRequestMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/OpenedMergeRequestMetricTest.class.st index 5ced5ed..e649384 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/OpenedMergeRequestMetricTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/OpenedMergeRequestMetricTest.class.st @@ -10,10 +10,17 @@ Class { { #category : #tests } OpenedMergeRequestMetricTest >> testCalculate [ - | openedMergeRequest result glhImporter user | + | openedMergeRequest result glhImporter user user2| "Given" user := GLHUser new - username: 'test'; + username: 'user'; + name: 'user'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + user2 := GLHUser new + username: 'user2'; + name: 'user2'; contributedProjects: { (GLHProject new repository: GLHRepository new) }. @@ -26,8 +33,53 @@ OpenedMergeRequestMetricTest >> testCalculate [ openedMergeRequest := OpenedMergeRequestMetric new user: user; glhImporter: glhImporter; - setPeriodSince: '09-04-2024' - until: '09-04-2024'; + setPeriodSince: '09-01-2024' + until: '09-07-2024'; + over: Week. + + "When" + result := openedMergeRequest calculate. + + "Then" + self assert: result equals: 1 +] + +{ #category : #tests } +OpenedMergeRequestMetricTest >> testCalculate1OpenedAnd2NotOpenedByUser [ + + | openedMergeRequest result glhImporter user user2| + "Given" + user := GLHUser new + username: 'user'; + name: 'user'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + user2 := GLHUser new + username: 'user2'; + name: 'user2'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { + (GLPHEMergeRequest new + author: user2; + created_at: '09-02-2024'). + (GLPHEMergeRequest new + author: user2; + created_at: '09-03-2024'). + (GLPHEMergeRequest new + author: user; + created_at: '09-03-2024') + }. + + + openedMergeRequest := OpenedMergeRequestMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-01-2024' + until: '09-07-2024'; over: Week. "When" @@ -53,8 +105,50 @@ OpenedMergeRequestMetricTest >> testCalculateNoMergeRequests [ openedMergeRequest := OpenedMergeRequestMetric new user: user; glhImporter: glhImporter; - setPeriodSince: '09-04-2024' - until: '09-04-2024'; + setPeriodSince: '09-01-2024' + until: '09-07-2024'; + over: Week. + + "When" + result := openedMergeRequest calculate. + + "Then" + self assert: result equals: 0 +] + +{ #category : #tests } +OpenedMergeRequestMetricTest >> testCalculateNotOpenedByUser [ + + | openedMergeRequest result glhImporter user user2| + "Given" + user := GLHUser new + username: 'user'; + name: 'user'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + user2 := GLHUser new + username: 'user2'; + name: 'user2'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { + (GLPHEMergeRequest new + author: user2; + created_at: '09-02-2024'). + (GLPHEMergeRequest new + author: user2; + created_at: '09-03-2024') + }. + + + openedMergeRequest := OpenedMergeRequestMetric new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-01-2024' + until: '09-07-2024'; over: Week. "When" diff --git a/src/GitLabHealth-Model-Analysis-Tests/PendingMergeRequestMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/PendingMergeRequestMetricTest.class.st new file mode 100644 index 0000000..b88c72f --- /dev/null +++ b/src/GitLabHealth-Model-Analysis-Tests/PendingMergeRequestMetricTest.class.st @@ -0,0 +1,176 @@ +" +A PendingMergeRequestMetricTest is a test class for testing the behavior of PendingMergeRequestMetric +" +Class { + #name : #PendingMergeRequestMetricTest, + #superclass : #TestCase, + #category : #'GitLabHealth-Model-Analysis-Tests' +} + +{ #category : #test } +PendingMergeRequestMetricTest >> testCalculate [ + + | result glhImporter user mergedMergeRequestPending| + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { + (GLPHEMergeRequest new + author: user; + merge_user: user; + created_at: '09-05-2024:00-00-00' asDateAndTime; + state: 'opened'; + merged_at: nil). + }. + + + mergedMergeRequestPending := PendingMergeRequestMetric + new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-01-2024' + until: '09-07-2024'; + over: Week. + + "When" + result := mergedMergeRequestPending calculate. + + "Then" + self assert: result equals: 1 +] + +{ #category : #test } +PendingMergeRequestMetricTest >> testCalculate1Pending1Closed [ + + | result glhImporter user mergedMergeRequestPending| + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { + (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024:00-00-00' asDateAndTime; + state: 'opened'; + merged_at: nil). + (GLPHEMergeRequest new + author: user; + created_at: '09-01-2024:00-00-00' asDateAndTime; + state: 'closed'; + merged_at: '09-02-2024:00-00-00' asDateAndTime). + }. + + + mergedMergeRequestPending := PendingMergeRequestMetric + new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-01-2024' + until: '09-07-2024'; + over: Week. + + "When" + result := mergedMergeRequestPending calculate. + + "Then" + self assert: result equals: 1 +] + +{ #category : #test } +PendingMergeRequestMetricTest >> testCalculate1PendingByUser [ + + | result glhImporter user mergedMergeRequestPending user2| + "Given" + user := GLHUser new + username: 'user'; + name: 'user'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + user2 := GLHUser new + username: 'user2'; + name: 'user2'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { + (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024:00-00-00' asDateAndTime; + state: 'opened'; + merged_at: nil). + (GLPHEMergeRequest new + author: user2; + created_at: '09-01-2024:00-00-00' asDateAndTime; + state: 'opened'; + merged_at: nil). + }. + + mergedMergeRequestPending := PendingMergeRequestMetric + new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-01-2024' + until: '09-07-2024'; + over: Week. + + "When" + result := mergedMergeRequestPending calculate. + + "Then" + self assert: result equals: 1 +] + +{ #category : #test } +PendingMergeRequestMetricTest >> testCalculate2Pending [ + + | result glhImporter user mergedMergeRequestPending user2| + "Given" + user := GLHUser new + username: 'user'; + name: 'user'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + user2 := GLHUser new + username: 'user2'; + name: 'user2'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { + (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024:00-00-00' asDateAndTime; + state: 'opened'; + merged_at: nil). + (GLPHEMergeRequest new + author: user; + created_at: '09-02-2024:00-00-00' asDateAndTime; + state: 'opened'; + merged_at: nil). + }. + + mergedMergeRequestPending := PendingMergeRequestMetric + new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-01-2024' + until: '09-07-2024'; + over: Week. + + "When" + result := mergedMergeRequestPending calculate. + + "Then" + self assert: result equals: 2 +] diff --git a/src/GitLabHealth-Model-Analysis-Tests/ReviewedByUserMergeRequestMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/ReviewedByUserMergeRequestMetricTest.class.st new file mode 100644 index 0000000..37fecb9 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis-Tests/ReviewedByUserMergeRequestMetricTest.class.st @@ -0,0 +1,126 @@ +" +A ReviewedByUserMergeRequestMetricTest is a test class for testing the behavior of ReviewedByUserMergeRequestMetric +" +Class { + #name : #ReviewedByUserMergeRequestMetricTest, + #superclass : #TestCase, + #category : #'GitLabHealth-Model-Analysis-Tests' +} + +{ #category : #test } +ReviewedByUserMergeRequestMetricTest >> testCalculate [ + + | result glhImporter user mergeRequests user2| + "Given" + user := GLHUser new + name: 'testUser'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + user2 := GLHUser new + name: 'testUser2'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { + (GLPHEMergeRequest new + author: user; + merge_user: user; + reviewers: { user }; + created_at: '09-05-2024:00-00-00' asDateAndTime; + merged_at: '09-05-2024:00-00-01' asDateAndTime). + (GLPHEMergeRequest new + author: user; + merge_user: nil; + created_at: '09-05-2024:00-00-00' asDateAndTime; + merged_at: '09-05-2024:00-00-01' asDateAndTime) }. + + + mergeRequests := ReviewedByUserMergeRequestMetric + new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-04-2024' + until: '09-04-2024'; + over: Week. + + "When" + result := mergeRequests calculate. + + "Then" + self assert: result equals: 1 +] + +{ #category : #test } +ReviewedByUserMergeRequestMetricTest >> testCalculateNoMergeRequests [ + + | result glhImporter user mergeRequests | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { }. + + + mergeRequests := ReviewedByUserMergeRequestMetric + new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-04-2024' + until: '09-04-2024'; + over: Week. + + "When" + result := mergeRequests calculate. + + "Then" + self assert: result equals: 0 +] + +{ #category : #test } +ReviewedByUserMergeRequestMetricTest >> testCalculateReviewByOther [ + + | result glhImporter user mergedMergeRequestWithoutReview user2| + "Given" + user := GLHUser new + name: 'testUser'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + user2 := GLHUser new + name: 'testUser2'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { + (GLPHEMergeRequest new + author: user; + merge_user: user; + reviewers: { user2 }; + created_at: '09-05-2024:00-00-00' asDateAndTime; + merged_at: '09-05-2024:00-00-01' asDateAndTime). + (GLPHEMergeRequest new + author: user; + merge_user: user2; + reviewers: { user2 }; + created_at: '09-05-2024:00-00-00' asDateAndTime; + merged_at: '09-05-2024:00-00-01' asDateAndTime). }. + + + mergedMergeRequestWithoutReview := ReviewedByUserMergeRequestMetric + new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-04-2024' + until: '09-04-2024'; + over: Week. + + "When" + result := mergedMergeRequestWithoutReview calculate. + + "Then" + self assert: result equals: 0 +] diff --git a/src/GitLabHealth-Model-Analysis-Tests/MergedMergeRequestWithoutReviewMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/SelfMergedUnderAMinuteMergeRequestMetricTest.class.st similarity index 84% rename from src/GitLabHealth-Model-Analysis-Tests/MergedMergeRequestWithoutReviewMetricTest.class.st rename to src/GitLabHealth-Model-Analysis-Tests/SelfMergedUnderAMinuteMergeRequestMetricTest.class.st index 92301d4..c2100bb 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/MergedMergeRequestWithoutReviewMetricTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/SelfMergedUnderAMinuteMergeRequestMetricTest.class.st @@ -2,13 +2,13 @@ A MergedMergeRequestWithoutReviewMetricTest is a test class for testing the behavior of MergedMergeRequestWithoutReviewMetric " Class { - #name : #MergedMergeRequestWithoutReviewMetricTest, + #name : #SelfMergedUnderAMinuteMergeRequestMetricTest, #superclass : #TestCase, #category : #'GitLabHealth-Model-Analysis-Tests' } { #category : #tests } -MergedMergeRequestWithoutReviewMetricTest >> testCalculate [ +SelfMergedUnderAMinuteMergeRequestMetricTest >> testCalculate [ | result glhImporter user mergedMergeRequestWithoutReview | "Given" @@ -22,6 +22,7 @@ MergedMergeRequestWithoutReviewMetricTest >> testCalculate [ (GLPHEMergeRequest new author: user; merge_user: user; + reviewers: { user }; created_at: '09-05-2024:00-00-00' asDateAndTime; merged_at: '09-05-2024:00-00-01' asDateAndTime). (GLPHEMergeRequest new @@ -31,7 +32,7 @@ MergedMergeRequestWithoutReviewMetricTest >> testCalculate [ merged_at: '09-05-2024:00-00-01' asDateAndTime) }. - mergedMergeRequestWithoutReview := MergedMergeRequestWithoutReviewMetric + mergedMergeRequestWithoutReview := SelfMergedUnderAMinuteMergeRequestMetric new user: user; glhImporter: glhImporter; @@ -47,7 +48,7 @@ MergedMergeRequestWithoutReviewMetricTest >> testCalculate [ ] { #category : #tests } -MergedMergeRequestWithoutReviewMetricTest >> testCalculateNoMergeRequests [ +SelfMergedUnderAMinuteMergeRequestMetricTest >> testCalculateNoMergeRequests [ | result glhImporter user mergedMergeRequestWithoutReview | "Given" @@ -58,7 +59,7 @@ MergedMergeRequestWithoutReviewMetricTest >> testCalculateNoMergeRequests [ glhImporter := GLPHImporterMock new. - mergedMergeRequestWithoutReview := MergedMergeRequestWithoutReviewMetric + mergedMergeRequestWithoutReview := SelfMergedUnderAMinuteMergeRequestMetric new user: user; glhImporter: glhImporter; diff --git a/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st index d98dd6b..55388e2 100644 --- a/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st @@ -13,7 +13,7 @@ ClosedMergeRequestMetric >> calculate [ userClosedMergeRequests := userMergeRequests select: [ :userMergeRequest | - userMergeRequest merged_at isNil and: + "userMergeRequest merged_at isNil and:" userMergeRequest state = 'closed' ]. userClosedMergeRequests do: [ :userMergeRequest | @@ -26,14 +26,13 @@ ClosedMergeRequestMetric >> calculate [ groupedByDate := groupedByDate collect: [ :group | group size ]. - ^ groupedByDate average asFloat ] { #category : #accessing } ClosedMergeRequestMetric >> description [ - ^ 'number of merge requests closed and not merged' + ^ 'number of merge requests closed' ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st b/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st index 04d177e..576d867 100644 --- a/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st +++ b/src/GitLabHealth-Model-Analysis/GLHUserCatalogueV2.class.st @@ -423,3 +423,12 @@ GLHUserCatalogueV2 >> users [ ^ self collect: [ :entry | entry at: #user ]. ] + +{ #category : #search } +GLHUserCatalogueV2 >> weirdUsers [ + "return user that have name containing weird caracter, making them suspicious" + ^ self select: [ :entry | + ((entry at:#user) name includesSubstring: '.') or: [ + (entry at:#user) name includesSubstring: '@' ] + ]. +] diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index cd9122c..c8efee8 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -457,7 +457,7 @@ GitMetricExporter >> initialize [ OpenedMergeRequestMetric. ClosedMergeRequestMetric. MergedMergeRequestMetric. - MergedMergeRequestWithoutReviewMetric. + SelfMergedUnderAMinuteMergeRequestMetric. ClosedTicketsMetric} ] diff --git a/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st index 33190cc..2547b0a 100644 --- a/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st @@ -16,7 +16,8 @@ MergedMergeRequestMetric >> calculate [ userMergeRequest merged_at isNotNil ]. userMergedMergeRequests do: [ :userMergeRequest | - dateOver := self transformDate: userMergeRequest created_at to: over. + "here we look at the specific date of its merged" + dateOver := self transformDate: userMergeRequest merged_at to: over. groupedByDate at: dateOver printString ifPresent: [ :value | value add: userMergeRequest ] ]. diff --git a/src/GitLabHealth-Model-Analysis/PendingMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/PendingMergeRequestMetric.class.st new file mode 100644 index 0000000..9626360 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/PendingMergeRequestMetric.class.st @@ -0,0 +1,38 @@ +Class { + #name : #PendingMergeRequestMetric, + #superclass : #UserMergeRequestMetric, + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #calculating } +PendingMergeRequestMetric >> calculate [ + + | groupedByDate userMergedMergeRequests dateOver | + userMergeRequests ifNil: [ self load ]. + groupedByDate := self setupGroupedDate. + + userMergedMergeRequests := userMergeRequests select: [ + :userMergeRequest | + userMergeRequest state = 'opened' ]. + + userMergedMergeRequests do: [ :userMergeRequest | + "here we look at the specific date of its merged" + dateOver := self transformDate: userMergeRequest created_at to: over. + groupedByDate + at: dateOver printString + ifPresent: [ :value | value add: userMergeRequest ] ]. + groupedByDate := groupedByDate collect: [ :group | group size ]. + + ^ groupedByDate average asFloat +] + +{ #category : #accessing } +PendingMergeRequestMetric >> description [ + + ^ 'number of merge request opened during the period and left opened at the end of it' +] + +{ #category : #accessing } +PendingMergeRequestMetric >> name [ + ^'pendingMergeRequest' +] diff --git a/src/GitLabHealth-Model-Analysis/ReviewedByUserMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/ReviewedByUserMergeRequestMetric.class.st new file mode 100644 index 0000000..d3b6e57 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/ReviewedByUserMergeRequestMetric.class.st @@ -0,0 +1,57 @@ +Class { + #name : #ReviewedByUserMergeRequestMetric, + #superclass : #UserMergeRequestMetric, + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #calculating } +ReviewedByUserMergeRequestMetric >> calculate [ + + | groupedByDate mergedMergeRequest reviewedMergeRequests dateOver gitAnalyzer | + userMergeRequests ifNil: [ self load ]. + groupedByDate := self setupGroupedDate. + + gitAnalyzer := GitAnalyzer new. + + mergedMergeRequest := userMergeRequests select: [ :mr | + mr reviewers isNotEmpty ]. + + reviewedMergeRequests := mergedMergeRequest select: [ + :userMergeRequest | + | validation | + validation := gitAnalyzer + analyseMergeResquestValidation: + userMergeRequest. + (userMergeRequest reviewers includes: user) ]. + + reviewedMergeRequests do: [ :userMergeRequest | + dateOver := self transformDate: userMergeRequest created_at to: over. + + groupedByDate + at: dateOver printString + ifPresent: [ :value | value add: userMergeRequest ] ]. + + groupedByDate := groupedByDate collect: [ :group | group size ]. + + ^ groupedByDate average asFloat +] + +{ #category : #accessing } +ReviewedByUserMergeRequestMetric >> description [ + + ^ 'number of merger request reviewed by the user' +] + +{ #category : #loading } +ReviewedByUserMergeRequestMetric >> load [ + userMergeRequests := self + loadCompleteMergeRequestsSince: + (period at: #since) + until: (period at: #until) +] + +{ #category : #accessing } +ReviewedByUserMergeRequestMetric >> name [ + + ^ 'reviewedMergeRequest' +] diff --git a/src/GitLabHealth-Model-Analysis/MergedMergeRequestWithoutReviewMetric.class.st b/src/GitLabHealth-Model-Analysis/SelfMergedUnderAMinuteMergeRequestMetric.class.st similarity index 86% rename from src/GitLabHealth-Model-Analysis/MergedMergeRequestWithoutReviewMetric.class.st rename to src/GitLabHealth-Model-Analysis/SelfMergedUnderAMinuteMergeRequestMetric.class.st index 4371515..2f873d9 100644 --- a/src/GitLabHealth-Model-Analysis/MergedMergeRequestWithoutReviewMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/SelfMergedUnderAMinuteMergeRequestMetric.class.st @@ -1,11 +1,11 @@ Class { - #name : #MergedMergeRequestWithoutReviewMetric, + #name : #SelfMergedUnderAMinuteMergeRequestMetric, #superclass : #UserMergeRequestMetric, #category : #'GitLabHealth-Model-Analysis' } { #category : #calculating } -MergedMergeRequestWithoutReviewMetric >> calculate [ +SelfMergedUnderAMinuteMergeRequestMetric >> calculate [ | groupedByDate mergedMergeRequest noVerificationMergeRequests dateOver gitAnalyzer | userMergeRequests ifNil: [ self load ]. @@ -44,13 +44,13 @@ MergedMergeRequestWithoutReviewMetric >> calculate [ ] { #category : #accessing } -MergedMergeRequestWithoutReviewMetric >> description [ +SelfMergedUnderAMinuteMergeRequestMetric >> description [ ^ 'number of merge requests merged without review' ] { #category : #loading } -MergedMergeRequestWithoutReviewMetric >> load [ +SelfMergedUnderAMinuteMergeRequestMetric >> load [ userMergeRequests := self loadCompleteMergeRequestsSince: @@ -59,7 +59,7 @@ MergedMergeRequestWithoutReviewMetric >> load [ ] { #category : #accessing } -MergedMergeRequestWithoutReviewMetric >> name [ +SelfMergedUnderAMinuteMergeRequestMetric >> name [ ^ 'mergeRequestMergedWithoutReview' ] From 3b6ee8853eef07708c04fd5c1f58e0b783e90da2 Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Fri, 13 Sep 2024 10:38:45 +0200 Subject: [PATCH 101/154] utilized class name as metric name for coherence and simplicity --- .../ClosedMergeRequestMetric.class.st | 2 +- src/GitLabHealth-Model-Analysis/CodeAdditionMetric.class.st | 6 ------ src/GitLabHealth-Model-Analysis/CodeChurnMetric.class.st | 6 ------ src/GitLabHealth-Model-Analysis/CodeDeletionMetric.class.st | 6 ------ .../CommentContributionMetric.class.st | 6 ------ .../CommitFrequencyMetric.class.st | 6 ------ .../ContributedProjectMetric.class.st | 6 ------ .../DelayUntilFirstChurnMetric.class.st | 6 ------ .../MergeRequestDurationMetric.class.st | 2 +- src/GitLabHealth-Model-Analysis/Metric.class.st | 5 +++++ .../PendingMergeRequestMetric.class.st | 2 +- .../SelfMergedUnderAMinuteMergeRequestMetric.class.st | 4 ++-- .../TimeBetweenCommitMetric.class.st | 6 ------ src/GitLabHealth-Model-Analysis/UserCommitsMetric.class.st | 2 +- 14 files changed, 11 insertions(+), 54 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st index 55388e2..1cf7693 100644 --- a/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st @@ -32,7 +32,7 @@ ClosedMergeRequestMetric >> calculate [ { #category : #accessing } ClosedMergeRequestMetric >> description [ - ^ 'number of merge requests closed' + ^ 'number of closed merge requests' ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/CodeAdditionMetric.class.st b/src/GitLabHealth-Model-Analysis/CodeAdditionMetric.class.st index 8f4ddd8..bd0acbf 100644 --- a/src/GitLabHealth-Model-Analysis/CodeAdditionMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CodeAdditionMetric.class.st @@ -41,9 +41,3 @@ CodeAdditionMetric >> description [ ^ 'code addition (avg)' ] - -{ #category : #accessing } -CodeAdditionMetric >> name [ - - ^ 'codeContribution' -] diff --git a/src/GitLabHealth-Model-Analysis/CodeChurnMetric.class.st b/src/GitLabHealth-Model-Analysis/CodeChurnMetric.class.st index 18917e8..a34aff2 100644 --- a/src/GitLabHealth-Model-Analysis/CodeChurnMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CodeChurnMetric.class.st @@ -75,9 +75,3 @@ CodeChurnMetric >> description [ CodeChurnMetric >> initialize [ maxCommitWindow := 3 ] - -{ #category : #accessing } -CodeChurnMetric >> name [ - - ^ 'codeChurn' -] diff --git a/src/GitLabHealth-Model-Analysis/CodeDeletionMetric.class.st b/src/GitLabHealth-Model-Analysis/CodeDeletionMetric.class.st index 4469457..e6f465c 100644 --- a/src/GitLabHealth-Model-Analysis/CodeDeletionMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CodeDeletionMetric.class.st @@ -41,9 +41,3 @@ CodeDeletionMetric >> description [ ^'code deletion (avg)' ] - -{ #category : #accessing } -CodeDeletionMetric >> name [ - - ^'codeDeletion' -] diff --git a/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st b/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st index 33d3fe4..8811872 100644 --- a/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st @@ -52,9 +52,3 @@ CommentContributionMetric >> load [ loadCompleteCommitsSince: (period at: #since) until: (period at: #until) ] - -{ #category : #accessing } -CommentContributionMetric >> name [ - - ^ 'commentContribution' -] diff --git a/src/GitLabHealth-Model-Analysis/CommitFrequencyMetric.class.st b/src/GitLabHealth-Model-Analysis/CommitFrequencyMetric.class.st index d907f36..10c7d36 100644 --- a/src/GitLabHealth-Model-Analysis/CommitFrequencyMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CommitFrequencyMetric.class.st @@ -26,9 +26,3 @@ CommitFrequencyMetric >> description [ ^'commits frequency (avg)' ] - -{ #category : #accessing } -CommitFrequencyMetric >> name [ - - ^ 'commitFrequency' -] diff --git a/src/GitLabHealth-Model-Analysis/ContributedProjectMetric.class.st b/src/GitLabHealth-Model-Analysis/ContributedProjectMetric.class.st index 32a3414..8cc89bc 100644 --- a/src/GitLabHealth-Model-Analysis/ContributedProjectMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/ContributedProjectMetric.class.st @@ -30,9 +30,3 @@ ContributedProjectMetric >> description [ ^ 'number of project with min 1 commit of user' ] - -{ #category : #accessing } -ContributedProjectMetric >> name [ - - ^ 'contributedProject' -] diff --git a/src/GitLabHealth-Model-Analysis/DelayUntilFirstChurnMetric.class.st b/src/GitLabHealth-Model-Analysis/DelayUntilFirstChurnMetric.class.st index 61b51fa..f6b0f08 100644 --- a/src/GitLabHealth-Model-Analysis/DelayUntilFirstChurnMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/DelayUntilFirstChurnMetric.class.st @@ -81,9 +81,3 @@ DelayUntilFirstChurnMetric >> initialize [ super initialize. maxCommitWindow := 3 ] - -{ #category : #accessing } -DelayUntilFirstChurnMetric >> name [ - - ^'delayUntilFirstChurn' -] diff --git a/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st b/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st index 196569b..d038eac 100644 --- a/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st @@ -53,7 +53,7 @@ MergeRequestDurationMetric >> calculate [ { #category : #accessing } MergeRequestDurationMetric >> description [ - ^ 'merge request duration (in seconds)' + ^ 'average time to merge a merge request (in seconds)' ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/Metric.class.st b/src/GitLabHealth-Model-Analysis/Metric.class.st index 3871199..b9e360f 100644 --- a/src/GitLabHealth-Model-Analysis/Metric.class.st +++ b/src/GitLabHealth-Model-Analysis/Metric.class.st @@ -10,6 +10,11 @@ Class { #category : #'GitLabHealth-Model-Analysis' } +{ #category : #'as yet unclassified' } +Metric >> accronym [ + ^ (self name first uppercase asString), (self name select: #isUppercase) +] + { #category : #calculating } Metric >> calculate [ diff --git a/src/GitLabHealth-Model-Analysis/PendingMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/PendingMergeRequestMetric.class.st index 9626360..185e7c5 100644 --- a/src/GitLabHealth-Model-Analysis/PendingMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/PendingMergeRequestMetric.class.st @@ -29,7 +29,7 @@ PendingMergeRequestMetric >> calculate [ { #category : #accessing } PendingMergeRequestMetric >> description [ - ^ 'number of merge request opened during the period and left opened at the end of it' + ^ 'number of merge request opened during a period and left opened at the end of it' ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/SelfMergedUnderAMinuteMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/SelfMergedUnderAMinuteMergeRequestMetric.class.st index 2f873d9..774ca86 100644 --- a/src/GitLabHealth-Model-Analysis/SelfMergedUnderAMinuteMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/SelfMergedUnderAMinuteMergeRequestMetric.class.st @@ -46,7 +46,7 @@ SelfMergedUnderAMinuteMergeRequestMetric >> calculate [ { #category : #accessing } SelfMergedUnderAMinuteMergeRequestMetric >> description [ - ^ 'number of merge requests merged without review' + ^ 'number of merge requests merged by its author under a minute after creation' ] { #category : #loading } @@ -61,5 +61,5 @@ SelfMergedUnderAMinuteMergeRequestMetric >> load [ { #category : #accessing } SelfMergedUnderAMinuteMergeRequestMetric >> name [ - ^ 'mergeRequestMergedWithoutReview' + ^ 'SelfMergedUnderAMinuteMergeRequest' ] diff --git a/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st b/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st index 1b2dcf6..522f3e4 100644 --- a/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st @@ -49,9 +49,3 @@ TimeBetweenCommitMetric >> description [ ^ 'average time between commits (in seconds)' ] - -{ #category : #accessing } -TimeBetweenCommitMetric >> name [ - - ^ 'timeBetweenCommit' -] diff --git a/src/GitLabHealth-Model-Analysis/UserCommitsMetric.class.st b/src/GitLabHealth-Model-Analysis/UserCommitsMetric.class.st index c4fe087..645aadb 100644 --- a/src/GitLabHealth-Model-Analysis/UserCommitsMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserCommitsMetric.class.st @@ -27,5 +27,5 @@ UserCommitsMetric >> load [ { #category : #accessing } UserCommitsMetric >> name [ - ^ self subclassResponsibility + ^ self class name asString ] From 9d4695b3c386863ea954a49786ddc7ae8e0e13ce Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Fri, 13 Sep 2024 15:01:52 +0200 Subject: [PATCH 102/154] fix metric definitions and implementation for MR --- .../MergedMergeRequestMetricTest.class.st | 116 +++++++++++++++++- .../ClosedTicketsMetric.class.st | 2 +- .../GitMetricExporter.class.st | 6 - .../MergedMergeRequestMetric.class.st | 14 ++- .../OpenedMergeRequestMetric.class.st | 6 + .../PendingMergeRequestMetric.class.st | 6 + .../TimeBetweenCommitMetric.class.st | 4 +- .../UserMergeRequestMetric.class.st | 2 +- .../UserMetric.class.st | 29 ++++- 9 files changed, 166 insertions(+), 19 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis-Tests/MergedMergeRequestMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/MergedMergeRequestMetricTest.class.st index 10b5169..45e5fc0 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/MergedMergeRequestMetricTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/MergedMergeRequestMetricTest.class.st @@ -20,6 +20,7 @@ MergedMergeRequestMetricTest >> testCalculate [ glhImporter := GLPHImporterMock new. glhImporter mergeRequests: { (GLPHEMergeRequest new author: user; + merge_user: user; created_at: '09-05-2024'; merged_at: '09-05-2024') }. @@ -54,11 +55,14 @@ MergedMergeRequestMetricTest >> testCalculate1MRInPeriod1Outside [ "open and merge during the same week" (GLPHEMergeRequest new author: user; + merge_user: user; created_at: '09-05-2024'; - merged_at: '09-05-2024') + merged_at: '09-05-2024'). + "open but merged anotherWeek" - .(GLPHEMergeRequest new + (GLPHEMergeRequest new author: user; + merge_user: user; created_at: '09-05-2024'; merged_at: '09-10-2024')}. @@ -88,14 +92,17 @@ MergedMergeRequestMetricTest >> testCalculate1MROpenedButNotMerged [ { (GLHProject new repository: GLHRepository new) }. glhImporter := GLPHImporterMock new. - glhImporter mergeRequests: { (GLPHEMergeRequest new + glhImporter mergeRequests: { + (GLPHEMergeRequest new author: user; + merge_user: user; created_at: '09-05-2024'; - merged_at: '09-05-2024') - .(GLPHEMergeRequest new + merged_at: '09-05-2024'). + (GLPHEMergeRequest new author: user; created_at: '09-05-2024'; - merged_at: nil)}. + merged_at: nil) + }. mergedMergeRequest := MergedMergeRequestMetric new @@ -112,6 +119,103 @@ MergedMergeRequestMetricTest >> testCalculate1MROpenedButNotMerged [ self assert: result equals: 1 ] +{ #category : #tests } +MergedMergeRequestMetricTest >> testCalculate2MROneForEachUser [ + + | result glhImporter user1 mergedMergeRequest user2 | + "Given" + user1 := GLHUser new + name: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + user2 := GLHUser new + name: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { (GLPHEMergeRequest new + author: user1; + title: 'MR1'; + created_at: '09-05-2024'; + merge_user: user1; + merged_at: '09-05-2024') + .(GLPHEMergeRequest new + author: user2; + title: 'MR2'; + created_at: '09-05-2024'; + merge_user: user2; + merged_at: '09-06-2024' + )}. + + + mergedMergeRequest := MergedMergeRequestMetric new + user: user1; + glhImporter: glhImporter; + setPeriodSince: '09-01-2024' + until: '09-07-2024'; + over: Week. + + "When" + result := mergedMergeRequest calculate. + + "Then" + self assert: result equals: 2 +] + +{ #category : #tests } +MergedMergeRequestMetricTest >> testCalculate3MROpenByOther [ + + | result glhImporter user1 mergedMergeRequest user2 | + "Given" + user1 := GLHUser new + name: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + user2 := GLHUser new + name: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { (GLPHEMergeRequest new + author: user2; + title: 'MR1'; + created_at: '09-05-2024'; + merge_user: user1; + merged_at: '09-05-2024'). + (GLPHEMergeRequest new + author: user2; + title: 'MR2'; + created_at: '09-05-2024'; + merge_user: user1; + merged_at: '09-06-2024' + ). + (GLPHEMergeRequest new + author: user2; + title: 'MR3'; + created_at: '09-05-2024'; + merge_user: user1; + merged_at: '09-06-2024' + )}. + + + mergedMergeRequest := MergedMergeRequestMetric new + user: user1; + glhImporter: glhImporter; + setPeriodSince: '09-01-2024' + until: '09-07-2024'; + over: Week. + + "When" + result := mergedMergeRequest calculate. + + "Then" + self assert: result equals: 3 +] + { #category : #tests } MergedMergeRequestMetricTest >> testCalculateNoMergeRequests [ diff --git a/src/GitLabHealth-Model-Analysis/ClosedTicketsMetric.class.st b/src/GitLabHealth-Model-Analysis/ClosedTicketsMetric.class.st index 4da2be6..a368fd8 100644 --- a/src/GitLabHealth-Model-Analysis/ClosedTicketsMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/ClosedTicketsMetric.class.st @@ -26,7 +26,7 @@ ClosedTicketsMetric >> calculate [ { #category : #accessing } ClosedTicketsMetric >> description [ - ^ 'number of merge request with jira ticket closed' + ^ 'number of closed merge request associated with a jira ticket' ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index c8efee8..c1cd7d6 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -255,9 +255,6 @@ GitMetricExporter >> exportProjectAnalysesInCSV [ file := self constructFilePath: groupOver. file writeStreamDo: [ :aStream | - aStream - << 'sep=,'; - << OSPlatform current lineEnding. exportBrowserModel writeCSVOn: aStream ] ] ] @@ -301,9 +298,6 @@ GitMetricExporter >> exportUserAnalysesInCSV [ file := self constructFilePath: groupOver. file writeStreamDo: [ :aStream | - aStream - << 'sep=,'; - << OSPlatform current lineEnding. exportBrowserModel writeCSVOn: aStream ] ] ] diff --git a/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st index 2547b0a..5494e71 100644 --- a/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st @@ -9,11 +9,13 @@ MergedMergeRequestMetric >> calculate [ | groupedByDate userMergedMergeRequests dateOver | userMergeRequests ifNil: [ self load ]. + groupedByDate := self setupGroupedDate. userMergedMergeRequests := userMergeRequests select: [ :userMergeRequest | - userMergeRequest merged_at isNotNil ]. + userMergeRequest merge_user isNotNil + and: [ userMergeRequest merge_user id = user id ] ]. userMergedMergeRequests do: [ :userMergeRequest | "here we look at the specific date of its merged" @@ -29,7 +31,15 @@ MergedMergeRequestMetric >> calculate [ { #category : #accessing } MergedMergeRequestMetric >> description [ - ^ 'number of merged merge request' + ^ 'number of merge request merged by this user' +] + +{ #category : #loading } +MergedMergeRequestMetric >> load [ + userMergeRequests := self + loadMergeRequestsSince: + (period at: #since) + until: (period at: #until) ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st index 2e1c4b2..e2f153a 100644 --- a/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st @@ -30,6 +30,12 @@ OpenedMergeRequestMetric >> description [ ^'number of opened merge request' ] +{ #category : #loading } +OpenedMergeRequestMetric >> load [ + userMergeRequests := self loadMergeRequestsOfUser: user since: (period at: #since) + until: (period at: #until). +] + { #category : #accessing } OpenedMergeRequestMetric >> name [ diff --git a/src/GitLabHealth-Model-Analysis/PendingMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/PendingMergeRequestMetric.class.st index 185e7c5..bd020d4 100644 --- a/src/GitLabHealth-Model-Analysis/PendingMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/PendingMergeRequestMetric.class.st @@ -32,6 +32,12 @@ PendingMergeRequestMetric >> description [ ^ 'number of merge request opened during a period and left opened at the end of it' ] +{ #category : #loading } +PendingMergeRequestMetric >> load [ + userMergeRequests := self loadMergeRequestsOfUser: user since: (period at: #since) + until: (period at: #until). +] + { #category : #accessing } PendingMergeRequestMetric >> name [ ^'pendingMergeRequest' diff --git a/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st b/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st index 522f3e4..5af9688 100644 --- a/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/TimeBetweenCommitMetric.class.st @@ -39,9 +39,9 @@ TimeBetweenCommitMetric >> calculate [ average := groupedByDate ifEmpty: [ nil ] - ifNotEmpty: [ groupedByDate average ]. + ifNotEmpty: [ groupedByDate average asFloat ]. - ^ average + ^ average ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/UserMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/UserMergeRequestMetric.class.st index c9f94e9..f5d6bab 100644 --- a/src/GitLabHealth-Model-Analysis/UserMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserMergeRequestMetric.class.st @@ -27,5 +27,5 @@ UserMergeRequestMetric >> load [ { #category : #accessing } UserMergeRequestMetric >> name [ - ^ self subclassResponsibility + ^ self class name asString ] diff --git a/src/GitLabHealth-Model-Analysis/UserMetric.class.st b/src/GitLabHealth-Model-Analysis/UserMetric.class.st index d7f517b..90cbdbd 100644 --- a/src/GitLabHealth-Model-Analysis/UserMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserMetric.class.st @@ -121,6 +121,33 @@ UserMetric >> loadCompleteMergeRequestsSince: since until: until [ ^ mergeRequests ] +{ #category : #loading } +UserMetric >> loadMergeRequestsOfUser: anUser since: since until: until [ + + | cacheSymbol mergeRequests | + glhImporter withCommitDiffs: false. + cacheSymbol := self + cacheSymbolFor: GLPHEMergeRequest + since: since + until: until. + + mergeRequests := anUser contributedProjects collect: [ :project | + | mr | + project cacheAt: cacheSymbol ifAbsentPut: [ + mr := glhImporter + importMergeRequests: project + since: since + until: until. + mr ] ]. + + mergeRequests := mergeRequests flattened. + glhImporter withCommitDiffs: true. + + mergeRequests do: [ :mr | glhImporter importMergeResquestAuthor: mr ]. + + ^ mergeRequests select: [ :mergeRequest | mergeRequest author = anUser ] +] + { #category : #loading } UserMetric >> loadMergeRequestsSince: since until: until [ @@ -145,7 +172,7 @@ UserMetric >> loadMergeRequestsSince: since until: until [ mergeRequests do: [ :mr | glhImporter importMergeResquestAuthor: mr ]. - ^ mergeRequests select: [ :mergeRequest | mergeRequest author = user ] + ^ mergeRequests "select: [ :mergeRequest | mergeRequest author = user ]" ] { #category : #loading } From 8ebde174d627df22cf21ef91635086e5c5ad5f80 Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Fri, 13 Sep 2024 15:36:15 +0200 Subject: [PATCH 103/154] add new generic object to represent parameter of importers --- .../BaselineOfGitLabHealth.class.st | 9 +- .../GHAPIPipelineOverview.class.st | 15 +- .../GHApi.class.st | 33 ++-- .../GHApiFile.class.st | 15 +- .../GHModelImporter.class.st | 53 ++++--- src/GitHubHealth-Model-Importer/package.st | 2 +- .../GLHApi.class.st | 85 +++++----- .../GLHApiFile.class.st | 15 +- .../GLHModelImporter.class.st | 149 +++++++++--------- src/GitLabHealth-Model-Importer/package.st | 2 +- .../RSCommit.class.st | 53 ++++--- .../RSCommitDiff.class.st | 25 +-- src/GitLabHealth-Visualization/package.st | 2 +- 13 files changed, 236 insertions(+), 222 deletions(-) diff --git a/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st b/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st index 97122f3..831dcd2 100644 --- a/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st +++ b/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st @@ -46,7 +46,12 @@ BaselineOfGitLabHealth >> defineGroups: spec [ { #category : 'baselines' } BaselineOfGitLabHealth >> definePackages: spec [ + "generic" + spec package: 'GitProjectHealth-Model-Importer'. + + + "gitlab" spec package: 'GitLabHealth-Model'; package: 'GitLabHealth-Model-Extension' @@ -58,9 +63,9 @@ BaselineOfGitLabHealth >> definePackages: spec [ with: [ spec requires: #( 'GitLabHealth-Model-Visualization' ) ]; package: 'GitLabHealth-Model-Visualization'; package: 'GitLabHealth-Model-Importer' - with: [ spec requires: #( 'NeoJSON' 'MoreLogger' ) ]; + with: [ spec requires: #( 'NeoJSON' 'MoreLogger' 'GitProjectHealth-Model-Importer' ) ]; package: 'GitHubHealth-Model-Importer' - with: [ spec requires: #( 'NeoJSON' 'MoreLogger' ) ]; + with: [ spec requires: #( 'NeoJSON' 'MoreLogger' 'GitProjectHealth-Model-Importer' ) ]; package: 'GitLabHealth-Model-Importer-Tests' with: [ spec requires: #( 'GitLabHealth-Model-Importer' 'GitHubHealth-Model-Importer' ) ]. diff --git a/src/GitHubHealth-Model-Importer/GHAPIPipelineOverview.class.st b/src/GitHubHealth-Model-Importer/GHAPIPipelineOverview.class.st index 684778d..adc203a 100644 --- a/src/GitHubHealth-Model-Importer/GHAPIPipelineOverview.class.st +++ b/src/GitHubHealth-Model-Importer/GHAPIPipelineOverview.class.st @@ -1,32 +1,33 @@ Class { - #name : #GHAPIPipelineOverview, - #superclass : #Object, + #name : 'GHAPIPipelineOverview', + #superclass : 'Object', #instVars : [ 'total_count', 'workflow_runs' ], - #category : #'GitHubHealth-Model-Importer' + #category : 'GitHubHealth-Model-Importer', + #package : 'GitHubHealth-Model-Importer' } -{ #category : #accessing } +{ #category : 'accessing' } GHAPIPipelineOverview >> total_count [ ^ total_count ] -{ #category : #accessing } +{ #category : 'accessing' } GHAPIPipelineOverview >> total_count: anObject [ total_count := anObject ] -{ #category : #accessing } +{ #category : 'accessing' } GHAPIPipelineOverview >> workflow_runs [ ^ workflow_runs ] -{ #category : #accessing } +{ #category : 'accessing' } GHAPIPipelineOverview >> workflow_runs: anObject [ workflow_runs := anObject diff --git a/src/GitHubHealth-Model-Importer/GHApi.class.st b/src/GitHubHealth-Model-Importer/GHApi.class.st index 97b80df..3de5712 100644 --- a/src/GitHubHealth-Model-Importer/GHApi.class.st +++ b/src/GitHubHealth-Model-Importer/GHApi.class.st @@ -1,17 +1,18 @@ " -You can use me to extract query GitHub +You can use me to extract query [GitHub REST Api](https://docs.github.com/en/rest) " Class { - #name : #GHApi, - #superclass : #Object, + #name : 'GHApi', + #superclass : 'Object', #instVars : [ 'baseAPIUrl', 'client' ], - #category : #'GitHubHealth-Model-Importer' + #category : 'GitHubHealth-Model-Importer', + #package : 'GitHubHealth-Model-Importer' } -{ #category : #api } +{ #category : 'api' } GHApi >> actionsRunOfRepo: aRepoName ofOrganization: anOrganizationName [ ^ self client get: @@ -19,19 +20,19 @@ GHApi >> actionsRunOfRepo: aRepoName ofOrganization: anOrganizationName [ , '/actions/runs' ] -{ #category : #accessing } +{ #category : 'accessing' } GHApi >> baseAPIUrl [ ^ baseAPIUrl ] -{ #category : #accessing } +{ #category : 'accessing' } GHApi >> baseAPIUrl: anObject [ baseAPIUrl := anObject ] -{ #category : #api } +{ #category : 'api' } GHApi >> branchesOfRepo: aRepoName ofOrganization: anOrganizationName [ self client url: @@ -40,19 +41,19 @@ GHApi >> branchesOfRepo: aRepoName ofOrganization: anOrganizationName [ ^ self client get ] -{ #category : #accessing } +{ #category : 'accessing' } GHApi >> client [ ^ client ] -{ #category : #accessing } +{ #category : 'accessing' } GHApi >> client: anObject [ client := anObject ] -{ #category : #api } +{ #category : 'api' } GHApi >> contentsOfRepo: aRepoName ofOrganization: anOrganizationName inBranch: aBranchRef withPath: aPath [ self client url: @@ -62,7 +63,7 @@ GHApi >> contentsOfRepo: aRepoName ofOrganization: anOrganizationName inBranch: ^ self client get ] -{ #category : #initialization } +{ #category : 'initialization' } GHApi >> initialize [ self baseAPIUrl: 'https://api.github.com'. @@ -71,25 +72,25 @@ GHApi >> initialize [ yourself) ] -{ #category : #api } +{ #category : 'api' } GHApi >> organization: anOrganizationName [ ^ self client get: self baseAPIUrl , '/orgs/' , anOrganizationName ] -{ #category : #accessing } +{ #category : 'accessing' } GHApi >> privateToken [ ^ self client request headers at: #'Authorization' ] -{ #category : #accessing } +{ #category : 'accessing' } GHApi >> privateToken: anObject [ self client headerAt: #'Authorization' add: ('token ', anObject) ] -{ #category : #api } +{ #category : 'api' } GHApi >> reposOfOrganization: anOrganizationName [ ^ self client get: self baseAPIUrl , '/orgs/' , anOrganizationName, '/repos' diff --git a/src/GitHubHealth-Model-Importer/GHApiFile.class.st b/src/GitHubHealth-Model-Importer/GHApiFile.class.st index ba45a04..e8c1128 100644 --- a/src/GitHubHealth-Model-Importer/GHApiFile.class.st +++ b/src/GitHubHealth-Model-Importer/GHApiFile.class.st @@ -1,32 +1,33 @@ Class { - #name : #GHApiFile, - #superclass : #Object, + #name : 'GHApiFile', + #superclass : 'Object', #instVars : [ 'name', 'type' ], - #category : #'GitHubHealth-Model-Importer' + #category : 'GitHubHealth-Model-Importer', + #package : 'GitHubHealth-Model-Importer' } -{ #category : #accessing } +{ #category : 'accessing' } GHApiFile >> name [ ^ name ] -{ #category : #accessing } +{ #category : 'accessing' } GHApiFile >> name: anObject [ name := anObject ] -{ #category : #accessing } +{ #category : 'accessing' } GHApiFile >> type [ ^ type ] -{ #category : #accessing } +{ #category : 'accessing' } GHApiFile >> type: anObject [ type := anObject diff --git a/src/GitHubHealth-Model-Importer/GHModelImporter.class.st b/src/GitHubHealth-Model-Importer/GHModelImporter.class.st index 2372d61..3ac4417 100644 --- a/src/GitHubHealth-Model-Importer/GHModelImporter.class.st +++ b/src/GitHubHealth-Model-Importer/GHModelImporter.class.st @@ -1,39 +1,40 @@ Class { - #name : #GHModelImporter, - #superclass : #Object, + #name : 'GHModelImporter', + #superclass : 'GPModelImporter', #instVars : [ 'api', 'glhModel', 'withFiles' ], - #category : #'GitHubHealth-Model-Importer' + #category : 'GitHubHealth-Model-Importer', + #package : 'GitHubHealth-Model-Importer' } -{ #category : #accessing } +{ #category : 'accessing' } GHModelImporter >> api [ ^ api ] -{ #category : #accessing } +{ #category : 'accessing' } GHModelImporter >> api: anObject [ api := anObject ] -{ #category : #accessing } +{ #category : 'accessing' } GHModelImporter >> beWithFiles [ withFiles := true ] -{ #category : #accessing } +{ #category : 'accessing' } GHModelImporter >> beWithoutFiles [ withFiles := false ] -{ #category : #private } +{ #category : 'private' } GHModelImporter >> convertApiFileAsFile: aAPIFile [ aAPIFile type = 'dir' ifTrue: [ @@ -45,19 +46,19 @@ GHModelImporter >> convertApiFileAsFile: aAPIFile [ yourself ] -{ #category : #accessing } +{ #category : 'accessing' } GHModelImporter >> glhModel [ ^ glhModel ] -{ #category : #accessing } +{ #category : 'accessing' } GHModelImporter >> glhModel: anObject [ glhModel := anObject ] -{ #category : #api } +{ #category : 'api' } GHModelImporter >> importBranchesOf: project [ "add the pipeline (actions runs) in the project" @@ -76,7 +77,7 @@ GHModelImporter >> importBranchesOf: project [ self withFiles ifTrue: [ self importFilesOfBranch: branch ] ] ] -{ #category : #api } +{ #category : 'api' } GHModelImporter >> importDirectoryFiles: aDirectoryFile OfBranch: aBranch [ | result files apiFiles | @@ -98,7 +99,7 @@ GHModelImporter >> importDirectoryFiles: aDirectoryFile OfBranch: aBranch [ self importDirectoryFiles: file OfBranch: aBranch ] ] -{ #category : #api } +{ #category : 'api' } GHModelImporter >> importFilesOfBranch: aBranch [ | result files apiFiles | @@ -119,7 +120,7 @@ GHModelImporter >> importFilesOfBranch: aBranch [ self importDirectoryFiles: file OfBranch: aBranch ] ] -{ #category : #api } +{ #category : 'api' } GHModelImporter >> importGroup: aGroupName [ | result groupResult | @@ -130,7 +131,7 @@ GHModelImporter >> importGroup: aGroupName [ ^ groupResult ] -{ #category : #api } +{ #category : 'api' } GHModelImporter >> importPipelinesOf: project [ "add the pipeline (actions runs) in the project" @@ -144,7 +145,7 @@ GHModelImporter >> importPipelinesOf: project [ project addPipeline: pipeline ] ] -{ #category : #api } +{ #category : 'api' } GHModelImporter >> importRepositoriesOfGroup: groupResult [ | reposResult | @@ -158,14 +159,14 @@ GHModelImporter >> importRepositoriesOfGroup: groupResult [ ^ groupResult ] -{ #category : #initialization } +{ #category : 'initialization' } GHModelImporter >> initialize [ super initialize. self api: GHApi new. withFiles := false ] -{ #category : #private } +{ #category : 'private' } GHModelImporter >> parseArrayOfProject: arrayOfProjects [ | reader | @@ -184,7 +185,7 @@ GHModelImporter >> parseArrayOfProject: arrayOfProjects [ ^ reader nextAs: #ArrayOfProjects ] -{ #category : #private } +{ #category : 'private' } GHModelImporter >> parseBranchesResult: arrayOfBranch [ | reader | @@ -197,7 +198,7 @@ GHModelImporter >> parseBranchesResult: arrayOfBranch [ ^ reader nextAs: #ArrayOfBranch ] -{ #category : #private } +{ #category : 'private' } GHModelImporter >> parseFileTreeResult: aResult [ | reader | @@ -210,7 +211,7 @@ GHModelImporter >> parseFileTreeResult: aResult [ ^ reader nextAs: #ArrayOfFile ] -{ #category : #private } +{ #category : 'private' } GHModelImporter >> parseGroupResult: aResult [ | reader | @@ -223,7 +224,7 @@ GHModelImporter >> parseGroupResult: aResult [ ^ reader nextAs: GLHGroup ] -{ #category : #private } +{ #category : 'private' } GHModelImporter >> parsePipelinesResult: pipelineOverview [ | reader | @@ -245,23 +246,23 @@ GHModelImporter >> parsePipelinesResult: pipelineOverview [ ^ reader nextAs: GHAPIPipelineOverview ] -{ #category : #api } +{ #category : 'api' } GHModelImporter >> privateToken [ ^ self api privateToken ] -{ #category : #api } +{ #category : 'api' } GHModelImporter >> privateToken: aTokenString [ ^ self api privateToken: aTokenString ] -{ #category : #accessing } +{ #category : 'accessing' } GHModelImporter >> withFiles [ ^ withFiles ] -{ #category : #accessing } +{ #category : 'accessing' } GHModelImporter >> withFiles: anObject [ withFiles := anObject diff --git a/src/GitHubHealth-Model-Importer/package.st b/src/GitHubHealth-Model-Importer/package.st index 2fce379..2cae246 100644 --- a/src/GitHubHealth-Model-Importer/package.st +++ b/src/GitHubHealth-Model-Importer/package.st @@ -1 +1 @@ -Package { #name : #'GitHubHealth-Model-Importer' } +Package { #name : 'GitHubHealth-Model-Importer' } diff --git a/src/GitLabHealth-Model-Importer/GLHApi.class.st b/src/GitLabHealth-Model-Importer/GLHApi.class.st index d12f853..1a2d09a 100644 --- a/src/GitLabHealth-Model-Importer/GLHApi.class.st +++ b/src/GitLabHealth-Model-Importer/GLHApi.class.st @@ -2,8 +2,8 @@ This is the API. I do not perform any kinds of JSON transformation " Class { - #name : #GLHApi, - #superclass : #Object, + #name : 'GLHApi', + #superclass : 'Object', #instVars : [ 'baseAPIUrl', 'client' @@ -11,28 +11,29 @@ Class { #classVars : [ 'currentAPI' ], - #category : 'GitLabHealth-Model-Importer' + #category : 'GitLabHealth-Model-Importer', + #package : 'GitLabHealth-Model-Importer' } -{ #category : #accessing } +{ #category : 'accessing' } GLHApi class >> current [ ^ currentAPI ] -{ #category : #accessing } +{ #category : 'accessing' } GLHApi >> baseAPIUrl [ ^ baseAPIUrl ] -{ #category : #accessing } +{ #category : 'accessing' } GLHApi >> baseAPIUrl: anObject [ baseAPIUrl := anObject ] -{ #category : #'as yet unclassified' } +{ #category : 'as yet unclassified' } GLHApi >> blamesOfProject: aProjectId forFile: filePath onBranch: branchRef onStartRange: start toEndRange: end [ self client path: @@ -46,7 +47,7 @@ GLHApi >> blamesOfProject: aProjectId forFile: filePath onBranch: branchRef onSt ^ self client get ] -{ #category : #'as yet unclassified' } +{ #category : 'as yet unclassified' } GLHApi >> blamesOfProject: aProjectId forFile: filePath onStartRange: start toEndRange: end [ self client path: @@ -59,7 +60,7 @@ GLHApi >> blamesOfProject: aProjectId forFile: filePath onStartRange: start toEn ^ self client get ] -{ #category : #api } +{ #category : 'api' } GLHApi >> branchesOfRepository: aProjectID [ ^ self client get: @@ -67,19 +68,19 @@ GLHApi >> branchesOfRepository: aProjectID [ , '/repository/branches' ] -{ #category : #accessing } +{ #category : 'accessing' } GLHApi >> client [ ^ client ] -{ #category : #accessing } +{ #category : 'accessing' } GLHApi >> client: anObject [ client := anObject ] -{ #category : #'api - commits' } +{ #category : 'api - commits' } GLHApi >> commit: commitSHA ofProject: aProjectId [ self client path: (String streamContents: [ :str | @@ -94,7 +95,7 @@ GLHApi >> commit: commitSHA ofProject: aProjectId [ ^ self client get ] -{ #category : #'api - commits' } +{ #category : 'api - commits' } GLHApi >> commit: commitSHA ofProject: aProjectId withStat: stats [ self client path: (String streamContents: [ :str | @@ -112,7 +113,7 @@ GLHApi >> commit: commitSHA ofProject: aProjectId withStat: stats [ ^ self client get ] -{ #category : #'api - commits' } +{ #category : 'api - commits' } GLHApi >> commitDiff: commitSHA ofProject: aProjectId unidiff: unidiff [ self client path: (String streamContents: [ :str | @@ -131,7 +132,7 @@ GLHApi >> commitDiff: commitSHA ofProject: aProjectId unidiff: unidiff [ ^ self client get ] -{ #category : #'api - commits' } +{ #category : 'api - commits' } GLHApi >> commitsOfProject: aProjectId [ ^ self @@ -150,7 +151,7 @@ GLHApi >> commitsOfProject: aProjectId [ page: nil ] -{ #category : #commits } +{ #category : 'commits' } GLHApi >> commitsOfProject: anInteger forRefName: refName since: since [ ^ self commitsOfProject: anInteger @@ -168,7 +169,7 @@ GLHApi >> commitsOfProject: anInteger forRefName: refName since: since [ page: nil. ] -{ #category : #'api - commits' } +{ #category : 'api - commits' } GLHApi >> commitsOfProject: aProjectId forRefName: refName since: since until: until path: aPath author: author all: aAllBoolean with_stats: withStateBoolean firstParent: firstParent order: orderString trailers: trailers perPage: aPerPageNumber page: aPageNumber [ "https://docs.gitlab.com/ee/api/commits.html#list-repository-commits" @@ -194,7 +195,7 @@ GLHApi >> commitsOfProject: aProjectId forRefName: refName since: since until: u ^ self client get ] -{ #category : #commits } +{ #category : 'commits' } GLHApi >> commitsOfUser: aUserName inProject: anInteger [ | name | @@ -221,7 +222,7 @@ GLHApi >> commitsOfUser: aUserName inProject: anInteger [ ^ client get. " ] -{ #category : #commits } +{ #category : 'commits' } GLHApi >> commitsOfUser: aUserName inProject: anInteger since: since until: until [ | name | @@ -248,7 +249,7 @@ GLHApi >> commitsOfUser: aUserName inProject: anInteger since: since until: unti ^ client get. " ] -{ #category : #'api - repositories' } +{ #category : 'api - repositories' } GLHApi >> compareProject: aProjectID from: fromSha to: toSha fromProject: fromProjectID straight: straight unidiff: unidiff [ self client path: @@ -266,7 +267,7 @@ GLHApi >> compareProject: aProjectID from: fromSha to: toSha fromProject: fromPr ^ self client get ] -{ #category : #'api - branches' } +{ #category : 'api - branches' } GLHApi >> createBranch: newBranchName forProject: aProjectID fromBranch: refBranchName [ self client url: @@ -277,7 +278,7 @@ GLHApi >> createBranch: newBranchName forProject: aProjectID fromBranch: refBran ^ self client post ] -{ #category : #'api - branches' } +{ #category : 'api - branches' } GLHApi >> deleteBranch: branchName forProject: aProjectID [ self client url: @@ -286,7 +287,7 @@ GLHApi >> deleteBranch: branchName forProject: aProjectID [ ^ self client delete ] -{ #category : #'api - projects' } +{ #category : 'api - projects' } GLHApi >> editProject: aProjectID changeDefaultBranchTo: refBranchName [ self client url: @@ -295,7 +296,7 @@ GLHApi >> editProject: aProjectID changeDefaultBranchTo: refBranchName [ ^ self client put ] -{ #category : #'api - projects' } +{ #category : 'api - projects' } GLHApi >> editProject: aProjectID usingDictionary: aDictionaryOfNewParam [ self client url: @@ -306,7 +307,7 @@ GLHApi >> editProject: aProjectID usingDictionary: aDictionaryOfNewParam [ ^ self client put ] -{ #category : #'api - repository files' } +{ #category : 'api - repository files' } GLHApi >> getFileBlameForProject: aProjectId andFilePath: aFilePath inRef: aRef fromLine: rangeStart toLine: rangeEnd [ "filePath is converted here. So give a path such as ""path/to/file.md""" @@ -323,13 +324,13 @@ GLHApi >> getFileBlameForProject: aProjectId andFilePath: aFilePath inRef: aRef ^ self client get ] -{ #category : #api } +{ #category : 'api' } GLHApi >> group: aGroupID [ ^ self client get: self baseAPIUrl , '/groups/' , aGroupID printString ] -{ #category : #projects } +{ #category : 'projects' } GLHApi >> importProjects: first after: after [ | request query variables body response | @@ -371,7 +372,7 @@ GLHApi >> importProjects: first after: after [ ^ response contents ] -{ #category : #initialization } +{ #category : 'initialization' } GLHApi >> initialize [ self client: (ZnClient new @@ -380,7 +381,7 @@ GLHApi >> initialize [ currentAPI:= self ] -{ #category : #'api - jobs' } +{ #category : 'api - jobs' } GLHApi >> jobsOfProject: aProjectID ofPipelines: aPipelineID [ ^ self client get: @@ -388,7 +389,7 @@ GLHApi >> jobsOfProject: aProjectID ofPipelines: aPipelineID [ , '/pipelines/' , aPipelineID printString , '/jobs' ] -{ #category : #'api - groups' } +{ #category : 'api - groups' } GLHApi >> listGroupsWithTopLevelOnly: topLevelOnly page: aPageNumber [ "https://docs.gitlab.com/ee/api/groups.html#list-groups" @@ -400,24 +401,24 @@ GLHApi >> listGroupsWithTopLevelOnly: topLevelOnly page: aPageNumber [ ^ self client get ] -{ #category : #api } +{ #category : 'api' } GLHApi >> pipelinesOfProject: aProjectID [ ^ self client get: self baseAPIUrl , '/projects/' , aProjectID printString, '/pipelines' ] -{ #category : #accessing } +{ #category : 'accessing' } GLHApi >> privateToken [ ^ self client request headers at: #'PRIVATE-TOKEN' ] -{ #category : #accessing } +{ #category : 'accessing' } GLHApi >> privateToken: anObject [ self client headerAt: #'PRIVATE-TOKEN' add: anObject ] -{ #category : #accessing } +{ #category : 'accessing' } GLHApi >> projects [ "use GraphQL" @@ -446,13 +447,13 @@ GLHApi >> projects [ ^ projectIds ] -{ #category : #projects } +{ #category : 'projects' } GLHApi >> projects: aPerPageNumber page: aPageNumber [ self projects: aPerPageNumber since: nil page: aPageNumber ] -{ #category : #projects } +{ #category : 'projects' } GLHApi >> projects: aPerPageNumber since: since page: aPageNumber [ self client path: self baseAPIUrl , '/projects/'. @@ -464,7 +465,7 @@ GLHApi >> projects: aPerPageNumber since: since page: aPageNumber [ ^ self client get ] -{ #category : #private } +{ #category : 'private' } GLHApi >> resetClient [ | token | @@ -474,14 +475,14 @@ GLHApi >> resetClient [ self client accept: ZnMimeType applicationJson ] -{ #category : #'api - groups' } +{ #category : 'api - groups' } GLHApi >> subgroupsOfGroup: aGroupID [ ^ self client get: self baseAPIUrl , '/groups/' , aGroupID printString , '/subgroups' ] -{ #category : #'api - groups' } +{ #category : 'api - groups' } GLHApi >> subgroupsOfGroup: aGroupID page: aPageNumber [ self client url: @@ -490,7 +491,7 @@ GLHApi >> subgroupsOfGroup: aGroupID page: aPageNumber [ ^ self client get ] -{ #category : #api } +{ #category : 'api' } GLHApi >> treeOfRepository: aProjectID ofBranch: aBranchRef andPath: aPath [ | result | @@ -504,13 +505,13 @@ GLHApi >> treeOfRepository: aProjectID ofBranch: aBranchRef andPath: aPath [ ^ result ] -{ #category : #api } +{ #category : 'api' } GLHApi >> user: aUserID [ ^ self client get: self baseAPIUrl , '/users/' , aUserID printString ] -{ #category : #api } +{ #category : 'api' } GLHApi >> userWithUsername: anUsername [ ^ self client get: self baseAPIUrl , '/users?username=' , anUsername diff --git a/src/GitLabHealth-Model-Importer/GLHApiFile.class.st b/src/GitLabHealth-Model-Importer/GLHApiFile.class.st index 2c0531f..355c042 100644 --- a/src/GitLabHealth-Model-Importer/GLHApiFile.class.st +++ b/src/GitLabHealth-Model-Importer/GLHApiFile.class.st @@ -1,32 +1,33 @@ Class { - #name : #GLHApiFile, - #superclass : #Object, + #name : 'GLHApiFile', + #superclass : 'Object', #instVars : [ 'name', 'type' ], - #category : 'GitLabHealth-Model-Importer' + #category : 'GitLabHealth-Model-Importer', + #package : 'GitLabHealth-Model-Importer' } -{ #category : #accessing } +{ #category : 'accessing' } GLHApiFile >> name [ ^ name ] -{ #category : #accessing } +{ #category : 'accessing' } GLHApiFile >> name: anObject [ name := anObject ] -{ #category : #accessing } +{ #category : 'accessing' } GLHApiFile >> type [ ^ type ] -{ #category : #accessing } +{ #category : 'accessing' } GLHApiFile >> type: anObject [ type := anObject diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index 1aa3c96..170c5f5 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -1,12 +1,11 @@ Class { - #name : #GLHModelImporter, - #superclass : #Object, + #name : 'GLHModelImporter', + #superclass : 'GPModelImporter', #instVars : [ 'glhModel', 'glhApi', 'withFiles', 'withCommitDiffs', - 'withCommitsSince', 'withInitialCommits', 'withInitialMergeRequest', 'generalReader' @@ -14,16 +13,17 @@ Class { #classVars : [ 'currentImporter' ], - #category : #'GitLabHealth-Model-Importer' + #category : 'GitLabHealth-Model-Importer', + #package : 'GitLabHealth-Model-Importer' } -{ #category : #accessing } +{ #category : 'accessing' } GLHModelImporter class >> current [ ^ currentImporter ] -{ #category : #'private - api' } +{ #category : 'private - api' } GLHModelImporter >> addCommits: commitsList toRepository: aProjectRepository [ "I take a list of GLHCommit. But some might have been parsed but are already on the model..." @@ -40,7 +40,7 @@ GLHModelImporter >> addCommits: commitsList toRepository: aProjectRepository [ ^ newlyFoundCommit ] -{ #category : #private } +{ #category : 'private' } GLHModelImporter >> addGroupResultToModel: groupResult [ |group| group := self glhModel add: groupResult unless: self blockOnIdEquality. @@ -50,43 +50,43 @@ GLHModelImporter >> addGroupResultToModel: groupResult [ ^ group ] -{ #category : #accessing } +{ #category : 'accessing' } GLHModelImporter >> beWithFiles [ withFiles := true ] -{ #category : #accessing } +{ #category : 'accessing' } GLHModelImporter >> beWithouFiles [ withFiles := false ] -{ #category : #'as yet unclassified' } +{ #category : 'as yet unclassified' } GLHModelImporter >> blockEqualityOn: aSymbol [ ^ [ :existing :new | (existing perform: aSymbol) = (new perform: aSymbol) ] ] -{ #category : #equality } +{ #category : 'equality' } GLHModelImporter >> blockForDiffEquality [ ^ [ :existing :new | existing diffString size = new diffString size and: [ existing diffString = new diffString ] ] ] -{ #category : #equality } +{ #category : 'equality' } GLHModelImporter >> blockOnIdEquality [ ^ [ :existing :new | existing id = new id ] ] -{ #category : #equality } +{ #category : 'equality' } GLHModelImporter >> blockOnNameEquality [ ^ self blockEqualityOn: #name ] -{ #category : #'private - api' } +{ #category : 'private - api' } GLHModelImporter >> completeImportProject: aGLHProject [ |importedProject| ('Complete import of project: ' , aGLHProject id printString) @@ -108,7 +108,7 @@ GLHModelImporter >> completeImportProject: aGLHProject [ ^ importedProject ] -{ #category : #'as yet unclassified' } +{ #category : 'as yet unclassified' } GLHModelImporter >> completeImportedCommit: aCommit [ ('completing commit: ' , aCommit short_id printString) recordInfo. @@ -123,7 +123,7 @@ GLHModelImporter >> completeImportedCommit: aCommit [ ^ aCommit ] -{ #category : #private } +{ #category : 'private' } GLHModelImporter >> configureReaderForCommit: reader [ reader for: GLHCommit do: [ :mapping | @@ -155,7 +155,7 @@ GLHModelImporter >> configureReaderForCommit: reader [ ] -{ #category : #'as yet unclassified' } +{ #category : 'as yet unclassified' } GLHModelImporter >> configureReaderForDiffs: reader [ reader for: GLHDiff do: [ :mapping | @@ -170,7 +170,7 @@ GLHModelImporter >> configureReaderForDiffs: reader [ ^ reader ] -{ #category : #private } +{ #category : 'private' } GLHModelImporter >> configureReaderForGroup: reader [ reader for: GLHGroup do: [ :mapping | @@ -187,7 +187,7 @@ GLHModelImporter >> configureReaderForGroup: reader [ customMappting listOfElementSchema: GLHGroup ] ] -{ #category : #private } +{ #category : 'private' } GLHModelImporter >> convertApiFileAsFile: aAPIFile [ aAPIFile type = 'tree' ifTrue: [ @@ -199,14 +199,14 @@ GLHModelImporter >> convertApiFileAsFile: aAPIFile [ yourself ] -{ #category : #'as yet unclassified' } +{ #category : 'as yet unclassified' } GLHModelImporter >> detectEntityType: aType overAttribut: aSelector equalTo: value [ ^ (self glhModel allWithType: aType) detect: [ :entity | (entity perform: aSelector) = value ] ifNone: [ nil ]. ] -{ #category : #'as yet unclassified' } +{ #category : 'as yet unclassified' } GLHModelImporter >> filterCommitChanges: aCollection [ ^ aCollection reject: [ :line | @@ -217,31 +217,31 @@ GLHModelImporter >> filterCommitChanges: aCollection [ trimmedLine beginsWith: '\ No newline at end of file' ] ] ] ] -{ #category : #accessing } +{ #category : 'accessing' } GLHModelImporter >> glhApi [ ^ glhApi ] -{ #category : #accessing } +{ #category : 'accessing' } GLHModelImporter >> glhApi: anObject [ glhApi := anObject ] -{ #category : #accessing } +{ #category : 'accessing' } GLHModelImporter >> glhModel [ ^ glhModel ] -{ #category : #accessing } +{ #category : 'accessing' } GLHModelImporter >> glhModel: anObject [ glhModel := anObject ] -{ #category : #api } +{ #category : 'api' } GLHModelImporter >> importAllGroups [ | page foundGroups newlyFoundGroups | @@ -260,7 +260,7 @@ GLHModelImporter >> importAllGroups [ ^ foundGroups ] -{ #category : #'private - api' } +{ #category : 'private - api' } GLHModelImporter >> importCommit: aCommitID ofProject: aGLHProject [ | result parsedResult | @@ -278,7 +278,7 @@ GLHModelImporter >> importCommit: aCommitID ofProject: aGLHProject [ ^ parsedResult ] -{ #category : #'as yet unclassified' } +{ #category : 'as yet unclassified' } GLHModelImporter >> importCommitOfProject: anProject withId: anID [ | commit result | @@ -305,7 +305,7 @@ GLHModelImporter >> importCommitOfProject: anProject withId: anID [ ^ commit ] -{ #category : #'private - api' } +{ #category : 'private - api' } GLHModelImporter >> importCommits: aGLHProject [ "limited to the last 20 commits" @@ -336,7 +336,7 @@ GLHModelImporter >> importCommits: aGLHProject [ ^ parsedResults. ] -{ #category : #'as yet unclassified' } +{ #category : 'as yet unclassified' } GLHModelImporter >> importCommitsFollowing: aCommit upToDays: aNumberOfDay [ "import the 'n' commits of a project starting from an initial 'aCommit' commit. Lazy import does not import the entities inside the model" @@ -351,7 +351,7 @@ GLHModelImporter >> importCommitsFollowing: aCommit upToDays: aNumberOfDay [ until: (date + aNumberOfDay day) ] -{ #category : #commit } +{ #category : 'commit' } GLHModelImporter >> importCommitsOProject: aProject since: fromDate until: toDate [ | newlyFoundCommit page foundCommit | @@ -390,7 +390,7 @@ GLHModelImporter >> importCommitsOProject: aProject since: fromDate until: toDat ^ self glhModel addAll: foundCommit unless: self blockOnIdEquality ] -{ #category : #api } +{ #category : 'api' } GLHModelImporter >> importCommitsOf: aGLHProject withStats: aBoolean until: toDate [ | newlyFoundCommit page | @@ -435,7 +435,7 @@ GLHModelImporter >> importCommitsOf: aGLHProject withStats: aBoolean until: toDa self importDiffOfCommit: commit ] ] ] -{ #category : #commit } +{ #category : 'commit' } GLHModelImporter >> importCommitsOfBranch: aGLHBranch forRefName: refName since: fromDate [ ^ self @@ -445,7 +445,7 @@ GLHModelImporter >> importCommitsOfBranch: aGLHBranch forRefName: refName since: until: nil ] -{ #category : #commit } +{ #category : 'commit' } GLHModelImporter >> importCommitsOfBranch: aGLHBranch forRefName: refName since: fromDate until: toDate [ | newlyFoundCommit page foundCommit| @@ -490,7 +490,7 @@ GLHModelImporter >> importCommitsOfBranch: aGLHBranch forRefName: refName since: ^ foundCommit ] -{ #category : #commit } +{ #category : 'commit' } GLHModelImporter >> importCommitsOfBranch: aGLHBranch forRefName: refName until: toDate [ ^ self @@ -500,7 +500,7 @@ GLHModelImporter >> importCommitsOfBranch: aGLHBranch forRefName: refName until: until: toDate ] -{ #category : #'as yet unclassified' } +{ #category : 'as yet unclassified' } GLHModelImporter >> importCreatorOfCommit: aCommit [ aCommit commitCreator ifNil: [ @@ -508,7 +508,7 @@ GLHModelImporter >> importCreatorOfCommit: aCommit [ (self importUserByUsername: aCommit author_name) ] ] -{ #category : #api } +{ #category : 'api' } GLHModelImporter >> importDiffOfCommit: aCommit [ | result diffsResult | @@ -526,7 +526,7 @@ GLHModelImporter >> importDiffOfCommit: aCommit [ ] -{ #category : #'private - api' } +{ #category : 'private - api' } GLHModelImporter >> importDirectoryFiles: aDirectoryFile OfBranch: aBranch [ | result files apiFiles | @@ -547,7 +547,7 @@ GLHModelImporter >> importDirectoryFiles: aDirectoryFile OfBranch: aBranch [ self importDirectoryFiles: file OfBranch: aBranch ] ] -{ #category : #'private - api' } +{ #category : 'private - api' } GLHModelImporter >> importFilesOfBranch: aBranch [ | result files apiFiles | @@ -567,7 +567,7 @@ GLHModelImporter >> importFilesOfBranch: aBranch [ self importDirectoryFiles: file OfBranch: aBranch ] ] -{ #category : #api } +{ #category : 'api' } GLHModelImporter >> importGroup: aGroupID [ | result groupResult | @@ -588,7 +588,7 @@ GLHModelImporter >> importGroup: aGroupID [ ^ groupResult ] -{ #category : #api } +{ #category : 'api' } GLHModelImporter >> importJobsOf: aPipeline [ | result jobs | @@ -601,7 +601,7 @@ GLHModelImporter >> importJobsOf: aPipeline [ ] -{ #category : #commit } +{ #category : 'commit' } GLHModelImporter >> importParentCommitsOfCommit: aGLHCommit forOnly: number [ | parentsIds commits | @@ -627,7 +627,7 @@ GLHModelImporter >> importParentCommitsOfCommit: aGLHCommit forOnly: number [ forOnly: number - 1 ]) flatten ] -{ #category : #commit } +{ #category : 'commit' } GLHModelImporter >> importParentCommitsOfCommit: aGLHCommit since: aDate [ | parentsIds commits | @@ -651,7 +651,7 @@ GLHModelImporter >> importParentCommitsOfCommit: aGLHCommit since: aDate [ flatten ] -{ #category : #'private - api' } +{ #category : 'private - api' } GLHModelImporter >> importPipelinesOfProject: aGLHProject [ (self pipelinesOf: aGLHProject id) do: [ :pipeline | @@ -659,13 +659,13 @@ GLHModelImporter >> importPipelinesOfProject: aGLHProject [ aGLHProject pipelines add: pipeline unless: self blockOnIdEquality] ] -{ #category : #imports } +{ #category : 'imports' } GLHModelImporter >> importProjects [ ^ self importProjectsSince: nil ] -{ #category : #projects } +{ #category : 'projects' } GLHModelImporter >> importProjects: aCollectionOfProjectID [ ^ aCollectionOfProjectID collect: [ :id | @@ -674,7 +674,7 @@ GLHModelImporter >> importProjects: aCollectionOfProjectID [ ] -{ #category : #imports } +{ #category : 'imports' } GLHModelImporter >> importProjectsSince: since [ "heavy import of all projects" @@ -703,7 +703,7 @@ GLHModelImporter >> importProjectsSince: since [ ^ foundProject ] -{ #category : #'private - api' } +{ #category : 'private - api' } GLHModelImporter >> importRepository: aGLHRepository [ | resultBranches branches | @@ -730,7 +730,7 @@ GLHModelImporter >> importRepository: aGLHRepository [ self inform: aGLHRepository project name , ' has no repository' ] ] -{ #category : #'private - api' } +{ #category : 'private - api' } GLHModelImporter >> importUser: aUserID [ | result userResult | @@ -743,7 +743,7 @@ GLHModelImporter >> importUser: aUserID [ ^ glhModel add: userResult unless: self blockOnIdEquality ] -{ #category : #user } +{ #category : 'user' } GLHModelImporter >> importUserByUsername: anUsername [ | dicUsername | @@ -776,7 +776,7 @@ GLHModelImporter >> importUserByUsername: anUsername [ ifNone: [ self importUser: userId ] ] ] ] ] -{ #category : #initialization } +{ #category : 'initialization' } GLHModelImporter >> initReader [ generalReader := NeoJSONReader new. @@ -785,19 +785,18 @@ GLHModelImporter >> initReader [ self configureReaderForDiffs: generalReader. ] -{ #category : #initialization } +{ #category : 'initialization' } GLHModelImporter >> initialize [ withFiles := false. withCommitDiffs := false. withInitialCommits := false. withInitialMergeRequest := false. - withCommitsSince := (Date today - 1 week) asDateAndTime. self initReader. currentImporter := self. ] -{ #category : #importer } +{ #category : 'importer' } GLHModelImporter >> loadAllProjectsFromRepositorySoftware [ "heavy import that load all the active project inside the model. Only import the project entities" |projects| @@ -805,7 +804,7 @@ GLHModelImporter >> loadAllProjectsFromRepositorySoftware [ projects := self glhApi projects. ] -{ #category : #private } +{ #category : 'private' } GLHModelImporter >> newParseCommitResult: result [ generalReader on: result readStream. @@ -813,14 +812,14 @@ GLHModelImporter >> newParseCommitResult: result [ ^ generalReader nextAs: GLHCommit ] -{ #category : #private } +{ #category : 'private' } GLHModelImporter >> newParseDiffResult: result [ generalReader on: result readStream. ^ generalReader nextAs: #ArrayOfDiffs ] -{ #category : #parsing } +{ #category : 'parsing' } GLHModelImporter >> parseArrayOfProject: arrayOfProjects [ | reader | @@ -839,7 +838,7 @@ GLHModelImporter >> parseArrayOfProject: arrayOfProjects [ ^ reader nextAs: #ArrayOfProjects ] -{ #category : #private } +{ #category : 'private' } GLHModelImporter >> parseBranchesResult: result [ | reader | @@ -852,7 +851,7 @@ GLHModelImporter >> parseBranchesResult: result [ ^ reader nextAs: #ArrayOfBranch ] -{ #category : #private } +{ #category : 'private' } GLHModelImporter >> parseCommitResult: result [ | reader | @@ -884,7 +883,7 @@ GLHModelImporter >> parseCommitResult: result [ ^ reader nextAs: GLHCommit ] -{ #category : #private } +{ #category : 'private' } GLHModelImporter >> parseCommitsResult: result [ | reader | @@ -920,7 +919,7 @@ GLHModelImporter >> parseCommitsResult: result [ ^ reader nextAs: #ArrayOfCommit ] -{ #category : #private } +{ #category : 'private' } GLHModelImporter >> parseDiffResult: result [ | reader | @@ -942,7 +941,7 @@ GLHModelImporter >> parseDiffResult: result [ ^ reader nextAs: #ArrayOfDiffs ] -{ #category : #private } +{ #category : 'private' } GLHModelImporter >> parseFileTreeResult: aResult [ | reader | @@ -955,7 +954,7 @@ GLHModelImporter >> parseFileTreeResult: aResult [ ^ reader nextAs: #ArrayOfFile ] -{ #category : #private } +{ #category : 'private' } GLHModelImporter >> parseGroupResult: aResult [ | reader | @@ -972,7 +971,7 @@ GLHModelImporter >> parseGroupResult: aResult [ ^ reader nextAs: GLHGroup ] -{ #category : #private } +{ #category : 'private' } GLHModelImporter >> parseJobsResult: result ofProject: aProject [ | reader | @@ -1007,7 +1006,7 @@ GLHModelImporter >> parseJobsResult: result ofProject: aProject [ ^ reader nextAs: #ArrayOfGLHJob ] -{ #category : #private } +{ #category : 'private' } GLHModelImporter >> parsePipelinesResult: result [ | reader | @@ -1026,7 +1025,7 @@ GLHModelImporter >> parsePipelinesResult: result [ ^ reader nextAs: #ArrayOfPipelines ] -{ #category : #private } +{ #category : 'private' } GLHModelImporter >> parseSubGroupResult: aResult [ | reader | @@ -1035,7 +1034,7 @@ GLHModelImporter >> parseSubGroupResult: aResult [ ^ reader nextAs: #ArrayOfGroups ] -{ #category : #private } +{ #category : 'private' } GLHModelImporter >> parseUserResult: result [ | reader | @@ -1044,7 +1043,7 @@ GLHModelImporter >> parseUserResult: result [ ^ reader nextAs: GLHUser ] -{ #category : #'private - api' } +{ #category : 'private - api' } GLHModelImporter >> pipelinesOf: aProjectID [ | result | @@ -1053,14 +1052,14 @@ GLHModelImporter >> pipelinesOf: aProjectID [ ^ self parsePipelinesResult: result ] -{ #category : #'as yet unclassified' } +{ #category : 'as yet unclassified' } GLHModelImporter >> selectEntityType: aType overAttribut: aSelector equalTo: value [ ^ (self glhModel allWithType: aType) select: [ :entity | (entity perform: aSelector) = value ] ] -{ #category : #'private - api' } +{ #category : 'private - api' } GLHModelImporter >> subGroupsOf: aGroupID [ | results parsedResult result page | @@ -1078,29 +1077,29 @@ GLHModelImporter >> subGroupsOf: aGroupID [ ^ results ] -{ #category : #accessing } +{ #category : 'accessing' } GLHModelImporter >> withCommitDiffs [ ^ withCommitDiffs ] -{ #category : #accessing } +{ #category : 'accessing' } GLHModelImporter >> withCommitDiffs: anObject [ withCommitDiffs := anObject ] -{ #category : #accessing } +{ #category : 'accessing' } GLHModelImporter >> withFiles [ ^ withFiles ] -{ #category : #accessing } +{ #category : 'accessing' } GLHModelImporter >> withFiles: aBoolean [ withFiles := aBoolean ] -{ #category : #accessing } +{ #category : 'accessing' } GLHModelImporter >> withInitialCommits: boolean [ withInitialCommits := boolean ] diff --git a/src/GitLabHealth-Model-Importer/package.st b/src/GitLabHealth-Model-Importer/package.st index 25caa96..b63772b 100644 --- a/src/GitLabHealth-Model-Importer/package.st +++ b/src/GitLabHealth-Model-Importer/package.st @@ -1 +1 @@ -Package { #name : #'GitLabHealth-Model-Importer' } +Package { #name : 'GitLabHealth-Model-Importer' } diff --git a/src/GitLabHealth-Visualization/RSCommit.class.st b/src/GitLabHealth-Visualization/RSCommit.class.st index 3a14ee3..3dc16e1 100644 --- a/src/GitLabHealth-Visualization/RSCommit.class.st +++ b/src/GitLabHealth-Visualization/RSCommit.class.st @@ -1,14 +1,15 @@ Class { - #name : #RSCommit, - #superclass : #Object, + #name : 'RSCommit', + #superclass : 'Object', #instVars : [ 'aCommit', 'canvas' ], - #category : #'GitLabHealth-Visualization' + #category : 'GitLabHealth-Visualization', + #package : 'GitLabHealth-Visualization' } -{ #category : #'as yet unclassified' } +{ #category : 'as yet unclassified' } RSCommit class >> canvasCompleteHierachyFor: aGLHCommit [ ^ self new @@ -16,7 +17,7 @@ RSCommit class >> canvasCompleteHierachyFor: aGLHCommit [ buildCommitCompleteHierachyCanvas ] -{ #category : #'as yet unclassified' } +{ #category : 'as yet unclassified' } RSCommit class >> canvasDiffImpactFor: aGLHCommit [ ^ self new @@ -24,7 +25,7 @@ RSCommit class >> canvasDiffImpactFor: aGLHCommit [ buildCommitDiffFileImpact ] -{ #category : #'as yet unclassified' } +{ #category : 'as yet unclassified' } RSCommit class >> canvasHierarchyFor: aGLHCommit [ ^ self new @@ -32,7 +33,7 @@ RSCommit class >> canvasHierarchyFor: aGLHCommit [ buildCommitHierachyCanvas ] -{ #category : #shape } +{ #category : 'shape' } RSCommit >> allChildrenShapesFrom: aGLHCommit [ | children sum | @@ -53,7 +54,7 @@ RSCommit >> allChildrenShapesFrom: aGLHCommit [ ^ children, sum . ] -{ #category : #shape } +{ #category : 'shape' } RSCommit >> allChildrenShapesFrom: aGLHCommit into: dic [ | children sum | @@ -67,7 +68,7 @@ RSCommit >> allChildrenShapesFrom: aGLHCommit into: dic [ self allChildrenShapesFrom: commit model into: dic ]) flattened ] -{ #category : #canvas } +{ #category : 'canvas' } RSCommit >> buildCommitCompleteHierachyCanvas [ | shapes parents children commitShape dic churnAnalyzer files2Commits shape2change allCommitShps | @@ -79,7 +80,9 @@ RSCommit >> buildCommitCompleteHierachyCanvas [ dic := Dictionary new. - churnAnalyzer := GitAnalyzer new fromCommit: aCommit; maxChildCommit: 50. + churnAnalyzer := GitAnalyzer new + fromCommit: aCommit; + maxChildCommit: 50. files2Commits := churnAnalyzer impactedFilesInFollowUpCommitsOf: aCommit. files2Commits := files2Commits select: [ :entry | @@ -130,7 +133,7 @@ RSCommit >> buildCommitCompleteHierachyCanvas [ ^ canvas ] -{ #category : #canvas } +{ #category : 'canvas' } RSCommit >> buildCommitDiffFileImpact [ | shapes | @@ -157,7 +160,7 @@ RSCommit >> buildCommitDiffFileImpact [ ^ canvas ] -{ #category : #canvas } +{ #category : 'canvas' } RSCommit >> buildCommitHierachyCanvas [ "build the commit graph from a starting root commit toward all of the descendants (children commit). Regardless of branches. Also display in red border the following commits that touch on the same files commited by the root commit. " @@ -214,7 +217,7 @@ RSCommit >> buildCommitHierachyCanvas [ ^ canvas ] -{ #category : #shape } +{ #category : 'shape' } RSCommit >> buildCompositeLayer: shapes withName: name withColor: color [ | shapesCompo label boxGroup | @@ -246,7 +249,7 @@ RSCommit >> buildCompositeLayer: shapes withName: name withColor: color [ yourself ] -{ #category : #canvas } +{ #category : 'canvas' } RSCommit >> buildDiffCanvas [ | shapes parents children commitShape group | @@ -302,25 +305,25 @@ RSCommit >> buildDiffCanvas [ ^ canvas ] -{ #category : #color } +{ #category : 'color' } RSCommit >> childColor [ ^ Color lightGreen ] -{ #category : #accessing } +{ #category : 'accessing' } RSCommit >> commit: aGLHCommit [ aCommit := aGLHCommit ] -{ #category : #color } +{ #category : 'color' } RSCommit >> commitColor [ ^ Color blue ] -{ #category : #shape } +{ #category : 'shape' } RSCommit >> createChildrenGroupFor: aGLHCommit [ |group| group := RSGroup new. @@ -345,7 +348,7 @@ RSCommit >> createChildrenGroupFor: aGLHCommit [ ^ group ] -{ #category : #lines } +{ #category : 'lines' } RSCommit >> createLinesBetweenCommits [ (RSLineBuilder arrowedLine @@ -357,7 +360,7 @@ RSCommit >> createLinesBetweenCommits [ connectToAll: [ :commit | commit childCommits ]) pushBack ] -{ #category : #lines } +{ #category : 'lines' } RSCommit >> createLinesBetweenCommits: shapes [ (RSLineBuilder arrowedLine @@ -369,31 +372,31 @@ RSCommit >> createLinesBetweenCommits: shapes [ connectToAll: [ :commit | commit childCommits ]) pushFront ] -{ #category : #color } +{ #category : 'color' } RSCommit >> defaultColor [ ^ Color lightOrange ] -{ #category : #initialization } +{ #category : 'initialization' } RSCommit >> initialize [ canvas := RSCanvas new. aCommit := GLHCommit new. ] -{ #category : #color } +{ #category : 'color' } RSCommit >> parentColor [ ^ Color gray ] -{ #category : #shape } +{ #category : 'shape' } RSCommit >> shapeForCommit: aGLHCommit [ ^ self shapeForCommit: aGLHCommit withColor: self defaultColor. ] -{ #category : #shape } +{ #category : 'shape' } RSCommit >> shapeForCommit: aGLHCommit withColor: color [ | box group labelTitle labelCommiter impactedFiles | diff --git a/src/GitLabHealth-Visualization/RSCommitDiff.class.st b/src/GitLabHealth-Visualization/RSCommitDiff.class.st index eb41d99..cb91254 100644 --- a/src/GitLabHealth-Visualization/RSCommitDiff.class.st +++ b/src/GitLabHealth-Visualization/RSCommitDiff.class.st @@ -1,14 +1,15 @@ Class { - #name : #RSCommitDiff, - #superclass : #Object, + #name : 'RSCommitDiff', + #superclass : 'Object', #instVars : [ 'aDiff', 'canvas' ], - #category : #'GitLabHealth-Visualization' + #category : 'GitLabHealth-Visualization', + #package : 'GitLabHealth-Visualization' } -{ #category : #'as yet unclassified' } +{ #category : 'as yet unclassified' } RSCommitDiff class >> canvasFor: aGLHDiff [ ^ self new @@ -16,7 +17,7 @@ RSCommitDiff class >> canvasFor: aGLHDiff [ buildCanvas ] -{ #category : #hooks } +{ #category : 'hooks' } RSCommitDiff class >> shapeFor: aCommitDiff [ ^ self new diffCommit: aCommitDiff; @@ -25,7 +26,7 @@ RSCommitDiff class >> shapeFor: aCommitDiff [ ] -{ #category : #canvas } +{ #category : 'canvas' } RSCommitDiff >> buildCanvas [ | shapes | @@ -46,7 +47,7 @@ RSCommitDiff >> buildCanvas [ ^ canvas ] -{ #category : #shape } +{ #category : 'shape' } RSCommitDiff >> buildCompositeLayer: shapes withName: name withColor: color [ | shapesCompo label boxGroup | @@ -77,7 +78,7 @@ RSCommitDiff >> buildCompositeLayer: shapes withName: name withColor: color [ yourself ] -{ #category : #lines } +{ #category : 'lines' } RSCommitDiff >> createLinesBetweenCommits: shapes [ (RSLineBuilder arrowedLine @@ -89,12 +90,12 @@ RSCommitDiff >> createLinesBetweenCommits: shapes [ connectToAll: [ :diff | diff childCommits ]) pushFront ] -{ #category : #setter } +{ #category : 'setter' } RSCommitDiff >> diffCommit: aGLHDiff [ aDiff := aGLHDiff ] -{ #category : #shape } +{ #category : 'shape' } RSCommitDiff >> shapeForDiff: aGLHDiff withColor: color [ | box group label | @@ -121,7 +122,7 @@ RSCommitDiff >> shapeForDiff: aGLHDiff withColor: color [ yourself ] -{ #category : #shape } +{ #category : 'shape' } RSCommitDiff >> shapeForDiffRange: aGLPHEDiffRange withColor: aColor [ | box group label | @@ -146,7 +147,7 @@ RSCommitDiff >> shapeForDiffRange: aGLPHEDiffRange withColor: aColor [ yourself ] -{ #category : #shape } +{ #category : 'shape' } RSCommitDiff >> shapeForRange: aGLHDiff withColor: color [ | box group label | diff --git a/src/GitLabHealth-Visualization/package.st b/src/GitLabHealth-Visualization/package.st index aaa0de3..7f9a7e6 100644 --- a/src/GitLabHealth-Visualization/package.st +++ b/src/GitLabHealth-Visualization/package.st @@ -1 +1 @@ -Package { #name : #'GitLabHealth-Visualization' } +Package { #name : 'GitLabHealth-Visualization' } From 4aedf781ac7bfcca0261f381f5cd6162bbe70dcd Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Fri, 13 Sep 2024 15:40:39 +0200 Subject: [PATCH 104/154] more with files properties to generic importer --- .../GHModelImporter.class.st | 28 +-------- .../GLHModelImporter.class.st | 25 +------- .../GPModelImporter.class.st | 59 +++++++++++++++++++ .../package.st | 1 + 4 files changed, 64 insertions(+), 49 deletions(-) create mode 100644 src/GitProjectHealth-Model-Importer/GPModelImporter.class.st create mode 100644 src/GitProjectHealth-Model-Importer/package.st diff --git a/src/GitHubHealth-Model-Importer/GHModelImporter.class.st b/src/GitHubHealth-Model-Importer/GHModelImporter.class.st index 3ac4417..00d3c00 100644 --- a/src/GitHubHealth-Model-Importer/GHModelImporter.class.st +++ b/src/GitHubHealth-Model-Importer/GHModelImporter.class.st @@ -3,8 +3,7 @@ Class { #superclass : 'GPModelImporter', #instVars : [ 'api', - 'glhModel', - 'withFiles' + 'glhModel' ], #category : 'GitHubHealth-Model-Importer', #package : 'GitHubHealth-Model-Importer' @@ -22,18 +21,6 @@ GHModelImporter >> api: anObject [ api := anObject ] -{ #category : 'accessing' } -GHModelImporter >> beWithFiles [ - - withFiles := true -] - -{ #category : 'accessing' } -GHModelImporter >> beWithoutFiles [ - - withFiles := false -] - { #category : 'private' } GHModelImporter >> convertApiFileAsFile: aAPIFile [ @@ -161,6 +148,7 @@ GHModelImporter >> importRepositoriesOfGroup: groupResult [ { #category : 'initialization' } GHModelImporter >> initialize [ + super initialize. self api: GHApi new. withFiles := false @@ -255,15 +243,3 @@ GHModelImporter >> privateToken [ GHModelImporter >> privateToken: aTokenString [ ^ self api privateToken: aTokenString ] - -{ #category : 'accessing' } -GHModelImporter >> withFiles [ - - ^ withFiles -] - -{ #category : 'accessing' } -GHModelImporter >> withFiles: anObject [ - - withFiles := anObject -] diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index 170c5f5..800c2d5 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -4,7 +4,6 @@ Class { #instVars : [ 'glhModel', 'glhApi', - 'withFiles', 'withCommitDiffs', 'withInitialCommits', 'withInitialMergeRequest', @@ -50,16 +49,6 @@ GLHModelImporter >> addGroupResultToModel: groupResult [ ^ group ] -{ #category : 'accessing' } -GLHModelImporter >> beWithFiles [ - withFiles := true -] - -{ #category : 'accessing' } -GLHModelImporter >> beWithouFiles [ - withFiles := false -] - { #category : 'as yet unclassified' } GLHModelImporter >> blockEqualityOn: aSymbol [ ^ [ :existing :new | @@ -788,12 +777,12 @@ GLHModelImporter >> initReader [ { #category : 'initialization' } GLHModelImporter >> initialize [ - withFiles := false. + super initialize. withCommitDiffs := false. withInitialCommits := false. withInitialMergeRequest := false. self initReader. - currentImporter := self. + currentImporter := self ] { #category : 'importer' } @@ -1089,16 +1078,6 @@ GLHModelImporter >> withCommitDiffs: anObject [ withCommitDiffs := anObject ] -{ #category : 'accessing' } -GLHModelImporter >> withFiles [ - ^ withFiles -] - -{ #category : 'accessing' } -GLHModelImporter >> withFiles: aBoolean [ - withFiles := aBoolean -] - { #category : 'accessing' } GLHModelImporter >> withInitialCommits: boolean [ withInitialCommits := boolean diff --git a/src/GitProjectHealth-Model-Importer/GPModelImporter.class.st b/src/GitProjectHealth-Model-Importer/GPModelImporter.class.st new file mode 100644 index 0000000..b88e291 --- /dev/null +++ b/src/GitProjectHealth-Model-Importer/GPModelImporter.class.st @@ -0,0 +1,59 @@ +" +I am a superclass for Model importer. +I am a try of normalization for the different importer. + +I also define some contract so it is easier to switch from one importer to another +" +Class { + #name : 'GPModelImporter', + #superclass : 'Object', + #instVars : [ + 'withCommitsSince', + 'withFiles' + ], + #category : 'GitProjectHealth-Model-Importer', + #package : 'GitProjectHealth-Model-Importer' +} + +{ #category : 'accessing' } +GPModelImporter >> beWithFiles [ + + withFiles := true +] + +{ #category : 'accessing' } +GPModelImporter >> beWithoutFiles [ + + withFiles := false +] + +{ #category : 'initialization' } +GPModelImporter >> initialize [ + + super initialize. + self withCommitsSince: (Date today - 1 week) asDateAndTime +] + +{ #category : 'accessing' } +GPModelImporter >> withCommitsSince [ + + ^ withCommitsSince +] + +{ #category : 'accessing' } +GPModelImporter >> withCommitsSince: anObject [ + + withCommitsSince := anObject +] + +{ #category : 'accessing' } +GPModelImporter >> withFiles [ + + ^ withFiles +] + +{ #category : 'accessing' } +GPModelImporter >> withFiles: anObject [ + + withFiles := anObject +] diff --git a/src/GitProjectHealth-Model-Importer/package.st b/src/GitProjectHealth-Model-Importer/package.st new file mode 100644 index 0000000..8668e89 --- /dev/null +++ b/src/GitProjectHealth-Model-Importer/package.st @@ -0,0 +1 @@ +Package { #name : 'GitProjectHealth-Model-Importer' } From 465955268a726d1c5b7493db876f7d3bd2a9c6f5 Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Fri, 13 Sep 2024 15:50:25 +0200 Subject: [PATCH 105/154] keep test green --- .../GLPHApi.class.st | 29 ++++----- .../GLPHModelImporter.class.st | 61 +++++++++++-------- .../package.st | 2 +- 3 files changed, 50 insertions(+), 42 deletions(-) diff --git a/src/GitLabProjectHealth-Model-Importer/GLPHApi.class.st b/src/GitLabProjectHealth-Model-Importer/GLPHApi.class.st index a772926..be266da 100644 --- a/src/GitLabProjectHealth-Model-Importer/GLPHApi.class.st +++ b/src/GitLabProjectHealth-Model-Importer/GLPHApi.class.st @@ -1,10 +1,11 @@ Class { - #name : #GLPHApi, - #superclass : #GLHApi, - #category : #'GitLabProjectHealth-Model-Importer' + #name : 'GLPHApi', + #superclass : 'GLHApi', + #category : 'GitLabProjectHealth-Model-Importer', + #package : 'GitLabProjectHealth-Model-Importer' } -{ #category : #mergeRequest } +{ #category : 'mergeRequest' } GLPHApi >> approvalsOfMergeQuest: aMergeRequestIID ofProject: aProjectId [ self client path: @@ -13,7 +14,7 @@ GLPHApi >> approvalsOfMergeQuest: aMergeRequestIID ofProject: aProjectId [ ^ self client get ] -{ #category : #commit } +{ #category : 'commit' } GLPHApi >> commitsOfProject: anInteger forRefName: refName [ self @@ -38,7 +39,7 @@ GLPHApi >> commitsOfProject: anInteger forRefName: refName [ page: nil ] -{ #category : #commits } +{ #category : 'commits' } GLPHApi >> commitsOfProject: anInteger forRefName: refName since: since [ self @@ -63,7 +64,7 @@ GLPHApi >> commitsOfProject: anInteger forRefName: refName since: since [ page: nil ] -{ #category : #commit } +{ #category : 'commit' } GLPHApi >> commitsOfProject: aGLHProject forRefName: refName until: toDate [ | newlyFoundCommit page | @@ -108,7 +109,7 @@ GLPHApi >> commitsOfProject: aGLHProject forRefName: refName until: toDate [ self importDiffOfCommit: commit ] ] ] -{ #category : #'as yet unclassified' } +{ #category : 'as yet unclassified' } GLPHApi >> diffsMergeRequestOfProject: aProjectID withId: anMRiid [ ^ self client get: @@ -116,13 +117,13 @@ GLPHApi >> diffsMergeRequestOfProject: aProjectID withId: anMRiid [ , '/merge_requests/' , anMRiid printString , '/diffs/' ] -{ #category : #initialization } +{ #category : 'initialization' } GLPHApi >> initialize [ super initialize ] -{ #category : #'as yet unclassified' } +{ #category : 'as yet unclassified' } GLPHApi >> mergeRequestOfProject: aProjectID [ ^ self client get: @@ -130,7 +131,7 @@ GLPHApi >> mergeRequestOfProject: aProjectID [ , '/merge_requests/' ] -{ #category : #'as yet unclassified' } +{ #category : 'as yet unclassified' } GLPHApi >> mergeRequestOfProject: aProjectID withId: anMRiid [ ^ self client get: @@ -138,7 +139,7 @@ GLPHApi >> mergeRequestOfProject: aProjectID withId: anMRiid [ , '/merge_requests/' , anMRiid printString ] -{ #category : #mergeRequest } +{ #category : 'mergeRequest' } GLPHApi >> mergeRequestsOfProject: aProjectId createdAfter: createdAfter createdBefore: createdBefore authorId: authorId authorUsername: authorUsername scope: scope orderBy: orderBy page: page [ self client path: @@ -159,14 +160,14 @@ GLPHApi >> mergeRequestsOfProject: aProjectId createdAfter: createdAfter created ^ self client get ] -{ #category : #accessing } +{ #category : 'accessing' } GLPHApi >> project: aProjectID [ ^ self client get: self baseAPIUrl , '/projects/' , aProjectID printString ] -{ #category : #user } +{ #category : 'user' } GLPHApi >> usersSearchByUsername: aUserName [ |name| diff --git a/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st b/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st index 4b9f134..f0f165a 100644 --- a/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st +++ b/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st @@ -1,10 +1,11 @@ Class { - #name : #GLPHModelImporter, - #superclass : #GLHModelImporter, - #category : #'GitLabProjectHealth-Model-Importer' + #name : 'GLPHModelImporter', + #superclass : 'GLHModelImporter', + #category : 'GitLabProjectHealth-Model-Importer', + #package : 'GitLabProjectHealth-Model-Importer' } -{ #category : #'as yet unclassified' } +{ #category : 'as yet unclassified' } GLPHModelImporter >> blockForDiffRangeEquality [ ^ [ :existing :new | @@ -13,7 +14,7 @@ GLPHModelImporter >> blockForDiffRangeEquality [ existing newLineRange = new newLineRange ] ] ] ] -{ #category : #commit } +{ #category : 'commit' } GLPHModelImporter >> chainsCommitsFrom: commitsCollection [ | dic | @@ -35,7 +36,7 @@ GLPHModelImporter >> chainsCommitsFrom: commitsCollection [ ^ commitsCollection ] -{ #category : #commit } +{ #category : 'commit' } GLPHModelImporter >> commitsOfProject: aGLHProject forRefName: refName until: toDate [ | newlyFoundCommit page | @@ -75,7 +76,7 @@ GLPHModelImporter >> commitsOfProject: aGLHProject forRefName: refName until: to self importDiffOfCommit: commit ] ] ] -{ #category : #'private - api' } +{ #category : 'private - api' } GLPHModelImporter >> completeImportProject: aGLHProject [ |completedProject| completedProject := super completeImportProject: aGLHProject. @@ -89,7 +90,7 @@ GLPHModelImporter >> completeImportProject: aGLHProject [ ^ completedProject ] -{ #category : #'private - configure reader' } +{ #category : 'private - configure reader' } GLPHModelImporter >> configureReaderForMergeRequest: reader [ "declare quil y a un array a mapper" @@ -138,7 +139,7 @@ GLPHModelImporter >> configureReaderForMergeRequest: reader [ string ifNil: [ nil ] ifNotNil: [ DateAndTime fromString: string ] ] ] ] -{ #category : #import } +{ #category : 'import' } GLPHModelImporter >> importCommitsOfBranch: aGLHBranch [ | commits | @@ -158,7 +159,7 @@ GLPHModelImporter >> importCommitsOfBranch: aGLHBranch [ ] ] -{ #category : #import } +{ #category : 'import' } GLPHModelImporter >> importCommitsOfMergeResquest: aGLPHEMergeRequest [ | foundCommits | @@ -191,7 +192,7 @@ GLPHModelImporter >> importCommitsOfMergeResquest: aGLPHEMergeRequest [ ^ foundCommits ] -{ #category : #api } +{ #category : 'api' } GLPHModelImporter >> importDiffOfCommit: aCommit [ super importDiffOfCommit: aCommit. @@ -202,7 +203,7 @@ GLPHModelImporter >> importDiffOfCommit: aCommit [ ^ aCommit diffs ] -{ #category : #'as yet unclassified' } +{ #category : 'as yet unclassified' } GLPHModelImporter >> importDiffOfMergeRequest: aMergeRequest [ | result diffsResult | @@ -231,7 +232,7 @@ GLPHModelImporter >> importDiffOfMergeRequest: aMergeRequest [ ^ aMergeRequest diffs ] -{ #category : #import } +{ #category : 'import' } GLPHModelImporter >> importDiffRangesForDiff: aGLHDiff [ | diffRanges | @@ -250,7 +251,7 @@ GLPHModelImporter >> importDiffRangesForDiff: aGLHDiff [ unless: self blockForDiffRangeEquality ] -{ #category : #'import - merge request' } +{ #category : 'import - merge request' } GLPHModelImporter >> importMergeRequests: aGLHProject [ | results parsedResults | @@ -279,7 +280,7 @@ GLPHModelImporter >> importMergeRequests: aGLHProject [ self importDiffOfMergeRequest: mr ] ] ] -{ #category : #'import - merge request' } +{ #category : 'import - merge request' } GLPHModelImporter >> importMergeRequests: aGLHProject since: fromDate until: toDate [ | newlyFoundMR page foundMR | @@ -324,7 +325,7 @@ GLPHModelImporter >> importMergeRequests: aGLHProject since: fromDate until: toD ^ foundMR ] -{ #category : #'import - merge request' } +{ #category : 'import - merge request' } GLPHModelImporter >> importMergeResquestApprovals: aGLPHEMergeRequest [ | results parsedResult | @@ -346,7 +347,7 @@ GLPHModelImporter >> importMergeResquestApprovals: aGLPHEMergeRequest [ ^ aGLPHEMergeRequest ] -{ #category : #'import - merge request' } +{ #category : 'import - merge request' } GLPHModelImporter >> importMergeResquestAuthor: aGLPHEMergeRequest [ | authorID | @@ -361,7 +362,7 @@ GLPHModelImporter >> importMergeResquestAuthor: aGLPHEMergeRequest [ aGLPHEMergeRequest author: (self importUser: authorID) ] -{ #category : #'import - merge request' } +{ #category : 'import - merge request' } GLPHModelImporter >> importMergeResquestMerger: aGLPHEMergeRequest [ | authorID | @@ -380,7 +381,7 @@ GLPHModelImporter >> importMergeResquestMerger: aGLPHEMergeRequest [ aGLPHEMergeRequest merge_user: (self importUser: authorID) ] -{ #category : #'as yet unclassified' } +{ #category : 'as yet unclassified' } GLPHModelImporter >> importProject: aProjectID [ | result projectResult | @@ -392,7 +393,7 @@ GLPHModelImporter >> importProject: aProjectID [ ^ self completeImportProject: projectResult ] -{ #category : #'private - api' } +{ #category : 'private - api' } GLPHModelImporter >> importRepository: aGLHRepository [ super importRepository: aGLHRepository. @@ -402,21 +403,21 @@ GLPHModelImporter >> importRepository: aGLHRepository [ self importCommitsOfBranch: branch ] ] ] -{ #category : #initialization } +{ #category : 'initialization' } GLPHModelImporter >> initReader [ super initReader. self configureReaderForMergeRequest: generalReader ] -{ #category : #initialization } +{ #category : 'initialization' } GLPHModelImporter >> initialize [ super initialize. withCommitDiffs := true ] -{ #category : #parsing } +{ #category : 'parsing' } GLPHModelImporter >> parseDiffString: aDiff [ "parse diff string to create entities for each lines" @@ -458,14 +459,14 @@ GLPHModelImporter >> parseDiffString: aDiff [ ^ aDiff diffRanges ] -{ #category : #parsing } +{ #category : 'parsing' } GLPHModelImporter >> parseMergeRequestResult: result [ generalReader on: result readStream. ^ generalReader nextAs: #ArrayOfMergeRequest ] -{ #category : #parsing } +{ #category : 'parsing' } GLPHModelImporter >> parseProjectResult: aResult [ | reader | reader := NeoJSONReader on: aResult readStream. @@ -476,10 +477,16 @@ GLPHModelImporter >> parseProjectResult: aResult [ ^ reader nextAs: GLHProject ] -{ #category : #accessing } +{ #category : 'accessing' } GLPHModelImporter >> withCommitsSince: someDays [ "substract the current date with a given number of days. Use to retrieve the commits submit in the last giving days" + "(GLPHModelImporter new withCommitsSince: 1 week ) >>> (Date today - 1 week) asDateAndTime" + "(GLPHModelImporter new withCommitsSince: 30 day ) >>> (Date today - 30 day) asDateAndTime" - withCommitsSince := (Date today - someDays) asDateAndTime + + (someDays isKindOf: DateAndTime) + ifTrue: [ withCommitsSince := someDays ] + ifFalse: [ + withCommitsSince := (Date today - someDays) asDateAndTime ] ] diff --git a/src/GitLabProjectHealth-Model-Importer/package.st b/src/GitLabProjectHealth-Model-Importer/package.st index 2420566..3dee3f2 100644 --- a/src/GitLabProjectHealth-Model-Importer/package.st +++ b/src/GitLabProjectHealth-Model-Importer/package.st @@ -1 +1 @@ -Package { #name : #'GitLabProjectHealth-Model-Importer' } +Package { #name : 'GitLabProjectHealth-Model-Importer' } From d6b4d828627c4d7dfa88e9dab163e3300cb6fa80 Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Sun, 15 Sep 2024 10:14:45 +0200 Subject: [PATCH 106/154] wip --- .../GHApi.class.st | 8 ++++++ .../GHModelImporter.class.st | 25 ++++++++++++++++--- .../GLHModelImporter.class.st | 7 ++++-- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/GitHubHealth-Model-Importer/GHApi.class.st b/src/GitHubHealth-Model-Importer/GHApi.class.st index 3de5712..7f35630 100644 --- a/src/GitHubHealth-Model-Importer/GHApi.class.st +++ b/src/GitHubHealth-Model-Importer/GHApi.class.st @@ -53,6 +53,14 @@ GHApi >> client: anObject [ client := anObject ] +{ #category : 'api - commits' } +GHApi >> commitsOfProject: aProjectId ofOrganization: organisationName [ + + ^ self client get: + self baseAPIUrl , '/repos/' , organisationName , '/' , aProjectId + , '/commits' +] + { #category : 'api' } GHApi >> contentsOfRepo: aRepoName ofOrganization: anOrganizationName inBranch: aBranchRef withPath: aPath [ diff --git a/src/GitHubHealth-Model-Importer/GHModelImporter.class.st b/src/GitHubHealth-Model-Importer/GHModelImporter.class.st index 00d3c00..51fce97 100644 --- a/src/GitHubHealth-Model-Importer/GHModelImporter.class.st +++ b/src/GitHubHealth-Model-Importer/GHModelImporter.class.st @@ -21,6 +21,15 @@ GHModelImporter >> api: anObject [ api := anObject ] +{ #category : 'api' } +GHModelImporter >> completeImportProject: aGLHProject [ + + self importPipelinesOf: aGLHProject. + self importBranchesOf: aGLHProject. + self withCommitsSince ifNotNil: [ :withCommitSince | "If not nil, it means we have to import commit" + self importCommitsOfProject: aGLHProject ] +] + { #category : 'private' } GHModelImporter >> convertApiFileAsFile: aAPIFile [ @@ -64,6 +73,16 @@ GHModelImporter >> importBranchesOf: project [ self withFiles ifTrue: [ self importFilesOfBranch: branch ] ] ] +{ #category : 'api' } +GHModelImporter >> importCommitsOfProject: aGLHProject [ + + | commits | + commits := self api + commitsOfProject: aGLHProject name + ofOrganization: aGLHProject group name. + self halt +] + { #category : 'api' } GHModelImporter >> importDirectoryFiles: aDirectoryFile OfBranch: aBranch [ @@ -138,11 +157,9 @@ GHModelImporter >> importRepositoriesOfGroup: groupResult [ | reposResult | reposResult := self api reposOfOrganization: groupResult name. groupResult projects addAll: (self parseArrayOfProject: reposResult). - self glhModel - addAll: groupResult projects. + self glhModel addAll: groupResult projects. groupResult projects do: [ :project | - self importPipelinesOf: project. - self importBranchesOf: project ]. + self completeImportProject: project ]. ^ groupResult ] diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index 800c2d5..529c1e3 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -77,10 +77,13 @@ GLHModelImporter >> blockOnNameEquality [ { #category : 'private - api' } GLHModelImporter >> completeImportProject: aGLHProject [ - |importedProject| + + | importedProject | ('Complete import of project: ' , aGLHProject id printString) recordInfo. - importedProject := self glhModel add: aGLHProject unless: (self blockOnIdEquality ). + importedProject := self glhModel + add: aGLHProject + unless: self blockOnIdEquality. self importPipelinesOfProject: importedProject. From 34152fd268afdb66ce98f0ad6c7452a15c1acd12 Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Sun, 15 Sep 2024 10:38:08 +0200 Subject: [PATCH 107/154] add a test for the parse of commits from github --- .../GHModelImporterTest.class.st | 181 +++++++++++++++++- .../package.st | 2 +- .../GHModelImporter.class.st | 41 +++- .../GLHCommit.extension.st | 16 +- .../GLHDiff.extension.st | 4 +- .../GLHFile.extension.st | 4 +- .../GLHUser.extension.st | 6 +- .../MooseAbstractGroup.extension.st | 8 +- .../OrderedCollection.extension.st | 6 +- src/GitLabHealth-Model-Extension/package.st | 2 +- 10 files changed, 236 insertions(+), 34 deletions(-) diff --git a/src/GitHubHealth-Model-Importer-Tests/GHModelImporterTest.class.st b/src/GitHubHealth-Model-Importer-Tests/GHModelImporterTest.class.st index 91433ad..8623193 100644 --- a/src/GitHubHealth-Model-Importer-Tests/GHModelImporterTest.class.st +++ b/src/GitHubHealth-Model-Importer-Tests/GHModelImporterTest.class.st @@ -2,22 +2,193 @@ A GHModelImporterTest is a test class for testing the behavior of GHModelImporter " Class { - #name : #GHModelImporterTest, - #superclass : #TestCase, + #name : 'GHModelImporterTest', + #superclass : 'TestCase', #instVars : [ 'importer' ], - #category : #'GitHubHealth-Model-Importer-Tests' + #category : 'GitHubHealth-Model-Importer-Tests', + #package : 'GitHubHealth-Model-Importer-Tests' } -{ #category : #running } +{ #category : 'running' } GHModelImporterTest >> setUp [ super setUp. importer := GHModelImporter new ] -{ #category : #test } +{ #category : 'tests' } +GHModelImporterTest >> testParseCommitsResult [ + + | commits | + commits := importer parseCommitsResult: '[ + { + "sha": "f5ac58f4afe4632b0a26d1e968439c78962da289", + "node_id": "C_kwDOAmR199oAKGY1YWM1OGY0YWZlNDYzMmIwYTI2ZDFlOTY4NDM5Yzc4OTYyZGEyODk", + "commit": { + "author": { + "name": "Clotilde Toullec", + "email": "39184695+ClotildeToullec@users.noreply.github.com", + "date": "2024-09-09T14:32:48Z" + }, + "committer": { + "name": "GitHub", + "email": "noreply@github.com", + "date": "2024-09-09T14:32:48Z" + }, + "message": "Update test-and-release.yml", + "tree": { + "sha": "d6163cb0d50d0e6fe149e3c92b22b13cf2c253f1", + "url": "https://api.github.com/repos/moosetechnology/Moose/git/trees/d6163cb0d50d0e6fe149e3c92b22b13cf2c253f1" + }, + "url": "https://api.github.com/repos/moosetechnology/Moose/git/commits/f5ac58f4afe4632b0a26d1e968439c78962da289", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\nwsFcBAABCAAQBQJm3wcQCRC1aQ7uu5UhlAAAQ7kQAJOUaDn2VQd1VHl7LbmYSF/R\nTaV6o9Ck1RzeZQRKKhIeofERpItb726h8IPtDh7AcS7c97D0+Opv3c8x7GXvgfzi\ne+XhZ2FErra11pd1AXW1bZwlCEp2KhBEkTXEhKZK8Yg18z/1/hGR3gE27P1qBU7N\nm6pGDVPapdKVmljbteCGprUGcDe9uKqg9sj1YONXNDVm7pAYSrQXOnqfUKm/sFDm\n3wdLVr+U0jshg4Obhy+kxPHqNCxEFCPov4SxUJ0Fx6L4Gg90K4qQ3GwiuSUbwNGP\nAbopNPdNfcWlK2Zzez1e2GiaSwBjhcADkSQ1aGveINuE34KAe/yYd1BRuIW7BtDK\nc+qSGD98KyfNNxPBwv/JyPh76CvDghexgz8+j3PKE+SQkwPHKfJjHbB3Ool4RwY2\npeHU1E1mj0O29a+y6iUcYGyRXkAzBC+B86PJ5QC7dQvklLHZfX2uIFw3tr2ZlunC\nbjhLN7Vnor6BPocSLPdPanOrZXDmoy6grUhyNSgvCuoiRZ9HoG3NREn4GLEFIjLd\nNKxnS8Zim8QQnd2lvvunz7Gge6mfwWLGMIX4MPC3BQUYhZ6i2nx7vqIID0cEyWlj\n6K+tUj/MJkgj0EcnBL8HC1AIiJeJk9hTBdOHrJj3/kvM/0HIrAg+PQEdK0y2iYLp\nxXqau3U95zTp2792mpVc\n=n2IL\n-----END PGP SIGNATURE-----\n", + "payload": "tree d6163cb0d50d0e6fe149e3c92b22b13cf2c253f1\nparent eb31d04f01254d0caf7c7a5b03546e3f6a5c3d58\nauthor Clotilde Toullec <39184695+ClotildeToullec@users.noreply.github.com> 1725892368 +0200\ncommitter GitHub 1725892368 +0200\n\nUpdate test-and-release.yml" + } + }, + "url": "https://api.github.com/repos/moosetechnology/Moose/commits/f5ac58f4afe4632b0a26d1e968439c78962da289", + "html_url": "https://github.com/moosetechnology/Moose/commit/f5ac58f4afe4632b0a26d1e968439c78962da289", + "comments_url": "https://api.github.com/repos/moosetechnology/Moose/commits/f5ac58f4afe4632b0a26d1e968439c78962da289/comments", + "author": { + "login": "ClotildeToullec", + "id": 39184695, + "node_id": "MDQ6VXNlcjM5MTg0Njk1", + "avatar_url": "https://avatars.githubusercontent.com/u/39184695?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ClotildeToullec", + "html_url": "https://github.com/ClotildeToullec", + "followers_url": "https://api.github.com/users/ClotildeToullec/followers", + "following_url": "https://api.github.com/users/ClotildeToullec/following{/other_user}", + "gists_url": "https://api.github.com/users/ClotildeToullec/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ClotildeToullec/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ClotildeToullec/subscriptions", + "organizations_url": "https://api.github.com/users/ClotildeToullec/orgs", + "repos_url": "https://api.github.com/users/ClotildeToullec/repos", + "events_url": "https://api.github.com/users/ClotildeToullec/events{/privacy}", + "received_events_url": "https://api.github.com/users/ClotildeToullec/received_events", + "type": "User", + "site_admin": false + }, + "committer": { + "login": "web-flow", + "id": 19864447, + "node_id": "MDQ6VXNlcjE5ODY0NDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/19864447?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/web-flow", + "html_url": "https://github.com/web-flow", + "followers_url": "https://api.github.com/users/web-flow/followers", + "following_url": "https://api.github.com/users/web-flow/following{/other_user}", + "gists_url": "https://api.github.com/users/web-flow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/web-flow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/web-flow/subscriptions", + "organizations_url": "https://api.github.com/users/web-flow/orgs", + "repos_url": "https://api.github.com/users/web-flow/repos", + "events_url": "https://api.github.com/users/web-flow/events{/privacy}", + "received_events_url": "https://api.github.com/users/web-flow/received_events", + "type": "User", + "site_admin": false + }, + "parents": [ + { + "sha": "eb31d04f01254d0caf7c7a5b03546e3f6a5c3d58", + "url": "https://api.github.com/repos/moosetechnology/Moose/commits/eb31d04f01254d0caf7c7a5b03546e3f6a5c3d58", + "html_url": "https://github.com/moosetechnology/Moose/commit/eb31d04f01254d0caf7c7a5b03546e3f6a5c3d58" + } + ] + }, + { + "sha": "eb31d04f01254d0caf7c7a5b03546e3f6a5c3d58", + "node_id": "C_kwDOAmR199oAKGViMzFkMDRmMDEyNTRkMGNhZjdjN2E1YjAzNTQ2ZTNmNmE1YzNkNTg", + "commit": { + "author": { + "name": "Clotilde Toullec", + "email": "39184695+ClotildeToullec@users.noreply.github.com", + "date": "2024-09-09T14:23:04Z" + }, + "committer": { + "name": "GitHub", + "email": "noreply@github.com", + "date": "2024-09-09T14:23:04Z" + }, + "message": "Update release.yml", + "tree": { + "sha": "2603616f5508d52a14de694ebfd36a4fe3d92c32", + "url": "https://api.github.com/repos/moosetechnology/Moose/git/trees/2603616f5508d52a14de694ebfd36a4fe3d92c32" + }, + "url": "https://api.github.com/repos/moosetechnology/Moose/git/commits/eb31d04f01254d0caf7c7a5b03546e3f6a5c3d58", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\nwsFcBAABCAAQBQJm3wTJCRC1aQ7uu5UhlAAAMVsQADtx9h/p+gZpgOZfWwGUgV1O\nk8HSuq+Q1Z/OMg22+zvTYw77qS7ni+jFn34XYGpZECbMybTobqT8bRWvKGaoyhE3\n054OutXJLRhh/6Siy1AI9Bcr/huLWHzQ0faU4M4mO+SS/RQF1yfqCNzyDFfafWEU\nxnlf1CpdknoWAAjN2kaNBXvBBmTBOPZQ5mP+j7Mi2U4DvoG/2NpB9QhkjE0zdw0Z\nddApTKCe4QkrtFfLTJ3NJuWoCoNif+8leyfAsE4iqonZvhUKly/9EdZuhR8QgbrE\nunDk9RF9IoZDR4b1Sz/qY+ajd1IXqYNRQg0Aihb5DDzQY8tZsZRmrlSKw/xqwTOf\nOy5rO9MWSGHFqnRbWZfgzWYgE/w0pvbL3Z9ahsYbHJaWcxSX9BcfV1KbN5ygm9Bx\nlDUr8D2scOrmr+Eg4LdmJxtZB6eEJfPA34H/PY5IZvQDkbFyzPJm4IUfRRFmEwLy\nx1JmE/bVBl1q0YaLiDW856y5yAAkYfRlkHVhqgya6kfaWEHNMl4r0od8M4PbNF9F\n/Qx4VNqQH+u+iThn8l9BDA0B2NrPu5rUyz+SAo/OjRuBoVv+yiYBaevLzkuLOhkL\noUxYduwo9bT2imkiOvKEAsXpNPjuraf6gHUkY9OxinnEp6AWe/qyqc5duhFSJuzC\nAVA3RPqe7kvwqnWKurpZ\n=bDEh\n-----END PGP SIGNATURE-----\n", + "payload": "tree 2603616f5508d52a14de694ebfd36a4fe3d92c32\nparent cfa833e9c504fe1f27c93fca016a5006cc300206\nauthor Clotilde Toullec <39184695+ClotildeToullec@users.noreply.github.com> 1725891784 +0200\ncommitter GitHub 1725891784 +0200\n\nUpdate release.yml" + } + }, + "url": "https://api.github.com/repos/moosetechnology/Moose/commits/eb31d04f01254d0caf7c7a5b03546e3f6a5c3d58F", + "html_url": "https://github.com/moosetechnology/Moose/commit/eb31d04f01254d0caf7c7a5b03546e3f6a5c3d58", + "comments_url": "https://api.github.com/repos/moosetechnology/Moose/commits/eb31d04f01254d0caf7c7a5b03546e3f6a5c3d58/comments", + "author": { + "login": "ClotildeToullec", + "id": 39184695, + "node_id": "MDQ6VXNlcjM5MTg0Njk1", + "avatar_url": "https://avatars.githubusercontent.com/u/39184695?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ClotildeToullec", + "html_url": "https://github.com/ClotildeToullec", + "followers_url": "https://api.github.com/users/ClotildeToullec/followers", + "following_url": "https://api.github.com/users/ClotildeToullec/following{/other_user}", + "gists_url": "https://api.github.com/users/ClotildeToullec/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ClotildeToullec/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ClotildeToullec/subscriptions", + "organizations_url": "https://api.github.com/users/ClotildeToullec/orgs", + "repos_url": "https://api.github.com/users/ClotildeToullec/repos", + "events_url": "https://api.github.com/users/ClotildeToullec/events{/privacy}", + "received_events_url": "https://api.github.com/users/ClotildeToullec/received_events", + "type": "User", + "site_admin": false + }, + "committer": { + "login": "web-flow", + "id": 19864447, + "node_id": "MDQ6VXNlcjE5ODY0NDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/19864447?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/web-flow", + "html_url": "https://github.com/web-flow", + "followers_url": "https://api.github.com/users/web-flow/followers", + "following_url": "https://api.github.com/users/web-flow/following{/other_user}", + "gists_url": "https://api.github.com/users/web-flow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/web-flow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/web-flow/subscriptions", + "organizations_url": "https://api.github.com/users/web-flow/orgs", + "repos_url": "https://api.github.com/users/web-flow/repos", + "events_url": "https://api.github.com/users/web-flow/events{/privacy}", + "received_events_url": "https://api.github.com/users/web-flow/received_events", + "type": "User", + "site_admin": false + }, + "parents": [ + { + "sha": "cfa833e9c504fe1f27c93fca016a5006cc300206", + "url": "https://api.github.com/repos/moosetechnology/Moose/commits/cfa833e9c504fe1f27c93fca016a5006cc300206", + "html_url": "https://github.com/moosetechnology/Moose/commit/cfa833e9c504fe1f27c93fca016a5006cc300206" + } + ] + } +]'. + + self assert: commits size equals: 2. + self assert: commits first message equals: 'Update test-and-release.yml'. + self assert: commits second message equals: 'Update release.yml'. +] + +{ #category : 'test' } GHModelImporterTest >> testParsePipelinesResult [ | project | diff --git a/src/GitHubHealth-Model-Importer-Tests/package.st b/src/GitHubHealth-Model-Importer-Tests/package.st index 5cc38a9..d228c56 100644 --- a/src/GitHubHealth-Model-Importer-Tests/package.st +++ b/src/GitHubHealth-Model-Importer-Tests/package.st @@ -1 +1 @@ -Package { #name : #'GitHubHealth-Model-Importer-Tests' } +Package { #name : 'GitHubHealth-Model-Importer-Tests' } diff --git a/src/GitHubHealth-Model-Importer/GHModelImporter.class.st b/src/GitHubHealth-Model-Importer/GHModelImporter.class.st index 51fce97..bfee1c7 100644 --- a/src/GitHubHealth-Model-Importer/GHModelImporter.class.st +++ b/src/GitHubHealth-Model-Importer/GHModelImporter.class.st @@ -76,11 +76,11 @@ GHModelImporter >> importBranchesOf: project [ { #category : 'api' } GHModelImporter >> importCommitsOfProject: aGLHProject [ - | commits | - commits := self api - commitsOfProject: aGLHProject name - ofOrganization: aGLHProject group name. - self halt + | commitsResult commits | + commitsResult := self api + commitsOfProject: aGLHProject name + ofOrganization: aGLHProject group name. + commits := self parseCommitsResult: commitsResult ] { #category : 'api' } @@ -203,6 +203,37 @@ GHModelImporter >> parseBranchesResult: arrayOfBranch [ ^ reader nextAs: #ArrayOfBranch ] +{ #category : 'parsing' } +GHModelImporter >> parseCommitsResult: result [ + + | reader | + reader := NeoJSONReader on: result readStream. + + reader for: GLHCommit do: [ :mapping | + mapping mapInstVar: #id to: #sha. + mapping mapInstVar: #web_url to: #html_url. + mapping + mapProperty: #commit + getter: [ :object | #ignore ] + setter: [ :glhCommit :value | + glhCommit message: (value at: #message) ]. + (mapping mapInstVar: #parent_ids) valueSchema: #ArrayOfIds ]. + + reader for: DateAndTime customDo: [ :mapping | + mapping decoder: [ :string | DateAndTime fromString: string ] ]. + + reader for: #ArrayOfIds customDo: [ :mapping | + mapping decoder: [ :parents | + parents collect: [ :parent | parent at: #sha ] ] ]. + + reader + for: #ArrayOfCommit + customDo: [ :customMappting | + customMappting listOfElementSchema: GLHCommit ]. + + ^ reader nextAs: #ArrayOfCommit +] + { #category : 'private' } GHModelImporter >> parseFileTreeResult: aResult [ diff --git a/src/GitLabHealth-Model-Extension/GLHCommit.extension.st b/src/GitLabHealth-Model-Extension/GLHCommit.extension.st index 54b169c..aca7182 100644 --- a/src/GitLabHealth-Model-Extension/GLHCommit.extension.st +++ b/src/GitLabHealth-Model-Extension/GLHCommit.extension.st @@ -1,6 +1,6 @@ -Extension { #name : #GLHCommit } +Extension { #name : 'GLHCommit' } -{ #category : #'*GitLabHealth-Model-Extension' } +{ #category : '*GitLabHealth-Model-Extension' } GLHCommit >> computeChurnForMaxCommits: aLimit [ ^ GitAnalyzer new @@ -9,16 +9,16 @@ GLHCommit >> computeChurnForMaxCommits: aLimit [ analyseChurn ] -{ #category : #'*GitLabHealth-Model-Extension' } +{ #category : '*GitLabHealth-Model-Extension' } GLHCommit >> displayStringOn: aStream [ aStream - << self short_id; + << (self short_id ifNil: [ self id first: 7 ]); << ' '; << self message ] -{ #category : #'*GitLabHealth-Model-Extension' } +{ #category : '*GitLabHealth-Model-Extension' } GLHCommit >> inspectionGLHCommitChildren [ @@ -28,7 +28,7 @@ GLHCommit >> inspectionGLHCommitChildren [ ^ canvas asPresenter ] -{ #category : #'*GitLabHealth-Model-Extension' } +{ #category : '*GitLabHealth-Model-Extension' } GLHCommit >> inspectionGLHCommitFileImpacts [ @@ -38,12 +38,12 @@ GLHCommit >> inspectionGLHCommitFileImpacts [ ^ canvas asPresenter ] -{ #category : #'*GitLabHealth-Model-Extension' } +{ #category : '*GitLabHealth-Model-Extension' } GLHCommit >> name [ ^ message ifNil: [ 'Commit#' , short_id ] ] -{ #category : #'*GitLabHealth-Model-Extension' } +{ #category : '*GitLabHealth-Model-Extension' } GLHCommit >> parent_ids [ ^ parent_ids diff --git a/src/GitLabHealth-Model-Extension/GLHDiff.extension.st b/src/GitLabHealth-Model-Extension/GLHDiff.extension.st index 1b10673..c07313d 100644 --- a/src/GitLabHealth-Model-Extension/GLHDiff.extension.st +++ b/src/GitLabHealth-Model-Extension/GLHDiff.extension.st @@ -1,6 +1,6 @@ -Extension { #name : #GLHDiff } +Extension { #name : 'GLHDiff' } -{ #category : #'*GitLabHealth-Model-Extension' } +{ #category : '*GitLabHealth-Model-Extension' } GLHDiff >> name [ diff --git a/src/GitLabHealth-Model-Extension/GLHFile.extension.st b/src/GitLabHealth-Model-Extension/GLHFile.extension.st index efea138..035f4b3 100644 --- a/src/GitLabHealth-Model-Extension/GLHFile.extension.st +++ b/src/GitLabHealth-Model-Extension/GLHFile.extension.st @@ -1,6 +1,6 @@ -Extension { #name : #GLHFile } +Extension { #name : 'GLHFile' } -{ #category : #'*GitLabHealth-Model-Extension' } +{ #category : '*GitLabHealth-Model-Extension' } GLHFile >> path [ ^ (self directoryOwner diff --git a/src/GitLabHealth-Model-Extension/GLHUser.extension.st b/src/GitLabHealth-Model-Extension/GLHUser.extension.st index 9d6e6c2..8e949b4 100644 --- a/src/GitLabHealth-Model-Extension/GLHUser.extension.st +++ b/src/GitLabHealth-Model-Extension/GLHUser.extension.st @@ -1,6 +1,6 @@ -Extension { #name : #GLHUser } +Extension { #name : 'GLHUser' } -{ #category : #'*GitLabHealth-Model-Extension' } +{ #category : '*GitLabHealth-Model-Extension' } GLHUser >> computeCommitFrequencyOver: aDateWeekMonthOrYear [ | orderedCommits | @@ -17,7 +17,7 @@ GLHUser >> computeCommitFrequencyOver: aDateWeekMonthOrYear [ overA: aDateWeekMonthOrYear ] -{ #category : #'*GitLabHealth-Model-Extension' } +{ #category : '*GitLabHealth-Model-Extension' } GLHUser >> computeCommitFrequencySince: since until: until overA: aDateWeekMonthOrYear [ ^ GitMetric4User new diff --git a/src/GitLabHealth-Model-Extension/MooseAbstractGroup.extension.st b/src/GitLabHealth-Model-Extension/MooseAbstractGroup.extension.st index 808b195..45e17e2 100644 --- a/src/GitLabHealth-Model-Extension/MooseAbstractGroup.extension.st +++ b/src/GitLabHealth-Model-Extension/MooseAbstractGroup.extension.st @@ -1,13 +1,13 @@ -Extension { #name : #MooseAbstractGroup } +Extension { #name : 'MooseAbstractGroup' } -{ #category : #'*GitLabHealth-Model-Extension' } +{ #category : '*GitLabHealth-Model-Extension' } MooseAbstractGroup >> add: anElmt unless: aConditionAsBlock [ "()>>>" ^ (self addAll: { anElmt } unless: aConditionAsBlock) first ] -{ #category : #'*GitLabHealth-Model-Extension' } +{ #category : '*GitLabHealth-Model-Extension' } MooseAbstractGroup >> addAll: anElmtCollection ofType: aType unless: aConditionAsBlock [ | originalCollection returnCollection | @@ -27,7 +27,7 @@ MooseAbstractGroup >> addAll: anElmtCollection ofType: aType unless: aConditionA ^ returnCollection ] -{ #category : #'*GitLabHealth-Model-Extension' } +{ #category : '*GitLabHealth-Model-Extension' } MooseAbstractGroup >> addAll: anElmtCollection unless: aConditionAsBlock [ "()>>>" diff --git a/src/GitLabHealth-Model-Extension/OrderedCollection.extension.st b/src/GitLabHealth-Model-Extension/OrderedCollection.extension.st index db53bb8..eb0356a 100644 --- a/src/GitLabHealth-Model-Extension/OrderedCollection.extension.st +++ b/src/GitLabHealth-Model-Extension/OrderedCollection.extension.st @@ -1,13 +1,13 @@ -Extension { #name : #OrderedCollection } +Extension { #name : 'OrderedCollection' } -{ #category : #'*GitLabHealth-Model-Extension' } +{ #category : '*GitLabHealth-Model-Extension' } OrderedCollection >> add: anElmt unless: aConditionAsBlock [ "()>>>" ^ (self addAll: { anElmt } unless: aConditionAsBlock) first ] -{ #category : #'*GitLabHealth-Model-Extension' } +{ #category : '*GitLabHealth-Model-Extension' } OrderedCollection >> addAll: anElmtCollection unless: aConditionAsBlock [ | returnCollection | diff --git a/src/GitLabHealth-Model-Extension/package.st b/src/GitLabHealth-Model-Extension/package.st index e602c9d..07d8ed2 100644 --- a/src/GitLabHealth-Model-Extension/package.st +++ b/src/GitLabHealth-Model-Extension/package.st @@ -1 +1 @@ -Package { #name : #'GitLabHealth-Model-Extension' } +Package { #name : 'GitLabHealth-Model-Extension' } From 25735e8b42d679a188928ba74ae9617e839108dd Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Sun, 15 Sep 2024 10:44:44 +0200 Subject: [PATCH 108/154] add the parsed commits of GitHub in the model --- .../GHModelImporter.class.st | 10 +++++++++- src/GitLabHealth-Visualization/RSCommit.class.st | 6 ++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/GitHubHealth-Model-Importer/GHModelImporter.class.st b/src/GitHubHealth-Model-Importer/GHModelImporter.class.st index bfee1c7..ddfbf1a 100644 --- a/src/GitHubHealth-Model-Importer/GHModelImporter.class.st +++ b/src/GitHubHealth-Model-Importer/GHModelImporter.class.st @@ -80,7 +80,15 @@ GHModelImporter >> importCommitsOfProject: aGLHProject [ commitsResult := self api commitsOfProject: aGLHProject name ofOrganization: aGLHProject group name. - commits := self parseCommitsResult: commitsResult + commits := self parseCommitsResult: commitsResult. + "add the imported commits (unless they are already added to this repository)" + aGLHProject repository commits + addAll: commits + unless: [ :existing :new | existing id = new id ]. + "add the imported commits to the model unles they are already added to the model" + ^ self glhModel + addAll: commits + unless: [ :existing :new | existing id = new id ] ] { #category : 'api' } diff --git a/src/GitLabHealth-Visualization/RSCommit.class.st b/src/GitLabHealth-Visualization/RSCommit.class.st index 3dc16e1..c328651 100644 --- a/src/GitLabHealth-Visualization/RSCommit.class.st +++ b/src/GitLabHealth-Visualization/RSCommit.class.st @@ -407,8 +407,10 @@ RSCommit >> shapeForCommit: aGLHCommit withColor: color [ yourself. labelCommiter := RSLabel new - text: 'by ', - (aGLHCommit author_name truncateWithElipsisTo: 50); + text: 'by ' , (aGLHCommit author_name + ifNil: [ 'unknown' ] + ifNotNil: [ :authorName | + authorName truncateWithElipsisTo: 50 ]); yourself. box := RSBox new From 05af8d43a791c8d3d0934018a5ea5d92d5b81998 Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Sun, 15 Sep 2024 11:31:25 +0200 Subject: [PATCH 109/154] add simple import of users --- .../GHModelImporterTest.class.st | 4 +- .../GHApi.class.st | 6 +++ .../GHModelImporter.class.st | 53 ++++++++++++++++++- 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/src/GitHubHealth-Model-Importer-Tests/GHModelImporterTest.class.st b/src/GitHubHealth-Model-Importer-Tests/GHModelImporterTest.class.st index 8623193..3e11684 100644 --- a/src/GitHubHealth-Model-Importer-Tests/GHModelImporterTest.class.st +++ b/src/GitHubHealth-Model-Importer-Tests/GHModelImporterTest.class.st @@ -20,7 +20,7 @@ GHModelImporterTest >> setUp [ { #category : 'tests' } GHModelImporterTest >> testParseCommitsResult [ - + "we remove the id of author entries to not trigger the call to import user" | commits | commits := importer parseCommitsResult: '[ { @@ -56,7 +56,6 @@ GHModelImporterTest >> testParseCommitsResult [ "comments_url": "https://api.github.com/repos/moosetechnology/Moose/commits/f5ac58f4afe4632b0a26d1e968439c78962da289/comments", "author": { "login": "ClotildeToullec", - "id": 39184695, "node_id": "MDQ6VXNlcjM5MTg0Njk1", "avatar_url": "https://avatars.githubusercontent.com/u/39184695?v=4", "gravatar_id": "", @@ -135,7 +134,6 @@ GHModelImporterTest >> testParseCommitsResult [ "comments_url": "https://api.github.com/repos/moosetechnology/Moose/commits/eb31d04f01254d0caf7c7a5b03546e3f6a5c3d58/comments", "author": { "login": "ClotildeToullec", - "id": 39184695, "node_id": "MDQ6VXNlcjM5MTg0Njk1", "avatar_url": "https://avatars.githubusercontent.com/u/39184695?v=4", "gravatar_id": "", diff --git a/src/GitHubHealth-Model-Importer/GHApi.class.st b/src/GitHubHealth-Model-Importer/GHApi.class.st index 7f35630..b18d9b1 100644 --- a/src/GitHubHealth-Model-Importer/GHApi.class.st +++ b/src/GitHubHealth-Model-Importer/GHApi.class.st @@ -103,3 +103,9 @@ GHApi >> reposOfOrganization: anOrganizationName [ ^ self client get: self baseAPIUrl , '/orgs/' , anOrganizationName, '/repos' ] + +{ #category : 'api - users' } +GHApi >> user: aUserID [ + + ^ self client get: self baseAPIUrl , '/user/' , aUserID asString +] diff --git a/src/GitHubHealth-Model-Importer/GHModelImporter.class.st b/src/GitHubHealth-Model-Importer/GHModelImporter.class.st index ddfbf1a..5445b19 100644 --- a/src/GitHubHealth-Model-Importer/GHModelImporter.class.st +++ b/src/GitHubHealth-Model-Importer/GHModelImporter.class.st @@ -171,6 +171,21 @@ GHModelImporter >> importRepositoriesOfGroup: groupResult [ ^ groupResult ] +{ #category : 'api' } +GHModelImporter >> importUser: userID [ + + | result userResult | + (glhModel allWithType: GLHUser) + detect: [ :user | user id = userID ] + ifFound: [ :user | ^ user ]. + ('Import user: ' , userID printString) recordInfo. + result := self api user: userID. + userResult := self parseUserResult: result. + ^ glhModel + add: userResult + unless: [ :current :new | current id = new id ] +] + { #category : 'initialization' } GHModelImporter >> initialize [ @@ -225,7 +240,25 @@ GHModelImporter >> parseCommitsResult: result [ getter: [ :object | #ignore ] setter: [ :glhCommit :value | glhCommit message: (value at: #message) ]. - (mapping mapInstVar: #parent_ids) valueSchema: #ArrayOfIds ]. + + mapping + mapProperty: #author + getter: [ :object | #ignore ] + setter: [ :glhCommit :value | + glhCommit author_name: (value at: #login). + value + at: #id + ifPresent: [ :authorId | + glhCommit commitCreator: (self importUser: authorId) ] ]. + + mapping + mapProperty: #committer + getter: [ :object | #ignore ] + setter: [ :glhCommit :value | + glhCommit committer_name: (value at: #login) ]. + + (mapping mapInstVar: #parent_ids to: #parents) valueSchema: + #ArrayOfIds ]. reader for: DateAndTime customDo: [ :mapping | mapping decoder: [ :string | DateAndTime fromString: string ] ]. @@ -290,6 +323,24 @@ GHModelImporter >> parsePipelinesResult: pipelineOverview [ ^ reader nextAs: GHAPIPipelineOverview ] +{ #category : 'parsing' } +GHModelImporter >> parseUserResult: result [ + + | reader | + reader := NeoJSONReader on: result readStream. + reader for: GLHUser do: [ :mapping | + mapping mapInstVar: #id to: #id. + mapping mapInstVar: #public_email to: #email. + mapping mapInstVar: #username to: #login. + mapping mapInstVar: #bio to: #bio. + mapping mapInstVar: #organization to: #company. + mapping mapInstVar: #followers to: #followers. + mapping mapInstVar: #following to: #following. + mapping mapInstVar: #web_url to: #html_url. + mapping mapInstVar: #avatar_url to: #avatar_url ]. + ^ reader nextAs: GLHUser +] + { #category : 'api' } GHModelImporter >> privateToken [ ^ self api privateToken From 05b07e7ea93865d819bb62da3a11409e893ae6ec Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Sun, 15 Sep 2024 11:33:43 +0200 Subject: [PATCH 110/154] add a test for parseUserResult --- .../GHModelImporterTest.class.st | 45 +++++++++++++++++++ .../GHModelImporter.class.st | 1 + 2 files changed, 46 insertions(+) diff --git a/src/GitHubHealth-Model-Importer-Tests/GHModelImporterTest.class.st b/src/GitHubHealth-Model-Importer-Tests/GHModelImporterTest.class.st index 3e11684..b7ec943 100644 --- a/src/GitHubHealth-Model-Importer-Tests/GHModelImporterTest.class.st +++ b/src/GitHubHealth-Model-Importer-Tests/GHModelImporterTest.class.st @@ -206,3 +206,48 @@ GHModelImporterTest >> testParsePipelinesResult [ assert: project workflow_runs anyOne runDate equals: (DateAndTime year: 2024 month: 01 day: 11) ] + +{ #category : 'tests' } +GHModelImporterTest >> testParseUserResult [ + + | user | + user := importer parseUserResult: '{ + "login": "ClotildeToullec", + "id": 39184695, + "node_id": "MDQ6VXNlcjM5MTg0Njk1", + "avatar_url": "https://avatars.githubusercontent.com/u/39184695?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ClotildeToullec", + "html_url": "https://github.com/ClotildeToullec", + "followers_url": "https://api.github.com/users/ClotildeToullec/followers", + "following_url": "https://api.github.com/users/ClotildeToullec/following{/other_user}", + "gists_url": "https://api.github.com/users/ClotildeToullec/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ClotildeToullec/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ClotildeToullec/subscriptions", + "organizations_url": "https://api.github.com/users/ClotildeToullec/orgs", + "repos_url": "https://api.github.com/users/ClotildeToullec/repos", + "events_url": "https://api.github.com/users/ClotildeToullec/events{/privacy}", + "received_events_url": "https://api.github.com/users/ClotildeToullec/received_events", + "type": "User", + "site_admin": false, + "name": "Clotilde Toullec", + "company": "Inria", + "blog": "", + "location": "Villeneuve d''Ascq", + "email": null, + "hireable": null, + "bio": "Software engineer at Inria Lille, France\r\nMaintainer and developer of @moosetechnology ", + "twitter_username": null, + "public_repos": 35, + "public_gists": 0, + "followers": 11, + "following": 2, + "created_at": "2018-05-11T07:52:42Z", + "updated_at": "2024-08-26T08:29:32Z" +} +'. + + self assert: user name equals: 'Clotilde Toullec'. + + self assert: user id equals: 39184695 +] diff --git a/src/GitHubHealth-Model-Importer/GHModelImporter.class.st b/src/GitHubHealth-Model-Importer/GHModelImporter.class.st index 5445b19..58b9788 100644 --- a/src/GitHubHealth-Model-Importer/GHModelImporter.class.st +++ b/src/GitHubHealth-Model-Importer/GHModelImporter.class.st @@ -337,6 +337,7 @@ GHModelImporter >> parseUserResult: result [ mapping mapInstVar: #followers to: #followers. mapping mapInstVar: #following to: #following. mapping mapInstVar: #web_url to: #html_url. + mapping mapInstVar: #name to: #name. mapping mapInstVar: #avatar_url to: #avatar_url ]. ^ reader nextAs: GLHUser ] From f5384a57d49d61c8f97d8eb99471da0868a0383e Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Sun, 15 Sep 2024 11:42:10 +0200 Subject: [PATCH 111/154] deal with some strange null value --- .../GHModelImporterTest.class.st | 52 +++++++++++++++++++ .../GHModelImporter.class.st | 16 +++--- 2 files changed, 60 insertions(+), 8 deletions(-) diff --git a/src/GitHubHealth-Model-Importer-Tests/GHModelImporterTest.class.st b/src/GitHubHealth-Model-Importer-Tests/GHModelImporterTest.class.st index b7ec943..56f0b1e 100644 --- a/src/GitHubHealth-Model-Importer-Tests/GHModelImporterTest.class.st +++ b/src/GitHubHealth-Model-Importer-Tests/GHModelImporterTest.class.st @@ -186,6 +186,58 @@ GHModelImporterTest >> testParseCommitsResult [ self assert: commits second message equals: 'Update release.yml'. ] +{ #category : 'tests' } +GHModelImporterTest >> testParseCommitsResultWithSomeNullValue [ + "we remove the id of author entries to not trigger the call to import user" + + | commits | + commits := importer parseCommitsResult: '[ +{ + "sha": "f566f11d4bb045e5ab762fb430655f3d218bd784", + "node_id": "C_kwDOCCsKwdoAKGY1NjZmMTFkNGJiMDQ1ZTVhYjc2MmZiNDMwNjU1ZjNkMjE4YmQ3ODQ", + "commit": { + "author": { + "name": "anquetil", + "email": "nicolas.anquetil@inria.fr", + "date": "2024-02-22T14:09:56Z" + }, + "committer": { + "name": "anquetil", + "email": "nicolas.anquetil@inria.fr", + "date": "2024-02-22T14:09:56Z" + }, + "message": "A generator for a copy visitor (ie. a visitor that creates a copy of an AST", + "tree": { + "sha": "29b55107b0378ae3668b984a688d1e1cbd6062d4", + "url": "https://api.github.com/repos/moosetechnology/FAST/git/trees/29b55107b0378ae3668b984a688d1e1cbd6062d4" + }, + "url": "https://api.github.com/repos/moosetechnology/FAST/git/commits/f566f11d4bb045e5ab762fb430655f3d218bd784", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null + } + }, + "url": "https://api.github.com/repos/moosetechnology/FAST/commits/f566f11d4bb045e5ab762fb430655f3d218bd784", + "html_url": "https://github.com/moosetechnology/FAST/commit/f566f11d4bb045e5ab762fb430655f3d218bd784", + "comments_url": "https://api.github.com/repos/moosetechnology/FAST/commits/f566f11d4bb045e5ab762fb430655f3d218bd784/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "bfd5bfcb6cafe10be0cf58ff5eb22d26df809eaa", + "url": "https://api.github.com/repos/moosetechnology/FAST/commits/bfd5bfcb6cafe10be0cf58ff5eb22d26df809eaa", + "html_url": "https://github.com/moosetechnology/FAST/commit/bfd5bfcb6cafe10be0cf58ff5eb22d26df809eaa" + } + ] + } +]'. + + self assert: commits size equals: 1 +] + { #category : 'test' } GHModelImporterTest >> testParsePipelinesResult [ diff --git a/src/GitHubHealth-Model-Importer/GHModelImporter.class.st b/src/GitHubHealth-Model-Importer/GHModelImporter.class.st index 58b9788..d32a21b 100644 --- a/src/GitHubHealth-Model-Importer/GHModelImporter.class.st +++ b/src/GitHubHealth-Model-Importer/GHModelImporter.class.st @@ -2,8 +2,7 @@ Class { #name : 'GHModelImporter', #superclass : 'GPModelImporter', #instVars : [ - 'api', - 'glhModel' + 'api' ], #category : 'GitHubHealth-Model-Importer', #package : 'GitHubHealth-Model-Importer' @@ -245,17 +244,18 @@ GHModelImporter >> parseCommitsResult: result [ mapProperty: #author getter: [ :object | #ignore ] setter: [ :glhCommit :value | - glhCommit author_name: (value at: #login). - value - at: #id - ifPresent: [ :authorId | - glhCommit commitCreator: (self importUser: authorId) ] ]. + value ifNotNil: [ + glhCommit author_name: (value at: #login). + value + at: #id + ifPresent: [ :authorId | + glhCommit commitCreator: (self importUser: authorId) ] ] ]. mapping mapProperty: #committer getter: [ :object | #ignore ] setter: [ :glhCommit :value | - glhCommit committer_name: (value at: #login) ]. + value ifNotNil: [ glhCommit committer_name: (value at: #login) ] ]. (mapping mapInstVar: #parent_ids to: #parents) valueSchema: #ArrayOfIds ]. From a754018fb8b4f43b3f23ffabf44b88e5ab5f2cbc Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Sun, 15 Sep 2024 11:42:36 +0200 Subject: [PATCH 112/154] make glhModel generic and reuse chainsCommitsFrom: --- .../GHModelImporter.class.st | 16 ++------ .../GLHModelImporter.class.st | 13 ------- .../GLPHModelImporter.class.st | 22 ----------- .../GPModelImporter.class.st | 37 ++++++++++++++++++- 4 files changed, 39 insertions(+), 49 deletions(-) diff --git a/src/GitHubHealth-Model-Importer/GHModelImporter.class.st b/src/GitHubHealth-Model-Importer/GHModelImporter.class.st index d32a21b..29a71b5 100644 --- a/src/GitHubHealth-Model-Importer/GHModelImporter.class.st +++ b/src/GitHubHealth-Model-Importer/GHModelImporter.class.st @@ -26,7 +26,9 @@ GHModelImporter >> completeImportProject: aGLHProject [ self importPipelinesOf: aGLHProject. self importBranchesOf: aGLHProject. self withCommitsSince ifNotNil: [ :withCommitSince | "If not nil, it means we have to import commit" - self importCommitsOfProject: aGLHProject ] + | commits | + commits := self importCommitsOfProject: aGLHProject. + self chainsCommitsFrom: commits ] ] { #category : 'private' } @@ -41,18 +43,6 @@ GHModelImporter >> convertApiFileAsFile: aAPIFile [ yourself ] -{ #category : 'accessing' } -GHModelImporter >> glhModel [ - - ^ glhModel -] - -{ #category : 'accessing' } -GHModelImporter >> glhModel: anObject [ - - glhModel := anObject -] - { #category : 'api' } GHModelImporter >> importBranchesOf: project [ diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index 529c1e3..cfff37c 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -2,7 +2,6 @@ Class { #name : 'GLHModelImporter', #superclass : 'GPModelImporter', #instVars : [ - 'glhModel', 'glhApi', 'withCommitDiffs', 'withInitialCommits', @@ -221,18 +220,6 @@ GLHModelImporter >> glhApi: anObject [ glhApi := anObject ] -{ #category : 'accessing' } -GLHModelImporter >> glhModel [ - - ^ glhModel -] - -{ #category : 'accessing' } -GLHModelImporter >> glhModel: anObject [ - - glhModel := anObject -] - { #category : 'api' } GLHModelImporter >> importAllGroups [ diff --git a/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st b/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st index f0f165a..df51341 100644 --- a/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st +++ b/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st @@ -14,28 +14,6 @@ GLPHModelImporter >> blockForDiffRangeEquality [ existing newLineRange = new newLineRange ] ] ] ] -{ #category : 'commit' } -GLPHModelImporter >> chainsCommitsFrom: commitsCollection [ - - | dic | - - ('Chains ', commitsCollection size printString , ' commits') recordInfo. - - dic := ((self glhModel allWithType: GLHCommit) collect: [ :commit | - commit id -> commit ]) asSet asDictionary. - - commitsCollection do: [ :commit | - commit parent_ids do: [ :parentId | - dic - at: parentId - ifPresent: [ :parentCommit | - parentCommit childCommits - add: commit - unless: self blockOnIdEquality ] - ifAbsent: [ ] ] ]. - ^ commitsCollection -] - { #category : 'commit' } GLPHModelImporter >> commitsOfProject: aGLHProject forRefName: refName until: toDate [ diff --git a/src/GitProjectHealth-Model-Importer/GPModelImporter.class.st b/src/GitProjectHealth-Model-Importer/GPModelImporter.class.st index b88e291..1fdc96d 100644 --- a/src/GitProjectHealth-Model-Importer/GPModelImporter.class.st +++ b/src/GitProjectHealth-Model-Importer/GPModelImporter.class.st @@ -9,7 +9,8 @@ Class { #superclass : 'Object', #instVars : [ 'withCommitsSince', - 'withFiles' + 'withFiles', + 'glhModel' ], #category : 'GitProjectHealth-Model-Importer', #package : 'GitProjectHealth-Model-Importer' @@ -27,6 +28,40 @@ GPModelImporter >> beWithoutFiles [ withFiles := false ] +{ #category : 'commit' } +GPModelImporter >> chainsCommitsFrom: commitsCollection [ + + | dic | + ('Chains ' , commitsCollection size printString , ' commits') + recordInfo. + + dic := ((self glhModel allWithType: GLHCommit) collect: [ :commit | + commit id -> commit ]) asSet asDictionary. + + commitsCollection do: [ :commit | + commit parent_ids do: [ :parentId | + dic + at: parentId + ifPresent: [ :parentCommit | + parentCommit childCommits + add: commit + unless: [ :existing :new | existing id = new id ] ] + ifAbsent: [ ] ] ]. + ^ commitsCollection +] + +{ #category : 'accessing' } +GPModelImporter >> glhModel [ + + ^ glhModel +] + +{ #category : 'accessing' } +GPModelImporter >> glhModel: anObject [ + + glhModel := anObject +] + { #category : 'initialization' } GPModelImporter >> initialize [ From 658f0e8a256eb7517834e3f472424ca3fe9b4c6b Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Sun, 15 Sep 2024 12:09:18 +0200 Subject: [PATCH 113/154] + can import commits since a date + add tests to ensure we get the date of each commit --- .../GHModelImporterTest.class.st | 7 +++- .../GHApi.class.st | 22 ++++++++-- .../GHModelImporter.class.st | 42 +++++++++++++++---- 3 files changed, 59 insertions(+), 12 deletions(-) diff --git a/src/GitHubHealth-Model-Importer-Tests/GHModelImporterTest.class.st b/src/GitHubHealth-Model-Importer-Tests/GHModelImporterTest.class.st index 56f0b1e..5380c10 100644 --- a/src/GitHubHealth-Model-Importer-Tests/GHModelImporterTest.class.st +++ b/src/GitHubHealth-Model-Importer-Tests/GHModelImporterTest.class.st @@ -21,6 +21,7 @@ GHModelImporterTest >> setUp [ { #category : 'tests' } GHModelImporterTest >> testParseCommitsResult [ "we remove the id of author entries to not trigger the call to import user" + | commits | commits := importer parseCommitsResult: '[ { @@ -182,8 +183,12 @@ GHModelImporterTest >> testParseCommitsResult [ ]'. self assert: commits size equals: 2. - self assert: commits first message equals: 'Update test-and-release.yml'. + self + assert: commits first message + equals: 'Update test-and-release.yml'. self assert: commits second message equals: 'Update release.yml'. + self assert: commits first authored_date isNotNil. + self assert: commits first committed_date isNotNil ] { #category : 'tests' } diff --git a/src/GitHubHealth-Model-Importer/GHApi.class.st b/src/GitHubHealth-Model-Importer/GHApi.class.st index b18d9b1..9ec875b 100644 --- a/src/GitHubHealth-Model-Importer/GHApi.class.st +++ b/src/GitHubHealth-Model-Importer/GHApi.class.st @@ -56,9 +56,25 @@ GHApi >> client: anObject [ { #category : 'api - commits' } GHApi >> commitsOfProject: aProjectId ofOrganization: organisationName [ - ^ self client get: - self baseAPIUrl , '/repos/' , organisationName , '/' , aProjectId - , '/commits' + ^ self + commitsOfProject: aProjectId + ofOrganization: organisationName + since: nil + perPage: nil + page: nil +] + +{ #category : 'api - commits' } +GHApi >> commitsOfProject: aProjectId ofOrganization: organisationName since: aSinceDate perPage: itemPerPage page: pageNumber [ + + self client url: + self baseAPIUrl , '/repos/' , organisationName , '/' , aProjectId + , '/commits'. + aSinceDate ifNotNil: [ self client queryAt: #since put: aSinceDate ]. + itemPerPage ifNotNil: [ + self client queryAt: #per_page put: itemPerPage ]. + pageNumber ifNotNil: [ self client queryAt: #page put: pageNumber ]. + ^ self client get ] { #category : 'api' } diff --git a/src/GitHubHealth-Model-Importer/GHModelImporter.class.st b/src/GitHubHealth-Model-Importer/GHModelImporter.class.st index 29a71b5..cf3a484 100644 --- a/src/GitHubHealth-Model-Importer/GHModelImporter.class.st +++ b/src/GitHubHealth-Model-Importer/GHModelImporter.class.st @@ -65,18 +65,40 @@ GHModelImporter >> importBranchesOf: project [ { #category : 'api' } GHModelImporter >> importCommitsOfProject: aGLHProject [ - | commitsResult commits | - commitsResult := self api - commitsOfProject: aGLHProject name - ofOrganization: aGLHProject group name. - commits := self parseCommitsResult: commitsResult. + | itemByPage foundCommits tmp pageNumber | + itemByPage := 100. + pageNumber := 1. + ('Extract all commits of ' , aGLHProject name) recordInfo. + foundCommits := OrderedCollection new. + ('Extract commits from ' , foundCommits size printString , ' to ' + , (foundCommits size + itemByPage) printString) recordInfo. + tmp := self parseCommitsResult: (self api + commitsOfProject: aGLHProject name + ofOrganization: aGLHProject group name + since: self withCommitsSince + perPage: itemByPage + page: pageNumber). + + foundCommits addAll: tmp. + [ tmp size = itemByPage ] whileTrue: [ + pageNumber := pageNumber + 1. + ('Extract issues from ' , foundCommits size printString , ' to ' + , (foundCommits size + itemByPage) printString) recordInfo. + tmp := self parseCommitsResult: (self api + commitsOfProject: aGLHProject name + ofOrganization: aGLHProject group name + since: self withCommitsSince + perPage: itemByPage + page: pageNumber). + foundCommits addAll: tmp ]. + "add the imported commits (unless they are already added to this repository)" aGLHProject repository commits - addAll: commits + addAll: foundCommits unless: [ :existing :new | existing id = new id ]. "add the imported commits to the model unles they are already added to the model" ^ self glhModel - addAll: commits + addAll: foundCommits unless: [ :existing :new | existing id = new id ] ] @@ -228,7 +250,11 @@ GHModelImporter >> parseCommitsResult: result [ mapProperty: #commit getter: [ :object | #ignore ] setter: [ :glhCommit :value | - glhCommit message: (value at: #message) ]. + glhCommit message: (value at: #message). + glhCommit authored_date: + (DateAndTime fromString: (value at: #author at: #date)). + glhCommit committed_date: + (DateAndTime fromString: (value at: #committer at: #date)) ]. mapping mapProperty: #author From 39a95d59e58db56a1acce323c94ebe6ea817d828 Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Sun, 15 Sep 2024 12:25:05 +0200 Subject: [PATCH 114/154] really import all projects of an organization --- .../GHApi.class.st | 15 +++++++++-- .../GHModelImporter.class.st | 26 +++++++++++++++++-- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/GitHubHealth-Model-Importer/GHApi.class.st b/src/GitHubHealth-Model-Importer/GHApi.class.st index 9ec875b..d43f5a9 100644 --- a/src/GitHubHealth-Model-Importer/GHApi.class.st +++ b/src/GitHubHealth-Model-Importer/GHApi.class.st @@ -114,10 +114,21 @@ GHApi >> privateToken: anObject [ self client headerAt: #'Authorization' add: ('token ', anObject) ] -{ #category : 'api' } +{ #category : 'api - repositories' } GHApi >> reposOfOrganization: anOrganizationName [ - ^ self client get: self baseAPIUrl , '/orgs/' , anOrganizationName, '/repos' + ^ self reposOfOrganization: anOrganizationName perPage: nil page: nil +] + +{ #category : 'api - repositories' } +GHApi >> reposOfOrganization: anOrganizationName perPage: itemPerPage page: pageNumber [ + + self client url: + self baseAPIUrl , '/orgs/' , anOrganizationName , '/repos'. + itemPerPage ifNotNil: [ + self client queryAt: #per_page put: itemPerPage ]. + pageNumber ifNotNil: [ self client queryAt: #page put: pageNumber ]. + ^ self client get ] { #category : 'api - users' } diff --git a/src/GitHubHealth-Model-Importer/GHModelImporter.class.st b/src/GitHubHealth-Model-Importer/GHModelImporter.class.st index cf3a484..d3ab046 100644 --- a/src/GitHubHealth-Model-Importer/GHModelImporter.class.st +++ b/src/GitHubHealth-Model-Importer/GHModelImporter.class.st @@ -173,9 +173,31 @@ GHModelImporter >> importPipelinesOf: project [ { #category : 'api' } GHModelImporter >> importRepositoriesOfGroup: groupResult [ - | reposResult | + | reposResult itemByPage pageNumber reposFound tmp | + itemByPage := 100. + pageNumber := 1. + ('Extract all repository of ' , groupResult name) recordInfo. + reposFound := OrderedCollection new. + ('Extract commits from ' , reposFound size printString , ' to ' + , (reposFound size + itemByPage) printString) recordInfo. + tmp := self parseArrayOfProject: (self api + reposOfOrganization: groupResult name + perPage: itemByPage + page: pageNumber). + + reposFound addAll: tmp. + [ tmp size = itemByPage ] whileTrue: [ + pageNumber := pageNumber + 1. + ('Extract issues from ' , reposFound size printString , ' to ' + , (reposFound size + itemByPage) printString) recordInfo. + tmp := self parseArrayOfProject: (self api + reposOfOrganization: groupResult name + perPage: itemByPage + page: pageNumber). + reposFound addAll: tmp ]. + reposResult := self api reposOfOrganization: groupResult name. - groupResult projects addAll: (self parseArrayOfProject: reposResult). + groupResult projects addAll: reposFound. self glhModel addAll: groupResult projects. groupResult projects do: [ :project | self completeImportProject: project ]. From a5fe468b1929dba1b3c338c682aa40583d7c9ead Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Sun, 15 Sep 2024 12:47:58 +0200 Subject: [PATCH 115/154] add visualization of commits by date --- .../GLHGroupCSVExporter.class.st | 17 +++++---- .../GLHGroupGroup.extension.st | 4 +- .../GLHGroupVisualization.class.st | 29 ++++++++------- .../GLHProject.extension.st | 6 +-- .../GLHRepository.extension.st | 12 ++++++ ...ryCommitDistributionVisualization.class.st | 37 +++++++++++++++++++ .../package.st | 2 +- 7 files changed, 79 insertions(+), 28 deletions(-) create mode 100644 src/GitLabHealth-Model-Visualization/GLHRepository.extension.st create mode 100644 src/GitLabHealth-Model-Visualization/GLHRepositoryCommitDistributionVisualization.class.st diff --git a/src/GitLabHealth-Model-Visualization/GLHGroupCSVExporter.class.st b/src/GitLabHealth-Model-Visualization/GLHGroupCSVExporter.class.st index b8d5411..7dabeff 100644 --- a/src/GitLabHealth-Model-Visualization/GLHGroupCSVExporter.class.st +++ b/src/GitLabHealth-Model-Visualization/GLHGroupCSVExporter.class.st @@ -1,17 +1,18 @@ Class { - #name : #GLHGroupCSVExporter, - #superclass : #MiAbstractVisualization, - #category : #'GitLabHealth-Model-Visualization' + #name : 'GLHGroupCSVExporter', + #superclass : 'MiAbstractVisualization', + #category : 'GitLabHealth-Model-Visualization', + #package : 'GitLabHealth-Model-Visualization' } -{ #category : #running } +{ #category : 'running' } GLHGroupCSVExporter >> forGroup: aGLHGroup [ ^String streamContents: [ :output | self headerLineOn: output. self forGroup: aGLHGroup on: output ] ] -{ #category : #running } +{ #category : 'running' } GLHGroupCSVExporter >> forGroup: aGLHGroup on: outputStream [ (aGLHGroup allToScope: GLHGroup) do: [ :group | @@ -20,7 +21,7 @@ GLHGroupCSVExporter >> forGroup: aGLHGroup on: outputStream [ ] ] -{ #category : #running } +{ #category : 'running' } GLHGroupCSVExporter >> forProject: aGHLProject inGroup: aGLHGroup onStream: outputStream [ outputStream @@ -35,7 +36,7 @@ GLHGroupCSVExporter >> forProject: aGHLProject inGroup: aGLHGroup onStream: outp cr ] -{ #category : #running } +{ #category : 'running' } GLHGroupCSVExporter >> headerLineOn: outputStream [ outputStream @@ -43,7 +44,7 @@ GLHGroupCSVExporter >> headerLineOn: outputStream [ cr ] -{ #category : #running } +{ #category : 'running' } GLHGroupCSVExporter >> pipelineResult: aGHLProject [ ^aGHLProject lastPipeline diff --git a/src/GitLabHealth-Model-Visualization/GLHGroupGroup.extension.st b/src/GitLabHealth-Model-Visualization/GLHGroupGroup.extension.st index 0b6395e..fd349ff 100644 --- a/src/GitLabHealth-Model-Visualization/GLHGroupGroup.extension.st +++ b/src/GitLabHealth-Model-Visualization/GLHGroupGroup.extension.st @@ -1,6 +1,6 @@ -Extension { #name : #GLHGroupGroup } +Extension { #name : 'GLHGroupGroup' } -{ #category : #'*GitLabHealth-Model-Visualization' } +{ #category : '*GitLabHealth-Model-Visualization' } GLHGroupGroup >> groupQuality: aBuilder [ diff --git a/src/GitLabHealth-Model-Visualization/GLHGroupVisualization.class.st b/src/GitLabHealth-Model-Visualization/GLHGroupVisualization.class.st index 79cb9bd..cac0e5b 100644 --- a/src/GitLabHealth-Model-Visualization/GLHGroupVisualization.class.st +++ b/src/GitLabHealth-Model-Visualization/GLHGroupVisualization.class.st @@ -1,15 +1,16 @@ Class { - #name : #GLHGroupVisualization, - #superclass : #MiAbstractVisualization, + #name : 'GLHGroupVisualization', + #superclass : 'MiAbstractVisualization', #instVars : [ 'noPipelineColor', 'passingPipelineColor', 'failingPipelinecolor' ], - #category : #'GitLabHealth-Model-Visualization' + #category : 'GitLabHealth-Model-Visualization', + #package : 'GitLabHealth-Model-Visualization' } -{ #category : #running } +{ #category : 'running' } GLHGroupVisualization >> createLegend [ | legend | @@ -34,7 +35,7 @@ GLHGroupVisualization >> createLegend [ ^ legend ] -{ #category : #running } +{ #category : 'running' } GLHGroupVisualization >> createShapeFor: project [ | box inspect | @@ -69,7 +70,7 @@ GLHGroupVisualization >> createShapeFor: project [ ^ box ] -{ #category : #running } +{ #category : 'running' } GLHGroupVisualization >> createShapes: aGLHGroup [ ^(aGLHGroup allToScope: GLHGroup) collect: [ :group || lbl projects composite | @@ -98,19 +99,19 @@ GLHGroupVisualization >> createShapes: aGLHGroup [ ] ] -{ #category : #accessing } +{ #category : 'accessing' } GLHGroupVisualization >> failingPipelinecolor [ ^ failingPipelinecolor ] -{ #category : #accessing } +{ #category : 'accessing' } GLHGroupVisualization >> failingPipelinecolor: anObject [ failingPipelinecolor := anObject ] -{ #category : #running } +{ #category : 'running' } GLHGroupVisualization >> forGroup: aGLHGroups [ | c shapes legend | @@ -141,7 +142,7 @@ GLHGroupVisualization >> forGroup: aGLHGroups [ ^ c ] -{ #category : #initialization } +{ #category : 'initialization' } GLHGroupVisualization >> initialize [ super initialize. @@ -151,25 +152,25 @@ GLHGroupVisualization >> initialize [ failingPipelinecolor := Color red ] -{ #category : #accessing } +{ #category : 'accessing' } GLHGroupVisualization >> noPipelineColor [ ^ noPipelineColor ] -{ #category : #accessing } +{ #category : 'accessing' } GLHGroupVisualization >> noPipelineColor: anObject [ noPipelineColor := anObject ] -{ #category : #accessing } +{ #category : 'accessing' } GLHGroupVisualization >> passingPipelineColor [ ^ passingPipelineColor ] -{ #category : #accessing } +{ #category : 'accessing' } GLHGroupVisualization >> passingPipelineColor: anObject [ passingPipelineColor := anObject diff --git a/src/GitLabHealth-Model-Visualization/GLHProject.extension.st b/src/GitLabHealth-Model-Visualization/GLHProject.extension.st index 32d46ce..9a236d1 100644 --- a/src/GitLabHealth-Model-Visualization/GLHProject.extension.st +++ b/src/GitLabHealth-Model-Visualization/GLHProject.extension.st @@ -1,6 +1,6 @@ -Extension { #name : #GLHProject } +Extension { #name : 'GLHProject' } -{ #category : #'*GitLabHealth-Model-Visualization' } +{ #category : '*GitLabHealth-Model-Visualization' } GLHProject >> lastPipeline [ ^self @@ -14,7 +14,7 @@ GLHProject >> lastPipeline [ ] ] -{ #category : #'*GitLabHealth-Model-Visualization' } +{ #category : '*GitLabHealth-Model-Visualization' } GLHProject >> lastPipelineDate [ ^self diff --git a/src/GitLabHealth-Model-Visualization/GLHRepository.extension.st b/src/GitLabHealth-Model-Visualization/GLHRepository.extension.st new file mode 100644 index 0000000..e515b89 --- /dev/null +++ b/src/GitLabHealth-Model-Visualization/GLHRepository.extension.st @@ -0,0 +1,12 @@ +Extension { #name : 'GLHRepository' } + +{ #category : '*GitLabHealth-Model-Visualization' } +GLHRepository >> rsCommitDistribution: aBuilder [ + + + ^ SpRoassalInspectorPresenter new + canvas: + (GLHRepositoryCommitDistributionVisualization new forRepository: + self); + yourself +] diff --git a/src/GitLabHealth-Model-Visualization/GLHRepositoryCommitDistributionVisualization.class.st b/src/GitLabHealth-Model-Visualization/GLHRepositoryCommitDistributionVisualization.class.st new file mode 100644 index 0000000..22a4261 --- /dev/null +++ b/src/GitLabHealth-Model-Visualization/GLHRepositoryCommitDistributionVisualization.class.st @@ -0,0 +1,37 @@ +Class { + #name : 'GLHRepositoryCommitDistributionVisualization', + #superclass : 'MiAbstractVisualization', + #category : 'GitLabHealth-Model-Visualization', + #package : 'GitLabHealth-Model-Visualization' +} + +{ #category : 'instance creation' } +GLHRepositoryCommitDistributionVisualization >> forRepository: aRepository [ + + | c lb oldestCommit oldestCommitDate commitByDate horizontal | + c := RSCompositeChart new. + oldestCommit := aRepository commits last. + oldestCommitDate := oldestCommit committed_date. + commitByDate := (oldestCommitDate to: Date today) dates collect: [ + :date | + date -> (aRepository commits select: [ :commit | + commit committed_date asDate = date ]) ]. + + c add: (RSAbstractChart barHeights: + (commitByDate collect: [ :dateToCommit | dateToCommit value size ])). + " c add: ((RSAbstractChart barHeights: womenMeans) bottom: menMeans)." + horizontal := c horizontalTick fromNames: + (commitByDate collect: [ :dateToCommit | + dateToCommit key printString ]). + horizontal configuration fontSize: 2. + horizontal useDiagonalLabel. + c verticalTick integer. + c ylabel: 'Number of commits'. + c title: 'Number of commits by date grouped by user'. + c build. + lb := RSLegend new. + lb layout horizontal. + lb container: c canvas. + lb build. + ^ c canvas +] diff --git a/src/GitLabHealth-Model-Visualization/package.st b/src/GitLabHealth-Model-Visualization/package.st index c3f0d61..1b48da4 100644 --- a/src/GitLabHealth-Model-Visualization/package.st +++ b/src/GitLabHealth-Model-Visualization/package.st @@ -1 +1 @@ -Package { #name : #'GitLabHealth-Model-Visualization' } +Package { #name : 'GitLabHealth-Model-Visualization' } From 1723e31deefac39db5bea742fba9831538d0df8d Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Sun, 15 Sep 2024 13:16:57 +0200 Subject: [PATCH 116/154] ~ improve vizu to show commits distribution --- ...LHCommitDistributionVisualization.class.st | 77 +++++++++++++++++++ .../GLHRepository.extension.st | 4 +- ...ryCommitDistributionVisualization.class.st | 37 --------- 3 files changed, 79 insertions(+), 39 deletions(-) create mode 100644 src/GitLabHealth-Model-Visualization/GLHCommitDistributionVisualization.class.st delete mode 100644 src/GitLabHealth-Model-Visualization/GLHRepositoryCommitDistributionVisualization.class.st diff --git a/src/GitLabHealth-Model-Visualization/GLHCommitDistributionVisualization.class.st b/src/GitLabHealth-Model-Visualization/GLHCommitDistributionVisualization.class.st new file mode 100644 index 0000000..e07afbb --- /dev/null +++ b/src/GitLabHealth-Model-Visualization/GLHCommitDistributionVisualization.class.st @@ -0,0 +1,77 @@ +Class { + #name : 'GLHCommitDistributionVisualization', + #superclass : 'MiAbstractVisualization', + #instVars : [ + 'groupCommitBlock' + ], + #category : 'GitLabHealth-Model-Visualization', + #package : 'GitLabHealth-Model-Visualization' +} + +{ #category : 'instance creation' } +GLHCommitDistributionVisualization >> forCommits: commits [ + + | c lb oldestCommit horizontal commitGroups groupToCommitByDate alreadyAdded dates | + c := RSCompositeChart new. + oldestCommit := commits last. + dates := (oldestCommit committed_date to: Date today) dates. + + commitGroups := commits groupedBy: self groupCommitBlock. + + groupToCommitByDate := commitGroups associations collect: [ :assoc | + assoc key -> (dates collect: [ :date | + date + -> + (assoc value select: [ :commit | + commit committed_date asDate = date ]) ]) ]. + + alreadyAdded := dates collect: [ :d | 0 ]. + groupToCommitByDate do: [ :assocGroupToCommitByDate | + | chart | + chart := (RSAbstractChart barHeights: + (assocGroupToCommitByDate value collect: [ :dateToCommit | + dateToCommit value size ])) bottom: alreadyAdded. + c add: chart. + alreadyAdded := chart yValues ]. + + horizontal := c horizontalTick fromNames: + (dates collect: [ :date | date printString ]). + horizontal configuration fontSize: 2. + horizontal useDiagonalLabel. + c verticalTick integer. + c ylabel: 'Number of commits'. + c title: 'Number of commits by date'. + c build. + lb := RSLegend new. + lb layout vertical. + commitGroups keys doWithIndex: [ :groupObject :index | + lb + text: groupObject fullDisplayString + withBoxColor: (c plots at: index) computeColor ]. + lb container: c canvas. + lb location + right; + middle; + offset: 10 @ 0. + lb build. + ^ c canvas +] + +{ #category : 'accessing' } +GLHCommitDistributionVisualization >> groupCommitBlock [ + + ^ groupCommitBlock +] + +{ #category : 'accessing' } +GLHCommitDistributionVisualization >> groupCommitBlock: anObject [ + + groupCommitBlock := anObject +] + +{ #category : 'initialization' } +GLHCommitDistributionVisualization >> initialize [ + + super initialize. + groupCommitBlock := [ :commit | commit commitCreator ] +] diff --git a/src/GitLabHealth-Model-Visualization/GLHRepository.extension.st b/src/GitLabHealth-Model-Visualization/GLHRepository.extension.st index e515b89..10ab053 100644 --- a/src/GitLabHealth-Model-Visualization/GLHRepository.extension.st +++ b/src/GitLabHealth-Model-Visualization/GLHRepository.extension.st @@ -6,7 +6,7 @@ GLHRepository >> rsCommitDistribution: aBuilder [ ^ SpRoassalInspectorPresenter new canvas: - (GLHRepositoryCommitDistributionVisualization new forRepository: - self); + (GLHCommitDistributionVisualization new forCommits: + self commits); yourself ] diff --git a/src/GitLabHealth-Model-Visualization/GLHRepositoryCommitDistributionVisualization.class.st b/src/GitLabHealth-Model-Visualization/GLHRepositoryCommitDistributionVisualization.class.st deleted file mode 100644 index 22a4261..0000000 --- a/src/GitLabHealth-Model-Visualization/GLHRepositoryCommitDistributionVisualization.class.st +++ /dev/null @@ -1,37 +0,0 @@ -Class { - #name : 'GLHRepositoryCommitDistributionVisualization', - #superclass : 'MiAbstractVisualization', - #category : 'GitLabHealth-Model-Visualization', - #package : 'GitLabHealth-Model-Visualization' -} - -{ #category : 'instance creation' } -GLHRepositoryCommitDistributionVisualization >> forRepository: aRepository [ - - | c lb oldestCommit oldestCommitDate commitByDate horizontal | - c := RSCompositeChart new. - oldestCommit := aRepository commits last. - oldestCommitDate := oldestCommit committed_date. - commitByDate := (oldestCommitDate to: Date today) dates collect: [ - :date | - date -> (aRepository commits select: [ :commit | - commit committed_date asDate = date ]) ]. - - c add: (RSAbstractChart barHeights: - (commitByDate collect: [ :dateToCommit | dateToCommit value size ])). - " c add: ((RSAbstractChart barHeights: womenMeans) bottom: menMeans)." - horizontal := c horizontalTick fromNames: - (commitByDate collect: [ :dateToCommit | - dateToCommit key printString ]). - horizontal configuration fontSize: 2. - horizontal useDiagonalLabel. - c verticalTick integer. - c ylabel: 'Number of commits'. - c title: 'Number of commits by date grouped by user'. - c build. - lb := RSLegend new. - lb layout horizontal. - lb container: c canvas. - lb build. - ^ c canvas -] From e2ddae04d0c6b9dd1ccb5b522a267296226e018a Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Sun, 15 Sep 2024 13:23:17 +0200 Subject: [PATCH 117/154] adapt commit contribution for user --- src/GitLabHealth-Visualization/GLHUser.extension.st | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/GitLabHealth-Visualization/GLHUser.extension.st diff --git a/src/GitLabHealth-Visualization/GLHUser.extension.st b/src/GitLabHealth-Visualization/GLHUser.extension.st new file mode 100644 index 0000000..c95baec --- /dev/null +++ b/src/GitLabHealth-Visualization/GLHUser.extension.st @@ -0,0 +1,12 @@ +Extension { #name : 'GLHUser' } + +{ #category : '*GitLabHealth-Visualization' } +GLHUser >> rsCommitDistribution: aBuilder [ + + + ^ SpRoassalInspectorPresenter new + canvas: (GLHCommitDistributionVisualization new + groupCommitBlock: [ :commit | commit repository project ]; + forCommits: self commits); + yourself +] From 2957363dd4f1132c0e35b4ff32419cb4e6fa3bf5 Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Sun, 15 Sep 2024 13:56:26 +0200 Subject: [PATCH 118/154] support github project without code repository --- src/GitHubHealth-Model-Importer/GHModelImporter.class.st | 8 +++++++- .../GHRepositoryEmptyError.class.st | 9 +++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 src/GitHubHealth-Model-Importer/GHRepositoryEmptyError.class.st diff --git a/src/GitHubHealth-Model-Importer/GHModelImporter.class.st b/src/GitHubHealth-Model-Importer/GHModelImporter.class.st index d3ab046..e4aba38 100644 --- a/src/GitHubHealth-Model-Importer/GHModelImporter.class.st +++ b/src/GitHubHealth-Model-Importer/GHModelImporter.class.st @@ -72,12 +72,16 @@ GHModelImporter >> importCommitsOfProject: aGLHProject [ foundCommits := OrderedCollection new. ('Extract commits from ' , foundCommits size printString , ' to ' , (foundCommits size + itemByPage) printString) recordInfo. + "also check that there is at least one commit with the error handling" + [ tmp := self parseCommitsResult: (self api commitsOfProject: aGLHProject name ofOrganization: aGLHProject group name since: self withCommitsSince perPage: itemByPage - page: pageNumber). + page: pageNumber) ] + on: GHRepositoryEmptyError + do: [ ^ { } ]. foundCommits addAll: tmp. [ tmp size = itemByPage ] whileTrue: [ @@ -263,6 +267,8 @@ GHModelImporter >> parseBranchesResult: arrayOfBranch [ GHModelImporter >> parseCommitsResult: result [ | reader | + (result includesSubstring: '"status":"409"') ifTrue: [ + GHRepositoryEmptyError signal: 'Git Repository is empty' ]. reader := NeoJSONReader on: result readStream. reader for: GLHCommit do: [ :mapping | diff --git a/src/GitHubHealth-Model-Importer/GHRepositoryEmptyError.class.st b/src/GitHubHealth-Model-Importer/GHRepositoryEmptyError.class.st new file mode 100644 index 0000000..1d7462e --- /dev/null +++ b/src/GitHubHealth-Model-Importer/GHRepositoryEmptyError.class.st @@ -0,0 +1,9 @@ +Class { + #name : 'GHRepositoryEmptyError', + #superclass : 'Error', + #instVars : [ + 'api' + ], + #category : 'GitHubHealth-Model-Importer', + #package : 'GitHubHealth-Model-Importer' +} From 9aa4fc9984e135db787654f67bf103f1b99596b8 Mon Sep 17 00:00:00 2001 From: nhlad Date: Mon, 16 Sep 2024 08:06:25 +0000 Subject: [PATCH 119/154] try fixing pipeline --- src/GitLabHealth-Model-Importer/GLHModelImporter.class.st | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index 64699bf..12d1efd 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -15,13 +15,11 @@ Class { #category : 'GitLabHealth-Model-Importer', } - { #category : #'as yet unclassified' } GLHModelImporter class >> importers [ ^ currentImporter ] - { #category : #initialization } GLHModelImporter class >> reset [ currentImporter := nil. From 81b26eb060e6f03808d88ff438abf9cb13e088c3 Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Mon, 16 Sep 2024 10:08:06 +0200 Subject: [PATCH 120/154] Update GLHModelImporter.class.st --- src/GitLabHealth-Model-Importer/GLHModelImporter.class.st | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index 140d846..55037ca 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -12,7 +12,7 @@ Class { #classVars : [ 'currentImporter' ], - #category : 'GitLabHealth-Model-Importer', + #category : 'GitLabHealth-Model-Importer' } { #category : 'accessing' } From e278df8f8892e2ced5fc2d4b5a6b6b863731073a Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Mon, 16 Sep 2024 10:10:39 +0200 Subject: [PATCH 121/154] Update ci-moose11.yml --- .github/workflows/ci-moose11.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci-moose11.yml b/.github/workflows/ci-moose11.yml index 4f0a089..0790455 100644 --- a/.github/workflows/ci-moose11.yml +++ b/.github/workflows/ci-moose11.yml @@ -7,6 +7,7 @@ on: push: branches: - main + - develop jobs: build: From f2741e8e3fe7a0e5ab1bbbb051320fefe75d8b9d Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Mon, 16 Sep 2024 10:14:16 +0200 Subject: [PATCH 122/154] Update GLHModelImporter.class.st --- src/GitLabHealth-Model-Importer/GLHModelImporter.class.st | 1 + 1 file changed, 1 insertion(+) diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index 55037ca..9cf7c80 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -588,6 +588,7 @@ GLHModelImporter >> importContributedProjectsOfUser: aGLHUser [ (self glhModel addAll: newlyFoundElmts unless: self blockOnIdEquality) ]. +] { #category : 'as yet unclassified' } GLHModelImporter >> importCreatorOfCommit: aCommit [ From aef27716a8ddbec8aa8b8a46cbdd59c08918fb26 Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Mon, 16 Sep 2024 10:17:30 +0200 Subject: [PATCH 123/154] Update GLHModelImporter.class.st --- src/GitLabHealth-Model-Importer/GLHModelImporter.class.st | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index 9cf7c80..38465e0 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -605,7 +605,7 @@ GLHModelImporter >> importCreatorOfCommit: aCommit [ ] { #category : #'as yet unclassified' } -GLHModelImporter >> importCreatorOfCommit: aCommit [ +GLHModelImporter >> importCreatorOfCommit2: aCommit [ aCommit commitCreator ifNil: [ aCommit commitCreator: @@ -938,7 +938,7 @@ GLHModelImporter >> initialize [ userCatalogue := GLHUserCatalogueV2 new anImporter: self; yourself. - self initReader + self initReader. currentImporter := self ] From 9e671762a55ddac64f59bab4fbcbdf7103f44a2f Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Mon, 16 Sep 2024 10:27:23 +0200 Subject: [PATCH 124/154] fix test of MergedMRMetrics --- .../MergedMergeRequestMetricTest.class.st | 64 ++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/src/GitLabHealth-Model-Analysis-Tests/MergedMergeRequestMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/MergedMergeRequestMetricTest.class.st index 45e5fc0..54727d3 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/MergedMergeRequestMetricTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/MergedMergeRequestMetricTest.class.st @@ -14,6 +14,7 @@ MergedMergeRequestMetricTest >> testCalculate [ "Given" user := GLHUser new username: 'test'; + id: 1; contributedProjects: { (GLHProject new repository: GLHRepository new) }. @@ -47,6 +48,7 @@ MergedMergeRequestMetricTest >> testCalculate1MRInPeriod1Outside [ "Given" user := GLHUser new username: 'test'; + id: 1; contributedProjects: { (GLHProject new repository: GLHRepository new) }. @@ -88,6 +90,7 @@ MergedMergeRequestMetricTest >> testCalculate1MROpenedButNotMerged [ "Given" user := GLHUser new username: 'test'; + id: 1; contributedProjects: { (GLHProject new repository: GLHRepository new) }. @@ -126,11 +129,13 @@ MergedMergeRequestMetricTest >> testCalculate2MROneForEachUser [ "Given" user1 := GLHUser new name: 'test'; + id: 1; contributedProjects: { (GLHProject new repository: GLHRepository new) }. user2 := GLHUser new name: 'test'; + id: 2; contributedProjects: { (GLHProject new repository: GLHRepository new) }. @@ -161,7 +166,61 @@ MergedMergeRequestMetricTest >> testCalculate2MROneForEachUser [ result := mergedMergeRequest calculate. "Then" - self assert: result equals: 2 + self assert: result equals: 1 +] + +{ #category : #tests } +MergedMergeRequestMetricTest >> testCalculate3MROpenButMergedByOthers [ + + | result glhImporter user1 mergedMergeRequest user2 | + "Given" + user1 := GLHUser new + name: 'test'; + id: 1; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + user2 := GLHUser new + name: 'test'; + id: 2; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { (GLPHEMergeRequest new + author: user1; + title: 'MR1'; + created_at: '09-05-2024'; + merge_user: user2; + merged_at: '09-05-2024'). + (GLPHEMergeRequest new + author: user1; + title: 'MR2'; + created_at: '09-05-2024'; + merge_user: user2; + merged_at: '09-06-2024' + ). + (GLPHEMergeRequest new + author: user1; + title: 'MR3'; + created_at: '09-05-2024'; + merge_user: user2; + merged_at: '09-06-2024' + )}. + + + mergedMergeRequest := MergedMergeRequestMetric new + user: user1; + glhImporter: glhImporter; + setPeriodSince: '09-01-2024' + until: '09-07-2024'; + over: Week. + + "When" + result := mergedMergeRequest calculate. + + "Then" + self assert: result equals: 0 ] { #category : #tests } @@ -171,11 +230,13 @@ MergedMergeRequestMetricTest >> testCalculate3MROpenByOther [ "Given" user1 := GLHUser new name: 'test'; + id: 1; contributedProjects: { (GLHProject new repository: GLHRepository new) }. user2 := GLHUser new name: 'test'; + id: 2; contributedProjects: { (GLHProject new repository: GLHRepository new) }. @@ -223,6 +284,7 @@ MergedMergeRequestMetricTest >> testCalculateNoMergeRequests [ "Given" user := GLHUser new username: 'test'; + id: 1; contributedProjects: { (GLHProject new repository: GLHRepository new) }. From de542ff51d835851a6eb2f283446bcf7d9ccbf00 Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Mon, 16 Sep 2024 12:21:06 +0200 Subject: [PATCH 125/154] restore method as before --- .../GLHModelImporter.class.st | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index 00fe37d..d8378fc 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -12,7 +12,7 @@ Class { #classVars : [ 'currentImporter' ], - #category : 'GitLabHealth-Model-Importer' + #category : #'GitLabHealth-Model-Importer' } { #category : #'as yet unclassified' } @@ -563,7 +563,7 @@ GLHModelImporter >> importCommitsOfBranch: aGLHBranch forRefName: refName until: { #category : #'as yet unclassified' } GLHModelImporter >> importContributedProjectsOfUser: aGLHUser [ - | newlyFoundElmts page foundElmts remaningProjects| + | newlyFoundElmts page foundElmts remaningProjects | page := 0. foundElmts := OrderedCollection new. newlyFoundElmts := { true }. @@ -572,7 +572,7 @@ GLHModelImporter >> importContributedProjectsOfUser: aGLHUser [ page := page + 1. ('import contributed project of user ' , aGLHUser name , ' page ' , page printString) recordInfo. - results := self glhApi + results := self glhApi contributedProjectsOfUserId: aGLHUser id orderBy: 'last_activity_at' simple: true @@ -586,10 +586,24 @@ GLHModelImporter >> importContributedProjectsOfUser: aGLHUser [ (self glhModel addAll: newlyFoundElmts unless: self blockOnIdEquality) ]. + remaningProjects := self importProjects: + ((foundElmts collect: #id) difference: + ((self userCatalogue atId: aGLHUser id) at: + #contributedProjects)). + + aGLHUser contributedProjects + addAll: foundElmts , remaningProjects + unless: self blockOnIdEquality. + + self userCatalogue + addUser: aGLHUser + withProjects: (aGLHUser contributedProjects collect: #id). + + ^ foundElmts ] { #category : #'as yet unclassified' } -GLHModelImporter >> importCreatorOfCommit2: aCommit [ +GLHModelImporter >> importCreatorOfCommit: aCommit [ aCommit commitCreator ifNil: [ aCommit commitCreator: @@ -598,20 +612,6 @@ GLHModelImporter >> importCreatorOfCommit2: aCommit [ ^ aCommit commitCreator ] -{ #category : #'as yet unclassified' } -GLHModelImporter >> importCreatorOfCommit: aCommit [ - - remaningProjects := self importProjects: ((foundElmts collect: #id) difference: ((self userCatalogue atId: aGLHUser id) at: #contributedProjects)). - - aGLHUser contributedProjects - addAll: (foundElmts, remaningProjects) - unless: self blockOnIdEquality. - - self userCatalogue addUser: aGLHUser withProjects: (aGLHUser contributedProjects collect: #id). - - ^ foundElmts -] - { #category : #api } GLHModelImporter >> importDiffOfCommit: aCommit [ From edf6c8c4d46cdffdf9cfe890d89abba55d933afa Mon Sep 17 00:00:00 2001 From: BAUVENT Kilian Date: Mon, 16 Sep 2024 16:31:20 +0200 Subject: [PATCH 126/154] feat: import merge request commits and add metric --- .../GLPHEMergeRequest.class.st | 13 +++++ ...iraTimeMRTimeDifferenceMetricTest.class.st | 44 ++++++++++++++++ .../GitMetricExporter.class.st | 2 +- .../JiraTimeMRTimeDifferenceMetric.class.st | 50 +++++++++++++++++++ .../UserJiraMetric.class.st | 4 +- .../UserMetric.class.st | 27 +++++++++- .../GLPHApi.class.st | 15 ++++++ .../GLPHModelImporter.class.st | 32 +++++++++++- 8 files changed, 182 insertions(+), 5 deletions(-) create mode 100644 src/GitLabHealth-Model-Analysis-Tests/JiraTimeMRTimeDifferenceMetricTest.class.st create mode 100644 src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st diff --git a/src/GLPHExtended-Model/GLPHEMergeRequest.class.st b/src/GLPHExtended-Model/GLPHEMergeRequest.class.st index 348b7a3..4f7e0f1 100644 --- a/src/GLPHExtended-Model/GLPHEMergeRequest.class.st +++ b/src/GLPHExtended-Model/GLPHEMergeRequest.class.st @@ -97,6 +97,7 @@ Class { '#changes_count => FMProperty', '#closed_at => FMProperty', '#created_at => FMProperty', + '#commits => FMProperty', '#description => FMProperty', '#detailed_merge_status => FMProperty', '#discussion_locked => FMProperty', @@ -318,6 +319,18 @@ GLPHEMergeRequest >> closed_by: anObject [ self attributeAt: #closed_by put: (FMMultivalueLink on: self update: #closedMergeRequests from: self closed_by to: anObject). ] +{ #category : #accessing } +GLPHEMergeRequest >> commits [ + + ^ commits +] + +{ #category : #accessing } +GLPHEMergeRequest >> commits: anObject [ + + commits := anObject +] + { #category : #accessing } GLPHEMergeRequest >> created_at [ diff --git a/src/GitLabHealth-Model-Analysis-Tests/JiraTimeMRTimeDifferenceMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/JiraTimeMRTimeDifferenceMetricTest.class.st new file mode 100644 index 0000000..4cf232c --- /dev/null +++ b/src/GitLabHealth-Model-Analysis-Tests/JiraTimeMRTimeDifferenceMetricTest.class.st @@ -0,0 +1,44 @@ +" +A JiraTimeMRTimeDifferenceMetricTest is a test class for testing the behavior of JiraTimeMRTimeDifferenceMetric +" +Class { + #name : #JiraTimeMRTimeDifferenceMetricTest, + #superclass : #TestCase, + #category : #'GitLabHealth-Model-Analysis-Tests' +} + +{ #category : #test } +JiraTimeMRTimeDifferenceMetricTest >> testCalculate [ + + | result glhImporter user jiraImporter jiraMRDifference | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: '09-06-2024'; + title: '205 feat do something') }. + + jiraImporter := JiraImporterMock new. + jiraImporter issues: { (JPIssue new key: '205'; timeEstimate: '20') }. + + + jiraMRDifference := JiraTimeMRTimeDifferenceMetric new + user: user; + glhImporter: glhImporter; + jiraImporter: jiraImporter; + setPeriodSince: '09-04-2024' + until: '09-04-2024'; + over: Week. + + "When" + result := jiraMRDifference calculate. + + "Then" + self assert: result equals: 1 +] diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index c1cd7d6..4c732f9 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -452,7 +452,7 @@ GitMetricExporter >> initialize [ ClosedMergeRequestMetric. MergedMergeRequestMetric. SelfMergedUnderAMinuteMergeRequestMetric. - ClosedTicketsMetric} + ClosedTicketsMetric. JiraTimeMRTimeDifferenceMetric } ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st b/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st new file mode 100644 index 0000000..a6d62d6 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st @@ -0,0 +1,50 @@ +Class { + #name : #JiraTimeMRTimeDifferenceMetric, + #superclass : #UserJiraMetric, + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #calculating } +JiraTimeMRTimeDifferenceMetric >> calculate [ + + | groupedByDate dateOver | + userMergeRequests ifNil: [ self load ]. + groupedByDate := self setupGroupedDate. + + Halt now. + + userMergeRequests := userMergeRequests select: [ :mergeRequest | + mergeRequest merged_at isNotNil ]. + + userMergeRequests do: [ :userMergeRequest | + dateOver := self transformDate: userMergeRequest created_at to: over. + groupedByDate + at: dateOver printString + ifPresent: [ :value | value add: userMergeRequest ] ]. + + groupedByDate := groupedByDate collect: [ :group | + group collect: [ :mergeRequest | + | mergeRequestBranch createdDate duration | + mergeRequestBranch := STONJSON fromString: + (glhImporter glhApi + branchOfRepository: + mergeRequest project_id + withName: + mergeRequest + source_branch). + + createdDate := (mergeRequestBranch at: #commit) + at: #created_at. + + duration := mergeRequest merged_at - createdDate. + + mergeRequest jiraIssue timeEstimate - duration ] ]. + + ^ groupedByDate average asFloat +] + +{ #category : #accessing } +JiraTimeMRTimeDifferenceMetric >> description [ + + ^ 'average difference between jira estimate time and associated merge resquest time' +] diff --git a/src/GitLabHealth-Model-Analysis/UserJiraMetric.class.st b/src/GitLabHealth-Model-Analysis/UserJiraMetric.class.st index b09b6f2..845662d 100644 --- a/src/GitLabHealth-Model-Analysis/UserJiraMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserJiraMetric.class.st @@ -20,7 +20,7 @@ UserJiraMetric >> description [ UserJiraMetric >> load [ userMergeRequests := self - loadMergeRequestsWithJiraIssueSince: + loadMergeRequestsWithJiraIssueOfUser: user since: (period at: #since) until: (period at: #until) ] @@ -28,5 +28,5 @@ UserJiraMetric >> load [ { #category : #accessing } UserJiraMetric >> name [ - ^ self subclassResponsibility + ^ self class name asString ] diff --git a/src/GitLabHealth-Model-Analysis/UserMetric.class.st b/src/GitLabHealth-Model-Analysis/UserMetric.class.st index 90cbdbd..780ab4d 100644 --- a/src/GitLabHealth-Model-Analysis/UserMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserMetric.class.st @@ -116,7 +116,10 @@ UserMetric >> loadCompleteMergeRequestsSince: since until: until [ mergeRequests := self loadMergeRequestsSince: since until: until. mergeRequests do: [ :mergeRequest | - glhImporter importMergeResquestMerger: mergeRequest ]. + glhImporter importMergeResquestMerger: mergeRequest. + glhImporter importMergeRequestCommits: mergeRequest ]. + + Halt now. ^ mergeRequests ] @@ -175,6 +178,28 @@ UserMetric >> loadMergeRequestsSince: since until: until [ ^ mergeRequests "select: [ :mergeRequest | mergeRequest author = user ]" ] +{ #category : #loading } +UserMetric >> loadMergeRequestsWithJiraIssueOfUser: anUser since: since until: until [ + + | email mergeRequests | + mergeRequests := self + loadMergeRequestsOfUser: anUser + since: since + until: until. + + email := self userEmail. + + jiraImporter importAllCurrentAndPastIssuesOf: email. + + GPJCConnector new + gpModel: glhImporter glhModel; + jiraModel: jiraImporter model; + connect. + + ^ mergeRequests select: [ :mergeRequest | + mergeRequest jiraIssue isNotNil ] +] + { #category : #loading } UserMetric >> loadMergeRequestsWithJiraIssueSince: since until: until [ diff --git a/src/GitLabProjectHealth-Model-Importer/GLPHApi.class.st b/src/GitLabProjectHealth-Model-Importer/GLPHApi.class.st index a772926..7dc16f1 100644 --- a/src/GitLabProjectHealth-Model-Importer/GLPHApi.class.st +++ b/src/GitLabProjectHealth-Model-Importer/GLPHApi.class.st @@ -13,6 +13,21 @@ GLPHApi >> approvalsOfMergeQuest: aMergeRequestIID ofProject: aProjectId [ ^ self client get ] +{ #category : #'as yet unclassified' } +GLPHApi >> commitsOfMergeRequest: mergeRequestIID ofProject: projectId page: page perPage: perPage [ + + self client path: + self baseAPIUrl , '/projects/' , projectId printString + , '/merge_requests/' , mergeRequestIID printString, '/commits'. + + + perPage ifNotNil: [ + self client queryAt: #per_page put: perPage ]. + page ifNotNil: [ self client queryAt: #page put: page ]. + + ^ self client get +] + { #category : #commit } GLPHApi >> commitsOfProject: anInteger forRefName: refName [ diff --git a/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st b/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st index e48d113..d5f2dbe 100644 --- a/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st +++ b/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st @@ -1,7 +1,7 @@ Class { #name : #GLPHModelImporter, #superclass : #GLHModelImporter, - #category : 'GitLabProjectHealth-Model-Importer' + #category : #'GitLabProjectHealth-Model-Importer' } { #category : #'as yet unclassified' } @@ -228,6 +228,36 @@ GLPHModelImporter >> importDiffRangesForDiff: aGLHDiff [ unless: self blockForDiffRangeEquality ] +{ #category : #'import - merge request' } +GLPHModelImporter >> importMergeRequestCommits: aGLPHEMergeRequest [ + + | results page commits parseResult | + aGLPHEMergeRequest commits ifNotNil: [ ^ aGLPHEMergeRequest commits ]. + page := 1. + + parseResult := { nil }. + commits := OrderedCollection new. + + [ + results := glhApi + commitsOfMergeRequest: aGLPHEMergeRequest iid + ofProject: aGLPHEMergeRequest project id + page: page + perPage: 100. + parseResult := self parseCommitsResult: results. + + commits addAll: parseResult. + page := page + 1 ] doWhileTrue: [ parseResult isNotEmpty ]. + + + aGLPHEMergeRequest commits: commits. + + self glhModel + addAll: aGLPHEMergeRequest commits + unless: self blockOnIdEquality. + ^ commits +] + { #category : #'import - merge request' } GLPHModelImporter >> importMergeRequests: aGLHProject [ From adb8479243310a8d07866f88c937edb046ad2841 Mon Sep 17 00:00:00 2001 From: BAUVENT Kilian Date: Mon, 16 Sep 2024 16:52:38 +0200 Subject: [PATCH 127/154] refactor: change load method --- .../JiraTimeMRTimeDifferenceMetric.class.st | 47 ++++++++----- .../MergedMergeRequestMetric.class.st | 8 --- .../OpenedMergeRequestMetric.class.st | 6 -- .../PendingMergeRequestMetric.class.st | 6 -- .../ReviewedByUserMergeRequestMetric.class.st | 7 +- ...gedUnderAMinuteMergeRequestMetric.class.st | 4 +- .../UserMergeRequestMetric.class.st | 2 +- .../UserMetric.class.st | 67 ++++++------------- 8 files changed, 60 insertions(+), 87 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st b/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st index a6d62d6..dc5cde9 100644 --- a/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st @@ -10,11 +10,16 @@ JiraTimeMRTimeDifferenceMetric >> calculate [ | groupedByDate dateOver | userMergeRequests ifNil: [ self load ]. groupedByDate := self setupGroupedDate. - - Halt now. userMergeRequests := userMergeRequests select: [ :mergeRequest | - mergeRequest merged_at isNotNil ]. + | issueIsEstimated | + issueIsEstimated := mergeRequest jiraIssue + timeEstimate isNotNil or: + mergeRequest jiraIssue + timeOriginalEstimate + isNotNil. + mergeRequest merged_at isNotNil and: + issueIsEstimated ]. userMergeRequests do: [ :userMergeRequest | dateOver := self transformDate: userMergeRequest created_at to: over. @@ -24,23 +29,24 @@ JiraTimeMRTimeDifferenceMetric >> calculate [ groupedByDate := groupedByDate collect: [ :group | group collect: [ :mergeRequest | - | mergeRequestBranch createdDate duration | - mergeRequestBranch := STONJSON fromString: - (glhImporter glhApi - branchOfRepository: - mergeRequest project_id - withName: - mergeRequest - source_branch). + | firstCommitDate mergeRequestTime jiraTime | + firstCommitDate := mergeRequest commits last + created_at. - createdDate := (mergeRequestBranch at: #commit) - at: #created_at. + mergeRequestTime := mergeRequest merged_at + - firstCommitDate. - duration := mergeRequest merged_at - createdDate. + jiraTime := mergeRequest jiraIssue + timeOriginalEstimate + ifNil: [ + mergeRequest jiraIssue timeEstimate ] + ifNotNil: [ + mergeRequest jiraIssue + timeOriginalEstimate ]. - mergeRequest jiraIssue timeEstimate - duration ] ]. + jiraTime - mergeRequestTime ] ]. - ^ groupedByDate average asFloat + ^groupedByDate average ifNil: [ nil ] ifNotNil: [ groupedByDate average ] ] { #category : #accessing } @@ -48,3 +54,12 @@ JiraTimeMRTimeDifferenceMetric >> description [ ^ 'average difference between jira estimate time and associated merge resquest time' ] + +{ #category : #loading } +JiraTimeMRTimeDifferenceMetric >> load [ + + userMergeRequests := self + loadCompleteMergeRequestsWithJiraIssueOfUser: user + since: (period at: #since) + until: (period at: #until) +] diff --git a/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st index 5494e71..82e8f7d 100644 --- a/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st @@ -34,14 +34,6 @@ MergedMergeRequestMetric >> description [ ^ 'number of merge request merged by this user' ] -{ #category : #loading } -MergedMergeRequestMetric >> load [ - userMergeRequests := self - loadMergeRequestsSince: - (period at: #since) - until: (period at: #until) -] - { #category : #accessing } MergedMergeRequestMetric >> name [ diff --git a/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st index e2f153a..2e1c4b2 100644 --- a/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/OpenedMergeRequestMetric.class.st @@ -30,12 +30,6 @@ OpenedMergeRequestMetric >> description [ ^'number of opened merge request' ] -{ #category : #loading } -OpenedMergeRequestMetric >> load [ - userMergeRequests := self loadMergeRequestsOfUser: user since: (period at: #since) - until: (period at: #until). -] - { #category : #accessing } OpenedMergeRequestMetric >> name [ diff --git a/src/GitLabHealth-Model-Analysis/PendingMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/PendingMergeRequestMetric.class.st index bd020d4..185e7c5 100644 --- a/src/GitLabHealth-Model-Analysis/PendingMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/PendingMergeRequestMetric.class.st @@ -32,12 +32,6 @@ PendingMergeRequestMetric >> description [ ^ 'number of merge request opened during a period and left opened at the end of it' ] -{ #category : #loading } -PendingMergeRequestMetric >> load [ - userMergeRequests := self loadMergeRequestsOfUser: user since: (period at: #since) - until: (period at: #until). -] - { #category : #accessing } PendingMergeRequestMetric >> name [ ^'pendingMergeRequest' diff --git a/src/GitLabHealth-Model-Analysis/ReviewedByUserMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/ReviewedByUserMergeRequestMetric.class.st index d3b6e57..9797975 100644 --- a/src/GitLabHealth-Model-Analysis/ReviewedByUserMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/ReviewedByUserMergeRequestMetric.class.st @@ -43,9 +43,10 @@ ReviewedByUserMergeRequestMetric >> description [ ] { #category : #loading } -ReviewedByUserMergeRequestMetric >> load [ - userMergeRequests := self - loadCompleteMergeRequestsSince: +ReviewedByUserMergeRequestMetric >> load [ + + userMergeRequests := self + loadCompleteMergeRequestsOfUser: user since: (period at: #since) until: (period at: #until) ] diff --git a/src/GitLabHealth-Model-Analysis/SelfMergedUnderAMinuteMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/SelfMergedUnderAMinuteMergeRequestMetric.class.st index 774ca86..d519400 100644 --- a/src/GitLabHealth-Model-Analysis/SelfMergedUnderAMinuteMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/SelfMergedUnderAMinuteMergeRequestMetric.class.st @@ -53,8 +53,8 @@ SelfMergedUnderAMinuteMergeRequestMetric >> description [ SelfMergedUnderAMinuteMergeRequestMetric >> load [ userMergeRequests := self - loadCompleteMergeRequestsSince: - (period at: #since) + loadCompleteMergeRequestsOfUser: user + since: (period at: #since) until: (period at: #until) ] diff --git a/src/GitLabHealth-Model-Analysis/UserMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/UserMergeRequestMetric.class.st index f5d6bab..17696fe 100644 --- a/src/GitLabHealth-Model-Analysis/UserMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserMergeRequestMetric.class.st @@ -20,7 +20,7 @@ UserMergeRequestMetric >> description [ UserMergeRequestMetric >> load [ userMergeRequests := self - loadMergeRequestsSince: (period at: #since) + loadMergeRequestsOfUser: user since: (period at: #since) until: (period at: #until) ] diff --git a/src/GitLabHealth-Model-Analysis/UserMetric.class.st b/src/GitLabHealth-Model-Analysis/UserMetric.class.st index 780ab4d..3aa722f 100644 --- a/src/GitLabHealth-Model-Analysis/UserMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserMetric.class.st @@ -110,49 +110,45 @@ UserMetric >> loadCompleteCommitsSince: since until: until [ ] { #category : #loading } -UserMetric >> loadCompleteMergeRequestsSince: since until: until [ +UserMetric >> loadCompleteMergeRequestsOfUser: anUser since: since until: until [ | mergeRequests | - mergeRequests := self loadMergeRequestsSince: since until: until. + mergeRequests := self + loadMergeRequestsOfUser: anUser + since: since + until: until. mergeRequests do: [ :mergeRequest | glhImporter importMergeResquestMerger: mergeRequest. glhImporter importMergeRequestCommits: mergeRequest ]. - Halt now. - ^ mergeRequests ] { #category : #loading } -UserMetric >> loadMergeRequestsOfUser: anUser since: since until: until [ +UserMetric >> loadCompleteMergeRequestsWithJiraIssueOfUser: anUser since: since until: until [ - | cacheSymbol mergeRequests | - glhImporter withCommitDiffs: false. - cacheSymbol := self - cacheSymbolFor: GLPHEMergeRequest - since: since - until: until. + | email mergeRequests | + mergeRequests := self + loadCompleteMergeRequestsOfUser: anUser + since: since + until: until. - mergeRequests := anUser contributedProjects collect: [ :project | - | mr | - project cacheAt: cacheSymbol ifAbsentPut: [ - mr := glhImporter - importMergeRequests: project - since: since - until: until. - mr ] ]. + email := self userEmail. - mergeRequests := mergeRequests flattened. - glhImporter withCommitDiffs: true. + jiraImporter importAllCurrentAndPastIssuesOf: email. - mergeRequests do: [ :mr | glhImporter importMergeResquestAuthor: mr ]. + GPJCConnector new + gpModel: glhImporter glhModel; + jiraModel: jiraImporter model; + connect. - ^ mergeRequests select: [ :mergeRequest | mergeRequest author = anUser ] + ^ mergeRequests select: [ :mergeRequest | + mergeRequest jiraIssue isNotNil ] ] { #category : #loading } -UserMetric >> loadMergeRequestsSince: since until: until [ +UserMetric >> loadMergeRequestsOfUser: anUser since: since until: until [ | cacheSymbol mergeRequests | glhImporter withCommitDiffs: false. @@ -161,7 +157,7 @@ UserMetric >> loadMergeRequestsSince: since until: until [ since: since until: until. - mergeRequests := user contributedProjects collect: [ :project | + mergeRequests := anUser contributedProjects collect: [ :project | | mr | project cacheAt: cacheSymbol ifAbsentPut: [ mr := glhImporter @@ -175,7 +171,7 @@ UserMetric >> loadMergeRequestsSince: since until: until [ mergeRequests do: [ :mr | glhImporter importMergeResquestAuthor: mr ]. - ^ mergeRequests "select: [ :mergeRequest | mergeRequest author = user ]" + ^ mergeRequests select: [ :mergeRequest | mergeRequest author = anUser ] ] { #category : #loading } @@ -200,25 +196,6 @@ UserMetric >> loadMergeRequestsWithJiraIssueOfUser: anUser since: since until: u mergeRequest jiraIssue isNotNil ] ] -{ #category : #loading } -UserMetric >> loadMergeRequestsWithJiraIssueSince: since until: until [ - - | email mergeRequests | - mergeRequests := self loadMergeRequestsSince: since until: until. - - email := self userEmail. - - jiraImporter importAllCurrentAndPastIssuesOf: email. - - GPJCConnector new - gpModel: glhImporter glhModel; - jiraModel: jiraImporter model; - connect. - - ^ mergeRequests select: [ :mergeRequest | - mergeRequest jiraIssue isNotNil ] -] - { #category : #accessing } UserMetric >> name [ From 6821c1b31aa1746cc5b560a712815d84a69d522c Mon Sep 17 00:00:00 2001 From: BAUVENT Kilian Date: Mon, 16 Sep 2024 17:06:37 +0200 Subject: [PATCH 128/154] fix: csv display not working --- .../GitMetricExporter.class.st | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 4c732f9..607363d 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -263,41 +263,32 @@ GitMetricExporter >> exportUserAnalysesInCSV [ | exportBrowserModel groupedByOver group groupOver groupByName periods csvMetrics file | exportBrowserModel := MiExportModel new. - groupedByOver := self userAnalyses groupedBy: #over. - - groupedByOver associations do: [ :groupAssociation | group := groupAssociation value. groupOver := groupAssociation key. - - groupByName := group groupedBy: #username. exportBrowserModel entitiesList: groupByName. - exportBrowserModel removeColumnForQueryNamed: #Type. exportBrowserModel removeColumnForQueryNamed: #Name. - exportBrowserModel addColumnForQuery: [ :groupAnalyses | (groupAnalyses at: 1) username ] withName: #'User name'. - periods := (group groupedBy: #period) keys. - periods do: [ :period | csvMetrics := self csvMetricsFor: self userMetrics at: (period at: #since). - - csvMetrics associations do: [ :association | exportBrowserModel addColumnForQuery: association value withName: association key ] ]. - file := self constructFilePath: groupOver. file writeStreamDo: [ :aStream | + aStream + << 'sep=,'; + << OSPlatform current lineEnding. exportBrowserModel writeCSVOn: aStream ] ] ] From 39d05135de16a6e7e06654975f07deab2d90cbd6 Mon Sep 17 00:00:00 2001 From: BAUVENT Kilian Date: Mon, 16 Sep 2024 17:12:36 +0200 Subject: [PATCH 129/154] fix: jiraTimeMRtimeDifference return an empty array when there is no data --- .../GitMetricExporter.class.st | 6 +++++- .../JiraTimeMRTimeDifferenceMetric.class.st | 10 +++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 607363d..16703a2 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -255,6 +255,9 @@ GitMetricExporter >> exportProjectAnalysesInCSV [ file := self constructFilePath: groupOver. file writeStreamDo: [ :aStream | + aStream + << 'sep=,'; + << OSPlatform current lineEnding. exportBrowserModel writeCSVOn: aStream ] ] ] @@ -443,7 +446,8 @@ GitMetricExporter >> initialize [ ClosedMergeRequestMetric. MergedMergeRequestMetric. SelfMergedUnderAMinuteMergeRequestMetric. - ClosedTicketsMetric. JiraTimeMRTimeDifferenceMetric } + ClosedTicketsMetric . + JiraTimeMRTimeDifferenceMetric } ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st b/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st index dc5cde9..92e6b09 100644 --- a/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st @@ -7,7 +7,7 @@ Class { { #category : #calculating } JiraTimeMRTimeDifferenceMetric >> calculate [ - | groupedByDate dateOver | + | groupedByDate dateOver average | userMergeRequests ifNil: [ self load ]. groupedByDate := self setupGroupedDate. @@ -45,8 +45,12 @@ JiraTimeMRTimeDifferenceMetric >> calculate [ timeOriginalEstimate ]. jiraTime - mergeRequestTime ] ]. - - ^groupedByDate average ifNil: [ nil ] ifNotNil: [ groupedByDate average ] + + groupedByDate := groupedByDate select: [ :group | group isNotEmpty ]. + average := groupedByDate ifEmpty: [ nil ] ifNotEmpty: [ groupedByDate average ]. + + ^average. + ] { #category : #accessing } From ab2c5625a3c871251e72fa9d3626edcd75c5a585 Mon Sep 17 00:00:00 2001 From: BAUVENT Kilian Date: Tue, 17 Sep 2024 10:26:21 +0200 Subject: [PATCH 130/154] test: add calculate and calculateWithNoMR tests for JiraTimeMRTime difference --- .../GLPHImporterMock.class.st | 6 ++ .../JiraImporterMock.class.st | 6 +- ...iraTimeMRTimeDifferenceMetricTest.class.st | 46 +++++++++++- .../JiraTimeMRTimeDifferenceMetric.class.st | 73 ++++++++++--------- 4 files changed, 92 insertions(+), 39 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st b/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st index d5e860e..6aafd99 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st @@ -58,6 +58,12 @@ GLPHImporterMock >> importCreatorOfCommit: commit [ ^self ] +{ #category : #'import - merge request' } +GLPHImporterMock >> importMergeRequestCommits: mergeRequest [ + + mergeRequest commits: self commits +] + { #category : #'import - merge request' } GLPHImporterMock >> importMergeRequests: project since: since until: until [ diff --git a/src/GitLabHealth-Model-Analysis-Tests/JiraImporterMock.class.st b/src/GitLabHealth-Model-Analysis-Tests/JiraImporterMock.class.st index 3ba29d2..f267524 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/JiraImporterMock.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/JiraImporterMock.class.st @@ -16,8 +16,10 @@ JiraImporterMock >> importAllCurrentAndPastIssuesOf: email [ ] { #category : #initialization } -JiraImporterMock >> initialize [ - model := GLPHEModel new name: 'model' +JiraImporterMock >> initialize [ + + model := GLPHEModel new name: 'model'. + issues := { }. ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis-Tests/JiraTimeMRTimeDifferenceMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/JiraTimeMRTimeDifferenceMetricTest.class.st index 4cf232c..233af38 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/JiraTimeMRTimeDifferenceMetricTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/JiraTimeMRTimeDifferenceMetricTest.class.st @@ -7,7 +7,7 @@ Class { #category : #'GitLabHealth-Model-Analysis-Tests' } -{ #category : #test } +{ #category : #tests } JiraTimeMRTimeDifferenceMetricTest >> testCalculate [ | result glhImporter user jiraImporter jiraMRDifference | @@ -21,11 +21,49 @@ JiraTimeMRTimeDifferenceMetricTest >> testCalculate [ glhImporter mergeRequests: { (GLPHEMergeRequest new author: user; created_at: '09-05-2024'; - merged_at: '09-06-2024'; + merged_at: '09-06-2024' asDate; title: '205 feat do something') }. + glhImporter commits: { (GLHCommit new + id: 1; + created_at: '09-05-2024' asDate; + commitCreator: user; + deletions: 5) }. + + jiraImporter := JiraImporterMock new. + jiraImporter issues: { (JPIssue new + key: '205'; + timeEstimate: 25 hours asDuration) }. + + + jiraMRDifference := JiraTimeMRTimeDifferenceMetric new + user: user; + glhImporter: glhImporter; + jiraImporter: jiraImporter; + setPeriodSince: '09-04-2024' + until: '09-04-2024'; + over: Week. + + "When" + result := jiraMRDifference calculate. + + "Then" + self assert: result equals: 1 hours asSeconds +] + +{ #category : #tests } +JiraTimeMRTimeDifferenceMetricTest >> testCalculateNoMergeRequests [ + + | result glhImporter user jiraImporter jiraMRDifference | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + jiraImporter := JiraImporterMock new. - jiraImporter issues: { (JPIssue new key: '205'; timeEstimate: '20') }. jiraMRDifference := JiraTimeMRTimeDifferenceMetric new @@ -40,5 +78,5 @@ JiraTimeMRTimeDifferenceMetricTest >> testCalculate [ result := jiraMRDifference calculate. "Then" - self assert: result equals: 1 + self assert: result equals: nil ] diff --git a/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st b/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st index 92e6b09..9d0aaf0 100644 --- a/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st @@ -7,20 +7,11 @@ Class { { #category : #calculating } JiraTimeMRTimeDifferenceMetric >> calculate [ - | groupedByDate dateOver average | + | groupedByDate dateOver | userMergeRequests ifNil: [ self load ]. + userMergeRequests ifEmpty: [ ^nil ]. groupedByDate := self setupGroupedDate. - userMergeRequests := userMergeRequests select: [ :mergeRequest | - | issueIsEstimated | - issueIsEstimated := mergeRequest jiraIssue - timeEstimate isNotNil or: - mergeRequest jiraIssue - timeOriginalEstimate - isNotNil. - mergeRequest merged_at isNotNil and: - issueIsEstimated ]. - userMergeRequests do: [ :userMergeRequest | dateOver := self transformDate: userMergeRequest created_at to: over. groupedByDate @@ -28,29 +19,32 @@ JiraTimeMRTimeDifferenceMetric >> calculate [ ifPresent: [ :value | value add: userMergeRequest ] ]. groupedByDate := groupedByDate collect: [ :group | - group collect: [ :mergeRequest | - | firstCommitDate mergeRequestTime jiraTime | - firstCommitDate := mergeRequest commits last - created_at. + | differences | + differences := group collect: [ :mergeRequest | + | firstCommitDate mergeRequestTime jiraTime | + firstCommitDate := mergeRequest + commits last + created_at. - mergeRequestTime := mergeRequest merged_at - - firstCommitDate. + mergeRequestTime := mergeRequest + merged_at + - + firstCommitDate. - jiraTime := mergeRequest jiraIssue - timeOriginalEstimate - ifNil: [ - mergeRequest jiraIssue timeEstimate ] - ifNotNil: [ - mergeRequest jiraIssue - timeOriginalEstimate ]. + jiraTime := mergeRequest jiraIssue + timeOriginalEstimate + ifNil: [ + mergeRequest jiraIssue + timeEstimate ] + ifNotNil: [ + mergeRequest jiraIssue + timeOriginalEstimate ]. - jiraTime - mergeRequestTime ] ]. - - groupedByDate := groupedByDate select: [ :group | group isNotEmpty ]. - average := groupedByDate ifEmpty: [ nil ] ifNotEmpty: [ groupedByDate average ]. - - ^average. - + (jiraTime - mergeRequestTime) + asSeconds ]. + differences average ]. + + ^ groupedByDate average ] { #category : #accessing } @@ -63,7 +57,20 @@ JiraTimeMRTimeDifferenceMetric >> description [ JiraTimeMRTimeDifferenceMetric >> load [ userMergeRequests := self - loadCompleteMergeRequestsWithJiraIssueOfUser: user + loadCompleteMergeRequestsWithJiraIssueOfUser: + user since: (period at: #since) - until: (period at: #until) + until: (period at: #until). + + + "Take only the mergeRequest who are merged and got a time estimated" + userMergeRequests := userMergeRequests select: [ :mergeRequest | + | issueIsEstimated | + issueIsEstimated := mergeRequest jiraIssue + timeEstimate isNotNil or: + mergeRequest jiraIssue + timeOriginalEstimate + isNotNil. + mergeRequest merged_at isNotNil and: + issueIsEstimated ]. ] From 1ec906474693a091d580c395e33a21971a689cf0 Mon Sep 17 00:00:00 2001 From: BAUVENT Kilian Date: Tue, 17 Sep 2024 10:32:22 +0200 Subject: [PATCH 131/154] test: add specific tests for JiraTimeMRTimeDifference --- ...iraTimeMRTimeDifferenceMetricTest.class.st | 86 +++++++++++++++++++ .../JiraTimeMRTimeDifferenceMetric.class.st | 2 +- 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/src/GitLabHealth-Model-Analysis-Tests/JiraTimeMRTimeDifferenceMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/JiraTimeMRTimeDifferenceMetricTest.class.st index 233af38..a363fd1 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/JiraTimeMRTimeDifferenceMetricTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/JiraTimeMRTimeDifferenceMetricTest.class.st @@ -80,3 +80,89 @@ JiraTimeMRTimeDifferenceMetricTest >> testCalculateNoMergeRequests [ "Then" self assert: result equals: nil ] + +{ #category : #tests } +JiraTimeMRTimeDifferenceMetricTest >> testCalculateWithNoEstimatedTime [ + + | result glhImporter user jiraImporter jiraMRDifference | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: '09-06-2024' asDate; + title: '205 feat do something') }. + + glhImporter commits: { (GLHCommit new + id: 1; + created_at: '09-05-2024' asDate; + commitCreator: user; + deletions: 5) }. + + jiraImporter := JiraImporterMock new. + jiraImporter issues: { (JPIssue new key: '205') }. + + + jiraMRDifference := JiraTimeMRTimeDifferenceMetric new + user: user; + glhImporter: glhImporter; + jiraImporter: jiraImporter; + setPeriodSince: '09-04-2024' + until: '09-04-2024'; + over: Week. + + "When" + result := jiraMRDifference calculate. + + "Then" + self assert: result equals: nil +] + +{ #category : #tests } +JiraTimeMRTimeDifferenceMetricTest >> testCalculateWithTimeOriginalEstimateAndNoTimeEstimate [ + + | result glhImporter user jiraImporter jiraMRDifference | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: '09-06-2024' asDate; + title: '205 feat do something') }. + + glhImporter commits: { (GLHCommit new + id: 1; + created_at: '09-05-2024' asDate; + commitCreator: user; + deletions: 5) }. + + jiraImporter := JiraImporterMock new. + jiraImporter issues: { (JPIssue new + key: '205'; + timeEstimate: nil; timeOriginalEstimate: 25 hours asDuration)}. + + + jiraMRDifference := JiraTimeMRTimeDifferenceMetric new + user: user; + glhImporter: glhImporter; + jiraImporter: jiraImporter; + setPeriodSince: '09-04-2024' + until: '09-04-2024'; + over: Week. + + "When" + result := jiraMRDifference calculate. + + "Then" + self assert: result equals: 1 hours asSeconds +] diff --git a/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st b/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st index 9d0aaf0..b5e05d2 100644 --- a/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st @@ -50,7 +50,7 @@ JiraTimeMRTimeDifferenceMetric >> calculate [ { #category : #accessing } JiraTimeMRTimeDifferenceMetric >> description [ - ^ 'average difference between jira estimate time and associated merge resquest time' + ^ 'average difference between jira estimate time and associated merge request time (time between first commit and merge date)' ] { #category : #loading } From 9ab06d2e8177657bb1131f468d938e7d28022689 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Tue, 17 Sep 2024 14:58:37 +0200 Subject: [PATCH 132/154] fix: import commit when importing merge request commit --- .../JiraTimeMRTimeDifferenceMetric.class.st | 6 +- .../GLHModelImporter.class.st | 2 +- .../GLPHModelImporter.class.st | 75 +++++++++---------- 3 files changed, 41 insertions(+), 42 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st b/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st index b5e05d2..b1d2d30 100644 --- a/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st @@ -61,9 +61,8 @@ JiraTimeMRTimeDifferenceMetric >> load [ user since: (period at: #since) until: (period at: #until). - - - "Take only the mergeRequest who are merged and got a time estimated" + + "Take only the merge requests that have been merged and given a time estimate" userMergeRequests := userMergeRequests select: [ :mergeRequest | | issueIsEstimated | issueIsEstimated := mergeRequest jiraIssue @@ -73,4 +72,5 @@ JiraTimeMRTimeDifferenceMetric >> load [ isNotNil. mergeRequest merged_at isNotNil and: issueIsEstimated ]. + ] diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index d8378fc..d173374 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -330,7 +330,7 @@ GLHModelImporter >> importCommit: aCommitID ofProject: aGLHProject [ result := self glhApi commit: aCommitID ofProject: aGLHProject id - withStat: false. + withStat: true. parsedResult := self parseCommitResult: result. self addCommits: { parsedResult } diff --git a/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st b/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st index d5f2dbe..f97a0fe 100644 --- a/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st +++ b/src/GitLabProjectHealth-Model-Importer/GLPHModelImporter.class.st @@ -136,39 +136,6 @@ GLPHModelImporter >> importCommitsOfBranch: aGLHBranch [ ] ] -{ #category : #import } -GLPHModelImporter >> importCommitsOfMergeResquest: aGLPHEMergeRequest [ - - | foundCommits | - foundCommits := OrderedCollection new. - - ('Import commit sha of MR: ' , aGLPHEMergeRequest iid printString) - recordInfo. - "the founds commits are added to the model during their respective import" - aGLPHEMergeRequest mergeRequestCommit: ((self - importCommitOfProject: aGLPHEMergeRequest project - withId: aGLPHEMergeRequest sha) ifNotNil: [ :commit | - foundCommits add: commit ]). - - ('Import commit merge_commit_sha of MR: ' - , aGLPHEMergeRequest iid printString) recordInfo. - aGLPHEMergeRequest mergedCommit: ((self - importCommitOfProject: aGLPHEMergeRequest project - withId: aGLPHEMergeRequest merge_commit_sha) ifNotNil: [ :commit | - foundCommits add: commit ]). - - ('Import commit squash_commit_sha of MR: ' - , aGLPHEMergeRequest iid printString) recordInfo. - aGLPHEMergeRequest squashCommit: ((self - importCommitOfProject: aGLPHEMergeRequest project - withId: aGLPHEMergeRequest squash_commit_sha) ifNotNil: [ :commit | - foundCommits add: commit ]). - - - self chainsCommitsFrom: foundCommits. - ^ foundCommits -] - { #category : #api } GLPHModelImporter >> importDiffOfCommit: aCommit [ @@ -250,14 +217,46 @@ GLPHModelImporter >> importMergeRequestCommits: aGLPHEMergeRequest [ page := page + 1 ] doWhileTrue: [ parseResult isNotEmpty ]. + commits := commits collect: [ :commit | self importCommit: commit id ofProject: aGLPHEMergeRequest project ]. aGLPHEMergeRequest commits: commits. - self glhModel - addAll: aGLPHEMergeRequest commits - unless: self blockOnIdEquality. + ^ commits ] +{ #category : #import } +GLPHModelImporter >> importMergeRequestMergeCommits: aGLPHEMergeRequest [ + + | foundCommits | + foundCommits := OrderedCollection new. + + ('Import commit sha of MR: ' , aGLPHEMergeRequest iid printString) + recordInfo. + "the founds commits are added to the model during their respective import" + aGLPHEMergeRequest mergeRequestCommit: ((self + importCommitOfProject: aGLPHEMergeRequest project + withId: aGLPHEMergeRequest sha) ifNotNil: [ :commit | + foundCommits add: commit ]). + + ('Import commit merge_commit_sha of MR: ' + , aGLPHEMergeRequest iid printString) recordInfo. + aGLPHEMergeRequest mergedCommit: ((self + importCommitOfProject: aGLPHEMergeRequest project + withId: aGLPHEMergeRequest merge_commit_sha) ifNotNil: [ :commit | + foundCommits add: commit ]). + + ('Import commit squash_commit_sha of MR: ' + , aGLPHEMergeRequest iid printString) recordInfo. + aGLPHEMergeRequest squashCommit: ((self + importCommitOfProject: aGLPHEMergeRequest project + withId: aGLPHEMergeRequest squash_commit_sha) ifNotNil: [ :commit | + foundCommits add: commit ]). + + + self chainsCommitsFrom: foundCommits. + ^ foundCommits +] + { #category : #'import - merge request' } GLPHModelImporter >> importMergeRequests: aGLHProject [ @@ -279,7 +278,7 @@ GLPHModelImporter >> importMergeRequests: aGLHProject [ "gets it related commits" aGLHProject mergeRequests do: [ :mr | - self importCommitsOfMergeResquest: mr ]. + self importMergeRequestMergeCommits: mr ]. self withCommitDiffs ifTrue: [ @@ -323,7 +322,7 @@ GLPHModelImporter >> importMergeRequests: aGLHProject since: fromDate until: toD "gets it related commits" aGLHProject mergeRequests do: [ :mr | - self importCommitsOfMergeResquest: mr ]. + self importMergeRequestMergeCommits: mr ]. self withCommitDiffs ifTrue: [ aGLHProject mergeRequests do: [ :mr | From 800acb94e1997445a7d814059de9eb5a7a9eee02 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Tue, 17 Sep 2024 15:12:12 +0200 Subject: [PATCH 133/154] refactor: change JiraTimeMRTimeDifference description --- .../JiraTimeMRTimeDifferenceMetric.class.st | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st b/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st index b1d2d30..2590676 100644 --- a/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st @@ -50,7 +50,7 @@ JiraTimeMRTimeDifferenceMetric >> calculate [ { #category : #accessing } JiraTimeMRTimeDifferenceMetric >> description [ - ^ 'average difference between jira estimate time and associated merge request time (time between first commit and merge date)' + ^ 'average difference in seconds between jira estimate time and associated merge request time (time between first commit and merge date)' ] { #category : #loading } From 4d21fe6af48f3c3be1512194e81738047b6c910e Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Tue, 17 Sep 2024 16:10:04 +0200 Subject: [PATCH 134/154] fix: multiple period analyses not working --- .../GitMetricExporter.class.st | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 16703a2..9825319 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -267,17 +267,21 @@ GitMetricExporter >> exportUserAnalysesInCSV [ | exportBrowserModel groupedByOver group groupOver groupByName periods csvMetrics file | exportBrowserModel := MiExportModel new. groupedByOver := self userAnalyses groupedBy: #over. + groupedByOver associations do: [ :groupAssociation | group := groupAssociation value. groupOver := groupAssociation key. + groupByName := group groupedBy: #username. exportBrowserModel entitiesList: groupByName. exportBrowserModel removeColumnForQueryNamed: #Type. exportBrowserModel removeColumnForQueryNamed: #Name. + exportBrowserModel addColumnForQuery: [ :groupAnalyses | (groupAnalyses at: 1) username ] withName: #'User name'. + periods := (group groupedBy: #period) keys. periods do: [ :period | csvMetrics := self @@ -287,7 +291,10 @@ GitMetricExporter >> exportUserAnalysesInCSV [ exportBrowserModel addColumnForQuery: association value withName: association key ] ]. + + file := self constructFilePath: groupOver. + file writeStreamDo: [ :aStream | aStream << 'sep=,'; @@ -333,16 +340,17 @@ GitMetricExporter >> findProjectsOfUser: aCollection [ { #category : #analysis } GitMetricExporter >> generateAnalysesOver: aDateWeekMonthOrYear [ - | userAnalyses projectAnalyses | + analyses := OrderedCollection new. runningPeriods do: [ :period | - userAnalyses := self - generateUsersAnalysesDuringPeriod: period - over: aDateWeekMonthOrYear. - projectAnalyses := self - generateProjectsAnalysesDuringPeriod: period - over: aDateWeekMonthOrYear ]. + analyses addAll: (self + generateUsersAnalysesDuringPeriod: period + over: aDateWeekMonthOrYear). + + analyses addAll: (self + generateProjectsAnalysesDuringPeriod: period + over: aDateWeekMonthOrYear) ]. - ^ analyses := userAnalyses, projectAnalyses. + ^ analyses ] { #category : #analysis } @@ -446,8 +454,7 @@ GitMetricExporter >> initialize [ ClosedMergeRequestMetric. MergedMergeRequestMetric. SelfMergedUnderAMinuteMergeRequestMetric. - ClosedTicketsMetric . - JiraTimeMRTimeDifferenceMetric } + ClosedTicketsMetric. JiraTimeMRTimeDifferenceMetric } ] { #category : #accessing } From cb9dd0374962fcf0898070fffeb2876471dd16cb Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Wed, 18 Sep 2024 11:21:30 +0200 Subject: [PATCH 135/154] fix: merge requests loading (#63) --- .../ClosedMergeRequestMetric.class.st | 12 +- .../CommentContributionMetric.class.st | 2 +- .../JiraTimeMRTimeDifferenceMetric.class.st | 7 +- .../MergedMergeRequestMetric.class.st | 8 ++ .../ReviewedByUserMergeRequestMetric.class.st | 3 +- ...gedUnderAMinuteMergeRequestMetric.class.st | 3 +- .../UserCommitsMetric.class.st | 2 +- .../UserJiraMetric.class.st | 3 +- .../UserMergeRequestMetric.class.st | 3 +- .../UserMetric.class.st | 115 ++++++++++++------ 10 files changed, 97 insertions(+), 61 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st index 1cf7693..56fd116 100644 --- a/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/ClosedMergeRequestMetric.class.st @@ -7,16 +7,14 @@ Class { { #category : #calculating } ClosedMergeRequestMetric >> calculate [ - | groupedByDate userClosedMergeRequests dateOver | + | groupedByDate dateOver | userMergeRequests ifNil: [ self load ]. groupedByDate := self setupGroupedDate. + + userMergeRequests := userMergeRequests select: [ :userMergeRequest | + userMergeRequest state = 'closed' ]. - userClosedMergeRequests := userMergeRequests select: [ - :userMergeRequest | - "userMergeRequest merged_at isNil and:" - userMergeRequest state = 'closed' ]. - - userClosedMergeRequests do: [ :userMergeRequest | + userMergeRequests do: [ :userMergeRequest | dateOver := self transformDate: userMergeRequest created_at to: over. groupedByDate diff --git a/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st b/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st index 8811872..5872abd 100644 --- a/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CommentContributionMetric.class.st @@ -49,6 +49,6 @@ CommentContributionMetric >> description [ CommentContributionMetric >> load [ userCommits := self - loadCompleteCommitsSince: (period at: #since) + loadUserCompleteCommitsSince: (period at: #since) until: (period at: #until) ] diff --git a/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st b/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st index 2590676..144e4e2 100644 --- a/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st @@ -57,9 +57,7 @@ JiraTimeMRTimeDifferenceMetric >> description [ JiraTimeMRTimeDifferenceMetric >> load [ userMergeRequests := self - loadCompleteMergeRequestsWithJiraIssueOfUser: - user - since: (period at: #since) + loadUserCompleteMergeRequestsWithJiraIssueSince: (period at: #since) until: (period at: #until). "Take only the merge requests that have been merged and given a time estimate" @@ -71,6 +69,5 @@ JiraTimeMRTimeDifferenceMetric >> load [ timeOriginalEstimate isNotNil. mergeRequest merged_at isNotNil and: - issueIsEstimated ]. - + issueIsEstimated ] ] diff --git a/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st index 82e8f7d..4217136 100644 --- a/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/MergedMergeRequestMetric.class.st @@ -34,6 +34,14 @@ MergedMergeRequestMetric >> description [ ^ 'number of merge request merged by this user' ] +{ #category : #loading } +MergedMergeRequestMetric >> load [ + + userMergeRequests := self + loadMergeRequestsSince: (period at: #since) + until: (period at: #until) +] + { #category : #accessing } MergedMergeRequestMetric >> name [ diff --git a/src/GitLabHealth-Model-Analysis/ReviewedByUserMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/ReviewedByUserMergeRequestMetric.class.st index 9797975..ca408fe 100644 --- a/src/GitLabHealth-Model-Analysis/ReviewedByUserMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/ReviewedByUserMergeRequestMetric.class.st @@ -46,8 +46,7 @@ ReviewedByUserMergeRequestMetric >> description [ ReviewedByUserMergeRequestMetric >> load [ userMergeRequests := self - loadCompleteMergeRequestsOfUser: user since: - (period at: #since) + loadCompleteMergeRequestsSince: (period at: #since) until: (period at: #until) ] diff --git a/src/GitLabHealth-Model-Analysis/SelfMergedUnderAMinuteMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/SelfMergedUnderAMinuteMergeRequestMetric.class.st index d519400..32ff2c0 100644 --- a/src/GitLabHealth-Model-Analysis/SelfMergedUnderAMinuteMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/SelfMergedUnderAMinuteMergeRequestMetric.class.st @@ -53,8 +53,7 @@ SelfMergedUnderAMinuteMergeRequestMetric >> description [ SelfMergedUnderAMinuteMergeRequestMetric >> load [ userMergeRequests := self - loadCompleteMergeRequestsOfUser: user - since: (period at: #since) + loadCompleteMergeRequestsSince: (period at: #since) until: (period at: #until) ] diff --git a/src/GitLabHealth-Model-Analysis/UserCommitsMetric.class.st b/src/GitLabHealth-Model-Analysis/UserCommitsMetric.class.st index 645aadb..e891e4a 100644 --- a/src/GitLabHealth-Model-Analysis/UserCommitsMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserCommitsMetric.class.st @@ -20,7 +20,7 @@ UserCommitsMetric >> description [ UserCommitsMetric >> load [ userCommits := self - loadCommitsSince: (period at: #since) + loadUserCommitsSince: (period at: #since) until: (period at: #until) ] diff --git a/src/GitLabHealth-Model-Analysis/UserJiraMetric.class.st b/src/GitLabHealth-Model-Analysis/UserJiraMetric.class.st index 845662d..ba19b36 100644 --- a/src/GitLabHealth-Model-Analysis/UserJiraMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserJiraMetric.class.st @@ -20,8 +20,7 @@ UserJiraMetric >> description [ UserJiraMetric >> load [ userMergeRequests := self - loadMergeRequestsWithJiraIssueOfUser: user since: - (period at: #since) + loadUserMergeRequestsWithJiraIssueSince: (period at: #since) until: (period at: #until) ] diff --git a/src/GitLabHealth-Model-Analysis/UserMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/UserMergeRequestMetric.class.st index 17696fe..d635858 100644 --- a/src/GitLabHealth-Model-Analysis/UserMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserMergeRequestMetric.class.st @@ -20,8 +20,9 @@ UserMergeRequestMetric >> description [ UserMergeRequestMetric >> load [ userMergeRequests := self - loadMergeRequestsOfUser: user since: (period at: #since) + loadUserMergeRequestsSince: (period at: #since) until: (period at: #until) + ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/UserMetric.class.st b/src/GitLabHealth-Model-Analysis/UserMetric.class.st index 3aa722f..ecd36c0 100644 --- a/src/GitLabHealth-Model-Analysis/UserMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserMetric.class.st @@ -69,7 +69,69 @@ UserMetric >> load [ ] { #category : #loading } -UserMetric >> loadCommitsSince: since until: until [ +UserMetric >> loadCompleteMergeRequestsSince: since until: until [ + + | mergeRequests | + mergeRequests := self + loadMergeRequestsSince: since until: until. + + mergeRequests do: [ :mergeRequest | + glhImporter importMergeResquestMerger: mergeRequest. + glhImporter importMergeRequestCommits: mergeRequest ]. + + ^ mergeRequests +] + +{ #category : #loading } +UserMetric >> loadMergeRequestsSince: since until: until [ + + | cacheSymbol mergeRequests | + glhImporter withCommitDiffs: false. + cacheSymbol := self + cacheSymbolFor: GLPHEMergeRequest + since: since + until: until. + + mergeRequests := user contributedProjects collect: [ :project | + | mr | + project cacheAt: cacheSymbol ifAbsentPut: [ + mr := glhImporter + importMergeRequests: project + since: since + until: until. + mr ] ]. + + mergeRequests := mergeRequests flattened. + glhImporter withCommitDiffs: true. + + mergeRequests do: [ :mr | glhImporter importMergeResquestAuthor: mr ]. + + ^ mergeRequests "mergeRequests select: [ :mergeRequest | + mergeRequest author = user ]" +] + +{ #category : #loading } +UserMetric >> loadMergeRequestsWithJiraIssueSince: since until: until [ + + | email mergeRequests | + mergeRequests := self + loadMergeRequestsSince: since until: until. + + email := self userEmail. + + jiraImporter importAllCurrentAndPastIssuesOf: email. + + GPJCConnector new + gpModel: glhImporter glhModel; + jiraModel: jiraImporter model; + connect. + + ^ mergeRequests select: [ :mergeRequest | + mergeRequest jiraIssue isNotNil ] +] + +{ #category : #loading } +UserMetric >> loadUserCommitsSince: since until: until [ | cacheSymbol allCommits | glhImporter withCommitDiffs: false. @@ -101,22 +163,19 @@ UserMetric >> loadCommitsSince: since until: until [ ] { #category : #loading } -UserMetric >> loadCompleteCommitsSince: since until: until [ +UserMetric >> loadUserCompleteCommitsSince: since until: until [ | commits | - commits := self loadCommitsSince: since until: until. + commits := self loadUserCommitsSince: since until: until. commits do: [ :commit | glhImporter completeImportedCommit: commit ]. ^ commits ] { #category : #loading } -UserMetric >> loadCompleteMergeRequestsOfUser: anUser since: since until: until [ +UserMetric >> loadUserCompleteMergeRequestsSince: since until: until [ | mergeRequests | - mergeRequests := self - loadMergeRequestsOfUser: anUser - since: since - until: until. + mergeRequests := self loadUserMergeRequestsSince: since until: until. mergeRequests do: [ :mergeRequest | glhImporter importMergeResquestMerger: mergeRequest. @@ -126,13 +185,10 @@ UserMetric >> loadCompleteMergeRequestsOfUser: anUser since: since until: until ] { #category : #loading } -UserMetric >> loadCompleteMergeRequestsWithJiraIssueOfUser: anUser since: since until: until [ +UserMetric >> loadUserCompleteMergeRequestsWithJiraIssueSince: since until: until [ | email mergeRequests | - mergeRequests := self - loadCompleteMergeRequestsOfUser: anUser - since: since - until: until. + mergeRequests := self loadUserCompleteMergeRequestsSince: since until: until. email := self userEmail. @@ -148,40 +204,19 @@ UserMetric >> loadCompleteMergeRequestsWithJiraIssueOfUser: anUser since: since ] { #category : #loading } -UserMetric >> loadMergeRequestsOfUser: anUser since: since until: until [ - - | cacheSymbol mergeRequests | - glhImporter withCommitDiffs: false. - cacheSymbol := self - cacheSymbolFor: GLPHEMergeRequest - since: since - until: until. +UserMetric >> loadUserMergeRequestsSince: since until: until [ - mergeRequests := anUser contributedProjects collect: [ :project | - | mr | - project cacheAt: cacheSymbol ifAbsentPut: [ - mr := glhImporter - importMergeRequests: project - since: since - until: until. - mr ] ]. - - mergeRequests := mergeRequests flattened. - glhImporter withCommitDiffs: true. - - mergeRequests do: [ :mr | glhImporter importMergeResquestAuthor: mr ]. + | mergeRequests | + mergeRequests := self loadMergeRequestsSince: since until: until. - ^ mergeRequests select: [ :mergeRequest | mergeRequest author = anUser ] + ^ mergeRequests select: [ :mergeRequest | mergeRequest author = user ] ] { #category : #loading } -UserMetric >> loadMergeRequestsWithJiraIssueOfUser: anUser since: since until: until [ +UserMetric >> loadUserMergeRequestsWithJiraIssueSince: since until: until [ | email mergeRequests | - mergeRequests := self - loadMergeRequestsOfUser: anUser - since: since - until: until. + mergeRequests := self loadUserMergeRequestsSince: since until: until. email := self userEmail. From 2dfe0a08eec80f6e61915488ec2223d56ab15800 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:03:37 +0200 Subject: [PATCH 136/154] fix: GitlabHealth-Model-Analysis-Tests package is not in coverage (#62) * fix: typo in gitlab package name in smalltalk.ston * chore: add gitlabHealth-model-analysis-tests in core baseline * fix: test closedMergeRequestMetric * test: add tests for reviewedByUserMergeRequestMetric and SelfMergedUnderAMinuteMergeRequestMetric --- .smalltalk.ston | 2 +- .../BaselineOfGitLabHealth.class.st | 5 ++- .../ClosedMergeRequestMetricTest.class.st | 8 ++-- ...iewedByUserMergeRequestMetricTest.class.st | 39 ++++++++++++++++ ...nderAMinuteMergeRequestMetricTest.class.st | 45 +++++++++++++++++++ ...gedUnderAMinuteMergeRequestMetric.class.st | 3 +- 6 files changed, 94 insertions(+), 8 deletions(-) diff --git a/.smalltalk.ston b/.smalltalk.ston index 0b19fe0..7749e40 100644 --- a/.smalltalk.ston +++ b/.smalltalk.ston @@ -11,7 +11,7 @@ SmalltalkCISpec { } ], #testing: { - #packages : [ 'GitLab*', 'GLPH.*', 'GitHub.*', 'GitProject.*' ], + #packages : [ 'GitLab.*', 'GLPH.*', 'GitHub.*', 'GitProject.*' ], #coverage : { #packages : [ 'GitLab.*', 'GLPH.*', 'GitHub.*', 'GitProject.*' ], #format : #lcov diff --git a/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st b/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st index 1f39f27..82cc0ec 100644 --- a/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st +++ b/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st @@ -56,7 +56,8 @@ BaselineOfGitLabHealth >> defineGroups: spec [ spec group: 'Jira' with: - #( 'GitProject-JiraConnector' 'GitProject-JiraConnector-Generator' 'GitProject-JiraConnector-Tests' ). + #( 'GitProject-JiraConnector' 'GitProject-JiraConnector-Generator' + 'GitProject-JiraConnector-Tests' ). spec group: 'Core' with: #( 'GitLabHealth-Model' 'GitLabHealth-Model-Extension' @@ -66,7 +67,7 @@ BaselineOfGitLabHealth >> defineGroups: spec [ 'GitLabHealth-Model-Importer' 'GitLabHealth-Model-Importer-Tests' 'GitHubHealth-Model-Importer-Tests' 'GLPHExtended-Model' 'GLPHExtended-Model-Tests' - 'GLPHExtended-Model-Extension' 'GitLabHealth-Model-Analysis' + 'GLPHExtended-Model-Extension' 'GitLabHealth-Model-Analysis' 'GitLabHealth-Model-Analysis-Tests' 'GitLabHealth-Visualization' 'GitLabProjectHealth-ExtendModel-Generator' 'GitLabProjectHealth-Model-Importer' 'GitLabProjectHealth-Model-Importer-Tests' ). diff --git a/src/GitLabHealth-Model-Analysis-Tests/ClosedMergeRequestMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/ClosedMergeRequestMetricTest.class.st index 1bf9f7e..7442a8a 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/ClosedMergeRequestMetricTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/ClosedMergeRequestMetricTest.class.st @@ -67,18 +67,18 @@ ClosedMergeRequestMetricTest >> testCalculate1MRinPeriod2Outside [ created_at: '09-05-2024'; merged_at: nil; state: 'closed'). - (GLPHEMergeRequest new + (GLPHEMergeRequest new author: user; created_at: '08-01-2024'; merged_at: nil; - state: 'closed')}. + state: 'closed') }. closedMergeRequestMetric := ClosedMergeRequestMetric new user: user; glhImporter: glhImporter; - setPeriodSince: '08-01-2024' - until: '08-05-2024'; + setPeriodSince: '07-28-2024' + until: '08-03-2024'; over: Week. "When" diff --git a/src/GitLabHealth-Model-Analysis-Tests/ReviewedByUserMergeRequestMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/ReviewedByUserMergeRequestMetricTest.class.st index 37fecb9..d366be3 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/ReviewedByUserMergeRequestMetricTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/ReviewedByUserMergeRequestMetricTest.class.st @@ -80,6 +80,45 @@ ReviewedByUserMergeRequestMetricTest >> testCalculateNoMergeRequests [ self assert: result equals: 0 ] +{ #category : #tests } +ReviewedByUserMergeRequestMetricTest >> testCalculateReviewButNotCreated [ + + | result glhImporter user mergedMergeRequestWithoutReview user2 | + "Given" + user := GLHUser new + name: 'testUser'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + user2 := GLHUser new + name: 'testUser2'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { + (GLPHEMergeRequest new + author: user2; + merge_user: user2; + reviewers: { user }; + created_at: '09-05-2024:00-00-00' asDateAndTime; + merged_at: '09-05-2024:00-00-01' asDateAndTime). }. + + + mergedMergeRequestWithoutReview := ReviewedByUserMergeRequestMetric + new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-04-2024' + until: '09-04-2024'; + over: Week. + + "When" + result := mergedMergeRequestWithoutReview calculate. + + "Then" + self assert: result equals: 1 +] + { #category : #test } ReviewedByUserMergeRequestMetricTest >> testCalculateReviewByOther [ diff --git a/src/GitLabHealth-Model-Analysis-Tests/SelfMergedUnderAMinuteMergeRequestMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/SelfMergedUnderAMinuteMergeRequestMetricTest.class.st index c2100bb..f7b0444 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/SelfMergedUnderAMinuteMergeRequestMetricTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/SelfMergedUnderAMinuteMergeRequestMetricTest.class.st @@ -47,6 +47,51 @@ SelfMergedUnderAMinuteMergeRequestMetricTest >> testCalculate [ self assert: result equals: 1 ] +{ #category : #tests } +SelfMergedUnderAMinuteMergeRequestMetricTest >> testCalculateMergeButNotCreated [ + + | result glhImporter user mergedMergeRequestWithoutReview user2 | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + user2 := GLHUser new + name: 'testUser2'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { + (GLPHEMergeRequest new + author: user2; + merge_user: user; + reviewers: { user }; + created_at: '09-05-2024:00-00-00' asDateAndTime; + merged_at: '09-05-2024:00-00-01' asDateAndTime). + (GLPHEMergeRequest new + author: user; + merge_user: nil; + created_at: '09-05-2024:00-00-00' asDateAndTime; + merged_at: '09-05-2024:00-00-01' asDateAndTime) }. + + + mergedMergeRequestWithoutReview := SelfMergedUnderAMinuteMergeRequestMetric + new + user: user; + glhImporter: glhImporter; + setPeriodSince: '09-04-2024' + until: '09-04-2024'; + over: Week. + + "When" + result := mergedMergeRequestWithoutReview calculate. + + "Then" + self assert: result equals: 0 +] + { #category : #tests } SelfMergedUnderAMinuteMergeRequestMetricTest >> testCalculateNoMergeRequests [ diff --git a/src/GitLabHealth-Model-Analysis/SelfMergedUnderAMinuteMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/SelfMergedUnderAMinuteMergeRequestMetric.class.st index 32ff2c0..cf25445 100644 --- a/src/GitLabHealth-Model-Analysis/SelfMergedUnderAMinuteMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/SelfMergedUnderAMinuteMergeRequestMetric.class.st @@ -53,7 +53,8 @@ SelfMergedUnderAMinuteMergeRequestMetric >> description [ SelfMergedUnderAMinuteMergeRequestMetric >> load [ userMergeRequests := self - loadCompleteMergeRequestsSince: (period at: #since) + loadUserCompleteMergeRequestsSince: + (period at: #since) until: (period at: #until) ] From 457070a268920cea8fa249ab32f0d7f1998004d5 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:48:59 +0200 Subject: [PATCH 137/154] feat: add commitsNumberByJiraTicket metric --- .../CommitsNumberByJiraTicketsMetric.class.st | 39 +++++++++++++++++++ .../GitMetricExporter.class.st | 6 +++ 2 files changed, 45 insertions(+) create mode 100644 src/GitLabHealth-Model-Analysis/CommitsNumberByJiraTicketsMetric.class.st diff --git a/src/GitLabHealth-Model-Analysis/CommitsNumberByJiraTicketsMetric.class.st b/src/GitLabHealth-Model-Analysis/CommitsNumberByJiraTicketsMetric.class.st new file mode 100644 index 0000000..6ce6e12 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/CommitsNumberByJiraTicketsMetric.class.st @@ -0,0 +1,39 @@ +Class { + #name : #CommitsNumberByJiraTicketsMetric, + #superclass : #UserJiraMetric, + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #calculating } +CommitsNumberByJiraTicketsMetric >> calculate [ + + | groupedByDate dateOver | + userMergeRequests ifNil: [ self load ]. + userMergeRequests ifEmpty: [ ^ 0 ]. + groupedByDate := self setupGroupedDate. + userMergeRequests do: [ :userMergeRequest | + dateOver := self transformDate: userMergeRequest created_at to: over. + groupedByDate + at: dateOver printString + ifPresent: [ :value | value add: userMergeRequest ] ]. + groupedByDate := groupedByDate collect: [ :group | + | average | + average := (group collect: [ :mergeRequest | + mergeRequest commits size ]) average ]. + ^ groupedByDate average +] + +{ #category : #accessing } +CommitsNumberByJiraTicketsMetric >> description [ + + ^ 'average number of commit by merge request associated to a jira ticket' +] + +{ #category : #loading } +CommitsNumberByJiraTicketsMetric >> load [ + + userMergeRequests := self + loadUserCompleteMergeRequestsWithJiraIssueSince: + (period at: #since) + until: (period at: #until). +] diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 9825319..02579b4 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -473,6 +473,12 @@ GitMetricExporter >> maxCommitWindow: anInteger [ maxCommitWindow := anInteger abs ] +{ #category : #accessing } +GitMetricExporter >> metrics: anObject [ + + metrics := anObject +] + { #category : #adding } GitMetricExporter >> onlyImportProjectsOfGroup: groupId [ From d6bce78390e347029dab9d4ff3cb0a43fcc2a90d Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:50:35 +0200 Subject: [PATCH 138/154] test: commitsNumberByJiraTicketMetric tests --- ...mitsNumberByJiraTicketsMetricTest.class.st | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 src/GitLabHealth-Model-Analysis-Tests/CommitsNumberByJiraTicketsMetricTest.class.st diff --git a/src/GitLabHealth-Model-Analysis-Tests/CommitsNumberByJiraTicketsMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/CommitsNumberByJiraTicketsMetricTest.class.st new file mode 100644 index 0000000..2bbd598 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis-Tests/CommitsNumberByJiraTicketsMetricTest.class.st @@ -0,0 +1,120 @@ +" +A CommitsNumberByJiraTicketsMetricTest is a test class for testing the behavior of CommitsNumberByJiraTicketsMetric +" +Class { + #name : #CommitsNumberByJiraTicketsMetricTest, + #superclass : #TestCase, + #category : #'GitLabHealth-Model-Analysis-Tests' +} + +{ #category : #tests } +CommitsNumberByJiraTicketsMetricTest >> testCalculate [ + + | result glhImporter user jiraImporter commitsNumber | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: '09-06-2024' asDate; + title: '205 feat do something') }. + + glhImporter commits: { (GLHCommit new + id: 1; + created_at: '09-05-2024' asDate; + commitCreator: user; + deletions: 5) }. + + jiraImporter := JiraImporterMock new. + jiraImporter issues: { (JPIssue new + key: '205'; + timeEstimate: 25 hours asDuration) }. + + + commitsNumber := CommitsNumberByJiraTicketsMetric new + user: user; + glhImporter: glhImporter; + jiraImporter: jiraImporter; + setPeriodSince: '09-04-2024' until: '09-04-2024'; + over: Week. + + "When" + result := commitsNumber calculate. + + "Then" + self assert: result equals: 1 +] + +{ #category : #tests } +CommitsNumberByJiraTicketsMetricTest >> testCalculateNoCommits [ + + | result glhImporter user jiraImporter commitsNumber | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: '09-06-2024' asDate; + title: '205 feat do something') }. + + jiraImporter := JiraImporterMock new. + jiraImporter issues: { (JPIssue new + key: '205'; + timeEstimate: 25 hours asDuration) }. + + + commitsNumber := CommitsNumberByJiraTicketsMetric new + user: user; + glhImporter: glhImporter; + jiraImporter: jiraImporter; + setPeriodSince: '09-04-2024' until: '09-04-2024'; + over: Week. + + "When" + result := commitsNumber calculate. + + "Then" + self assert: result equals: 0 +] + +{ #category : #tests } +CommitsNumberByJiraTicketsMetricTest >> testCalculateNoMergeRequests [ + + | result glhImporter user jiraImporter commitsNumber | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + + jiraImporter := JiraImporterMock new. + jiraImporter issues: { (JPIssue new + key: '205'; + timeEstimate: 25 hours asDuration) }. + + + commitsNumber := CommitsNumberByJiraTicketsMetric new + user: user; + glhImporter: glhImporter; + jiraImporter: jiraImporter; + setPeriodSince: '09-04-2024' until: '09-04-2024'; + over: Week. + + "When" + result := commitsNumber calculate. + + "Then" + self assert: result equals: 0 +] From bfca23d1301d4594017acdffd6efeb7e4e4271cd Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:57:40 +0200 Subject: [PATCH 139/154] feat: add commit number by jira tickets metric in git metric exporter initialize --- src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 02579b4..032b00e 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -454,7 +454,8 @@ GitMetricExporter >> initialize [ ClosedMergeRequestMetric. MergedMergeRequestMetric. SelfMergedUnderAMinuteMergeRequestMetric. - ClosedTicketsMetric. JiraTimeMRTimeDifferenceMetric } + ClosedTicketsMetric. + JiraTimeMRTimeDifferenceMetric. CommitsNumberByJiraTicketsMetric } ] { #category : #accessing } From 63393a37b708304650b46b7e08c10a3282dec2f1 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Wed, 18 Sep 2024 16:33:35 +0200 Subject: [PATCH 140/154] feat: add code addition by tickets metric --- .../CodeAdditionByTicketMetric.class.st | 44 +++++++++++++++++++ .../GitMetricExporter.class.st | 6 +++ 2 files changed, 50 insertions(+) create mode 100644 src/GitLabHealth-Model-Analysis/CodeAdditionByTicketMetric.class.st diff --git a/src/GitLabHealth-Model-Analysis/CodeAdditionByTicketMetric.class.st b/src/GitLabHealth-Model-Analysis/CodeAdditionByTicketMetric.class.st new file mode 100644 index 0000000..8a84ab6 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/CodeAdditionByTicketMetric.class.st @@ -0,0 +1,44 @@ +Class { + #name : #CodeAdditionByTicketMetric, + #superclass : #UserJiraMetric, + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #calculating } +CodeAdditionByTicketMetric >> calculate [ + + | groupedByDate dateOver | + userMergeRequests ifNil: [ self load ]. + groupedByDate := self setupGroupedDate. + userMergeRequests ifEmpty: [ ^ 0 ]. + + + userMergeRequests do: [ :userMergeRequest | + dateOver := self transformDate: userMergeRequest created_at to: over. + groupedByDate + at: dateOver printString + ifPresent: [ :value | value add: userMergeRequest ] ]. + + groupedByDate := groupedByDate collect: [ :group | + | average | + average := (group collect: [ :mergeRequest | mergeRequest commits sum: [ :commit | commit additions ] ]) average + + ]. + + ^ groupedByDate average asFloat +] + +{ #category : #accessing } +CodeAdditionByTicketMetric >> description [ + + ^ 'average code addition by merge request associated with a jira ticket' +] + +{ #category : #loading } +CodeAdditionByTicketMetric >> load [ + + userMergeRequests := self + loadUserCompleteMergeRequestsWithJiraIssueSince: + (period at: #since) + until: (period at: #until). +] diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 9825319..02579b4 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -473,6 +473,12 @@ GitMetricExporter >> maxCommitWindow: anInteger [ maxCommitWindow := anInteger abs ] +{ #category : #accessing } +GitMetricExporter >> metrics: anObject [ + + metrics := anObject +] + { #category : #adding } GitMetricExporter >> onlyImportProjectsOfGroup: groupId [ From 4a9fe6c2381f05dbdb9eda889669c817478edd4f Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Wed, 18 Sep 2024 16:33:56 +0200 Subject: [PATCH 141/154] test: code addition by metric tests --- .../CodeAdditionByTicketMetricTest.class.st | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 src/GitLabHealth-Model-Analysis-Tests/CodeAdditionByTicketMetricTest.class.st diff --git a/src/GitLabHealth-Model-Analysis-Tests/CodeAdditionByTicketMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/CodeAdditionByTicketMetricTest.class.st new file mode 100644 index 0000000..159ea3c --- /dev/null +++ b/src/GitLabHealth-Model-Analysis-Tests/CodeAdditionByTicketMetricTest.class.st @@ -0,0 +1,127 @@ +" +A CodeAdditionByTicketMetricTest is a test class for testing the behavior of CodeAdditionByTicketMetric +" +Class { + #name : #CodeAdditionByTicketMetricTest, + #superclass : #TestCase, + #category : #'GitLabHealth-Model-Analysis-Tests' +} + +{ #category : #tests } +CodeAdditionByTicketMetricTest >> testCalculate [ + + | result glhImporter user jiraImporter codeAddition | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: '09-06-2024' asDate; + title: '205 feat do something') }. + + glhImporter commits: { (GLHCommit new + id: 1; + created_at: '09-05-2024' asDate; + additions: 7; + commitCreator: user; + deletions: 5). (GLHCommit new + id: 2; + created_at: '09-05-2024' asDate; + additions: 3; + commitCreator: user; + deletions: 5) }. + + jiraImporter := JiraImporterMock new. + jiraImporter issues: { (JPIssue new + key: '205'; + timeEstimate: 25 hours asDuration) }. + + + codeAddition := CodeAdditionByTicketMetric new + user: user; + glhImporter: glhImporter; + jiraImporter: jiraImporter; + setPeriodSince: '09-04-2024' until: '09-04-2024'; + over: Week. + + "When" + result := codeAddition calculate. + + "Then" + self assert: result equals: 10 +] + +{ #category : #tests } +CodeAdditionByTicketMetricTest >> testCalculateNoCommits [ + + | result glhImporter user jiraImporter codeAddition | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: '09-06-2024' asDate; + title: '205 feat do something') }. + + + jiraImporter := JiraImporterMock new. + jiraImporter issues: { (JPIssue new + key: '205'; + timeEstimate: 25 hours asDuration) }. + + + codeAddition := CodeAdditionByTicketMetric new + user: user; + glhImporter: glhImporter; + jiraImporter: jiraImporter; + setPeriodSince: '09-04-2024' until: '09-04-2024'; + over: Week. + + "When" + result := codeAddition calculate. + + "Then" + self assert: result equals: 0 +] + +{ #category : #tests } +CodeAdditionByTicketMetricTest >> testCalculateNoMergeRequests [ + + | result glhImporter user jiraImporter codeAddition | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + + jiraImporter := JiraImporterMock new. + jiraImporter issues: { (JPIssue new + key: '205'; + timeEstimate: 25 hours asDuration) }. + + + codeAddition := CodeAdditionByTicketMetric new + user: user; + glhImporter: glhImporter; + jiraImporter: jiraImporter; + setPeriodSince: '09-04-2024' until: '09-04-2024'; + over: Week. + + "When" + result := codeAddition calculate. + + "Then" + self assert: result equals: 0 +] From d276c8d171696d80a32a910e47014cf2cc609919 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Wed, 18 Sep 2024 16:34:14 +0200 Subject: [PATCH 142/154] feat: add code deletion by metric --- .../CodeDeletionByTicketMetric.class.st | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/GitLabHealth-Model-Analysis/CodeDeletionByTicketMetric.class.st diff --git a/src/GitLabHealth-Model-Analysis/CodeDeletionByTicketMetric.class.st b/src/GitLabHealth-Model-Analysis/CodeDeletionByTicketMetric.class.st new file mode 100644 index 0000000..d65b2d4 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis/CodeDeletionByTicketMetric.class.st @@ -0,0 +1,44 @@ +Class { + #name : #CodeDeletionByTicketMetric, + #superclass : #UserJiraMetric, + #category : #'GitLabHealth-Model-Analysis' +} + +{ #category : #calculating } +CodeDeletionByTicketMetric >> calculate [ + + | groupedByDate dateOver | + userMergeRequests ifNil: [ self load ]. + groupedByDate := self setupGroupedDate. + userMergeRequests ifEmpty: [ ^ 0 ]. + + + userMergeRequests do: [ :userMergeRequest | + dateOver := self transformDate: userMergeRequest created_at to: over. + groupedByDate + at: dateOver printString + ifPresent: [ :value | value add: userMergeRequest ] ]. + + groupedByDate := groupedByDate collect: [ :group | + | average | + average := (group collect: [ :mergeRequest | + mergeRequest commits sum: [ :commit | + commit deletions ] ]) average ]. + + ^ groupedByDate average asFloat +] + +{ #category : #accessing } +CodeDeletionByTicketMetric >> description [ + + ^ 'average code deletion by merge request associated with a jira ticket' +] + +{ #category : #loading } +CodeDeletionByTicketMetric >> load [ + + userMergeRequests := self + loadUserCompleteMergeRequestsWithJiraIssueSince: + (period at: #since) + until: (period at: #until) +] From 48d7e7547b5f656641a5d40096ef19f2a65d4347 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Wed, 18 Sep 2024 16:34:30 +0200 Subject: [PATCH 143/154] test: code deletion by metric tests --- .../CodeDeletionByTicketMetricTest.class.st | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/GitLabHealth-Model-Analysis-Tests/CodeDeletionByTicketMetricTest.class.st diff --git a/src/GitLabHealth-Model-Analysis-Tests/CodeDeletionByTicketMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/CodeDeletionByTicketMetricTest.class.st new file mode 100644 index 0000000..dfa02e3 --- /dev/null +++ b/src/GitLabHealth-Model-Analysis-Tests/CodeDeletionByTicketMetricTest.class.st @@ -0,0 +1,128 @@ +" +A CodeDeletionByTicketMetricTest is a test class for testing the behavior of CodeDeletionByTicketMetric +" +Class { + #name : #CodeDeletionByTicketMetricTest, + #superclass : #TestCase, + #category : #'GitLabHealth-Model-Analysis-Tests' +} + +{ #category : #tests } +CodeDeletionByTicketMetricTest >> testCalculate [ + + | result glhImporter user jiraImporter codeAddition | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: '09-06-2024' asDate; + title: '205 feat do something') }. + + glhImporter commits: { + (GLHCommit new + id: 1; + created_at: '09-05-2024' asDate; + additions: 7; + commitCreator: user; + deletions: 5). + (GLHCommit new + id: 2; + created_at: '09-05-2024' asDate; + additions: 3; + commitCreator: user; + deletions: 5) }. + + jiraImporter := JiraImporterMock new. + jiraImporter issues: { (JPIssue new + key: '205'; + timeEstimate: 25 hours asDuration) }. + + + codeAddition := CodeAdditionByTicketMetric new + user: user; + glhImporter: glhImporter; + jiraImporter: jiraImporter; + setPeriodSince: '09-04-2024' until: '09-04-2024'; + over: Week. + + "When" + result := codeAddition calculate. + + "Then" + self assert: result equals: 10 +] + +{ #category : #tests } +CodeDeletionByTicketMetricTest >> testCalculateNoCommits [ + + | result glhImporter user jiraImporter codeAddition | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: '09-06-2024' asDate; + title: '205 feat do something') }. + + jiraImporter := JiraImporterMock new. + jiraImporter issues: { (JPIssue new + key: '205'; + timeEstimate: 25 hours asDuration) }. + + + codeAddition := CodeAdditionByTicketMetric new + user: user; + glhImporter: glhImporter; + jiraImporter: jiraImporter; + setPeriodSince: '09-04-2024' until: '09-04-2024'; + over: Week. + + "When" + result := codeAddition calculate. + + "Then" + self assert: result equals: 0 +] + +{ #category : #tests } +CodeDeletionByTicketMetricTest >> testCalculateNoMergeRequests [ + + | result glhImporter user jiraImporter codeAddition | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + + jiraImporter := JiraImporterMock new. + jiraImporter issues: { (JPIssue new + key: '205'; + timeEstimate: 25 hours asDuration) }. + + + codeAddition := CodeAdditionByTicketMetric new + user: user; + glhImporter: glhImporter; + jiraImporter: jiraImporter; + setPeriodSince: '09-04-2024' until: '09-04-2024'; + over: Week. + + "When" + result := codeAddition calculate. + + "Then" + self assert: result equals: 0 +] From 32560861bbe2bde0c8be113d9d620d24634c31b0 Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Thu, 19 Sep 2024 17:36:18 +0200 Subject: [PATCH 144/154] update ci --- .github/workflows/ci-dev.yml | 36 ++++++++++++++++++++++++++++++++ .github/workflows/ci-moose11.yml | 3 +-- ci/generatePUML.st | 8 +++---- 3 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/ci-dev.yml diff --git a/.github/workflows/ci-dev.yml b/.github/workflows/ci-dev.yml new file mode 100644 index 0000000..53b44bd --- /dev/null +++ b/.github/workflows/ci-dev.yml @@ -0,0 +1,36 @@ +name: CI + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +on: + push: + branches: + - develop + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + smalltalk: [ Moose64-11] + name: ${{ matrix.smalltalk }} + steps: + - uses: actions/checkout@v2 + with: + persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token. + fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository. + + - uses: hpi-swa/setup-smalltalkCI@v1 + with: + smalltalk-image: ${{ matrix.smalltalk }} + + - run: smalltalkci -s ${{ matrix.smalltalk }} + shell: bash + timeout-minutes: 15 + + - name: Coveralls + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + diff --git a/.github/workflows/ci-moose11.yml b/.github/workflows/ci-moose11.yml index 0790455..dca3694 100644 --- a/.github/workflows/ci-moose11.yml +++ b/.github/workflows/ci-moose11.yml @@ -7,14 +7,13 @@ on: push: branches: - main - - develop jobs: build: runs-on: ubuntu-latest strategy: matrix: - smalltalk: [ Moose64-11] + smalltalk: [ Moose64-11 ] name: ${{ matrix.smalltalk }} steps: - uses: actions/checkout@v2 diff --git a/ci/generatePUML.st b/ci/generatePUML.st index f957676..fb4f4da 100644 --- a/ci/generatePUML.st +++ b/ci/generatePUML.st @@ -1,10 +1,10 @@ documentor := FamixUMLDocumentor new. documentor - model: GLHModel; - beWithStubs; - excludeClasses: { GLHModel. TEntityMetaLevelDependency. Object . GLHEntity . GLHTEntityCreator }; + model: GLPHEModel color: Color white; + model: GLHModel color: Color white; + excludeClasses: { GLHModel. TEntityMetaLevelDependency. Object . GLHEntity . GLPHEEntity . GLPHEModel . GLPHETEntityCreator . GLHTEntityCreator . GLHGroupGroup }; generate. - + 'gitproject.puml' asFileReference writeStreamDo: [ :stream | FamixUMLPlantUMLBackend new outputStream: stream; From e4d30af2fd21c4e9bc845c42fa475fb18472af80 Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Thu, 19 Sep 2024 17:50:23 +0200 Subject: [PATCH 145/154] fix doc link --- README.md | 34 +--------------------------------- 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/README.md b/README.md index 388c7af..cc3765e 100644 --- a/README.md +++ b/README.md @@ -106,39 +106,7 @@ Here is the metamodel used in this project ## Connectors This project comes with connectors to others metamodel to increase its powerfullness. - -### Jira Connector - -The Jira connector connect this project to the [Pharo Jira API project](https://github.com/Evref-BL/Jira-Pharo-API). -It basically looks for commit and merge request links to Jira Issue. - -To install the connector, please perform: - -```st -Metacello new - repository: 'github://moosetechnology/GitProjectHealth:main/src'; - baseline: 'GitLabHealth'; - onConflict: [ :ex | ex useIncoming ]; - onUpgrade: [ :ex | ex useIncoming ]; - onDowngrade: [ :ex | ex useLoaded ]; - load: #( 'default' 'Jira' ) -``` - -> loading default is optional if you already loaded it. - -Then, it is possible to connect two models using - -```st -GPJCConnector new - gpModel: aGpModel; "or glh model" - jiraModel: aJiraModel; - connect -``` - -### Famix Connector - -> The project exists and some code already exists, but it is not released yet. -> Raise an issue if you want us to investigate more on this +Explore this part of the [documentation on the main website](https://modularmoose.org/moose-wiki/Users/gitproject-health). ## Contributor From bd793e59dc5b6868965d5d8801b49821ebcb8646 Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Thu, 19 Sep 2024 18:02:41 +0200 Subject: [PATCH 146/154] add baseline for famix connector --- .../BaselineOfGitLabHealth.class.st | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st b/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st index 82cc0ec..ab1b92b 100644 --- a/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st +++ b/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st @@ -13,6 +13,7 @@ BaselineOfGitLabHealth >> baseline: spec [ self definePackages: spec. self defineGroups: spec. self defineJiraConnector: spec. + self defineFamixConnector: spec. spec for: #( #WithoutFamix ) do: [ spec @@ -50,6 +51,19 @@ BaselineOfGitLabHealth >> defineDependencies: spec [ ] ] +{ #category : #baselines } +BaselineOfGitLabHealth >> defineFamixConnector: spec [ + + spec + package: 'GitProject-FamixConnector' + with: [ spec requires: #( 'GitProject-FamixConnector-Model' ) ]; + package: 'GitProject-FamixConnector-Model'; + package: 'GitProject-FamixConnector-Generator' + with: [ spec requires: #( 'GitProject-FamixConnector-Model' ) ]; + package: 'GitProject-FamixConnector-Tests' + with: [ spec requires: #( 'GitProject-FamixConnector' ) ] +] + { #category : #baselines } BaselineOfGitLabHealth >> defineGroups: spec [ @@ -58,6 +72,12 @@ BaselineOfGitLabHealth >> defineGroups: spec [ with: #( 'GitProject-JiraConnector' 'GitProject-JiraConnector-Generator' 'GitProject-JiraConnector-Tests' ). + + spec + group: 'Famix' + with: + #( 'GitProject-FamixConnector' 'GitProject-FamixConnector-Generator' + 'GitProject-FamixConnector-Tests' ). spec group: 'Core' with: #( 'GitLabHealth-Model' 'GitLabHealth-Model-Extension' @@ -67,7 +87,8 @@ BaselineOfGitLabHealth >> defineGroups: spec [ 'GitLabHealth-Model-Importer' 'GitLabHealth-Model-Importer-Tests' 'GitHubHealth-Model-Importer-Tests' 'GLPHExtended-Model' 'GLPHExtended-Model-Tests' - 'GLPHExtended-Model-Extension' 'GitLabHealth-Model-Analysis' 'GitLabHealth-Model-Analysis-Tests' + 'GLPHExtended-Model-Extension' 'GitLabHealth-Model-Analysis' + 'GitLabHealth-Model-Analysis-Tests' 'GitLabHealth-Visualization' 'GitLabProjectHealth-ExtendModel-Generator' 'GitLabProjectHealth-Model-Importer' 'GitLabProjectHealth-Model-Importer-Tests' ). From 1c9e4ff1bb9a8beb78fd65446d260cae2314ec0a Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Mon, 23 Sep 2024 10:28:46 +0200 Subject: [PATCH 147/154] fix: jiraTimeMRTimeDifferenceMetric error on 2 period (#66) * test: add test to cover new jiraTimeMRTimeDifference error * fix: JiraTimeMRTimeDifferenceMetric error --- ...iraTimeMRTimeDifferenceMetricTest.class.st | 44 +++++++++++++++++++ .../JiraTimeMRTimeDifferenceMetric.class.st | 12 +++-- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis-Tests/JiraTimeMRTimeDifferenceMetricTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/JiraTimeMRTimeDifferenceMetricTest.class.st index a363fd1..4e80cb4 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/JiraTimeMRTimeDifferenceMetricTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/JiraTimeMRTimeDifferenceMetricTest.class.st @@ -51,6 +51,50 @@ JiraTimeMRTimeDifferenceMetricTest >> testCalculate [ self assert: result equals: 1 hours asSeconds ] +{ #category : #tests } +JiraTimeMRTimeDifferenceMetricTest >> testCalculate2PeriodWith1EmptyPeriod [ + + | result glhImporter user jiraImporter jiraMRDifference | + "Given" + user := GLHUser new + username: 'test'; + contributedProjects: + { (GLHProject new repository: GLHRepository new) }. + + glhImporter := GLPHImporterMock new. + glhImporter mergeRequests: { (GLPHEMergeRequest new + author: user; + created_at: '09-05-2024'; + merged_at: '09-06-2024' asDate; + title: '205 feat do something') }. + + glhImporter commits: { (GLHCommit new + id: 1; + created_at: '09-05-2024' asDate; + commitCreator: user; + deletions: 5) }. + + jiraImporter := JiraImporterMock new. + jiraImporter issues: { (JPIssue new + key: '205'; + timeEstimate: 25 hours asDuration) }. + + + jiraMRDifference := JiraTimeMRTimeDifferenceMetric new + user: user; + glhImporter: glhImporter; + jiraImporter: jiraImporter; + setPeriodSince: '09-04-2024' + until: '09-09-2024'; + over: Week. + + "When" + result := jiraMRDifference calculate. + + "Then" + self assert: result equals: 1 hours /2 asSeconds +] + { #category : #tests } JiraTimeMRTimeDifferenceMetricTest >> testCalculateNoMergeRequests [ diff --git a/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st b/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st index 144e4e2..0b7f7cf 100644 --- a/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st @@ -9,7 +9,7 @@ JiraTimeMRTimeDifferenceMetric >> calculate [ | groupedByDate dateOver | userMergeRequests ifNil: [ self load ]. - userMergeRequests ifEmpty: [ ^nil ]. + userMergeRequests ifEmpty: [ ^ nil ]. groupedByDate := self setupGroupedDate. userMergeRequests do: [ :userMergeRequest | @@ -19,7 +19,7 @@ JiraTimeMRTimeDifferenceMetric >> calculate [ ifPresent: [ :value | value add: userMergeRequest ] ]. groupedByDate := groupedByDate collect: [ :group | - | differences | + | differences average | differences := group collect: [ :mergeRequest | | firstCommitDate mergeRequestTime jiraTime | firstCommitDate := mergeRequest @@ -42,9 +42,13 @@ JiraTimeMRTimeDifferenceMetric >> calculate [ (jiraTime - mergeRequestTime) asSeconds ]. - differences average ]. + + average := group ifEmpty: [ 0 ] ifNotEmpty: [ differences average ]. + average + ]. - ^ groupedByDate average + + ^ groupedByDate average ] { #category : #accessing } From 09b884182a07e05a2a3a2ef8886d252571d96b67 Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Mon, 23 Sep 2024 15:16:18 +0200 Subject: [PATCH 148/154] add import for only one project --- .../GHApi.class.st | 9 +++- .../GHModelImporter.class.st | 49 ++++++++++++++++--- 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/GitHubHealth-Model-Importer/GHApi.class.st b/src/GitHubHealth-Model-Importer/GHApi.class.st index 77fb4b2..10040e8 100644 --- a/src/GitHubHealth-Model-Importer/GHApi.class.st +++ b/src/GitHubHealth-Model-Importer/GHApi.class.st @@ -8,7 +8,7 @@ Class { 'baseAPIUrl', 'client' ], - #category : 'GitHubHealth-Model-Importer' + #category : #'GitHubHealth-Model-Importer' } { #category : #api } @@ -101,6 +101,13 @@ GHApi >> organization: anOrganizationName [ ^ self client get: self baseAPIUrl , '/orgs/' , anOrganizationName ] +{ #category : #api } +GHApi >> organization: aGroupName repo: aRepoName [ + + ^ self client get: + self baseAPIUrl , '/repos/' , aGroupName , '/' , aRepoName +] + { #category : #accessing } GHApi >> privateToken [ diff --git a/src/GitHubHealth-Model-Importer/GHModelImporter.class.st b/src/GitHubHealth-Model-Importer/GHModelImporter.class.st index c92fc30..fd483ad 100644 --- a/src/GitHubHealth-Model-Importer/GHModelImporter.class.st +++ b/src/GitHubHealth-Model-Importer/GHModelImporter.class.st @@ -4,7 +4,7 @@ Class { #instVars : [ 'api' ], - #category : 'GitHubHealth-Model-Importer' + #category : #'GitHubHealth-Model-Importer' } { #category : #accessing } @@ -42,6 +42,15 @@ GHModelImporter >> convertApiFileAsFile: aAPIFile [ yourself ] +{ #category : #api } +GHModelImporter >> ensureGroupNamed: aGroupName [ + + ^ self glhModel + detect: [ :a | + (a isKindOf: GLHGroup) and: [ a name = aGroupName ] ] + ifNone: [ self glhModel newGroupNamed: aGroupName ] +] + { #category : #api } GHModelImporter >> importBranchesOf: project [ @@ -173,6 +182,19 @@ GHModelImporter >> importPipelinesOf: project [ project addPipeline: pipeline ] ] +{ #category : #api } +GHModelImporter >> importProject: aProjectName ofGroup: aGroupName [ + + | result projectResult group | + group := self ensureGroupNamed: aGroupName. + result := self api organization: aGroupName repo: aProjectName. + projectResult := self parseProjectResult: result. + projectResult group: group. + self glhModel add: projectResult. + self completeImportProject: projectResult. + ^ projectResult +] + { #category : #api } GHModelImporter >> importRepositoriesOfGroup: groupResult [ @@ -230,7 +252,7 @@ GHModelImporter >> initialize [ withFiles := false ] -{ #category : #private } +{ #category : #parsing } GHModelImporter >> parseArrayOfProject: arrayOfProjects [ | reader | @@ -249,7 +271,7 @@ GHModelImporter >> parseArrayOfProject: arrayOfProjects [ ^ reader nextAs: #ArrayOfProjects ] -{ #category : #private } +{ #category : #parsing } GHModelImporter >> parseBranchesResult: arrayOfBranch [ | reader | @@ -318,7 +340,7 @@ GHModelImporter >> parseCommitsResult: result [ ^ reader nextAs: #ArrayOfCommit ] -{ #category : #private } +{ #category : #parsing } GHModelImporter >> parseFileTreeResult: aResult [ | reader | @@ -331,7 +353,7 @@ GHModelImporter >> parseFileTreeResult: aResult [ ^ reader nextAs: #ArrayOfFile ] -{ #category : #private } +{ #category : #parsing } GHModelImporter >> parseGroupResult: aResult [ | reader | @@ -344,7 +366,7 @@ GHModelImporter >> parseGroupResult: aResult [ ^ reader nextAs: GLHGroup ] -{ #category : #private } +{ #category : #parsing } GHModelImporter >> parsePipelinesResult: pipelineOverview [ | reader | @@ -366,6 +388,21 @@ GHModelImporter >> parsePipelinesResult: pipelineOverview [ ^ reader nextAs: GHAPIPipelineOverview ] +{ #category : #parsing } +GHModelImporter >> parseProjectResult: aResult [ + + | reader | + reader := NeoJSONReader on: aResult readStream. + reader for: GLHProject do: [ :mapping | + mapping mapInstVar: #name to: #name. + mapping mapInstVar: #description to: #description. + mapping mapInstVar: #id to: #id. + mapping mapInstVar: #archived to: #archived. + mapping mapInstVar: #web_url to: #html_url. + mapping mapInstVar: #topics to: #topics ]. + ^ reader nextAs: GLHProject +] + { #category : #parsing } GHModelImporter >> parseUserResult: result [ From a9b93e4fb7641e12e3105f2fcffa94a79413ae0b Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Mon, 23 Sep 2024 16:32:30 +0200 Subject: [PATCH 149/154] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cc3765e..bbd5adb 100644 --- a/README.md +++ b/README.md @@ -105,8 +105,8 @@ Here is the metamodel used in this project ## Connectors -This project comes with connectors to others metamodel to increase its powerfullness. -Explore this part of the [documentation on the main website](https://modularmoose.org/moose-wiki/Users/gitproject-health). +This project comes with connectors to other metamodels to increase its powerfulness. +Explore this part of the [documentation on the main website](https://modularmoose.org/moose-wiki/Users/gitproject-health/getting-started-with-gitproject-health). ## Contributor From d242ff4a0fcade41440681d9b6e2444bd2547c33 Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Tue, 24 Sep 2024 18:05:23 +0200 Subject: [PATCH 150/154] can load on Pharo 12 --- .../BaselineOfGitLabHealth.class.st | 23 ++++++++++--------- src/BaselineOfGitLabHealth/package.st | 2 +- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st b/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st index ab1b92b..ecbc2d4 100644 --- a/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st +++ b/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st @@ -1,10 +1,11 @@ Class { - #name : #BaselineOfGitLabHealth, - #superclass : #BaselineOf, - #category : #BaselineOfGitLabHealth + #name : 'BaselineOfGitLabHealth', + #superclass : 'BaselineOf', + #category : 'BaselineOfGitLabHealth', + #package : 'BaselineOfGitLabHealth' } -{ #category : #baselines } +{ #category : 'baselines' } BaselineOfGitLabHealth >> baseline: spec [ @@ -23,14 +24,14 @@ BaselineOfGitLabHealth >> baseline: spec [ spec package: 'GitLabHealth-Model' with: [ spec requires: #( 'Moose' ) ] ] ] ] -{ #category : #baselines } +{ #category : 'baselines' } BaselineOfGitLabHealth >> customProjectAttributes [ self class environment at: #MooseEntity ifAbsent: [ ^ #(#WithoutFamix) ]. ^ #() ] -{ #category : #baselines } +{ #category : 'baselines' } BaselineOfGitLabHealth >> defineDependencies: spec [ spec @@ -47,11 +48,11 @@ BaselineOfGitLabHealth >> defineDependencies: spec [ spec baseline: 'AWS' with: [ - spec repository: 'github://newapplesho/aws-sdk-smalltalk/pharo-repository' + spec repository: 'github://Evref-BL/aws-sdk-smalltalk:master/pharo-repository' ] ] -{ #category : #baselines } +{ #category : 'baselines' } BaselineOfGitLabHealth >> defineFamixConnector: spec [ spec @@ -64,7 +65,7 @@ BaselineOfGitLabHealth >> defineFamixConnector: spec [ with: [ spec requires: #( 'GitProject-FamixConnector' ) ] ] -{ #category : #baselines } +{ #category : 'baselines' } BaselineOfGitLabHealth >> defineGroups: spec [ spec @@ -95,7 +96,7 @@ BaselineOfGitLabHealth >> defineGroups: spec [ spec group: 'default' with: #( 'Core' ) ] -{ #category : #baselines } +{ #category : 'baselines' } BaselineOfGitLabHealth >> defineJiraConnector: spec [ spec @@ -116,7 +117,7 @@ BaselineOfGitLabHealth >> defineJiraConnector: spec [ spec repository: 'github://Evref-BL/Jira-Pharo-API:main/src' ] ] -{ #category : #baselines } +{ #category : 'baselines' } BaselineOfGitLabHealth >> definePackages: spec [ "generic" diff --git a/src/BaselineOfGitLabHealth/package.st b/src/BaselineOfGitLabHealth/package.st index 1aeec40..0d5dae3 100644 --- a/src/BaselineOfGitLabHealth/package.st +++ b/src/BaselineOfGitLabHealth/package.st @@ -1 +1 @@ -Package { #name : #BaselineOfGitLabHealth } +Package { #name : 'BaselineOfGitLabHealth' } From 950e5524c25de924003097e98845bbd9333968e9 Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Thu, 26 Sep 2024 09:29:27 +0200 Subject: [PATCH 151/154] fix importer --- .../GLHModelImporter.class.st | 13 ------------- src/GitLabHealth-Visualization/RSCommit.class.st | 4 ++-- .../GPModelImporter.class.st | 15 ++++++++++++++- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index d173374..18bfeeb 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -9,22 +9,9 @@ Class { 'generalReader', 'userCatalogue' ], - #classVars : [ - 'currentImporter' - ], #category : #'GitLabHealth-Model-Importer' } -{ #category : #'as yet unclassified' } -GLHModelImporter class >> importers [ - ^ currentImporter -] - -{ #category : #initialization } -GLHModelImporter class >> reset [ - currentImporter := nil. -] - { #category : #'private - api' } GLHModelImporter >> addCommits: commitsList toRepository: aProjectRepository [ "I take a list of GLHCommit. But some might have been parsed but are already on the model..." diff --git a/src/GitLabHealth-Visualization/RSCommit.class.st b/src/GitLabHealth-Visualization/RSCommit.class.st index f519c77..5637dac 100644 --- a/src/GitLabHealth-Visualization/RSCommit.class.st +++ b/src/GitLabHealth-Visualization/RSCommit.class.st @@ -5,7 +5,7 @@ Class { 'aCommit', 'canvas' ], - #category : 'GitLabHealth-Visualization' + #category : #'GitLabHealth-Visualization' } { #category : #'as yet unclassified' } @@ -402,7 +402,7 @@ RSCommit >> shapeForCommit: aGLHCommit withColor: color [ group := RSGroup new. impactedFiles := RSGroup new. labelTitle := RSLabel new - text: (aGLHCommit name truncateWithElipsisTo: 40); + text: (aGLHCommit message ifNil: [ (aGLHCommit id truncateWithElipsisTo: 7) printString ] ifNotNil: [ aGLHCommit message truncateWithElipsisTo: 40] ); yourself. labelCommiter := RSLabel new diff --git a/src/GitProjectHealth-Model-Importer/GPModelImporter.class.st b/src/GitProjectHealth-Model-Importer/GPModelImporter.class.st index c964f9e..8be76cf 100644 --- a/src/GitProjectHealth-Model-Importer/GPModelImporter.class.st +++ b/src/GitProjectHealth-Model-Importer/GPModelImporter.class.st @@ -12,9 +12,22 @@ Class { 'withFiles', 'glhModel' ], - #category : 'GitProjectHealth-Model-Importer' + #classVars : [ + 'currentImporter' + ], + #category : #'GitProjectHealth-Model-Importer' } +{ #category : #'accessing - global variables' } +GPModelImporter class >> importers [ + ^ currentImporter +] + +{ #category : #initialization } +GPModelImporter class >> reset [ + currentImporter := nil. +] + { #category : #accessing } GPModelImporter >> beWithFiles [ From afb64c6a21f23a372cfb0265edda2a1794f6af8d Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Thu, 26 Sep 2024 09:33:44 +0200 Subject: [PATCH 152/154] removing =sep to csv export --- src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 032b00e..126f7ef 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -255,9 +255,6 @@ GitMetricExporter >> exportProjectAnalysesInCSV [ file := self constructFilePath: groupOver. file writeStreamDo: [ :aStream | - aStream - << 'sep=,'; - << OSPlatform current lineEnding. exportBrowserModel writeCSVOn: aStream ] ] ] @@ -296,9 +293,6 @@ GitMetricExporter >> exportUserAnalysesInCSV [ file := self constructFilePath: groupOver. file writeStreamDo: [ :aStream | - aStream - << 'sep=,'; - << OSPlatform current lineEnding. exportBrowserModel writeCSVOn: aStream ] ] ] From 5c64954efaabe951f9a6ae45078aa79ce16eaf79 Mon Sep 17 00:00:00 2001 From: HLAD Nicolas Date: Thu, 26 Sep 2024 17:58:48 +0200 Subject: [PATCH 153/154] add Float return after averaging --- .../CommitsNumberByJiraTicketsMetric.class.st | 2 +- .../JiraTimeMRTimeDifferenceMetric.class.st | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/GitLabHealth-Model-Analysis/CommitsNumberByJiraTicketsMetric.class.st b/src/GitLabHealth-Model-Analysis/CommitsNumberByJiraTicketsMetric.class.st index 6ce6e12..9114c13 100644 --- a/src/GitLabHealth-Model-Analysis/CommitsNumberByJiraTicketsMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CommitsNumberByJiraTicketsMetric.class.st @@ -20,7 +20,7 @@ CommitsNumberByJiraTicketsMetric >> calculate [ | average | average := (group collect: [ :mergeRequest | mergeRequest commits size ]) average ]. - ^ groupedByDate average + ^ groupedByDate average asFloat ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st b/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st index 0b7f7cf..6a969f3 100644 --- a/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/JiraTimeMRTimeDifferenceMetric.class.st @@ -48,7 +48,7 @@ JiraTimeMRTimeDifferenceMetric >> calculate [ ]. - ^ groupedByDate average + ^ groupedByDate average asFloat ] { #category : #accessing } From 89c52cd2ab2e246fe6160b477690eec36f025eb0 Mon Sep 17 00:00:00 2001 From: Kilian B <60846047+knowbased@users.noreply.github.com> Date: Thu, 3 Oct 2024 16:08:34 +0200 Subject: [PATCH 154/154] feat: bitbucket importer (#74) * feat: add bitbucket package + base bitbucket api * chore: add bitbucket package in baseline * feat: get user method in bitBucket api * feat: importUser for bitbucket importer * feat: change bitbucket api for 1.0 + add projects method * feat(BitBucketApi): repositories of a project * feat(BitBucketApi): commits of repo in project since until date * feat(BitBucketImporter): importContributedProjectsOfUser method * refactor: improve repo/project transformation into GLHProject * test: add tests for bitbucket api and importer * feat: base completeImportProject * feat: import commits of project in bit bucket importer * feat(bitBucketImporter): import creator of commit method * refactor: move testImportUser method * refactor: rename importCommitsOfProject:since:until * fix: change imporContributedProject test to work on any date * feat(BitBucketApi): remove merge commit in commitsOfRepo:Inproject * feat(bitBucketImporter): add getContributionFromDiff * test: improve tests getContributionFromDiffs: * feat(bitBucketModelImporter): add withInitialCommits * feat(BitBucketApi): add usersByUserName * feat(BitBucketModelImporter): importUserByUsername * fix: problem with commitsInRepoOfProject * fix: small fix in bitbucket importer * fix: infinit loop with importContributedProjects * feat(BitBucketModelImporter): fix importCreatorOfCommit + add tests * test(BitBucketModelImporter): fix test importContributedProject * feat: add parentsId in bit bucket importer commit parsing * feat(BitBucketApi): pullrequestsOfRepo:InProject:Since:Until * feat(bitbucketModelImporter): importMergeRequests:since:until * fix(bitBucketImporter): improve precision in dates * feat(BitBucketModelImporter): add reviewers in parsing of pull requests * feat(BitBucketApi): activities of pull requests * feat(BitBucketModelImporter): import merge request merger * feat(BitBucketApi): commits of pull requests * feat(BitBucketModelImporter): importMergeRequestCommits * fix(BitBucketApi): error in commit created_at date * test: improve mock structure * refactor(BitBucketModelImporter): change classifications of methods * chore: add bitbucket test package in baseline * ci: add bitbucket packages in smalltalk.ston testing --- .smalltalk.ston | 4 +- .../BaselineOfGitLabHealth.class.st | 21 +- .../BitBucketApiMock.class.st | 1189 +++++++++++++++++ .../BitBucketModelImporterTest.class.st | 479 +++++++ .../package.st | 1 + .../BitBucketApi.class.st | 272 ++++ .../BitBucketModelImporter.class.st | 450 +++++++ src/BitBucketHealth-Model-Importer/package.st | 1 + .../GLPHImporterMock.class.st | 2 +- .../GitAnalyzerTest.class.st | 2 +- .../GitAnalyzer.class.st | 2 +- .../GitMetricExporter.class.st | 14 +- .../MergeRequestDurationMetric.class.st | 1 + .../UserMergeRequestMetric.class.st | 3 +- .../UserMetric.class.st | 5 +- .../GLHModelImporter.class.st | 78 +- 16 files changed, 2461 insertions(+), 63 deletions(-) create mode 100644 src/BitBucketHealth-Model-Importer-Tests/BitBucketApiMock.class.st create mode 100644 src/BitBucketHealth-Model-Importer-Tests/BitBucketModelImporterTest.class.st create mode 100644 src/BitBucketHealth-Model-Importer-Tests/package.st create mode 100644 src/BitBucketHealth-Model-Importer/BitBucketApi.class.st create mode 100644 src/BitBucketHealth-Model-Importer/BitBucketModelImporter.class.st create mode 100644 src/BitBucketHealth-Model-Importer/package.st diff --git a/.smalltalk.ston b/.smalltalk.ston index 7749e40..6423cb2 100644 --- a/.smalltalk.ston +++ b/.smalltalk.ston @@ -11,9 +11,9 @@ SmalltalkCISpec { } ], #testing: { - #packages : [ 'GitLab.*', 'GLPH.*', 'GitHub.*', 'GitProject.*' ], + #packages : [ 'GitLab.*', 'GLPH.*', 'GitHub.*', 'GitProject.*', 'BitBucket.*' ], #coverage : { - #packages : [ 'GitLab.*', 'GLPH.*', 'GitHub.*', 'GitProject.*' ], + #packages : [ 'GitLab.*', 'GLPH.*', 'GitHub.*', 'GitProject.*', 'BitBucket.*' ], #format : #lcov } } diff --git a/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st b/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st index ecbc2d4..f3cf6da 100644 --- a/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st +++ b/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st @@ -92,7 +92,8 @@ BaselineOfGitLabHealth >> defineGroups: spec [ 'GitLabHealth-Model-Analysis-Tests' 'GitLabHealth-Visualization' 'GitLabProjectHealth-ExtendModel-Generator' 'GitLabProjectHealth-Model-Importer' - 'GitLabProjectHealth-Model-Importer-Tests' ). + 'GitLabProjectHealth-Model-Importer-Tests' + 'BitBucketHealth-Model-Importer' 'BitBucketHealth-Model-Importer-Tests' ). spec group: 'default' with: #( 'Core' ) ] @@ -123,7 +124,6 @@ BaselineOfGitLabHealth >> definePackages: spec [ spec package: 'GitProjectHealth-Model-Importer'. - "gitlab" spec package: 'GitLabHealth-Model'; @@ -135,10 +135,12 @@ BaselineOfGitLabHealth >> definePackages: spec [ package: 'GitLabHealth-Model-Inspector' with: [ spec requires: #( 'GitLabHealth-Model-Visualization' ) ]; package: 'GitLabHealth-Model-Visualization'; - package: 'GitLabHealth-Model-Importer' - with: [ spec requires: #( 'NeoJSON' 'MoreLogger' 'GitProjectHealth-Model-Importer' ) ]; - package: 'GitHubHealth-Model-Importer' - with: [ spec requires: #( 'NeoJSON' 'MoreLogger' 'GitProjectHealth-Model-Importer' ) ]; + package: 'GitLabHealth-Model-Importer' with: [ + spec requires: + #( 'NeoJSON' 'MoreLogger' 'GitProjectHealth-Model-Importer' ) ]; + package: 'GitHubHealth-Model-Importer' with: [ + spec requires: + #( 'NeoJSON' 'MoreLogger' 'GitProjectHealth-Model-Importer' ) ]; package: 'GitLabHealth-Model-Importer-Tests' with: [ spec requires: #( 'GitLabHealth-Model-Importer' 'GitHubHealth-Model-Importer' ) ]. @@ -146,6 +148,10 @@ BaselineOfGitLabHealth >> definePackages: spec [ package: 'GitHubHealth-Model-Importer-Tests' with: [ spec requires: #( 'GitHubHealth-Model-Importer' ) ]. + "bitBucket" + spec package: 'BitBucketHealth-Model-Importer'; + package: 'BitBucketHealth-Model-Importer-Tests' with: [ spec requires: #( 'BitBucketHealth-Model-Importer' ) ]. + "model extension" spec package: 'GLPHExtended-Model' with: [ @@ -156,7 +162,8 @@ BaselineOfGitLabHealth >> definePackages: spec [ package: 'GLPHExtended-Model-Extension' with: [ spec requires: #( 'GLPHExtended-Model' 'GitLabHealth-Model' 'GitLabHealth-Model-Extension' ) ]; - package: 'GitLabHealth-Model-Analysis' with: [ spec requires: #( 'Voyage' 'AWS' ) ]; + package: 'GitLabHealth-Model-Analysis' + with: [ spec requires: #( 'Voyage' 'AWS' ) ]; package: 'GitLabHealth-Model-Analysis-Tests' with: [ spec requires: #( 'GitLabHealth-Model-Analysis' ) ]; package: 'GitLabHealth-Visualization'; diff --git a/src/BitBucketHealth-Model-Importer-Tests/BitBucketApiMock.class.st b/src/BitBucketHealth-Model-Importer-Tests/BitBucketApiMock.class.st new file mode 100644 index 0000000..687146b --- /dev/null +++ b/src/BitBucketHealth-Model-Importer-Tests/BitBucketApiMock.class.st @@ -0,0 +1,1189 @@ +Class { + #name : #BitBucketApiMock, + #superclass : #Object, + #instVars : [ + 'userMock', + 'commits', + 'diffs', + 'mergeRequests' + ], + #category : #'BitBucketHealth-Model-Importer-Tests' +} + +{ #category : #'api - pull-requests' } +BitBucketApiMock >> activitiesOfPullRequest: pullRequestId inRepo: repoSlug ofProject: projectKey [ + + ^self pullRequestActivities +] + +{ #category : #accessing } +BitBucketApiMock >> commits [ + + ^ commits +] + +{ #category : #accessing } +BitBucketApiMock >> commits1 [ + + | commits1 | + commits1 := '[ + { + "id": "abcdef0123abcdef4567abcdef8987abcdef6543", + "message": "message test", + "displayId": "abcdef0123a", + "author": { + "name": "charlie", + "emailAddress": "charlie@example.com" + }, + "authorTimestamp": 1727168151000, + "committer": { + "name": "charlie", + "emailAddress": "charlie@example.com" + }, + "committerTimestamp": 1727168151000, + "message": "WIP on feature 1", + "parents": [ + { + "id": "abcdef0123abcdef4567abcdef8987abcdef6543", + "displayId": "abcdef0" + } + ] + } + ]'. + + ^ commits1 := (NeoJSONReader on: commits1 readStream) next +] + +{ #category : #accessing } +BitBucketApiMock >> commits: anObject [ + + commits := anObject +] + +{ #category : #'api - pull-requests' } +BitBucketApiMock >> commitsOfPullRequest: mergeRequestId ofRepo: repoSlug inProject: projectKey [ + + ^commits +] + +{ #category : #'api - projects' } +BitBucketApiMock >> commitsOfRepo: repositorySlug inProject: projectKey since: since until: until [ + + ^ self commits select: [ :commit | + | commitDate | + commitDate := DateAndTime fromUnixTime: + (commit at: #committerTimestamp) / 1000. + commitDate >= since asDate and: commitDate <= until asDate ] +] + +{ #category : #accessing } +BitBucketApiMock >> declinedMergeRequest [ + + | pullRequest | + pullRequest := '{ + "id": 539, + "version": 10, + "title": "title", + "state": "DECLINED", + "open": false, + "closed": true, + "createdDate": 1721396425473, + "updatedDate": 1721457513310, + "closedDate": 1721457513310, + "fromRef": { + "id": "refs/heads/wip/1", + "displayId": "wip/1", + "latestCommit": "2", + "repository": { + "slug": "repoSlug", + "id": 242, + "name": "repo-name", + "scmId": "git", + "state": "AVAILABLE", + "statusMessage": "Available", + "forkable": true, + "project": { + "key": "project-key", + "id": 242, + "name": "project-name", + "description": "project description", + "public": true, + "type": "NORMAL", + "links": { + "self": [ + { + "href": "link" + } + ] + } + }, + "public": false, + "links": { + "clone": [ + { + "href": "clone", + "name": "ssh" + }, + { + "href": "clone", + "name": "http" + } + ], + "self": [ + { + "href": "link" + } + ] + } + } + }, + "toRef": { + "id": "refs/heads/develop/trunk", + "displayId": "develop/trunk", + "latestCommit": "3", + "repository": { + "slug": "repo-slug", + "id": 242, + "name": "repo-name", + "scmId": "git", + "state": "AVAILABLE", + "statusMessage": "Available", + "forkable": true, + "project": { + "key": "project-key", + "id": 242, + "name": "project-name", + "description": "description", + "public": true, + "type": "NORMAL", + "links": { + "self": [ + { + "href": "link" + } + ] + } + }, + "public": false, + "links": { + "clone": [ + { + "href": "link", + "name": "ssh" + }, + { + "href": "link-http", + "name": "http" + } + ], + "self": [ + { + "href": "link-self" + } + ] + } + } + }, + "locked": false, + "author": { + "user": { + "name": "user-name", + "id": 1, + "displayName": "user-display-name", + "active": false, + "slug": "user-slug", + "type": "NORMAL", + "links": { + "self": [ + { + "href": "link-self" + } + ] + } + }, + "role": "AUTHOR", + "approved": false, + "status": "UNAPPROVED" + }, + "reviewers": [ + { + "user": { + "name": "reviewer-name", + "emailAddress": "reviewer@email.com", + "id": 1713, + "displayName": "reviewer-display-name", + "active": true, + "slug": "reviewer-slug", + "type": "NORMAL", + "links": { + "self": [ + { + "href": "link-self" + } + ] + } + }, + "lastReviewedCommit": "2", + "role": "REVIEWER", + "approved": true, + "status": "APPROVED" + }, + { + "user": { + "name": "reveiwer2-name", + "emailAddress": "reviewer2@email.com", + "id": 49, + "displayName": "reviewer2 display name", + "active": true, + "slug": "reviewer2-slug", + "type": "NORMAL", + "links": { + "self": [ + { + "href": "link-self" + } + ] + } + }, + "role": "REVIEWER", + "approved": false, + "status": "UNAPPROVED" + } + ], + "participants": [], + "properties": { + "mergeResult": { + "outcome": "CONFLICTED", + "current": true + }, + "resolvedTaskCount": 0, + "commentCount": 4, + "openTaskCount": 0 + }, + "links": { + "self": [ + { + "href": "link" + } + ] + } + }'. + + ^ pullRequest := (NeoJSONReader on: pullRequest readStream) next +] + +{ #category : #accessing } +BitBucketApiMock >> diffs [ + + ^ diffs +] + +{ #category : #accessing } +BitBucketApiMock >> diffs1 [ + + | diffs1 | + diffs1 := '{ + "fromHash": null, + "toHash": "123", + "contextLines": 10, + "whitespace": "SHOW", + "diffs": [ + { + "source": { + "components": [ + "build.gradle" + ], + "parent": "", + "name": "build.gradle", + "extension": "gradle", + "toString": "build.gradle" + }, + "destination": { + "components": [ + "build.gradle" + ], + "parent": "", + "name": "build.gradle", + "extension": "gradle", + "toString": "build.gradle" + }, + "hunks": [ + { + "sourceLine": 1, + "sourceSpan": 14, + "destinationLine": 1, + "destinationSpan": 14, + "segments": [ + { + "type": "CONTEXT", + "lines": [ + { + "source": 3, + "destination": 3, + "line": " line", + "truncated": false + } + ], + "truncated": false + }, + { + "type": "REMOVED", + "lines": [ + { + "source": 4, + "destination": 4, + "line": "line4", + "truncated": false + } + ], + "truncated": false + }, + { + "type": "ADDED", + "lines": [ + { + "source": 5, + "destination": 4, + "line": "line5", + "truncated": false + } + ], + "truncated": false + }, + { + "type": "CONTEXT", + "lines": [ + { + "source": 14, + "destination": 14, + "line": "", + "truncated": false + } + ], + "truncated": false + } + ], + "truncated": false + } + ], + "truncated": false + } + ], + "truncated": false +}'. + + ^ diffs1 := (NeoJSONReader on: diffs1 readStream) next +] + +{ #category : #accessing } +BitBucketApiMock >> diffs: anObject [ + + diffs := anObject +] + +{ #category : #'api - commits' } +BitBucketApiMock >> diffsOfCommit: commitID inRepo: repositorySlug inProject: projectKey [ + ^diffs +] + +{ #category : #accessing } +BitBucketApiMock >> diffsWithoutAdded [ + + | diffsWithoutAdded | + diffsWithoutAdded := '{ + "fromHash": null, + "toHash": "3", + "contextLines": 10, + "whitespace": "SHOW", + "diffs": [ + { + "source": { + "components": [ + "build.gradle" + ], + "parent": "", + "name": "build.gradle", + "extension": "gradle", + "toString": "build.gradle" + }, + "destination": { + "components": [ + "build.gradle" + ], + "parent": "", + "name": "build.gradle", + "extension": "gradle", + "toString": "build.gradle" + }, + "hunks": [ + { + "sourceLine": 1, + "sourceSpan": 14, + "destinationLine": 1, + "destinationSpan": 14, + "segments": [ + { + "type": "CONTEXT", + "lines": [ + { + "source": 1, + "destination": 1, + "line": "line1", + "truncated": false + }, + { + "source": 2, + "destination": 2, + "line": "line2", + "truncated": false + }, + { + "source": 3, + "destination": 3, + "line": "line3", + "truncated": false + } + ], + "truncated": false + }, + { + "type": "REMOVED", + "lines": [ + { + "source": 4, + "destination": 4, + "line": "line4", + "truncated": false + } + ], + "truncated": false + }, + { + "type": "CONTEXT", + "lines": [ + { + "source": 5, + "destination": 5, + "line": "", + "truncated": false + } + ], + "truncated": false + } + ], + "truncated": false + } + ], + "truncated": false + } + ], + "truncated": false +}'. + + ^ diffsWithoutAdded := (NeoJSONReader on: + diffsWithoutAdded readStream) next +] + +{ #category : #accessing } +BitBucketApiMock >> diffsWithoutHunks [ + + | diffsWithoutHunks | + diffsWithoutHunks := '{ + "fromHash": null, + "toHash": "2", + "contextLines": 10, + "whitespace": "SHOW", + "diffs": [ + { + "source": { + "components": [ + "build.gradle" + ], + "parent": "", + "name": "build.gradle", + "extension": "gradle", + "toString": "build.gradle" + }, + "destination": { + "components": [ + "build.gradle" + ], + "parent": "", + "name": "build.gradle", + "extension": "gradle", + "toString": "build.gradle" + }, + + "truncated": false + } + ], + "truncated": false +}'. + + ^ diffsWithoutHunks := (NeoJSONReader on: + diffsWithoutHunks readStream) next +] + +{ #category : #accessing } +BitBucketApiMock >> diffsWithoutRemoved [ + + | diffsWithoutRemoved | + diffsWithoutRemoved := '{ + "fromHash": null, + "toHash": "1", + "contextLines": 10, + "whitespace": "SHOW", + "diffs": [ + { + "source": { + "components": [ + "build.gradle" + ], + "parent": "", + "name": "build.gradle", + "extension": "gradle", + "toString": "build.gradle" + }, + "destination": { + "components": [ + "build.gradle" + ], + "parent": "", + "name": "build.gradle", + "extension": "gradle", + "toString": "build.gradle" + }, + "hunks": [ + { + "sourceLine": 1, + "sourceSpan": 14, + "destinationLine": 1, + "destinationSpan": 14, + "segments": [ + { + "type": "CONTEXT", + "lines": [ + { + "source": 3, + "destination": 3, + "line": " line", + "truncated": false + } + ], + "truncated": false + }, + { + "type": "ADDED", + "lines": [ + { + "source": 5, + "destination": 4, + "line": " test2", + "truncated": false + } + ], + "truncated": false + }, + { + "type": "CONTEXT", + "lines": [ + { + "source": 6, + "destination": 6, + "line": "", + "truncated": false + } + ], + "truncated": false + } + ], + "truncated": false + } + ], + "truncated": false + } + ], + "truncated": false +}'. + + ^ diffsWithoutRemoved := (NeoJSONReader on: + diffsWithoutRemoved readStream) next +] + +{ #category : #initialization } +BitBucketApiMock >> initialize [ + + commits := self commits1. + diffs := self diffs1. + userMock := self user1. + mergeRequests := { self openedMergeRequest } +] + +{ #category : #accessing } +BitBucketApiMock >> mergeRequests [ + + ^ mergeRequests +] + +{ #category : #accessing } +BitBucketApiMock >> mergeRequests: anObject [ + + mergeRequests := anObject +] + +{ #category : #accessing } +BitBucketApiMock >> mergedMergeRequest [ + + | pullRequest | + pullRequest := '{ + "id": 539, + "version": 10, + "title": "title", + "state": "MERGED", + "open": false, + "closed": true, + "createdDate": 1721396425473, + "updatedDate": 1721457513310, + "closedDate": 1721457513310, + "fromRef": { + "id": "refs/heads/wip/1", + "displayId": "wip/1", + "latestCommit": "2", + "repository": { + "slug": "repoSlug", + "id": 242, + "name": "repo-name", + "scmId": "git", + "state": "AVAILABLE", + "statusMessage": "Available", + "forkable": true, + "project": { + "key": "project-key", + "id": 242, + "name": "project-name", + "description": "project description", + "public": true, + "type": "NORMAL", + "links": { + "self": [ + { + "href": "link" + } + ] + } + }, + "public": false, + "links": { + "clone": [ + { + "href": "clone", + "name": "ssh" + }, + { + "href": "clone", + "name": "http" + } + ], + "self": [ + { + "href": "link" + } + ] + } + } + }, + "toRef": { + "id": "refs/heads/develop/trunk", + "displayId": "develop/trunk", + "latestCommit": "3", + "repository": { + "slug": "repo-slug", + "id": 242, + "name": "repo-name", + "scmId": "git", + "state": "AVAILABLE", + "statusMessage": "Available", + "forkable": true, + "project": { + "key": "project-key", + "id": 242, + "name": "project-name", + "description": "description", + "public": true, + "type": "NORMAL", + "links": { + "self": [ + { + "href": "link" + } + ] + } + }, + "public": false, + "links": { + "clone": [ + { + "href": "link", + "name": "ssh" + }, + { + "href": "link-http", + "name": "http" + } + ], + "self": [ + { + "href": "link-self" + } + ] + } + } + }, + "locked": false, + "author": { + "user": { + "name": "user-name", + "id": 1, + "displayName": "user-display-name", + "active": false, + "slug": "user-slug", + "type": "NORMAL", + "links": { + "self": [ + { + "href": "link-self" + } + ] + } + }, + "role": "AUTHOR", + "approved": false, + "status": "UNAPPROVED" + }, + "reviewers": [ + { + "user": { + "name": "reviewer-name", + "emailAddress": "reviewer@email.com", + "id": 1713, + "displayName": "reviewer-display-name", + "active": true, + "slug": "reviewer-slug", + "type": "NORMAL", + "links": { + "self": [ + { + "href": "link-self" + } + ] + } + }, + "lastReviewedCommit": "2", + "role": "REVIEWER", + "approved": true, + "status": "APPROVED" + }, + { + "user": { + "name": "reveiwer2-name", + "emailAddress": "reviewer2@email.com", + "id": 49, + "displayName": "reviewer2 display name", + "active": true, + "slug": "reviewer2-slug", + "type": "NORMAL", + "links": { + "self": [ + { + "href": "link-self" + } + ] + } + }, + "role": "REVIEWER", + "approved": false, + "status": "UNAPPROVED" + } + ], + "participants": [], + "properties": { + "mergeResult": { + "outcome": "CONFLICTED", + "current": true + }, + "resolvedTaskCount": 0, + "commentCount": 4, + "openTaskCount": 0 + }, + "links": { + "self": [ + { + "href": "link" + } + ] + } + }'. + + ^ pullRequest := (NeoJSONReader on: pullRequest readStream) next +] + +{ #category : #accessing } +BitBucketApiMock >> openedMergeRequest [ + + | pullRequest | + pullRequest := '{ + "id": 539, + "version": 10, + "title": "title", + "state": "OPEN", + "open": true, + "closed": false, + "createdDate": 1709726344893, + "updatedDate": 1709728944248, + "fromRef": { + "id": "refs/heads/wip/1", + "displayId": "wip/1", + "latestCommit": "2", + "repository": { + "slug": "repoSlug", + "id": 242, + "name": "repo-name", + "scmId": "git", + "state": "AVAILABLE", + "statusMessage": "Available", + "forkable": true, + "project": { + "key": "project-key", + "id": 242, + "name": "project-name", + "description": "project description", + "public": true, + "type": "NORMAL", + "links": { + "self": [ + { + "href": "link" + } + ] + } + }, + "public": false, + "links": { + "clone": [ + { + "href": "clone", + "name": "ssh" + }, + { + "href": "clone", + "name": "http" + } + ], + "self": [ + { + "href": "link" + } + ] + } + } + }, + "toRef": { + "id": "refs/heads/develop/trunk", + "displayId": "develop/trunk", + "latestCommit": "3", + "repository": { + "slug": "repo-slug", + "id": 242, + "name": "repo-name", + "scmId": "git", + "state": "AVAILABLE", + "statusMessage": "Available", + "forkable": true, + "project": { + "key": "project-key", + "id": 242, + "name": "project-name", + "description": "description", + "public": true, + "type": "NORMAL", + "links": { + "self": [ + { + "href": "link" + } + ] + } + }, + "public": false, + "links": { + "clone": [ + { + "href": "link", + "name": "ssh" + }, + { + "href": "link-http", + "name": "http" + } + ], + "self": [ + { + "href": "link-self" + } + ] + } + } + }, + "locked": false, + "author": { + "user": { + "name": "user-name", + "id": 1, + "displayName": "user-display-name", + "active": false, + "slug": "user-slug", + "type": "NORMAL", + "links": { + "self": [ + { + "href": "link-self" + } + ] + } + }, + "role": "AUTHOR", + "approved": false, + "status": "UNAPPROVED" + }, + "reviewers": [ + { + "user": { + "name": "reviewer-name", + "emailAddress": "reviewer@email.com", + "id": 1713, + "displayName": "reviewer-display-name", + "active": true, + "slug": "reviewer-slug", + "type": "NORMAL", + "links": { + "self": [ + { + "href": "link-self" + } + ] + } + }, + "lastReviewedCommit": "2", + "role": "REVIEWER", + "approved": true, + "status": "APPROVED" + }, + { + "user": { + "name": "reveiwer2-name", + "emailAddress": "reviewer2@email.com", + "id": 49, + "displayName": "reviewer2 display name", + "active": true, + "slug": "reviewer2-slug", + "type": "NORMAL", + "links": { + "self": [ + { + "href": "link-self" + } + ] + } + }, + "role": "REVIEWER", + "approved": false, + "status": "UNAPPROVED" + } + ], + "participants": [], + "properties": { + "mergeResult": { + "outcome": "CONFLICTED", + "current": true + }, + "resolvedTaskCount": 0, + "commentCount": 4, + "openTaskCount": 0 + }, + "links": { + "self": [ + { + "href": "link" + } + ] + } + }'. + + ^pullRequest := (NeoJSONReader on: pullRequest readStream) next. +] + +{ #category : #accessing } +BitBucketApiMock >> projects [ + + | projects | + projects := '[ + { + "key": "PRJ", + "id": 1, + "name": "My Cool Project", + "description": "The description for my cool project.", + "public": true, + "type": "NORMAL", + "links": { + "self": [{"href": "http://link/to/project"}] + } + } + ], +'. + + projects := (NeoJSONReader on: projects readStream) next. + + ^ projects +] + +{ #category : #accessing } +BitBucketApiMock >> pullRequestActivities [ + + | pullRequestActivities | + pullRequestActivities := ' + [{ + "id": 1, + "createdDate": 1720510446734, + "user": { + "name": "user-name", + "emailAddress": "user-name@email.com", + "id": 24, + "displayName": "user name", + "active": true, + "slug": "un", + "type": "NORMAL", + "links": { + "self": [ + { + "href": "link" + } + ] + } + }, + "action": "MERGED" +}]'. + + ^ pullRequestActivities := (NeoJSONReader on: + pullRequestActivities readStream) next +] + +{ #category : #'api - pull-requests' } +BitBucketApiMock >> pullRequestsOfRepo: repoSlug inProject: projectKey since: since until: until [ + + ^ mergeRequests +] + +{ #category : #'api - projects' } +BitBucketApiMock >> repositoriesOfProject: projectKey [ + + | repos | + repos := '[ + { + "slug": "my-repo", + "id": 1, + "name": "My repo", + "scmId": "git", + "state": "AVAILABLE", + "statusMessage": "Available", + "forkable": true, + "project": { + "key": "PRJ", + "id": 1, + "name": "My Cool Project", + "description": "The description for my cool project.", + "public": true, + "type": "NORMAL", + "links": { + "self": [{"href": "http://link/to/project"}] + } + }, + "public": true, + "links": { + "clone": [ + {"href": "ssh://git@/PRJ/my-repo.git", "name": "ssh"}, + {"href": "https:///scm/PRJ/my-repo.git", "name": "http"} + ], + "self": [{"href": "http://link/to/repository"}] + } + } + ],'. + +repos := (NeoJSONReader on: repos readStream) next. + +^repos +] + +{ #category : #accessing } +BitBucketApiMock >> user1 [ + + | user1 | + user1 := ' + { + "name": "test", + "emailAddress": "test@test.com", + "id": 1, + "displayName": "test test", + "active": true, + "slug": "test", + "type": "NORMAL", + "directoryName": "directory", + "deletable": false, + "lastAuthenticationTimestamp": 1727444943000, + "mutableDetails": false, + "mutableGroups": true, + "links": { + "self": [ + { + "href": "test.com" + } + ] + } + } + '. + + + ^ user1 := (NeoJSONReader on: user1 readStream) next +] + +{ #category : #accessing } +BitBucketApiMock >> user: accountId [ + + | user | + user := '{ + "type": "user", + "nickname": "evzijst", + "display_name": "Erik van Zijst", + "created_on": "12-04-2024", + "uuid": "{d301aafa-d676-4ee0-88be-962be7417567}" + }'. + + ^ user +] + +{ #category : #accessing } +BitBucketApiMock >> userMock [ + + ^ userMock +] + +{ #category : #accessing } +BitBucketApiMock >> userMock: anObject [ + + userMock := anObject +] + +{ #category : #'api - user' } +BitBucketApiMock >> usersByUsername: username [ + + userMock ifNil: [ ^Array new ] ifNotNil: [ ^{ userMock }] +] diff --git a/src/BitBucketHealth-Model-Importer-Tests/BitBucketModelImporterTest.class.st b/src/BitBucketHealth-Model-Importer-Tests/BitBucketModelImporterTest.class.st new file mode 100644 index 0000000..14aef61 --- /dev/null +++ b/src/BitBucketHealth-Model-Importer-Tests/BitBucketModelImporterTest.class.st @@ -0,0 +1,479 @@ +" +A BitBucketModelImporterTest is a test class for testing the behavior of BitBucketModelImporter +" +Class { + #name : #BitBucketModelImporterTest, + #superclass : #TestCase, + #category : #'BitBucketHealth-Model-Importer-Tests' +} + +{ #category : #tests } +BitBucketModelImporterTest >> testCompleteImportProject [ + "Given" + + | glphModel project bitBucketApi bitBucketImporter | + bitBucketApi := BitBucketApiMock new. + glphModel := GLPHEModel new name: 'test'. + + project := GLHProject new. + + glphModel add: project. + + bitBucketImporter := BitBucketModelImporter new + bitBucketApi: bitBucketApi; + glhModel: glphModel. + + "When" + project := bitBucketImporter completeImportProject: project. + + "Then" + self deny: project repository equals: nil. + self + assert: (bitBucketImporter glhModel allWithType: GLHRepository) size + equals: 1 +] + +{ #category : #tests } +BitBucketModelImporterTest >> testGetContributionFromDiffs [ + "Given" + + | bitBucketApi glphModel bitBucketImporter diffs contribution | + bitBucketApi := BitBucketApiMock new. + + glphModel := GLPHEModel new name: 'test'. + + bitBucketImporter := BitBucketModelImporter new + bitBucketApi: bitBucketApi; + glhModel: glphModel. + + diffs := bitBucketApi diffs. + + "When" + contribution := bitBucketImporter getContributionFromDiffs: (diffs at: #diffs). + + "Then" + self assert: (contribution at: #additions) equals: 1. + self assert: (contribution at: #deletions) equals: 1 +] + +{ #category : #tests } +BitBucketModelImporterTest >> testGetContributionFromDiffsWithoutAdded [ + "Given" + + | bitBucketApi glphModel bitBucketImporter diffs contribution | + bitBucketApi := BitBucketApiMock new. + + glphModel := GLPHEModel new name: 'test'. + + bitBucketImporter := BitBucketModelImporter new + bitBucketApi: bitBucketApi; + glhModel: glphModel. + + diffs := bitBucketApi diffsWithoutAdded. + bitBucketApi diffs: diffs. + + "When" + contribution := bitBucketImporter getContributionFromDiffs: + (diffs at: #diffs). + + "Then" + self assert: (contribution at: #additions) equals: 0. + self assert: (contribution at: #deletions) equals: 1 +] + +{ #category : #tests } +BitBucketModelImporterTest >> testGetContributionFromDiffsWithoutHunks [ + "Given" + + | bitBucketApi glphModel bitBucketImporter diffs contribution | + bitBucketApi := BitBucketApiMock new. + + glphModel := GLPHEModel new name: 'test'. + + bitBucketImporter := BitBucketModelImporter new + bitBucketApi: bitBucketApi; + glhModel: glphModel. + + diffs := bitBucketApi diffsWithoutHunks. + bitBucketApi diffs: diffs. + + "When" + contribution := bitBucketImporter getContributionFromDiffs: + (diffs at: #diffs). + + "Then" + self assert: (contribution at: #additions) equals: 0. + self assert: (contribution at: #deletions) equals: 0 +] + +{ #category : #tests } +BitBucketModelImporterTest >> testGetContributionFromDiffsWithoutRemoved [ + "Given" + + | bitBucketApi glphModel bitBucketImporter diffs contribution | + bitBucketApi := BitBucketApiMock new. + + glphModel := GLPHEModel new name: 'test'. + + bitBucketImporter := BitBucketModelImporter new + bitBucketApi: bitBucketApi; + glhModel: glphModel. + + diffs := bitBucketApi diffsWithoutRemoved. + bitBucketApi diffs: diffs. + + "When" + contribution := bitBucketImporter getContributionFromDiffs: + (diffs at: #diffs). + + "Then" + self assert: (contribution at: #additions) equals: 1. + self assert: (contribution at: #deletions) equals: 0 +] + +{ #category : #tests } +BitBucketModelImporterTest >> testImportCommitsOfProjectSinceUntil [ + + | bitBucketApi glphModel bitBucketImporter project commits group repo | + "Given" + bitBucketApi := BitBucketApiMock new. + + glphModel := GLPHEModel new name: 'test'. + + bitBucketImporter := BitBucketModelImporter new + bitBucketApi: bitBucketApi; + glhModel: glphModel. + + group := GLHGroup new id: 1. + repo := GLHRepository new. + project := GLHProject new + group: group; + repository: repo. + + "When" + commits := bitBucketImporter + importCommitsOfProject: project + since: '09-23-2024' + until: '09-25-2024'. + + "Then" + self + assert: (bitBucketImporter glhModel allWithType: GLHCommit) size + equals: 1. + + self assert: project repository commits size equals: 1. +] + +{ #category : #tests } +BitBucketModelImporterTest >> testImportContributedProjectsOfUser [ + + | bitBucketApi glphModel bitBucketImporter user projects commits yesterdayAsTimestamp | + bitBucketApi := BitBucketApiMock new. + + glphModel := GLPHEModel new name: 'test'. + + bitBucketImporter := BitBucketModelImporter new + bitBucketApi: bitBucketApi; + glhModel: glphModel. + + user := GLHUser new + id: 1; + username: 'charlie'. + + commits := bitBucketApi commits1. + yesterdayAsTimestamp := (Date today - 1 days) asDateAndTime + asUnixTime * 1000. + commits first at: #committerTimestamp put: yesterdayAsTimestamp. + bitBucketApi commits: commits. + + "When" + projects := bitBucketImporter importContributedProjectsOfUser: user. + + "Then" + self assert: projects size equals: 1. + self + assert: (bitBucketImporter glhModel allWithType: GLHProject) size + equals: 1. + self + assert: (bitBucketImporter glhModel allWithType: GLHProject) first + equals: projects first. + self + assertCollection: user contributedProjects + hasSameElements: projects +] + +{ #category : #tests } +BitBucketModelImporterTest >> testImportCreatorOfCommit [ + + | bitBucketApi glphModel bitBucketImporter creator commit | + + "Given" + bitBucketApi := BitBucketApiMock new. + + glphModel := GLPHEModel new name: 'test'. + + bitBucketImporter := BitBucketModelImporter new + bitBucketApi: bitBucketApi; + glhModel: glphModel. + + commit := GLHCommit new author_name: 'test'. + + + "When" + creator := bitBucketImporter importCreatorOfCommit: commit. + + "Then" + self + assert: creator id + equals: + (bitBucketImporter parseUserIntoGLHUser: bitBucketApi userMock) id. + self assert: commit commitCreator equals: creator +] + +{ #category : #tests } +BitBucketModelImporterTest >> testImportCreatorOfCommitIfAlreadyExist [ + + | bitBucketApi glphModel bitBucketImporter creator commit | + "Given" + bitBucketApi := BitBucketApiMock new. + + glphModel := GLPHEModel new name: 'test'. + + bitBucketImporter := BitBucketModelImporter new + bitBucketApi: bitBucketApi; + glhModel: glphModel. + + glphModel add: (bitBucketImporter parseUserIntoGLHUser: bitBucketApi userMock). + + commit := GLHCommit new author_name: 'test'. + + + "When" + creator := bitBucketImporter importCreatorOfCommit: commit. + + "Then" + self + assert: creator id + equals: + (bitBucketImporter parseUserIntoGLHUser: bitBucketApi userMock) id. + self assert: commit commitCreator equals: creator +] + +{ #category : #tests } +BitBucketModelImporterTest >> testImportMergeRequestCommits [ + + | bitBucketApi glphModel bitBucketImporter mergeRequest commits | + "Given" + bitBucketApi := BitBucketApiMock new. + + glphModel := GLPHEModel new name: 'test'. + + bitBucketImporter := BitBucketModelImporter new + bitBucketApi: bitBucketApi; + glhModel: glphModel. + + mergeRequest := bitBucketImporter + parsePullRequestIntoGLPHEMergeRequest: + bitBucketApi mergedMergeRequest. + + + "When" + commits := bitBucketImporter importMergeRequestCommits: mergeRequest. + + "Then" + self deny: mergeRequest commits equals: nil. + self assert: mergeRequest commits equals: commits +] + +{ #category : #tests } +BitBucketModelImporterTest >> testImportMergeRequestsSinceUntil [ + + | bitBucketApi glphModel bitBucketImporter group repo project mergeRequests mergeRequest | + "Given" + bitBucketApi := BitBucketApiMock new. + + glphModel := GLPHEModel new name: 'test'. + + bitBucketImporter := BitBucketModelImporter new + bitBucketApi: bitBucketApi; + glhModel: glphModel. + + group := GLHGroup new id: 1. + repo := GLHRepository new. + project := GLHProject new + group: group; + repository: repo. + + "When" + mergeRequests := bitBucketImporter + importMergeRequests: project + since: '09-23-2024' + until: '09-25-2024'. + + "Then" + self + assert: + (bitBucketImporter glhModel allWithType: GLPHEMergeRequest) size + equals: 1. + + self assert: mergeRequests size equals: 1. + + mergeRequest := mergeRequests first. + self assert: mergeRequest state equals: 'opened'. + self assert: mergeRequest closed_at equals: nil. +] + +{ #category : #tests } +BitBucketModelImporterTest >> testImportMergeRequestsSinceUntilClosedMR [ + + | bitBucketApi glphModel bitBucketImporter group repo project mergeRequests mergeRequest | + "Given" + bitBucketApi := BitBucketApiMock new. + + glphModel := GLPHEModel new name: 'test'. + + bitBucketImporter := BitBucketModelImporter new + bitBucketApi: bitBucketApi; + glhModel: glphModel. + + bitBucketApi mergeRequests: { bitBucketApi mergedMergeRequest }. + + group := GLHGroup new id: 1. + repo := GLHRepository new. + project := GLHProject new + group: group; + repository: repo. + + "When" + mergeRequests := bitBucketImporter + importMergeRequests: project + since: '09-23-2024' + until: '09-25-2024'. + + "Then" + self + assert: + (bitBucketImporter glhModel allWithType: GLPHEMergeRequest) size + equals: 1. + + self assert: mergeRequests size equals: 1. + + mergeRequest := mergeRequests first. + self assert: mergeRequest state equals: 'merged'. + self assert: mergeRequest closed_at equals: nil. + self deny: mergeRequest merged_at equals: nil. +] + +{ #category : #tests } +BitBucketModelImporterTest >> testImportMergeRequestsSinceUntilDeclinedMR [ + + | bitBucketApi glphModel bitBucketImporter group repo project mergeRequests mergeRequest | + "Given" + bitBucketApi := BitBucketApiMock new. + + glphModel := GLPHEModel new name: 'test'. + + bitBucketImporter := BitBucketModelImporter new + bitBucketApi: bitBucketApi; + glhModel: glphModel. + + bitBucketApi mergeRequests: { bitBucketApi declinedMergeRequest }. + + group := GLHGroup new id: 1. + repo := GLHRepository new. + project := GLHProject new + group: group; + repository: repo. + + "When" + mergeRequests := bitBucketImporter + importMergeRequests: project + since: '09-23-2024' + until: '09-25-2024'. + + "Then" + self + assert: + (bitBucketImporter glhModel allWithType: GLPHEMergeRequest) size + equals: 1. + + self assert: mergeRequests size equals: 1. + + mergeRequest := mergeRequests first. + self assert: mergeRequest state equals: 'closed'. + self deny: mergeRequest closed_at equals: nil. + self assert: mergeRequest merged_at equals: nil +] + +{ #category : #tests } +BitBucketModelImporterTest >> testImportMergeResquestMerger [ + + | bitBucketApi glphModel bitBucketImporter mergeRequest mergeUser | + "Given" + bitBucketApi := BitBucketApiMock new. + + glphModel := GLPHEModel new name: 'test'. + + bitBucketImporter := BitBucketModelImporter new + bitBucketApi: bitBucketApi; + glhModel: glphModel. + + mergeRequest := bitBucketImporter + parsePullRequestIntoGLPHEMergeRequest: + bitBucketApi mergedMergeRequest. + + + "When" + mergeUser := bitBucketImporter importMergeResquestMerger: + mergeRequest. + + "Then" + self deny: mergeRequest merge_user equals: nil. + self assert: mergeRequest merge_user equals: mergeUser +] + +{ #category : #tests } +BitBucketModelImporterTest >> testImportUserByUsername [ + "Given" + + | bitBucketApi glphModel bitBucketImporter user | + bitBucketApi := BitBucketApiMock new. + + glphModel := GLPHEModel new name: 'test'. + + bitBucketImporter := BitBucketModelImporter new + bitBucketApi: bitBucketApi; + glhModel: glphModel. + + "When" + user := bitBucketImporter importUserByUsername: 'test'. + + "Then" + self assert: (glphModel allWithType: GLHUser) size equals: 1. + self + assertCollection: (glphModel allWithType: GLHUser) + hasSameElements: {user}. +] + +{ #category : #tests } +BitBucketModelImporterTest >> testImportUserByUsernameWithoutUsers [ + "Given" + + | bitBucketApi glphModel bitBucketImporter user | + bitBucketApi := BitBucketApiMock new. + + glphModel := GLPHEModel new name: 'test'. + + bitBucketImporter := BitBucketModelImporter new + bitBucketApi: bitBucketApi; + glhModel: glphModel. + + bitBucketApi userMock: nil. + + "When" + user := bitBucketImporter importUserByUsername: 'test'. + + "Then" + self assert: (glphModel allWithType: GLHUser) size equals: 0. + self assert: user equals: nil +] diff --git a/src/BitBucketHealth-Model-Importer-Tests/package.st b/src/BitBucketHealth-Model-Importer-Tests/package.st new file mode 100644 index 0000000..b1f504f --- /dev/null +++ b/src/BitBucketHealth-Model-Importer-Tests/package.st @@ -0,0 +1 @@ +Package { #name : #'BitBucketHealth-Model-Importer-Tests' } diff --git a/src/BitBucketHealth-Model-Importer/BitBucketApi.class.st b/src/BitBucketHealth-Model-Importer/BitBucketApi.class.st new file mode 100644 index 0000000..b6a9726 --- /dev/null +++ b/src/BitBucketHealth-Model-Importer/BitBucketApi.class.st @@ -0,0 +1,272 @@ +Class { + #name : #BitBucketApi, + #superclass : #Object, + #instVars : [ + 'endpoint', + 'basePath', + 'client', + 'bearerToken', + 'apiToken', + 'username' + ], + #category : #'BitBucketHealth-Model-Importer' +} + +{ #category : #'api - pull-requests' } +BitBucketApi >> activitiesOfPullRequest: pullRequestId inRepo: repositorySlug ofProject: projectKey [ + + ^ self allValuesOfPath: + self basePath , '/projects/' , projectKey , '/repos/' + , repositorySlug , '/pull-requests/' , pullRequestId printString + , '/activities' +] + +{ #category : #'private - building' } +BitBucketApi >> allValuesOfPath: path [ + + | results values | + self prepareZnClient. + self client path: path. + values := OrderedCollection new. + + [ + results := self client get. + results := (NeoJSONReader on: results readStream) next. + values addAll: (results at: #values). + results + at: #nextPageStart + ifPresent: [ + client queryAt: #start put: (results at: #nextPageStart) ]. + results at: #isLastPage ] whileFalse. + + ^ values +] + +{ #category : #accessing } +BitBucketApi >> apiToken [ + + ^ apiToken +] + +{ #category : #accessing } +BitBucketApi >> apiToken: anObject [ + + apiToken := anObject +] + +{ #category : #accessing } +BitBucketApi >> basePath [ + + ^ basePath +] + +{ #category : #accessing } +BitBucketApi >> basePath: anObject [ + + basePath := anObject +] + +{ #category : #accessing } +BitBucketApi >> bearerToken [ + + ^ bearerToken +] + +{ #category : #accessing } +BitBucketApi >> bearerToken: anObject [ + + bearerToken := anObject +] + +{ #category : #accessing } +BitBucketApi >> client [ + + ^ client +] + +{ #category : #accessing } +BitBucketApi >> client: anObject [ + + client := anObject +] + +{ #category : #'api - pull-requests' } +BitBucketApi >> commitsOfPullRequest: pullRequestId ofRepo: repoSlug inProject: projectKey [ + ^ self allValuesOfPath: self basePath, '/projects/', projectKey, '/repos/', repoSlug, '/pull-requests/', pullRequestId printString, '/commits'. + +] + +{ #category : #'api - commits' } +BitBucketApi >> commitsOfRepo: repositorySlug inProject: projectKey since: since until: until [ + "/rest/api/1.0/projects/{projectKey}/repos/{repositorySlug}/commits" + + | results lastDate lastCommitterTimestamp commits | + self prepareZnClient. + self client path: + self basePath , '/projects/' , projectKey , '/repos/' + , repositorySlug , '/commits'. + self client queryAt: 'merges' put: 'exclude'. + + commits := OrderedCollection new. + + [ + results := self client get. + results := (NeoJSONReader on: results readStream) next. + commits addAll: (results at: #values). + results + at: #nextPageStart + ifPresent: [ + client queryAt: #start put: (results at: #nextPageStart) ]. + + (results at: #isLastPage) + ifTrue: [ false ] + ifFalse: [ + lastCommitterTimestamp := commits last at: #authorTimestamp. + lastDate := DateAndTime fromUnixTime: lastCommitterTimestamp / 1000. + since asDate <= lastDate ] ] whileTrue. + + ^ commits select: [ :commit | + | commitDate | + commitDate := DateAndTime fromUnixTime: + (commit at: #authorTimestamp) / 1000. + commitDate >= since asDateAndTime and: + commitDate <= until asDateAndTime ] +] + +{ #category : #'api - commits' } +BitBucketApi >> diffsOfCommit: commitID inRepo: repositorySlug inProject: projectKey [ + + | results | + self prepareZnClient. + + self client path: + self basePath , '/projects/' , projectKey , '/repos/' + , repositorySlug , '/commits/' , commitID , '/diff'. + + results := self client get. + + ^ (NeoJSONReader on: results readStream) next +] + +{ #category : #accessing } +BitBucketApi >> endpoint [ + + ^ endpoint +] + +{ #category : #accessing } +BitBucketApi >> endpoint: anObject [ + + endpoint := anObject +] + +{ #category : #initialization } +BitBucketApi >> initialize [ + + self client: (ZnClient new + accept: ZnMimeType applicationJson; + yourself). + + self basePath: 'rest/api/1.0' +] + +{ #category : #'private - building' } +BitBucketApi >> prepareZnClient [ + + client := ZnClient new + accept: ZnMimeType applicationJson; + yourself. + + client host: self endpoint. + client http. + + self bearerToken ifNotNil: [ :token | + client headerAt: #Authorization put: 'Bearer ' , token ]. + self apiToken ifNotNil: [ :anApiKey | + client headerAt: #Authorization put: 'Basic ' + , (self username , ':' , self apiToken) utf8Encoded base64Encoded ]. +] + +{ #category : #'api - projects' } +BitBucketApi >> projects [ + "/rest/api/1.0/projects" + + ^ self allValuesOfPath: self basePath , '/projects'. +] + +{ #category : #'api - pull-requests' } +BitBucketApi >> pullRequestsOfRepo: repositorySlug inProject: projectKey since: since until: until [ + + | pullRequests results lastCommitterTimestamp lastDate | + self prepareZnClient. + self client path: + self basePath , '/projects/' , projectKey , '/repos/' + , repositorySlug , '/pull-requests'. + + self client queryAt: 'state' put: 'all'. + + pullRequests := OrderedCollection new. + + [ + results := self client get. + results := (NeoJSONReader on: results readStream) next. + pullRequests addAll: (results at: #values). + results + at: #nextPageStart + ifPresent: [ + client queryAt: #start put: (results at: #nextPageStart) ]. + + (results at: #isLastPage) + ifTrue: [ false ] + ifFalse: [ + lastCommitterTimestamp := pullRequests last at: #createdDate. + lastDate := DateAndTime fromUnixTime: lastCommitterTimestamp / 1000. + since asDate <= lastDate ] ] whileTrue. + + ^ pullRequests select: [ :commit | + | commitDate | + commitDate := DateAndTime fromUnixTime: + (commit at: #createdDate) / 1000. + commitDate >= since asDate and: commitDate <= until asDate ] +] + +{ #category : #'api - projects' } +BitBucketApi >> repositoriesOfProject: projectKey [ + ^self allValuesOfPath: self basePath, '/projects/', projectKey, '/repos'. +] + +{ #category : #'api - user' } +BitBucketApi >> user: accountId [ + "https://developer.atlassian.com/cloud/bitbucket/rest/api-group-users/#api-user-get" + + self prepareZnClient. + + self client path: self basePath, '/user/' , accountId printString. + ^ self client get +] + +{ #category : #accessing } +BitBucketApi >> username [ + + ^ username +] + +{ #category : #accessing } +BitBucketApi >> username: anObject [ + + username := anObject +] + +{ #category : #'api - user' } +BitBucketApi >> usersByUsername: usernameString [ + + | users | + self prepareZnClient. + self client path: self basePath , '/admin/users'. + self client queryAt: 'filter' put: usernameString. + + users := self client get. + users := (NeoJSONReader on: users readStream) next. + + ^ (users at: #values) +] diff --git a/src/BitBucketHealth-Model-Importer/BitBucketModelImporter.class.st b/src/BitBucketHealth-Model-Importer/BitBucketModelImporter.class.st new file mode 100644 index 0000000..60ef88e --- /dev/null +++ b/src/BitBucketHealth-Model-Importer/BitBucketModelImporter.class.st @@ -0,0 +1,450 @@ +Class { + #name : #BitBucketModelImporter, + #superclass : #GPModelImporter, + #instVars : [ + 'bitBucketApi', + 'withCommitDiffs', + 'withInitialCommits', + 'userCatalogue' + ], + #category : #'BitBucketHealth-Model-Importer' +} + +{ #category : #accessing } +BitBucketModelImporter >> bitBucketApi [ + + ^ bitBucketApi +] + +{ #category : #accessing } +BitBucketModelImporter >> bitBucketApi: anObject [ + + bitBucketApi := anObject +] + +{ #category : #equality } +BitBucketModelImporter >> blockOnIdEquality [ + + ^ [ :existing :new | existing id = new id ] +] + +{ #category : #'private - api' } +BitBucketModelImporter >> completeImportProject: aGLHProject [ + + aGLHProject repository: GLHRepository new. + self glhModel add: aGLHProject repository. + "TODO: import repository" + ^ aGLHProject +] + +{ #category : #'private - api' } +BitBucketModelImporter >> getContributionFromDiffs: diffs [ + + | contribution | + contribution := { + ('additions' -> 0). + ('deletions' -> 0) } asDictionary. + + diffs do: [ :diff | + | hunks segments | + hunks := diff at: #hunks ifAbsent: Array new. + + hunks do: [ :hunk | + | addedSegment removedSegment | + segments := hunk at: #segments. + + addedSegment := segments + detect: [ :segment | + (segment at: #type) = 'ADDED' ] + ifNone: [ nil ]. + removedSegment := segments + detect: [ :segment | + (segment at: #type) = 'REMOVED' ] + ifNone: [ nil ]. + + addedSegment ifNotNil: [ + contribution + at: #additions + put: + (contribution at: #additions) + (addedSegment at: #lines) size ]. + removedSegment ifNotNil: [ + contribution + at: #deletions + put: + (contribution at: #deletions) + (removedSegment at: #lines) size ] ] ]. + + ^ contribution +] + +{ #category : #'import - commits' } +BitBucketModelImporter >> importCommitsOfProject: aGLHProject since: since until: until [ + + | commits | + commits := bitBucketApi + commitsOfRepo: aGLHProject id + inProject: aGLHProject group id + since: since + until: until. + + commits := commits collect: [ :commit | + | glhCommit commitDiffs contribution | + glhCommit := self parseCommitIntoGLHCommit: commit. + commitDiffs := self bitBucketApi + diffsOfCommit: glhCommit id + inRepo: aGLHProject id + inProject: aGLHProject group id. + + contribution := self getContributionFromDiffs: + (commitDiffs at: #diffs). + glhCommit additions: (contribution at: #additions). + glhCommit deletions: (contribution at: #deletions). + glhCommit ]. + + aGLHProject repository commits: commits. + self glhModel addAll: commits unless: self blockOnIdEquality. + + ^ commits +] + +{ #category : #'import - projects' } +BitBucketModelImporter >> importContributedProjectsOfUser: aGLHUser [ + + | projects repositories repositoriesCommits userRepositories userProjects | + "get all projects" + projects := self bitBucketApi projects. + + "get all repos of projects" + repositories := projects flatCollect: [ :project | + self bitBucketApi repositoriesOfProject: + (project at: #key) ]. + + + "get all commits of repo" + repositoriesCommits := repositories collect: [ :repository | + repository -> (self bitBucketApi + commitsOfRepo: (repository at: #slug) + inProject: + ((repository at: #project) at: #key) + since: DateAndTime now - 10 days + until: DateAndTime now) ]. + + + "look if user is author of min one commit" + userRepositories := repositoriesCommits select: [ :repository | + | repos | + repos := repository value + ifEmpty: [ false ] + ifNotEmpty: [ + repository value + detect: [ :commit | + ((commit at: #author) at: #name) + = aGLHUser username ] + ifFound: [ true ] + ifNone: [ false ] ] ]. + + + "Transform user repositories in GLHProject" + userProjects := userRepositories collect: [ :repoCommits | + | repo project | + repo := repoCommits key. + project := repo at: #project. + + (self glhModel allWithType: GLHProject) + detect: [ :glhProject | + glhProject id = (project at: #key) ] + ifFound: [ :glhProject | glhProject ] + ifNone: [ + | glhProject | + glhProject := self parseRepoIntoGLHProject: repo. + glhModel add: glhProject. + glhProject ] ]. + + aGLHUser contributedProjects: userProjects. + + ^ userProjects +] + +{ #category : #'import - commits' } +BitBucketModelImporter >> importCreatorOfCommit: aGLHCommit [ + + | creator | + (self glhModel allWithType: GLHUser) + detect: [ :user | user username = aGLHCommit author_name ] + ifFound: [ :user | + aGLHCommit commitCreator: user. + ^ user ]. + + creator := self importUserByUsername: aGLHCommit author_name. + aGLHCommit commitCreator: creator. + ^ creator +] + +{ #category : #'import - merge-requests' } +BitBucketModelImporter >> importMergeRequestCommits: mergeRequest [ + + | commits | + commits := self bitBucketApi + commitsOfPullRequest: mergeRequest id + ofRepo: mergeRequest project id + inProject: mergeRequest project group id. + + commits := commits collect: [ :commit | + self parseCommitIntoGLHCommit: commit ]. + + mergeRequest commits: commits. + + ^ commits +] + +{ #category : #'import - merge-requests' } +BitBucketModelImporter >> importMergeRequests: aGLHProject since: fromDate until: toDate [ + + | pullRequests | + pullRequests := bitBucketApi + pullRequestsOfRepo: aGLHProject id + inProject: aGLHProject group id + since: fromDate + until: toDate. + + pullRequests := pullRequests collect: [ :pullRequest | + self parsePullRequestIntoGLPHEMergeRequest: + pullRequest ]. + + self glhModel addAll: pullRequests unless: self blockOnIdEquality. + + ^ pullRequests +] + +{ #category : #'import - merge-requests' } +BitBucketModelImporter >> importMergeResquestAuthor: mergeRequest [ + mergeRequest author ifNotNil: [ ^mergeRequest ] +] + +{ #category : #'import - merge-requests' } +BitBucketModelImporter >> importMergeResquestMerger: mergeRequest [ + + | activities mergeActivity mergeUser | + mergeRequest merge_user ifNotNil: [ ^ mergeRequest merge_user ]. + mergeRequest state = 'merged' ifFalse: [ ^ nil ]. + + activities := self bitBucketApi + activitiesOfPullRequest: mergeRequest id + inRepo: mergeRequest project id + ofProject: mergeRequest project group id. + + mergeActivity := activities detect: [ :activity | + (activity at: #action) = 'MERGED' ]. + + mergeUser := mergeActivity at: #user. + + mergeUser := (glhModel allWithType: GLHUser) + detect: [ :user | user id = (mergeUser at: #id) ] + ifFound: [ :user | user ] + ifNone: [ + | glhUser | + glhUser := self parseUserIntoGLHUser: mergeUser. + glhModel add: glhUser. + glhUser ]. + + mergeRequest merge_user: mergeUser. + ^ mergeUser +] + +{ #category : #'import - users' } +BitBucketModelImporter >> importUserByUsername: username [ + + | users user glhUser | + users := self bitBucketApi usersByUsername: username. + + users ifEmpty: [ ^nil ]. + + user := users first. + + glhUser := self parseUserIntoGLHUser: user. + + self glhModel add: glhUser unless: [ :nu :ou | nu id = ou id ]. + ^ glhUser +] + +{ #category : #parsing } +BitBucketModelImporter >> parseCommitIntoGLHCommit: commitDictionary [ + + | author committer parentIds | + author := commitDictionary at: #author. + committer := commitDictionary at: #committer. + + parentIds := (commitDictionary at: #parents) collect: [ :parent | + parent at: #id ]. + + ^ GLHCommit new + id: (commitDictionary at: #id); + message: (commitDictionary at: #message); + author_email: (author at: #emailAddress); + author_name: (author at: #name); + authored_date: (DateAndTime fromUnixTime: + (commitDictionary at: #authorTimestamp) / 1000); + created_at: (DateAndTime fromUnixTime: + (commitDictionary at: #authorTimestamp) / 1000); + committed_date: (DateAndTime fromUnixTime: + (commitDictionary at: #committerTimestamp) / 1000); + committer_email: (committer at: #emailAddress); + committer_name: (committer at: #name); + parent_ids: parentIds +] + +{ #category : #parsing } +BitBucketModelImporter >> parseProjectIntoGLHGroup: projectRepository [ + + ^GLHGroup new + name: (projectRepository at: #name); + id: (projectRepository at: #key); + description: (projectRepository at: #description). +] + +{ #category : #parsing } +BitBucketModelImporter >> parsePullRequestIntoGLPHEMergeRequest: pullRequestDictionary [ + + | repository project toRef fromRef glpheMergeRequest author state reviewers | + toRef := pullRequestDictionary at: #toRef. + fromRef := pullRequestDictionary at: #fromRef. + + reviewers := pullRequestDictionary at: #reviewers. + reviewers := reviewers collect: [ :reviewer | + |reviewerUser| + reviewerUser := reviewer at: #user. + (self glhModel allWithType: GLHUser) detect: [ :user | user id = (reviewerUser at: #id) ] ifFound: [ :user | user ] ifNone: [ + |glhUser| + glhUser := self parseUserIntoGLHUser: reviewerUser. + glhModel add: glhUser. + glhUser. + ] + + ]. + + repository := toRef at: #repository. + project := (self glhModel allWithType: GLHProject) + detect: [ :glhProject | + glhProject id = (repository at: #id) ] + ifFound: [ :glhProject | glhProject ] + ifNone: [ + project := self parseRepoIntoGLHProject: repository. + self glhModel add: project. + project ]. + + + author := pullRequestDictionary at: #author. + author := (self glhModel allWithType: GLHUser) + detect: [ :user | user id = ((author at: #user) at: #id) ] + ifFound: [ :user | user ] + ifNone: [ + self importUserByUsername: + ((author at: #user) at: #displayName) ]. + + + glpheMergeRequest := GLPHEMergeRequest new + name: (pullRequestDictionary at: #title); + title: (pullRequestDictionary at: #title); + id: (pullRequestDictionary at: #id); + project: project; + project_id: project id; + target_branch: (toRef at: #id); + target_project_id: + ((toRef at: #repository) at: #id); + source_branch: (fromRef at: #id); + target_project_id: + ((fromRef at: #repository) at: #id); + updated_at: (DateAndTime fromUnixTime: + (pullRequestDictionary at: #updatedDate) + / 1000); + created_at: (DateAndTime fromUnixTime: + (pullRequestDictionary at: #createdDate) + / 1000); + author: author. + + "STATE" + state := pullRequestDictionary at: #state. + state = 'OPEN' ifTrue: [ glpheMergeRequest state: 'opened' ]. + state = 'MERGED' ifTrue: [ + glpheMergeRequest state: 'merged'. + glpheMergeRequest merged_at: (DateAndTime fromUnixTime: + (pullRequestDictionary at: #closedDate) / 1000) ]. + + state = 'DECLINED' ifTrue: [ + glpheMergeRequest state: 'closed'. + glpheMergeRequest closed_at: (DateAndTime fromUnixTime: + (pullRequestDictionary at: #closedDate) / 1000) ]. + + ^ glpheMergeRequest +] + +{ #category : #parsing } +BitBucketModelImporter >> parseRepoIntoGLHProject: repositoryDictionary [ + + | project group glhProject | + project := repositoryDictionary at: #project. + + group := (self glhModel allWithType: GLHGroup) + detect: [ :glhGroup | glhGroup id = (project at: #key) ] + ifFound: [ :glhGroup | glhGroup ] + ifNone: [ + | newGroup | + newGroup := self parseProjectIntoGLHGroup: project. + glhModel add: newGroup. + newGroup ]. + + + glhProject := GLHProject new + name: (repositoryDictionary at: #name); + id: (repositoryDictionary at: #slug); + repository: GLHRepository new; + group: group. + + group addProject: glhProject. + + ^ glhProject +] + +{ #category : #parsing } +BitBucketModelImporter >> parseUserIntoGLHUser: userDictionnary [ + + ^ GLHUser new name: (userDictionnary at: #displayName); + public_email: (userDictionnary at: #emailAddress); + id: (userDictionnary at: #id); + username: (userDictionnary at: #name). +] + +{ #category : #accessing } +BitBucketModelImporter >> userCatalogue [ + + ^ userCatalogue +] + +{ #category : #accessing } +BitBucketModelImporter >> userCatalogue: anObject [ + + userCatalogue := anObject +] + +{ #category : #accessing } +BitBucketModelImporter >> withCommitDiffs [ + + ^ withCommitDiffs +] + +{ #category : #accessing } +BitBucketModelImporter >> withCommitDiffs: anObject [ + + withCommitDiffs := anObject +] + +{ #category : #accessing } +BitBucketModelImporter >> withInitialCommits [ + + ^ withInitialCommits +] + +{ #category : #accessing } +BitBucketModelImporter >> withInitialCommits: anObject [ + + withInitialCommits := anObject +] diff --git a/src/BitBucketHealth-Model-Importer/package.st b/src/BitBucketHealth-Model-Importer/package.st new file mode 100644 index 0000000..288298e --- /dev/null +++ b/src/BitBucketHealth-Model-Importer/package.st @@ -0,0 +1 @@ +Package { #name : #'BitBucketHealth-Model-Importer' } diff --git a/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st b/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st index 6aafd99..0a63a93 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st @@ -46,7 +46,7 @@ GLPHImporterMock >> glhModel: anObject [ ] { #category : #commit } -GLPHImporterMock >> importCommitsOProject: project since: since until: until [ +GLPHImporterMock >> importCommitsOfProject: project since: since until: until [ glhModel addAll: commits. ^ commits diff --git a/src/GitLabHealth-Model-Analysis-Tests/GitAnalyzerTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/GitAnalyzerTest.class.st index 9f12e0e..142d61b 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/GitAnalyzerTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/GitAnalyzerTest.class.st @@ -42,7 +42,7 @@ GitAnalyzerTest >> setUp [ glhImporter - importCommitsOProject: projects first + importCommitsOfProject: projects first since: since asDate until: nil. diff --git a/src/GitLabHealth-Model-Analysis/GitAnalyzer.class.st b/src/GitLabHealth-Model-Analysis/GitAnalyzer.class.st index fc0ded4..ffbbbff 100644 --- a/src/GitLabHealth-Model-Analysis/GitAnalyzer.class.st +++ b/src/GitLabHealth-Model-Analysis/GitAnalyzer.class.st @@ -100,7 +100,7 @@ GitAnalyzer >> analyseCommitFrequencySince: since until: until [ (#frequency -> nil) } asDictionary. commits := glhImporter - importCommitsOProject: onProject + importCommitsOfProject: onProject since: since until: until. diff --git a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st index 126f7ef..e0f79fc 100644 --- a/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st +++ b/src/GitLabHealth-Model-Analysis/GitMetricExporter.class.st @@ -517,15 +517,15 @@ GitMetricExporter >> setupAnalysisForUsersWithNames: userNames [ users := userNames collect: [ :username | glhImporter importUserByUsername: username ]. - glhImporter userCatalogue scrapeAuthorNamesForUsers: users. - + glhImporter userCatalogue ifNotNil: [ + glhImporter userCatalogue scrapeAuthorNamesForUsers: users ]. + users do: [ :user | - |projects | + | projects | projects := glhImporter importContributedProjectsOfUser: user. - projects do: [ :project | - glhImporter completeImportProject: project ]. - - ]. + + projects do: [ :project | + glhImporter completeImportProject: project ] ]. entities addAll: users. diff --git a/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st b/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st index d038eac..609b404 100644 --- a/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/MergeRequestDurationMetric.class.st @@ -9,6 +9,7 @@ MergeRequestDurationMetric >> calculate [ | groupedByDate gitAnalyzer mergeRequestsValidation filterGroups | userMergeRequests ifNil: [ self load ]. + groupedByDate := self setupGroupedDate. userMergeRequests ifEmpty: [ ^ nil ]. diff --git a/src/GitLabHealth-Model-Analysis/UserMergeRequestMetric.class.st b/src/GitLabHealth-Model-Analysis/UserMergeRequestMetric.class.st index d635858..83a07b9 100644 --- a/src/GitLabHealth-Model-Analysis/UserMergeRequestMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserMergeRequestMetric.class.st @@ -21,8 +21,7 @@ UserMergeRequestMetric >> load [ userMergeRequests := self loadUserMergeRequestsSince: (period at: #since) - until: (period at: #until) - + until: (period at: #until). ] { #category : #accessing } diff --git a/src/GitLabHealth-Model-Analysis/UserMetric.class.st b/src/GitLabHealth-Model-Analysis/UserMetric.class.st index ecd36c0..c420eec 100644 --- a/src/GitLabHealth-Model-Analysis/UserMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserMetric.class.st @@ -148,7 +148,7 @@ UserMetric >> loadUserCommitsSince: since until: until [ ifAbsentPut: [ | foundCommits | foundCommits := glhImporter - importCommitsOProject: project + importCommitsOfProject: project since: since until: until. foundCommits ] ]. @@ -158,8 +158,7 @@ UserMetric >> loadUserCommitsSince: since until: until [ glhImporter chainsCommitsFrom: allCommits. glhImporter withCommitDiffs: true. - ^allCommits reject: [ :commit | - commit commitCreator ~= user ] + ^ allCommits reject: [ :commit | commit commitCreator ~= user ] ] { #category : #loading } diff --git a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st index 18bfeeb..29adf0c 100644 --- a/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GLHModelImporter.class.st @@ -398,45 +398,6 @@ GLHModelImporter >> importCommitsFollowing: aCommit upToDays: aNumberOfDay [ until: (date + aNumberOfDay day) ] -{ #category : #commit } -GLHModelImporter >> importCommitsOProject: aProject since: fromDate until: toDate [ - - | newlyFoundCommit page foundCommit | - page := 0. - foundCommit := OrderedCollection new. - newlyFoundCommit := { true }. - [ newlyFoundCommit isNotEmpty ] whileTrue: [ - | results | - page := page + 1. - ('import commit page ' , page printString) recordInfo. - results := self glhApi - commitsOfProject: aProject id - forRefName: nil - since: - (fromDate ifNotNil: [ fromDate asDateAndTime asString ]) - until: - (toDate ifNotNil: [ toDate asDateAndTime asString ]) - path: nil - author: nil - all: true - with_stats: true - firstParent: nil - order: nil - trailers: nil - perPage: 100 - page: page. - - newlyFoundCommit := self parseCommitsResult: results. - "newlyFoundCommit do: [ :c | c repository: aProject repository ]." - - foundCommit addAll: (aProject repository commits - addAll: newlyFoundCommit - unless: self blockOnIdEquality). ]. - - - ^ self glhModel addAll: foundCommit unless: self blockOnIdEquality -] - { #category : #commit } GLHModelImporter >> importCommitsOf: aGLHProject withStats: aBoolean until: toDate [ @@ -547,6 +508,45 @@ GLHModelImporter >> importCommitsOfBranch: aGLHBranch forRefName: refName until: until: toDate ] +{ #category : #commit } +GLHModelImporter >> importCommitsOfProject: aProject since: fromDate until: toDate [ + + | newlyFoundCommit page foundCommit | + page := 0. + foundCommit := OrderedCollection new. + newlyFoundCommit := { true }. + [ newlyFoundCommit isNotEmpty ] whileTrue: [ + | results | + page := page + 1. + ('import commit page ' , page printString) recordInfo. + results := self glhApi + commitsOfProject: aProject id + forRefName: nil + since: + (fromDate ifNotNil: [ fromDate asDateAndTime asString ]) + until: + (toDate ifNotNil: [ toDate asDateAndTime asString ]) + path: nil + author: nil + all: true + with_stats: true + firstParent: nil + order: nil + trailers: nil + perPage: 100 + page: page. + + newlyFoundCommit := self parseCommitsResult: results. + "newlyFoundCommit do: [ :c | c repository: aProject repository ]." + + foundCommit addAll: (aProject repository commits + addAll: newlyFoundCommit + unless: self blockOnIdEquality). ]. + + + ^ self glhModel addAll: foundCommit unless: self blockOnIdEquality +] + { #category : #'as yet unclassified' } GLHModelImporter >> importContributedProjectsOfUser: aGLHUser [