diff --git a/README.md b/README.md index b28e305..c577690 100644 --- a/README.md +++ b/README.md @@ -140,6 +140,15 @@ pullRequestTasks: # Tasks specific to the improvement issue type: improvement: - improvement task1 +branches: + # Make the bot add a label with the name of base ref when a pull requests target a non-main branch. + enabled: true + # Prefix is only added when a prefix format is passed. Must contain a single %s that will be replaced with the base ref + titlePrefix: "[%s]" + # Label is only added when a label format is passed. Must contain a single %s that will be replaced with the base ref + label: "branch-%s" + ignore: + # as other config sections, supports ignore rules ``` ### Altering the infrastructure diff --git a/src/main/java/org/hibernate/infra/bot/EditPullRequestAddBranchTagLabel.java b/src/main/java/org/hibernate/infra/bot/EditPullRequestAddBranchTagLabel.java new file mode 100644 index 0000000..4703aff --- /dev/null +++ b/src/main/java/org/hibernate/infra/bot/EditPullRequestAddBranchTagLabel.java @@ -0,0 +1,111 @@ +package org.hibernate.infra.bot; + +import java.io.IOException; +import java.util.List; +import java.util.Locale; +import java.util.Random; + +import org.hibernate.infra.bot.config.DeploymentConfig; +import org.hibernate.infra.bot.config.RepositoryConfig; + +import org.jboss.logging.Logger; + +import io.quarkiverse.githubapp.ConfigFile; +import io.quarkiverse.githubapp.event.PullRequest; +import jakarta.inject.Inject; +import org.kohsuke.github.GHEventPayload; +import org.kohsuke.github.GHFileNotFoundException; +import org.kohsuke.github.GHIssueState; +import org.kohsuke.github.GHLabel; +import org.kohsuke.github.GHPullRequest; +import org.kohsuke.github.GHRepository; +import org.kohsuke.github.GHUser; + +public class EditPullRequestAddBranchTagLabel { + private static final Logger LOG = Logger.getLogger( EditPullRequestAddBranchTagLabel.class ); + + @Inject + DeploymentConfig deploymentConfig; + + void pullRequestChanged( + @PullRequest.Opened @PullRequest.Reopened @PullRequest.Edited @PullRequest.Synchronize + GHEventPayload.PullRequest payload, + @ConfigFile("hibernate-github-bot.yml") RepositoryConfig repositoryConfig + ) throws IOException { + addTagOrLabel( payload.getRepository(), repositoryConfig, payload.getPullRequest() ); + } + + private void addTagOrLabel( + GHRepository repository, + RepositoryConfig repositoryConfig, + GHPullRequest pullRequest + ) throws IOException { + if ( repositoryConfig == null || repositoryConfig.branches == null + || !repositoryConfig.branches.getEnabled().orElse( Boolean.FALSE ) ) { + return; + } + + if ( !shouldCheck( repository, pullRequest, repositoryConfig.branches.getIgnore() ) ) { + return; + } + + String base = pullRequest.getBase().getRef(); + if ( "main".equalsIgnoreCase( base ) ) { + return; + } + + if ( repositoryConfig.branches.getTitlePrefix().isPresent() ) { + String prefix = String.format( Locale.ROOT, repositoryConfig.branches.getTitlePrefix().get(), base ); + String title = pullRequest.getTitle(); + if ( !title.startsWith( prefix ) ) { + if ( !deploymentConfig.isDryRun() ) { + pullRequest.setTitle( prefix + " " + title ); + } + else { + LOG.info( "Pull request #" + pullRequest.getNumber() + " - Setting title to: " + title ); + } + } + } + + if ( repositoryConfig.branches.getLabel().isPresent() ) { + String labelName = String.format( Locale.ROOT, repositoryConfig.branches.getLabel().get(), base ); + for ( GHLabel ghLabel : pullRequest.getLabels() ) { + if ( ghLabel.getName().equals( labelName ) ) { + return; + } + } + + GHLabel label; + try { + label = repository.getLabel( base ); + } + catch (GHFileNotFoundException e) { + label = repository.createLabel( + base, + String.format( Locale.ROOT, "%06x", new Random().nextInt( 0xffffff + 1 ) ), + "Label for pull requests targeting [" + base + "] branch." + ); + } + + if ( !deploymentConfig.isDryRun() ) { + pullRequest.addLabels( label ); + } + else { + LOG.info( "Pull request #" + pullRequest.getNumber() + " - Adding label: " + label.getName() ); + } + } + } + + private boolean shouldCheck(GHRepository repository, GHPullRequest pullRequest, List ignoredPRConfigurations) throws IOException { + GHUser author = pullRequest.getUser(); + String title = pullRequest.getTitle(); + for ( RepositoryConfig.IgnoreConfiguration ignore : ignoredPRConfigurations ) { + if ( ignore.getUser().equals( author.getLogin() ) + && ignore.getTitlePattern().matcher( title ).matches() ) { + return false; + } + } + return !GHIssueState.CLOSED.equals( pullRequest.getState() ) + && repository.getId() == pullRequest.getBase().getRepository().getId(); + } +} diff --git a/src/main/java/org/hibernate/infra/bot/config/RepositoryConfig.java b/src/main/java/org/hibernate/infra/bot/config/RepositoryConfig.java index 32ab729..1868afb 100644 --- a/src/main/java/org/hibernate/infra/bot/config/RepositoryConfig.java +++ b/src/main/java/org/hibernate/infra/bot/config/RepositoryConfig.java @@ -20,6 +20,8 @@ public class RepositoryConfig { public TaskList pullRequestTasks; + public BranchLabel branches; + public static class JiraConfig { private Optional issueKeyPattern = Optional.empty(); @@ -229,4 +231,43 @@ public void setIgnore(List ignore) { this.ignore = ignore; } } + + public static class BranchLabel { + private Optional enabled = Optional.empty(); + private List ignore = Collections.emptyList(); + private Optional label = Optional.empty(); + private Optional titlePrefix = Optional.empty(); + + public Optional getEnabled() { + return enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = Optional.of( enabled ); + } + + public List getIgnore() { + return ignore; + } + + public void setIgnore(List ignore) { + this.ignore = ignore; + } + + public Optional getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = Optional.of( label ); + } + + public Optional getTitlePrefix() { + return titlePrefix; + } + + public void setTitlePrefix(String titlePrefix) { + this.titlePrefix = Optional.of( titlePrefix ); + } + } } diff --git a/src/test/java/org/hibernate/infra/bot/tests/EditPullRequestAddBranchTagLabelTest.java b/src/test/java/org/hibernate/infra/bot/tests/EditPullRequestAddBranchTagLabelTest.java new file mode 100644 index 0000000..3491f67 --- /dev/null +++ b/src/test/java/org/hibernate/infra/bot/tests/EditPullRequestAddBranchTagLabelTest.java @@ -0,0 +1,220 @@ +package org.hibernate.infra.bot.tests; + +import static io.quarkiverse.githubapp.testing.GitHubAppTesting.given; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import java.io.IOException; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import io.quarkiverse.githubapp.testing.GitHubAppTest; +import io.quarkus.test.junit.QuarkusTest; +import org.kohsuke.github.GHEvent; +import org.kohsuke.github.GHFileNotFoundException; +import org.kohsuke.github.GHLabel; +import org.kohsuke.github.GHPullRequest; +import org.kohsuke.github.GHRepository; +import org.mockito.ArgumentCaptor; +import org.mockito.junit.jupiter.MockitoExtension; + +@QuarkusTest +@GitHubAppTest +@ExtendWith(MockitoExtension.class) +public class EditPullRequestAddBranchTagLabelTest extends AbstractPullRequestTest { + @Test + void simple() throws IOException { + long repoId = 344815557L; + long prId = 585627026L; + given() + .github( mocks -> { + mocks.configFile("hibernate-github-bot.yml") + .fromString( """ + jira: + projectKey: "HSEARCH" + branches: + enabled: true + label: "%s" + """ ); + + GHRepository repoMock = mocks.repository( "yrodiere/hibernate-github-bot-playground" ); + when( repoMock.getId() ).thenReturn( repoId ); + when( repoMock.getLabel( any() ) ).thenAnswer( invocation -> { + GHLabel label = mock( GHLabel.class ); + when( label.getName() ).thenReturn( "base-ref" ); + return label; + } ); + + PullRequestMockHelper.start( mocks, prId, repoMock ) + .commit( "HSEARCH-1111 Correct message" ) + .comment( "Some comment" ) + .comment( "Some other comment" ); + + mockCheckRuns( repoMock, "6e9f11a1e2946b207c6eb245ec942f2b5a3ea156" ); + } ) + .when() + .payloadFromClasspath( "/pullrequest-opened-hsearch-1111-non-main-branch.json" ) + .event( GHEvent.PULL_REQUEST ) + .then() + .github( mocks -> { + GHPullRequest prMock = mocks.pullRequest( prId ); + ArgumentCaptor labelArgumentCaptor = ArgumentCaptor.forClass( GHLabel.class ); + verify( prMock ).addLabels( labelArgumentCaptor.capture() ); + assertThat( labelArgumentCaptor.getValue().getName() ).isEqualTo( "base-ref" ); + + verifyNoMoreInteractions( mocks.ghObjects() ); + } ); + } + + @Test + void labelDoesNotExist() throws IOException { + long repoId = 344815557L; + long prId = 585627026L; + given() + .github( mocks -> { + mocks.configFile("hibernate-github-bot.yml") + .fromString( """ + jira: + projectKey: "HSEARCH" + branches: + enabled: true + label: "%s" + """ ); + + GHRepository repoMock = mocks.repository( "yrodiere/hibernate-github-bot-playground" ); + when( repoMock.getId() ).thenReturn( repoId ); + when( repoMock.getLabel( any() ) ).thenThrow( GHFileNotFoundException.class ); + + when( repoMock.createLabel( any(), any(), any() ) ).thenAnswer( invocation -> { + GHLabel label = mock( GHLabel.class ); + when( label.getName() ).thenReturn( "base-ref" ); + when( label.getColor() ).thenReturn( invocation.getArgument( 1 ) ); + when( label.getDescription() ).thenReturn( invocation.getArgument( 1 ) ); + return label; + } ); + + PullRequestMockHelper.start( mocks, prId, repoMock ) + .commit( "HSEARCH-1111 Correct message" ) + .comment( "Some comment" ) + .comment( "Some other comment" ); + + mockCheckRuns( repoMock, "6e9f11a1e2946b207c6eb245ec942f2b5a3ea156" ); + } ) + .when() + .payloadFromClasspath( "/pullrequest-opened-hsearch-1111-non-main-branch.json" ) + .event( GHEvent.PULL_REQUEST ) + .then() + .github( mocks -> { + GHRepository repoMock = mocks.repository( "yrodiere/hibernate-github-bot-playground" ); + GHPullRequest prMock = mocks.pullRequest( prId ); + + ArgumentCaptor name = ArgumentCaptor.forClass( String.class ); + ArgumentCaptor color = ArgumentCaptor.forClass( String.class ); + ArgumentCaptor description = ArgumentCaptor.forClass( String.class ); + verify( repoMock ).createLabel( name.capture(), color.capture(), description.capture() ); + assertThat( color.getValue() ).hasSize( 6 ); + assertThat( description.getValue() ).contains( "Label for pull requests targeting" ); + + ArgumentCaptor labelArgumentCaptor = ArgumentCaptor.forClass( GHLabel.class ); + verify( prMock ).addLabels( labelArgumentCaptor.capture() ); + assertThat( labelArgumentCaptor.getValue().getName() ).isEqualTo( "base-ref" ); + + verifyNoMoreInteractions( mocks.ghObjects() ); + } ); + } + + @Test + void updateTitle() throws IOException { + long repoId = 344815557L; + long prId = 585627026L; + given() + .github( mocks -> { + mocks.configFile("hibernate-github-bot.yml") + .fromString( """ + jira: + projectKey: "HSEARCH" + branches: + enabled: true + titlePrefix: "[%s]" + """ ); + + GHRepository repoMock = mocks.repository( "yrodiere/hibernate-github-bot-playground" ); + when( repoMock.getId() ).thenReturn( repoId ); + + PullRequestMockHelper.start( mocks, prId, repoMock ) + .commit( "HSEARCH-1111 Correct message" ) + .comment( "Some comment" ) + .comment( "Some other comment" ); + + mockCheckRuns( repoMock, "6e9f11a1e2946b207c6eb245ec942f2b5a3ea156" ); + } ) + .when() + .payloadFromClasspath( "/pullrequest-opened-hsearch-1111-non-main-branch.json" ) + .event( GHEvent.PULL_REQUEST ) + .then() + .github( mocks -> { + GHPullRequest prMock = mocks.pullRequest( prId ); + + ArgumentCaptor title = ArgumentCaptor.forClass( String.class ); + verify( prMock ).setTitle( title.capture() ); + assertThat( title.getValue() ).startsWith( "[" ); + + verifyNoMoreInteractions( mocks.ghObjects() ); + } ); + } + + @Test + void updateLabelAndTitle() throws IOException { + long repoId = 344815557L; + long prId = 585627026L; + given() + .github( mocks -> { + mocks.configFile("hibernate-github-bot.yml") + .fromString( """ + jira: + projectKey: "HSEARCH" + branches: + enabled: true + titlePrefix: "[%s]" + label: "%s" + """ ); + + GHRepository repoMock = mocks.repository( "yrodiere/hibernate-github-bot-playground" ); + when( repoMock.getId() ).thenReturn( repoId ); + when( repoMock.getLabel( any() ) ).thenAnswer( invocation -> { + GHLabel label = mock( GHLabel.class ); + when( label.getName() ).thenReturn( "base-ref" ); + return label; + } ); + + PullRequestMockHelper.start( mocks, prId, repoMock ) + .commit( "HSEARCH-1111 Correct message" ) + .comment( "Some comment" ) + .comment( "Some other comment" ); + + mockCheckRuns( repoMock, "6e9f11a1e2946b207c6eb245ec942f2b5a3ea156" ); + } ) + .when() + .payloadFromClasspath( "/pullrequest-opened-hsearch-1111-non-main-branch.json" ) + .event( GHEvent.PULL_REQUEST ) + .then() + .github( mocks -> { + GHPullRequest prMock = mocks.pullRequest( prId ); + ArgumentCaptor labelArgumentCaptor = ArgumentCaptor.forClass( GHLabel.class ); + verify( prMock ).addLabels( labelArgumentCaptor.capture() ); + assertThat( labelArgumentCaptor.getValue().getName() ).isEqualTo( "base-ref" ); + + ArgumentCaptor title = ArgumentCaptor.forClass( String.class ); + verify( prMock ).setTitle( title.capture() ); + assertThat( title.getValue() ).startsWith( "[" ); + + verifyNoMoreInteractions( mocks.ghObjects() ); + } ); + } +} diff --git a/src/test/resources/pullrequest-opened-hsearch-1111-non-main-branch.json b/src/test/resources/pullrequest-opened-hsearch-1111-non-main-branch.json new file mode 100644 index 0000000..3a4835e --- /dev/null +++ b/src/test/resources/pullrequest-opened-hsearch-1111-non-main-branch.json @@ -0,0 +1,478 @@ +{ + "action": "opened", + "number": 1, + "pull_request": { + "url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/pulls/1", + "id": 585627026, + "node_id": "MDExOlB1bGxSZXF1ZXN0NTg1NjI3MDI2", + "html_url": "https://github.com/yrodiere/hibernate-github-bot-playground/pull/1", + "diff_url": "https://github.com/yrodiere/hibernate-github-bot-playground/pull/1.diff", + "patch_url": "https://github.com/yrodiere/hibernate-github-bot-playground/pull/1.patch", + "issue_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/issues/1", + "number": 1, + "state": "open", + "locked": false, + "title": "HSEARCH-1111 Some title", + "user": { + "login": "yrodiere", + "id": 412878, + "node_id": "MDQ6VXNlcjQxMjg3OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/412878?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/yrodiere", + "html_url": "https://github.com/yrodiere", + "followers_url": "https://api.github.com/users/yrodiere/followers", + "following_url": "https://api.github.com/users/yrodiere/following{/other_user}", + "gists_url": "https://api.github.com/users/yrodiere/gists{/gist_id}", + "starred_url": "https://api.github.com/users/yrodiere/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/yrodiere/subscriptions", + "organizations_url": "https://api.github.com/users/yrodiere/orgs", + "repos_url": "https://api.github.com/users/yrodiere/repos", + "events_url": "https://api.github.com/users/yrodiere/events{/privacy}", + "received_events_url": "https://api.github.com/users/yrodiere/received_events", + "type": "User", + "site_admin": false + }, + "body": "Original pull request body", + "created_at": "2021-03-05T13:52:31Z", + "updated_at": "2021-03-05T13:52:31Z", + "closed_at": null, + "merged_at": null, + "merge_commit_sha": null, + "assignee": null, + "assignees": [], + "requested_reviewers": [], + "requested_teams": [], + "labels": [], + "milestone": null, + "draft": false, + "commits_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/pulls/1/commits", + "review_comments_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/pulls/1/comments", + "review_comment_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/pulls/comments{/number}", + "comments_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/issues/1/comments", + "statuses_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/statuses/6e9f11a1e2946b207c6eb245ec942f2b5a3ea156", + "head": { + "label": "yrodiere:yrodiere-patch-1", + "ref": "yrodiere-patch-1", + "sha": "6e9f11a1e2946b207c6eb245ec942f2b5a3ea156", + "user": { + "login": "yrodiere", + "id": 412878, + "node_id": "MDQ6VXNlcjQxMjg3OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/412878?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/yrodiere", + "html_url": "https://github.com/yrodiere", + "followers_url": "https://api.github.com/users/yrodiere/followers", + "following_url": "https://api.github.com/users/yrodiere/following{/other_user}", + "gists_url": "https://api.github.com/users/yrodiere/gists{/gist_id}", + "starred_url": "https://api.github.com/users/yrodiere/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/yrodiere/subscriptions", + "organizations_url": "https://api.github.com/users/yrodiere/orgs", + "repos_url": "https://api.github.com/users/yrodiere/repos", + "events_url": "https://api.github.com/users/yrodiere/events{/privacy}", + "received_events_url": "https://api.github.com/users/yrodiere/received_events", + "type": "User", + "site_admin": false + }, + "repo": { + "id": 344815557, + "node_id": "MDEwOlJlcG9zaXRvcnkzNDQ4MTU1NTc=", + "name": "hibernate-github-bot-playground", + "full_name": "yrodiere/hibernate-github-bot-playground", + "private": false, + "owner": { + "login": "yrodiere", + "id": 412878, + "node_id": "MDQ6VXNlcjQxMjg3OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/412878?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/yrodiere", + "html_url": "https://github.com/yrodiere", + "followers_url": "https://api.github.com/users/yrodiere/followers", + "following_url": "https://api.github.com/users/yrodiere/following{/other_user}", + "gists_url": "https://api.github.com/users/yrodiere/gists{/gist_id}", + "starred_url": "https://api.github.com/users/yrodiere/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/yrodiere/subscriptions", + "organizations_url": "https://api.github.com/users/yrodiere/orgs", + "repos_url": "https://api.github.com/users/yrodiere/repos", + "events_url": "https://api.github.com/users/yrodiere/events{/privacy}", + "received_events_url": "https://api.github.com/users/yrodiere/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/yrodiere/hibernate-github-bot-playground", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground", + "forks_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/forks", + "keys_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/teams", + "hooks_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/hooks", + "issue_events_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/issues/events{/number}", + "events_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/events", + "assignees_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/assignees{/user}", + "branches_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/branches{/branch}", + "tags_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/tags", + "blobs_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/statuses/{sha}", + "languages_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/languages", + "stargazers_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/stargazers", + "contributors_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/contributors", + "subscribers_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/subscribers", + "subscription_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/subscription", + "commits_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/contents/{+path}", + "compare_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/merges", + "archive_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/downloads", + "issues_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/issues{/number}", + "pulls_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/pulls{/number}", + "milestones_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/milestones{/number}", + "notifications_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/labels{/name}", + "releases_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/releases{/id}", + "deployments_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/deployments", + "created_at": "2021-03-05T13:13:43Z", + "updated_at": "2021-03-05T13:27:59Z", + "pushed_at": "2021-03-05T13:52:31Z", + "git_url": "git://github.com/yrodiere/hibernate-github-bot-playground.git", + "ssh_url": "git@github.com:yrodiere/hibernate-github-bot-playground.git", + "clone_url": "https://github.com/yrodiere/hibernate-github-bot-playground.git", + "svn_url": "https://github.com/yrodiere/hibernate-github-bot-playground", + "homepage": null, + "size": 0, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 1, + "license": { + "key": "mit", + "name": "MIT License", + "spdx_id": "MIT", + "url": "https://api.github.com/licenses/mit", + "node_id": "MDc6TGljZW5zZTEz" + }, + "forks": 0, + "open_issues": 1, + "watchers": 0, + "default_branch": "main", + "allow_squash_merge": true, + "allow_merge_commit": true, + "allow_rebase_merge": true, + "delete_branch_on_merge": false + } + }, + "base": { + "label": "yrodiere:main", + "ref": "3.0", + "sha": "cfb01674fb6ac59109b79108d859bed6271ec531", + "user": { + "login": "yrodiere", + "id": 412878, + "node_id": "MDQ6VXNlcjQxMjg3OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/412878?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/yrodiere", + "html_url": "https://github.com/yrodiere", + "followers_url": "https://api.github.com/users/yrodiere/followers", + "following_url": "https://api.github.com/users/yrodiere/following{/other_user}", + "gists_url": "https://api.github.com/users/yrodiere/gists{/gist_id}", + "starred_url": "https://api.github.com/users/yrodiere/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/yrodiere/subscriptions", + "organizations_url": "https://api.github.com/users/yrodiere/orgs", + "repos_url": "https://api.github.com/users/yrodiere/repos", + "events_url": "https://api.github.com/users/yrodiere/events{/privacy}", + "received_events_url": "https://api.github.com/users/yrodiere/received_events", + "type": "User", + "site_admin": false + }, + "repo": { + "id": 344815557, + "node_id": "MDEwOlJlcG9zaXRvcnkzNDQ4MTU1NTc=", + "name": "hibernate-github-bot-playground", + "full_name": "yrodiere/hibernate-github-bot-playground", + "private": false, + "owner": { + "login": "yrodiere", + "id": 412878, + "node_id": "MDQ6VXNlcjQxMjg3OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/412878?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/yrodiere", + "html_url": "https://github.com/yrodiere", + "followers_url": "https://api.github.com/users/yrodiere/followers", + "following_url": "https://api.github.com/users/yrodiere/following{/other_user}", + "gists_url": "https://api.github.com/users/yrodiere/gists{/gist_id}", + "starred_url": "https://api.github.com/users/yrodiere/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/yrodiere/subscriptions", + "organizations_url": "https://api.github.com/users/yrodiere/orgs", + "repos_url": "https://api.github.com/users/yrodiere/repos", + "events_url": "https://api.github.com/users/yrodiere/events{/privacy}", + "received_events_url": "https://api.github.com/users/yrodiere/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/yrodiere/hibernate-github-bot-playground", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground", + "forks_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/forks", + "keys_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/teams", + "hooks_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/hooks", + "issue_events_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/issues/events{/number}", + "events_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/events", + "assignees_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/assignees{/user}", + "branches_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/branches{/branch}", + "tags_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/tags", + "blobs_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/statuses/{sha}", + "languages_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/languages", + "stargazers_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/stargazers", + "contributors_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/contributors", + "subscribers_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/subscribers", + "subscription_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/subscription", + "commits_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/contents/{+path}", + "compare_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/merges", + "archive_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/downloads", + "issues_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/issues{/number}", + "pulls_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/pulls{/number}", + "milestones_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/milestones{/number}", + "notifications_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/labels{/name}", + "releases_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/releases{/id}", + "deployments_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/deployments", + "created_at": "2021-03-05T13:13:43Z", + "updated_at": "2021-03-05T13:27:59Z", + "pushed_at": "2021-03-05T13:52:31Z", + "git_url": "git://github.com/yrodiere/hibernate-github-bot-playground.git", + "ssh_url": "git@github.com:yrodiere/hibernate-github-bot-playground.git", + "clone_url": "https://github.com/yrodiere/hibernate-github-bot-playground.git", + "svn_url": "https://github.com/yrodiere/hibernate-github-bot-playground", + "homepage": null, + "size": 0, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 1, + "license": { + "key": "mit", + "name": "MIT License", + "spdx_id": "MIT", + "url": "https://api.github.com/licenses/mit", + "node_id": "MDc6TGljZW5zZTEz" + }, + "forks": 0, + "open_issues": 1, + "watchers": 0, + "default_branch": "main", + "allow_squash_merge": true, + "allow_merge_commit": true, + "allow_rebase_merge": true, + "delete_branch_on_merge": false + } + }, + "_links": { + "self": { + "href": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/pulls/1" + }, + "html": { + "href": "https://github.com/yrodiere/hibernate-github-bot-playground/pull/1" + }, + "issue": { + "href": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/issues/1" + }, + "comments": { + "href": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/issues/1/comments" + }, + "review_comments": { + "href": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/pulls/1/comments" + }, + "review_comment": { + "href": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/pulls/comments{/number}" + }, + "commits": { + "href": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/pulls/1/commits" + }, + "statuses": { + "href": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/statuses/6e9f11a1e2946b207c6eb245ec942f2b5a3ea156" + } + }, + "author_association": "OWNER", + "auto_merge": null, + "active_lock_reason": null, + "merged": false, + "mergeable": null, + "rebaseable": null, + "mergeable_state": "unknown", + "merged_by": null, + "comments": 0, + "review_comments": 0, + "maintainer_can_modify": false, + "commits": 1, + "additions": 1, + "deletions": 0, + "changed_files": 1 + }, + "repository": { + "id": 344815557, + "node_id": "MDEwOlJlcG9zaXRvcnkzNDQ4MTU1NTc=", + "name": "hibernate-github-bot-playground", + "full_name": "yrodiere/hibernate-github-bot-playground", + "private": false, + "owner": { + "login": "yrodiere", + "id": 412878, + "node_id": "MDQ6VXNlcjQxMjg3OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/412878?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/yrodiere", + "html_url": "https://github.com/yrodiere", + "followers_url": "https://api.github.com/users/yrodiere/followers", + "following_url": "https://api.github.com/users/yrodiere/following{/other_user}", + "gists_url": "https://api.github.com/users/yrodiere/gists{/gist_id}", + "starred_url": "https://api.github.com/users/yrodiere/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/yrodiere/subscriptions", + "organizations_url": "https://api.github.com/users/yrodiere/orgs", + "repos_url": "https://api.github.com/users/yrodiere/repos", + "events_url": "https://api.github.com/users/yrodiere/events{/privacy}", + "received_events_url": "https://api.github.com/users/yrodiere/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/yrodiere/hibernate-github-bot-playground", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground", + "forks_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/forks", + "keys_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/teams", + "hooks_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/hooks", + "issue_events_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/issues/events{/number}", + "events_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/events", + "assignees_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/assignees{/user}", + "branches_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/branches{/branch}", + "tags_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/tags", + "blobs_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/statuses/{sha}", + "languages_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/languages", + "stargazers_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/stargazers", + "contributors_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/contributors", + "subscribers_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/subscribers", + "subscription_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/subscription", + "commits_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/contents/{+path}", + "compare_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/merges", + "archive_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/downloads", + "issues_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/issues{/number}", + "pulls_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/pulls{/number}", + "milestones_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/milestones{/number}", + "notifications_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/labels{/name}", + "releases_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/releases{/id}", + "deployments_url": "https://api.github.com/repos/yrodiere/hibernate-github-bot-playground/deployments", + "created_at": "2021-03-05T13:13:43Z", + "updated_at": "2021-03-05T13:27:59Z", + "pushed_at": "2021-03-05T13:52:31Z", + "git_url": "git://github.com/yrodiere/hibernate-github-bot-playground.git", + "ssh_url": "git@github.com:yrodiere/hibernate-github-bot-playground.git", + "clone_url": "https://github.com/yrodiere/hibernate-github-bot-playground.git", + "svn_url": "https://github.com/yrodiere/hibernate-github-bot-playground", + "homepage": null, + "size": 0, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 1, + "license": { + "key": "mit", + "name": "MIT License", + "spdx_id": "MIT", + "url": "https://api.github.com/licenses/mit", + "node_id": "MDc6TGljZW5zZTEz" + }, + "forks": 0, + "open_issues": 1, + "watchers": 0, + "default_branch": "main" + }, + "sender": { + "login": "yrodiere", + "id": 412878, + "node_id": "MDQ6VXNlcjQxMjg3OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/412878?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/yrodiere", + "html_url": "https://github.com/yrodiere", + "followers_url": "https://api.github.com/users/yrodiere/followers", + "following_url": "https://api.github.com/users/yrodiere/following{/other_user}", + "gists_url": "https://api.github.com/users/yrodiere/gists{/gist_id}", + "starred_url": "https://api.github.com/users/yrodiere/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/yrodiere/subscriptions", + "organizations_url": "https://api.github.com/users/yrodiere/orgs", + "repos_url": "https://api.github.com/users/yrodiere/repos", + "events_url": "https://api.github.com/users/yrodiere/events{/privacy}", + "received_events_url": "https://api.github.com/users/yrodiere/received_events", + "type": "User", + "site_admin": false + }, + "installation": { + "id": 15144501, + "node_id": "MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMTUxNDQ1MDE=" + } +}