diff --git a/README.md b/README.md index a9d3f0a..0cff77e 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,16 @@ links to JIRA tickets will be appended at the bottom of the PR body. Optionally, the bot can be configured to automatically create a GitHub check listing Develocity build scans for every commit that has completed checks related to CI (GitHub Actions or Jenkins). +### License agreement check + +Optionally, the bot can be configured to check that the pull request body includes the license agreement text from the template. + +### Pull request tasks + +Optionally, the bot can also add a list of tasks to the pull request as a reminder of the steps to complete before +the pull request can be merged. This can be enabled per repository. Once enabled, the list of tasks per +issue type should be configured. If the Jira issue type doesn't have a list of tasks configured the default tasks will be used. + ## Configuration ### Enabling the bot in a new repository @@ -100,15 +110,37 @@ develocity: replacement: "$0" - pattern: "hibernate.search|elasticsearch|opensearch|main|\\d+.\\d+|PR-\\d+" replacement: "" # Just remove these tags +licenseAgreement: + enabled: true + # Optionally provide the pattern to use for extracting the license text from the `PULL_REQUEST_TEMPLATE.md` + # Keep in mind that the bot expects that the license text to check is matched by the 1st group: + pullRequestTemplatePattern: .+(---.+---).+ +pullRequestTasks: + # Make the bot add list of tasks to the pull requests and enable the check that makes sure all tasks are completed: + enabled: true + # Tasks for a particular issue type, with `default` being a "unique" category: + tasks: + # List of tasks for commits without a Jira ID + # or for those with Jira ID but that don't have a specific configuration for a corresponding issue type: + default: + - task1 + - task2 + # Tasks specific to the bug issue type: + bug: + - bug task1 + - bug task2 + # Tasks specific to the improvement issue type: + improvement: + - improvement task1 ``` ### Altering the infrastructure This should only be needed very rarely, so think twice before trying this. -You will need admin rights in the Hibernate organization. +You will need admin rights in the Hibernate organization and access to the OpenShift cluster. -The infrastructure configuration can be found [here](https://github.com/hibernate/ci.hibernate.org). +The infrastructure configuration can be found [here](src/main/resources/application.properties) under "#Deployment configuration". The GitHub registration of this bot can be found [here](https://github.com/organizations/hibernate/settings/apps/hibernate-github-bot). diff --git a/pom.xml b/pom.xml index ea27ce0..e0cad80 100644 --- a/pom.xml +++ b/pom.xml @@ -140,6 +140,11 @@ mockito-junit-jupiter test + + io.quarkus + quarkus-junit5-mockito + test + diff --git a/src/main/java/org/hibernate/infra/bot/CheckPullRequestContributionRules.java b/src/main/java/org/hibernate/infra/bot/CheckPullRequestContributionRules.java index e47a271..50b3cf0 100644 --- a/src/main/java/org/hibernate/infra/bot/CheckPullRequestContributionRules.java +++ b/src/main/java/org/hibernate/infra/bot/CheckPullRequestContributionRules.java @@ -5,6 +5,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import java.util.regex.Matcher; import java.util.regex.Pattern; import jakarta.inject.Inject; @@ -55,27 +56,29 @@ public class CheckPullRequestContributionRules { void pullRequestChanged( @PullRequest.Opened @PullRequest.Reopened @PullRequest.Edited @PullRequest.Synchronize GHEventPayload.PullRequest payload, - @ConfigFile("hibernate-github-bot.yml") RepositoryConfig repositoryConfig) throws IOException { - checkPullRequestContributionRules( payload.getRepository(), repositoryConfig, - payload.getPullRequest() - ); + @ConfigFile("hibernate-github-bot.yml") RepositoryConfig repositoryConfig, + @ConfigFile("PULL_REQUEST_TEMPLATE.md") String pullRequestTemplate) throws IOException { + checkPullRequestContributionRules( payload.getRepository(), repositoryConfig, pullRequestTemplate, payload.getPullRequest() ); } void checkRunRequested(@CheckRun.Rerequested GHEventPayload.CheckRun payload, - @ConfigFile("hibernate-github-bot.yml") RepositoryConfig repositoryConfig) throws IOException { + @ConfigFile("hibernate-github-bot.yml") RepositoryConfig repositoryConfig, + @ConfigFile("PULL_REQUEST_TEMPLATE.md") String pullRequestTemplate) throws IOException { for ( GHPullRequest pullRequest : payload.getCheckRun().getPullRequests() ) { - checkPullRequestContributionRules( payload.getRepository(), repositoryConfig, pullRequest ); + checkPullRequestContributionRules( payload.getRepository(), repositoryConfig, pullRequestTemplate, pullRequest ); } } void checkSuiteRequested(@CheckSuite.Requested @CheckSuite.Rerequested GHEventPayload.CheckSuite payload, - @ConfigFile("hibernate-github-bot.yml") RepositoryConfig repositoryConfig) throws IOException { + @ConfigFile("hibernate-github-bot.yml") RepositoryConfig repositoryConfig, + @ConfigFile("PULL_REQUEST_TEMPLATE.md") String pullRequestTemplate) throws IOException { for ( GHPullRequest pullRequest : payload.getCheckSuite().getPullRequests() ) { - checkPullRequestContributionRules( payload.getRepository(), repositoryConfig, pullRequest ); + checkPullRequestContributionRules( payload.getRepository(), repositoryConfig, pullRequestTemplate, pullRequest ); } } private void checkPullRequestContributionRules(GHRepository repository, RepositoryConfig repositoryConfig, + String pullRequestTemplate, GHPullRequest pullRequest) throws IOException { if ( !shouldCheck( repository, pullRequest ) ) { @@ -83,7 +86,7 @@ private void checkPullRequestContributionRules(GHRepository repository, Reposito } PullRequestCheckRunContext context = new PullRequestCheckRunContext( deploymentConfig, repository, repositoryConfig, pullRequest ); - List checks = createChecks( repositoryConfig ); + List checks = createChecks( repositoryConfig, pullRequestTemplate ); List outputs = new ArrayList<>(); for ( PullRequestCheck check : checks ) { outputs.add( PullRequestCheck.run( context, check ) ); @@ -133,7 +136,7 @@ private GHIssueComment findExistingComment(GHPullRequest pullRequest) throws IOE return null; } - private List createChecks(RepositoryConfig repositoryConfig) { + private List createChecks(RepositoryConfig repositoryConfig, String pullRequestTemplate) { List checks = new ArrayList<>(); checks.add( new TitleCheck() ); @@ -150,6 +153,24 @@ private List createChecks(RepositoryConfig repositoryConfig) { ) ) ); } + if ( repositoryConfig != null + && repositoryConfig.licenseAgreement != null + && repositoryConfig.licenseAgreement.getEnabled().orElse( Boolean.FALSE ) ) { + Matcher matcher = repositoryConfig.licenseAgreement.getPullRequestTemplatePattern().matcher( pullRequestTemplate ); + if ( matcher.matches() + && matcher.groupCount() == 1 ) { + checks.add( new LicenseCheck( matcher.group( 1 ).trim() ) ); + } + else { + throw new IllegalArgumentException( "Misconfigured license agreement check. Pattern should contain exactly 1 match group. Pattern: %s. Fetched Pull Request template: %s".formatted( repositoryConfig.licenseAgreement.getPullRequestTemplatePattern(), pullRequestTemplate ) ); + } + } + + if ( repositoryConfig != null && repositoryConfig.pullRequestTasks != null + && repositoryConfig.pullRequestTasks.getEnabled().orElse( Boolean.FALSE ) ) { + checks.add( new TasksCompletedCheck() ); + } + return checks; } @@ -256,4 +277,45 @@ private boolean shouldCheckPullRequest(PullRequestCheckRunContext context) throw } } + static class LicenseCheck extends PullRequestCheck { + + private final String agreementText; + + protected LicenseCheck(String agreementText) { + super( "Contribution — License agreement" ); + this.agreementText = agreementText; + } + + @Override + public void perform(PullRequestCheckRunContext context, PullRequestCheckRunOutput output) { + String body = context.pullRequest.getBody(); + PullRequestCheckRunRule rule = output.rule( "The pull request description must contain the license agreement text." ); + if ( body != null && body.contains( agreementText ) ) { + rule.passed(); + } + else { + rule.failed( """ + The description of this pull request must contain the following license agreement text: + ``` + %s + ``` + """.formatted( agreementText ) ); + } + } + } + + static class TasksCompletedCheck extends PullRequestCheck { + + protected TasksCompletedCheck() { + super( "Contribution — Review tasks" ); + } + + @Override + public void perform(PullRequestCheckRunContext context, PullRequestCheckRunOutput output) { + String body = context.pullRequest.getBody(); + output.rule( "All pull request tasks should be completed." ) + .result( !EditPullRequestBodyAddTaskList.containsUnfinishedTasks( body ) ); + } + } + } diff --git a/src/main/java/org/hibernate/infra/bot/EditPullRequestBodyAddTaskList.java b/src/main/java/org/hibernate/infra/bot/EditPullRequestBodyAddTaskList.java new file mode 100644 index 0000000..b298a89 --- /dev/null +++ b/src/main/java/org/hibernate/infra/bot/EditPullRequestBodyAddTaskList.java @@ -0,0 +1,195 @@ +package org.hibernate.infra.bot; + +import java.io.IOException; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.Set; +import java.util.regex.Pattern; + +import org.hibernate.infra.bot.config.DeploymentConfig; +import org.hibernate.infra.bot.config.RepositoryConfig; +import org.hibernate.infra.bot.jira.JiraIssue; +import org.hibernate.infra.bot.jira.JiraIssues; +import org.hibernate.infra.bot.jira.JiraRestClient; +import org.hibernate.infra.bot.util.CommitMessages; +import org.hibernate.infra.bot.util.Patterns; + +import org.jboss.logging.Logger; + +import io.quarkiverse.githubapp.ConfigFile; +import io.quarkiverse.githubapp.event.PullRequest; +import jakarta.inject.Inject; +import org.eclipse.microprofile.rest.client.inject.RestClient; +import org.kohsuke.github.GHEventPayload; +import org.kohsuke.github.GHIssueState; +import org.kohsuke.github.GHPullRequest; +import org.kohsuke.github.GHPullRequestCommitDetail; +import org.kohsuke.github.GHRepository; + +public class EditPullRequestBodyAddTaskList { + private static final Logger LOG = Logger.getLogger( EditPullRequestBodyAddTaskList.class ); + + private static final String START_MARKER = ""; + + private static final String END_MARKER = ""; + private static final Set REGEX_ESCAPE_CHARS = Set.of( '(', ')', '[', ']', '{', '}', '\\', '.', '?', '*', '+' ); + + @Inject + DeploymentConfig deploymentConfig; + @RestClient + JiraRestClient jiraRestClient; + + void pullRequestChanged( + @PullRequest.Opened @PullRequest.Reopened @PullRequest.Edited @PullRequest.Synchronize + GHEventPayload.PullRequest payload, + @ConfigFile("hibernate-github-bot.yml") RepositoryConfig repositoryConfig + ) throws IOException { + addUpdateTaskList( payload.getRepository(), repositoryConfig, payload.getPullRequest() ); + } + + private void addUpdateTaskList( + GHRepository repository, + RepositoryConfig repositoryConfig, + GHPullRequest pullRequest + ) throws IOException { + if ( repositoryConfig == null || repositoryConfig.pullRequestTasks == null + || !repositoryConfig.pullRequestTasks.getEnabled().orElse( Boolean.FALSE ) ) { + return; + } + + if ( !shouldCheck( repository, pullRequest ) ) { + return; + } + + final Set issueKeys = new HashSet<>(); + boolean genericTasksRequired = false; + if ( repositoryConfig.jira.getIssueKeyPattern().isPresent() ) { + Pattern issueKeyPattern = repositoryConfig.jira.getIssueKeyPattern().get(); + + for ( GHPullRequestCommitDetail commitDetails : pullRequest.listCommits() ) { + final GHPullRequestCommitDetail.Commit commit = commitDetails.getCommit(); + final List commitIssueKeys = CommitMessages.extractIssueKeys( + issueKeyPattern, + commit.getMessage() + ); + issueKeys.addAll( commitIssueKeys ); + genericTasksRequired = genericTasksRequired || commitIssueKeys.isEmpty(); + } + } + else { + genericTasksRequired = true; + } + + final String originalBody = Objects.toString( pullRequest.getBody(), "" ); + final String currentTasks = currentTaskBody( originalBody ); + final String tasks = generateTaskList( repositoryConfig.pullRequestTasks, genericTasksRequired, issueKeys ); + + String body; + + if ( currentTasks == null && tasks == null ) { + return; + } + + if ( tasks == null ) { + body = originalBody.replace( currentTasks, "" ); + } + else if ( currentTasks != null ) { + if (tasksAreTheSame( currentTasks, tasks ) ) { + return; + } + body = originalBody.replace( currentTasks, tasks ); + } + else { + body = "%s\n\n---\n%s\n%s\n%s".formatted( originalBody, START_MARKER, tasks, END_MARKER ); + } + + if ( !deploymentConfig.isDryRun() ) { + pullRequest.setBody( body ); + } + else { + LOG.info( "Pull request #" + pullRequest.getNumber() + " - Updated PR body: " + body ); + } + } + + private boolean tasksAreTheSame(String currentTasks, String tasks) { + StringBuilder sb = new StringBuilder(); + for ( char c : tasks.trim().toCharArray() ) { + if ( REGEX_ESCAPE_CHARS.contains( c ) ) { + sb.append( '\\' ); + } + if ( c == '\n' ) { + sb.append( '\\' ).append( 'n' ); + } + else { + sb.append( c ); + } + } + + return Patterns.compile( sb.toString().replace( "- \\[ \\]", "- \\[.\\]" ) ) + .matcher( currentTasks.trim() ) + .matches(); + } + + private String generateTaskList(RepositoryConfig.TaskList taskListConfiguration, boolean genericTasksRequired, Set issueKeys) { + if ( !genericTasksRequired && issueKeys.isEmpty() ) { + return null; + } + StringBuilder taskList = new StringBuilder(); + taskList.append( "Please make sure that the following tasks are completed:\n" ); + if ( genericTasksRequired ) { + addTasks( taskList, taskListConfiguration.defaultTasks() ); + } + if ( !issueKeys.isEmpty() ) { + JiraIssues issues = jiraRestClient.find( "key IN (" + String.join( ",", issueKeys ) + ") ORDER BY KEY DESC", "issuetype,key" ); + for ( JiraIssue issue : issues.issues ) { + taskList.append( "Tasks specific to " ) + .append( issue.key ) + .append( " (" ) + .append( issue.fields.issuetype.name ) + .append( "):\n" ); + addTasks( taskList, taskListConfiguration.getTasks().getOrDefault( issue.fields.issuetype.name.toLowerCase( Locale.ROOT ), taskListConfiguration.defaultTasks() ) ); + } + } + + return taskList.toString(); + } + + private void addTasks(StringBuilder sb, List tasks) { + for ( String task : tasks ) { + sb.append( "- [ ] " ) + .append( task ) + .append( "\n" ); + } + sb.append( "\n" ); + } + + public static boolean containsUnfinishedTasks(String body) { + if ( body == null || body.isEmpty() ) { + return false; + } + String taskBody = currentTaskBody( body ); + if ( taskBody == null ) { + return false; + } + return taskBody.contains( "- [ ]" ); + } + + private static String currentTaskBody(String originalBody) { + // Check if the body already contains the tasks + final int startIndex = originalBody.indexOf( START_MARKER ); + final int endIndex = startIndex > -1 ? originalBody.indexOf( END_MARKER ) : -1; + if ( startIndex > -1 && endIndex > -1 ) { + return originalBody.substring( startIndex + START_MARKER.length() + 1, endIndex - 1 ); + } + else { + return null; + } + } + + private boolean shouldCheck(GHRepository repository, GHPullRequest pullRequest) { + return !GHIssueState.CLOSED.equals( pullRequest.getState() ) + && repository.getId() == pullRequest.getBase().getRepository().getId(); + } +} diff --git a/src/main/java/org/hibernate/infra/bot/config/DeploymentConfig.java b/src/main/java/org/hibernate/infra/bot/config/DeploymentConfig.java index d29250d..be691f5 100644 --- a/src/main/java/org/hibernate/infra/bot/config/DeploymentConfig.java +++ b/src/main/java/org/hibernate/infra/bot/config/DeploymentConfig.java @@ -14,6 +14,8 @@ public interface DeploymentConfig { Jenkins jenkins(); + Jira jira(); + default boolean isDryRun() { Optional dryRun = dryRun(); return dryRun.isPresent() && dryRun.get(); @@ -27,4 +29,10 @@ interface Develocity { interface Jenkins { long githubAppId(); } + + interface Jira { + URI uri(); + String username(); + String token(); + } } 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 f2c6995..f59c125 100644 --- a/src/main/java/org/hibernate/infra/bot/config/RepositoryConfig.java +++ b/src/main/java/org/hibernate/infra/bot/config/RepositoryConfig.java @@ -2,7 +2,9 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.regex.Pattern; @@ -14,6 +16,10 @@ public class RepositoryConfig { public Develocity develocity; + public LicenseAgreement licenseAgreement; + + public TaskList pullRequestTasks; + public static class JiraConfig { private Optional issueKeyPattern = Optional.empty(); @@ -129,4 +135,50 @@ public void setPattern(String pattern) { } } + public static class LicenseAgreement { + private Optional enabled = Optional.empty(); + private Pattern pullRequestTemplatePattern = Patterns.compile( ".+([-]{22}.+[-]{22}).++" ); + + public Optional getEnabled() { + return enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = Optional.of( enabled ); + } + + public Pattern getPullRequestTemplatePattern() { + return pullRequestTemplatePattern; + } + + public void setPullRequestTemplatePattern(String pullRequestTemplatePattern) { + this.pullRequestTemplatePattern = Patterns.compile( pullRequestTemplatePattern ); + } + } + + public static class TaskList { + private static final String DEFAULT_TASKS_CATEGORY = "default"; + private Optional enabled = Optional.empty(); + private Map> tasks = new HashMap<>(); + + public Optional getEnabled() { + return enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = Optional.of( enabled ); + } + + public Map> getTasks() { + return tasks; + } + + public void setTasks(Map> tasks) { + this.tasks = tasks; + } + + public List defaultTasks() { + return tasks.getOrDefault( DEFAULT_TASKS_CATEGORY, List.of() ); + } + } } diff --git a/src/main/java/org/hibernate/infra/bot/jira/JiraBaseObject.java b/src/main/java/org/hibernate/infra/bot/jira/JiraBaseObject.java new file mode 100644 index 0000000..32ec31e --- /dev/null +++ b/src/main/java/org/hibernate/infra/bot/jira/JiraBaseObject.java @@ -0,0 +1,18 @@ +package org.hibernate.infra.bot.jira; + +import java.util.HashMap; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; + +public class JiraBaseObject { + @JsonAnyGetter + @JsonAnySetter + private Map properties = new HashMap<>(); + + public Map properties() { + return properties; + } + +} diff --git a/src/main/java/org/hibernate/infra/bot/jira/JiraFields.java b/src/main/java/org/hibernate/infra/bot/jira/JiraFields.java new file mode 100644 index 0000000..5f4505c --- /dev/null +++ b/src/main/java/org/hibernate/infra/bot/jira/JiraFields.java @@ -0,0 +1,5 @@ +package org.hibernate.infra.bot.jira; + +public class JiraFields extends JiraBaseObject { + public JiraSimpleObject issuetype; +} diff --git a/src/main/java/org/hibernate/infra/bot/jira/JiraIssue.java b/src/main/java/org/hibernate/infra/bot/jira/JiraIssue.java new file mode 100644 index 0000000..2d6b156 --- /dev/null +++ b/src/main/java/org/hibernate/infra/bot/jira/JiraIssue.java @@ -0,0 +1,10 @@ +package org.hibernate.infra.bot.jira; + +import java.net.URI; + +public class JiraIssue extends JiraBaseObject { + public Long id; + public String key; + public URI self; + public JiraFields fields; +} diff --git a/src/main/java/org/hibernate/infra/bot/jira/JiraIssues.java b/src/main/java/org/hibernate/infra/bot/jira/JiraIssues.java new file mode 100644 index 0000000..f887ebd --- /dev/null +++ b/src/main/java/org/hibernate/infra/bot/jira/JiraIssues.java @@ -0,0 +1,7 @@ +package org.hibernate.infra.bot.jira; + +import java.util.List; + +public class JiraIssues extends JiraBaseObject { + public List issues; +} diff --git a/src/main/java/org/hibernate/infra/bot/jira/JiraRestClient.java b/src/main/java/org/hibernate/infra/bot/jira/JiraRestClient.java new file mode 100644 index 0000000..3d708f7 --- /dev/null +++ b/src/main/java/org/hibernate/infra/bot/jira/JiraRestClient.java @@ -0,0 +1,16 @@ +package org.hibernate.infra.bot.jira; + +import io.quarkus.rest.client.reactive.ClientBasicAuth; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.QueryParam; +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; + +@Path("/rest/api/3") +@RegisterRestClient(configKey = "jira") +@ClientBasicAuth(username = "${hibernate-github-bot.jira.username}", password = "${hibernate-github-bot.jira.token}") +public interface JiraRestClient { + @GET + @Path("/search/jql") + JiraIssues find(@QueryParam("jql") String jql, @QueryParam("fields") String fields); +} diff --git a/src/main/java/org/hibernate/infra/bot/jira/JiraSimpleObject.java b/src/main/java/org/hibernate/infra/bot/jira/JiraSimpleObject.java new file mode 100644 index 0000000..7416a44 --- /dev/null +++ b/src/main/java/org/hibernate/infra/bot/jira/JiraSimpleObject.java @@ -0,0 +1,9 @@ +package org.hibernate.infra.bot.jira; + +import java.net.URI; + +public class JiraSimpleObject extends JiraBaseObject { + public String id; + public String name; + public URI self; +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index b408090..a77ae24 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -23,6 +23,11 @@ quarkus.openapi-generator.gradle_enterprise_2023_4_api_yaml.auth.DevelocityAcces %dev,test.hibernate-github-bot.dry-run=false %dev,test.hibernate-github-bot.develocity.access-key=foo +hibernate-github-bot.jira.uri=https://hibernate.atlassian.net/ +hibernate-github-bot.jira.username=foo +hibernate-github-bot.jira.token=bar +quarkus.rest-client.jira.url=${hibernate-github-bot.jira.uri} + ############## # Deployment configuration: # diff --git a/src/test/java/org/hibernate/infra/bot/tests/AbstractPullRequestTest.java b/src/test/java/org/hibernate/infra/bot/tests/AbstractPullRequestTest.java index 7ef7cba..2d33897 100644 --- a/src/test/java/org/hibernate/infra/bot/tests/AbstractPullRequestTest.java +++ b/src/test/java/org/hibernate/infra/bot/tests/AbstractPullRequestTest.java @@ -6,15 +6,10 @@ import java.io.IOException; -import org.junit.jupiter.api.extension.ExtendWith; - -import io.quarkiverse.githubapp.testing.GitHubAppTest; -import io.quarkus.test.junit.QuarkusTest; import org.kohsuke.github.GHCheckRun; import org.kohsuke.github.GHCheckRunBuilder; import org.kohsuke.github.GHRepository; import org.mockito.Answers; -import org.mockito.junit.jupiter.MockitoExtension; abstract class AbstractPullRequestTest { final GHCheckRunBuilder titleCheckRunCreateBuilderMock = mockCheckRunBuilder(); @@ -38,6 +33,7 @@ void mockCheckRuns(GHRepository repoMock, String headSHA) throws IOException { jiraCheckRunCreateBuilderMock, jiraCheckRunMock, 43L ); mockUpdateCheckRun( repoMock, 43L, jiraCheckRunUpdateBuilderMock, jiraCheckRunMock ); + } void mockCreateCheckRun(GHRepository repoMock, String name, String headSHA, diff --git a/src/test/java/org/hibernate/infra/bot/tests/CheckPullRequestContributionRulesLicenseTest.java b/src/test/java/org/hibernate/infra/bot/tests/CheckPullRequestContributionRulesLicenseTest.java new file mode 100644 index 0000000..2f097f0 --- /dev/null +++ b/src/test/java/org/hibernate/infra/bot/tests/CheckPullRequestContributionRulesLicenseTest.java @@ -0,0 +1,159 @@ +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.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.GHCheckRun; +import org.kohsuke.github.GHCheckRunBuilder; +import org.kohsuke.github.GHEvent; +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 CheckPullRequestContributionRulesLicenseTest extends AbstractPullRequestTest { + + final GHCheckRunBuilder licenseCheckRunCreateBuilderMock = mockCheckRunBuilder(); + final GHCheckRunBuilder licenseCheckRunUpdateBuilderMock = mockCheckRunBuilder(); + + @Override + void mockCheckRuns(GHRepository repoMock, String headSHA) throws IOException { + super.mockCheckRuns( repoMock, headSHA ); + GHCheckRun licenseCheckRunMock = mock( GHCheckRun.class ); + mockCreateCheckRun( repoMock, "Contribution — License agreement", headSHA, + licenseCheckRunCreateBuilderMock, licenseCheckRunMock, 44L + ); + mockUpdateCheckRun( repoMock, 44L, licenseCheckRunUpdateBuilderMock, licenseCheckRunMock ); + } + + @Test + void bodyMissingLicenseAgreement() throws IOException { + long repoId = 344815557L; + long prId = 585627026L; + given() + .github( mocks -> { + mocks.configFile("hibernate-github-bot.yml") + .fromString( """ + jira: + projectKey: "HSEARCH" + licenseAgreement: + enabled: true + """ ); + mocks.configFile("PULL_REQUEST_TEMPLATE.md") + .fromString( """ + [Please describe here what your change is about] + + + ---------------------- + By submitting this pull request, I confirm that my contribution is made under the terms of the [Apache 2.0 license](https://www.apache.org/licenses/LICENSE-2.0.txt) + and can be relicensed under the terms of the [LGPL v2.1 license](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt) in the future at the maintainers' discretion. + For more information on licensing, please check [here](https://github.com/hibernate/hibernate-search/blob/main/CONTRIBUTING.md#legal). + + ---------------------- + """ ); + + 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.json" ) + .event( GHEvent.PULL_REQUEST ) + .then() + .github( mocks -> { + GHPullRequest prMock = mocks.pullRequest( prId ); + ArgumentCaptor messageCaptor = ArgumentCaptor.forClass( String.class ); + verify( prMock ).comment( messageCaptor.capture() ); + assertThat( messageCaptor.getValue() ) + .isEqualTo( """ + Thanks for your pull request! + + This pull request does not follow the contribution rules. Could you have a look? + + ❌ The pull request description must contain the license agreement text. +     ↳ The description of this pull request must contain the following license agreement text: + ``` + ---------------------- + By submitting this pull request, I confirm that my contribution is made under the terms of the [Apache 2.0 license](https://www.apache.org/licenses/LICENSE-2.0.txt) + and can be relicensed under the terms of the [LGPL v2.1 license](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt) in the future at the maintainers' discretion. + For more information on licensing, please check [here](https://github.com/hibernate/hibernate-search/blob/main/CONTRIBUTING.md#legal). + + ---------------------- + ``` + + + › This message was automatically generated.""" ); + verifyNoMoreInteractions( mocks.ghObjects() ); + } ); + } + + @Test + void bodyContainsLicenseAgreement() throws IOException { + long repoId = 344815557L; + long prId = 585627026L; + given() + .github( mocks -> { + mocks.configFile("hibernate-github-bot.yml") + .fromString( """ + jira: + projectKey: "HSEARCH" + licenseAgreement: + enabled: true + """ ); + mocks.configFile("PULL_REQUEST_TEMPLATE.md") + .fromString( """ + [Please describe here what your change is about] + + + ---------------------- + By submitting this pull request, I confirm that my contribution is made under the terms of the [Apache 2.0 license](https://www.apache.org/licenses/LICENSE-2.0.txt) + and can be relicensed under the terms of the [LGPL v2.1 license](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt) in the future at the maintainers' discretion. + For more information on licensing, please check [here](https://github.com/hibernate/hibernate-search/blob/main/CONTRIBUTING.md#legal). + + ---------------------- + """ ); + + 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-with-license.json" ) + .event( GHEvent.PULL_REQUEST ) + .then() + .github( mocks -> { + verifyNoMoreInteractions( mocks.ghObjects() ); + } ); + } + +} diff --git a/src/test/java/org/hibernate/infra/bot/tests/CheckPullRequestContributionRulesTasksTest.java b/src/test/java/org/hibernate/infra/bot/tests/CheckPullRequestContributionRulesTasksTest.java new file mode 100644 index 0000000..e15dc0d --- /dev/null +++ b/src/test/java/org/hibernate/infra/bot/tests/CheckPullRequestContributionRulesTasksTest.java @@ -0,0 +1,216 @@ +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.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 java.util.List; + +import org.hibernate.infra.bot.jira.JiraFields; +import org.hibernate.infra.bot.jira.JiraIssue; +import org.hibernate.infra.bot.jira.JiraIssues; +import org.hibernate.infra.bot.jira.JiraRestClient; +import org.hibernate.infra.bot.jira.JiraSimpleObject; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import io.quarkiverse.githubapp.testing.GitHubAppTest; +import io.quarkus.test.InjectMock; +import io.quarkus.test.junit.QuarkusTest; +import org.eclipse.microprofile.rest.client.inject.RestClient; +import org.kohsuke.github.GHCheckRun; +import org.kohsuke.github.GHCheckRunBuilder; +import org.kohsuke.github.GHEvent; +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 CheckPullRequestContributionRulesTasksTest extends AbstractPullRequestTest { + + @InjectMock + @RestClient + JiraRestClient mock; + + final GHCheckRunBuilder taskCheckRunCreateBuilderMock = mockCheckRunBuilder(); + final GHCheckRunBuilder taskCheckRunUpdateBuilderMock = mockCheckRunBuilder(); + + @Override + void mockCheckRuns(GHRepository repoMock, String headSHA) throws IOException { + super.mockCheckRuns( repoMock, headSHA ); + GHCheckRun taskCheckRunMock = mock( GHCheckRun.class ); + mockCreateCheckRun( repoMock, "Contribution — Review tasks", headSHA, + taskCheckRunCreateBuilderMock, taskCheckRunMock, 45L + ); + mockUpdateCheckRun( repoMock, 45L, taskCheckRunUpdateBuilderMock, taskCheckRunMock ); + } + + + @BeforeEach + public void setUp() { + JiraIssues issues = new JiraIssues(); + JiraIssue issue1 = new JiraIssue(); + issue1.key = "HSEARCH-1111"; + issue1.fields = new JiraFields(); + issue1.fields.issuetype = new JiraSimpleObject(); + issue1.fields.issuetype.name = "bug"; + issues.issues = List.of( issue1 ); + when(mock.find(anyString(),anyString())).thenReturn( issues ); + } + + @Test + void createTasks() throws IOException { + long repoId = 344815557L; + long prId = 585627026L; + given() + .github( mocks -> { + mocks.configFile("hibernate-github-bot.yml") + .fromString( """ + jira: + projectKey: "HSEARCH" + pullRequestTasks: + enabled: true + tasks: + default: + - task1 + - task2 + - task3 + - task4 + bug: + - bug task1 + - bug task2 + - bug task3 + - bug task4 + improvement: + - improvement task1 + - improvement task2 + - improvement task3 + - improvement task4 + """ ); + + GHRepository repoMock = mocks.repository( "yrodiere/hibernate-github-bot-playground" ); + when( repoMock.getId() ).thenReturn( repoId ); + + PullRequestMockHelper.start( mocks, prId, repoMock ) + .commit( "HSEARCH-1111 Correct message" ) + .commit( "Commit with no Jira key" ) + .comment( "some comment" ); + + mockCheckRuns( repoMock, "6e9f11a1e2946b207c6eb245ec942f2b5a3ea156" ); + } ) + .when() + .payloadFromClasspath( "/pullrequest-opened-hsearch-1111-no-body.json" ) + .event( GHEvent.PULL_REQUEST ) + .then() + .github( mocks -> { + GHPullRequest prMock = mocks.pullRequest( prId ); + ArgumentCaptor commentCaptor = ArgumentCaptor.forClass( String.class ); + verify( prMock ).comment( commentCaptor.capture() ); + assertThat( commentCaptor.getValue() ) + .isEqualTo( """ + Thanks for your pull request! + + This pull request does not follow the contribution rules. Could you have a look? + + ❌ All commit messages should start with a JIRA issue key matching pattern `HSEARCH-\\d+` +     ↳ Offending commits: [null] + + › This message was automatically generated.""" ); + ArgumentCaptor bodyCaptor = ArgumentCaptor.forClass( String.class ); + verify( prMock ).setBody( bodyCaptor.capture() ); + assertThat( bodyCaptor.getValue() ) + .isEqualTo( """ + + + --- + + Please make sure that the following tasks are completed: + - [ ] task1 + - [ ] task2 + - [ ] task3 + - [ ] task4 + + Tasks specific to HSEARCH-1111 (bug): + - [ ] bug task1 + - [ ] bug task2 + - [ ] bug task3 + - [ ] bug task4 + + + """ ); + verifyNoMoreInteractions( mocks.ghObjects() ); + } ); + } + + @Test + void bodyContainsTasks() throws IOException { + long repoId = 344815557L; + long prId = 585627026L; + given() + .github( mocks -> { + mocks.configFile("hibernate-github-bot.yml") + .fromString( """ + jira: + projectKey: "HSEARCH" + pullRequestTasks: + enabled: true + tasks: + default: + - task1 + - task2 + - task3 + - task4 + bug: + - bug task1 + - bug task2 + - bug task3 + - bug task4 + improvement: + - improvement task1 + - improvement task2 + - improvement task3 + - improvement task4 + """ ); + + 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 other comment" ); + + mockCheckRuns( repoMock, "6e9f11a1e2946b207c6eb245ec942f2b5a3ea156" ); + } ) + .when() + .payloadFromClasspath( "/pullrequest-opened-hsearch-1111-with-tasks.json" ) + .event( GHEvent.PULL_REQUEST ) + .then() + .github( mocks -> { + GHPullRequest prMock = mocks.pullRequest( prId ); + ArgumentCaptor commentCaptor = ArgumentCaptor.forClass( String.class ); + verify( prMock ).comment( commentCaptor.capture() ); + assertThat( commentCaptor.getValue() ) + .isEqualTo( """ + Thanks for your pull request! + + This pull request does not follow the contribution rules. Could you have a look? + + ❌ All pull request tasks should be completed. + + › This message was automatically generated.""" ); + + verifyNoMoreInteractions( mocks.ghObjects() ); + } ); + } + +} diff --git a/src/test/resources/pullrequest-opened-hsearch-1111-with-license.json b/src/test/resources/pullrequest-opened-hsearch-1111-with-license.json new file mode 100644 index 0000000..c824111 --- /dev/null +++ b/src/test/resources/pullrequest-opened-hsearch-1111-with-license.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\n\n----------------------\nBy submitting this pull request, I confirm that my contribution is made under the terms of the [Apache 2.0 license](https://www.apache.org/licenses/LICENSE-2.0.txt)\nand can be relicensed under the terms of the [LGPL v2.1 license](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt) in the future at the maintainers' discretion.\nFor more information on licensing, please check [here](https://github.com/hibernate/hibernate-search/blob/main/CONTRIBUTING.md#legal).\n\n----------------------", + "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": "main", + "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=" + } +} diff --git a/src/test/resources/pullrequest-opened-hsearch-1111-with-tasks.json b/src/test/resources/pullrequest-opened-hsearch-1111-with-tasks.json new file mode 100644 index 0000000..f97dd5e --- /dev/null +++ b/src/test/resources/pullrequest-opened-hsearch-1111-with-tasks.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": "\n\n\n ---\n \nPlease make sure that the following tasks are completed:\nTasks specific to HSEARCH-1111 (bug):\n- [ ] bug task1\n- [ ] bug task2\n- [ ] bug task3\n- [ ] bug task4\n\n ", + "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": "main", + "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=" + } +}