diff --git a/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st b/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st index ff8f5af6..5f353c40 100644 --- a/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st +++ b/src/BaselineOfGitLabHealth/BaselineOfGitLabHealth.class.st @@ -99,8 +99,8 @@ BaselineOfGitLabHealth >> defineGroups: spec [ 'GitLabHealth-Model-Importer' 'GitLabHealth-Model-Importer-Tests' 'GitHubHealth-Model-Importer-Tests' 'GitLabHealth-Model-Analysis' 'GitLabHealth-Model-Analysis-Tests' - 'GitLabHealth-Visualization' - 'GitLabProjectHealth-Model-Importer' + 'GitLabHealth-Visualization' 'GitLabProjectHealth-Model-Importer' + 'GitProjectHealth-Model-Importer-Tests' 'BitBucketHealth-Model-Importer' 'BitBucketHealth-Model-Importer-Tests' ). spec group: 'default' with: #( 'Core' ) diff --git a/src/BitBucketHealth-Model-Importer-Tests/BitBucketModelImporterTest.class.st b/src/BitBucketHealth-Model-Importer-Tests/BitBucketModelImporterTest.class.st index 644714be..7c206c44 100644 --- a/src/BitBucketHealth-Model-Importer-Tests/BitBucketModelImporterTest.class.st +++ b/src/BitBucketHealth-Model-Importer-Tests/BitBucketModelImporterTest.class.st @@ -672,7 +672,7 @@ BitBucketModelImporterTest >> testImportMergeRequestsSinceUntil [ "When" mergeRequests := bitBucketImporter - importMergeRequests: project + importMergeRequestsOfProject: project since: '09-23-2024' until: '09-25-2024'. @@ -712,7 +712,7 @@ BitBucketModelImporterTest >> testImportMergeRequestsSinceUntilAttachedToGoodPro "When" mergeRequests := bitBucketImporter - importMergeRequests: project + importMergeRequestsOfProject: project since: '09-23-2024' until: '09-25-2024'. @@ -749,7 +749,7 @@ BitBucketModelImporterTest >> testImportMergeRequestsSinceUntilClosedMR [ "When" mergeRequests := bitBucketImporter - importMergeRequests: project + importMergeRequestsOfProject: project since: '09-23-2024' until: '09-25-2024'. @@ -790,7 +790,7 @@ BitBucketModelImporterTest >> testImportMergeRequestsSinceUntilDeclinedMR [ "When" mergeRequests := bitBucketImporter - importMergeRequests: project + importMergeRequestsOfProject: project since: '09-23-2024' until: '09-25-2024'. diff --git a/src/BitBucketHealth-Model-Importer/BitBucketModelImporter.class.st b/src/BitBucketHealth-Model-Importer/BitBucketModelImporter.class.st index 63566300..212f06ef 100644 --- a/src/BitBucketHealth-Model-Importer/BitBucketModelImporter.class.st +++ b/src/BitBucketHealth-Model-Importer/BitBucketModelImporter.class.st @@ -31,7 +31,7 @@ BitBucketModelImporter >> bitBucketApi: anObject [ repoApi := anObject ] -{ #category : #commit } +{ #category : #'import - commits' } BitBucketModelImporter >> completeImportedCommit: aCommit [ ('completing commit: ' , aCommit short_id printString) recordInfo. @@ -118,7 +118,7 @@ BitBucketModelImporter >> convertBitBucketDiffToGitDiff: response [ ^ result ] -{ #category : #'as yet unclassified' } +{ #category : #'import - notes' } BitBucketModelImporter >> extractNoteFromComment: aDictionary [ ^ GLHNote new @@ -186,9 +186,35 @@ BitBucketModelImporter >> importAndLoadLatestsCommitsOfProject: aGLHProject [ ^ commits ] -{ #category : #'import - repositories' } +{ #category : #'import - branches' } BitBucketModelImporter >> importBranchesOf: aGLHProject [ + | branches glhBranches | + self + deprecated: 'Use importBranchesOfProject: instead of current one' + on: '26 September 2025' + in: + 'Pharo-12.0.0+SNAPSHOT.build.1571.sha.cf5fcd22e66957962c97dffc58b0393b7f368147 (64 Bit)'. + branches := self repoApi branches + allWithParams: { } asDictionary + inRepository: aGLHProject id + ofProject: aGLHProject group id. + glhBranches := branches collect: [ :branch | + self + parseBranchIntoGLHBranch: branch + ofProject: aGLHProject ]. + + glhBranches do: [ :glhBranch | + aGLHProject repository addBranch: glhBranch ]. + + self glhModel addAll: glhBranches unless: self blockForBranchEquality. + + ^ glhBranches +] + +{ #category : #'import - branches' } +BitBucketModelImporter >> importBranchesOfProject: aGLHProject [ + | branches glhBranches | branches := self repoApi branches allWithParams: { } asDictionary @@ -377,7 +403,7 @@ BitBucketModelImporter >> importMergeRequestCommits: mergeRequest [ ^ commits ] -{ #category : #'import - merge request' } +{ #category : #'import - merge-requests' } BitBucketModelImporter >> importMergeRequestMergeCommits: aGLHMergeRequest [ aGLHMergeRequest mergedCommit ifNotNil: [ @@ -406,7 +432,7 @@ BitBucketModelImporter >> importMergeRequestMergeCommits: aGLHMergeRequest [ ^ { found } ] ] -{ #category : #'import - merge request' } +{ #category : #'import - merge-requests' } BitBucketModelImporter >> importMergeRequestStats: aMergeRequest [ | commitDiffs contribution | @@ -432,7 +458,7 @@ BitBucketModelImporter >> importMergeRequestStats: aMergeRequest [ ] { #category : #'import - merge-requests' } -BitBucketModelImporter >> importMergeRequests: aGLHProject since: fromDate until: toDate [ +BitBucketModelImporter >> importMergeRequestsOfProject: aGLHProject since: fromDate until: toDate [ | pullRequests params | params := { @@ -484,7 +510,7 @@ BitBucketModelImporter >> importMergeResquestMerger: mergeRequest [ ] { #category : #'import - notes' } -BitBucketModelImporter >> importNotesfromMergeRequest: mergeRequest [ +BitBucketModelImporter >> importNotesOfMergeRequest: mergeRequest [ | results notes | results := self repoApi pullRequests diff --git a/src/GitHubHealth-Model-Importer-Tests/GithubActionsMock.class.st b/src/GitHubHealth-Model-Importer-Tests/GithubActionsMock.class.st new file mode 100644 index 00000000..97fe9265 --- /dev/null +++ b/src/GitHubHealth-Model-Importer-Tests/GithubActionsMock.class.st @@ -0,0 +1,722 @@ +Class { + #name : #GithubActionsMock, + #superclass : #Object, + #category : #'GitHubHealth-Model-Importer-Tests' +} + +{ #category : #get } +GithubActionsMock >> getAllRunsForRepo: aGLHProject ofOwner: aString withParms: aCollection [ + ^ '{ + "total_count": 1, + "workflow_runs": [ + { + "id": 30433642, + "name": "Build", + "node_id": "MDEyOldvcmtmbG93IFJ1bjI2OTI4OQ==", + "check_suite_id": 42, + "check_suite_node_id": "MDEwOkNoZWNrU3VpdGU0Mg==", + "head_branch": "master", + "head_sha": "acb5820ced9479c074f688cc328bf03f341a511d", + "path": ".github/workflows/build.yml@main", + "run_number": 562, + "event": "push", + "display_title": "Update README.md", + "status": "queued", + "conclusion": null, + "workflow_id": 159038, + "url": "https://api.github.com/repos/octo-org/octo-repo/actions/runs/30433642", + "html_url": "https://github.com/octo-org/octo-repo/actions/runs/30433642", + "pull_requests": [], + "created_at": "2020-01-22T19:33:08Z", + "updated_at": "2020-01-22T19:33:08Z", + "actor": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "run_attempt": 1, + "run_started_at": "2020-01-22T19:33:08Z", + "triggering_actor": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "jobs_url": "https://api.github.com/repos/octo-org/octo-repo/actions/runs/30433642/jobs", + "logs_url": "https://api.github.com/repos/octo-org/octo-repo/actions/runs/30433642/logs", + "check_suite_url": "https://api.github.com/repos/octo-org/octo-repo/check-suites/414944374", + "artifacts_url": "https://api.github.com/repos/octo-org/octo-repo/actions/runs/30433642/artifacts", + "cancel_url": "https://api.github.com/repos/octo-org/octo-repo/actions/runs/30433642/cancel", + "rerun_url": "https://api.github.com/repos/octo-org/octo-repo/actions/runs/30433642/rerun", + "workflow_url": "https://api.github.com/repos/octo-org/octo-repo/actions/workflows/159038", + "head_commit": { + "id": "acb5820ced9479c074f688cc328bf03f341a511d", + "tree_id": "d23f6eedb1e1b9610bbc754ddb5197bfe7271223", + "message": "Create linter.yaml", + "timestamp": "2020-01-22T19:33:05Z", + "author": { + "name": "Octo Cat", + "email": "octocat@github.com" + }, + "committer": { + "name": "GitHub", + "email": "noreply@github.com" + } + }, + "repository": { + "id": 1296269, + "node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5", + "name": "Hello-World", + "full_name": "octocat/Hello-World", + "owner": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/octocat/Hello-World", + "description": "This your first repo!", + "fork": false, + "url": "https://api.github.com/repos/octocat/Hello-World", + "archive_url": "https://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}", + "assignees_url": "https://api.github.com/repos/octocat/Hello-World/assignees{/user}", + "blobs_url": "https://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}", + "branches_url": "https://api.github.com/repos/octocat/Hello-World/branches{/branch}", + "collaborators_url": "https://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}", + "comments_url": "https://api.github.com/repos/octocat/Hello-World/comments{/number}", + "commits_url": "https://api.github.com/repos/octocat/Hello-World/commits{/sha}", + "compare_url": "https://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}", + "contents_url": "https://api.github.com/repos/octocat/Hello-World/contents/{+path}", + "contributors_url": "https://api.github.com/repos/octocat/Hello-World/contributors", + "deployments_url": "https://api.github.com/repos/octocat/Hello-World/deployments", + "downloads_url": "https://api.github.com/repos/octocat/Hello-World/downloads", + "events_url": "https://api.github.com/repos/octocat/Hello-World/events", + "forks_url": "https://api.github.com/repos/octocat/Hello-World/forks", + "git_commits_url": "https://api.github.com/repos/octocat/Hello-World/git/commits{/sha}", + "git_refs_url": "https://api.github.com/repos/octocat/Hello-World/git/refs{/sha}", + "git_tags_url": "https://api.github.com/repos/octocat/Hello-World/git/tags{/sha}", + "git_url": "git:github.com/octocat/Hello-World.git", + "issue_comment_url": "https://api.github.com/repos/octocat/Hello-World/issues/comments{/number}", + "issue_events_url": "https://api.github.com/repos/octocat/Hello-World/issues/events{/number}", + "issues_url": "https://api.github.com/repos/octocat/Hello-World/issues{/number}", + "keys_url": "https://api.github.com/repos/octocat/Hello-World/keys{/key_id}", + "labels_url": "https://api.github.com/repos/octocat/Hello-World/labels{/name}", + "languages_url": "https://api.github.com/repos/octocat/Hello-World/languages", + "merges_url": "https://api.github.com/repos/octocat/Hello-World/merges", + "milestones_url": "https://api.github.com/repos/octocat/Hello-World/milestones{/number}", + "notifications_url": "https://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}", + "pulls_url": "https://api.github.com/repos/octocat/Hello-World/pulls{/number}", + "releases_url": "https://api.github.com/repos/octocat/Hello-World/releases{/id}", + "ssh_url": "git@github.com:octocat/Hello-World.git", + "stargazers_url": "https://api.github.com/repos/octocat/Hello-World/stargazers", + "statuses_url": "https://api.github.com/repos/octocat/Hello-World/statuses/{sha}", + "subscribers_url": "https://api.github.com/repos/octocat/Hello-World/subscribers", + "subscription_url": "https://api.github.com/repos/octocat/Hello-World/subscription", + "tags_url": "https://api.github.com/repos/octocat/Hello-World/tags", + "teams_url": "https://api.github.com/repos/octocat/Hello-World/teams", + "trees_url": "https://api.github.com/repos/octocat/Hello-World/git/trees{/sha}", + "hooks_url": "http://api.github.com/repos/octocat/Hello-World/hooks" + }, + "head_repository": { + "id": 217723378, + "node_id": "MDEwOlJlcG9zaXRvcnkyMTc3MjMzNzg=", + "name": "octo-repo", + "full_name": "octo-org/octo-repo", + "private": true, + "owner": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/octo-org/octo-repo", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/octo-org/octo-repo", + "forks_url": "https://api.github.com/repos/octo-org/octo-repo/forks", + "keys_url": "https://api.github.com/repos/octo-org/octo-repo/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/octo-org/octo-repo/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/octo-org/octo-repo/teams", + "hooks_url": "https://api.github.com/repos/octo-org/octo-repo/hooks", + "issue_events_url": "https://api.github.com/repos/octo-org/octo-repo/issues/events{/number}", + "events_url": "https://api.github.com/repos/octo-org/octo-repo/events", + "assignees_url": "https://api.github.com/repos/octo-org/octo-repo/assignees{/user}", + "branches_url": "https://api.github.com/repos/octo-org/octo-repo/branches{/branch}", + "tags_url": "https://api.github.com/repos/octo-org/octo-repo/tags", + "blobs_url": "https://api.github.com/repos/octo-org/octo-repo/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/octo-org/octo-repo/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/octo-org/octo-repo/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/octo-org/octo-repo/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/octo-org/octo-repo/statuses/{sha}", + "languages_url": "https://api.github.com/repos/octo-org/octo-repo/languages", + "stargazers_url": "https://api.github.com/repos/octo-org/octo-repo/stargazers", + "contributors_url": "https://api.github.com/repos/octo-org/octo-repo/contributors", + "subscribers_url": "https://api.github.com/repos/octo-org/octo-repo/subscribers", + "subscription_url": "https://api.github.com/repos/octo-org/octo-repo/subscription", + "commits_url": "https://api.github.com/repos/octo-org/octo-repo/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/octo-org/octo-repo/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/octo-org/octo-repo/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/octo-org/octo-repo/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/octo-org/octo-repo/contents/{+path}", + "compare_url": "https://api.github.com/repos/octo-org/octo-repo/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/octo-org/octo-repo/merges", + "archive_url": "https://api.github.com/repos/octo-org/octo-repo/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/octo-org/octo-repo/downloads", + "issues_url": "https://api.github.com/repos/octo-org/octo-repo/issues{/number}", + "pulls_url": "https://api.github.com/repos/octo-org/octo-repo/pulls{/number}", + "milestones_url": "https://api.github.com/repos/octo-org/octo-repo/milestones{/number}", + "notifications_url": "https://api.github.com/repos/octo-org/octo-repo/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/octo-org/octo-repo/labels{/name}", + "releases_url": "https://api.github.com/repos/octo-org/octo-repo/releases{/id}", + "deployments_url": "https://api.github.com/repos/octo-org/octo-repo/deployments" + } + } + ] +}' +] + +{ #category : #'as yet unclassified' } +GithubActionsMock >> getLatestForRepo: aString ofOwner: aString2 [ + "https://docs.github.com/en/rest/actions/workflow-runs?apiVersion=2022-11-28#list-workflow-runs-for-a-repository" + + ^ '{ + "total_count": 1, + "workflow_runs": [ + { + "id": 30433642, + "name": "Build", + "node_id": "MDEyOldvcmtmbG93IFJ1bjI2OTI4OQ==", + "check_suite_id": 42, + "check_suite_node_id": "MDEwOkNoZWNrU3VpdGU0Mg==", + "head_branch": "master", + "head_sha": "acb5820ced9479c074f688cc328bf03f341a511d", + "path": ".github/workflows/build.yml@main", + "run_number": 562, + "event": "push", + "display_title": "Update README.md", + "status": "queued", + "conclusion": null, + "workflow_id": 159038, + "url": "https://api.github.com/repos/octo-org/octo-repo/actions/runs/30433642", + "html_url": "https://github.com/octo-org/octo-repo/actions/runs/30433642", + "pull_requests": [], + "created_at": "2020-01-22T19:33:08Z", + "updated_at": "2020-01-22T19:33:08Z", + "actor": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "run_attempt": 1, + "run_started_at": "2020-01-22T19:33:08Z", + "triggering_actor": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "jobs_url": "https://api.github.com/repos/octo-org/octo-repo/actions/runs/30433642/jobs", + "logs_url": "https://api.github.com/repos/octo-org/octo-repo/actions/runs/30433642/logs", + "check_suite_url": "https://api.github.com/repos/octo-org/octo-repo/check-suites/414944374", + "artifacts_url": "https://api.github.com/repos/octo-org/octo-repo/actions/runs/30433642/artifacts", + "cancel_url": "https://api.github.com/repos/octo-org/octo-repo/actions/runs/30433642/cancel", + "rerun_url": "https://api.github.com/repos/octo-org/octo-repo/actions/runs/30433642/rerun", + "workflow_url": "https://api.github.com/repos/octo-org/octo-repo/actions/workflows/159038", + "head_commit": { + "id": "acb5820ced9479c074f688cc328bf03f341a511d", + "tree_id": "d23f6eedb1e1b9610bbc754ddb5197bfe7271223", + "message": "Create linter.yaml", + "timestamp": "2020-01-22T19:33:05Z", + "author": { + "name": "Octo Cat", + "email": "octocat@github.com" + }, + "committer": { + "name": "GitHub", + "email": "noreply@github.com" + } + }, + "repository": { + "id": 1296269, + "node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5", + "name": "Hello-World", + "full_name": "octocat/Hello-World", + "owner": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/octocat/Hello-World", + "description": "This your first repo!", + "fork": false, + "url": "https://api.github.com/repos/octocat/Hello-World", + "archive_url": "https://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}", + "assignees_url": "https://api.github.com/repos/octocat/Hello-World/assignees{/user}", + "blobs_url": "https://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}", + "branches_url": "https://api.github.com/repos/octocat/Hello-World/branches{/branch}", + "collaborators_url": "https://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}", + "comments_url": "https://api.github.com/repos/octocat/Hello-World/comments{/number}", + "commits_url": "https://api.github.com/repos/octocat/Hello-World/commits{/sha}", + "compare_url": "https://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}", + "contents_url": "https://api.github.com/repos/octocat/Hello-World/contents/{+path}", + "contributors_url": "https://api.github.com/repos/octocat/Hello-World/contributors", + "deployments_url": "https://api.github.com/repos/octocat/Hello-World/deployments", + "downloads_url": "https://api.github.com/repos/octocat/Hello-World/downloads", + "events_url": "https://api.github.com/repos/octocat/Hello-World/events", + "forks_url": "https://api.github.com/repos/octocat/Hello-World/forks", + "git_commits_url": "https://api.github.com/repos/octocat/Hello-World/git/commits{/sha}", + "git_refs_url": "https://api.github.com/repos/octocat/Hello-World/git/refs{/sha}", + "git_tags_url": "https://api.github.com/repos/octocat/Hello-World/git/tags{/sha}", + "git_url": "git:github.com/octocat/Hello-World.git", + "issue_comment_url": "https://api.github.com/repos/octocat/Hello-World/issues/comments{/number}", + "issue_events_url": "https://api.github.com/repos/octocat/Hello-World/issues/events{/number}", + "issues_url": "https://api.github.com/repos/octocat/Hello-World/issues{/number}", + "keys_url": "https://api.github.com/repos/octocat/Hello-World/keys{/key_id}", + "labels_url": "https://api.github.com/repos/octocat/Hello-World/labels{/name}", + "languages_url": "https://api.github.com/repos/octocat/Hello-World/languages", + "merges_url": "https://api.github.com/repos/octocat/Hello-World/merges", + "milestones_url": "https://api.github.com/repos/octocat/Hello-World/milestones{/number}", + "notifications_url": "https://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}", + "pulls_url": "https://api.github.com/repos/octocat/Hello-World/pulls{/number}", + "releases_url": "https://api.github.com/repos/octocat/Hello-World/releases{/id}", + "ssh_url": "git@github.com:octocat/Hello-World.git", + "stargazers_url": "https://api.github.com/repos/octocat/Hello-World/stargazers", + "statuses_url": "https://api.github.com/repos/octocat/Hello-World/statuses/{sha}", + "subscribers_url": "https://api.github.com/repos/octocat/Hello-World/subscribers", + "subscription_url": "https://api.github.com/repos/octocat/Hello-World/subscription", + "tags_url": "https://api.github.com/repos/octocat/Hello-World/tags", + "teams_url": "https://api.github.com/repos/octocat/Hello-World/teams", + "trees_url": "https://api.github.com/repos/octocat/Hello-World/git/trees{/sha}", + "hooks_url": "http://api.github.com/repos/octocat/Hello-World/hooks" + }, + "head_repository": { + "id": 217723378, + "node_id": "MDEwOlJlcG9zaXRvcnkyMTc3MjMzNzg=", + "name": "octo-repo", + "full_name": "octo-org/octo-repo", + "private": true, + "owner": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/octo-org/octo-repo", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/octo-org/octo-repo", + "forks_url": "https://api.github.com/repos/octo-org/octo-repo/forks", + "keys_url": "https://api.github.com/repos/octo-org/octo-repo/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/octo-org/octo-repo/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/octo-org/octo-repo/teams", + "hooks_url": "https://api.github.com/repos/octo-org/octo-repo/hooks", + "issue_events_url": "https://api.github.com/repos/octo-org/octo-repo/issues/events{/number}", + "events_url": "https://api.github.com/repos/octo-org/octo-repo/events", + "assignees_url": "https://api.github.com/repos/octo-org/octo-repo/assignees{/user}", + "branches_url": "https://api.github.com/repos/octo-org/octo-repo/branches{/branch}", + "tags_url": "https://api.github.com/repos/octo-org/octo-repo/tags", + "blobs_url": "https://api.github.com/repos/octo-org/octo-repo/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/octo-org/octo-repo/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/octo-org/octo-repo/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/octo-org/octo-repo/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/octo-org/octo-repo/statuses/{sha}", + "languages_url": "https://api.github.com/repos/octo-org/octo-repo/languages", + "stargazers_url": "https://api.github.com/repos/octo-org/octo-repo/stargazers", + "contributors_url": "https://api.github.com/repos/octo-org/octo-repo/contributors", + "subscribers_url": "https://api.github.com/repos/octo-org/octo-repo/subscribers", + "subscription_url": "https://api.github.com/repos/octo-org/octo-repo/subscription", + "commits_url": "https://api.github.com/repos/octo-org/octo-repo/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/octo-org/octo-repo/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/octo-org/octo-repo/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/octo-org/octo-repo/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/octo-org/octo-repo/contents/{+path}", + "compare_url": "https://api.github.com/repos/octo-org/octo-repo/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/octo-org/octo-repo/merges", + "archive_url": "https://api.github.com/repos/octo-org/octo-repo/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/octo-org/octo-repo/downloads", + "issues_url": "https://api.github.com/repos/octo-org/octo-repo/issues{/number}", + "pulls_url": "https://api.github.com/repos/octo-org/octo-repo/pulls{/number}", + "milestones_url": "https://api.github.com/repos/octo-org/octo-repo/milestones{/number}", + "notifications_url": "https://api.github.com/repos/octo-org/octo-repo/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/octo-org/octo-repo/labels{/name}", + "releases_url": "https://api.github.com/repos/octo-org/octo-repo/releases{/id}", + "deployments_url": "https://api.github.com/repos/octo-org/octo-repo/deployments" + } + } + ] +}' +] + +{ #category : #get } +GithubActionsMock >> getRun: anInteger forRepo: aString ofOwner: aString3 [ + ^'{ + "id": 30433642, + "name": "Build", + "node_id": "MDEyOldvcmtmbG93IFJ1bjI2OTI4OQ==", + "check_suite_id": 42, + "check_suite_node_id": "MDEwOkNoZWNrU3VpdGU0Mg==", + "head_branch": "main", + "head_sha": "acb5820ced9479c074f688cc328bf03f341a511d", + "path": ".github/workflows/build.yml@main", + "run_number": 562, + "event": "push", + "display_title": "Update README.md", + "status": "queued", + "conclusion": null, + "workflow_id": 159038, + "url": "https://api.github.com/repos/octo-org/octo-repo/actions/runs/30433642", + "html_url": "https://github.com/octo-org/octo-repo/actions/runs/30433642", + "pull_requests": [], + "created_at": "2020-01-22T19:33:08Z", + "updated_at": "2020-01-22T19:33:08Z", + "actor": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "run_attempt": 1, + "referenced_workflows": [ + { + "path": "octocat/Hello-World/.github/workflows/deploy.yml@main", + "sha": "86e8bc9ecf7d38b1ed2d2cfb8eb87ba9b35b01db", + "ref": "refs/heads/main" + }, + { + "path": "octo-org/octo-repo/.github/workflows/report.yml@v2", + "sha": "79e9790903e1c3373b1a3e3a941d57405478a232", + "ref": "refs/tags/v2" + }, + { + "path": "octo-org/octo-repo/.github/workflows/secure.yml@1595d4b6de6a9e9751fb270a41019ce507d4099e", + "sha": "1595d4b6de6a9e9751fb270a41019ce507d4099e" + } + ], + "run_started_at": "2020-01-22T19:33:08Z", + "triggering_actor": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "jobs_url": "https://api.github.com/repos/octo-org/octo-repo/actions/runs/30433642/jobs", + "logs_url": "https://api.github.com/repos/octo-org/octo-repo/actions/runs/30433642/logs", + "check_suite_url": "https://api.github.com/repos/octo-org/octo-repo/check-suites/414944374", + "artifacts_url": "https://api.github.com/repos/octo-org/octo-repo/actions/runs/30433642/artifacts", + "cancel_url": "https://api.github.com/repos/octo-org/octo-repo/actions/runs/30433642/cancel", + "rerun_url": "https://api.github.com/repos/octo-org/octo-repo/actions/runs/30433642/rerun", + "previous_attempt_url": "https://api.github.com/repos/octo-org/octo-repo/actions/runs/30433642/attempts/1", + "workflow_url": "https://api.github.com/repos/octo-org/octo-repo/actions/workflows/159038", + "head_commit": { + "id": "acb5820ced9479c074f688cc328bf03f341a511d", + "tree_id": "d23f6eedb1e1b9610bbc754ddb5197bfe7271223", + "message": "Create linter.yaml", + "timestamp": "2020-01-22T19:33:05Z", + "author": { + "name": "Octo Cat", + "email": "octocat@github.com" + }, + "committer": { + "name": "GitHub", + "email": "noreply@github.com" + } + }, + "repository": { + "id": 1296269, + "node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5", + "name": "Hello-World", + "full_name": "octocat/Hello-World", + "owner": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/octocat/Hello-World", + "description": "This your first repo!", + "fork": false, + "url": "https://api.github.com/repos/octocat/Hello-World", + "archive_url": "https://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}", + "assignees_url": "https://api.github.com/repos/octocat/Hello-World/assignees{/user}", + "blobs_url": "https://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}", + "branches_url": "https://api.github.com/repos/octocat/Hello-World/branches{/branch}", + "collaborators_url": "https://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}", + "comments_url": "https://api.github.com/repos/octocat/Hello-World/comments{/number}", + "commits_url": "https://api.github.com/repos/octocat/Hello-World/commits{/sha}", + "compare_url": "https://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}", + "contents_url": "https://api.github.com/repos/octocat/Hello-World/contents/{+path}", + "contributors_url": "https://api.github.com/repos/octocat/Hello-World/contributors", + "deployments_url": "https://api.github.com/repos/octocat/Hello-World/deployments", + "downloads_url": "https://api.github.com/repos/octocat/Hello-World/downloads", + "events_url": "https://api.github.com/repos/octocat/Hello-World/events", + "forks_url": "https://api.github.com/repos/octocat/Hello-World/forks", + "git_commits_url": "https://api.github.com/repos/octocat/Hello-World/git/commits{/sha}", + "git_refs_url": "https://api.github.com/repos/octocat/Hello-World/git/refs{/sha}", + "git_tags_url": "https://api.github.com/repos/octocat/Hello-World/git/tags{/sha}", + "git_url": "git:github.com/octocat/Hello-World.git", + "issue_comment_url": "https://api.github.com/repos/octocat/Hello-World/issues/comments{/number}", + "issue_events_url": "https://api.github.com/repos/octocat/Hello-World/issues/events{/number}", + "issues_url": "https://api.github.com/repos/octocat/Hello-World/issues{/number}", + "keys_url": "https://api.github.com/repos/octocat/Hello-World/keys{/key_id}", + "labels_url": "https://api.github.com/repos/octocat/Hello-World/labels{/name}", + "languages_url": "https://api.github.com/repos/octocat/Hello-World/languages", + "merges_url": "https://api.github.com/repos/octocat/Hello-World/merges", + "milestones_url": "https://api.github.com/repos/octocat/Hello-World/milestones{/number}", + "notifications_url": "https://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}", + "pulls_url": "https://api.github.com/repos/octocat/Hello-World/pulls{/number}", + "releases_url": "https://api.github.com/repos/octocat/Hello-World/releases{/id}", + "ssh_url": "git@github.com:octocat/Hello-World.git", + "stargazers_url": "https://api.github.com/repos/octocat/Hello-World/stargazers", + "statuses_url": "https://api.github.com/repos/octocat/Hello-World/statuses/{sha}", + "subscribers_url": "https://api.github.com/repos/octocat/Hello-World/subscribers", + "subscription_url": "https://api.github.com/repos/octocat/Hello-World/subscription", + "tags_url": "https://api.github.com/repos/octocat/Hello-World/tags", + "teams_url": "https://api.github.com/repos/octocat/Hello-World/teams", + "trees_url": "https://api.github.com/repos/octocat/Hello-World/git/trees{/sha}", + "hooks_url": "http://api.github.com/repos/octocat/Hello-World/hooks" + }, + "head_repository": { + "id": 217723378, + "node_id": "MDEwOlJlcG9zaXRvcnkyMTc3MjMzNzg=", + "name": "octo-repo", + "full_name": "octo-org/octo-repo", + "private": true, + "owner": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/octo-org/octo-repo", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/octo-org/octo-repo", + "forks_url": "https://api.github.com/repos/octo-org/octo-repo/forks", + "keys_url": "https://api.github.com/repos/octo-org/octo-repo/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/octo-org/octo-repo/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/octo-org/octo-repo/teams", + "hooks_url": "https://api.github.com/repos/octo-org/octo-repo/hooks", + "issue_events_url": "https://api.github.com/repos/octo-org/octo-repo/issues/events{/number}", + "events_url": "https://api.github.com/repos/octo-org/octo-repo/events", + "assignees_url": "https://api.github.com/repos/octo-org/octo-repo/assignees{/user}", + "branches_url": "https://api.github.com/repos/octo-org/octo-repo/branches{/branch}", + "tags_url": "https://api.github.com/repos/octo-org/octo-repo/tags", + "blobs_url": "https://api.github.com/repos/octo-org/octo-repo/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/octo-org/octo-repo/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/octo-org/octo-repo/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/octo-org/octo-repo/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/octo-org/octo-repo/statuses/{sha}", + "languages_url": "https://api.github.com/repos/octo-org/octo-repo/languages", + "stargazers_url": "https://api.github.com/repos/octo-org/octo-repo/stargazers", + "contributors_url": "https://api.github.com/repos/octo-org/octo-repo/contributors", + "subscribers_url": "https://api.github.com/repos/octo-org/octo-repo/subscribers", + "subscription_url": "https://api.github.com/repos/octo-org/octo-repo/subscription", + "commits_url": "https://api.github.com/repos/octo-org/octo-repo/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/octo-org/octo-repo/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/octo-org/octo-repo/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/octo-org/octo-repo/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/octo-org/octo-repo/contents/{+path}", + "compare_url": "https://api.github.com/repos/octo-org/octo-repo/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/octo-org/octo-repo/merges", + "archive_url": "https://api.github.com/repos/octo-org/octo-repo/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/octo-org/octo-repo/downloads", + "issues_url": "https://api.github.com/repos/octo-org/octo-repo/issues{/number}", + "pulls_url": "https://api.github.com/repos/octo-org/octo-repo/pulls{/number}", + "milestones_url": "https://api.github.com/repos/octo-org/octo-repo/milestones{/number}", + "notifications_url": "https://api.github.com/repos/octo-org/octo-repo/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/octo-org/octo-repo/labels{/name}", + "releases_url": "https://api.github.com/repos/octo-org/octo-repo/releases{/id}", + "deployments_url": "https://api.github.com/repos/octo-org/octo-repo/deployments" + } +}' +] + +{ #category : #get } +GithubActionsMock >> getWorkflow: anInteger forRepo: aString ofOwner: aString3 [ + ^ '{ + "id": 161335, + "node_id": "MDg6V29ya2Zsb3cxNjEzMzU=", + "name": "CI", + "path": ".github/workflows/blank.yaml", + "state": "active", + "created_at": "2020-01-08T23:48:37.000-08:00", + "updated_at": "2020-01-08T23:50:21.000-08:00", + "url": "https://api.github.com/repos/octo-org/octo-repo/actions/workflows/161335", + "html_url": "https://github.com/octo-org/octo-repo/blob/master/.github/workflows/161335", + "badge_url": "https://github.com/octo-org/octo-repo/workflows/CI/badge.svg" +}' +] diff --git a/src/GitHubHealth-Model-Importer-Tests/GithubApiMock.class.st b/src/GitHubHealth-Model-Importer-Tests/GithubApiMock.class.st new file mode 100644 index 00000000..c50bba87 --- /dev/null +++ b/src/GitHubHealth-Model-Importer-Tests/GithubApiMock.class.st @@ -0,0 +1,41 @@ +Class { + #name : #GithubApiMock, + #superclass : #Object, + #category : #'GitHubHealth-Model-Importer-Tests' +} + +{ #category : #actions } +GithubApiMock >> actions [ + ^ GithubActionsMock new +] + +{ #category : #accessing } +GithubApiMock >> branches [ + ^ GithubBranchesMock new +] + +{ #category : #accessing } +GithubApiMock >> commits [ + ^ GithubCommitsMock new. +] + +{ #category : #organizations } +GithubApiMock >> organizations [ + ^ GithubOrganizationsMock new +] + +{ #category : #accessing } +GithubApiMock >> output: aString [ + ^ self +] + +{ #category : #ressources } +GithubApiMock >> pullRequests [ + + ^ GithubPullRequestsMock new +] + +{ #category : #accessing } +GithubApiMock >> users [ + ^ GithubUsersMock new +] diff --git a/src/GitHubHealth-Model-Importer-Tests/GithubBranchesMock.class.st b/src/GitHubHealth-Model-Importer-Tests/GithubBranchesMock.class.st new file mode 100644 index 00000000..18d72e94 --- /dev/null +++ b/src/GitHubHealth-Model-Importer-Tests/GithubBranchesMock.class.st @@ -0,0 +1,30 @@ +Class { + #name : #GithubBranchesMock, + #superclass : #Object, + #category : #'GitHubHealth-Model-Importer-Tests' +} + +{ #category : #'as yet unclassified' } +GithubBranchesMock >> getAllForRepo: aString ofOwner: aString2 [ + + ^ {'[ + { + "name": "master", + "commit": { + "sha": "c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc", + "url": "https://api.github.com/repos/octocat/Hello-World/commits/c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc" + }, + "protected": true, + "protection": { + "required_status_checks": { + "enforcement_level": "non_admins", + "contexts": [ + "ci-test", + "linter" + ] + } + }, + "protection_url": "https://api.github.com/repos/octocat/hello-world/branches/master/protection" + } +]'} +] diff --git a/src/GitHubHealth-Model-Importer-Tests/GithubCommitsMock.class.st b/src/GitHubHealth-Model-Importer-Tests/GithubCommitsMock.class.st new file mode 100644 index 00000000..75d4d7b2 --- /dev/null +++ b/src/GitHubHealth-Model-Importer-Tests/GithubCommitsMock.class.st @@ -0,0 +1,201 @@ +Class { + #name : #GithubCommitsMock, + #superclass : #Object, + #category : #'GitHubHealth-Model-Importer-Tests' +} + +{ #category : #api } +GithubCommitsMock >> get: anInteger inProject: anUndefinedObject [ + + ^ '{ + "url": "https://api.github.com/repos/octocat/Hello-World/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e", + "sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e", + "node_id": "MDY6Q29tbWl0NmRjYjA5YjViNTc4NzVmMzM0ZjYxYWViZWQ2OTVlMmU0MTkzZGI1ZQ==", + "html_url": "https://github.com/octocat/Hello-World/commit/6dcb09b5b57875f334f61aebed695e2e4193db5e", + "comments_url": "https://api.github.com/repos/octocat/Hello-World/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e/comments", + "commit": { + "url": "https://api.github.com/repos/octocat/Hello-World/git/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e", + "author": { + "name": "Monalisa Octocat", + "email": "mona@github.com", + "date": "2011-04-14T16:00:49Z" + }, + "committer": { + "name": "Monalisa Octocat", + "email": "mona@github.com", + "date": "2011-04-14T16:00:49Z" + }, + "message": "Fix all the bugs", + "tree": { + "url": "https://api.github.com/repos/octocat/Hello-World/tree/6dcb09b5b57875f334f61aebed695e2e4193db5e", + "sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e" + }, + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "author": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "committer": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "parents": [ + { + "url": "https://api.github.com/repos/octocat/Hello-World/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e", + "sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e" + } + ], + "stats": { + "additions": 104, + "deletions": 4, + "total": 108 + }, + "files": [ + { + "filename": "file1.txt", + "additions": 10, + "deletions": 2, + "changes": 12, + "status": "modified", + "raw_url": "https://github.com/octocat/Hello-World/raw/7ca483543807a51b6079e54ac4cc392bc29ae284/file1.txt", + "blob_url": "https://github.com/octocat/Hello-World/blob/7ca483543807a51b6079e54ac4cc392bc29ae284/file1.txt", + "patch": "@@ -29,7 +29,7 @@\n....." + } + ] +}' +] + +{ #category : #'as yet unclassified' } +GithubCommitsMock >> getCommit: aString ForRepo: aString2 ofOwner: aString3 [ + ^ self get: nil inProject: nil +] + +{ #category : #'as yet unclassified' } +GithubCommitsMock >> getForRepo: aString ofOwner: aString2 withParms: aCollection [ + ^ self getLatestForRepo: nil ofOwner: nil +] + +{ #category : #'as yet unclassified' } +GithubCommitsMock >> getLatestForRepo: aString ofOwner: aString2 [ + ^ '[ + { + "url": "https://api.github.com/repos/octocat/Hello-World/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e", + "sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e", + "node_id": "MDY6Q29tbWl0NmRjYjA5YjViNTc4NzVmMzM0ZjYxYWViZWQ2OTVlMmU0MTkzZGI1ZQ==", + "html_url": "https://github.com/octocat/Hello-World/commit/6dcb09b5b57875f334f61aebed695e2e4193db5e", + "comments_url": "https://api.github.com/repos/octocat/Hello-World/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e/comments", + "commit": { + "url": "https://api.github.com/repos/octocat/Hello-World/git/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e", + "author": { + "name": "Monalisa Octocat", + "email": "support@github.com", + "date": "2011-04-14T16:00:49Z" + }, + "committer": { + "name": "Monalisa Octocat", + "email": "support@github.com", + "date": "2011-04-14T16:00:49Z" + }, + "message": "Fix all the bugs", + "tree": { + "url": "https://api.github.com/repos/octocat/Hello-World/tree/6dcb09b5b57875f334f61aebed695e2e4193db5e", + "sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e" + }, + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "author": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "committer": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "parents": [ + { + "url": "https://api.github.com/repos/octocat/Hello-World/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e", + "sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e" + } + ] + } +]' +] diff --git a/src/GitHubHealth-Model-Importer-Tests/GHModelImporterTest.class.st b/src/GitHubHealth-Model-Importer-Tests/GithubModelImporterTest.class.st similarity index 88% rename from src/GitHubHealth-Model-Importer-Tests/GHModelImporterTest.class.st rename to src/GitHubHealth-Model-Importer-Tests/GithubModelImporterTest.class.st index d8ee080b..04f22c85 100644 --- a/src/GitHubHealth-Model-Importer-Tests/GHModelImporterTest.class.st +++ b/src/GitHubHealth-Model-Importer-Tests/GithubModelImporterTest.class.st @@ -1,309 +1,323 @@ -" -A GHModelImporterTest is a test class for testing the behavior of GHModelImporter -" -Class { - #name : #GHModelImporterTest, - #superclass : #TestCase, - #instVars : [ - 'importer' - ], - #category : #'GitHubHealth-Model-Importer-Tests' -} - -{ #category : #running } -GHModelImporterTest >> setUp [ - super setUp. - - importer := GithubModelImporter new -] - -{ #category : #tests } -GHModelImporterTest >> testParseCommitsResult [ - "we remove the id of author entries to not trigger the call to import user" - - | 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", - "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", - "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'. - self assert: commits first authored_date isNotNil. - self assert: commits first committed_date isNotNil -] - -{ #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 [ - - | project | - project := importer parsePipelinesResult: '{ - "total_count": 1, - "workflow_runs": [ - { - "id": 7482814798, - "conclusion": "success", - "run_started_at": "2024-01-11T00:00:00" - }]}'. - - self assert: project workflow_runs size equals: 1. - - self assert: project workflow_runs anyOne status equals: 'success'. - self - 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 -] +" +A GithubModelImporterTest is a test class for testing the behavior of GithubModelImporter +" +Class { + #name : #GithubModelImporterTest, + #superclass : #TestCase, + #traits : 'TGitModelImporterTest', + #classTraits : 'TGitModelImporterTest classTrait', + #category : #'GitHubHealth-Model-Importer-Tests' +} + +{ #category : #running } +GithubModelImporterTest >> setUp [ + + super setUp. + "first set the local importer" + importer := GithubModelImporter new. + importer repoApi: GithubApiMock new. + + "than set up the model in super" + model := GLHModel new. + importer glhModel: model. + + defaultProject := GLHProject new + name: 'myProject'; + group: (GLHGroup new name: 'itsGroup'); + repository: GLHRepository new; + yourself. + + defaultMergeRequestOrPipeline := GLHMergeRequest new + name: 'myPipeline'; + sha: '30433642'; + project: (GLHProject new + name: 'myProject'; + group: (GLHGroup new name: 'itsGroup'); + repository: GLHRepository new; + yourself); + yourself +] + +{ #category : #'tests - parsing' } +GithubModelImporterTest >> testParseCommitsResult [ + "we remove the id of author entries to not trigger the call to import user" + + | 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", + "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", + "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'. + self assert: commits first authored_date isNotNil. + self assert: commits first committed_date isNotNil +] + +{ #category : #'tests - parsing' } +GithubModelImporterTest >> 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 : #'tests - parsing' } +GithubModelImporterTest >> testParsePipelinesResult [ + + | project | + project := importer parsePipelinesResult: (GithubActionsMock new getLatestForRepo: nil ofOwner: nil). + + self assert: project workflow_runs size equals: 1. + + self assert: project workflow_runs anyOne status equals: 'queued'. + self + assert: project workflow_runs anyOne runDate asDate printString + equals: (Date year: 2020 month: 01 day: 22) printString +] + +{ #category : #'tests - parsing' } +GithubModelImporterTest >> 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-Tests/GithubOrganizationsMock.class.st b/src/GitHubHealth-Model-Importer-Tests/GithubOrganizationsMock.class.st new file mode 100644 index 00000000..29cc722b --- /dev/null +++ b/src/GitHubHealth-Model-Importer-Tests/GithubOrganizationsMock.class.st @@ -0,0 +1,212 @@ +Class { + #name : #GithubOrganizationsMock, + #superclass : #Object, + #category : #'GitHubHealth-Model-Importer-Tests' +} + +{ #category : #api } +GithubOrganizationsMock >> get: anInteger [ + ^ '{ + "login": "github", + "id": 1, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjE=", + "url": "https://api.github.com/orgs/github", + "repos_url": "https://api.github.com/orgs/github/repos", + "events_url": "https://api.github.com/orgs/github/events", + "hooks_url": "https://api.github.com/orgs/github/hooks", + "issues_url": "https://api.github.com/orgs/github/issues", + "members_url": "https://api.github.com/orgs/github/members{/member}", + "public_members_url": "https://api.github.com/orgs/github/public_members{/member}", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "description": "A great organization", + "name": "github", + "company": "GitHub", + "blog": "https://github.com/blog", + "location": "San Francisco", + "email": "octocat@github.com", + "twitter_username": "github", + "is_verified": true, + "has_organization_projects": true, + "has_repository_projects": true, + "public_repos": 2, + "public_gists": 1, + "followers": 20, + "following": 0, + "html_url": "https://github.com/octocat", + "created_at": "2008-01-14T04:33:35Z", + "type": "Organization", + "total_private_repos": 100, + "owned_private_repos": 100, + "private_gists": 81, + "disk_usage": 10000, + "collaborators": 8, + "billing_email": "mona@github.com", + "plan": { + "name": "Medium", + "space": 400, + "private_repos": 20, + "filled_seats": 4, + "seats": 5 + }, + "default_repository_permission": "read", + "default_repository_branch": "main", + "members_can_create_repositories": true, + "two_factor_requirement_enabled": true, + "members_allowed_repository_creation_type": "all", + "members_can_create_public_repositories": false, + "members_can_create_private_repositories": false, + "members_can_create_internal_repositories": false, + "members_can_create_pages": true, + "members_can_create_public_pages": true, + "members_can_create_private_pages": true, + "members_can_delete_repositories": true, + "members_can_change_repo_visibility": true, + "members_can_invite_outside_collaborators": true, + "members_can_delete_issues": false, + "display_commenter_full_name_setting_enabled": false, + "readers_can_create_discussions": true, + "members_can_create_teams": true, + "members_can_view_dependency_insights": true, + "members_can_fork_private_repositories": false, + "web_commit_signoff_required": false, + "updated_at": "2014-03-03T18:58:10Z", + "deploy_keys_enabled_for_repositories": false, + "dependency_graph_enabled_for_new_repositories": false, + "dependabot_alerts_enabled_for_new_repositories": false, + "dependabot_security_updates_enabled_for_new_repositories": false, + "advanced_security_enabled_for_new_repositories": false, + "secret_scanning_enabled_for_new_repositories": false, + "secret_scanning_push_protection_enabled_for_new_repositories": false, + "secret_scanning_push_protection_custom_link": "https://github.com/octo-org/octo-repo/blob/main/im-blocked.md", + "secret_scanning_push_protection_custom_link_enabled": false +}' +] + +{ #category : #get } +GithubOrganizationsMock >> getRepositoriesOfOrganization: aString [ + ^ self getRepositoriesOfOrganization: nil perPage: nil page: nil +] + +{ #category : #get } +GithubOrganizationsMock >> getRepositoriesOfOrganization: aString perPage: anInteger page: anInteger3 [ + ^ '[ + { + "id": 1296269, + "node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5", + "name": "Hello-World", + "full_name": "octocat/Hello-World", + "owner": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/octocat/Hello-World", + "description": "This your first repo!", + "fork": false, + "url": "https://api.github.com/repos/octocat/Hello-World", + "archive_url": "https://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}", + "assignees_url": "https://api.github.com/repos/octocat/Hello-World/assignees{/user}", + "blobs_url": "https://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}", + "branches_url": "https://api.github.com/repos/octocat/Hello-World/branches{/branch}", + "collaborators_url": "https://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}", + "comments_url": "https://api.github.com/repos/octocat/Hello-World/comments{/number}", + "commits_url": "https://api.github.com/repos/octocat/Hello-World/commits{/sha}", + "compare_url": "https://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}", + "contents_url": "https://api.github.com/repos/octocat/Hello-World/contents/{+path}", + "contributors_url": "https://api.github.com/repos/octocat/Hello-World/contributors", + "deployments_url": "https://api.github.com/repos/octocat/Hello-World/deployments", + "downloads_url": "https://api.github.com/repos/octocat/Hello-World/downloads", + "events_url": "https://api.github.com/repos/octocat/Hello-World/events", + "forks_url": "https://api.github.com/repos/octocat/Hello-World/forks", + "git_commits_url": "https://api.github.com/repos/octocat/Hello-World/git/commits{/sha}", + "git_refs_url": "https://api.github.com/repos/octocat/Hello-World/git/refs{/sha}", + "git_tags_url": "https://api.github.com/repos/octocat/Hello-World/git/tags{/sha}", + "git_url": "git:github.com/octocat/Hello-World.git", + "issue_comment_url": "https://api.github.com/repos/octocat/Hello-World/issues/comments{/number}", + "issue_events_url": "https://api.github.com/repos/octocat/Hello-World/issues/events{/number}", + "issues_url": "https://api.github.com/repos/octocat/Hello-World/issues{/number}", + "keys_url": "https://api.github.com/repos/octocat/Hello-World/keys{/key_id}", + "labels_url": "https://api.github.com/repos/octocat/Hello-World/labels{/name}", + "languages_url": "https://api.github.com/repos/octocat/Hello-World/languages", + "merges_url": "https://api.github.com/repos/octocat/Hello-World/merges", + "milestones_url": "https://api.github.com/repos/octocat/Hello-World/milestones{/number}", + "notifications_url": "https://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}", + "pulls_url": "https://api.github.com/repos/octocat/Hello-World/pulls{/number}", + "releases_url": "https://api.github.com/repos/octocat/Hello-World/releases{/id}", + "ssh_url": "git@github.com:octocat/Hello-World.git", + "stargazers_url": "https://api.github.com/repos/octocat/Hello-World/stargazers", + "statuses_url": "https://api.github.com/repos/octocat/Hello-World/statuses/{sha}", + "subscribers_url": "https://api.github.com/repos/octocat/Hello-World/subscribers", + "subscription_url": "https://api.github.com/repos/octocat/Hello-World/subscription", + "tags_url": "https://api.github.com/repos/octocat/Hello-World/tags", + "teams_url": "https://api.github.com/repos/octocat/Hello-World/teams", + "trees_url": "https://api.github.com/repos/octocat/Hello-World/git/trees{/sha}", + "clone_url": "https://github.com/octocat/Hello-World.git", + "mirror_url": "git:git.example.com/octocat/Hello-World", + "hooks_url": "https://api.github.com/repos/octocat/Hello-World/hooks", + "svn_url": "https://svn.github.com/octocat/Hello-World", + "homepage": "https://github.com", + "language": null, + "forks_count": 9, + "stargazers_count": 80, + "watchers_count": 80, + "size": 108, + "default_branch": "master", + "open_issues_count": 0, + "is_template": false, + "topics": [ + "octocat", + "atom", + "electron", + "api" + ], + "has_issues": true, + "has_projects": true, + "has_wiki": true, + "has_pages": false, + "has_downloads": true, + "has_discussions": false, + "archived": false, + "disabled": false, + "visibility": "public", + "pushed_at": "2011-01-26T19:06:43Z", + "created_at": "2011-01-26T19:01:12Z", + "updated_at": "2011-01-26T19:14:43Z", + "permissions": { + "admin": false, + "push": false, + "pull": true + }, + "security_and_analysis": { + "advanced_security": { + "status": "enabled" + }, + "secret_scanning": { + "status": "enabled" + }, + "secret_scanning_push_protection": { + "status": "disabled" + }, + "secret_scanning_non_provider_patterns": { + "status": "disabled" + } + } + } +]' +] diff --git a/src/GitHubHealth-Model-Importer-Tests/GithubPullRequestsMock.class.st b/src/GitHubHealth-Model-Importer-Tests/GithubPullRequestsMock.class.st new file mode 100644 index 00000000..664d0523 --- /dev/null +++ b/src/GitHubHealth-Model-Importer-Tests/GithubPullRequestsMock.class.st @@ -0,0 +1,530 @@ +Class { + #name : #GithubPullRequestsMock, + #superclass : #Object, + #category : #'GitHubHealth-Model-Importer-Tests' +} + +{ #category : #'as yet unclassified' } +GithubPullRequestsMock >> getLatestForRepo: aString ofOwner: aString2 [ + ^ '[ + { + "url": "https://api.github.com/repos/octocat/Hello-World/pulls/1347", + "id": 1, + "node_id": "MDExOlB1bGxSZXF1ZXN0MQ==", + "html_url": "https://github.com/octocat/Hello-World/pull/1347", + "diff_url": "https://github.com/octocat/Hello-World/pull/1347.diff", + "patch_url": "https://github.com/octocat/Hello-World/pull/1347.patch", + "issue_url": "https://api.github.com/repos/octocat/Hello-World/issues/1347", + "commits_url": "https://api.github.com/repos/octocat/Hello-World/pulls/1347/commits", + "review_comments_url": "https://api.github.com/repos/octocat/Hello-World/pulls/1347/comments", + "review_comment_url": "https://api.github.com/repos/octocat/Hello-World/pulls/comments{/number}", + "comments_url": "https://api.github.com/repos/octocat/Hello-World/issues/1347/comments", + "statuses_url": "https://api.github.com/repos/octocat/Hello-World/statuses/6dcb09b5b57875f334f61aebed695e2e4193db5e", + "number": 1347, + "state": "open", + "locked": true, + "title": "Amazing new feature", + "user": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "body": "Please pull these awesome changes in!", + "labels": [ + { + "id": 208045946, + "node_id": "MDU6TGFiZWwyMDgwNDU5NDY=", + "url": "https://api.github.com/repos/octocat/Hello-World/labels/bug", + "name": "bug", + "description": "Something isn''t working", + "color": "f29513", + "default": true + } + ], + "milestone": { + "url": "https://api.github.com/repos/octocat/Hello-World/milestones/1", + "html_url": "https://github.com/octocat/Hello-World/milestones/v1.0", + "labels_url": "https://api.github.com/repos/octocat/Hello-World/milestones/1/labels", + "id": 1002604, + "node_id": "MDk6TWlsZXN0b25lMTAwMjYwNA==", + "number": 1, + "state": "open", + "title": "v1.0", + "description": "Tracking milestone for version 1.0", + "creator": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "open_issues": 4, + "closed_issues": 8, + "created_at": "2011-04-10T20:09:31Z", + "updated_at": "2014-03-03T18:58:10Z", + "closed_at": "2013-02-12T13:22:01Z", + "due_on": "2012-10-09T23:39:01Z" + }, + "active_lock_reason": "too heated", + "created_at": "2011-01-26T19:01:12Z", + "updated_at": "2011-01-26T19:01:12Z", + "closed_at": "2011-01-26T19:01:12Z", + "merged_at": "2011-01-26T19:01:12Z", + "merge_commit_sha": "e5bd3914e2e596debea16f433f57875b5b90bcd6", + "assignee": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "assignees": [ + { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + { + "login": "hubot", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/hubot_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/hubot", + "html_url": "https://github.com/hubot", + "followers_url": "https://api.github.com/users/hubot/followers", + "following_url": "https://api.github.com/users/hubot/following{/other_user}", + "gists_url": "https://api.github.com/users/hubot/gists{/gist_id}", + "starred_url": "https://api.github.com/users/hubot/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/hubot/subscriptions", + "organizations_url": "https://api.github.com/users/hubot/orgs", + "repos_url": "https://api.github.com/users/hubot/repos", + "events_url": "https://api.github.com/users/hubot/events{/privacy}", + "received_events_url": "https://api.github.com/users/hubot/received_events", + "type": "User", + "site_admin": true + } + ], + "requested_reviewers": [ + { + "login": "other_user", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/other_user_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/other_user", + "html_url": "https://github.com/other_user", + "followers_url": "https://api.github.com/users/other_user/followers", + "following_url": "https://api.github.com/users/other_user/following{/other_user}", + "gists_url": "https://api.github.com/users/other_user/gists{/gist_id}", + "starred_url": "https://api.github.com/users/other_user/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/other_user/subscriptions", + "organizations_url": "https://api.github.com/users/other_user/orgs", + "repos_url": "https://api.github.com/users/other_user/repos", + "events_url": "https://api.github.com/users/other_user/events{/privacy}", + "received_events_url": "https://api.github.com/users/other_user/received_events", + "type": "User", + "site_admin": false + } + ], + "requested_teams": [ + { + "id": 1, + "node_id": "MDQ6VGVhbTE=", + "url": "https://api.github.com/teams/1", + "html_url": "https://github.com/orgs/github/teams/justice-league", + "name": "Justice League", + "slug": "justice-league", + "description": "A great team.", + "privacy": "closed", + "permission": "admin", + "notification_setting": "notifications_enabled", + "members_url": "https://api.github.com/teams/1/members{/member}", + "repositories_url": "https://api.github.com/teams/1/repos", + "parent": null + } + ], + "head": { + "label": "octocat:new-topic", + "ref": "new-topic", + "sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e", + "user": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "repo": { + "id": 1296269, + "node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5", + "name": "Hello-World", + "full_name": "octocat/Hello-World", + "owner": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/octocat/Hello-World", + "description": "This your first repo!", + "fork": false, + "url": "https://api.github.com/repos/octocat/Hello-World", + "archive_url": "https://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}", + "assignees_url": "https://api.github.com/repos/octocat/Hello-World/assignees{/user}", + "blobs_url": "https://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}", + "branches_url": "https://api.github.com/repos/octocat/Hello-World/branches{/branch}", + "collaborators_url": "https://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}", + "comments_url": "https://api.github.com/repos/octocat/Hello-World/comments{/number}", + "commits_url": "https://api.github.com/repos/octocat/Hello-World/commits{/sha}", + "compare_url": "https://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}", + "contents_url": "https://api.github.com/repos/octocat/Hello-World/contents/{+path}", + "contributors_url": "https://api.github.com/repos/octocat/Hello-World/contributors", + "deployments_url": "https://api.github.com/repos/octocat/Hello-World/deployments", + "downloads_url": "https://api.github.com/repos/octocat/Hello-World/downloads", + "events_url": "https://api.github.com/repos/octocat/Hello-World/events", + "forks_url": "https://api.github.com/repos/octocat/Hello-World/forks", + "git_commits_url": "https://api.github.com/repos/octocat/Hello-World/git/commits{/sha}", + "git_refs_url": "https://api.github.com/repos/octocat/Hello-World/git/refs{/sha}", + "git_tags_url": "https://api.github.com/repos/octocat/Hello-World/git/tags{/sha}", + "git_url": "git:github.com/octocat/Hello-World.git", + "issue_comment_url": "https://api.github.com/repos/octocat/Hello-World/issues/comments{/number}", + "issue_events_url": "https://api.github.com/repos/octocat/Hello-World/issues/events{/number}", + "issues_url": "https://api.github.com/repos/octocat/Hello-World/issues{/number}", + "keys_url": "https://api.github.com/repos/octocat/Hello-World/keys{/key_id}", + "labels_url": "https://api.github.com/repos/octocat/Hello-World/labels{/name}", + "languages_url": "https://api.github.com/repos/octocat/Hello-World/languages", + "merges_url": "https://api.github.com/repos/octocat/Hello-World/merges", + "milestones_url": "https://api.github.com/repos/octocat/Hello-World/milestones{/number}", + "notifications_url": "https://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}", + "pulls_url": "https://api.github.com/repos/octocat/Hello-World/pulls{/number}", + "releases_url": "https://api.github.com/repos/octocat/Hello-World/releases{/id}", + "ssh_url": "git@github.com:octocat/Hello-World.git", + "stargazers_url": "https://api.github.com/repos/octocat/Hello-World/stargazers", + "statuses_url": "https://api.github.com/repos/octocat/Hello-World/statuses/{sha}", + "subscribers_url": "https://api.github.com/repos/octocat/Hello-World/subscribers", + "subscription_url": "https://api.github.com/repos/octocat/Hello-World/subscription", + "tags_url": "https://api.github.com/repos/octocat/Hello-World/tags", + "teams_url": "https://api.github.com/repos/octocat/Hello-World/teams", + "trees_url": "https://api.github.com/repos/octocat/Hello-World/git/trees{/sha}", + "clone_url": "https://github.com/octocat/Hello-World.git", + "mirror_url": "git:git.example.com/octocat/Hello-World", + "hooks_url": "https://api.github.com/repos/octocat/Hello-World/hooks", + "svn_url": "https://svn.github.com/octocat/Hello-World", + "homepage": "https://github.com", + "language": null, + "forks_count": 9, + "stargazers_count": 80, + "watchers_count": 80, + "size": 108, + "default_branch": "master", + "open_issues_count": 0, + "is_template": true, + "topics": [ + "octocat", + "atom", + "electron", + "api" + ], + "has_issues": true, + "has_projects": true, + "has_wiki": true, + "has_pages": false, + "has_downloads": true, + "archived": false, + "disabled": false, + "visibility": "public", + "pushed_at": "2011-01-26T19:06:43Z", + "created_at": "2011-01-26T19:01:12Z", + "updated_at": "2011-01-26T19:14:43Z", + "permissions": { + "admin": false, + "push": false, + "pull": true + }, + "allow_rebase_merge": true, + "template_repository": null, + "temp_clone_token": "ABTLWHOULUVAXGTRYU7OC2876QJ2O", + "allow_squash_merge": true, + "allow_auto_merge": false, + "delete_branch_on_merge": true, + "allow_merge_commit": true, + "subscribers_count": 42, + "network_count": 0, + "license": { + "key": "mit", + "name": "MIT License", + "url": "https://api.github.com/licenses/mit", + "spdx_id": "MIT", + "node_id": "MDc6TGljZW5zZW1pdA==", + "html_url": "https://github.com/licenses/mit" + }, + "forks": 1, + "open_issues": 1, + "watchers": 1 + } + }, + "base": { + "label": "octocat:master", + "ref": "master", + "sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e", + "user": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "repo": { + "id": 1296269, + "node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5", + "name": "Hello-World", + "full_name": "octocat/Hello-World", + "owner": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/octocat/Hello-World", + "description": "This your first repo!", + "fork": false, + "url": "https://api.github.com/repos/octocat/Hello-World", + "archive_url": "https://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}", + "assignees_url": "https://api.github.com/repos/octocat/Hello-World/assignees{/user}", + "blobs_url": "https://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}", + "branches_url": "https://api.github.com/repos/octocat/Hello-World/branches{/branch}", + "collaborators_url": "https://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}", + "comments_url": "https://api.github.com/repos/octocat/Hello-World/comments{/number}", + "commits_url": "https://api.github.com/repos/octocat/Hello-World/commits{/sha}", + "compare_url": "https://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}", + "contents_url": "https://api.github.com/repos/octocat/Hello-World/contents/{+path}", + "contributors_url": "https://api.github.com/repos/octocat/Hello-World/contributors", + "deployments_url": "https://api.github.com/repos/octocat/Hello-World/deployments", + "downloads_url": "https://api.github.com/repos/octocat/Hello-World/downloads", + "events_url": "https://api.github.com/repos/octocat/Hello-World/events", + "forks_url": "https://api.github.com/repos/octocat/Hello-World/forks", + "git_commits_url": "https://api.github.com/repos/octocat/Hello-World/git/commits{/sha}", + "git_refs_url": "https://api.github.com/repos/octocat/Hello-World/git/refs{/sha}", + "git_tags_url": "https://api.github.com/repos/octocat/Hello-World/git/tags{/sha}", + "git_url": "git:github.com/octocat/Hello-World.git", + "issue_comment_url": "https://api.github.com/repos/octocat/Hello-World/issues/comments{/number}", + "issue_events_url": "https://api.github.com/repos/octocat/Hello-World/issues/events{/number}", + "issues_url": "https://api.github.com/repos/octocat/Hello-World/issues{/number}", + "keys_url": "https://api.github.com/repos/octocat/Hello-World/keys{/key_id}", + "labels_url": "https://api.github.com/repos/octocat/Hello-World/labels{/name}", + "languages_url": "https://api.github.com/repos/octocat/Hello-World/languages", + "merges_url": "https://api.github.com/repos/octocat/Hello-World/merges", + "milestones_url": "https://api.github.com/repos/octocat/Hello-World/milestones{/number}", + "notifications_url": "https://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}", + "pulls_url": "https://api.github.com/repos/octocat/Hello-World/pulls{/number}", + "releases_url": "https://api.github.com/repos/octocat/Hello-World/releases{/id}", + "ssh_url": "git@github.com:octocat/Hello-World.git", + "stargazers_url": "https://api.github.com/repos/octocat/Hello-World/stargazers", + "statuses_url": "https://api.github.com/repos/octocat/Hello-World/statuses/{sha}", + "subscribers_url": "https://api.github.com/repos/octocat/Hello-World/subscribers", + "subscription_url": "https://api.github.com/repos/octocat/Hello-World/subscription", + "tags_url": "https://api.github.com/repos/octocat/Hello-World/tags", + "teams_url": "https://api.github.com/repos/octocat/Hello-World/teams", + "trees_url": "https://api.github.com/repos/octocat/Hello-World/git/trees{/sha}", + "clone_url": "https://github.com/octocat/Hello-World.git", + "mirror_url": "git:git.example.com/octocat/Hello-World", + "hooks_url": "https://api.github.com/repos/octocat/Hello-World/hooks", + "svn_url": "https://svn.github.com/octocat/Hello-World", + "homepage": "https://github.com", + "language": null, + "forks_count": 9, + "stargazers_count": 80, + "watchers_count": 80, + "size": 108, + "default_branch": "master", + "open_issues_count": 0, + "is_template": true, + "topics": [ + "octocat", + "atom", + "electron", + "api" + ], + "has_issues": true, + "has_projects": true, + "has_wiki": true, + "has_pages": false, + "has_downloads": true, + "archived": false, + "disabled": false, + "visibility": "public", + "pushed_at": "2011-01-26T19:06:43Z", + "created_at": "2011-01-26T19:01:12Z", + "updated_at": "2011-01-26T19:14:43Z", + "permissions": { + "admin": false, + "push": false, + "pull": true + }, + "allow_rebase_merge": true, + "template_repository": null, + "temp_clone_token": "ABTLWHOULUVAXGTRYU7OC2876QJ2O", + "allow_squash_merge": true, + "allow_auto_merge": false, + "delete_branch_on_merge": true, + "allow_merge_commit": true, + "subscribers_count": 42, + "network_count": 0, + "license": { + "key": "mit", + "name": "MIT License", + "url": "https://api.github.com/licenses/mit", + "spdx_id": "MIT", + "node_id": "MDc6TGljZW5zZW1pdA==", + "html_url": "https://github.com/licenses/mit" + }, + "forks": 1, + "open_issues": 1, + "watchers": 1 + } + }, + "_links": { + "self": { + "href": "https://api.github.com/repos/octocat/Hello-World/pulls/1347" + }, + "html": { + "href": "https://github.com/octocat/Hello-World/pull/1347" + }, + "issue": { + "href": "https://api.github.com/repos/octocat/Hello-World/issues/1347" + }, + "comments": { + "href": "https://api.github.com/repos/octocat/Hello-World/issues/1347/comments" + }, + "review_comments": { + "href": "https://api.github.com/repos/octocat/Hello-World/pulls/1347/comments" + }, + "review_comment": { + "href": "https://api.github.com/repos/octocat/Hello-World/pulls/comments{/number}" + }, + "commits": { + "href": "https://api.github.com/repos/octocat/Hello-World/pulls/1347/commits" + }, + "statuses": { + "href": "https://api.github.com/repos/octocat/Hello-World/statuses/6dcb09b5b57875f334f61aebed695e2e4193db5e" + } + }, + "author_association": "OWNER", + "auto_merge": null, + "draft": false + } +]' +] diff --git a/src/GitHubHealth-Model-Importer-Tests/GithubUsersMock.class.st b/src/GitHubHealth-Model-Importer-Tests/GithubUsersMock.class.st new file mode 100644 index 00000000..85e5cb55 --- /dev/null +++ b/src/GitHubHealth-Model-Importer-Tests/GithubUsersMock.class.st @@ -0,0 +1,43 @@ +Class { + #name : #GithubUsersMock, + #superclass : #Object, + #category : #'GitHubHealth-Model-Importer-Tests' +} + +{ #category : #'as yet unclassified' } +GithubUsersMock >> getUserId: anInteger [ + ^ '{ + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false, + "name": "monalisa octocat", + "company": "GitHub", + "blog": "https://github.com/blog", + "location": "San Francisco", + "email": "octocat@github.com", + "hireable": false, + "bio": "There once was...", + "twitter_username": "monatheoctocat", + "public_repos": 2, + "public_gists": 1, + "followers": 20, + "following": 0, + "created_at": "2008-01-14T04:33:35Z", + "updated_at": "2008-01-14T04:33:35Z" +}' +] diff --git a/src/GitHubHealth-Model-Importer-Tests/package.st b/src/GitHubHealth-Model-Importer-Tests/package.st index 9c0b5b71..5cc38a96 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/GHAPIPipelineOverview.class.st b/src/GitHubHealth-Model-Importer/GHAPIPipelineOverview.class.st index 684778de..a000162d 100644 --- a/src/GitHubHealth-Model-Importer/GHAPIPipelineOverview.class.st +++ b/src/GitHubHealth-Model-Importer/GHAPIPipelineOverview.class.st @@ -3,11 +3,24 @@ Class { #superclass : #Object, #instVars : [ 'total_count', - 'workflow_runs' + 'workflow_runs', + 'jobs' ], #category : #'GitHubHealth-Model-Importer' } +{ #category : #accessing } +GHAPIPipelineOverview >> jobs [ + + ^ jobs +] + +{ #category : #accessing } +GHAPIPipelineOverview >> jobs: anObject [ + + jobs := anObject +] + { #category : #accessing } GHAPIPipelineOverview >> total_count [ diff --git a/src/GitHubHealth-Model-Importer/GHApi.class.st b/src/GitHubHealth-Model-Importer/GHApi.class.st index 7e74616f..b2b13f8d 100644 --- a/src/GitHubHealth-Model-Importer/GHApi.class.st +++ b/src/GitHubHealth-Model-Importer/GHApi.class.st @@ -19,9 +19,17 @@ GHApi class >> isDeprecated [ { #category : #api } GHApi >> actionsRunOfRepo: aRepoName ofOrganization: anOrganizationName [ - ^ self client get: +" ^ self client get: self baseAPIUrl , '/repos/' , anOrganizationName , '/' , aRepoName - , '/actions/runs' + , '/actions/runs'" + + self + deprecated: 'Use self actions getLatestForRepo:ofOwner: instead of current one' + on: '21 august 2025' + in: + 'Pharo-12.0.0+SNAPSHOT.build.1571.sha.cf5fcd22e66957962c97dffc58b0393b7f368147 (64 Bit)'. + + ^ self actions getLatestForRepo: aRepoName ofOwner: anOrganizationName. ] { #category : #accessing } diff --git a/src/GitHubHealth-Model-Importer/GithubModelImporter.class.st b/src/GitHubHealth-Model-Importer/GithubModelImporter.class.st index df6ab9ff..9cedd63d 100644 --- a/src/GitHubHealth-Model-Importer/GithubModelImporter.class.st +++ b/src/GitHubHealth-Model-Importer/GithubModelImporter.class.st @@ -4,7 +4,7 @@ Class { #category : #'GitHubHealth-Model-Importer' } -{ #category : #accessing } +{ #category : #api } GithubModelImporter >> api [ self @@ -16,7 +16,7 @@ GithubModelImporter >> api [ ^ repoApi ] -{ #category : #accessing } +{ #category : #api } GithubModelImporter >> api: anObject [ self @@ -28,7 +28,7 @@ GithubModelImporter >> api: anObject [ repoApi := anObject ] -{ #category : #commit } +{ #category : #'import - commits' } GithubModelImporter >> completeImportedCommit: aGLHCommit [ | result | @@ -61,10 +61,17 @@ GithubModelImporter >> completeImportedCommit: aGLHCommit [ ^ aGLHCommit ] -{ #category : #api } +{ #category : #'import - projects' } GithubModelImporter >> completeImportedProject: aGLHProject [ - self importPipelinesOf: aGLHProject. + ('Complete import of project: ' , aGLHProject id printString) + recordInfo. + aGLHProject repository ifNotNil: [ ^ aGLHProject ]. + + aGLHProject repository: GLHRepository new. + self glhModel add: aGLHProject repository. + + self importPipelinesOfProject: aGLHProject. self importBranchesOf: aGLHProject. self withCommitsSince ifNotNil: [ :withCommitSince | "If not nil, it means we have to import commit" | commits | @@ -72,6 +79,248 @@ GithubModelImporter >> completeImportedProject: aGLHProject [ self chainsCommitsFrom: commits ] ] +{ #category : #'private - configure reader' } +GithubModelImporter >> configureReaderForBranch: reader [ + + super configureReaderForBranch: reader. + + reader for: GLHBranch do: [ :mapping | + mapping + mapProperty: #sha + getter: [ :branch | #ignore ] + setter: [ :branch :value | branch sha: (value at: #sha) ] ] +] + +{ #category : #'private - configure reader' } +GithubModelImporter >> configureReaderForCommit: reader [ + + super configureReaderForCommit: reader. + + 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). + glhCommit authored_date: + (DateAndTime fromString: (value at: #author at: #date)). + glhCommit committed_date: + (DateAndTime fromString: (value at: #committer at: #date)) ]. + + mapping + mapProperty: #author + getter: [ :object | #ignore ] + setter: [ :glhCommit :value | + value ifNotNil: [ + glhCommit author_name: (value at: #login). + value + at: #id + ifPresent: [ :authorId | + glhCommit cacheAt: #authorID put: (value at: #id) ] ] ]. + + mapping + mapProperty: #committer + getter: [ :object | #ignore ] + setter: [ :glhCommit :value | + value ifNotNil: [ glhCommit committer_name: (value at: #login) ] ]. + + (mapping mapInstVar: #parent_ids to: #parents) valueSchema: + #ArrayOfId. + + (mapping mapInstVar: #diffs to: #files) valueSchema: #ArrayOfDiff. + + ]. + + reader for: DateAndTime customDo: [ :mapping | + mapping decoder: [ :string | DateAndTime fromString: string ] ]. + + reader for: #ArrayOfId customDo: [ :mapping | + mapping decoder: [ :parents | + parents collect: [ :parent | parent at: #sha ] ] ] +] + +{ #category : #'private - configure reader' } +GithubModelImporter >> configureReaderForDiff: reader [ + + super configureReaderForDiff: reader. + + reader for: GLHDiff do: [ :mapping | + mapping mapInstVar: #new_path to: #filename. + mapping mapInstVar: #old_path to: #filename. + mapping mapInstVar: #diffString to: #patch. ] +] + +{ #category : #'private - configure reader' } +GithubModelImporter >> configureReaderForGroup: reader [ + + super configureReaderForGroup: reader. + + reader + for: GLHGroup + do: [ :mapping | mapping mapInstVar: #web_url to: #html_url ] +] + +{ #category : #'private - configure reader' } +GithubModelImporter >> configureReaderForIssue: reader [ + + super configureReaderForIssue: reader. + + reader + for: GLHIssue + do: [ :mapping | "mapping mapInstVar: #status to: #conclusion." + (mapping mapInstVar: #created_at) valueSchema: DateAndTime. + (mapping mapInstVar: #updated_at) valueSchema: DateAndTime. + mapping mapInstVar: #name to: #title. + mapping mapInstVar: #description to: #body. + + + mapping + mapProperty: #assignees + getter: [ :object | #ignore ] + setter: [ :issue :values | + values do: [ :item | + issue + cacheAt: #assigneesID + ifPresent: [ :v | v add: (item at: #id) ] + ifAbsentPut: [ + Set new + add: (item at: #id); + yourself ] ] ]. + + + mapping + mapProperty: #user + getter: [ :object | #ignore ] + setter: [ :issue :value | + value ifNotNil: [ + value + at: #id + ifPresent: [ :authorId | + issue cacheAt: #authorID put: (value at: #id) ] ] ] ] +] + +{ #category : #'private - configure reader' } +GithubModelImporter >> configureReaderForJob: reader [ + + super configureReaderForJob: reader. + + reader for: GLHJob do: [ :mapping | + + mapping mapInstVar: #web_url to: #html_url. + + mapping + mapProperty: #pipeline + getter: [ ] + setter: [ :job :rawPipeline | + job cacheAt: #pipelineID put: (rawPipeline at: #head_sha) ]. + + mapping + mapProperty: #commit + getter: [ ] + setter: [ :job :rawCommit | + job cacheAt: #commitID put: (rawCommit at: #id) ]. + + mapping + mapProperty: #completed_at + getter: [ :object | #ignore ] + setter: [ :job :value | + value ifNotNil: [ job cacheAt: #completed_at put: (value asDateAndTime ) ] ]. + + mapping + mapProperty: #started_at + getter: [ :object | #ignore ] + setter: [ :job :value | + value ifNotNil: [ job cacheAt: #started_at put: (value asDateAndTime ) ] ] ] +] + +{ #category : #'private - configure reader' } +GithubModelImporter >> configureReaderForMergeRequest: reader [ + + super configureReaderForMergeRequest: reader. + + reader for: GLHMergeRequest do: [ :mapping | + (mapping mapInstVar: #created_at) valueSchema: DateAndTime. + (mapping mapInstVar: #updated_at) valueSchema: DateAndTime. + (mapping mapInstVar: #merged_at) valueSchema: DateAndTime. + (mapping mapInstVar: #closed_at) valueSchema: DateAndTime. + + mapping + mapProperty: #author + getter: [ ] + setter: [ :object :value | + object cacheAt: #authorID put: (value at: #id) ]. + mapping + mapProperty: #merge_user + getter: [ ] + setter: [ :object :value | + value ifNotNil: [ + object cacheAt: #mergeUserID put: (value at: #id) ] ] ]. + + + +] + +{ #category : #'private - configure reader' } +GithubModelImporter >> configureReaderForPipeline: reader [ + + super configureReaderForPipeline: reader. + + reader + for: GLHPipeline + do: [ :mapping | "mapping mapInstVar: #status to: #conclusion." + + (mapping mapInstVar: #created_at) valueSchema: DateAndTime. + (mapping mapInstVar: #updated_at) valueSchema: DateAndTime. + + mapping + mapProperty: #status + getter: [ :object | #ignore ] + setter: [ :object :value | + (object status isNil and: [ value isNotNil ]) ifTrue: [ + object status: value ] ]. + + mapping + mapProperty: #conclusion + getter: [ :object | #ignore ] + setter: [ :object :value | + (object status isNil and: [ value isNotNil ]) ifTrue: [ + object status: value ] ]. + + mapping + mapProperty: #run_started_at + getter: [ :object | #ignore ] + setter: [ :object :value | + object runDate: (DateAndTime fromString: value) ] ] +] + +{ #category : #'private - configure reader' } +GithubModelImporter >> configureReaderForProject: reader [ + + super configureReaderForProject: reader. + + reader for: GLHProject do: [ :mapping | + mapping mapInstVar: #web_url to: #html_url. + ]. + +] + +{ #category : #'private - configure reader' } +GithubModelImporter >> configureReaderForUser: reader [ + super configureReaderForUser: reader. + + + reader for: GLHUser do: [ :mapping | + mapping mapInstVar: #public_email to: #email. + mapping mapInstVar: #username to: #login. + mapping mapInstVar: #bio to: #bio. + mapping mapInstVar: #organization to: #company. + mapping mapInstVar: #web_url to: #html_url. + ]. +] + { #category : #private } GithubModelImporter >> convertApiFileAsFile: aAPIFile [ @@ -84,35 +333,110 @@ GithubModelImporter >> convertApiFileAsFile: aAPIFile [ yourself ] -{ #category : #api } +{ #category : #'import - groups' } GithubModelImporter >> ensureGroupNamed: aGroupName [ + self flag: 'WARNING: group from different platform (github vs gitlab) can share the same name, thus being confused here'. ^ self glhModel detect: [ :a | (a isKindOf: GLHGroup) and: [ a name = aGroupName ] ] ifNone: [ self glhModel newGroupNamed: aGroupName ] ] -{ #category : #'import - repositories' } -GithubModelImporter >> importBranchesOf: project [ +{ #category : #'import - branches' } +GithubModelImporter >> importBranchesOf: aGLHProject [ + "add the pipeline (actions runs) in the project" + + | branchesResults foundBranches branches | + self + deprecated: 'Use importBranchesOfProject: instead of current one' + on: '26 September 2025' + in: + 'Pharo-12.0.0+SNAPSHOT.build.1571.sha.cf5fcd22e66957962c97dffc58b0393b7f368147 (64 Bit)'. + branchesResults := self repoApi branches + getAllForRepo: aGLHProject name + ofOwner: aGLHProject group name. + + foundBranches := (branchesResults collect: [ :branchesResult | + self parseBranchesResult: branchesResult ]) + flattened. + + + "WARNING: always add branch first into repository, than into model !" + branches := aGLHProject repository branches + addAll: foundBranches + unless: self blockOnNameEquality. + + "branch HEAD commit is not imported by default. use branch ref (sha) to import it specifically" + + branches := self glhModel + addAll: branches + unless: self blockForBranchEquality. + self withFiles ifTrue: [ + branches do: [ :branch | self importFilesOfBranch: branch ] ]. + + ^ branches +] + +{ #category : #'import - repositories' } +GithubModelImporter >> importBranchesOfProject: aGLHProject [ "add the pipeline (actions runs) in the project" - | branchesResult branches repository | - branchesResult := self repoApi - branchesOfRepo: project name - ofOrganization: project group name. - branches := self parseBranchesResult: branchesResult. - self glhModel addAll: branches. - repository := GLHRepository new. - self glhModel add: repository. - project repository: repository. - branches do: [ :branch | - repository addBranch: branch. - self withFiles ifTrue: [ self importFilesOfBranch: branch ] ] + | branchesResults foundBranches branches | + branchesResults := self repoApi branches + getAllForRepo: aGLHProject name + ofOwner: aGLHProject group name. + + foundBranches := (branchesResults collect: [ :branchesResult | + self parseBranchesResult: branchesResult ]) + flattened. + + + "WARNING: always add branch first into repository, than into model !" + branches := aGLHProject repository branches + addAll: foundBranches + unless: self blockOnNameEquality. + + "branch HEAD commit is not imported by default. use branch ref (sha) to import it specifically" + + branches := self glhModel + addAll: branches + unless: self blockForBranchEquality. + + self withFiles ifTrue: [ + branches do: [ :branch | self importFilesOfBranch: branch ] ]. + + ^ branches ] -{ #category : #api } +{ #category : #'import - commits' } +GithubModelImporter >> importCommit: aCommitID ofProject: aGLHProject [ + + | result parsedResult | + (self glhModel allWithType: GLHCommit) asOrderedCollection + detect: [ :commit | commit id = aCommitID ] + ifFound: [ :commit | ^ commit ]. + + result := self repoApi commits + get: aCommitID + inProject: aGLHProject id. + + parsedResult := self parseCommitResult: result. + + parsedResult := self glhModel + add: parsedResult + unless: self blockOnIdEquality. + parsedResult := aGLHProject repository commits + add: parsedResult + unless: self blockOnIdEquality. + + self withCommitDiffs ifTrue: [ self importDiffOfCommit: parsedResult ]. + + ^ parsedResult +] + +{ #category : #'import - commits' } GithubModelImporter >> importCommitsOfProject: aGLHProject [ | itemByPage foundCommits tmp pageNumber | @@ -124,12 +448,13 @@ GithubModelImporter >> importCommitsOfProject: aGLHProject [ , (foundCommits size + itemByPage) printString) recordInfo. "also check that there is at least one commit with the error handling" [ - tmp := self parseCommitsResult: (self repoApi - commitsOfProject: aGLHProject name - ofOrganization: aGLHProject group name - since: self withCommitsSince - perPage: itemByPage - page: pageNumber) ] + tmp := self parseCommitsResult: (self repoApi commits + getForRepo: aGLHProject name + ofOwner: aGLHProject group name + withParms: { + (#since -> self withCommitsSince). + (#perPage -> itemByPage). + (#page -> pageNumber) } asDictionary) ] on: GHRepositoryEmptyError do: [ ^ { } ]. @@ -138,12 +463,13 @@ GithubModelImporter >> importCommitsOfProject: aGLHProject [ pageNumber := pageNumber + 1. ('Extract issues from ' , foundCommits size printString , ' to ' , (foundCommits size + itemByPage) printString) recordInfo. - tmp := self parseCommitsResult: (self repoApi - commitsOfProject: aGLHProject name - ofOrganization: aGLHProject group name - since: self withCommitsSince - perPage: itemByPage - page: pageNumber). + tmp := self parseCommitsResult: (self repoApi commits + getForRepo: aGLHProject name + ofOwner: aGLHProject group name + withParms: { + (#sine -> self withCommitsSince). + (#perPage -> itemByPage). + (#page -> pageNumber) } asDictionary). foundCommits addAll: tmp ]. "add the imported commits (unless they are already added to this repository)" @@ -172,28 +498,56 @@ GithubModelImporter >> importCreatorOfCommit: aGLHCommit [ ^ creator ] -{ #category : #api } +{ #category : #'import - diffs' } GithubModelImporter >> importDiffOfCommit: aGLHCommit [ - | result diffsResult | + | result diffs | aGLHCommit diffs ifNotEmpty: [ 'Diff already importer: ' , aGLHCommit short_id printString recordInfo. ^ aGLHCommit diffs ]. ('Import diff of commit: ' , aGLHCommit short_id printString) recordInfo. - result := self repoApi - commit: aGLHCommit id - ofOrganisation: aGLHCommit repository project group name - ofProject: aGLHCommit repository project name. - diffsResult := self parseDiffresult: result. + + result := self repoApi commits + getCommit: aGLHCommit id + ForRepo: aGLHCommit repository project name + ofOwner: aGLHCommit repository project group name. + + diffs := (self parseCommitResult: result) diffs. + + diffs do: [ :diff | + self parseDiffString: diff. + ]. + + diffs := aGLHCommit diffs + addAll: diffs + unless: self blockForDiffRangeEquality. + glhModel + addAll: diffs + unless: self blockForDiffRangeEquality. ^ aGLHCommit diffs - addAll: diffsResult - unless: self blockForDiffEquality ] -{ #category : #api } +{ #category : #'import - merge-requests' } +GithubModelImporter >> importDiffOfMergeRequest: aGLHMergeRequest [ + |diffsResult| + + diffsResult := self importDiffOfCommit: aGLHMergeRequest mergedCommit. + + diffsResult := aGLHMergeRequest diffs + addAll: diffsResult + unless: self blockForDiffEquality. + self glhModel + addAll: diffsResult + unless: self blockForDiffEquality. + + aGLHMergeRequest diffs do: [ :diff | self importDiffRangesForDiff: diff ]. + ^ aGLHMergeRequest diffs +] + +{ #category : #'import - files' } GithubModelImporter >> importDirectoryFiles: aDirectoryFile OfBranch: aBranch [ | result files apiFiles | @@ -215,7 +569,7 @@ GithubModelImporter >> importDirectoryFiles: aDirectoryFile OfBranch: aBranch [ self importDirectoryFiles: file OfBranch: aBranch ] ] -{ #category : #api } +{ #category : #'import - files' } GithubModelImporter >> importFilesOfBranch: aBranch [ | result files apiFiles | @@ -233,53 +587,254 @@ GithubModelImporter >> importFilesOfBranch: aBranch [ files select: [ :file | file isKindOf: GLHFileDirectory ] thenCollect: [ :file | - self importDirectoryFiles: file OfBranch: aBranch ] + self importDirectoryFiles: file OfBranch: aBranch ]. + ^ files ] -{ #category : #api } +{ #category : #'import - groups' } GithubModelImporter >> importGroup: aGroupName [ | result groupResult | - result := self repoApi organization: aGroupName. + result := self repoApi organizations get: aGroupName. groupResult := self parseGroupResult: result. self glhModel add: groupResult. self importRepositoriesOfGroup: groupResult. ^ groupResult ] -{ #category : #'import - merge request' } -GithubModelImporter >> importMergeRequests: aProject [ - |response mergeRequests| - response := self repoApi - mergeRequestsOfRepo: aProject group name - ofProject: aProject name. - mergeRequests := self parseMergeRequestsResult: response. +{ #category : #'import - issues' } +GithubModelImporter >> importIssuesOfProject: aGLHProject [ + + | results issues foundIssues | + results := self repoApi issues + getAllForRepo: aGLHProject name + ofOwner: aGLHProject group name + withParms: Dictionary new. + foundIssues := (results collect: [ :result | + self parseIssuesResult: result ]) flattened. + + + issues := OrderedCollection new. + issues := foundIssues collect: [ :issue | + + issue author: + (self importUser: (issue cacheAt: #authorID ifAbsent: [ '' ])). + + issue assignees + addAll: + ((issue cacheAt: #assigneesID ifAbsent: [ { } ]) collect: [ + :assigneeID | self importUser: assigneeID ]) + unless: self blockOnIdEquality. + issue. + + ]. + + + issues := aGLHProject issues + addAll: issues + unless: self blockOnIdEquality. + + glhModel addAll: issues unless: self blockOnIdEquality. + + + ^ aGLHProject issues +] + +{ #category : #'import - jobs' } +GithubModelImporter >> importJobsOfPipeline: aGLHPipeline [ + + | result jobs | + result := self repoApi actions + getAllJobsForRun: aGLHPipeline id + forRepo: aGLHPipeline project name + ofOwner: aGLHPipeline project group name. + + jobs := (self parsePipelinesResult: result) jobs. + + jobs do: [ :job | + |stop start| + stop := job cacheAt: #completed_at ifAbsent: [ nil ]. + start := job cacheAt: #started_at ifAbsent: [ nil ]. + job duration: (stop - start) asDuration . + ]. + + jobs := glhModel addAll: jobs unless: self blockOnIdEquality. + aGLHPipeline jobs addAll: jobs unless: self blockOnIdEquality. + + + ^ aGLHPipeline jobs +] + +{ #category : #'import - commits' } +GithubModelImporter >> importLatestCommitsOfProject: aGLHProject [ + "limited to the last 50 commits" + + | results parsedResults | + results := self repoApi commits + getLatestForRepo: aGLHProject name + ofOwner: aGLHProject group name. + parsedResults := self parseCommitsResult: results. + + + parsedResults := self glhModel + addAll: parsedResults + unless: self blockOnIdEquality. + + aGLHProject repository commits + addAll: parsedResults + unless: self blockOnIdEquality. + + self withCommitDiffs ifTrue: [ + parsedResults do: [ :commit | + self importDiffOfCommit: commit. + + ] ]. + + ^ parsedResults +] + +{ #category : #'import - merge-requests' } +GithubModelImporter >> importLatestMergeRequestsOfProject: aGLHProject [ + + | results parsedResults | + results := self repoApi pullRequests getLatestForRepo: aGLHProject name ofOwner: aGLHProject group name. + parsedResults := self parseMergeRequestsResult: results. + + parsedResults := aGLHProject mergeRequests + addAll: parsedResults + unless: self blockOnIdEquality. + parsedResults := glhModel + addAll: parsedResults + unless: self blockOnIdEquality. + ^ parsedResults +] + +{ #category : #'import - merge-requests' } +GithubModelImporter >> importLatestPullRequestsOfProject: aGLHProject [ + "alias method since PullRequest = MergeRequest in model" + ^ self importLatestMergeRequestsOfProject: aGLHProject +] + +{ #category : #'import - merge-requests' } +GithubModelImporter >> importMergeRequestMergeCommits: aGLHMergeRequest [ + + | foundCommits | + foundCommits := OrderedCollection new. + + ('Import commit sha of MR: ' , aGLHMergeRequest iid printString) + recordInfo. + "the founds commits are added to the model during their respective import" + aGLHMergeRequest mergeRequestCommit: ((self + importCommit: aGLHMergeRequest sha + ofProject: aGLHMergeRequest project) ifNotNil: [ :commit | + foundCommits add: commit ]). + + ('Import commit merge_commit_sha of MR: ' + , aGLHMergeRequest iid printString) recordInfo. + aGLHMergeRequest mergedCommit: ((self + importCommit: aGLHMergeRequest merge_commit_sha + ofProject: aGLHMergeRequest project) ifNotNil: [ :commit | + foundCommits add: commit ]). + + ('Import commit squash_commit_sha of MR: ' + , aGLHMergeRequest iid printString) recordInfo. + aGLHMergeRequest squashCommit: ((self + importCommit: aGLHMergeRequest squash_commit_sha + ofProject: aGLHMergeRequest project) ifNotNil: [ :commit | + foundCommits add: commit ]). + + + self chainsCommitsFrom: foundCommits. + ^ foundCommits +] + +{ #category : #'import - merge-requests' } +GithubModelImporter >> importMergeRequestsOfProject: aGLHProject [ + + | response mergeRequests | + response := self repoApi pullRequests + getLatestForRepo: aGLHProject name + ofOwner: aGLHProject group name. + mergeRequests := self parseMergeRequestsResult: response. + + mergeRequests := aGLHProject mergeRequests + addAll: mergeRequests + unless: self blockOnIdEquality. + + "gets it related commits" + aGLHProject mergeRequests do: [ :mr | + self importMergeRequestMergeCommits: mr ]. + + + self withCommitDiffs ifTrue: [ + aGLHProject mergeRequests do: [ :mr | + self importDiffOfMergeRequest: mr ] ]. - mergeRequests := aProject mergeRequests addAll:mergeRequests unless: self blockOnIdEquality. ^ mergeRequests +] + +{ #category : #'import - pipelines' } +GithubModelImporter >> importPipeline: aPipelineId OfProject: aGLHProject [ + + "import specific actions' run " + | reponse result | + aGLHProject pipelines + detect: [ :p | p id = aPipelineId ] + ifFound: [ :p | ^ p ] + ifNone: [ ]. + + reponse := self repoApi actions + getRun: aPipelineId + forRepo: aGLHProject name + ofOwner: aGLHProject group name. + result := self parsePipelineResult: reponse. + + result := self glhModel add: result unless: self blockOnIdEquality. + result := aGLHProject pipelines + add: result + unless: self blockOnIdEquality. + + ^ result +] + +{ #category : #'import - pipelines' } +GithubModelImporter >> importPipelinesOfMergeRequest: aGLHMergeRequest [ + |result pipelines| + result := self repoApi actions getAllRunsForRepo: aGLHMergeRequest project name ofOwner: aGLHMergeRequest project group name withParms: { #event->'pull_request' . #head_sha -> aGLHMergeRequest sha } asDictionary . + + + pipelines := (self parsePipelinesResult: result) workflow_runs . + + pipelines := aGLHMergeRequest project pipelines addAll: pipelines unless: self blockOnIdEquality. + pipelines := glhModel addAll: pipelines unless: self blockOnIdEquality. + pipelines := aGLHMergeRequest pipelines addAll: pipelines unless: self blockOnIdEquality. + + + + ^ pipelines ] -{ #category : #api } -GithubModelImporter >> importPipelinesOf: project [ +{ #category : #'import - pipelines' } +GithubModelImporter >> importPipelinesOfProject: project [ "add the pipeline (actions runs) in the project" | pipelinesResult ghApiPipelineOverview | - pipelinesResult := self repoApi - actionsRunOfRepo: project name - ofOrganization: project group name. + pipelinesResult := self repoApi actions + getLatestForRepo: project name + ofOwner: project group name. ghApiPipelineOverview := self parsePipelinesResult: pipelinesResult. ghApiPipelineOverview workflow_runs do: [ :pipeline | project addPipeline: pipeline ] ] -{ #category : #api } +{ #category : #'import - projects' } GithubModelImporter >> importProject: aProjectName ofGroup: aGroupName [ | result projectResult group | group := self ensureGroupNamed: aGroupName. - result := self repoApi organization: aGroupName repo: aProjectName. + result := self repoApi organizations getRepository: aProjectName ofOrganization: aGroupName . projectResult := self parseProjectResult: result. projectResult group: group. self glhModel add: projectResult. @@ -287,8 +842,16 @@ GithubModelImporter >> importProject: aProjectName ofGroup: aGroupName [ ^ projectResult ] -{ #category : #api } +{ #category : #'import - merge-requests' } +GithubModelImporter >> importPullRequestsOfProject: aProject [ + "alias method since PullRequest = MergeRequest in model" + + ^ self importMergeRequestsOfProject: aProject +] + +{ #category : #'import - groups' } GithubModelImporter >> importRepositoriesOfGroup: groupResult [ + "Github Repository = GLHProject" | reposResult itemByPage pageNumber reposFound tmp | itemByPage := 100. @@ -298,7 +861,7 @@ GithubModelImporter >> importRepositoriesOfGroup: groupResult [ ('Extract commits from ' , reposFound size printString , ' to ' , (reposFound size + itemByPage) printString) recordInfo. tmp := self parseArrayOfProject: (self repoApi - reposOfOrganization: groupResult name + organizations getRepositoriesOfOrganization: groupResult name perPage: itemByPage page: pageNumber). @@ -313,7 +876,7 @@ GithubModelImporter >> importRepositoriesOfGroup: groupResult [ page: pageNumber). reposFound addAll: tmp ]. - reposResult := self repoApi reposOfOrganization: groupResult name. + reposResult := self repoApi organizations getRepositoriesOfOrganization: groupResult name. groupResult projects addAll: reposFound. self glhModel addAll: groupResult projects. groupResult projects do: [ :project | @@ -321,7 +884,7 @@ GithubModelImporter >> importRepositoriesOfGroup: groupResult [ ^ groupResult ] -{ #category : #api } +{ #category : #'import - users' } GithubModelImporter >> importUser: userID [ | result userResult | @@ -329,20 +892,75 @@ GithubModelImporter >> importUser: userID [ detect: [ :user | user id = userID ] ifFound: [ :user | ^ user ]. ('Import user: ' , userID printString) recordInfo. - result := self repoApi user: userID. + result := self repoApi users getUserId: userID. userResult := self parseUserResult: result. ^ glhModel add: userResult unless: [ :current :new | current id = new id ] ] +{ #category : #'import - users' } +GithubModelImporter >> importUserByUsername: anUsername [ + + | dicUsername resultUser | + dicUsername := ((self glhModel allWithType: GLHUser) collect: [ :user | + user username -> user ]) asSet asDictionary. + + dicUsername addAll: self userCatalogue collectUsernames. + + + resultUser := dicUsername + at: anUsername + ifAbsent: [ "thus we have to import this new user" + | userId searchResult | + ('Import user with username: ' + , anUsername printString) recordInfo. + + searchResult := self repoApi users getUsername: anUsername. + + (searchResult class = Dictionary and: [ + (searchResult at: #status) includesSubstring: + '404' ]) + 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 } +GithubModelImporter >> initReader [ + + super initReader. +] + { #category : #initialization } GithubModelImporter >> initialize [ super initialize. - self repoApi: GHApi new. + self repoApi: GithubApi new. self repoApi output: 'json'. - self withCommitDiffs: false. + self withCommitDiffs: true. withFiles := false ] @@ -350,11 +968,13 @@ GithubModelImporter >> initialize [ GithubModelImporter >> parseArrayOfProject: arrayOfProjects [ | reader | - reader := NeoJSONReader on: arrayOfProjects readStream. + " reader := NeoJSONReader on: arrayOfProjects readStream. + reader for: #ArrayOfProjects customDo: [ :customMappting | customMappting listOfElementSchema: GLHProject ]. + reader for: GLHProject do: [ :mapping | mapping mapInstVar: #name to: #name. mapping mapInstVar: #description to: #description. @@ -363,21 +983,30 @@ GithubModelImporter >> parseArrayOfProject: arrayOfProjects [ mapping mapInstVar: #web_url to: #html_url. mapping mapInstVar: #topics to: #topics ]. ^ reader nextAs: #ArrayOfProjects + " + reader := generalReader on: arrayOfProjects readStream. + + ^ reader nextAs: #ArrayOfProject ] { #category : #parsing } GithubModelImporter >> parseBranchesResult: arrayOfBranch [ | reader | - reader := NeoJSONReader on: arrayOfBranch readStream. - reader mapInstVarsFor: GLHBranch. - reader - for: #ArrayOfBranch - customDo: [ :customMappting | - customMappting listOfElementSchema: GLHBranch ]. + reader := generalReader on: arrayOfBranch readStream. + ^ reader nextAs: #ArrayOfBranch ] +{ #category : #parsing } +GithubModelImporter >> parseCommitResult: result [ + | reader | + + reader := generalReader on: result readStream. + + ^ reader nextAs: GLHCommit +] + { #category : #parsing } GithubModelImporter >> parseCommitsResult: result [ @@ -385,54 +1014,7 @@ GithubModelImporter >> parseCommitsResult: result [ (result includesSubstring: '"status":"409"') ifTrue: [ GHRepositoryEmptyError signal: 'Git Repository is empty' ]. - 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). - glhCommit authored_date: - (DateAndTime fromString: (value at: #author at: #date)). - glhCommit committed_date: - (DateAndTime fromString: (value at: #committer at: #date)) ]. - - mapping - mapProperty: #author - getter: [ :object | #ignore ] - setter: [ :glhCommit :value | - 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 | - value ifNotNil: [ 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 ] ]. - - reader for: #ArrayOfIds customDo: [ :mapping | - mapping decoder: [ :parents | - parents collect: [ :parent | parent at: #sha ] ] ]. - - reader - for: #ArrayOfCommit - customDo: [ :customMappting | - customMappting listOfElementSchema: GLHCommit ]. - + reader := generalReader on: result readStream. ^ reader nextAs: #ArrayOfCommit ] @@ -467,15 +1049,17 @@ GithubModelImporter >> parseFileTreeResult: aResult [ GithubModelImporter >> parseGroupResult: aResult [ | reader | - reader := NeoJSONReader on: aResult readStream. - reader for: GLHGroup do: [ :mapping | - mapping mapInstVar: #name to: #login. - mapping mapInstVar: #description to: #description. - mapping mapInstVar: #id to: #id. - mapping mapInstVar: #web_url to: #html_url ]. + reader := generalReader on: aResult readStream. + ^ reader nextAs: GLHGroup ] +{ #category : #parsing } +GithubModelImporter >> parseIssuesResult: result [ + + ^ (generalReader on: result readStream) nextAs: #ArrayOfIssue +] + { #category : #parsing } GithubModelImporter >> parseMergeRequestsResult: response [ @@ -502,29 +1086,29 @@ GithubModelImporter >> parseMergeRequestsResult: response [ ^ result ] +{ #category : #parsing } +GithubModelImporter >> parsePipelineResult: result [ + + | reader | + reader := generalReader on: result readStream. + ^ reader nextAs: GLHPipeline . + +] + { #category : #parsing } GithubModelImporter >> parsePipelinesResult: pipelineOverview [ + "in github, Actions runs (pipeline) are returns in an overview objects" + | reader | - reader := NeoJSONReader on: pipelineOverview readStream. - + reader := generalReader on: pipelineOverview readStream. + reader for: GHAPIPipelineOverview do: [ :mapping | mapping mapInstVar: #total_count to: #total_count. - (mapping mapInstVar: #workflow_runs) valueSchema: #ArrayOfPipelines ]. - - reader - for: #ArrayOfPipelines - customDo: [ :customMappting | - customMappting listOfElementSchema: GLHPipeline ]. - - reader for: GLHPipeline do: [ :mapping | - mapping - mapInstVar: #status to: #conclusion; - mapProperty: #run_started_at - getter: [ :object | #ignore ] - setter: [ :object :value | - object runDate: (DateAndTime fromString: value) ] ]. - + (mapping mapInstVar: #workflow_runs) valueSchema: #ArrayOfPipeline. + (mapping mapInstVar: #jobs) valueSchema: #ArrayOfJob ]. + + ^ reader nextAs: GHAPIPipelineOverview ] @@ -532,14 +1116,9 @@ GithubModelImporter >> parsePipelinesResult: pipelineOverview [ GithubModelImporter >> 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 := generalReader on: aResult readStream. + ^ reader nextAs: GLHProject ] @@ -547,18 +1126,8 @@ GithubModelImporter >> parseProjectResult: aResult [ GithubModelImporter >> 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: #name to: #name. - mapping mapInstVar: #avatar_url to: #avatar_url ]. + reader := generalReader on: result readStream. + ^ reader nextAs: GLHUser ] diff --git a/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st b/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st index a3961e0e..f89adf80 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/GLPHImporterMock.class.st @@ -99,7 +99,7 @@ GLPHImporterMock >> importMergeRequestMergeCommits: aGLHMergeRequest [ ] { #category : #'import - merge request' } -GLPHImporterMock >> importMergeRequests: project since: since until: until [ +GLPHImporterMock >> importMergeRequestsOfProject: project since: since until: until [ self flag: 'Adds MR regardless of their creation date !'. glhModel addAll: mergeRequests . @@ -118,11 +118,16 @@ GLPHImporterMock >> importMergeResquestMerger: mergeRequest [ ] { #category : #'import - notes' } -GLPHImporterMock >> importNotesfromMergeRequest: mriid [ +GLPHImporterMock >> importNotesOfMergeRequest: mriid [ ^OrderedCollection with: (notes select: [ :note | (note noteable_iid == mriid) ]) ] +{ #category : #'as yet unclassified' } +GLPHImporterMock >> importRefCommitOfBranch: aGLHBranch [ + ^ aGLHBranch +] + { #category : #'import - tag' } GLPHImporterMock >> importTagsForProject: aGLHProject [ ^ tags. diff --git a/src/GitLabHealth-Model-Analysis-Tests/GitAnalyzerTest.class.st b/src/GitLabHealth-Model-Analysis-Tests/GitAnalyzerTest.class.st index dc327f93..8743b651 100644 --- a/src/GitLabHealth-Model-Analysis-Tests/GitAnalyzerTest.class.st +++ b/src/GitLabHealth-Model-Analysis-Tests/GitAnalyzerTest.class.st @@ -114,7 +114,7 @@ GitAnalyzerTest >> testAnalyseCommitFrequencySinceUntil [ GitAnalyzerTest >> testAnalyseMergeResquestValidation [ | mergeResquest res | - glhImporter importMergeRequests: projects anyOne. + glhImporter importMergeRequestsOfProject: projects anyOne. mergeResquest := (glhImporter glhModel allWithType: GLHMergeRequest) detect: [ :mr | mr iid = 1 ]. diff --git a/src/GitLabHealth-Model-Analysis/ActiveBranchesProjectMetric.class.st b/src/GitLabHealth-Model-Analysis/ActiveBranchesProjectMetric.class.st index 91054c6b..5777f2c0 100644 --- a/src/GitLabHealth-Model-Analysis/ActiveBranchesProjectMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/ActiveBranchesProjectMetric.class.st @@ -8,27 +8,24 @@ Class { ActiveBranchesProjectMetric >> calculate [ | groupedByDate | - + projectBranches ifNil: [ self load ]. - - projectBranches ifNil:[ self load]. - - - - groupedByDate := self setupGroupedDate. - + "convert group collect to set, to ensure no duplicated data" - groupedByDate keys do: [ :key | groupedByDate at: key put: Set new]. - + groupedByDate keys do: [ :key | groupedByDate at: key put: Set new ]. + projectBranches do: [ :branch | - | dateOver commit| + | dateOver commit | "sort commits by ASC date" - commit := (branch commits sort: [ :c1 :c2 | c1 created_at > c2 created_at]) first. - + commit := (branch commits sort: [ :c1 :c2 | + c1 created_at > c2 created_at ]) first. + dateOver := self transformDate: commit created_at to: over. - groupedByDate at: dateOver printString ifPresent: [ :v | v add: commit created_at ] ]. + groupedByDate + at: dateOver printString + ifPresent: [ :v | v add: commit created_at ] ]. groupedByDate := groupedByDate collect: [ :group | group size ]. diff --git a/src/GitLabHealth-Model-Analysis/CreatedACRPipelineByProject.class.st b/src/GitLabHealth-Model-Analysis/CreatedACRPipelineByProject.class.st index 3b87a077..ef496dcd 100644 --- a/src/GitLabHealth-Model-Analysis/CreatedACRPipelineByProject.class.st +++ b/src/GitLabHealth-Model-Analysis/CreatedACRPipelineByProject.class.st @@ -41,5 +41,5 @@ CreatedACRPipelineByProject >> load [ projectMergeRequests := self loadMergeRequestsSince: (period at: #since) until: (period at: #until) . - projectMergeRequests do: [ :mr | glhImporter importNotesfromMergeRequest: mr ]. + projectMergeRequests do: [ :mr | glhImporter importNotesOfMergeRequest: mr ]. ] diff --git a/src/GitLabHealth-Model-Analysis/CreatedNoteInMergedOrClosedMergeRequest.class.st b/src/GitLabHealth-Model-Analysis/CreatedNoteInMergedOrClosedMergeRequest.class.st index 0b5d4e12..1f190105 100644 --- a/src/GitLabHealth-Model-Analysis/CreatedNoteInMergedOrClosedMergeRequest.class.st +++ b/src/GitLabHealth-Model-Analysis/CreatedNoteInMergedOrClosedMergeRequest.class.st @@ -44,5 +44,5 @@ CreatedNoteInMergedOrClosedMergeRequest >> load [ projectMergeRequests := self loadMergeRequestsSince: (period at: #since) until: (period at: #until) . - projectMergeRequests do: [ :mr | glhImporter importNotesfromMergeRequest: mr ]. + projectMergeRequests do: [ :mr | glhImporter importNotesOfMergeRequest: mr ]. ] diff --git a/src/GitLabHealth-Model-Analysis/CreatedNotesByACRByProjectMetric.class.st b/src/GitLabHealth-Model-Analysis/CreatedNotesByACRByProjectMetric.class.st index 7d1b62b6..42ea9619 100644 --- a/src/GitLabHealth-Model-Analysis/CreatedNotesByACRByProjectMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/CreatedNotesByACRByProjectMetric.class.st @@ -45,5 +45,5 @@ CreatedNotesByACRByProjectMetric >> load [ projectMergeRequests := self loadMergeRequestsSince: (period at: #since) until: (period at: #until) . - projectMergeRequests do: [ :mr | glhImporter importNotesfromMergeRequest: mr ]. + projectMergeRequests do: [ :mr | glhImporter importNotesOfMergeRequest: mr ]. ] diff --git a/src/GitLabHealth-Model-Analysis/ProjectMetric.class.st b/src/GitLabHealth-Model-Analysis/ProjectMetric.class.st index f7fd6daf..a5e2b9de 100644 --- a/src/GitLabHealth-Model-Analysis/ProjectMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/ProjectMetric.class.st @@ -25,11 +25,14 @@ ProjectMetric >> loadAllTags [ ] { #category : #load } -ProjectMetric >> loadBranchesSince: since until: until [ +ProjectMetric >> loadBranchesSince: since until: until [ + | branches | + branches := glhImporter importBranchesOf: project. - ^ glhImporter importBranchesOf: project. - + + branches do: [ :branch | glhImporter importRefCommitOfBranch: branch ]. + ^ branches ] { #category : #loading } @@ -78,7 +81,7 @@ ProjectMetric >> loadMergeRequestsSince: since until: until [ ifAbsentPut: [ | foundMergeRequests | foundMergeRequests := glhImporter - importMergeRequests: + importMergeRequestsOfProject: project since: since until: until. diff --git a/src/GitLabHealth-Model-Analysis/UserMetric.class.st b/src/GitLabHealth-Model-Analysis/UserMetric.class.st index f4257c5a..27c55eb0 100644 --- a/src/GitLabHealth-Model-Analysis/UserMetric.class.st +++ b/src/GitLabHealth-Model-Analysis/UserMetric.class.st @@ -73,7 +73,7 @@ UserMetric >> loadMergeRequestsSince: since until: until [ | mr | project cacheAt: cacheSymbol ifAbsentPut: [ mr := glhImporter - importMergeRequests: project + importMergeRequestsOfProject: project since: since until: until. mr ] ]. diff --git a/src/GitLabHealth-Model-Generator/GLHMetamodelGenerator.class.st b/src/GitLabHealth-Model-Generator/GLHMetamodelGenerator.class.st index d4e52c12..64d64f73 100644 --- a/src/GitLabHealth-Model-Generator/GLHMetamodelGenerator.class.st +++ b/src/GitLabHealth-Model-Generator/GLHMetamodelGenerator.class.st @@ -26,7 +26,8 @@ Class { 'release', 'tag', 'issue', - 'milestone' + 'milestone', + 'tRef' ], #category : #'GitLabHealth-Model-Generator' } @@ -74,7 +75,7 @@ GLHMetamodelGenerator class >> submetamodels [ { #category : #branches } GLHMetamodelGenerator >> branchProperties [ - branch property: #name type: #String + ] { #category : #changes } @@ -213,6 +214,11 @@ GLHMetamodelGenerator >> defineHierarchy [ diff --|> #TNamedEntity. job --|> #TNamedEntity. note --|> #TNamedEntity. + + tRef --|> #TNamedEntity. + tRef <|-- commit . + tRef <|-- branch . + tRef <|-- tag . change --|> #TNamedEntity. change <|-- addition. @@ -246,6 +252,8 @@ GLHMetamodelGenerator >> defineProperties [ self releaseProperties. self issueProperties. self milestoneProperties. + + self tRefProperties. ] { #category : #definition } @@ -284,6 +292,15 @@ GLHMetamodelGenerator >> defineRelations [ self milestoneRelations. ] +{ #category : #definition } +GLHMetamodelGenerator >> defineTraits [ + super defineTraits. + + tRef := builder newTraitNamed: #TRef comment: 'I''m representing a Git reference, that is a reference point in a repository''s history'. + "generate the identity isXXX method (see https://modularmoose.org/developers/create-new-metamodel/#generating-test-method)" + tRef withTesting. +] + { #category : #diffs } GLHMetamodelGenerator >> diffProperties [ @@ -350,10 +367,9 @@ GLHMetamodelGenerator >> issueProperties [ { #category : #issues } GLHMetamodelGenerator >> issueRelations [ - (issue property: #project) *-<> (project property: #issue). + issue *-<> project. (issue property: #assignees) <>-* (user property: #assignedIssue). - (issue property: #author) <>- (user property: #createdIssue). - + (issue property: #author) *-<> (user property: #createdIssue) ] { #category : #jobs } @@ -447,9 +463,9 @@ GLHMetamodelGenerator >> mergeRequestsRelations [ (mergeRequest property: #assignee) *- (user property: #currentlyAssignedMergeRequest). (mergeRequest property: #reviewers) - *-* (user property: #reviewedMergeResquest). + *-* (user property: #reviewedMergeRequest). (mergeRequest property: #pipelines) - <>-* (pipeline property: #mergeResquest). + <>-* (pipeline property: #mergeRequest). (mergeRequest property: #mergedCommit) - (commit property: #commitedMergeRequest). (mergeRequest property: #mergeRequestCommit) @@ -597,10 +613,16 @@ GLHMetamodelGenerator >> releaseRelations [ (release property: #project) *-<> (project property: #releases) ] +{ #category : #'as yet unclassified' } +GLHMetamodelGenerator >> tRefProperties [ + "define the properties of a ref instance" + + tRef property: #sha type: #String. +] + { #category : #tags } GLHMetamodelGenerator >> tagProperties [ - tag property: #name type: #String. tag property: #message type: #String. tag property: #target type: #String. tag property: #protected type: #Boolean. diff --git a/src/GitLabHealth-Model-Importer-Tests/GLHApiMock.class.st b/src/GitLabHealth-Model-Importer-Tests/GLHApiMock.class.st deleted file mode 100644 index c7e073a2..00000000 --- a/src/GitLabHealth-Model-Importer-Tests/GLHApiMock.class.st +++ /dev/null @@ -1,32 +0,0 @@ -Class { - #name : #GLHApiMock, - #superclass : #Object, - #category : #'GitLabHealth-Model-Importer-Tests' -} - -{ #category : #accessing } -GLHApiMock >> commits [ - ^GitlabCommitsMock new. -] - -{ #category : #accessing } -GLHApiMock >> mergeRequests [ - - ^ GitlabMergeRequestsMock new -] - -{ #category : #accessing } -GLHApiMock >> output: aString [ - ^ self -] - -{ #category : #accessing } -GLHApiMock >> repositories [ - - ^ GitlabRepositoryMock new -] - -{ #category : #accessing } -GLHApiMock >> users [ - ^GitlabUsersMock new -] diff --git a/src/GitLabHealth-Model-Importer-Tests/GLPHModelImporterMergeRequestTest.class.st b/src/GitLabHealth-Model-Importer-Tests/GLPHModelImporterMergeRequestTest.class.st index 0824f298..20353f0f 100644 --- a/src/GitLabHealth-Model-Importer-Tests/GLPHModelImporterMergeRequestTest.class.st +++ b/src/GitLabHealth-Model-Importer-Tests/GLPHModelImporterMergeRequestTest.class.st @@ -16,7 +16,7 @@ GLPHModelImporterMergeRequestTest >> setUp [ super setUp. glhImporter := GitlabModelImporter new. - glhImporter repoApi: GLHApiMock new. + glhImporter repoApi: GitlabApiMock new. glhModel := GLHModel new. glhImporter glhModel: glhModel. gitlabMergeData := '[ diff --git a/src/GitLabHealth-Model-Importer-Tests/GitlabApiMock.class.st b/src/GitLabHealth-Model-Importer-Tests/GitlabApiMock.class.st new file mode 100644 index 00000000..257cf853 --- /dev/null +++ b/src/GitLabHealth-Model-Importer-Tests/GitlabApiMock.class.st @@ -0,0 +1,72 @@ +Class { + #name : #GitlabApiMock, + #superclass : #Object, + #category : #'GitLabHealth-Model-Importer-Tests' +} + +{ #category : #accessing } +GitlabApiMock >> branches [ + ^ GitlabBranchesMock new . +] + +{ #category : #accessing } +GitlabApiMock >> commits [ + ^GitlabCommitsMock new. +] + +{ #category : #accessing } +GitlabApiMock >> groups [ + ^ GitlabGroupMock new. +] + +{ #category : #accessing } +GitlabApiMock >> jobs [ + ^ GitlabJobsMock new +] + +{ #category : #accessing } +GitlabApiMock >> mergeRequests [ + + ^ GitlabMergeRequestsMock new +] + +{ #category : #accessing } +GitlabApiMock >> notes [ + ^ GitlabNotesMock new. +] + +{ #category : #accessing } +GitlabApiMock >> output: aString [ + ^ self +] + +{ #category : #accessing } +GitlabApiMock >> pipelines [ + ^ GitlabPipelinesMock new +] + +{ #category : #accessing } +GitlabApiMock >> projects [ + ^ GitlabProjectsMock new . +] + +{ #category : #accessing } +GitlabApiMock >> releases [ + ^ GitlabReleasesMock new. +] + +{ #category : #accessing } +GitlabApiMock >> repositories [ + + ^ GitlabRepositoryMock new +] + +{ #category : #accessing } +GitlabApiMock >> tags [ + ^GitlabTagMock new +] + +{ #category : #accessing } +GitlabApiMock >> users [ + ^GitlabUsersMock new +] diff --git a/src/GitLabHealth-Model-Importer-Tests/GitlabBranchesMock.class.st b/src/GitLabHealth-Model-Importer-Tests/GitlabBranchesMock.class.st new file mode 100644 index 00000000..6c2370aa --- /dev/null +++ b/src/GitLabHealth-Model-Importer-Tests/GitlabBranchesMock.class.st @@ -0,0 +1,40 @@ +Class { + #name : #GitlabBranchesMock, + #superclass : #Object, + #category : #'GitLabHealth-Model-Importer-Tests' +} + +{ #category : #api } +GitlabBranchesMock >> getAllFromProject: anUndefinedObject [ + ^ {'[ + { + "name": "main", + "merged": false, + "protected": true, + "default": true, + "developers_can_push": false, + "developers_can_merge": false, + "can_push": true, + "web_url": "https://gitlab.example.com/my-group/my-project/-/tree/main", + "commit": { + "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c", + "short_id": "7b5c3cc", + "created_at": "2024-06-28T03:44:20-07:00", + "parent_ids": [ + "4ad91d3c1144c406e50c7b33bae684bd6837faf8" + ], + "title": "add projects API", + "message": "add projects API", + "author_name": "John Smith", + "author_email": "john@example.com", + "authored_date": "2024-06-27T05:51:39-07:00", + "committer_name": "John Smith", + "committer_email": "john@example.com", + "committed_date": "2024-06-28T03:44:20-07:00", + "trailers": {}, + "extended_trailers": {}, + "web_url": "https://gitlab.example.com/my-group/my-project/-/commit/7b5c3cc8be40ee161ae89a06bba6229da1032a0c" + } + } +]'} +] diff --git a/src/GitLabHealth-Model-Importer-Tests/GitlabCommitsMock.class.st b/src/GitLabHealth-Model-Importer-Tests/GitlabCommitsMock.class.st index c7f39777..6d58326f 100644 --- a/src/GitLabHealth-Model-Importer-Tests/GitlabCommitsMock.class.st +++ b/src/GitLabHealth-Model-Importer-Tests/GitlabCommitsMock.class.st @@ -6,6 +6,91 @@ Class { { #category : #api } GitlabCommitsMock >> diffOf: commitSha inProject: projectId uniDiff: unidiff [ + commitSha = 'createError' ifTrue: [ - ^ '{"message":"500 Internal Server Error"}' ] + ^ '{"message":"500 Internal Server Error"}' ]. + ^ '[]' +] + +{ #category : #api } +GitlabCommitsMock >> get: aString inProject: anUndefinedObject [ + + ^ '{ + "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", + "short_id": "6104942438c", + "title": "Sanitize for network graph", + "author_name": "randx", + "author_email": "user@example.com", + "committer_name": "Dmitriy", + "committer_email": "user@example.com", + "created_at": "2021-09-20T09:06:12.300+03:00", + "message": "Sanitize for network graph", + "committed_date": "2021-09-20T09:06:12.300+03:00", + "authored_date": "2021-09-20T09:06:12.420+03:00", + "parent_ids": [ + "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" + ], + "last_pipeline": { + "id": 8, + "ref": "main", + "sha": "2dc6aa325a317eda67812f05600bdf0fcdc70ab0", + "status": "created" + }, + "stats": { + "additions": 15, + "deletions": 10, + "total": 25 + }, + "status": "running", + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/6104942438c14ec7bd21c6cd5bd995272b3faff6" +}' +] + +{ #category : #api } +GitlabCommitsMock >> getByPage: anInteger perPage: anInteger2 inProject: anUndefinedObject withParams: aCollection [ + ^ '[ + { + "id": "ed899a2f4b50b4370feeea94676502b42383c746", + "short_id": "ed899a2f4b5", + "title": "Replace sanitize with escape once", + "author_name": "Example User", + "author_email": "user@example.com", + "authored_date": "2021-09-20T11:50:22.001+00:00", + "committer_name": "Administrator", + "committer_email": "admin@example.com", + "committed_date": "2021-09-20T11:50:22.001+00:00", + "created_at": "2021-09-20T11:50:22.001+00:00", + "message": "Replace sanitize with escape once", + "parent_ids": [ + "6104942438c14ec7bd21c6cd5bd995272b3faff6" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746", + "trailers": {}, + "extended_trailers": {} + }, + { + "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", + "short_id": "6104942438c", + "title": "Sanitize for network graph", + "author_name": "randx", + "author_email": "user@example.com", + "committer_name": "ExampleName", + "committer_email": "user@example.com", + "created_at": "2021-09-20T09:06:12.201+00:00", + "message": "Sanitize for network graph\nCc: John Doe \nCc: Jane Doe ", + "parent_ids": [ + "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746", + "trailers": { + "Cc": "Jane Doe " + }, + "extended_trailers": { + "Cc": [ + "John Doe ", + "Jane Doe " + ] + } + } +]' ] diff --git a/src/GitLabHealth-Model-Importer-Tests/GitlabGroupMock.class.st b/src/GitLabHealth-Model-Importer-Tests/GitlabGroupMock.class.st new file mode 100644 index 00000000..b8131d49 --- /dev/null +++ b/src/GitLabHealth-Model-Importer-Tests/GitlabGroupMock.class.st @@ -0,0 +1,183 @@ +Class { + #name : #GitlabGroupMock, + #superclass : #Object, + #category : #'GitLabHealth-Model-Importer-Tests' +} + +{ #category : #api } +GitlabGroupMock >> get: anInteger [ + + ^ '{ + "id": 4, + "name": "Twitter", + "path": "twitter", + "description": "Aliquid qui quis dignissimos distinctio ut commodi voluptas est.", + "visibility": "public", + "avatar_url": null, + "web_url": "https://gitlab.example.com/groups/twitter", + "request_access_enabled": false, + "repository_storage": "default", + "full_name": "Twitter", + "full_path": "twitter", + "runners_token": "ba324ca7b1c77fc20bb9", + "file_template_project_id": 1, + "parent_id": null, + "enabled_git_access_protocol": "all", + "created_at": "2020-01-15T12:36:29.590Z", + "shared_with_groups": [ + { + "group_id": 28, + "group_name": "H5bp", + "group_full_path": "h5bp", + "group_access_level": 20, + "expires_at": null + } + ], + "prevent_sharing_groups_outside_hierarchy": false, + "projects": [ + { + "id": 7, + "description": "Voluptas veniam qui et beatae voluptas doloremque explicabo facilis.", + "default_branch": "main", + "tag_list": [], + "topics": [], + "archived": false, + "visibility": "public", + "ssh_url_to_repo": "git@gitlab.example.com:twitter/typeahead-js.git", + "http_url_to_repo": "https://gitlab.example.com/twitter/typeahead-js.git", + "web_url": "https://gitlab.example.com/twitter/typeahead-js", + "name": "Typeahead.Js", + "name_with_namespace": "Twitter / Typeahead.Js", + "path": "typeahead-js", + "path_with_namespace": "twitter/typeahead-js", + "issues_enabled": true, + "merge_requests_enabled": true, + "wiki_enabled": true, + "jobs_enabled": true, + "snippets_enabled": false, + "container_registry_enabled": true, + "created_at": "2016-06-17T07:47:25.578Z", + "last_activity_at": "2016-06-17T07:47:25.881Z", + "shared_runners_enabled": true, + "creator_id": 1, + "namespace": { + "id": 4, + "name": "Twitter", + "path": "twitter", + "kind": "group" + }, + "avatar_url": null, + "star_count": 0, + "forks_count": 0, + "open_issues_count": 3, + "public_jobs": true, + "shared_with_groups": [], + "request_access_enabled": false + }, + { + "id": 6, + "description": "Aspernatur omnis repudiandae qui voluptatibus eaque.", + "default_branch": "main", + "tag_list": [], + "topics": [], + "archived": false, + "visibility": "internal", + "ssh_url_to_repo": "git@gitlab.example.com:twitter/flight.git", + "http_url_to_repo": "https://gitlab.example.com/twitter/flight.git", + "web_url": "https://gitlab.example.com/twitter/flight", + "name": "Flight", + "name_with_namespace": "Twitter / Flight", + "path": "flight", + "path_with_namespace": "twitter/flight", + "issues_enabled": true, + "merge_requests_enabled": true, + "wiki_enabled": true, + "jobs_enabled": true, + "snippets_enabled": false, + "container_registry_enabled": true, + "created_at": "2016-06-17T07:47:24.661Z", + "last_activity_at": "2016-06-17T07:47:24.838Z", + "shared_runners_enabled": true, + "creator_id": 1, + "namespace": { + "id": 4, + "name": "Twitter", + "path": "twitter", + "kind": "group" + }, + "avatar_url": null, + "star_count": 0, + "forks_count": 0, + "open_issues_count": 8, + "public_jobs": true, + "shared_with_groups": [], + "request_access_enabled": false + } + ], + "shared_projects": [ + { + "id": 8, + "description": "Velit eveniet provident fugiat saepe eligendi autem.", + "default_branch": "main", + "tag_list": [], + "topics": [], + "archived": false, + "visibility": "private", + "ssh_url_to_repo": "git@gitlab.example.com:h5bp/html5-boilerplate.git", + "http_url_to_repo": "https://gitlab.example.com/h5bp/html5-boilerplate.git", + "web_url": "https://gitlab.example.com/h5bp/html5-boilerplate", + "name": "Html5 Boilerplate", + "name_with_namespace": "H5bp / Html5 Boilerplate", + "path": "html5-boilerplate", + "path_with_namespace": "h5bp/html5-boilerplate", + "issues_enabled": true, + "merge_requests_enabled": true, + "wiki_enabled": true, + "jobs_enabled": true, + "snippets_enabled": false, + "container_registry_enabled": true, + "created_at": "2016-06-17T07:47:27.089Z", + "last_activity_at": "2016-06-17T07:47:27.310Z", + "shared_runners_enabled": true, + "creator_id": 1, + "namespace": { + "id": 5, + "name": "H5bp", + "path": "h5bp", + "kind": "group" + }, + "avatar_url": null, + "star_count": 0, + "forks_count": 0, + "open_issues_count": 4, + "public_jobs": true, + "shared_with_groups": [ + { + "group_id": 4, + "group_name": "Twitter", + "group_full_path": "twitter", + "group_access_level": 30, + "expires_at": null + }, + { + "group_id": 3, + "group_name": "Gitlab Org", + "group_full_path": "gitlab-org", + "group_access_level": 10, + "expires_at": "2018-08-14" + } + ] + } + ], + "ip_restriction_ranges": null, + "math_rendering_limits_enabled": true, + "lock_math_rendering_limits_enabled": false +}' +] + +{ #category : #'api - subgroups' } +GitlabGroupMock >> subgroupsOf: anInteger [ + "can't have subgroup otherwise while true block" + ^ { '[ +]' } +] diff --git a/src/GitLabHealth-Model-Importer-Tests/GitlabJobsMock.class.st b/src/GitLabHealth-Model-Importer-Tests/GitlabJobsMock.class.st new file mode 100644 index 00000000..69932059 --- /dev/null +++ b/src/GitLabHealth-Model-Importer-Tests/GitlabJobsMock.class.st @@ -0,0 +1,167 @@ +Class { + #name : #GitlabJobsMock, + #superclass : #Object, + #category : #'GitLabHealth-Model-Importer-Tests' +} + +{ #category : #api } +GitlabJobsMock >> getAllForPipeline: anInteger inProject: anInteger2 [ + + ^ { '[ + { + "commit": { + "author_email": "admin@example.com", + "author_name": "Administrator", + "created_at": "2015-12-24T16:51:14.000+01:00", + "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "message": "Test the CI integration.", + "short_id": "0ff3ae19", + "title": "Test the CI integration." + }, + "coverage": null, + "archived": false, + "source": "push", + "allow_failure": false, + "created_at": "2015-12-24T15:51:21.802Z", + "started_at": "2015-12-24T17:54:27.722Z", + "finished_at": "2015-12-24T17:54:27.895Z", + "erased_at": null, + "duration": 0.173, + "queued_duration": 0.010, + "artifacts_file": { + "filename": "artifacts.zip", + "size": 1000 + }, + "artifacts": [ + {"file_type": "archive", "size": 1000, "filename": "artifacts.zip", "file_format": "zip"}, + {"file_type": "metadata", "size": 186, "filename": "metadata.gz", "file_format": "gzip"}, + {"file_type": "trace", "size": 1500, "filename": "job.log", "file_format": "raw"}, + {"file_type": "junit", "size": 750, "filename": "junit.xml.gz", "file_format": "gzip"} + ], + "artifacts_expire_at": "2016-01-23T17:54:27.895Z", + "tag_list": [ + "docker runner", "ubuntu18" + ], + "id": 7, + "name": "teaspoon", + "pipeline": { + "id": 6, + "project_id": 1, + "ref": "main", + "sha": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "status": "pending" + }, + "ref": "main", + "runner": { + "id": 32, + "description": "", + "ip_address": null, + "active": true, + "paused": false, + "is_shared": true, + "runner_type": "instance_type", + "name": null, + "online": false, + "status": "offline" + }, + "runner_manager": { + "id": 1, + "system_id": "s_89e5e9956577", + "version": "16.11.1", + "revision": "535ced5f", + "platform": "linux", + "architecture": "amd64", + "created_at": "2024-05-01T10:12:02.507Z", + "contacted_at": "2024-05-07T06:30:09.355Z", + "ip_address": "127.0.0.1", + "status": "offline" + }, + "stage": "test", + "status": "failed", + "failure_reason": "script_failure", + "tag": false, + "web_url": "https://example.com/foo/bar/-/jobs/7", + "project": { + "ci_job_token_scope_enabled": false + }, + "user": { + "id": 123, + "name": "Administrator", + "username": "root", + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "web_url": "http://gitlab.dev/root", + "created_at": "2015-12-21T13:14:24.077Z", + "bio": null, + "location": null, + "public_email": "", + "linkedin": "", + "twitter": "", + "website_url": "", + "organization": "" + } + }, + { + "commit": { + "author_email": "admin@example.com", + "author_name": "Administrator", + "created_at": "2015-12-24T16:51:14.000+01:00", + "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "message": "Test the CI integration.", + "short_id": "0ff3ae19", + "title": "Test the CI integration." + }, + "coverage": null, + "archived": false, + "source": "push", + "allow_failure": false, + "created_at": "2015-12-24T15:51:21.727Z", + "started_at": "2015-12-24T17:54:24.729Z", + "finished_at": "2015-12-24T17:54:24.921Z", + "erased_at": null, + "duration": 0.192, + "queued_duration": 0.023, + "artifacts_expire_at": "2016-01-23T17:54:24.921Z", + "tag_list": [ + "docker runner", "win10-2004" + ], + "id": 6, + "name": "rspec:other", + "pipeline": { + "id": 6, + "project_id": 1, + "ref": "main", + "sha": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "status": "pending" + }, + "ref": "main", + "artifacts": [], + "runner": null, + "runner_manager": null, + "stage": "test", + "status": "failed", + "failure_reason": "stuck_or_timeout_failure", + "tag": false, + "web_url": "https://example.com/foo/bar/-/jobs/6", + "project": { + "ci_job_token_scope_enabled": false + }, + "user": { + "id": 123, + "name": "Administrator", + "username": "root", + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "web_url": "http://gitlab.dev/root", + "created_at": "2015-12-21T13:14:24.077Z", + "bio": null, + "location": null, + "public_email": "", + "linkedin": "", + "twitter": "", + "website_url": "", + "organization": "" + } + } +]'} +] diff --git a/src/GitLabHealth-Model-Importer-Tests/GitlabMergeRequestsMock.class.st b/src/GitLabHealth-Model-Importer-Tests/GitlabMergeRequestsMock.class.st index 765237d1..5158ec7b 100644 --- a/src/GitLabHealth-Model-Importer-Tests/GitlabMergeRequestsMock.class.st +++ b/src/GitLabHealth-Model-Importer-Tests/GitlabMergeRequestsMock.class.st @@ -54,3 +54,253 @@ GitlabMergeRequestsMock >> get: id inProject: projectId [ "merge_user":{ "id": 12 } }' ] + +{ #category : #api } +GitlabMergeRequestsMock >> getAllOfProject: anUndefinedObject [ + ^ { '[ + { + "id": 1, + "iid": 1, + "project_id": 3, + "title": "test1", + "description": "fixed login page css paddings", + "state": "merged", + "imported": false, + "imported_from": "none", + "merged_by": { + "id": 87854, + "name": "Douwe Maan", + "username": "DouweM", + "state": "active", + "avatar_url": "https://gitlab.example.com/uploads/-/system/user/avatar/87854/avatar.png", + "web_url": "https://gitlab.com/DouweM" + }, + "merge_user": { + "id": 87854, + "name": "Douwe Maan", + "username": "DouweM", + "state": "active", + "avatar_url": "https://gitlab.example.com/uploads/-/system/user/avatar/87854/avatar.png", + "web_url": "https://gitlab.com/DouweM" + }, + "merged_at": "2018-09-07T11:16:17.520Z", + "merge_after": "2018-09-07T11:16:00.000Z", + "prepared_at": "2018-09-04T11:16:17.520Z", + "closed_by": null, + "closed_at": null, + "created_at": "2017-04-29T08:46:00Z", + "updated_at": "2017-04-29T08:46:00Z", + "target_branch": "main", + "source_branch": "test1", + "upvotes": 0, + "downvotes": 0, + "author": { + "id": 1, + "name": "Administrator", + "username": "admin", + "state": "active", + "avatar_url": null, + "web_url" : "https://gitlab.example.com/admin" + }, + "assignee": { + "id": 1, + "name": "Administrator", + "username": "admin", + "state": "active", + "avatar_url": null, + "web_url" : "https://gitlab.example.com/admin" + }, + "assignees": [{ + "name": "Miss Monserrate Beier", + "username": "axel.block", + "id": 12, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon", + "web_url": "https://gitlab.example.com/axel.block" + }], + "reviewers": [{ + "id": 2, + "name": "Sam Bauch", + "username": "kenyatta_oconnell", + "state": "active", + "avatar_url": "https://www.gravatar.com/avatar/956c92487c6f6f7616b536927e22c9a0?s=80&d=identicon", + "web_url": "http://gitlab.example.com//kenyatta_oconnell" + }], + "source_project_id": 2, + "target_project_id": 3, + "labels": [ + "Community contribution", + "Manage" + ], + "draft": false, + "work_in_progress": false, + "milestone": { + "id": 5, + "iid": 1, + "project_id": 3, + "title": "v2.0", + "description": "Assumenda aut placeat expedita exercitationem labore sunt enim earum.", + "state": "closed", + "created_at": "2015-02-02T19:49:26.013Z", + "updated_at": "2015-02-02T19:49:26.013Z", + "due_date": "2018-09-22", + "start_date": "2018-08-08", + "web_url": "https://gitlab.example.com/my-group/my-project/milestones/1" + }, + "merge_when_pipeline_succeeds": true, + "merge_status": "can_be_merged", + "detailed_merge_status": "not_open", + "sha": "8888888888888888888888888888888888888888", + "merge_commit_sha": null, + "squash_commit_sha": null, + "user_notes_count": 1, + "discussion_locked": null, + "should_remove_source_branch": true, + "force_remove_source_branch": false, + "allow_collaboration": false, + "allow_maintainer_to_push": false, + "web_url": "http://gitlab.example.com/my-group/my-project/merge_requests/1", + "references": { + "short": "!1", + "relative": "my-group/my-project!1", + "full": "my-group/my-project!1" + }, + "time_stats": { + "time_estimate": 0, + "total_time_spent": 0, + "human_time_estimate": null, + "human_total_time_spent": null + }, + "squash": false, + "task_completion_status":{ + "count":0, + "completed_count":0 + } + } +]' } +] + +{ #category : #api } +GitlabMergeRequestsMock >> getByPage: anInteger perPage: anInteger2 inProject: anUndefinedObject [ + ^ '[ + { + "id": 1, + "iid": 1, + "project_id": 3, + "title": "test1", + "description": "fixed login page css paddings", + "state": "merged", + "imported": false, + "imported_from": "none", + "merged_by": { + "id": 87854, + "name": "Douwe Maan", + "username": "DouweM", + "state": "active", + "avatar_url": "https://gitlab.example.com/uploads/-/system/user/avatar/87854/avatar.png", + "web_url": "https://gitlab.com/DouweM" + }, + "merge_user": { + "id": 87854, + "name": "Douwe Maan", + "username": "DouweM", + "state": "active", + "avatar_url": "https://gitlab.example.com/uploads/-/system/user/avatar/87854/avatar.png", + "web_url": "https://gitlab.com/DouweM" + }, + "merged_at": "2018-09-07T11:16:17.520Z", + "merge_after": "2018-09-07T11:16:00.000Z", + "prepared_at": "2018-09-04T11:16:17.520Z", + "closed_by": null, + "closed_at": null, + "created_at": "2017-04-29T08:46:00Z", + "updated_at": "2017-04-29T08:46:00Z", + "target_branch": "main", + "source_branch": "test1", + "upvotes": 0, + "downvotes": 0, + "author": { + "id": 1, + "name": "Administrator", + "username": "admin", + "state": "active", + "avatar_url": null, + "web_url" : "https://gitlab.example.com/admin" + }, + "assignee": { + "id": 1, + "name": "Administrator", + "username": "admin", + "state": "active", + "avatar_url": null, + "web_url" : "https://gitlab.example.com/admin" + }, + "assignees": [{ + "name": "Miss Monserrate Beier", + "username": "axel.block", + "id": 12, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon", + "web_url": "https://gitlab.example.com/axel.block" + }], + "reviewers": [{ + "id": 2, + "name": "Sam Bauch", + "username": "kenyatta_oconnell", + "state": "active", + "avatar_url": "https://www.gravatar.com/avatar/956c92487c6f6f7616b536927e22c9a0?s=80&d=identicon", + "web_url": "http://gitlab.example.com//kenyatta_oconnell" + }], + "source_project_id": 2, + "target_project_id": 3, + "labels": [ + "Community contribution", + "Manage" + ], + "draft": false, + "work_in_progress": false, + "milestone": { + "id": 5, + "iid": 1, + "project_id": 3, + "title": "v2.0", + "description": "Assumenda aut placeat expedita exercitationem labore sunt enim earum.", + "state": "closed", + "created_at": "2015-02-02T19:49:26.013Z", + "updated_at": "2015-02-02T19:49:26.013Z", + "due_date": "2018-09-22", + "start_date": "2018-08-08", + "web_url": "https://gitlab.example.com/my-group/my-project/milestones/1" + }, + "merge_when_pipeline_succeeds": true, + "merge_status": "can_be_merged", + "detailed_merge_status": "not_open", + "sha": "8888888888888888888888888888888888888888", + "merge_commit_sha": null, + "squash_commit_sha": null, + "user_notes_count": 1, + "discussion_locked": null, + "should_remove_source_branch": true, + "force_remove_source_branch": false, + "allow_collaboration": false, + "allow_maintainer_to_push": false, + "web_url": "http://gitlab.example.com/my-group/my-project/merge_requests/1", + "references": { + "short": "!1", + "relative": "my-group/my-project!1", + "full": "my-group/my-project!1" + }, + "time_stats": { + "time_estimate": 0, + "total_time_spent": 0, + "human_time_estimate": null, + "human_total_time_spent": null + }, + "squash": false, + "task_completion_status":{ + "count":0, + "completed_count":0 + } + } +]' +] diff --git a/src/GitLabHealth-Model-Importer-Tests/GitlabModelImporterRemoteTest.class.st b/src/GitLabHealth-Model-Importer-Tests/GitlabModelImporterRemoteTest.class.st index 9e02b794..1764e285 100644 --- a/src/GitLabHealth-Model-Importer-Tests/GitlabModelImporterRemoteTest.class.st +++ b/src/GitLabHealth-Model-Importer-Tests/GitlabModelImporterRemoteTest.class.st @@ -67,7 +67,7 @@ GitlabModelImporterRemoteTest >> testImportCommits [ | projectTestCodeChurn | projectTestCodeChurn := (self model allWithType: GLHProject) detect: [ :project | project id = 57841283 ]. - self glhImporter importLastestCommitsOfProject: projectTestCodeChurn. + self glhImporter importLatestCommitsOfProject: projectTestCodeChurn. self assert: projectTestCodeChurn repository commits last author_name diff --git a/src/GitLabHealth-Model-Importer-Tests/GitlabModelImporterTest.class.st b/src/GitLabHealth-Model-Importer-Tests/GitlabModelImporterTest.class.st index 353f1704..1aaa0ef7 100644 --- a/src/GitLabHealth-Model-Importer-Tests/GitlabModelImporterTest.class.st +++ b/src/GitLabHealth-Model-Importer-Tests/GitlabModelImporterTest.class.st @@ -4,31 +4,224 @@ The test suite for `GLHModelImporter` but not using remote API Class { #name : #GitlabModelImporterTest, #superclass : #TestCase, + #traits : 'TGitModelImporterTest', + #classTraits : 'TGitModelImporterTest classTrait', #instVars : [ - 'importer', - 'model', 'diffs' ], #category : #'GitLabHealth-Model-Importer-Tests' } -{ #category : #test } +{ #category : #json } GitlabModelImporterTest >> gitlabDiffData [ ^ '[{"b_mode":"100644","diff":"@@ -80,5 +80,10 @@ test test test {\r test test test(@test test[] test) test test, test {\r \ttest test(test.test(test), test.test_test, test);\r }\r+ \r+ @test(\"/testAvisMandtestement\")\r+ test test testAvisMandtestement(@test test[] test) test test, test {\r+ \ttest test(test.testAvisMandtestement(test), test.test_test, test);\r+ }\r \r }\r\\ test test test test test test\r","new_path":"@@ -80,5 +80,10 @@ test test test {\r test test test(@test test[] test) test test, test {\r \ttest test(test.test(test), test.test_test, test);\r }\r+ \r+ @test(\"/testAvisMandtestement\")\r+ test test testAvisMandtestement(@test test[] test) test test, test {\r+ \ttest test(test.testAvisMandtestement(test), test.test_test, test);\r+ }\r \r }\r\\ test test test test test test\r","a_mode":"100644","old_path":"@@ -80,5 +80,10 @@ test test test {\r test test test(@test test[] test) test test, test {\r \ttest test(test.test(test), test.test_test, test);\r }\r+ \r+ @test(\"/testAvisMandtestement\")\r+ test test testAvisMandtestement(@test test[] test) test test, test {\r+ \ttest test(test.testAvisMandtestement(test), test.test_test, test);\r+ }\r \r }\r\\ test test test test test test\r","new_file":false,"deleted_file":false,"renamed_file":false},{"b_mode":"100644","diff":"@@ -11,6 +11,7 @@ import org.springframework.stereotype.Service;\n import fr.bl.avenir.gf.rest.ecompta.edition.enums.TypeBordereauVolet;\n import fr.bl.avenir.gf.rest.ecompta.edition.enums.TypeReportEnumeration;\n import fr.bl.avenir.gf.rest.ecompta.edition.service.avis.ServiceImprimerAvis;\n+import fr.bl.avenir.gf.rest.ecompta.edition.service.avismandatement.ServiceImprimerAvisMandatement;\n import fr.bl.avenir.gf.rest.ecompta.edition.service.bordereau.ServiceImprimerBordereauMandat;\n import fr.bl.avenir.gf.rest.ecompta.edition.service.bordereau.ServiceImprimerBordereauTitre;\n import fr.magnus.reftechnique.transverse.EntiteRelationnelle;\n@@ -26,12 +27,12 @@ public class EditionService {\n \n @Autowired\n ServiceImprimerBordereauMandat serviceImprimerBordereauMandat;\n- \n @Autowired\n ServiceImprimerBordereauTitre serviceImprimerBordereauTitre;\n- \n @Autowired\n ServiceImprimerAvis serviceImprimerAvis;\n+ @Autowired\n+ ServiceImprimerAvis serviceImprimerAvisMandatement;\n \n public byte[] imprimerBordereauMandatVolet1( TableauAbstract[] jsonData) throws JRException, ParseException {\n Map params = new HashMap<>();\n@@ -85,6 +86,10 @@ public class EditionService {\n \treturn serviceImprimerAvis.imprimerFichier(jsonData, params, TypeReportEnumeration.AVIS_SOMMES_A_PAYER_SANS_EXP);\n }\n \t\n- \n+ public byte[] imprimerAvisMandatement(TableauAbstract[] jsonData) throws JRException, ParseException {\n+ \treturn serviceImprimerAvisMandatement.imprimerFichier(jsonData, null, TypeReportEnumeration.AVIS_MANDATEMENT);\n+ }\n+ \n+ \n \n }\n\\ No newline at end of file\n","new_path":"@@ -11,6 +11,7 @@ import org.springframework.stereotype.Service;\n import fr.bl.avenir.gf.rest.ecompta.edition.enums.TypeBordereauVolet;\n import fr.bl.avenir.gf.rest.ecompta.edition.enums.TypeReportEnumeration;\n import fr.bl.avenir.gf.rest.ecompta.edition.service.avis.ServiceImprimerAvis;\n+import fr.bl.avenir.gf.rest.ecompta.edition.service.avismandatement.ServiceImprimerAvisMandatement;\n import fr.bl.avenir.gf.rest.ecompta.edition.service.bordereau.ServiceImprimerBordereauMandat;\n import fr.bl.avenir.gf.rest.ecompta.edition.service.bordereau.ServiceImprimerBordereauTitre;\n import fr.magnus.reftechnique.transverse.EntiteRelationnelle;\n@@ -26,12 +27,12 @@ public class EditionService {\n \n @Autowired\n ServiceImprimerBordereauMandat serviceImprimerBordereauMandat;\n- \n @Autowired\n ServiceImprimerBordereauTitre serviceImprimerBordereauTitre;\n- \n @Autowired\n ServiceImprimerAvis serviceImprimerAvis;\n+ @Autowired\n+ ServiceImprimerAvis serviceImprimerAvisMandatement;\n \n public byte[] imprimerBordereauMandatVolet1( TableauAbstract[] jsonData) throws JRException, ParseException {\n Map params = new HashMap<>();\n@@ -85,6 +86,10 @@ public class EditionService {\n \treturn serviceImprimerAvis.imprimerFichier(jsonData, params, TypeReportEnumeration.AVIS_SOMMES_A_PAYER_SANS_EXP);\n }\n \t\n- \n+ public byte[] imprimerAvisMandatement(TableauAbstract[] jsonData) throws JRException, ParseException {\n+ \treturn serviceImprimerAvisMandatement.imprimerFichier(jsonData, null, TypeReportEnumeration.AVIS_MANDATEMENT);\n+ }\n+ \n+ \n \n }\n\\ No newline at end of file\n","a_mode":"100644","old_path":"@@ -11,6 +11,7 @@ import org.springframework.stereotype.Service;\n import fr.bl.avenir.gf.rest.ecompta.edition.enums.TypeBordereauVolet;\n import fr.bl.avenir.gf.rest.ecompta.edition.enums.TypeReportEnumeration;\n import fr.bl.avenir.gf.rest.ecompta.edition.service.avis.ServiceImprimerAvis;\n+import fr.bl.avenir.gf.rest.ecompta.edition.service.avismandatement.ServiceImprimerAvisMandatement;\n import fr.bl.avenir.gf.rest.ecompta.edition.service.bordereau.ServiceImprimerBordereauMandat;\n import fr.bl.avenir.gf.rest.ecompta.edition.service.bordereau.ServiceImprimerBordereauTitre;\n import fr.magnus.reftechnique.transverse.EntiteRelationnelle;\n@@ -26,12 +27,12 @@ public class EditionService {\n \n @Autowired\n ServiceImprimerBordereauMandat serviceImprimerBordereauMandat;\n- \n @Autowired\n ServiceImprimerBordereauTitre serviceImprimerBordereauTitre;\n- \n @Autowired\n ServiceImprimerAvis serviceImprimerAvis;\n+ @Autowired\n+ ServiceImprimerAvis serviceImprimerAvisMandatement;\n \n public byte[] imprimerBordereauMandatVolet1( TableauAbstract[] jsonData) throws JRException, ParseException {\n Map params = new HashMap<>();\n@@ -85,6 +86,10 @@ public class EditionService {\n \treturn serviceImprimerAvis.imprimerFichier(jsonData, params, TypeReportEnumeration.AVIS_SOMMES_A_PAYER_SANS_EXP);\n }\n \t\n- \n+ public byte[] imprimerAvisMandatement(TableauAbstract[] jsonData) throws JRException, ParseException {\n+ \treturn serviceImprimerAvisMandatement.imprimerFichier(jsonData, null, TypeReportEnumeration.AVIS_MANDATEMENT);\n+ }\n+ \n+ \n \n }\n\\ No newline at end of file\n","new_file":false,"deleted_file":false,"renamed_file":false},{"b_mode":"100644","diff":"@@ -0,0 +1,25 @@\n+package fr.bl.avenir.gf.rest.ecompta.edition.dto.avismandatement;\n+\n+import lombok.Getter;\n+import lombok.NoArgsConstructor;\n+import lombok.Setter;\n+\n+@NoArgsConstructor\n+@Getter\n+@Setter\n+public class DTOAvisMandatement {\n+\tprivate String collectiviteLogo;\n+\tprivate String collectiviteNom;\n+\tprivate String collectiviteAdresse;\n+\tprivate String collectiviteSignataire;\n+\tprivate String collectiviteSignature;\n+\tprivate String collectiviteTampon;\n+\tprivate String tiersNom;\n+\tprivate String tiersAdresse;\n+\tprivate String texteCourrier;\n+\tprivate String pieceJustificative;\n+\tprivate String pieceJustificativePjIdUnique;\n+\tprivate String observation;\n+\tprivate String comptableAssignataire;\n+\tprivate String contexte;\n+}\n","new_path":"@@ -0,0 +1,25 @@\n+package fr.bl.avenir.gf.rest.ecompta.edition.dto.avismandatement;\n+\n+import lombok.Getter;\n+import lombok.NoArgsConstructor;\n+import lombok.Setter;\n+\n+@NoArgsConstructor\n+@Getter\n+@Setter\n+public class DTOAvisMandatement {\n+\tprivate String collectiviteLogo;\n+\tprivate String collectiviteNom;\n+\tprivate String collectiviteAdresse;\n+\tprivate String collectiviteSignataire;\n+\tprivate String collectiviteSignature;\n+\tprivate String collectiviteTampon;\n+\tprivate String tiersNom;\n+\tprivate String tiersAdresse;\n+\tprivate String texteCourrier;\n+\tprivate String pieceJustificative;\n+\tprivate String pieceJustificativePjIdUnique;\n+\tprivate String observation;\n+\tprivate String comptableAssignataire;\n+\tprivate String contexte;\n+}\n","a_mode":"0","old_path":"@@ -0,0 +1,25 @@\n+package fr.bl.avenir.gf.rest.ecompta.edition.dto.avismandatement;\n+\n+import lombok.Getter;\n+import lombok.NoArgsConstructor;\n+import lombok.Setter;\n+\n+@NoArgsConstructor\n+@Getter\n+@Setter\n+public class DTOAvisMandatement {\n+\tprivate String collectiviteLogo;\n+\tprivate String collectiviteNom;\n+\tprivate String collectiviteAdresse;\n+\tprivate String collectiviteSignataire;\n+\tprivate String collectiviteSignature;\n+\tprivate String collectiviteTampon;\n+\tprivate String tiersNom;\n+\tprivate String tiersAdresse;\n+\tprivate String texteCourrier;\n+\tprivate String pieceJustificative;\n+\tprivate String pieceJustificativePjIdUnique;\n+\tprivate String observation;\n+\tprivate String comptableAssignataire;\n+\tprivate String contexte;\n+}\n","new_file":true,"deleted_file":false,"renamed_file":false},{"b_mode":"100644","diff":"@@ -34,7 +34,6 @@ public class TypeReportEnumeration extends EnumerationAbstract {\n public static final TypeReportEnumeration TITRE_VOLET2 = new TypeReportEnumeration(6, \"Bordereau de titres Volet 2\", JASPER_REPORT_BORDEREAU_TITRE);\n public static final TypeReportEnumeration TITRE_VOLET3 = new TypeReportEnumeration(7, \"Bordereau de titres Volet 3\", JASPER_REPORT_BORDEREAU_TITRE);\n public static final TypeReportEnumeration TITRE = new TypeReportEnumeration(8, \"Bordereau de titres\", JASPER_REPORT_BORDEREAU_TITRE);\n- private JasperReport jasperReport;\n \n \t// --- AVIS\n private static final String JASPER_AVIS_REPOSITORY = \"/jasper/avis/\";\n@@ -44,7 +43,13 @@ public class TypeReportEnumeration extends EnumerationAbstract {\n public static final TypeReportEnumeration AVIS_SOMMES_A_PAYER = new TypeReportEnumeration(9, \"Avis des sommes à payer\", JASPER_REPORT_AVIS);\n public static final TypeReportEnumeration AVIS_SOMMES_A_PAYER_SANS_EXP = new TypeReportEnumeration(10, \"Avis des sommes à payer sans expéditeur\", JASPER_REPORT_AVIS);\n \n+ // --- AVIS MANDATEMENT\n+ private static final String JASPER_AVIS_MANDATEMENT_REPOSITORY = \"/jasper/avismandatement/\";\n+ private static final String[] JASPER_AVIS_MANDATEMENT_REPORTS = new String[] {\"avisMandatement.jrxml\"};\n+ private static final JasperReport JASPER_REPORT_AVIS_MANDATEMENT = getJasperReport(JASPER_AVIS_MANDATEMENT_REPOSITORY, JASPER_AVIS_MANDATEMENT_REPORTS);\n+ public static final TypeReportEnumeration AVIS_MANDATEMENT= new TypeReportEnumeration(9, \"Avis mandatement\", JASPER_REPORT_AVIS_MANDATEMENT);\n \n+ private JasperReport jasperReport;\n public JasperReport getJasperReport() {\n return jasperReport;\n }\n","new_path":"@@ -34,7 +34,6 @@ public class TypeReportEnumeration extends EnumerationAbstract {\n public static final TypeReportEnumeration TITRE_VOLET2 = new TypeReportEnumeration(6, \"Bordereau de titres Volet 2\", JASPER_REPORT_BORDEREAU_TITRE);\n public static final TypeReportEnumeration TITRE_VOLET3 = new TypeReportEnumeration(7, \"Bordereau de titres Volet 3\", JASPER_REPORT_BORDEREAU_TITRE);\n public static final TypeReportEnumeration TITRE = new TypeReportEnumeration(8, \"Bordereau de titres\", JASPER_REPORT_BORDEREAU_TITRE);\n- private JasperReport jasperReport;\n \n \t// --- AVIS\n private static final String JASPER_AVIS_REPOSITORY = \"/jasper/avis/\";\n@@ -44,7 +43,13 @@ public class TypeReportEnumeration extends EnumerationAbstract {\n public static final TypeReportEnumeration AVIS_SOMMES_A_PAYER = new TypeReportEnumeration(9, \"Avis des sommes à payer\", JASPER_REPORT_AVIS);\n public static final TypeReportEnumeration AVIS_SOMMES_A_PAYER_SANS_EXP = new TypeReportEnumeration(10, \"Avis des sommes à payer sans expéditeur\", JASPER_REPORT_AVIS);\n \n+ // --- AVIS MANDATEMENT\n+ private static final String JASPER_AVIS_MANDATEMENT_REPOSITORY = \"/jasper/avismandatement/\";\n+ private static final String[] JASPER_AVIS_MANDATEMENT_REPORTS = new String[] {\"avisMandatement.jrxml\"};\n+ private static final JasperReport JASPER_REPORT_AVIS_MANDATEMENT = getJasperReport(JASPER_AVIS_MANDATEMENT_REPOSITORY, JASPER_AVIS_MANDATEMENT_REPORTS);\n+ public static final TypeReportEnumeration AVIS_MANDATEMENT= new TypeReportEnumeration(9, \"Avis mandatement\", JASPER_REPORT_AVIS_MANDATEMENT);\n \n+ private JasperReport jasperReport;\n public JasperReport getJasperReport() {\n return jasperReport;\n }\n","a_mode":"100644","old_path":"@@ -34,7 +34,6 @@ public class TypeReportEnumeration extends EnumerationAbstract {\n public static final TypeReportEnumeration TITRE_VOLET2 = new TypeReportEnumeration(6, \"Bordereau de titres Volet 2\", JASPER_REPORT_BORDEREAU_TITRE);\n public static final TypeReportEnumeration TITRE_VOLET3 = new TypeReportEnumeration(7, \"Bordereau de titres Volet 3\", JASPER_REPORT_BORDEREAU_TITRE);\n public static final TypeReportEnumeration TITRE = new TypeReportEnumeration(8, \"Bordereau de titres\", JASPER_REPORT_BORDEREAU_TITRE);\n- private JasperReport jasperReport;\n \n \t// --- AVIS\n private static final String JASPER_AVIS_REPOSITORY = \"/jasper/avis/\";\n@@ -44,7 +43,13 @@ public class TypeReportEnumeration extends EnumerationAbstract {\n public static final TypeReportEnumeration AVIS_SOMMES_A_PAYER = new TypeReportEnumeration(9, \"Avis des sommes à payer\", JASPER_REPORT_AVIS);\n public static final TypeReportEnumeration AVIS_SOMMES_A_PAYER_SANS_EXP = new TypeReportEnumeration(10, \"Avis des sommes à payer sans expéditeur\", JASPER_REPORT_AVIS);\n \n+ // --- AVIS MANDATEMENT\n+ private static final String JASPER_AVIS_MANDATEMENT_REPOSITORY = \"/jasper/avismandatement/\";\n+ private static final String[] JASPER_AVIS_MANDATEMENT_REPORTS = new String[] {\"avisMandatement.jrxml\"};\n+ private static final JasperReport JASPER_REPORT_AVIS_MANDATEMENT = getJasperReport(JASPER_AVIS_MANDATEMENT_REPOSITORY, JASPER_AVIS_MANDATEMENT_REPORTS);\n+ public static final TypeReportEnumeration AVIS_MANDATEMENT= new TypeReportEnumeration(9, \"Avis mandatement\", JASPER_REPORT_AVIS_MANDATEMENT);\n \n+ private JasperReport jasperReport;\n public JasperReport getJasperReport() {\n return jasperReport;\n }\n","new_file":false,"deleted_file":false,"renamed_file":false},{"b_mode":"100644","diff":"@@ -0,0 +1,7 @@\n+package fr.bl.avenir.gf.rest.ecompta.edition.service.avismandatement;\n+\n+import fr.bl.avenir.gf.rest.ecompta.edition.service.ServiceImprimer;\n+\n+public interface ServiceImprimerAvisMandatement extends ServiceImprimer {\n+\t\n+}\n","new_path":"@@ -0,0 +1,7 @@\n+package fr.bl.avenir.gf.rest.ecompta.edition.service.avismandatement;\n+\n+import fr.bl.avenir.gf.rest.ecompta.edition.service.ServiceImprimer;\n+\n+public interface ServiceImprimerAvisMandatement extends ServiceImprimer {\n+\t\n+}\n","a_mode":"0","old_path":"@@ -0,0 +1,7 @@\n+package fr.bl.avenir.gf.rest.ecompta.edition.service.avismandatement;\n+\n+import fr.bl.avenir.gf.rest.ecompta.edition.service.ServiceImprimer;\n+\n+public interface ServiceImprimerAvisMandatement extends ServiceImprimer {\n+\t\n+}\n","new_file":true,"deleted_file":false,"renamed_file":false},{"b_mode":"100644","diff":"@@ -0,0 +1,33 @@\n+package fr.bl.avenir.gf.rest.ecompta.edition.service.avismandatement.impl;\n+\n+import java.text.ParseException;\n+import java.util.List;\n+import java.util.Map;\n+\n+import org.springframework.stereotype.Service;\n+\n+import fr.bl.avenir.gf.rest.ecompta.edition.dto.avismandatement.DTOAvisMandatement;\n+import fr.bl.avenir.gf.rest.ecompta.edition.service.avismandatement.ServiceImprimerAvisMandatement;\n+import fr.bl.avenir.gf.rest.ecompta.edition.service.impl.ServiceImprimerImpl;\n+import fr.magnus.reftechnique.transverse.EntiteRelationnelle;\n+import fr.magnus.reftechnique.transverse.tableau.TableauAbstract;\n+\n+@Service(\"ServiceImprimerAvisMandatement\")\n+public class ServiceImprimerAvisMandatementImpl extends ServiceImprimerImpl implements ServiceImprimerAvisMandatement{\n+\n+ @Override\n+\tpublic List getListDonnee(TableauAbstract[] tableauEntiteRelationnelles, Map params) throws ParseException {\n+\n+ List dtoAvisMandatementList = null;\n+ \n+ if (tableauEntiteRelationnelles!= null && tableauEntiteRelationnelles.length == 2) {\n+ TableauAbstract tabDonnee = tableauEntiteRelationnelles[0];\n+// Collections.sort(dtoAvisMandatementList, Comparator.comparing(DTOAvis::getBordereauNumero)\n+// .thenComparing(DTOAvis::getTitreNumeroPiece)\n+// .thenComparing(DTOAvis::getTiers1)\n+// \t.thenComparing(DTOAvis::getImputationComplete));\n+ }\n+ return dtoAvisMandatementList;\t\t\n+\t}\n+\n+}\n","new_path":"@@ -0,0 +1,33 @@\n+package fr.bl.avenir.gf.rest.ecompta.edition.service.avismandatement.impl;\n+\n+import java.text.ParseException;\n+import java.util.List;\n+import java.util.Map;\n+\n+import org.springframework.stereotype.Service;\n+\n+import fr.bl.avenir.gf.rest.ecompta.edition.dto.avismandatement.DTOAvisMandatement;\n+import fr.bl.avenir.gf.rest.ecompta.edition.service.avismandatement.ServiceImprimerAvisMandatement;\n+import fr.bl.avenir.gf.rest.ecompta.edition.service.impl.ServiceImprimerImpl;\n+import fr.magnus.reftechnique.transverse.EntiteRelationnelle;\n+import fr.magnus.reftechnique.transverse.tableau.TableauAbstract;\n+\n+@Service(\"ServiceImprimerAvisMandatement\")\n+public class ServiceImprimerAvisMandatementImpl extends ServiceImprimerImpl implements ServiceImprimerAvisMandatement{\n+\n+ @Override\n+\tpublic List getListDonnee(TableauAbstract[] tableauEntiteRelationnelles, Map params) throws ParseException {\n+\n+ List dtoAvisMandatementList = null;\n+ \n+ if (tableauEntiteRelationnelles!= null && tableauEntiteRelationnelles.length == 2) {\n+ TableauAbstract tabDonnee = tableauEntiteRelationnelles[0];\n+// Collections.sort(dtoAvisMandatementList, Comparator.comparing(DTOAvis::getBordereauNumero)\n+// .thenComparing(DTOAvis::getTitreNumeroPiece)\n+// .thenComparing(DTOAvis::getTiers1)\n+// \t.thenComparing(DTOAvis::getImputationComplete));\n+ }\n+ return dtoAvisMandatementList;\t\t\n+\t}\n+\n+}\n","a_mode":"0","old_path":"@@ -0,0 +1,33 @@\n+package fr.bl.avenir.gf.rest.ecompta.edition.service.avismandatement.impl;\n+\n+import java.text.ParseException;\n+import java.util.List;\n+import java.util.Map;\n+\n+import org.springframework.stereotype.Service;\n+\n+import fr.bl.avenir.gf.rest.ecompta.edition.dto.avismandatement.DTOAvisMandatement;\n+import fr.bl.avenir.gf.rest.ecompta.edition.service.avismandatement.ServiceImprimerAvisMandatement;\n+import fr.bl.avenir.gf.rest.ecompta.edition.service.impl.ServiceImprimerImpl;\n+import fr.magnus.reftechnique.transverse.EntiteRelationnelle;\n+import fr.magnus.reftechnique.transverse.tableau.TableauAbstract;\n+\n+@Service(\"ServiceImprimerAvisMandatement\")\n+public class ServiceImprimerAvisMandatementImpl extends ServiceImprimerImpl implements ServiceImprimerAvisMandatement{\n+\n+ @Override\n+\tpublic List getListDonnee(TableauAbstract[] tableauEntiteRelationnelles, Map params) throws ParseException {\n+\n+ List dtoAvisMandatementList = null;\n+ \n+ if (tableauEntiteRelationnelles!= null && tableauEntiteRelationnelles.length == 2) {\n+ TableauAbstract tabDonnee = tableauEntiteRelationnelles[0];\n+// Collections.sort(dtoAvisMandatementList, Comparator.comparing(DTOAvis::getBordereauNumero)\n+// .thenComparing(DTOAvis::getTitreNumeroPiece)\n+// .thenComparing(DTOAvis::getTiers1)\n+// \t.thenComparing(DTOAvis::getImputationComplete));\n+ }\n+ return dtoAvisMandatementList;\t\t\n+\t}\n+\n+}\n","new_file":true,"deleted_file":false,"renamed_file":false},{"b_mode":"100644","diff":"@@ -1,8 +1,6 @@\n package fr.bl.avenir.gf.rest.ecompta.edition.service.impl;\n \n import java.math.BigDecimal;\n-import java.nio.file.Path;\n-import java.nio.file.Paths;\n import java.text.ParseException;\n import java.text.SimpleDateFormat;\n import java.util.ArrayList;\n@@ -58,14 +56,11 @@ public abstract class ServiceImprimerImpl implements ServiceImprimer {\n return getListDonnee(tableauEntiteRelationnelles, params);\n }\n \n- protected void mappingDtoEnvironnementFromJson(\n- TableauAbstract environnement,\n- Map params) {\n+ protected void mappingDtoEnvironnementFromJson(TableauAbstract environnement, Map params) {\n if (environnement != null && environnement.getLigneCount() > 0) {\n EntiteRelationnelle entiteRelationnelle = environnement.getDonnees().get(0);\n params.putAll(entiteRelationnelle.getData());\n }\n-\n }\n \n protected List mappingDtoOrdonnancementListFromJson(TableauAbstract ordonnancementJSon) {\n","new_path":"@@ -1,8 +1,6 @@\n package fr.bl.avenir.gf.rest.ecompta.edition.service.impl;\n \n import java.math.BigDecimal;\n-import java.nio.file.Path;\n-import java.nio.file.Paths;\n import java.text.ParseException;\n import java.text.SimpleDateFormat;\n import java.util.ArrayList;\n@@ -58,14 +56,11 @@ public abstract class ServiceImprimerImpl implements ServiceImprimer {\n return getListDonnee(tableauEntiteRelationnelles, params);\n }\n \n- protected void mappingDtoEnvironnementFromJson(\n- TableauAbstract environnement,\n- Map params) {\n+ protected void mappingDtoEnvironnementFromJson(TableauAbstract environnement, Map params) {\n if (environnement != null && environnement.getLigneCount() > 0) {\n EntiteRelationnelle entiteRelationnelle = environnement.getDonnees().get(0);\n params.putAll(entiteRelationnelle.getData());\n }\n-\n }\n \n protected List mappingDtoOrdonnancementListFromJson(TableauAbstract ordonnancementJSon) {\n","a_mode":"100644","old_path":"@@ -1,8 +1,6 @@\n package fr.bl.avenir.gf.rest.ecompta.edition.service.impl;\n \n import java.math.BigDecimal;\n-import java.nio.file.Path;\n-import java.nio.file.Paths;\n import java.text.ParseException;\n import java.text.SimpleDateFormat;\n import java.util.ArrayList;\n@@ -58,14 +56,11 @@ public abstract class ServiceImprimerImpl implements ServiceImprimer {\n return getListDonnee(tableauEntiteRelationnelles, params);\n }\n \n- protected void mappingDtoEnvironnementFromJson(\n- TableauAbstract environnement,\n- Map params) {\n+ protected void mappingDtoEnvironnementFromJson(TableauAbstract environnement, Map params) {\n if (environnement != null && environnement.getLigneCount() > 0) {\n EntiteRelationnelle entiteRelationnelle = environnement.getDonnees().get(0);\n params.putAll(entiteRelationnelle.getData());\n }\n-\n }\n \n protected List mappingDtoOrdonnancementListFromJson(TableauAbstract ordonnancementJSon) {\n","new_file":false,"deleted_file":false,"renamed_file":false},{"b_mode":"100644","diff":"@@ -0,0 +1,177 @@\n+\n+\n+\n+\t\n+\t\n+\t\n+\t\n+\t\n+\t\n+\t\n+\t\n+\t\n+\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\n+\n+\t\n+\t\n+\t\n+\t\n+\t\n+\t\n+\t\n+\t\n+\t\n+\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\n+\t\n+\n","a_mode":"0","old_path":"@@ -0,0 +1,177 @@\n+\n+\n+\n+\t\n+\t\n+\t\n+\t\n+\t\n+\t\n+\t\n+\t\n+\t\n+\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\n+\t\n+\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\t\n+\t\t\t\t\n+\t\t\t\t\t\n+\t\t\t\t\n+\t\t\t\t\n+\t\t\t\n+\t\t\n+\t\n+\n","new_file":true,"deleted_file":false,"renamed_file":false}]' ] +{ #category : #json } +GitlabModelImporterTest >> jobsJson [ + + ^ '[ + { + "commit": { + "author_email": "admin@example.com", + "author_name": "Administrator", + "created_at": "2015-12-24T16:51:14.000+01:00", + "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "message": "Test the CI integration.", + "short_id": "0ff3ae19", + "title": "Test the CI integration." + }, + "coverage": null, + "archived": false, + "source": "push", + "allow_failure": false, + "created_at": "2015-12-24T15:51:21.802Z", + "started_at": "2015-12-24T17:54:27.722Z", + "finished_at": "2015-12-24T17:54:27.895Z", + "erased_at": null, + "duration": 0.173, + "queued_duration": 0.010, + "artifacts_file": { + "filename": "artifacts.zip", + "size": 1000 + }, + "artifacts": [ + {"file_type": "archive", "size": 1000, "filename": "artifacts.zip", "file_format": "zip"}, + {"file_type": "metadata", "size": 186, "filename": "metadata.gz", "file_format": "gzip"}, + {"file_type": "trace", "size": 1500, "filename": "job.log", "file_format": "raw"}, + {"file_type": "junit", "size": 750, "filename": "junit.xml.gz", "file_format": "gzip"} + ], + "artifacts_expire_at": "2016-01-23T17:54:27.895Z", + "tag_list": [ + "docker runner", "ubuntu18" + ], + "id": 7, + "name": "teaspoon", + "pipeline": { + "id": 6, + "project_id": 1, + "ref": "main", + "sha": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "status": "pending" + }, + "ref": "main", + "runner": { + "id": 32, + "description": "", + "ip_address": null, + "active": true, + "paused": false, + "is_shared": true, + "runner_type": "instance_type", + "name": null, + "online": false, + "status": "offline" + }, + "runner_manager": { + "id": 1, + "system_id": "s_89e5e9956577", + "version": "16.11.1", + "revision": "535ced5f", + "platform": "linux", + "architecture": "amd64", + "created_at": "2024-05-01T10:12:02.507Z", + "contacted_at": "2024-05-07T06:30:09.355Z", + "ip_address": "127.0.0.1", + "status": "offline" + }, + "stage": "test", + "status": "failed", + "failure_reason": "script_failure", + "tag": false, + "web_url": "https://example.com/foo/bar/-/jobs/7", + "project": { + "ci_job_token_scope_enabled": false + }, + "user": { + "id": 123, + "name": "Administrator", + "username": "root", + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "web_url": "http://gitlab.dev/root", + "created_at": "2015-12-21T13:14:24.077Z", + "bio": null, + "location": null, + "public_email": "", + "linkedin": "", + "twitter": "", + "website_url": "", + "organization": "" + } + }, + { + "commit": { + "author_email": "admin@example.com", + "author_name": "Administrator", + "created_at": "2015-12-24T16:51:14.000+01:00", + "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "message": "Test the CI integration.", + "short_id": "0ff3ae19", + "title": "Test the CI integration." + }, + "coverage": null, + "archived": false, + "source": "push", + "allow_failure": false, + "created_at": "2015-12-24T15:51:21.727Z", + "started_at": "2015-12-24T17:54:24.729Z", + "finished_at": "2015-12-24T17:54:24.921Z", + "erased_at": null, + "duration": 0.192, + "queued_duration": 0.023, + "artifacts_expire_at": "2016-01-23T17:54:24.921Z", + "tag_list": [ + "docker runner", "win10-2004" + ], + "id": 6, + "name": "rspec:other", + "pipeline": { + "id": 6, + "project_id": 1, + "ref": "main", + "sha": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "status": "pending" + }, + "ref": "main", + "artifacts": [], + "runner": null, + "runner_manager": null, + "stage": "test", + "status": "failed", + "failure_reason": "stuck_or_timeout_failure", + "tag": false, + "web_url": "https://example.com/foo/bar/-/jobs/6", + "project": { + "ci_job_token_scope_enabled": false + }, + "user": { + "id": 123, + "name": "Administrator", + "username": "root", + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "web_url": "http://gitlab.dev/root", + "created_at": "2015-12-21T13:14:24.077Z", + "bio": null, + "location": null, + "public_email": "", + "linkedin": "", + "twitter": "", + "website_url": "", + "organization": "" + } + } +]' +] + { #category : #running } GitlabModelImporterTest >> setUp [ super setUp. + "first set the local importer" importer := GitlabModelImporter new. + importer repoApi: GitlabApiMock new. + + "than set up the model in super" model := GLHModel new. importer glhModel: model. - importer repoApi: GLHApiMock new + defaultProject := GLHProject new + repository: GLHRepository new; + yourself. + + defaultMergeRequestOrPipeline := GLHMergeRequest new + project: (GLHProject new id: 123); + iid: 123; + yourself ] -{ #category : #tests } +{ #category : #'tests - repositories' } +GitlabModelImporterTest >> testCompleteImportsOfRepository [ + + | element project | + project := GLHProject new + name: 'testProject'; + repository: GLHRepository new; + yourself. + element := importer completeImportsOfRepository: project repository. + + self assert: element isNotNil. + self assert: element class equals: GLHRepository. + + self assert: element project isNotNil. + self assert: element project equals: project. + + self assert: element branches isNotNil. + self assert: element branches anyOne class equals: GLHBranch +] + +{ #category : #'tests - commits' } GitlabModelImporterTest >> testImportCommitsFromTagToTagNoCommits [ | tag1 tag2 hostUrl gitlabApi projectId result client gitlabRepositories from to params | @@ -74,7 +267,7 @@ GitlabModelImporterTest >> testImportCommitsFromTagToTagNoCommits [ self assert: result isEmpty ] -{ #category : #tests } +{ #category : #'test - diffs' } GitlabModelImporterTest >> testImportDiffOfCommitWithServerRaiseError [ | commit repo project | @@ -88,7 +281,7 @@ GitlabModelImporterTest >> testImportDiffOfCommitWithServerRaiseError [ self assert: commit diffs isEmpty ] -{ #category : #tests } +{ #category : #'test - diffs' } GitlabModelImporterTest >> testImportDiffOfMergeRequest [ | mr | @@ -99,7 +292,124 @@ GitlabModelImporterTest >> testImportDiffOfMergeRequest [ self assert: (model allWithType: GLHDiff) size equals: 3 ] -{ #category : #tests } +{ #category : #'tests - jobs' } +GitlabModelImporterTest >> testImportJobsOfPipeline [ + + | json jobsArray job | + json := self jobsJson. + + jobsArray := importer importJobsOfPipeline: (GLHPipeline new + id: 12; + project: (GLHProject new + id: 12; + repository: GLHRepository new); + yourself). + + job := jobsArray first. + + self assert: jobsArray size equals: 2. + self assert: job name equals: 'teaspoon' +] + +{ #category : #'tests - pipelines' } +GitlabModelImporterTest >> testImportLatestPipelinesOfProject [ + + | collection element | + collection := importer importLatestPipelinesOfProject: (GLHProject new + repository: GLHRepository new; + yourself). + + self assert: collection isEmptyOrNil not. + self assert: collection isCollection. + + element := collection first. + self assert: element class equals: GLHPipeline . + self assert: element project isNotNil. + self assert: element project class equals: GLHProject + +] + +{ #category : #'tests - releases' } +GitlabModelImporterTest >> testImportLatestReleaseOfProject [ + + | element | + element := importer importLatestReleaseOfProject: + (GLHProject new + repository: GLHRepository new; + yourself). + + self deny: element isCollection. + self assert: element class equals: GLHRelease. + self assert: element project isNotNil +] + +{ #category : #'tests - notes' } +GitlabModelImporterTest >> testImportNotesOfMergeRequest [ + + | collection element | + collection := importer importNotesOfMergeRequest: + (GLHMergeRequest new + project: (GLHProject new id: 123); + yourself). + + self assert: collection isCollection. + element := collection first. + self assert: element class equals: GLHNote. + self assert: element mergeRequest isNotNil. + +] + +{ #category : #'tests - projects' } +GitlabModelImporterTest >> testImportProject [ + + | element | + element := importer importProject: 123. + + self assert: element isNotNil. + self assert: element class equals: GLHProject . + self assert: element repository class equals: GLHRepository. + +] + +{ #category : #'tests - projects' } +GitlabModelImporterTest >> testImportProjects [ + + | collection element | + collection := importer importProjects. + + self deny: collection isEmptyOrNil. + self assert: collection isCollection. + element := collection first. + + self assert: element isNotNil. + self assert: element class equals: GLHProject. + self assert: element repository isNil. +] + +{ #category : #'tests - tags' } +GitlabModelImporterTest >> testImportTagsForProject [ + + | collection element | + collection := importer importTagsForProject: (GLHProject new + repository: GLHRepository new; + yourself). + + self assert: collection isCollection. + element := collection first. + self assert: element class equals: GLHTag. + + self assert: element commit isNotNil. + self assert: element commit class equals: GLHCommit . + + self assert: element repository isNotNil. + self assert: element repository class equals: GLHRepository. + + self assert: element repository project isNotNil. + self assert: element repository project class equals: GLHProject. + +] + +{ #category : #'tests - users' } GitlabModelImporterTest >> testImportUserAlreadyInModel [ | user | @@ -110,14 +420,14 @@ GitlabModelImporterTest >> testImportUserAlreadyInModel [ self assert: (importer importUser: 12) equals: user ] -{ #category : #tests } +{ #category : #'tests - errors' } GitlabModelImporterTest >> testIsServerError [ self assert: (importer isServerError: '{"message":"500 Internal Server Error"}') ] -{ #category : #test } +{ #category : #'test - diffs' } GitlabModelImporterTest >> testNewParseDiffResultGitlab [ | parseRes | @@ -127,7 +437,7 @@ GitlabModelImporterTest >> testNewParseDiffResultGitlab [ self assert: parseRes size equals: 8 ] -{ #category : #tests } +{ #category : #'test - diffs' } GitlabModelImporterTest >> testParseDiffString [ | diff diffRange | @@ -160,7 +470,7 @@ GitlabModelImporterTest >> testParseDiffString [ equals: 2 ] -{ #category : #tests } +{ #category : #'tests - notes' } GitlabModelImporterTest >> testParseNote [ | jsonNote notesArray note | @@ -194,8 +504,8 @@ GitlabModelImporterTest >> testParseNote [ ] -{ #category : #tests } -GitlabModelImporterTest >> testParseUserResult [ +{ #category : #'tests - users' } +GitlabModelImporterTest >> testimportUser [ | user | user := importer importUser: 123. diff --git a/src/GitLabHealth-Model-Importer-Tests/GitlabNotesMock.class.st b/src/GitLabHealth-Model-Importer-Tests/GitlabNotesMock.class.st new file mode 100644 index 00000000..2ea84af1 --- /dev/null +++ b/src/GitLabHealth-Model-Importer-Tests/GitlabNotesMock.class.st @@ -0,0 +1,60 @@ +Class { + #name : #GitlabNotesMock, + #superclass : #Object, + #category : #'GitLabHealth-Model-Importer-Tests' +} + +{ #category : #'api - get' } +GitlabNotesMock >> allInMergeRequest: anUndefinedObject ofProject: anInteger [ + + ^ {'[ + { + "id": 302, + "body": "closed", + "author": { + "id": 1, + "username": "pipin", + "email": "admin@example.com", + "name": "Pip", + "state": "active", + "created_at": "2013-09-30T13:46:01Z" + }, + "created_at": "2013-10-02T09:22:45Z", + "updated_at": "2013-10-02T10:22:45Z", + "system": true, + "noteable_id": 377, + "noteable_type": "Issue", + "project_id": 5, + "noteable_iid": 377, + "resolvable": false, + "confidential": false, + "internal": false, + "imported": false, + "imported_from": "none" + }, + { + "id": 305, + "body": "Text of the comment\r\n", + "author": { + "id": 1, + "username": "pipin", + "email": "admin@example.com", + "name": "Pip", + "state": "active", + "created_at": "2013-09-30T13:46:01Z" + }, + "created_at": "2013-10-02T09:56:03Z", + "updated_at": "2013-10-02T09:56:03Z", + "system": true, + "noteable_id": 121, + "noteable_type": "Issue", + "project_id": 5, + "noteable_iid": 121, + "resolvable": false, + "confidential": true, + "internal": true, + "imported": false, + "imported_from": "none" + } +]'} +] diff --git a/src/GitLabHealth-Model-Importer-Tests/GitlabPipelinesMock.class.st b/src/GitLabHealth-Model-Importer-Tests/GitlabPipelinesMock.class.st new file mode 100644 index 00000000..61e190ed --- /dev/null +++ b/src/GitLabHealth-Model-Importer-Tests/GitlabPipelinesMock.class.st @@ -0,0 +1,88 @@ +Class { + #name : #GitlabPipelinesMock, + #superclass : #Object, + #category : #'GitLabHealth-Model-Importer-Tests' +} + +{ #category : #api } +GitlabPipelinesMock >> get: anInteger inProject: anInteger2 [ + ^ '{ + "id": 287, + "iid": 144, + "project_id": 21, + "name": "Build pipeline", + "sha": "50f0acb76a40e34a4ff304f7347dcc6587da8a14", + "ref": "main", + "status": "success", + "source": "push", + "created_at": "2022-09-21T01:05:07.200Z", + "updated_at": "2022-09-21T01:05:50.185Z", + "web_url": "http://127.0.0.1:3000/test-group/test-project/-/pipelines/287", + "before_sha": "8a24fb3c5877a6d0b611ca41fc86edc174593e2b", + "tag": false, + "yaml_errors": null, + "user": { + "id": 1, + "username": "root", + "name": "Administrator", + "state": "active", + "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "web_url": "http://127.0.0.1:3000/root" + }, + "started_at": "2022-09-21T01:05:14.197Z", + "finished_at": "2022-09-21T01:05:50.175Z", + "committed_at": null, + "duration": 34, + "queued_duration": 6, + "coverage": null, + "detailed_status": { + "icon": "status_success", + "text": "passed", + "label": "passed", + "group": "success", + "tooltip": "passed", + "has_details": false, + "details_path": "/test-group/test-project/-/pipelines/287", + "illustration": null, + "favicon": "/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png" + } +}' +] + +{ #category : #api } +GitlabPipelinesMock >> getByPage: anInteger perPage: anInteger2 inProject: anInteger3 [ + ^ '[ + { + "id": 47, + "iid": 12, + "project_id": 1, + "status": "pending", + "source": "push", + "ref": "new-pipeline", + "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a", + "name": "Build pipeline", + "web_url": "https://example.com/foo/bar/pipelines/47", + "created_at": "2016-08-11T11:28:34.085Z", + "updated_at": "2016-08-11T11:32:35.169Z" + }, + { + "id": 48, + "iid": 13, + "project_id": 1, + "status": "pending", + "source": "web", + "ref": "new-pipeline", + "sha": "eb94b618fb5865b26e80fdd8ae531b7a63ad851a", + "name": "Build pipeline", + "web_url": "https://example.com/foo/bar/pipelines/48", + "created_at": "2016-08-12T10:06:04.561Z", + "updated_at": "2016-08-12T10:09:56.223Z" + } +]' +] + +{ #category : #api } +GitlabPipelinesMock >> getByPage: anInteger perPage: anInteger2 inProject: anInteger3 forMergerRequestIid: anInteger4 [ + ^self getByPage: anInteger perPage: anInteger2 inProject: nil + +] diff --git a/src/GitLabHealth-Model-Importer-Tests/GitlabProjectsMock.class.st b/src/GitLabHealth-Model-Importer-Tests/GitlabProjectsMock.class.st new file mode 100644 index 00000000..0945180a --- /dev/null +++ b/src/GitLabHealth-Model-Importer-Tests/GitlabProjectsMock.class.st @@ -0,0 +1,329 @@ +Class { + #name : #GitlabProjectsMock, + #superclass : #Object, + #category : #'GitLabHealth-Model-Importer-Tests' +} + +{ #category : #accessing } +GitlabProjectsMock >> all [ + ^ { '[ + { + "id": 4, + "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + "description_html": "

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

", + "name": "Diaspora Client", + "name_with_namespace": "Diaspora / Diaspora Client", + "path": "diaspora-client", + "path_with_namespace": "diaspora/diaspora-client", + "created_at": "2013-09-30T13:46:02Z", + "updated_at": "2013-09-30T13:46:02Z", + "default_branch": "main", + "tag_list": [ + "example", + "disapora client" + ], + "topics": [ + "example", + "disapora client" + ], + "ssh_url_to_repo": "git@gitlab.example.com:diaspora/diaspora-client.git", + "http_url_to_repo": "https://gitlab.example.com/diaspora/diaspora-client.git", + "web_url": "https://gitlab.example.com/diaspora/diaspora-client", + "readme_url": "https://gitlab.example.com/diaspora/diaspora-client/blob/main/README.md", + "avatar_url": "https://gitlab.example.com/uploads/project/avatar/4/uploads/avatar.png", + "forks_count": 0, + "star_count": 0, + "last_activity_at": "2022-06-24T17:11:26.841Z", + "namespace": { + "id": 3, + "name": "Diaspora", + "path": "diaspora", + "kind": "group", + "full_path": "diaspora", + "parent_id": null, + "avatar_url": "https://gitlab.example.com/uploads/project/avatar/6/uploads/avatar.png", + "web_url": "https://gitlab.example.com/diaspora" + }, + "container_registry_image_prefix": "registry.gitlab.example.com/diaspora/diaspora-client", + "_links": { + "self": "https://gitlab.example.com/api/v4/projects/4", + "issues": "https://gitlab.example.com/api/v4/projects/4/issues", + "merge_requests": "https://gitlab.example.com/api/v4/projects/4/merge_requests", + "repo_branches": "https://gitlab.example.com/api/v4/projects/4/repository/branches", + "labels": "https://gitlab.example.com/api/v4/projects/4/labels", + "events": "https://gitlab.example.com/api/v4/projects/4/events", + "members": "https://gitlab.example.com/api/v4/projects/4/members", + "cluster_agents": "https://gitlab.example.com/api/v4/projects/4/cluster_agents" + }, + "packages_enabled": true, + "package_registry_access_level": "enabled", + "empty_repo": false, + "archived": false, + "visibility": "public", + "resolve_outdated_diff_discussions": false, + "container_expiration_policy": { + "cadence": "1month", + "enabled": true, + "keep_n": 1, + "older_than": "14d", + "name_regex": "", + "name_regex_keep": ".*-main", + "next_run_at": "2022-06-25T17:11:26.865Z" + }, + "issues_enabled": true, + "merge_requests_enabled": true, + "wiki_enabled": true, + "jobs_enabled": true, + "snippets_enabled": true, + "container_registry_enabled": true, + "service_desk_enabled": true, + "can_create_merge_request_in": true, + "issues_access_level": "enabled", + "repository_access_level": "enabled", + "merge_requests_access_level": "enabled", + "forking_access_level": "enabled", + "wiki_access_level": "enabled", + "builds_access_level": "enabled", + "snippets_access_level": "enabled", + "pages_access_level": "enabled", + "analytics_access_level": "enabled", + "container_registry_access_level": "enabled", + "security_and_compliance_access_level": "private", + "emails_disabled": null, + "emails_enabled": null, + "shared_runners_enabled": true, + "group_runners_enabled": true, + "lfs_enabled": true, + "creator_id": 1, + "import_url": null, + "import_type": null, + "import_status": "none", + "import_error": null, + "open_issues_count": 0, + "ci_default_git_depth": 20, + "ci_forward_deployment_enabled": true, + "ci_forward_deployment_rollback_allowed": true, + "ci_allow_fork_pipelines_to_run_in_parent_project": true, + "ci_id_token_sub_claim_components": ["project_path", "ref_type", "ref"], + "ci_job_token_scope_enabled": false, + "ci_separated_caches": true, + "ci_restrict_pipeline_cancellation_role": "developer", + "ci_pipeline_variables_minimum_override_role": "maintainer", + "ci_push_repository_for_job_token_allowed": false, + "public_jobs": true, + "build_timeout": 3600, + "auto_cancel_pending_pipelines": "enabled", + "ci_config_path": "", + "shared_with_groups": [], + "only_allow_merge_if_pipeline_succeeds": false, + "allow_merge_on_skipped_pipeline": null, + "allow_pipeline_trigger_approve_deployment": false, + "restrict_user_defined_variables": false, + "request_access_enabled": true, + "only_allow_merge_if_all_discussions_are_resolved": false, + "remove_source_branch_after_merge": true, + "printing_merge_request_link_enabled": true, + "merge_method": "merge", + "squash_option": "default_off", + "enforce_auth_checks_on_uploads": true, + "suggestion_commit_message": null, + "merge_commit_template": null, + "squash_commit_template": null, + "issue_branch_template": "gitlab/%{id}-%{title}", + "auto_devops_enabled": false, + "auto_devops_deploy_strategy": "continuous", + "autoclose_referenced_issues": true, + "keep_latest_artifact": true, + "runner_token_expiration_interval": null, + "external_authorization_classification_label": "", + "requirements_enabled": false, + "requirements_access_level": "enabled", + "security_and_compliance_enabled": false, + "secret_push_protection_enabled": false, + "compliance_frameworks": [], + "warn_about_potentially_unwanted_characters": true, + "permissions": { + "project_access": null, + "group_access": null + } + } +]' } +] + +{ #category : #api } +GitlabProjectsMock >> get: anInteger [ + ^ '{ + "id": 3, + "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + "description_html": "

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

", + "default_branch": "main", + "visibility": "private", + "ssh_url_to_repo": "git@example.com:diaspora/diaspora-project-site.git", + "http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git", + "web_url": "http://example.com/diaspora/diaspora-project-site", + "readme_url": "http://example.com/diaspora/diaspora-project-site/blob/main/README.md", + "tag_list": [ + "example", + "disapora project" + ], + "topics": [ + "example", + "disapora project" + ], + "owner": { + "id": 3, + "name": "Diaspora", + "created_at": "2013-09-30T13:46:02Z" + }, + "name": "Diaspora Project Site", + "name_with_namespace": "Diaspora / Diaspora Project Site", + "path": "diaspora-project-site", + "path_with_namespace": "diaspora/diaspora-project-site", + "issues_enabled": true, + "open_issues_count": 1, + "merge_requests_enabled": true, + "jobs_enabled": true, + "wiki_enabled": true, + "snippets_enabled": false, + "can_create_merge_request_in": true, + "resolve_outdated_diff_discussions": false, + "container_registry_enabled": false, + "container_registry_access_level": "disabled", + "security_and_compliance_access_level": "disabled", + "container_expiration_policy": { + "cadence": "7d", + "enabled": false, + "keep_n": null, + "older_than": null, + "name_regex": null, + "name_regex_delete": null, + "name_regex_keep": null, + "next_run_at": "2020-01-07T21:42:58.658Z" + }, + "created_at": "2013-09-30T13:46:02Z", + "updated_at": "2013-09-30T13:46:02Z", + "last_activity_at": "2013-09-30T13:46:02Z", + "creator_id": 3, + "namespace": { + "id": 3, + "name": "Diaspora", + "path": "diaspora", + "kind": "group", + "full_path": "diaspora", + "avatar_url": "http://localhost:3000/uploads/group/avatar/3/foo.jpg", + "web_url": "http://localhost:3000/groups/diaspora" + }, + "import_url": null, + "import_type": null, + "import_status": "none", + "import_error": null, + "permissions": { + "project_access": { + "access_level": 10, + "notification_level": 3 + }, + "group_access": { + "access_level": 50, + "notification_level": 3 + } + }, + "archived": false, + "avatar_url": "http://example.com/uploads/project/avatar/3/uploads/avatar.png", + "license_url": "http://example.com/diaspora/diaspora-client/blob/main/LICENSE", + "license": { + "key": "lgpl-3.0", + "name": "GNU Lesser General Public License v3.0", + "nickname": "GNU LGPLv3", + "html_url": "http://choosealicense.com/licenses/lgpl-3.0/", + "source_url": "http://www.gnu.org/licenses/lgpl-3.0.txt" + }, + "shared_runners_enabled": true, + "group_runners_enabled": true, + "forks_count": 0, + "star_count": 0, + "runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b", + "ci_default_git_depth": 50, + "ci_forward_deployment_enabled": true, + "ci_forward_deployment_rollback_allowed": true, + "ci_allow_fork_pipelines_to_run_in_parent_project": true, + "ci_id_token_sub_claim_components": ["project_path", "ref_type", "ref"], + "ci_separated_caches": true, + "ci_restrict_pipeline_cancellation_role": "developer", + "ci_pipeline_variables_minimum_override_role": "maintainer", + "ci_push_repository_for_job_token_allowed": false, + "public_jobs": true, + "shared_with_groups": [ + { + "group_id": 4, + "group_name": "Twitter", + "group_full_path": "twitter", + "group_access_level": 30 + }, + { + "group_id": 3, + "group_name": "Gitlab Org", + "group_full_path": "gitlab-org", + "group_access_level": 10 + } + ], + "repository_storage": "default", + "only_allow_merge_if_pipeline_succeeds": false, + "allow_merge_on_skipped_pipeline": false, + "allow_pipeline_trigger_approve_deployment": false, + "restrict_user_defined_variables": false, + "only_allow_merge_if_all_discussions_are_resolved": false, + "remove_source_branch_after_merge": false, + "printing_merge_requests_link_enabled": true, + "request_access_enabled": false, + "merge_method": "merge", + "squash_option": "default_on", + "auto_devops_enabled": true, + "auto_devops_deploy_strategy": "continuous", + "approvals_before_merge": 0, + "mirror": false, + "mirror_user_id": 45, + "mirror_trigger_builds": false, + "only_mirror_protected_branches": false, + "mirror_overwrites_diverged_branches": false, + "external_authorization_classification_label": null, + "packages_enabled": true, + "service_desk_enabled": false, + "service_desk_address": null, + "autoclose_referenced_issues": true, + "suggestion_commit_message": null, + "enforce_auth_checks_on_uploads": true, + "merge_commit_template": null, + "squash_commit_template": null, + "issue_branch_template": "gitlab/%{id}-%{title}", + "marked_for_deletion_at": "2020-04-03", + "marked_for_deletion_on": "2020-04-03", + "compliance_frameworks": [ "sox" ], + "warn_about_potentially_unwanted_characters": true, + "secret_push_protection_enabled": false, + "statistics": { + "commit_count": 37, + "storage_size": 1038090, + "repository_size": 1038090, + "wiki_size" : 0, + "lfs_objects_size": 0, + "job_artifacts_size": 0, + "pipeline_artifacts_size": 0, + "packages_size": 0, + "snippets_size": 0, + "uploads_size": 0, + "container_registry_size": 0 + }, + "container_registry_image_prefix": "registry.example.com/diaspora/diaspora-client", + "_links": { + "self": "http://example.com/api/v4/projects", + "issues": "http://example.com/api/v4/projects/1/issues", + "merge_requests": "http://example.com/api/v4/projects/1/merge_requests", + "repo_branches": "http://example.com/api/v4/projects/1/repository_branches", + "labels": "http://example.com/api/v4/projects/1/labels", + "events": "http://example.com/api/v4/projects/1/events", + "members": "http://example.com/api/v4/projects/1/members", + "cluster_agents": "http://example.com/api/v4/projects/1/cluster_agents" + }, + "spp_repository_pipeline_access": false +}' +] diff --git a/src/GitLabHealth-Model-Importer-Tests/GitlabReleasesMock.class.st b/src/GitLabHealth-Model-Importer-Tests/GitlabReleasesMock.class.st new file mode 100644 index 00000000..cb9fc8a6 --- /dev/null +++ b/src/GitLabHealth-Model-Importer-Tests/GitlabReleasesMock.class.st @@ -0,0 +1,124 @@ +Class { + #name : #GitlabReleasesMock, + #superclass : #Object, + #category : #'GitLabHealth-Model-Importer-Tests' +} + +{ #category : #get } +GitlabReleasesMock >> getLatestOfProject: anUndefinedObject [ + + ^ '{ + "tag_name":"v0.1", + "description":"## CHANGELOG\r\n\r\n- Remove limit of 100 when searching repository code. !8671\r\n- Show error message when attempting to reopen an MR and there is an open MR for the same branch. !16447 (Akos Gyimesi)\r\n- Fix a bug where internal email pattern wasn''t respected. !22516", + "name":"Awesome app v0.1 alpha", + "created_at":"2019-01-03T01:55:18.203Z", + "released_at":"2019-01-03T01:55:18.203Z", + "author":{ + "id":1, + "name":"Administrator", + "username":"root", + "state":"active", + "avatar_url":"https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon", + "web_url":"https://gitlab.example.com/root" + }, + "commit":{ + "id":"f8d3d94cbd347e924aa7b715845e439d00e80ca4", + "short_id":"f8d3d94c", + "title":"Initial commit", + "created_at":"2019-01-03T01:53:28.000Z", + "parent_ids":[ + + ], + "message":"Initial commit", + "author_name":"Administrator", + "author_email":"admin@example.com", + "authored_date":"2019-01-03T01:53:28.000Z", + "committer_name":"Administrator", + "committer_email":"admin@example.com", + "committed_date":"2019-01-03T01:53:28.000Z" + }, + "milestones": [ + { + "id":51, + "iid":1, + "project_id":24, + "title":"v1.0-rc", + "description":"Voluptate fugiat possimus quis quod aliquam expedita.", + "state":"closed", + "created_at":"2019-07-12T19:45:44.256Z", + "updated_at":"2019-07-12T19:45:44.256Z", + "due_date":"2019-08-16", + "start_date":"2019-07-30", + "web_url":"https://gitlab.example.com/root/awesome-app/-/milestones/1", + "issue_stats": { + "total": 98, + "closed": 76 + } + }, + { + "id":52, + "iid":2, + "project_id":24, + "title":"v1.0", + "description":"Voluptate fugiat possimus quis quod aliquam expedita.", + "state":"closed", + "created_at":"2019-07-16T14:00:12.256Z", + "updated_at":"2019-07-16T14:00:12.256Z", + "due_date":"2019-08-16", + "start_date":"2019-07-30", + "web_url":"https://gitlab.example.com/root/awesome-app/-/milestones/2", + "issue_stats": { + "total": 24, + "closed": 21 + } + } + ], + "commit_path":"/root/awesome-app/commit/588440f66559714280628a4f9799f0c4eb880a4a", + "tag_path":"/root/awesome-app/-/tags/v0.11.1", + "assets":{ + "count":5, + "sources":[ + { + "format":"zip", + "url":"https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.zip" + }, + { + "format":"tar.gz", + "url":"https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.tar.gz" + }, + { + "format":"tar.bz2", + "url":"https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.tar.bz2" + }, + { + "format":"tar", + "url":"https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.tar" + } + ], + "links":[ + { + "id":3, + "name":"hoge", + "url":"https://gitlab.example.com/root/awesome-app/-/tags/v0.11.1/binaries/linux-amd64", + "link_type":"other" + } + ] + }, + "evidences":[ + { + "sha": "760d6cdfb0879c3ffedec13af470e0f71cf52c6cde4d", + "filepath": "https://gitlab.example.com/root/awesome-app/-/releases/v0.1/evidence.json", + "collected_at": "2019-07-16T14:00:12.256Z" + } + ], + "_links": { + "closed_issues_url": "https://gitlab.example.com/root/awesome-app/-/issues?release_tag=v0.1&scope=all&state=closed", + "closed_merge_requests_url": "https://gitlab.example.com/root/awesome-app/-/merge_requests?release_tag=v0.1&scope=all&state=closed", + "edit_url": "https://gitlab.example.com/root/awesome-app/-/releases/v0.1/edit", + "merged_merge_requests_url": "https://gitlab.example.com/root/awesome-app/-/merge_requests?release_tag=v0.1&scope=all&state=merged", + "opened_issues_url": "https://gitlab.example.com/root/awesome-app/-/issues?release_tag=v0.1&scope=all&state=opened", + "opened_merge_requests_url": "https://gitlab.example.com/root/awesome-app/-/merge_requests?release_tag=v0.1&scope=all&state=opened", + "self": "https://gitlab.example.com/root/awesome-app/-/releases/v0.1" + } +}' +] diff --git a/src/GitLabHealth-Model-Importer-Tests/GitlabTagMock.class.st b/src/GitLabHealth-Model-Importer-Tests/GitlabTagMock.class.st new file mode 100644 index 00000000..4869dec8 --- /dev/null +++ b/src/GitLabHealth-Model-Importer-Tests/GitlabTagMock.class.st @@ -0,0 +1,39 @@ +Class { + #name : #GitlabTagMock, + #superclass : #Object, + #category : #'GitLabHealth-Model-Importer-Tests' +} + +{ #category : #api } +GitlabTagMock >> getAllOfProject: anUndefinedObject [ + + ^ {'[ + { + "commit": { + "id": "2695effb5807a22ff3d138d593fd856244e155e7", + "short_id": "2695effb", + "title": "Initial commit", + "created_at": "2017-07-26T11:08:53.000+02:00", + "parent_ids": [ + "2a4b78934375d7f53875269ffd4f45fd83a84ebe" + ], + "message": "Initial commit", + "author_name": "John Smith", + "author_email": "john@example.com", + "authored_date": "2012-05-28T04:42:42-07:00", + "committer_name": "Jack Smith", + "committer_email": "jack@example.com", + "committed_date": "2012-05-28T04:42:42-07:00" + }, + "release": { + "tag_name": "1.0.0", + "description": "Amazing release. Wow" + }, + "name": "v1.0.0", + "target": "2695effb5807a22ff3d138d593fd856244e155e7", + "message": null, + "protected": true, + "created_at": "2017-07-26T11:08:53.000+02:00" + } +]'} +] diff --git a/src/GitLabHealth-Model-Importer/GitlabModelImporter.class.st b/src/GitLabHealth-Model-Importer/GitlabModelImporter.class.st index e4953f63..a0006833 100644 --- a/src/GitLabHealth-Model-Importer/GitlabModelImporter.class.st +++ b/src/GitLabHealth-Model-Importer/GitlabModelImporter.class.st @@ -3,8 +3,7 @@ Class { #superclass : #GitModelImporter, #instVars : [ 'withInitialCommits', - 'withInitialMergeRequest', - 'generalReader' + 'withInitialMergeRequest' ], #category : #'GitLabHealth-Model-Importer' } @@ -48,28 +47,6 @@ GitlabModelImporter >> allPipelinesOf: aProjectID [ self parsePipelinesResult: pipelinesJson ]) flattened ] -{ #category : #private } -GitlabModelImporter >> 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 : #'import - commits' } GitlabModelImporter >> commitsOfProject: aGLHProject forRefName: refName until: toDate [ @@ -114,12 +91,12 @@ GitlabModelImporter >> completeImportProject: aGLHProject [ importedProject repository: GLHRepository new. self glhModel add: importedProject repository. - self importRepository: importedProject repository. + self completeImportsOfRepository: importedProject repository. withInitialMergeRequest ifTrue: [ self - importMergeRequests: importedProject + importMergeRequestsOfProject: importedProject since: DateAndTime today until: DateAndTime now ]. @@ -143,6 +120,27 @@ GitlabModelImporter >> completeImportedCommit: aCommit [ ^ aCommit ] +{ #category : #'import - jobs' } +GitlabModelImporter >> completeImportedJob: aGLHJob [ + + aGLHJob commit ifNil: [ + |commit| + commit := self + importCommit: + (aGLHJob cacheAt: #commitID ifAbsent: [ '' ]) + ofProject: aGLHJob pipeline project. + aGLHJob commit: commit. ]. + + aGLHJob user ifNil: [ + |user| + user := self importUser: (aGLHJob cacheAt: #userID ifAbsent: [ '' ]). + aGLHJob user: user. + ]. + + + ^ aGLHJob +] + { #category : #'import - pipelines' } GitlabModelImporter >> completeImportedPipeline: aGLHPipeline [ |result parsedResult| @@ -191,12 +189,12 @@ GitlabModelImporter >> completeImportedProject: aGLHProject [ importedProject repository: GLHRepository new. self glhModel add: importedProject repository. - self importRepository: importedProject repository. + self completeImportsOfRepository: importedProject repository. withInitialMergeRequest ifTrue: [ self - importMergeRequests: importedProject + importMergeRequestsOfProject: importedProject since: DateAndTime today until: DateAndTime now ]. @@ -205,13 +203,46 @@ GitlabModelImporter >> completeImportedProject: aGLHProject [ ] +{ #category : #'import - repositories' } +GitlabModelImporter >> completeImportsOfRepository: aGLHRepository [ + + | branches | + [ + ('import the repository of project ' , aGLHRepository project name) + recordInfo. + branches := self importBranchesOf: aGLHRepository project. + self withFiles ifTrue: [ + branches do: [ :branch | self importFilesOfBranch: branch ] ] ] + on: NeoJSONParseError + do: [ + self inform: aGLHRepository project name , ' has no repository' ]. + + withInitialCommits ifTrue: [ + aGLHRepository branches do: [ :branch | + self importCommitsOfBranch: branch ] ]. + + ^ aGLHRepository +] + +{ #category : #'private - configure reader' } +GitlabModelImporter >> configureReaderForBranch: reader [ + + super configureReaderForBranch: reader. + + reader for: GLHBranch do: [ :mapping | + mapping + mapProperty: #commit + getter: [ ] + setter: [ :branch :rawCommit | branch sha: (rawCommit at: #id) ] ]. +] + { #category : #'private - configure reader' } GitlabModelImporter >> configureReaderForCommit: reader [ - reader for: GLHCommit do: [ :mapping | - mapping mapInstVars: - #( id short_id title author_name author_email committer_name - committer_email message web_url ). + super configureReaderForCommit: reader. + + reader for: GLHCommit do: [ :mapping | + (mapping mapInstVar: #authored_date) valueSchema: DateAndTime. (mapping mapInstVar: #committed_date) valueSchema: DateAndTime. (mapping mapInstVar: #created_at) valueSchema: DateAndTime. @@ -223,185 +254,195 @@ GitlabModelImporter >> configureReaderForCommit: reader [ commit deletions: (value at: #deletions). commit additions: (value at: #additions) ] ]. - reader for: DateAndTime customDo: [ :mapping | - mapping decoder: [ :string | DateAndTime fromString: string ] ]. - reader for: #ArrayOfIds - customDo: [ :mapping | mapping decoder: [ :string | string ] ]. - - reader - for: #ArrayOfCommit - customDo: [ :customMappting | - customMappting listOfElementSchema: GLHCommit ]. - + customDo: [ :mapping | mapping decoder: [ :string | string ] ] ] { #category : #'private - configure reader' } -GitlabModelImporter >> configureReaderForDiffs: reader [ - - reader for: GLHDiff do: [ :mapping | - mapping mapInstVars: - #( deleted_file new_file new_path old_path renamed_file ). - mapping mapInstVar: #diffString to: #diff ]. +GitlabModelImporter >> configureReaderForDiff: reader [ + super configureReaderForDiff: reader. reader - for: #ArrayOfDiffs - customDo: [ :customMappting | - customMappting listOfElementSchema: GLHDiff ]. + for: GLHDiff + do: [ :mapping | + "mapping mapInstVars: + #( deleted_file new_file new_path old_path renamed_file )." + mapping mapInstVar: #diffString to: #diff ]. + ^ reader ] { #category : #'private - configure reader' } GitlabModelImporter >> configureReaderForGroup: reader [ + super configureReaderForGroup: reader. + reader for: GLHGroup do: [ :mapping | - mapping mapInstVars. - (mapping mapInstVar: #projects) valueSchema: #ArrayOfProjects ]. - reader mapInstVarsFor: GLHProject. - reader - for: #ArrayOfProjects - customDo: [ :customMappting | - customMappting listOfElementSchema: GLHProject ]. + (mapping mapInstVar: #projects) valueSchema: #ArrayOfProject ] +] + +{ #category : #'private - configure reader' } +GitlabModelImporter >> configureReaderForJob: reader [ + + super configureReaderForJob: reader. + reader - for: #ArrayOfGroups - customDo: [ :customMappting | - customMappting listOfElementSchema: GLHGroup ] + for: GLHJob + do: [ :mapping | "(mapping mapInstVar: #user) valueSchema: GLHUser. + (mapping mapInstVar: #pipeline) valueSchema: GLHPipeline." + mapping + mapProperty: #user + getter: [ ] + setter: [ :job :rawUser | + job cacheAt: #userID put: (rawUser at: #id) ]. + + mapping + mapProperty: #pipeline + getter: [ ] + setter: [ :job :rawPipeline | + job cacheAt: #pipelineID put: (rawPipeline at: #id) ]. + + mapping + mapProperty: #commit + getter: [ ] + setter: [ :job :rawCommit | + job cacheAt: #commitID put: (rawCommit at: #id) ]. + + "mapping + mapProperty: #user + getter: [ :object | #ignore ] + setter: [ :object :value | + object user: (self importUser: (value at: #id)) ]." + + mapping + mapProperty: #duration + getter: [ :object | #ignore ] + setter: [ :object :value | + value ifNotNil: [ object duration: value seconds ] ] ] ] { #category : #'private - configure reader' } GitlabModelImporter >> configureReaderForMergeRequest: reader [ "declare quil y a un array a mapper" - - reader for: #ArrayOfMergeRequest customDo: [ :customMappting | - customMappting listOfElementSchema: GLHMergeRequest ]. + self flag: 'assignee.s must be parsed with nil condition'. + super configureReaderForMergeRequest: reader. "declare la liste des properties" - reader for: GLHMergeRequest do: [ :mapping | - mapping mapInstVars: - #( blocking_discussions_resolved changes_count description - detailed_merge_status discussion_locked downvotes draft first_deployed_to_production_at - force_remove_source_branch has_conflicts id iid labels latest_build_finished_at - latest_build_started_at merge_commit_sha merge_status - merge_when_pipeline_succeeds merged_at milestone project_id - reference references_full references_relative - references_short sha should_remove_source_branch - source_branch source_project_id squash squash_commit_sha - squash_on_merge state subscribed target_branch target_project_id - task_completion_status_completed_count - task_completion_status_count time_stats_human_time_estimate - time_stats_human_total_time_spent - time_stats_time_estimate time_stats_total_time_spent - title updated_at upvotes user_notes_count web_url work_in_progress ). - (mapping mapInstVar: #created_at) valueSchema: DateAndTime. - (mapping mapInstVar: #updated_at) valueSchema: DateAndTime. - (mapping mapInstVar: #merged_at) valueSchema: DateAndTime. - (mapping mapInstVar: #closed_at) valueSchema: DateAndTime. - "(mapping mapInstVar: #assignee) valueSchema: GLHUser." - mapping - mapProperty: #author - getter: [ ] - setter: [ :object :value | - object cacheAt: #authorID put: (value at: #id) ]. - mapping - mapProperty: #merge_user - getter: [ ] - setter: [ :object :value | - value ifNotNil: [ - object cacheAt: #mergeUserID put: (value at: #id) ] ] ]. + reader + for: GLHMergeRequest + do: [ :mapping | + + "(mapping mapInstVar: #assignee) valueSchema: GLHUser." + "(mapping mapInstVar: #assignees) valueSchema: #ArrayOfUser." + (mapping mapInstVar: #created_at) valueSchema: DateAndTime. + (mapping mapInstVar: #updated_at) valueSchema: DateAndTime. + (mapping mapInstVar: #merged_at) valueSchema: DateAndTime. + (mapping mapInstVar: #closed_at) valueSchema: DateAndTime. + + mapping + mapProperty: #author + getter: [ ] + setter: [ :object :value | + object cacheAt: #authorID put: (value at: #id) ]. + mapping + mapProperty: #merge_user + getter: [ ] + setter: [ :object :value | + value ifNotNil: [ + object cacheAt: #mergeUserID put: (value at: #id) ] ] ] +] - "(mapping mapInstVar: #closed_by) valueSchema: GLHUser. - (mapping mapInstVar: #mergeCommit) valueSchema: GLHCommit." - "indique ce que doit faire le reader lorsqu'il parse une DateAndTime object" - reader for: DateAndTime customDo: [ :mapping | - mapping decoder: [ :string | - string ifNil: [ nil ] ifNotNil: [ DateAndTime fromString: string ] ] ] +{ #category : #'private - parsing' } +GitlabModelImporter >> configureReaderForNote: reader [ + + super configureReaderForNote: reader. + + reader for: GLHNote do: [ :mapping | + + (mapping mapInstVar: #created_at) valueSchema: DateAndTime. + (mapping mapInstVar: #updated_at) valueSchema: DateAndTime ] ] { #category : #'private - configure reader' } GitlabModelImporter >> configureReaderForPipeline: reader [ - reader mapInstVarsFor: GLHPipeline. - - reader for: GLHPipeline do: [ :mapping | + super configureReaderForPipeline: reader. + reader for: GLHPipeline do: [ :mapping | mapping mapProperty: #created_at getter: [ :object | #ignore ] setter: [ :object :value | - object created_at: (value ifNotNil: [DateAndTime fromString: value]). - object runDate: (value ifNotNil: [DateAndTime fromString: value]) ]. - + object created_at: + (value ifNotNil: [ DateAndTime fromString: value ]). + object runDate: + (value ifNotNil: [ DateAndTime fromString: value ]) ]. + mapping mapProperty: #updated_at getter: [ :object | #ignore ] setter: [ :object :value | - object updated_at: (value ifNotNil: [DateAndTime fromString: value]). - ]. - + object updated_at: + (value ifNotNil: [ DateAndTime fromString: value ]) ]. + mapping mapProperty: #finished_at getter: [ :object | #ignore ] setter: [ :object :value | - object finished_at: (value ifNotNil: [DateAndTime fromString: value]). - ]. - + object finished_at: + (value ifNotNil: [ DateAndTime fromString: value ]) ]. + mapping - mapProperty: #started_at + mapProperty: #started_at getter: [ :object | #ignore ] setter: [ :object :value | - object started_at: (value ifNotNil: [DateAndTime fromString: value]). - ]. - + object started_at: + (value ifNotNil: [ DateAndTime fromString: value ]) ]. + mapping mapProperty: #source getter: [ :object | #ignore ] - setter: [ :object :value | - object sourceEvent: value. - ]. - + setter: [ :object :value | object sourceEvent: value ]. + mapping mapProperty: #duration getter: [ :object | #ignore ] setter: [ :object :value | - object duration: (value ifNotNil: [value asDuration]) . - ]. - + object duration: (value ifNotNil: [ value asDuration ]) ]. + mapping mapProperty: #user getter: [ :object | #ignore ] setter: [ :object :value | - value ifNotNil: [object cacheAt: #userID put: (value at: #id)]. - ]. - - ]. - - reader - for: #ArrayOfPipelines - customDo: [ :customMappting | - customMappting listOfElementSchema: GLHPipeline ]. + value ifNotNil: [ object cacheAt: #userID put: (value at: #id) ] ] ]. + ] { #category : #'private - configure reader' } -GitlabModelImporter >> configureReaderForReleases: reader [ +GitlabModelImporter >> configureReaderForProject: reader [ - reader mapInstVarsFor: GLHRelease . - - - reader for: GLHRelease do: [ :mapping | - - (mapping mapInstVar: #author) valueSchema: GLHUser . - ]. - + super configureReaderForProject: reader. + reader for: GLHProject do: [ :mapping | + mapping mapInstVar: #web_url to: #html_url. + ]. +] + +{ #category : #'private - configure reader' } +GitlabModelImporter >> configureReaderForRelease: reader [ + + super configureReaderForRelease: reader. + + reader - for: #ArrayOfReleases - customDo: [ :customMappting | - customMappting listOfElementSchema: GLHRelease ]. + for: GLHRelease + do: [ :mapping | (mapping mapInstVar: #author) valueSchema: GLHUser ]. + ] { #category : #'private - configure reader' } -GitlabModelImporter >> configureReaderForTags: reader [ +GitlabModelImporter >> configureReaderForTag: reader [ reader mapInstVarsFor: GLHTag . @@ -426,15 +467,10 @@ GitlabModelImporter >> configureReaderForTags: reader [ ] { #category : #'private - configure reader' } -GitlabModelImporter >> configureReaderForUsers: reader [ - - reader mapInstVarsFor: GLHUser. - - reader - for: #ArrayOfUser - customDo: [ :customMappting | - customMappting listOfElementSchema: GLHUser ]. +GitlabModelImporter >> configureReaderForUser: reader [ + super configureReaderForUser: reader + ] { #category : #private } @@ -529,14 +565,13 @@ GitlabModelImporter >> importAllGroups [ { #category : #'import - pipelines' } GitlabModelImporter >> importAllPipelinesOfProject: aGLHProject [ - + (self allPipelinesOf: aGLHProject id) do: [ :pipeline | - |pip| - pip := self glhModel add: pipeline unless: self blockOnIdEquality . + | pip | + pip := self glhModel add: pipeline unless: self blockOnIdEquality. pip := aGLHProject pipelines add: pip unless: self blockOnIdEquality. - self completeImportedPipeline: pip. - ]. - + self completeImportedPipeline: pip ]. + ^ aGLHProject pipelines ] @@ -545,32 +580,44 @@ GitlabModelImporter >> importAndLoadLatestsCommitsOfProject: aGLHProject [ | commits completedProject | completedProject := self completeImportedProject: aGLHProject. - commits := self importLastestCommitsOfProject: completedProject. + commits := self importLatestCommitsOfProject: completedProject. commits do: [ :commit | self completeImportedCommit: commit ]. self chainsCommitsFrom: commits. ^ commits ] -{ #category : #'import - user' } -GitlabModelImporter >> importAuthorOfCommit: aGLHCommit [ - |user| - user:= (self importUserByUsername: aGLHCommit author_name) . - aGLHCommit commitCreator: user. +{ #category : #'import - users' } +GitlabModelImporter >> importAuthorOfCommit: aGLHCommit [ + + | user | + self + deprecated: 'Use importCreatorOfCommit: instead of current one' + on: '19 September 2025' + in: + 'Pharo-12.0.0+SNAPSHOT.build.1571.sha.cf5fcd22e66957962c97dffc58b0393b7f368147 (64 Bit)'. + + + user := self importUserByUsername: aGLHCommit author_name. + aGLHCommit commitCreator: user. ^ user ] -{ #category : #'import - repositories' } +{ #category : #'import - branches' } GitlabModelImporter >> importBranchesOf: aGLHProject [ | resultBranches branches foundBranches | "aGLHProject repository branches removeAll " + self + deprecated: 'Use importBranchesOfProject: instead of current one' + on: '26 September 2025' + in: + 'Pharo-12.0.0+SNAPSHOT.build.1571.sha.cf5fcd22e66957962c97dffc58b0393b7f368147 (64 Bit)'. resultBranches := self repoApi branches getAllFromProject: aGLHProject id. foundBranches := (resultBranches collect: [ :branchesJson | - self - parseBranchesResult: branchesJson - ofProject: aGLHProject ]) flattened. + self parseBranchesResult: branchesJson ]) + flattened. 'import the branches of project ' recordInfo. @@ -579,19 +626,40 @@ GitlabModelImporter >> importBranchesOf: aGLHProject [ addAll: foundBranches unless: self blockOnNameEquality. - foundBranches do: [ :fb | - branches do: [ :b | - fb name = b name ifTrue: [ - b commits addAll: fb commits unless: self blockOnIdEquality ] ] ]. branches := self glhModel addAll: branches unless: self blockForBranchEquality. - branches do: [ :b | - b commits do: [ :c | - b repository commits add: c unless: self blockOnIdEquality ] ]. + "WARNING : branch must load its HEAD commit (ref) in a second time " + ^ branches +] + +{ #category : #'import - branches' } +GitlabModelImporter >> importBranchesOfProject: aGLHProject [ + | resultBranches branches foundBranches | + "aGLHProject repository branches removeAll " + resultBranches := self repoApi branches getAllFromProject: + aGLHProject id. + + foundBranches := (resultBranches collect: [ :branchesJson | + self parseBranchesResult: branchesJson ]) + flattened. + + 'import the branches of project ' recordInfo. + + "WARNING: always add branch first into repository, than into model !" + branches := aGLHProject repository branches + addAll: foundBranches + unless: self blockOnNameEquality. + + + branches := self glhModel + addAll: branches + unless: self blockForBranchEquality. + + "WARNING : branch must load its HEAD commit (ref) in a second time " ^ branches ] @@ -662,11 +730,20 @@ GitlabModelImporter >> importCommits: aGLHProject [ "limited to the last 20 commits" | results parsedResults params | - params := { - #with_stats -> 'true' - } asDictionary. - results := self repoApi commits getByPage: 1 perPage: 20 inProject: aGLHProject id withParams: params. - + self + deprecated: + 'Use importLatestCommitsOfProject: instead of current one' + on: '19 September 2025' + in: + 'Pharo-12.0.0+SNAPSHOT.build.1571.sha.cf5fcd22e66957962c97dffc58b0393b7f368147 (64 Bit)'. + + params := { (#with_stats -> 'true') } asDictionary. + results := self repoApi commits + getByPage: 1 + perPage: 20 + inProject: aGLHProject id + withParams: params. + parsedResults := self parseCommitsResult: results. self glhModel addAll: parsedResults unless: self blockOnIdEquality. @@ -675,8 +752,8 @@ GitlabModelImporter >> importCommits: aGLHProject [ self withCommitDiffs ifTrue: [ parsedResults do: [ :commit | self importDiffOfCommit: commit ] ]. - - ^ parsedResults. + + ^ parsedResults ] { #category : #'import - commits' } @@ -889,18 +966,6 @@ GitlabModelImporter >> importContributedProjectsOfUser: aGLHUser [ ^ projects ] -{ #category : #'import - commits' } -GitlabModelImporter >> importCreatorOfCommit: aCommit [ - - aCommit commitCreator ifNil: [ - aCommit commitCreator: - (self importUserByUsername: aCommit author_name) ]. - self userCatalogue - addUser: aCommit commitCreator - withProject: aCommit repository project id. - ^ aCommit commitCreator -] - { #category : #'import - commits' } GitlabModelImporter >> importDiffOfCommit: aCommit [ @@ -926,7 +991,7 @@ GitlabModelImporter >> importDiffOfCommit: aCommit [ ^ aCommit diffs ] -{ #category : #'import - merge request' } +{ #category : #'import - merge-requests' } GitlabModelImporter >> importDiffOfMergeRequest: aMergeRequest [ | result diffsResult | @@ -981,6 +1046,12 @@ GitlabModelImporter >> importDirectoryFiles: aDirectoryFile OfBranch: aBranch [ self importDirectoryFiles: file OfBranch: aBranch ] ] +{ #category : #'import - file' } +GitlabModelImporter >> importFileWithPath: aPath ofProject: aGLHProject inBranch: aBranch [ + self flag: 'imported file need to be store inside the model'. + ^ self repoApi repositories getRawFile: aPath ofProject: aGLHProject id withParams: {#ref -> aBranch name} asDictionary . +] + { #category : #'import - repositories' } GitlabModelImporter >> importFilesOfBranch: aBranch [ @@ -1003,7 +1074,9 @@ GitlabModelImporter >> importFilesOfBranch: aBranch [ files select: [ :file | file isKindOf: GLHFileDirectory ] thenCollect: [ :file | - self importDirectoryFiles: file OfBranch: aBranch ] + self importDirectoryFiles: file OfBranch: aBranch ]. + + ^ files ] { #category : #'import - groups' } @@ -1032,6 +1105,18 @@ GitlabModelImporter >> importGroup: aGroupID [ { #category : #'import - jobs' } GitlabModelImporter >> importJobsOf: aPipeline [ + + self + deprecated: 'Use importJobsOfPipeline: instead of current one' + on: '26 September 2025' + in: + 'Pharo-12.0.0+SNAPSHOT.build.1571.sha.cf5fcd22e66957962c97dffc58b0393b7f368147 (64 Bit)'. + ^ self importJobsOfPipeline: aPipeline. +] + +{ #category : #'import - jobs' } +GitlabModelImporter >> importJobsOfPipeline: aPipeline [ + | jobs results | results := self repoApi jobs getAllForPipeline: aPipeline id @@ -1039,16 +1124,20 @@ GitlabModelImporter >> importJobsOf: aPipeline [ "jobsOfProject: aPipeline project id ofPipelines: aPipeline id." jobs := (results collect: [ :jobsJson | - self parseJobsResult: jobsJson ofProject: aPipeline project ]) - flattened. - jobs do: [ :job | aPipeline addJob: job ]. - self glhModel addAll: jobs. + self parseJobsResult: jobsJson ]) flattened. + + + jobs := self glhModel addAll: jobs unless: self blockOnIdEquality. + jobs := aPipeline jobs addAll: jobs unless: self blockOnIdEquality. + + + jobs do: [ :job | self completeImportedJob: job ]. ^ jobs ] { #category : #'import - commits' } -GitlabModelImporter >> importLastestCommitsOfProject: aGLHProject [ +GitlabModelImporter >> importLatestCommitsOfProject: aGLHProject [ "limited to the last 50 commits" | results parsedResults params | @@ -1073,7 +1162,7 @@ GitlabModelImporter >> importLastestCommitsOfProject: aGLHProject [ ^ parsedResults ] -{ #category : #'import - merge request' } +{ #category : #'import - merge-requests' } GitlabModelImporter >> importLatestMergeRequestsOfProject: aGLHProject [ |results parsedResults| @@ -1097,7 +1186,7 @@ GitlabModelImporter >> importLatestPipelinesOfProject: aGLHProject [ ^ aGLHProject pipelines ] -{ #category : #'import - release' } +{ #category : #'import - releases' } GitlabModelImporter >> importLatestReleaseOfProject: aGLHProject [ |result foundRelease| @@ -1112,7 +1201,7 @@ GitlabModelImporter >> importLatestReleaseOfProject: aGLHProject [ ^ foundRelease. ] -{ #category : #'import - merge request' } +{ #category : #'import - commits' } GitlabModelImporter >> importMergeRequestCommits: aGLPHEMergeRequest [ | commits result | @@ -1128,7 +1217,7 @@ GitlabModelImporter >> importMergeRequestCommits: aGLPHEMergeRequest [ ^ commits ] -{ #category : #'import - merge request' } +{ #category : #'import - commits' } GitlabModelImporter >> importMergeRequestMergeCommits: aGLPHEMergeRequest [ | foundCommits | @@ -1162,23 +1251,22 @@ GitlabModelImporter >> importMergeRequestMergeCommits: aGLPHEMergeRequest [ ] { #category : #'import - pipelines' } -GitlabModelImporter >> importMergeRequestPipelines: aGLHMergeRequest [ +GitlabModelImporter >> importMergeRequestPipelines: aGLHMergeRequest [ "default limit to one page with last 100 pipelines" - - |results parseResults| - - results := self repoApi pipelines getByPage: 1 perPage: 100 inProject: aGLHMergeRequest project id forMergerRequestIid: aGLHMergeRequest iid. - - parseResults := self parsePipelinesResult: results. - - parseResults := glhModel addAll: parseResults unless: self blockOnIdEquality. - parseResults := aGLHMergeRequest pipelines addAll: parseResults unless: self blockOnIdEquality. - ^ parseResults collect: [ :pip | self completeImportedPipeline: pip ] . - + + | results parseResults | + self + deprecated: + 'Use importPipelinesOfMergeRequest: instead of current one' + on: '23 September 2025' + in: + 'Pharo-12.0.0+SNAPSHOT.build.1571.sha.cf5fcd22e66957962c97dffc58b0393b7f368147 (64 Bit)'. + + ^ self importPipelinesOfMergeRequest: aGLHMergeRequest. ] -{ #category : #'import - merge request' } -GitlabModelImporter >> importMergeRequests: aGLHProject [ +{ #category : #'import - merge-requests' } +GitlabModelImporter >> importMergeRequestsOfProject: aGLHProject [ | results parsedResults mrs | ('Import merge request of Project: ' , aGLHProject id printString) @@ -1208,8 +1296,8 @@ GitlabModelImporter >> importMergeRequests: aGLHProject [ ^ mrs ] -{ #category : #'import - merge request' } -GitlabModelImporter >> importMergeRequests: aGLHProject since: fromDate until: toDate [ +{ #category : #'import - merge-requests' } +GitlabModelImporter >> importMergeRequestsOfProject: aGLHProject since: fromDate until: toDate [ | params result mergeRequests | ('import MR of Project ' , aGLHProject name) recordInfo. @@ -1252,7 +1340,7 @@ GitlabModelImporter >> importMergeRequests: aGLHProject since: fromDate until: t ^ mergeRequests ] -{ #category : #'import - merge request' } +{ #category : #'import - merge-requests' } GitlabModelImporter >> importMergeResquestApprovals: aGLPHEMergeRequest [ | results parsedResult | @@ -1272,7 +1360,7 @@ GitlabModelImporter >> importMergeResquestApprovals: aGLPHEMergeRequest [ ^ aGLPHEMergeRequest ] -{ #category : #'import - merge request' } +{ #category : #'import - merge-requests' } GitlabModelImporter >> importMergeResquestAuthor: aGLPHEMergeRequest [ | authorID | @@ -1289,7 +1377,7 @@ GitlabModelImporter >> importMergeResquestAuthor: aGLPHEMergeRequest [ ^aGLPHEMergeRequest author: (self importUser: authorID) ] -{ #category : #'import - merge request' } +{ #category : #'import - merge-requests' } GitlabModelImporter >> importMergeResquestMerger: aGLPHEMergeRequest [ | authorID | @@ -1310,7 +1398,7 @@ GitlabModelImporter >> importMergeResquestMerger: aGLPHEMergeRequest [ ] { #category : #'import - notes' } -GitlabModelImporter >> importNotesfromMergeRequest: mergeRequest [ +GitlabModelImporter >> importNotesOfMergeRequest: mergeRequest [ | results notes | results := self repoApi notes allInMergeRequest: mergeRequest iid ofProject: mergeRequest project id. @@ -1362,8 +1450,7 @@ GitlabModelImporter >> importPipeline: pipelineId OfProject: aGLHProject [ ('Search pipelines of: ' , aGLHProject id printString) recordInfo. result := self repoApi pipelines get: pipelineId inProject: aGLHProject id. - result isString ifTrue: [ ^ self parsePipelineResult: result ]. - + pipeline := self parsePipelineResult: result. pipeline := self glhModel add: pipeline unless: self blockOnIdEquality . @@ -1372,6 +1459,49 @@ GitlabModelImporter >> importPipeline: pipelineId OfProject: aGLHProject [ ^ self completeImportedPipeline: pipeline. ] +{ #category : #'import - pipelines' } +GitlabModelImporter >> importPipelinesOfMergeRequest: aGLHMergeRequest [ + "default limit to one page with last 100 pipelines" + + | results parseResults | + results := self repoApi pipelines + getByPage: 1 + perPage: 100 + inProject: aGLHMergeRequest project id + forMergerRequestIid: aGLHMergeRequest iid. + + parseResults := self parsePipelinesResult: results. + + parseResults do: [ :pipeline | + pipeline project: aGLHMergeRequest project. + ]. + + parseResults := glhModel + addAll: parseResults + unless: self blockOnIdEquality. + parseResults := aGLHMergeRequest pipelines + addAll: parseResults + unless: self blockOnIdEquality. + + + ^ parseResults collect: [ :pip | self completeImportedPipeline: pip ] +] + +{ #category : #'import - pipelines' } +GitlabModelImporter >> importPipelinesOfProject: aGLHProject [ + + self + deprecated: + 'Use importAllPipelinesOfProject: instead of current one' + on: '23 September 2025' + in: + 'Pharo-12.0.0+SNAPSHOT.build.1571.sha.cf5fcd22e66957962c97dffc58b0393b7f368147 (64 Bit)'. + + self flag: + 'WARNING: this import ALL the pipelines at ones. Prefered ImportLatestPipleinesOfProject: for faster performance (if possible)'. + ^ self importAllPipelinesOfProject: aGLHProject +] + { #category : #'import - pipelines' } GitlabModelImporter >> importPipelinesOfProject: aGLHProject after: after andBefore: before [ ^ (self pipelinesOf: aGLHProject id after: after andBefore: before) collect: [ :pipeline | @@ -1464,47 +1594,30 @@ GitlabModelImporter >> importProjectsSince: since [ foundProject addAll: newlyFoundProjects ]. ] -{ #category : #'import - repositories' } -GitlabModelImporter >> importRepository: aGLHRepository [ - - | branches | - [ - ('import the repository of project ' , aGLHRepository project name) - recordInfo. - branches := self importBranchesOf: aGLHRepository project. - self withFiles ifTrue: [ - branches do: [ :branch | self importFilesOfBranch: branch ] ] ] - on: NeoJSONParseError - do: [ - self inform: aGLHRepository project name , ' has no repository' ]. - - withInitialCommits ifTrue: [ - aGLHRepository branches do: [ :branch | - self importCommitsOfBranch: branch ] ] -] - -{ #category : #'as yet unclassified' } +{ #category : #'import - commits' } GitlabModelImporter >> importSZZFromCommit: aCommit [ - | result diffRanges diffs szzCommits| - szzCommits := Set new. - diffs := (self importDiffOfCommit: aCommit). + | diffRanges diffs szzCommits | + szzCommits := Set new. + diffs := self importDiffOfCommit: aCommit. diffRanges := diffs flatCollect: #diffRanges. diffRanges do: [ :range | - |blames| - - blames := NeoJSONReader fromString:( self repoApi repositories getBlameOf: range diff new_path inRef: aCommit id start: range start end:range end ofProject: (aCommit repository project id)). - blames collect: [ :blame | - blame isDictionary ifTrue: [ szzCommits add: (self importCommit:(blame at: #commit at: #id) ofProject: aCommit repository project). ] - - ] - - ]. - ^ szzCommits . - -] - -{ #category : #'import - tag' } + | blames | + blames := NeoJSONReader fromString: (self repoApi repositories + getBlameOf: range diff new_path + inRef: aCommit id + start: range start + end: range end + ofProject: aCommit repository project id). + blames collect: [ :blame | + blame isDictionary ifTrue: [ + szzCommits add: (self + importCommit: (blame at: #commit at: #id) + ofProject: aCommit repository project) ] ] ]. + ^ szzCommits +] + +{ #category : #'import - tags' } GitlabModelImporter >> importTagsForProject: aProject [ |results tags | results := repoApi tags getAllOfProject: aProject id. @@ -1609,16 +1722,9 @@ GitlabModelImporter >> importUserByUsername: anUsername [ { #category : #initialization } GitlabModelImporter >> initReader [ - - generalReader := NeoJSONReader new. - self configureReaderForCommit: generalReader. - self configureReaderForGroup: generalReader. - self configureReaderForDiffs: generalReader. - self configureReaderForMergeRequest: generalReader. - self configureReaderForPipeline: generalReader. - self configureReaderForTags: generalReader. - self configureReaderForReleases: generalReader. - self configureReaderForUsers: generalReader. + + "add specific reader for this importer here" + super initReader ] { #category : #initialization } @@ -1631,7 +1737,7 @@ GitlabModelImporter >> initialize [ self withCommitsSince: 1 week. - self initReader + ] { #category : #private } @@ -1659,32 +1765,39 @@ GitlabModelImporter >> newParseCommitResult: result [ GitlabModelImporter >> newParseDiffResult: result [ generalReader on: result readStream. - ^ generalReader nextAs: #ArrayOfDiffs + ^ generalReader nextAs: #ArrayOfDiff ] { #category : #'private - parsing' } GitlabModelImporter >> parseArrayOfProject: arrayOfProjects [ | reader | - reader := NeoJSONReader on: arrayOfProjects readStream. - reader - for: #ArrayOfProjects - customDo: [ :customMappting | - customMappting listOfElementSchema: GLHProject ]. - 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: #ArrayOfProjects + reader := generalReader on: arrayOfProjects readStream. + + ^ reader nextAs: #ArrayOfProject +] + +{ #category : #'private - parsing' } +GitlabModelImporter >> parseBranchesResult: result [ + + | reader | + reader := generalReader on: result readStream. + + ^ reader nextAs: #ArrayOfBranch ] { #category : #'private - parsing' } GitlabModelImporter >> parseBranchesResult: result ofProject: aGLHProject [ | reader | + self flag: 'WARNING: do not use the importer inside a parsing process. do it after using a object cached on the sub elemnt id'. + self + deprecated: 'Use parseBranchesResult: instead of current one' + on: '23 September 2025' + in: + 'Pharo-12.0.0+SNAPSHOT.build.1571.sha.cf5fcd22e66957962c97dffc58b0393b7f368147 (64 Bit)'. + + reader := NeoJSONReader on: result readStream. reader mapInstVarsFor: GLHBranch. @@ -1693,11 +1806,11 @@ GitlabModelImporter >> parseBranchesResult: result ofProject: aGLHProject [ mapProperty: #commit getter: [ ] setter: [ :branch :rawCommit | - | commit | - commit := self + branch sha: (rawCommit at: #id) + "commit := self importCommit: (rawCommit at: #id) ofProject: aGLHProject. - branch commits add: commit unless: self blockOnIdEquality ] ]. + branch commits add: commit unless: self blockOnIdEquality " ] ]. reader for: #ArrayOfBranch @@ -1711,30 +1824,7 @@ GitlabModelImporter >> parseBranchesResult: result ofProject: aGLHProject [ GitlabModelImporter >> parseCommitResult: result [ | reader | - reader := NeoJSONReader on: result readStream. - - reader for: GLHCommit do: [ :mapping | - mapping mapInstVars: - #( id short_id title author_name author_email committer_name - committer_email message web_url ). - (mapping mapInstVar: #authored_date) valueSchema: DateAndTime. - (mapping mapInstVar: #committed_date) valueSchema: DateAndTime. - (mapping mapInstVar: #created_at) valueSchema: DateAndTime. - (mapping mapInstVar: #parent_ids) valueSchema: #ArrayOfIds. - mapping - mapProperty: 'stats' - getter: [ :el | "Not used" ] - setter: [ :commit :value | - commit deletions: (value at: #deletions). - commit additions: (value at: #additions) ] ]. - - reader for: DateAndTime customDo: [ :mapping | - mapping decoder: [ :string | DateAndTime fromString: string ] ]. - - reader - for: #ArrayOfIds - customDo: [ :mapping | mapping decoder: [ :string | string ] ]. - + reader := generalReader on: result readStream. ^ reader nextAs: GLHCommit ] @@ -1743,34 +1833,7 @@ GitlabModelImporter >> parseCommitResult: result [ GitlabModelImporter >> parseCommitsResult: result [ | reader | - reader := NeoJSONReader on: result readStream. - - reader for: GLHCommit do: [ :mapping | - mapping mapInstVars: - #( id short_id title author_name author_email committer_name - committer_email message web_url ). - (mapping mapInstVar: #authored_date) valueSchema: DateAndTime. - (mapping mapInstVar: #committed_date) valueSchema: DateAndTime. - (mapping mapInstVar: #created_at) valueSchema: DateAndTime. - (mapping mapInstVar: #parent_ids) valueSchema: #ArrayOfIds. - mapping - mapProperty: 'stats' - getter: [ :el | "Not used" ] - setter: [ :commit :value | - commit deletions: (value at: #deletions). - commit additions: (value at: #additions) ] ]. - - reader for: DateAndTime customDo: [ :mapping | - mapping decoder: [ :string | DateAndTime fromString: string ] ]. - - reader - for: #ArrayOfIds - customDo: [ :mapping | mapping decoder: [ :string | string ] ]. - - reader - for: #ArrayOfCommit - customDo: [ :customMappting | - customMappting listOfElementSchema: GLHCommit ]. + reader := generalReader on: result readStream. ^ reader nextAs: #ArrayOfCommit ] @@ -1814,52 +1877,41 @@ GitlabModelImporter >> parseFileTreeResult: aResult [ GitlabModelImporter >> parseGroupResult: aResult [ | reader | + reader := generalReader on: aResult readStream. - reader := NeoJSONReader on: aResult readStream. - reader for: GLHGroup do: [ :mapping | - mapping mapInstVars. - (mapping mapInstVar: #projects) valueSchema: #ArrayOfProjects ]. - reader mapInstVarsFor: GLHProject. - reader - for: #ArrayOfProjects - customDo: [ :customMappting | - customMappting listOfElementSchema: GLHProject ]. ^ reader nextAs: GLHGroup ] +{ #category : #'private - parsing' } +GitlabModelImporter >> parseJobsResult: result [ + | reader | + reader := generalReader on: result readStream. + + ^ reader nextAs: #ArrayOfJob +] + { #category : #'private - parsing' } GitlabModelImporter >> parseJobsResult: result ofProject: aProject [ | reader | - reader := NeoJSONReader on: result readStream. + self + deprecated: 'Use parseJobsResult: instead of current one' + on: '23 September 2025' + in: + 'Pharo-12.0.0+SNAPSHOT.build.1571.sha.cf5fcd22e66957962c97dffc58b0393b7f368147 (64 Bit)'. + + reader := generalReader on: result readStream. reader for: GLHJob do: [ :mapping | - mapping mapInstVars: #( id allow_failure web_url name ). - - mapping - mapProperty: #user - getter: [ :object | #ignore ] - setter: [ :object :value | - object user: (self importUser: (value at: #id)) ]. - mapping mapProperty: #commit getter: [ :object | #ignore ] setter: [ :object :value | value ifNotNil: [ object commit: - (self importCommit: (value at: #id) ofProject: aProject) ] ]. + (self importCommit: (value at: #id) ofProject: aProject) ] ] ]. - mapping - mapProperty: #duration - getter: [ :object | #ignore ] - setter: [ :object :value | - value ifNotNil: [ object duration: value seconds ] ] ]. - reader - for: #ArrayOfGLHJob - customDo: [ :customMappting | - customMappting listOfElementSchema: GLHJob ]. - ^ reader nextAs: #ArrayOfGLHJob + ^ reader nextAs: #ArrayOfJob ] { #category : #'private - parsing' } @@ -1870,36 +1922,19 @@ GitlabModelImporter >> parseMergeRequestsResult: result [ ] { #category : #'private - parsing' } -GitlabModelImporter >> parseNoteJson: results [ - | reader | +GitlabModelImporter >> parseNoteJson: results [ - "Créer un lecteur JSON" - reader := NeoJSONReader on: results readStream. - - "Définir le mapping pour l'objet GLHNote" - reader for: GLHNote do: [ :mapping | - mapping mapInstVars: #(id noteable_id attachment system confidential internal - noteable_iid resolvable imported imported_from - author body project_id noteable_type). - - (mapping mapInstVar: #created_at) valueSchema: DateAndTime. - (mapping mapInstVar: #updated_at) valueSchema: DateAndTime. - ]. - - "Corriger la conversion des dates" - reader for: DateAndTime customDo: [ :mapping | - mapping decoder: [ :string | DateAndTime readFrom: string readStream ] ]. - - reader - for: #ArrayOfNote - customDo: [ :customMappting | - customMappting listOfElementSchema: GLHNote ]. - ^ reader nextAs: #ArrayOfNote - - "Retourner la Note" - "^ reader nextAs: GLHNote" + | reader | + "Créer un lecteur JSON" + reader := generalReader on: results readStream. + "Corriger la conversion des dates" + "reader for: DateAndTime customDo: [ :mapping | + mapping decoder: [ :string | + DateAndTime readFrom: string readStream ] ]." + + ^ reader nextAs: #ArrayOfNote ] { #category : #'private - parsing' } @@ -1918,26 +1953,23 @@ GitlabModelImporter >> parsePipelineResult: result [ GitlabModelImporter >> parsePipelinesResult: result [ | reader | - - (result includesSubstring: '{"message":"40' )ifTrue: [ ^ { } ]. - + (result includesSubstring: '{"message":"40') ifTrue: [ ^ { } ]. + reader := generalReader on: result readStream. - - ^ reader nextAs: #ArrayOfPipelines + + ^ reader nextAs: #ArrayOfPipeline ] { #category : #'private - parsing' } -GitlabModelImporter >> parseProjectResult: aResult [ - | reader | - reader := NeoJSONReader on: aResult readStream. - reader for: GLHProject do: [ :mapping | - mapping mapInstVars. ]. -" reader mapInstVarsFor: GLHProject." +GitlabModelImporter >> parseProjectResult: aResult [ + + | reader | + reader := generalReader on: aResult readStream. ^ reader nextAs: GLHProject ] -{ #category : #parsing } +{ #category : #'private - parsing' } GitlabModelImporter >> parseReleaseResult: result [ |reader| reader := generalReader on: result readStream. @@ -1945,24 +1977,25 @@ GitlabModelImporter >> parseReleaseResult: result [ ^ reader nextAs: GLHRelease ] -{ #category : #parsing } +{ #category : #'private - parsing' } GitlabModelImporter >> parseReleasesResult: result [ - |reader| + + | reader | reader := generalReader on: result readStream. - - ^ reader nextAs: #ArrayOfReleases + + ^ reader nextAs: #ArrayOfRelease ] { #category : #'private - parsing' } GitlabModelImporter >> parseSubGroupResult: aResult [ | reader | - reader := NeoJSONReader on: aResult readStream. - self configureReaderForGroup: reader. - ^ reader nextAs: #ArrayOfGroups + reader := generalReader on: aResult readStream. + + ^ reader nextAs: #ArrayOfGroup ] -{ #category : #parsing } +{ #category : #'private - parsing' } GitlabModelImporter >> parseTagsResult: result [ |reader| reader := generalReader on: result readStream. @@ -2009,7 +2042,7 @@ GitlabModelImporter >> partiallyImportProject: aProjectID [ projectResult repository: GLHRepository new. self glhModel add: projectResult repository. - self importRepository: projectResult repository. + self completeImportsOfRepository: projectResult repository. ^ projectResult ] diff --git a/src/GitLabHealth-Model/GLHBranch.class.st b/src/GitLabHealth-Model/GLHBranch.class.st index 0b217803..dacc3849 100644 --- a/src/GitLabHealth-Model/GLHBranch.class.st +++ b/src/GitLabHealth-Model/GLHBranch.class.st @@ -25,14 +25,16 @@ A git branch | Name | Type | Default value | Comment | |---| -| `name` | `String` | nil | | +| `name` | `String` | nil | Basic name of the entity, not full reference.| +| `sha` | `String` | nil | | " Class { #name : #GLHBranch, #superclass : #GLHEntity, + #traits : 'GLHTRef', + #classTraits : 'GLHTRef classTrait', #instVars : [ - '#name => FMProperty', '#repository => FMOne type: #GLHRepository opposite: #branches', '#files => FMMany type: #GLHFile opposite: #branch', '#commits => FMMany type: #GLHCommit opposite: #branch' @@ -100,20 +102,6 @@ GLHBranch >> filesGroup [ ^ MooseSpecializedGroup withAll: self files asSet ] -{ #category : #accessing } -GLHBranch >> name [ - - - - ^ name -] - -{ #category : #accessing } -GLHBranch >> name: anObject [ - - name := anObject -] - { #category : #accessing } GLHBranch >> repository [ "Relation named: #repository type: #GLHRepository opposite: #branches" diff --git a/src/GitLabHealth-Model/GLHCommit.class.st b/src/GitLabHealth-Model/GLHCommit.class.st index 401d7f4b..13d2c100 100644 --- a/src/GitLabHealth-Model/GLHCommit.class.st +++ b/src/GitLabHealth-Model/GLHCommit.class.st @@ -46,6 +46,7 @@ a commit attached to a repository | `message` | `String` | nil | | | `name` | `String` | nil | Basic name of the entity, not full reference.| | `parent_ids` | `Object` | 'OrderedCollection new' | | +| `sha` | `String` | nil | | | `short_id` | `String` | nil | | | `title` | `String` | nil | | | `web_url` | `String` | nil | | @@ -54,8 +55,8 @@ a commit attached to a repository Class { #name : #GLHCommit, #superclass : #GLHEntity, - #traits : 'FamixTNamedEntity', - #classTraits : 'FamixTNamedEntity classTrait', + #traits : 'FamixTNamedEntity + GLHTRef', + #classTraits : 'FamixTNamedEntity classTrait + GLHTRef classTrait', #instVars : [ '#parent_ids => FMProperty defaultValue: \'OrderedCollection new\'', '#id => FMProperty', diff --git a/src/GitLabHealth-Model/GLHEntity.class.st b/src/GitLabHealth-Model/GLHEntity.class.st index f5ed0647..61e3a593 100644 --- a/src/GitLabHealth-Model/GLHEntity.class.st +++ b/src/GitLabHealth-Model/GLHEntity.class.st @@ -43,3 +43,10 @@ GLHEntity >> isDeletion [ ^ false ] + +{ #category : #testing } +GLHEntity >> isRef [ + + + ^ false +] diff --git a/src/GitLabHealth-Model/GLHGroupGroup.class.st b/src/GitLabHealth-Model/GLHGroupGroup.class.st index e518f32b..6959d043 100644 --- a/src/GitLabHealth-Model/GLHGroupGroup.class.st +++ b/src/GitLabHealth-Model/GLHGroupGroup.class.st @@ -40,3 +40,10 @@ GLHGroupGroup >> isQueryable [ ^ false ] + +{ #category : #testing } +GLHGroupGroup >> isRef [ + + + ^ false +] diff --git a/src/GitLabHealth-Model/GLHIssue.class.st b/src/GitLabHealth-Model/GLHIssue.class.st index 8935e3aa..2d6fc7bb 100644 --- a/src/GitLabHealth-Model/GLHIssue.class.st +++ b/src/GitLabHealth-Model/GLHIssue.class.st @@ -7,14 +7,14 @@ an Issues help collaboration within a team to plan, track, and deliver work ### Parents | Relation | Origin | Opposite | Type | Comment | |---| +| `author` | `GLHIssue` | `createdIssue` | `GLHUser` | | | `milestone` | `GLHIssue` | `issue` | `GLHMilestone` | | -| `project` | `GLHIssue` | `issue` | `GLHProject` | | +| `project` | `GLHIssue` | `issues` | `GLHProject` | | ### Children | Relation | Origin | Opposite | Type | Comment | |---| | `assignees` | `GLHIssue` | `assignedIssue` | `GLHUser` | | -| `author` | `GLHIssue` | `createdIssue` | `GLHUser` | | ## Properties @@ -47,7 +47,7 @@ Class { '#updated_at => FMProperty', '#closed_at => FMProperty', '#due_date => FMProperty', - '#project => FMOne type: #GLHProject opposite: #issue', + '#project => FMOne type: #GLHProject opposite: #issues', '#assignees => FMMany type: #GLHUser opposite: #assignedIssue', '#author => FMOne type: #GLHUser opposite: #createdIssue', '#milestone => FMOne type: #GLHMilestone opposite: #issue' @@ -98,6 +98,7 @@ GLHIssue >> author [ "Relation named: #author type: #GLHUser opposite: #createdIssue" + ^ author ] @@ -224,7 +225,7 @@ GLHIssue >> name: anObject [ { #category : #accessing } GLHIssue >> project [ - "Relation named: #project type: #GLHProject opposite: #issue" + "Relation named: #project type: #GLHProject opposite: #issues" diff --git a/src/GitLabHealth-Model/GLHJob.class.st b/src/GitLabHealth-Model/GLHJob.class.st index b50f9f3d..bed62ed5 100644 --- a/src/GitLabHealth-Model/GLHJob.class.st +++ b/src/GitLabHealth-Model/GLHJob.class.st @@ -20,8 +20,8 @@ A CI Job | `allow_failure` | `Boolean` | nil | | | `duration` | `Object` | nil | | | `id` | `Number` | nil | | -| `name` | `String` | nil | | | `name` | `String` | nil | Basic name of the entity, not full reference.| +| `name` | `String` | nil | | | `ref` | `String` | nil | | | `web_url` | `String` | nil | | diff --git a/src/GitLabHealth-Model/GLHMergeRequest.class.st b/src/GitLabHealth-Model/GLHMergeRequest.class.st index 99a9b6a2..00141b14 100644 --- a/src/GitLabHealth-Model/GLHMergeRequest.class.st +++ b/src/GitLabHealth-Model/GLHMergeRequest.class.st @@ -13,7 +13,7 @@ a gitlab merge request ### Children | Relation | Origin | Opposite | Type | Comment | |---| -| `pipelines` | `GLHMergeRequest` | `mergeResquest` | `GLHPipeline` | | +| `pipelines` | `GLHMergeRequest` | `mergeRequest` | `GLHPipeline` | | ### Other | Relation | Origin | Opposite | Type | Comment | @@ -29,7 +29,7 @@ a gitlab merge request | `mergedCommit` | `GLHMergeRequest` | `commitedMergeRequest` | `GLHCommit` | | | `merged_by` | `GLHMergeRequest` | `mergerOfMergeRequests` | `GLHUser` | | | `note` | `GLHMergeRequest` | `mergeRequest` | `GLHNote` | | -| `reviewers` | `GLHMergeRequest` | `reviewedMergeResquest` | `GLHUser` | | +| `reviewers` | `GLHMergeRequest` | `reviewedMergeRequest` | `GLHUser` | | | `squashCommit` | `GLHMergeRequest` | `squashedMergeRequest` | `GLHCommit` | | @@ -158,8 +158,8 @@ Class { '#merged_by => FMOne type: #GLHUser opposite: #mergerOfMergeRequests', '#assignees => FMMany type: #GLHUser opposite: #assignedMergeRequests', '#assignee => FMOne type: #GLHUser opposite: #currentlyAssignedMergeRequest', - '#reviewers => FMMany type: #GLHUser opposite: #reviewedMergeResquest', - '#pipelines => FMMany type: #GLHPipeline opposite: #mergeResquest', + '#reviewers => FMMany type: #GLHUser opposite: #reviewedMergeRequest', + '#pipelines => FMMany type: #GLHPipeline opposite: #mergeRequest', '#mergedCommit => FMOne type: #GLHCommit opposite: #commitedMergeRequest', '#mergeRequestCommit => FMOne type: #GLHCommit opposite: #commitedMergeRequest', '#squashCommit => FMOne type: #GLHCommit opposite: #squashedMergeRequest', @@ -729,7 +729,7 @@ GLHMergeRequest >> note: anObject [ { #category : #accessing } GLHMergeRequest >> pipelines [ - "Relation named: #pipelines type: #GLHPipeline opposite: #mergeResquest" + "Relation named: #pipelines type: #GLHPipeline opposite: #mergeRequest" @@ -845,7 +845,7 @@ GLHMergeRequest >> references_short: anObject [ { #category : #accessing } GLHMergeRequest >> reviewers [ - "Relation named: #reviewers type: #GLHUser opposite: #reviewedMergeResquest" + "Relation named: #reviewers type: #GLHUser opposite: #reviewedMergeRequest" diff --git a/src/GitLabHealth-Model/GLHPipeline.class.st b/src/GitLabHealth-Model/GLHPipeline.class.st index 1eb5c1bf..0c1a2e51 100644 --- a/src/GitLabHealth-Model/GLHPipeline.class.st +++ b/src/GitLabHealth-Model/GLHPipeline.class.st @@ -7,7 +7,7 @@ A GitLab Pipeline execution ### Parents | Relation | Origin | Opposite | Type | Comment | |---| -| `mergeResquest` | `GLHPipeline` | `pipelines` | `GLHMergeRequest` | | +| `mergeRequest` | `GLHPipeline` | `pipelines` | `GLHMergeRequest` | | | `project` | `GLHPipeline` | `pipelines` | `GLHProject` | | ### Children @@ -59,7 +59,7 @@ Class { '#jobs => FMMany type: #GLHJob opposite: #pipeline', '#user => FMOne type: #GLHUser opposite: #launchedPipelines', '#project => FMOne type: #GLHProject opposite: #pipelines', - '#mergeResquest => FMOne type: #GLHMergeRequest opposite: #pipelines' + '#mergeRequest => FMOne type: #GLHMergeRequest opposite: #pipelines' ], #category : #'GitLabHealth-Model-Entities' } @@ -163,26 +163,26 @@ GLHPipeline >> jobsGroup [ ] { #category : #accessing } -GLHPipeline >> mergeResquest [ - "Relation named: #mergeResquest type: #GLHMergeRequest opposite: #pipelines" +GLHPipeline >> mergeRequest [ + "Relation named: #mergeRequest type: #GLHMergeRequest opposite: #pipelines" - ^ mergeResquest + ^ mergeRequest ] { #category : #accessing } -GLHPipeline >> mergeResquest: anObject [ +GLHPipeline >> mergeRequest: anObject [ - mergeResquest := anObject + mergeRequest := anObject ] { #category : #navigation } -GLHPipeline >> mergeResquestGroup [ +GLHPipeline >> mergeRequestGroup [ - - ^ MooseSpecializedGroup with: self mergeResquest + + ^ MooseSpecializedGroup with: self mergeRequest ] { #category : #accessing } diff --git a/src/GitLabHealth-Model/GLHProject.class.st b/src/GitLabHealth-Model/GLHProject.class.st index 2acb8fc9..26cecc34 100644 --- a/src/GitLabHealth-Model/GLHProject.class.st +++ b/src/GitLabHealth-Model/GLHProject.class.st @@ -12,7 +12,7 @@ A GitLab Project ### Children | Relation | Origin | Opposite | Type | Comment | |---| -| `issue` | `GLHProject` | `project` | `GLHIssue` | | +| `issues` | `GLHProject` | `project` | `GLHIssue` | | | `mergeRequests` | `GLHProject` | `project` | `GLHMergeRequest` | | | `milestone` | `GLHProject` | `project` | `GLHMilestone` | | | `pipelines` | `GLHProject` | `project` | `GLHPipeline` | | @@ -63,7 +63,7 @@ Class { '#contributors => FMMany type: #GLHUser opposite: #contributedProjects', '#repository => FMOne type: #GLHRepository opposite: #project', '#releases => FMMany type: #GLHRelease opposite: #project', - '#issue => FMMany type: #GLHIssue opposite: #project', + '#issues => FMMany type: #GLHIssue opposite: #project', '#mergeRequests => FMMany type: #GLHMergeRequest opposite: #project', '#milestone => FMMany type: #GLHMilestone opposite: #project' ], @@ -88,7 +88,7 @@ GLHProject >> addContributor: anObject [ { #category : #adding } GLHProject >> addIssue: anObject [ - ^ self issue add: anObject + ^ self issues add: anObject ] { #category : #adding } @@ -240,26 +240,26 @@ GLHProject >> id: anObject [ ] { #category : #accessing } -GLHProject >> issue [ - "Relation named: #issue type: #GLHIssue opposite: #project" +GLHProject >> issues [ + "Relation named: #issues type: #GLHIssue opposite: #project" - ^ issue + ^ issues ] { #category : #accessing } -GLHProject >> issue: anObject [ +GLHProject >> issues: anObject [ - issue value: anObject + issues value: anObject ] { #category : #navigation } -GLHProject >> issueGroup [ +GLHProject >> issuesGroup [ - - ^ MooseSpecializedGroup withAll: self issue asSet + + ^ MooseSpecializedGroup withAll: self issues asSet ] { #category : #accessing } diff --git a/src/GitLabHealth-Model/GLHTEntityCreator.trait.st b/src/GitLabHealth-Model/GLHTEntityCreator.trait.st index 5394ff21..f50e3745 100644 --- a/src/GitLabHealth-Model/GLHTEntityCreator.trait.st +++ b/src/GitLabHealth-Model/GLHTEntityCreator.trait.st @@ -32,6 +32,13 @@ GLHTEntityCreator >> newBranch [ ^ self add: GLHBranch new ] +{ #category : #'entity creation' } +GLHTEntityCreator >> newBranchNamed: aName [ + + + ^ self add: (GLHBranch named: aName) +] + { #category : #'entity creation' } GLHTEntityCreator >> newChange [ @@ -242,6 +249,13 @@ GLHTEntityCreator >> newTag [ ^ self add: GLHTag new ] +{ #category : #'entity creation' } +GLHTEntityCreator >> newTagNamed: aName [ + + + ^ self add: (GLHTag named: aName) +] + { #category : #'entity creation' } GLHTEntityCreator >> newUser [ diff --git a/src/GitLabHealth-Model/GLHTRef.trait.st b/src/GitLabHealth-Model/GLHTRef.trait.st new file mode 100644 index 00000000..aae54e5e --- /dev/null +++ b/src/GitLabHealth-Model/GLHTRef.trait.st @@ -0,0 +1,51 @@ +" +I'm representing a Git reference, that is a reference point in a repository's history + +## Properties +====================== + +| Name | Type | Default value | Comment | +|---| +| `name` | `String` | nil | Basic name of the entity, not full reference.| +| `sha` | `String` | nil | | + +" +Trait { + #name : #GLHTRef, + #instVars : [ + '#sha => FMProperty' + ], + #traits : 'FamixTNamedEntity', + #classTraits : 'FamixTNamedEntity classTrait', + #category : #'GitLabHealth-Model-Traits' +} + +{ #category : #meta } +GLHTRef classSide >> annotation [ + + + + + ^ self +] + +{ #category : #testing } +GLHTRef >> isRef [ + + + ^ true +] + +{ #category : #accessing } +GLHTRef >> sha [ + + + + ^ sha +] + +{ #category : #accessing } +GLHTRef >> sha: anObject [ + + sha := anObject +] diff --git a/src/GitLabHealth-Model/GLHTag.class.st b/src/GitLabHealth-Model/GLHTag.class.st index 7f966331..8715d8b0 100644 --- a/src/GitLabHealth-Model/GLHTag.class.st +++ b/src/GitLabHealth-Model/GLHTag.class.st @@ -23,16 +23,18 @@ a Tag is a reference to a specific point in the repository's history |---| | `created_at` | `Object` | nil | | | `message` | `String` | nil | | -| `name` | `String` | nil | | +| `name` | `String` | nil | Basic name of the entity, not full reference.| | `protected` | `Boolean` | nil | | +| `sha` | `String` | nil | | | `target` | `String` | nil | | " Class { #name : #GLHTag, #superclass : #GLHEntity, + #traits : 'GLHTRef', + #classTraits : 'GLHTRef classTrait', #instVars : [ - '#name => FMProperty', '#message => FMProperty', '#target => FMProperty', '#protected => FMProperty', @@ -96,20 +98,6 @@ GLHTag >> message: anObject [ message := anObject ] -{ #category : #accessing } -GLHTag >> name [ - - - - ^ name -] - -{ #category : #accessing } -GLHTag >> name: anObject [ - - name := anObject -] - { #category : #accessing } GLHTag >> protected [ diff --git a/src/GitLabHealth-Model/GLHUser.class.st b/src/GitLabHealth-Model/GLHUser.class.st index 2859bbf0..d6648af4 100644 --- a/src/GitLabHealth-Model/GLHUser.class.st +++ b/src/GitLabHealth-Model/GLHUser.class.st @@ -8,13 +8,13 @@ A GitLab User | Relation | Origin | Opposite | Type | Comment | |---| | `assignedIssue` | `GLHUser` | `assignees` | `GLHIssue` | | -| `createdIssue` | `GLHUser` | `author` | `GLHIssue` | | | `createdMilestone` | `GLHUser` | `author` | `GLHMilestone` | | ### Children | Relation | Origin | Opposite | Type | Comment | |---| | `commits` | `GLHUser` | `commitCreator` | `GLHCommit` | | +| `createdIssue` | `GLHUser` | `author` | `GLHIssue` | | | `jobs` | `GLHUser` | `user` | `GLHJob` | | | `releases` | `GLHUser` | `author` | `GLHRelease` | | @@ -30,7 +30,7 @@ A GitLab User | `currentlyAssignedMergeRequest` | `GLHUser` | `assignee` | `GLHMergeRequest` | | | `launchedPipelines` | `GLHUser` | `user` | `GLHPipeline` | | | `mergerOfMergeRequests` | `GLHUser` | `merged_by` | `GLHMergeRequest` | | -| `reviewedMergeResquest` | `GLHUser` | `reviewers` | `GLHMergeRequest` | | +| `reviewedMergeRequest` | `GLHUser` | `reviewers` | `GLHMergeRequest` | | | `usedMerges` | `GLHUser` | `merge_user` | `GLHMergeRequest` | | @@ -101,7 +101,7 @@ Class { '#contributedProjects => FMMany type: #GLHProject opposite: #contributors', '#releases => FMMany type: #GLHRelease opposite: #author', '#assignedIssue => FMOne type: #GLHIssue opposite: #assignees', - '#createdIssue => FMOne type: #GLHIssue opposite: #author', + '#createdIssue => FMMany type: #GLHIssue opposite: #author', '#createdMergeRequests => FMMany type: #GLHMergeRequest opposite: #author', '#approcheMergeRequests => FMMany type: #GLHMergeRequest opposite: #approved_by', '#usedMerges => FMMany type: #GLHMergeRequest opposite: #merge_user', @@ -109,7 +109,7 @@ Class { '#mergerOfMergeRequests => FMMany type: #GLHMergeRequest opposite: #merged_by', '#assignedMergeRequests => FMMany type: #GLHMergeRequest opposite: #assignees', '#currentlyAssignedMergeRequest => FMMany type: #GLHMergeRequest opposite: #assignee', - '#reviewedMergeResquest => FMMany type: #GLHMergeRequest opposite: #reviewers', + '#reviewedMergeRequest => FMMany type: #GLHMergeRequest opposite: #reviewers', '#createdMilestone => FMOne type: #GLHMilestone opposite: #author' ], #category : #'GitLabHealth-Model-Entities' @@ -154,6 +154,12 @@ GLHUser >> addContributedProject: anObject [ ^ self contributedProjects add: anObject ] +{ #category : #adding } +GLHUser >> addCreatedIssue: anObject [ + + ^ self createdIssue add: anObject +] + { #category : #adding } GLHUser >> addCreatedMergeRequest: anObject [ @@ -197,9 +203,9 @@ GLHUser >> addRelease: anObject [ ] { #category : #adding } -GLHUser >> addReviewedMergeResquest: anObject [ +GLHUser >> addReviewedMergeRequest: anObject [ - ^ self reviewedMergeResquest add: anObject + ^ self reviewedMergeRequest add: anObject ] { #category : #adding } @@ -376,7 +382,6 @@ GLHUser >> createdIssue [ "Relation named: #createdIssue type: #GLHIssue opposite: #author" - ^ createdIssue ] @@ -385,14 +390,14 @@ GLHUser >> createdIssue [ GLHUser >> createdIssue: anObject [ - createdIssue := anObject + createdIssue value: anObject ] { #category : #navigation } GLHUser >> createdIssueGroup [ - ^ MooseSpecializedGroup with: self createdIssue + ^ MooseSpecializedGroup withAll: self createdIssue asSet ] { #category : #accessing } @@ -714,18 +719,18 @@ GLHUser >> releasesGroup [ ] { #category : #accessing } -GLHUser >> reviewedMergeResquest [ - "Relation named: #reviewedMergeResquest type: #GLHMergeRequest opposite: #reviewers" +GLHUser >> reviewedMergeRequest [ + "Relation named: #reviewedMergeRequest type: #GLHMergeRequest opposite: #reviewers" - ^ reviewedMergeResquest + ^ reviewedMergeRequest ] { #category : #accessing } -GLHUser >> reviewedMergeResquest: anObject [ +GLHUser >> reviewedMergeRequest: anObject [ - reviewedMergeResquest value: anObject + reviewedMergeRequest value: anObject ] { #category : #accessing } diff --git a/src/GitProject-JiraConnector-Model/GLHCommit.extension.st b/src/GitProject-JiraConnector-Model/GLHCommit.extension.st index 5cb60994..b06d3468 100644 --- a/src/GitProject-JiraConnector-Model/GLHCommit.extension.st +++ b/src/GitProject-JiraConnector-Model/GLHCommit.extension.st @@ -1,6 +1,6 @@ -Extension { #name : 'GLHCommit' } +Extension { #name : #GLHCommit } -{ #category : '*GitProject-JiraConnector-Model-accessing' } +{ #category : #'*GitProject-JiraConnector-Model-accessing' } GLHCommit >> jiraIssue [ "Relation named: #jiraIssue type: #JPIssue opposite: #commits" @@ -12,7 +12,7 @@ GLHCommit >> jiraIssue [ ^ self attributeAt: #jiraIssue ifAbsent: [ nil ] ] -{ #category : '*GitProject-JiraConnector-Model-accessing' } +{ #category : #'*GitProject-JiraConnector-Model-accessing' } GLHCommit >> jiraIssue: anObject [ diff --git a/src/GitProject-JiraConnector-Model/GLHMergeRequest.extension.st b/src/GitProject-JiraConnector-Model/GLHMergeRequest.extension.st index de5fbc45..481e8502 100644 --- a/src/GitProject-JiraConnector-Model/GLHMergeRequest.extension.st +++ b/src/GitProject-JiraConnector-Model/GLHMergeRequest.extension.st @@ -1,6 +1,6 @@ -Extension { #name : 'GLHMergeRequest' } +Extension { #name : #GLHMergeRequest } -{ #category : '*GitProject-JiraConnector-Model-accessing' } +{ #category : #'*GitProject-JiraConnector-Model-accessing' } GLHMergeRequest >> jiraIssue [ "Relation named: #jiraIssue type: #JPIssue opposite: #mergeRequest" @@ -12,7 +12,7 @@ GLHMergeRequest >> jiraIssue [ ^ self attributeAt: #jiraIssue ifAbsent: [ nil ] ] -{ #category : '*GitProject-JiraConnector-Model-accessing' } +{ #category : #'*GitProject-JiraConnector-Model-accessing' } GLHMergeRequest >> jiraIssue: anObject [ diff --git a/src/GitProject-JiraConnector-Model/GPJCModel.class.st b/src/GitProject-JiraConnector-Model/GPJCModel.class.st index e37f5b9a..11843ad3 100644 --- a/src/GitProject-JiraConnector-Model/GPJCModel.class.st +++ b/src/GitProject-JiraConnector-Model/GPJCModel.class.st @@ -1,20 +1,18 @@ Class { - #name : 'GPJCModel', - #superclass : 'MooseModel', + #name : #GPJCModel, + #superclass : #MooseModel, #traits : 'GLHTEntityCreator + JPTEntityCreator', #classTraits : 'GLHTEntityCreator classTrait + JPTEntityCreator classTrait', - #category : 'GitProject-JiraConnector-Model-Model', - #package : 'GitProject-JiraConnector-Model', - #tag : 'Model' + #category : #'GitProject-JiraConnector-Model-Model' } -{ #category : 'accessing' } +{ #category : #accessing } GPJCModel class >> allSubmetamodelsPackagesNames [ ^ #(#'Moose-Query' #'JiraPharoAPI-Model' #'GitLabHealth-Model' #'Famix-Traits') ] -{ #category : 'meta' } +{ #category : #meta } GPJCModel class >> annotation [ diff --git a/src/GitProject-JiraConnector-Model/JPIssue.extension.st b/src/GitProject-JiraConnector-Model/JPIssue.extension.st index cf35aaca..9b4b769a 100644 --- a/src/GitProject-JiraConnector-Model/JPIssue.extension.st +++ b/src/GitProject-JiraConnector-Model/JPIssue.extension.st @@ -1,6 +1,6 @@ -Extension { #name : 'JPIssue' } +Extension { #name : #JPIssue } -{ #category : '*GitProject-JiraConnector-Model-accessing' } +{ #category : #'*GitProject-JiraConnector-Model-accessing' } JPIssue >> commits [ "Relation named: #commits type: #GLHCommit opposite: #jiraIssue" @@ -12,14 +12,14 @@ JPIssue >> commits [ ^ self attributeAt: #commits ifAbsentPut: [ FMMultivalueLink on: self opposite: #jiraIssue: ] ] -{ #category : '*GitProject-JiraConnector-Model-accessing' } +{ #category : #'*GitProject-JiraConnector-Model-accessing' } JPIssue >> commits: anObject [ self commits value: anObject ] -{ #category : '*GitProject-JiraConnector-Model-accessing' } +{ #category : #'*GitProject-JiraConnector-Model-accessing' } JPIssue >> mergeRequest [ "Relation named: #mergeRequest type: #GLHMergeRequest opposite: #jiraIssue" @@ -31,7 +31,7 @@ JPIssue >> mergeRequest [ ^ self attributeAt: #mergeRequest ifAbsent: [ nil ] ] -{ #category : '*GitProject-JiraConnector-Model-accessing' } +{ #category : #'*GitProject-JiraConnector-Model-accessing' } JPIssue >> mergeRequest: anObject [ diff --git a/src/GitProject-JiraConnector-Model/package.st b/src/GitProject-JiraConnector-Model/package.st index 9b69c19b..1ab2344b 100644 --- a/src/GitProject-JiraConnector-Model/package.st +++ b/src/GitProject-JiraConnector-Model/package.st @@ -1 +1 @@ -Package { #name : 'GitProject-JiraConnector-Model' } +Package { #name : #'GitProject-JiraConnector-Model' } diff --git a/src/GitProjectHealth-Model-Importer/GitModelImporter.class.st b/src/GitProjectHealth-Model-Importer/GitModelImporter.class.st index 7d913d3b..165980f4 100644 --- a/src/GitProjectHealth-Model-Importer/GitModelImporter.class.st +++ b/src/GitProjectHealth-Model-Importer/GitModelImporter.class.st @@ -13,7 +13,8 @@ Class { 'glhModel', 'userCatalogue', 'repoApi', - 'withCommitDiffs' + 'withCommitDiffs', + 'generalReader' ], #classVars : [ 'currentImporter' @@ -21,35 +22,116 @@ Class { #category : #'GitProjectHealth-Model-Importer' } +{ #category : #bitbucket } +GitModelImporter class >> forBitbucketHostOn: anHostURL withToken: anApiToken [ + + ^ self forBitbucketHostOn: anHostURL withToken: anApiToken andModel: GLHModel new. +] + +{ #category : #bitbucket } +GitModelImporter class >> forBitbucketHostOn: anHostURL withToken: anApiToken andModel: aGitModel [ + + | bitbucketApi bitBucketImporter | + bitbucketApi := BitbucketApi new + host: anHostURL; + bearerToken: anApiToken. + + bitBucketImporter := BitBucketModelImporter new + repoApi: bitbucketApi; + glhModel: aGitModel; + withFiles: false; + withCommitsSince: 3 day; + withCommitDiffs: false. + ^bitBucketImporter +] + +{ #category : #github } +GitModelImporter class >> forGithubWithToken: anApiToken [ + ^ self forGithubWithToken: anApiToken andModel: GLHModel new +] + +{ #category : #github } +GitModelImporter class >> forGithubWithToken: anApiToken andModel: aGitModel [ + + | githubImport | + githubImport := GithubModelImporter new + glhModel: aGitModel; + privateToken: anApiToken; + withCommitsSince: 3 day; + yourself. + ^ githubImport +] + +{ #category : #gitlab } +GitModelImporter class >> forGitlabHostOn: anHostURL withToken: anApiToken [ + ^ self forGitlabHostOn: anHostURL withToken: anApiToken andModel: GLHModel new. +] + +{ #category : #gitlab } +GitModelImporter class >> forGitlabHostOn: anHostURL withToken: anApiToken andModel: aGitModel [ + "use it when accessing onpremise or custom gitlab platform" + | glphApi gitlabImporter | + + glphApi := GitlabApi new + privateToken: anApiToken; + hostUrl: anHostURL; + output: 'json'; + yourself. + + gitlabImporter := GitlabModelImporter new + repoApi: glphApi; + glhModel: aGitModel; + withFiles: false; + withCommitsSince: 3 day; + withCommitDiffs: false. + + ^ gitlabImporter +] + +{ #category : #gitlab } +GitModelImporter class >> forGitlabWithToken: anApiToken [ + ^ self forGitlabHostOn: 'https://gitlab.com/api/v4' withToken: anApiToken andModel: GLHModel new. +] + +{ #category : #gitlab } +GitModelImporter class >> forGitlabWithToken: anApiToken andModel: aGitModel [ + ^ self forGitlabHostOn: 'https://gitlab.com/api/v4' withToken: anApiToken andModel: aGitModel +] + { #category : #'accessing - global variables' } GitModelImporter class >> importers [ ^ currentImporter ] +{ #category : #'class initialization' } +GitModelImporter class >> initialize [ + currentImporter := Dictionary new. +] + { #category : #initialization } GitModelImporter class >> reset [ currentImporter := OrderedDictionary new. ] -{ #category : #accessing } +{ #category : #initialization } GitModelImporter >> beWithFiles [ withFiles := true ] -{ #category : #accessing } +{ #category : #initialization } GitModelImporter >> beWithoutFiles [ withFiles := false ] -{ #category : #'as yet unclassified' } +{ #category : #equality } GitModelImporter >> blockEqualityOn: aSymbol [ ^ [ :existing :new | (existing perform: aSymbol) = (new perform: aSymbol) ] ] -{ #category : #'as yet unclassified' } +{ #category : #equality } GitModelImporter >> blockEqualityOn: aSymbol andOn: aSecondSymbol [ ^ (self blockEqualityOn: aSymbol) and: [ self blockEqualityOn: aSecondSymbol ] ] @@ -68,7 +150,7 @@ GitModelImporter >> blockForDiffEquality [ existing diffString = new diffString ] ] ] -{ #category : #'as yet unclassified' } +{ #category : #equality } GitModelImporter >> blockForDiffRangeEquality [ ^ [ :existing :new | @@ -90,7 +172,7 @@ GitModelImporter >> blockOnNameEquality [ ^ self blockEqualityOn: #name ] -{ #category : #commit } +{ #category : #utils } GitModelImporter >> chainsCommitsFrom: commitsCollection [ | dic | @@ -112,7 +194,7 @@ GitModelImporter >> chainsCommitsFrom: commitsCollection [ ^ commitsCollection ] -{ #category : #commit } +{ #category : #'import - commits' } GitModelImporter >> completeImportedCommit: aGLHCommit [ @@ -128,7 +210,162 @@ GitModelImporter >> completeImportedCommit: aGLHCommit [ ^ aGLHCommit ] -{ #category : #'as yet unclassified' } +{ #category : #'import - projects' } +GitModelImporter >> completeImportedProject: aGLHProject [ +] + +{ #category : #'private - configure reader' } +GitModelImporter >> configureReaderForBranch: reader [ + + reader mapInstVarsFor: GLHBranch. + + reader + for: #ArrayOfBranch + customDo: [ :customMappting | + customMappting listOfElementSchema: GLHBranch ] +] + +{ #category : #'private - configure reader' } +GitModelImporter >> configureReaderForCommit: reader [ + + reader mapInstVarsFor: GLHCommit . + + reader + for: #ArrayOfCommit + customDo: [ :customMappting | + customMappting listOfElementSchema: GLHCommit ] +] + +{ #category : #'private - configure reader' } +GitModelImporter >> configureReaderForDiff: reader [ + + reader mapInstVarsFor: GLHDiff. + + reader + for: #ArrayOfDiff + customDo: [ :customMappting | + customMappting listOfElementSchema: GLHDiff ] +] + +{ #category : #'private - configure reader' } +GitModelImporter >> configureReaderForGroup: reader [ + + reader mapInstVarsFor: GLHGroup. + + reader + for: #ArrayOfGroup + customDo: [ :customMappting | + customMappting listOfElementSchema: GLHGroup ] +] + +{ #category : #'private - configure reader' } +GitModelImporter >> configureReaderForIssue: reader [ + + reader mapInstVarsFor: GLHIssue . + + reader + for: #ArrayOfIssue + customDo: [ :customMappting | + customMappting listOfElementSchema: GLHIssue ] +] + +{ #category : #'private - configure reader' } +GitModelImporter >> configureReaderForJob: reader [ + + reader mapInstVarsFor: GLHJob . + + reader for: #ArrayOfJob customDo: [ :customMappting | + customMappting listOfElementSchema: GLHJob ] +] + +{ #category : #'private - configure reader' } +GitModelImporter >> configureReaderForMergeRequest: reader [ + + reader mapInstVarsFor: GLHMergeRequest. + + reader for: #ArrayOfMergeRequest customDo: [ :customMappting | + customMappting listOfElementSchema: GLHMergeRequest ] +] + +{ #category : #'private - configure reader' } +GitModelImporter >> configureReaderForMilestone: reader [ + + reader mapInstVarsFor: GLHMilestone. + + reader + for: #ArrayOfMilestone + customDo: [ :customMappting | + customMappting listOfElementSchema: GLHMilestone ] +] + +{ #category : #'private - configure reader' } +GitModelImporter >> configureReaderForNote: reader [ + + reader mapInstVarsFor: GLHNote . + + reader + for: #ArrayOfNote + customDo: [ :customMappting | + customMappting listOfElementSchema: GLHNote ] +] + +{ #category : #'private - configure reader' } +GitModelImporter >> configureReaderForPipeline: reader [ + + reader mapInstVarsFor: GLHPipeline. + + reader + for: #ArrayOfPipeline + customDo: [ :customMappting | + customMappting listOfElementSchema: GLHPipeline ] +] + +{ #category : #'private - configure reader' } +GitModelImporter >> configureReaderForProject: reader [ + + reader mapInstVarsFor: GLHProject. + + reader + for: #ArrayOfProject + customDo: [ :customMappting | + customMappting listOfElementSchema: GLHProject ] +] + +{ #category : #'private - configure reader' } +GitModelImporter >> configureReaderForRelease: reader [ + + reader mapInstVarsFor: GLHRelease. + + reader + for: #ArrayOfRelease + customDo: [ :customMappting | + customMappting listOfElementSchema: GLHRelease ] +] + +{ #category : #'private - configure reader' } +GitModelImporter >> configureReaderForTag: reader [ + + reader mapInstVarsFor: GLHTag. + + reader + for: #ArrayOfTag + customDo: [ :customMappting | + customMappting listOfElementSchema: GLHTag ] +] + +{ #category : #'private - configure reader' } +GitModelImporter >> configureReaderForUser: reader [ + + reader mapInstVarsFor: GLHUser. + + reader + for: #ArrayOfUser + customDo: [ :customMappting | + customMappting listOfElementSchema: GLHUser ]. + +] + +{ #category : #utils } GitModelImporter >> filterCommitChanges: aCollection [ ^ aCollection reject: [ :line | @@ -151,13 +388,85 @@ GitModelImporter >> glhModel: anObject [ glhModel := anObject ] +{ #category : #'import - commits' } +GitModelImporter >> importAndLoadLatestsCommitsOfProject: aGLHProject [ + + self subclassResponsibility +] + +{ #category : #'import - users' } +GitModelImporter >> importAuthorOfCommit: aGLHCommit [ + + self + deprecated: 'Use importCreatorOfCommit: instead of current one' + on: '19 September 2025' + in: + 'Pharo-12.0.0+SNAPSHOT.build.1571.sha.cf5fcd22e66957962c97dffc58b0393b7f368147 (64 Bit)'. + + self subclassResponsibility +] + { #category : #'import - repositories' } GitModelImporter >> importBranchesOf: aGLHProject [ + self + deprecated: 'Use importBranchesOfProject: instead of current one' + on: '26 September 2025' + in: + 'Pharo-12.0.0+SNAPSHOT.build.1571.sha.cf5fcd22e66957962c97dffc58b0393b7f368147 (64 Bit)'. + ^ self subclassResponsibility ] -{ #category : #import } +{ #category : #'import - repositories' } +GitModelImporter >> importBranchesOfProject: aGLHProject [ + + ^ self subclassResponsibility +] + +{ #category : #'import - commits' } +GitModelImporter >> importCommit: aCommitID ofProject: aGLHProject [ + + self subclassResponsibility +] + +{ #category : #'import - commits' } +GitModelImporter >> importCommitsOfBranch: aGLHBranch [ + self subclassResponsibility + + +] + +{ #category : #'import - commits' } +GitModelImporter >> importCommitsOfProject: aGLHProject since: since until: until [ + + self subclassResponsibility +] + +{ #category : #'import - projects' } +GitModelImporter >> importContributedProjectsOfUser: aGLHUser [ +] + +{ #category : #'import - users' } +GitModelImporter >> importCreatorOfCommit: aGLHCommit [ + + + aGLHCommit commitCreator ifNil: [ + aGLHCommit commitCreator: + (self importUserByUsername: aGLHCommit author_name) ]. + self userCatalogue + addUser: aGLHCommit commitCreator + withProject: aGLHCommit repository project id. + ^ aGLHCommit commitCreator +] + +{ #category : #'import - diffs' } +GitModelImporter >> importDiffOfCommit: aCommit [ + + self subclassResponsibility +] + +{ #category : #'import - diffs' } GitModelImporter >> importDiffRangesForDiff: aGLHDiff [ | diffRanges | @@ -182,19 +491,102 @@ GitModelImporter >> importGroup: aGroupID [ self subclassResponsibility ] -{ #category : #pipelines } -GitModelImporter >> importLatestPipelinesOfProject: aGLHProject [ - (self pipelinesOf: aGLHProject id withLimit:30) do: [ :pipeline | - self glhModel add: pipeline unless: self blockOnIdEquality . - aGLHProject pipelines add: pipeline unless: self blockOnIdEquality] +{ #category : #'import - issues' } +GitModelImporter >> importIssuesOfProject: aGLHProject [ + self subclassResponsibility +] + +{ #category : #'import - jobs' } +GitModelImporter >> importJobsOf: aGLHPipeline [ + + self + deprecated: 'Use importJobsOfPipeline: instead of current one' + on: '26 September 2025' + in: + 'Pharo-12.0.0+SNAPSHOT.build.1571.sha.cf5fcd22e66957962c97dffc58b0393b7f368147 (64 Bit)'. + self subclassResponsibility +] + +{ #category : #'import - jobs' } +GitModelImporter >> importJobsOfPipeline: aGLHPipeline [ + + self subclassResponsibility +] + +{ #category : #'import - commits' } +GitModelImporter >> importLatestCommitsOfProject: aGLHProject [ + "limited to the last 50 commits" + + self subclassResponsibility +] + +{ #category : #'import - merge-requests' } +GitModelImporter >> importLatestMergeRequestsOfProject: aGLHProject [ + self subclassResponsibility +] + +{ #category : #'import - pipelines' } +GitModelImporter >> importLatestPipelinesOfProject: aGLHProject [ + self subclassResponsibility + +] + +{ #category : #'import - releases' } +GitModelImporter >> importLatestReleaseOfProject: aGLHProject [ + ^ self subclassResponsibility +] + +{ #category : #'import - merge-requests' } +GitModelImporter >> importMergeRequestCommits: mergeRequest [ +] + +{ #category : #'import - merge-requests' } +GitModelImporter >> importMergeRequestMergeCommits: aGLHMergeRequest [ + + self subclassResponsibility +] + +{ #category : #'import - merge-requests' } +GitModelImporter >> importMergeRequestsOfProject: aGLHProject [ + + self subclassResponsibility +] + +{ #category : #'import - merge-requests' } +GitModelImporter >> importMergeRequestsOfProject: aGLHProject since: fromDate until: toDate [ + self subclassResponsibility +] + +{ #category : #'import - merge-requests' } +GitModelImporter >> importMergeResquestAuthor: mergeRequest [ +] + +{ #category : #'import - merge-requests' } +GitModelImporter >> importMergeResquestMerger: mergeRequest [ +] + +{ #category : #'import - milestones' } +GitModelImporter >> importMilestonesOfProject: aGLHProject [ + self subclassResponsibility ] { #category : #'import - notes' } -GitModelImporter >> importNotesfromMergeRequest: mergeRequest [ +GitModelImporter >> importNotesOfMergeRequest: mergeRequest [ self subclassResponsibility ] +{ #category : #'import - pipelines' } +GitModelImporter >> importPipeline: aPipelineId OfProject: aGLHProject [ + + ^ self subclassResponsibility +] + +{ #category : #'import - merge-requests' } +GitModelImporter >> importPipelinesOfProject: aGLHProject [ + ^ self subclassResponsibility +] + { #category : #'import - projects' } GitModelImporter >> importProject: id [ "id can be a string or an integer depending on the APi implementation" @@ -204,6 +596,10 @@ GitModelImporter >> importProject: id [ ^ self subclassResponsibility ] +{ #category : #'import - projects' } +GitModelImporter >> importProject: aProjectID ofGroup: aGroup [ +] + { #category : #'import - projects' } GitModelImporter >> importProjects: aCollectionOfProjectID [ @@ -211,22 +607,84 @@ GitModelImporter >> importProjects: aCollectionOfProjectID [ ^ aCollectionOfProjectID collect: [ :id | self importProject: id ] ] +{ #category : #'import - projects' } +GitModelImporter >> importProjectsOfUser: aGLHUser [ + "https://docs.github.com/fr/rest/repos/repos?apiVersion=2022-11-28#list-repositories-for-a-user" + + self subclassResponsibility +] + +{ #category : #'import - commits' } +GitModelImporter >> importRefCommitOfBranch: aGLHBranch [ + |commit| + commit := self + importCommit: aGLHBranch sha + ofProject: aGLHBranch repository project. + commit := aGLHBranch commits + add: commit + unless: self blockOnIdEquality. + ^ commit +] + +{ #category : #'import - releases' } +GitModelImporter >> importRelease: aReleaseID ofProject: aGLHProject [ + self subclassResponsibility +] + +{ #category : #'import - tags' } +GitModelImporter >> importTagsForProject: aGLHProject [ + self subclassResponsibility +] + +{ #category : #'import - users' } +GitModelImporter >> importUser: aUserID [ + self subclassResponsibility +] + +{ #category : #'import - users' } +GitModelImporter >> importUserByUsername: username [ + + self subclassResponsibility +] + +{ #category : #'private - configure reader' } +GitModelImporter >> initReader [ + + | configurators | + generalReader := NeoJSONReader new. + + "will be reuse for all reader next" + "indique ce que doit faire le reader lorsqu'il parse une DateAndTime object" + generalReader for: DateAndTime customDo: [ :mapping | + mapping decoder: [ :string | + string ifNil: [ nil ] ifNotNil: [ DateAndTime fromString: string ] ] ]. + + configurators := (self class allSelectors select: [ :m | + m beginsWith: #configureReaderFor ]) asSet. + + configurators do: [ :configureReader | + self perform: configureReader with: generalReader ] +] + { #category : #initialization } GitModelImporter >> initialize [ super initialize. + self withFiles: false. self withCommitsSince: (Date today - 1 week) asDateAndTime. - userCatalogue := GLHUserCatalogueV2 new + userCatalogue := GLHUserCatalogueV2 new anImporter: self; yourself. + + self initReader ] -{ #category : #'as yet unclassified' } +{ #category : #initialization } GitModelImporter >> makeGlobal [ ^ self makeGlobal: DateAndTime now printString. ] -{ #category : #'as yet unclassified' } +{ #category : #initialization } GitModelImporter >> makeGlobal: aLabel [ currentImporter := GithubModelImporter importers ifNil: [ OrderedDictionary new ]. @@ -277,6 +735,11 @@ GitModelImporter >> parseDiffString: aDiff [ ^ aDiff diffRanges ] +{ #category : #parsing } +GitModelImporter >> parseIssuesResult: aString [ + self subclassResponsibility +] + { #category : #accessing } GitModelImporter >> repoApi [ diff --git a/src/GitProjectHealth-Model-Importer/TGitModelImporterTest.trait.st b/src/GitProjectHealth-Model-Importer/TGitModelImporterTest.trait.st new file mode 100644 index 00000000..72d797a7 --- /dev/null +++ b/src/GitProjectHealth-Model-Importer/TGitModelImporterTest.trait.st @@ -0,0 +1,358 @@ +Trait { + #name : #TGitModelImporterTest, + #instVars : [ + 'importer', + 'model', + 'defaultProject', + 'defaultMergeRequestOrPipeline' + ], + #category : #'GitProjectHealth-Model-Importer' +} + +{ #category : #'accessing - method dictionary' } +TGitModelImporterTest classSide >> addAndClassifySelector: selector withMethod: compiledMethod inProtocol: aProtocol [ + "When a new methods is added, I add it to the localMethodDict and also propagate the changes to my users" + + self localMethodDict at: selector put: compiledMethod. + + super addAndClassifySelector: selector withMethod: compiledMethod inProtocol: aProtocol. + + TraitChange addSelector: selector on: self +] + +{ #category : #querying } +TGitModelImporterTest classSide >> allTraits [ + + ^ self traitComposition allTraits +] + +{ #category : #initialization } +TGitModelImporterTest classSide >> doRebuildMethodDictionary [ + + | selectors removedSelectors modified | + "During the creation of the class or after a change in the traitComposition, the whole method dictionary is calculated. + If I return true, my users should be updated""1. I recreate the local methodDict" + modified := false. + self methodDict valuesDo: [ :m | m traitSource ifNil: [ self localMethodDict at: m selector put: m ] ]. + + "2. I filter the selectors from the trait composition, rejecting the ones that are locally defined. + And then I install the methods in myself. The trait composition only install the method if it is needed." + selectors := self traitComposition selectors reject: [ :e | self localMethodDict includesKey: e ]. + selectors do: [ :e | modified := modified | (self traitComposition installSelector: e into: self replacing: false) ]. + + "3. I handle the methods that I have and they are no more in the traitComposition." + removedSelectors := self methodDict keys reject: [ :aSelector | (selectors includes: aSelector) or: [ self localMethodDict includesKey: aSelector ] ]. + modified := modified | removedSelectors isNotEmpty. + removedSelectors do: [ :aSelector | + self methodDict removeKey: aSelector. + self removeFromProtocols: aSelector ]. + + ^ modified +] + +{ #category : #testing } +TGitModelImporterTest classSide >> findOriginClassOf: aMethod [ + + "I return the myself or the trait that has the original implementation of a method. + If the method is an alias, the returned class includes the original aliased method" + + + (aMethod hasProperty: #traitSource) + ifTrue: [ ^ aMethod traitSource innerClass ]. + + (self includesLocalSelector: aMethod selector) + ifTrue: [ ^ self ]. + + ^ (self traitComposition traitDefining: aMethod selector ifNone: [ ^ self ]) innerClass +] + +{ #category : #testing } +TGitModelImporterTest classSide >> findOriginMethodOf: aMethod [ + + "I return the original method for a aMethod. + If this is a local method, the original method is itself. + If it cames from a trait composition I look for the method in the trait composition. + First I try with the trait stored in the traitSource. + If it is an aliased or conflicting method, the method is look up in the whole trait composition" + + + (self includesLocalSelector: aMethod selector) + ifTrue: [ ^ aMethod ]. + + (aMethod hasProperty: #traitSource) + ifTrue: [ |newSelector| + newSelector := self traitComposition originSelectorOf: aMethod selector. + ^ aMethod traitSource compiledMethodAt: newSelector ifAbsent: [aMethod] ]. + + ^ (self traitComposition traitDefining: aMethod selector ifNone: [ self ]) + compiledMethodAt: aMethod selector ifAbsent: [ ^ aMethod ] +] + +{ #category : #testing } +TGitModelImporterTest classSide >> hasTraitComposition [ + + ^ self traitComposition isEmpty not +] + +{ #category : #testing } +TGitModelImporterTest classSide >> includesLocalSelector: aSymbol [ + + ^ self isLocalSelector: aSymbol +] + +{ #category : #testing } +TGitModelImporterTest classSide >> includesTrait: aTrait [ + + + ^ self traitComposition includesTrait: aTrait +] + +{ #category : #testing } +TGitModelImporterTest classSide >> isAliasSelector: aSymbol [ + "Return true if the selector aSymbol is an alias defined + in my or in another composition somewhere deeper in + the tree of traits compositions." + + ^ self traitComposition isAliasSelector: aSymbol +] + +{ #category : #testing } +TGitModelImporterTest classSide >> isLocalAliasSelector: aSymbol [ + "Return true if the selector aSymbol is an alias defined + in my trait composition." + + ^ self traitComposition isLocalAliasSelector: aSymbol +] + +{ #category : #testing } +TGitModelImporterTest classSide >> isLocalSelector: aSelector [ + + ^ self localMethodDict includesKey: aSelector +] + +{ #category : #accessing } +TGitModelImporterTest classSide >> localMethodDict [ + "The local methodDict is in the metaclass. In this way I do not have to recompile the methods during the bootstrap when we don't have a compiler." + ^ self class baseLocalMethods +] + +{ #category : #accessing } +TGitModelImporterTest classSide >> localMethodDict: aMethodDictionary [ + ^ self class baseLocalMethods: aMethodDictionary +] + +{ #category : #accessing } +TGitModelImporterTest classSide >> localMethods [ + "returns the methods of classes excluding the ones of the traits that the class uses" + + ^ self localMethodDict values +] + +{ #category : #'accessing - method dictionary' } +TGitModelImporterTest classSide >> localSelectors [ + + ^ self localMethodDict keys +] + +{ #category : #categories } +TGitModelImporterTest classSide >> recategorizeSelector: selector from: oldProtocol to: newProtocol [ + "When a method is recategorized I have to classify the method, but also recategorize the aliases pointing to it" + + | originalProtocol | + "If it is nil is because it is a removal. It will removed when the method is removed." + newProtocol ifNil: [ ^ self ]. + + originalProtocol := (self protocolOfSelector: selector) ifNil: [ ^ self ]. + originalProtocol name = oldProtocol name ifTrue: [ self classify: selector under: newProtocol name ]. + + (self traitComposition reverseAlias: selector) do: [ :selectorAlias | + self recategorizeSelector: selectorAlias from: oldProtocol to: newProtocol. + self notifyOfRecategorizedSelector: selectorAlias from: oldProtocol to: newProtocol ] +] + +{ #category : #recompilation } +TGitModelImporterTest classSide >> recompile: selector from: oldClass [ + + super recompile: selector from: oldClass. + TraitChange addSelector: selector on: self +] + +{ #category : #'trait-composition' } +TGitModelImporterTest classSide >> removeFromComposition: aTrait [ + + self setTraitComposition: (self traitComposition copyWithoutTrait: aTrait asTraitComposition) +] + +{ #category : #removing } +TGitModelImporterTest classSide >> removeSelector: aSelector [ + + "When a selector is removed it should be notified to my users. + Check the class TraitChange for more details" + + super removeSelector: aSelector. + self localMethodDict removeKey: aSelector ifAbsent: [ ]. + + TraitChange removeSelector: aSelector on: self +] + +{ #category : #accessing } +TGitModelImporterTest classSide >> traitComposition [ + "My trait composition is in my class. So I do not need to recompile the methods when installing them during bootstrap" + ^ self class baseComposition +] + +{ #category : #accessing } +TGitModelImporterTest classSide >> traitComposition: aComposition [ + + aComposition asTraitComposition allTraits do: [ :aMaybeTrait | + aMaybeTrait isTrait ifFalse: [ + self error: 'All the members of the trait composition should be traits' ]]. + + self class baseComposition: aComposition +] + +{ #category : #accessing } +TGitModelImporterTest classSide >> traitCompositionString [ + ^ self traitComposition asString +] + +{ #category : #accessing } +TGitModelImporterTest classSide >> traits [ + + ^ self traitComposition traits +] + +{ #category : #accessing } +TGitModelImporterTest >> defaultMergeRequestOrPipeline [ + + ^ defaultMergeRequestOrPipeline +] + +{ #category : #accessing } +TGitModelImporterTest >> defaultProject [ + ^ defaultProject +] + +{ #category : #'tests - branches' } +TGitModelImporterTest >> testImportBranchesOf [ + + | collection element | + collection := importer importBranchesOf: self defaultProject. + + self assert: collection isCollection. + + element := collection first. + self assert: element class equals: GLHBranch +] + +{ #category : #'tests - commits' } +TGitModelImporterTest >> testImportCommitOfProject [ + + | commit | + commit := importer importCommit: 123 ofProject: self defaultProject. + + self assert: commit isNotNil. + self assert: commit class equals: GLHCommit. + self assert: commit repository class equals: GLHRepository. + self assert: commit repository project class equals: GLHProject +] + +{ #category : #'tests - groups' } +TGitModelImporterTest >> testImportGroup [ + + | collection element | + collection := importer importGroup: 123. + + self assert: collection class equals: GLHGroup. + + element := collection projects first. + self assert: element class equals: GLHProject. +] + +{ #category : #'tests - commits' } +TGitModelImporterTest >> testImportLatestCommitsOfProject [ + + | commits commit | + commits := importer importLatestCommitsOfProject: self defaultProject . + + self assert: commits isEmptyOrNil not. + + commit := commits first. + self assert: commit class equals: GLHCommit. + self assert: commit repository class equals: GLHRepository. + self assert: commit repository project class equals: GLHProject +] + +{ #category : #'tests - merge-requests' } +TGitModelImporterTest >> testImportLatestMergeRequestsOfProject [ + + | collection element | + collection := importer importLatestMergeRequestsOfProject: + self defaultProject. + + self assert: collection isCollection. + element := collection first. + self assert: element class equals: GLHMergeRequest. + self assert: element project class equals: GLHProject. + + +] + +{ #category : #'tests - merge-requests' } +TGitModelImporterTest >> testImportMergeRequestsOfProject [ + + | collection element | + + + collection := importer importMergeRequestsOfProject: + self defaultProject. + + self assert: collection isCollection. + element := collection first. + self assert: element class equals: GLHMergeRequest. + self assert: element project class equals: GLHProject. + self assert: element diffs isCollection. + self assert: element diffs first class equals: GLHDiff. + self assert: element mergeRequestCommit class equals: GLHCommit +] + +{ #category : #'tests - pipelines' } +TGitModelImporterTest >> testImportPipelineOfProject [ + + | element | + element := importer importPipeline: 123 OfProject: self defaultProject . + + self assert: element class equals: GLHPipeline. + self assert: element project isNotNil. + self assert: element project class equals: GLHProject +] + +{ #category : #'tests - pipelines' } +TGitModelImporterTest >> testImportPipelinesOfMergeRequest [ + + | collection element | + collection := importer importPipelinesOfMergeRequest: + self defaultMergeRequestOrPipeline. + + self assert: collection isEmptyOrNil not. + self assert: collection isCollection. + + element := collection first. + self assert: element class equals: GLHPipeline. + self assert: element project isNotNil. + self assert: element project class equals: GLHProject. + + self assert: element mergeRequest isNotNil. + self assert: element mergeRequest class equals: GLHMergeRequest +] + +{ #category : #'tests - users' } +TGitModelImporterTest >> testImportUser [ + + | element | + element := importer importUser: 123. + + self assert: element isNotNil. + self assert: element class equals: GLHUser. + +]