Recipes
Each recipe is self-contained: copy it in a Playground, replace the values between <…>, and run it.
Recipes that only need the history use the local importer (fast, no token); recipes about merge requests or pipelines need a platform importer.
Who commits the most? Local
Section titled “Who commits the most? ”model := GLHModel new name: 'top-committers'.repository := GLHRepository new.repository cacheAt: #localImporterReference put: '<PATH-TO-CLONE>' asFileReference.project := GLHProject new name: 'my-project'; repository: repository; yourself.model add: project; add: repository.
(GitLocalModelImporter new glhModel: model; withCommitsSince: 1 year; withCommitDiffs: false; "not needed here, much faster" yourself) importRepository: repository.
"Number of commits per author, highest first"((model allWithType: GLHCommit) collect: [ :commit | commit commitCreator ifNotNil: #name ifNil: [ commit author_name ] ]) asBag sortedCountsWhich files change the most? Local
Section titled “Which files change the most? ”model := GLHModel new name: 'hotspots'.repository := GLHRepository new.repository cacheAt: #localImporterReference put: '<PATH-TO-CLONE>' asFileReference.project := GLHProject new name: 'my-project'; repository: repository; yourself.model add: project; add: repository.
(GitLocalModelImporter new glhModel: model; withCommitsSince: 1 year; withCommitDiffs: true; yourself) importRepository: repository.
"The 20 paths modified by the largest number of commits"((model allWithType: GLHDiff) collect: #new_path) asBag sortedCounts first: 20Commits per week Local
Section titled “Commits per week ”Reuse the model of one of the recipes above:
((model allWithType: GLHCommit) groupedBy: [ :commit | commit committed_date asDate asWeek ]) associations collect: [ :weekToCommits | weekToCommits key printString -> weekToCommits value size ]Which projects have a failing pipeline? GitLab
Section titled “Which projects have a failing pipeline? ”model := GLHModel new name: 'pipelines'.importer := GitModelImporter forGitlabHostOn: '<GITLAB-URL>/api/v4' withToken: '<TOKEN>' andModel: model.importer withCommitsSince: 1 day. "we only need the projects and their latest pipelines"
group := importer importGroup: <GROUP-ID>.
(group containedEntitiesOfType: GLHProject) select: [ :project | project lastPipeline isNotNil and: [ project lastPipeline status ~= 'success' ] ]The same information is shown graphically by the Group Quality view.
Pull request states of a GitHub organization GitHub
Section titled “Pull request states of a GitHub organization ”This example takes a few minutes on a large organization such as eclipse.
model := GLHModel new name: 'pull-requests'.importer := GitModelImporter forGithubWithToken: '<TOKEN>' andModel: model.importer withCommitsSince: 10 days.
organization := importer importGroup: 'eclipse'.
"Import the latest pull requests of each repository"(organization containedEntitiesOfType: GLHProject) do: [ :project | importer importMergeRequestsOfProject: project ].
"Count them by state (open / closed)"((organization containedEntitiesOfType: GLHMergeRequest) collect: #state) asBagAverage time to merge GitLab
Section titled “Average time to merge ”model := GLHModel new name: 'time-to-merge'.importer := GitModelImporter forGitlabHostOn: '<GITLAB-URL>/api/v4' withToken: '<TOKEN>' andModel: model.
project := importer importProject: <PROJECT-ID>.mergeRequests := importer importMergeRequestsOfProject: project since: (Date today - 90 days) asDateAndTime until: DateAndTime now.
merged := mergeRequests select: [ :mr | mr merged_at isNotNil ].durations := merged collect: [ :mr | (mr merged_at asDateAndTime - mr created_at asDateAndTime) asHours ].durations ifNotEmpty: [ (durations sum / durations size) printShowingDecimalPlaces: 1 ] "hours"Merge requests merged without approval GitLab
Section titled “Merge requests merged without approval ”model := GLHModel new name: 'approvals'.importer := GitModelImporter forGitlabHostOn: '<GITLAB-URL>/api/v4' withToken: '<TOKEN>' andModel: model.
project := importer importProject: <PROJECT-ID>.mergeRequests := importer importMergeRequestsOfProject: project since: (Date today - 30 days) asDateAndTime until: DateAndTime now.
"One API call per merge request"mergeRequests do: [ :mr | importer importMergeResquestApprovals: mr ].
mergeRequests select: [ :mr | mr merged_at isNotNil and: [ mr approved_by isEmpty ] ]